diff options
author | dequis <dx@dxzone.com.ar> | 2015-09-13 01:17:14 -0300 |
---|---|---|
committer | dequis <dx@dxzone.com.ar> | 2015-10-30 07:27:20 -0300 |
commit | 345577bc90da1d1fffa0df013426eab54fa2b1b2 (patch) | |
tree | 2c07626bdaceb7bd5070eebd2c4a89b24d82db0b | |
parent | 0db66186f49438ae9c2f73ca85b915e999896309 (diff) |
IRC self-message support (messages sent by yourself from other clients)
This adds an OPT_SELFMESSAGE flag that can be passed to imcb_buddy_msg()
or imcb_chat_msg() to indicate that the protocol knows that the message
being sent is a self message.
This needs to be explicit since the old behavior is to silently drop
these messages, which also removed server echoes.
This commit doesn't break API/ABI, the flags parameters that were added
are all internal (between protocols and UI code)
On the irc protocol side, the situation isn't very nice, since some
clients put these messages in the wrong window. Irssi, hexchat and mirc
get this wrong. Irssi 0.8.18 has a fix for it, and the others have
scripts to patch it.
But meanwhile, there's a "self_messages" global setting that lets users
disable this, or get them as normal messages / notices with a "->"
prefix, which loosely imitates the workaround used by the ZNC
"privmsg_prefix" module.
-rw-r--r-- | doc/user-guide/commands.xml | 27 | ||||
-rw-r--r-- | irc.c | 1 | ||||
-rw-r--r-- | irc.h | 1 | ||||
-rw-r--r-- | irc_im.c | 54 | ||||
-rw-r--r-- | irc_util.c | 12 | ||||
-rw-r--r-- | protocols/bee.h | 4 | ||||
-rw-r--r-- | protocols/bee_chat.c | 9 | ||||
-rw-r--r-- | protocols/bee_user.c | 6 | ||||
-rw-r--r-- | protocols/nogaim.h | 3 |
9 files changed, 98 insertions, 19 deletions
diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index d671f6d0..32c3b24e 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -1403,6 +1403,33 @@ </description> </bitlbee-setting> + <bitlbee-setting name="self_messages" type="string" scope="global"> + <default>true</default> + <possible-values>true, false, prefix, prefix_notice</possible-values> + + <description> + <para> + Change this setting to customize how (or whether) to show self-messages, which are messages sent by yourself from other locations (for example, mobile clients), for IM protocols that support it. + </para> + + <para> + When this is set to "true", it will send those messages in the "standard" way, which is a PRIVMSG with source and target fields swapped. + </para> + + <para> + Since this isn't very well supported by some clients (the messages might appear in the wrong window), you can set it to "prefix" to show them as a normal message prefixed with "-> ", or use "prefix_notice" which is the same thing but with a NOTICE instead. + </para> + + <para> + You can also set it to "false" to disable these messages completely. + </para> + + <para> + This setting only applies to private messages. Self messages in groupchats are always shown, since they haven't caused issues in any clients so far. + </para> + </description> + </bitlbee-setting> + <bitlbee-setting name="server" type="string" scope="account"> <description> <para> @@ -128,6 +128,7 @@ irc_t *irc_new(int fd) s->flags |= SET_HIDDEN; s = set_add(&b->set, "show_offline", "false", set_eval_bw_compat, irc); s->flags |= SET_HIDDEN; + s = set_add(&b->set, "self_messages", "true", set_eval_self_messages, irc); s = set_add(&b->set, "simulate_netsplit", "true", set_eval_bool, irc); s = set_add(&b->set, "timezone", "local", set_eval_timezone, irc); s = set_add(&b->set, "to_char", ": ", set_eval_to_char, irc); @@ -353,6 +353,7 @@ void irc_user_quit(irc_user_t *iu, const char *msg); /* irc_util.c */ char *set_eval_timezone(struct set *set, char *value); char *irc_format_timestamp(irc_t *irc, time_t msg_ts); +char *set_eval_self_messages(struct set *set, char *value); /* irc_im.c */ void bee_irc_channel_update(irc_t *irc, irc_channel_t *ic, irc_user_t *iu); @@ -200,14 +200,17 @@ void bee_irc_channel_update(irc_t *irc, irc_channel_t *ic, irc_user_t *iu) } } -static gboolean bee_irc_user_msg(bee_t *bee, bee_user_t *bu, const char *msg_, time_t sent_at) +static gboolean bee_irc_user_msg(bee_t *bee, bee_user_t *bu, const char *msg_, guint32 flags, time_t sent_at) { irc_t *irc = bee->ui_data; irc_user_t *iu = (irc_user_t *) bu->ui_data; + irc_user_t *src_iu = iu; + irc_user_t *dst_iu = irc->user; const char *dst; char *prefix = NULL; char *wrapped, *ts = NULL; char *msg = g_strdup(msg_); + char *message_type = "PRIVMSG"; GSList *l; if (sent_at > 0 && set_getbool(&irc->b->set, "display_timestamps")) { @@ -215,9 +218,44 @@ static gboolean bee_irc_user_msg(bee_t *bee, bee_user_t *bu, const char *msg_, t } dst = irc_user_msgdest(iu); - if (dst != irc->user->nick) { - /* if not messaging directly, call user by name */ - prefix = g_strdup_printf("%s%s%s", irc->user->nick, set_getstr(&bee->set, "to_char"), ts ? : ""); + + if (flags & OPT_SELFMESSAGE) { + char *setting = set_getstr(&irc->b->set, "self_messages"); + + if (is_bool(setting)) { + if (bool2int(setting)) { + /* set to true, send it with src/dst flipped */ + + dst_iu = iu; + src_iu = irc->user; + + if (dst == irc->user->nick) { + dst = dst_iu->nick; + } + } else { + /* set to false, skip the message completely */ + goto cleanup; + } + } else if (g_strncasecmp(setting, "prefix", 6) == 0) { + /* third state, prefix, loosely imitates the znc privmsg_prefix module */ + + g_free(msg); + if (g_strncasecmp(msg_, "/me ", 4) == 0) { + msg = g_strdup_printf("/me -> %s", msg_ + 4); + } else { + msg = g_strdup_printf("-> %s", msg_); + } + + if (g_strcasecmp(setting, "prefix_notice") == 0) { + message_type = "NOTICE"; + } + } + + } + + if (dst != dst_iu->nick) { + /* if not messaging directly (control channel), call user by name */ + prefix = g_strdup_printf("%s%s%s", dst_iu->nick, set_getstr(&bee->set, "to_char"), ts ? : ""); } else { prefix = ts; ts = NULL; /* don't double-free */ @@ -248,7 +286,7 @@ static gboolean bee_irc_user_msg(bee_t *bee, bee_user_t *bu, const char *msg_, t } wrapped = word_wrap(msg, 425); - irc_send_msg(iu, "PRIVMSG", dst, wrapped, prefix); + irc_send_msg(src_iu, message_type, dst, wrapped, prefix); g_free(wrapped); cleanup: @@ -259,7 +297,7 @@ cleanup: return TRUE; } -static gboolean bee_irc_user_typing(bee_t *bee, bee_user_t *bu, uint32_t flags) +static gboolean bee_irc_user_typing(bee_t *bee, bee_user_t *bu, guint32 flags) { irc_t *irc = (irc_t *) bee->ui_data; @@ -616,10 +654,10 @@ static gboolean bee_irc_chat_log(bee_t *bee, struct groupchat *c, const char *te return TRUE; } -static gboolean bee_irc_chat_msg(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, time_t sent_at) +static gboolean bee_irc_chat_msg(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, guint32 flags, time_t sent_at) { irc_t *irc = bee->ui_data; - irc_user_t *iu = bu->ui_data; + irc_user_t *iu = flags & OPT_SELFMESSAGE ? irc->user : bu->ui_data; irc_channel_t *ic = c->ui_data; char *wrapped, *ts = NULL; @@ -118,3 +118,15 @@ char *irc_format_timestamp(irc_t *irc, time_t msg_ts) msg.tm_hour, msg.tm_min, msg.tm_sec); } } + + +char *set_eval_self_messages(set_t *set, char *value) +{ + if (is_bool(value) || + g_strcasecmp(value, "prefix") == 0 || + g_strcasecmp(value, "prefix_notice") == 0) { + return value; + } else { + return SET_INVALID; + } +} diff --git a/protocols/bee.h b/protocols/bee.h index fc27d424..a9678a6e 100644 --- a/protocols/bee.h +++ b/protocols/bee.h @@ -104,7 +104,7 @@ typedef struct bee_ui_funcs { /* State info is already updated, old is provided in case the UI needs a diff. */ gboolean (*user_status)(bee_t *bee, struct bee_user *bu, struct bee_user *old); /* On every incoming message. sent_at = 0 means unknown. */ - gboolean (*user_msg)(bee_t *bee, bee_user_t *bu, const char *msg, time_t sent_at); + gboolean (*user_msg)(bee_t *bee, bee_user_t *bu, const char *msg, guint32 flags, time_t sent_at); /* Flags currently defined (OPT_TYPING/THINKING) in nogaim.h. */ gboolean (*user_typing)(bee_t *bee, bee_user_t *bu, guint32 flags); /* CTCP-like stuff (buddy action) response */ @@ -117,7 +117,7 @@ typedef struct bee_ui_funcs { gboolean (*chat_free)(bee_t *bee, struct groupchat *c); /* System messages of any kind. */ gboolean (*chat_log)(bee_t *bee, struct groupchat *c, const char *text); - gboolean (*chat_msg)(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, time_t sent_at); + gboolean (*chat_msg)(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, guint32 flags, time_t sent_at); gboolean (*chat_add_user)(bee_t *bee, struct groupchat *c, bee_user_t *bu); gboolean (*chat_remove_user)(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *reason); gboolean (*chat_topic)(bee_t *bee, struct groupchat *c, const char *new_topic, bee_user_t *bu); diff --git a/protocols/bee_chat.c b/protocols/bee_chat.c index 6ea86c3a..2fcb0396 100644 --- a/protocols/bee_chat.c +++ b/protocols/bee_chat.c @@ -94,16 +94,15 @@ static gboolean handle_is_self(struct im_connection *ic, const char *handle) (ic->acc->prpl->handle_cmp(ic->acc->user, handle) == 0); } -void imcb_chat_msg(struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at) +void imcb_chat_msg(struct groupchat *c, const char *who, char *msg, guint32 flags, time_t sent_at) { struct im_connection *ic = c->ic; bee_t *bee = ic->bee; bee_user_t *bu; - gboolean temp; + gboolean temp = FALSE; char *s; - /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */ - if (handle_is_self(ic, who)) { + if (handle_is_self(ic, who) && !(flags & OPT_SELFMESSAGE)) { return; } @@ -121,7 +120,7 @@ void imcb_chat_msg(struct groupchat *c, const char *who, char *msg, uint32_t fla } if (bee->ui->chat_msg) { - bee->ui->chat_msg(bee, c, bu, msg, sent_at); + bee->ui->chat_msg(bee, c, bu, msg, flags, sent_at); } if (temp) { diff --git a/protocols/bee_user.c b/protocols/bee_user.c index 2d63bfb4..ced92ee9 100644 --- a/protocols/bee_user.c +++ b/protocols/bee_user.c @@ -246,7 +246,7 @@ void imcb_buddy_times(struct im_connection *ic, const char *handle, time_t login bu->idle_time = idle; } -void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, uint32_t flags, time_t sent_at) +void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, guint32 flags, time_t sent_at) { bee_t *bee = ic->bee; bee_user_t *bu; @@ -264,7 +264,7 @@ void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *ms } if (bee->ui->user_msg && bu) { - bee->ui->user_msg(bee, bu, msg, sent_at); + bee->ui->user_msg(bee, bu, msg, flags, sent_at); } else { imcb_log(ic, "Message from unknown handle %s:\n%s", handle, msg); } @@ -296,7 +296,7 @@ void imcb_notify_email(struct im_connection *ic, char *format, ...) g_free(msg); } -void imcb_buddy_typing(struct im_connection *ic, const char *handle, uint32_t flags) +void imcb_buddy_typing(struct im_connection *ic, const char *handle, guint32 flags) { bee_user_t *bu; diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 6e7343ba..548b22f9 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -69,6 +69,7 @@ #define OPT_NOOTR 0x00001000 /* protocol not suitable for OTR */ #define OPT_PONGS 0x00010000 /* Service sends us keep-alives */ #define OPT_PONGED 0x00020000 /* Received a keep-alive during last interval */ +#define OPT_SELFMESSAGE 0x00080000 /* A message sent by self from another location */ /* ok. now the fun begins. first we create a connection structure */ struct im_connection { @@ -324,7 +325,7 @@ G_MODULE_EXPORT void imcb_rename_buddy(struct im_connection *ic, const char *han G_MODULE_EXPORT void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick); G_MODULE_EXPORT void imcb_buddy_action_response(bee_user_t *bu, const char *action, char * const args[], void *data); -G_MODULE_EXPORT void imcb_buddy_typing(struct im_connection *ic, const char *handle, uint32_t flags); +G_MODULE_EXPORT void imcb_buddy_typing(struct im_connection *ic, const char *handle, guint32 flags); G_MODULE_EXPORT struct bee_user *imcb_buddy_by_handle(struct im_connection *ic, const char *handle); G_MODULE_EXPORT void imcb_clean_handle(struct im_connection *ic, char *handle); |