source: protocols/bee_chat.c @ 0d8a9bb0

Last change on this file since 0d8a9bb0 was 345577b, checked in by dequis <dx@…>, at 2015-10-30T10:27:20Z

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.

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Stuff to handle rooms                                                */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  USA
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28
29struct groupchat *imcb_chat_new(struct im_connection *ic, const char *handle)
30{
31        struct groupchat *c = g_new0(struct groupchat, 1);
32        bee_t *bee = ic->bee;
33
34        /* This one just creates the conversation structure, user won't see
35           anything yet until s/he is joined to the conversation. (This
36           allows you to add other already present participants first.) */
37
38        ic->groupchats = g_slist_prepend(ic->groupchats, c);
39        c->ic = ic;
40        c->title = g_strdup(handle);
41        c->topic = g_strdup_printf(
42                "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!",
43                c->title);
44
45        if (set_getbool(&ic->bee->set, "debug")) {
46                imcb_log(ic, "Creating new conversation: (id=%p,handle=%s)", c, handle);
47        }
48
49        if (bee->ui->chat_new) {
50                bee->ui->chat_new(bee, c);
51        }
52
53        return c;
54}
55
56void imcb_chat_name_hint(struct groupchat *c, const char *name)
57{
58        bee_t *bee = c->ic->bee;
59
60        if (bee->ui->chat_name_hint) {
61                bee->ui->chat_name_hint(bee, c, name);
62        }
63}
64
65void imcb_chat_free(struct groupchat *c)
66{
67        struct im_connection *ic = c->ic;
68        bee_t *bee = ic->bee;
69        GList *ir;
70
71        if (bee->ui->chat_free) {
72                bee->ui->chat_free(bee, c);
73        }
74
75        if (set_getbool(&ic->bee->set, "debug")) {
76                imcb_log(ic, "You were removed from conversation %p", c);
77        }
78
79        ic->groupchats = g_slist_remove(ic->groupchats, c);
80
81        for (ir = c->in_room; ir; ir = ir->next) {
82                g_free(ir->data);
83        }
84        g_list_free(c->in_room);
85        g_free(c->title);
86        g_free(c->topic);
87        g_free(c);
88}
89
90static gboolean handle_is_self(struct im_connection *ic, const char *handle)
91{
92        return (ic->acc->prpl->handle_is_self) ?
93               ic->acc->prpl->handle_is_self(ic, handle) :
94               (ic->acc->prpl->handle_cmp(ic->acc->user, handle) == 0);
95}
96
97void imcb_chat_msg(struct groupchat *c, const char *who, char *msg, guint32 flags, time_t sent_at)
98{
99        struct im_connection *ic = c->ic;
100        bee_t *bee = ic->bee;
101        bee_user_t *bu;
102        gboolean temp = FALSE;
103        char *s;
104
105        if (handle_is_self(ic, who) && !(flags & OPT_SELFMESSAGE)) {
106                return;
107        }
108
109        bu = bee_user_by_handle(bee, ic, who);
110        temp = (bu == NULL);
111
112        if (temp) {
113                bu = bee_user_new(bee, ic, who, BEE_USER_ONLINE);
114        }
115
116        s = set_getstr(&ic->bee->set, "strip_html");
117        if ((g_strcasecmp(s, "always") == 0) ||
118            ((ic->flags & OPT_DOES_HTML) && s)) {
119                strip_html(msg);
120        }
121
122        if (bee->ui->chat_msg) {
123                bee->ui->chat_msg(bee, c, bu, msg, flags, sent_at);
124        }
125
126        if (temp) {
127                bee_user_free(bee, bu);
128        }
129}
130
131void imcb_chat_log(struct groupchat *c, char *format, ...)
132{
133        struct im_connection *ic = c->ic;
134        bee_t *bee = ic->bee;
135        va_list params;
136        char *text;
137
138        if (!bee->ui->chat_log) {
139                return;
140        }
141
142        va_start(params, format);
143        text = g_strdup_vprintf(format, params);
144        va_end(params);
145
146        bee->ui->chat_log(bee, c, text);
147        g_free(text);
148}
149
150void imcb_chat_topic(struct groupchat *c, char *who, char *topic, time_t set_at)
151{
152        struct im_connection *ic = c->ic;
153        bee_t *bee = ic->bee;
154        bee_user_t *bu;
155
156        if (!bee->ui->chat_topic) {
157                return;
158        }
159
160        if (who == NULL) {
161                bu = NULL;
162        } else if (handle_is_self(ic, who)) {
163                bu = bee->user;
164        } else {
165                bu = bee_user_by_handle(bee, ic, who);
166        }
167
168        if ((g_strcasecmp(set_getstr(&ic->bee->set, "strip_html"), "always") == 0) ||
169            ((ic->flags & OPT_DOES_HTML) && set_getbool(&ic->bee->set, "strip_html"))) {
170                strip_html(topic);
171        }
172
173        bee->ui->chat_topic(bee, c, topic, bu);
174}
175
176void imcb_chat_add_buddy(struct groupchat *c, const char *handle)
177{
178        struct im_connection *ic = c->ic;
179        bee_t *bee = ic->bee;
180        bee_user_t *bu = bee_user_by_handle(bee, ic, handle);
181        gboolean me;
182
183        if (set_getbool(&c->ic->bee->set, "debug")) {
184                imcb_log(c->ic, "User %s added to conversation %p", handle, c);
185        }
186
187        me = handle_is_self(ic, handle);
188
189        /* Most protocols allow people to join, even when they're not in
190           your contact list. Try to handle that here */
191        if (!me && !bu) {
192                bu = bee_user_new(bee, ic, handle, BEE_USER_LOCAL);
193        }
194
195        /* Add the handle to the room userlist */
196        /* TODO: Use bu instead of a string */
197        c->in_room = g_list_append(c->in_room, g_strdup(handle));
198
199        if (bee->ui->chat_add_user) {
200                bee->ui->chat_add_user(bee, c, me ? bee->user : bu);
201        }
202
203        if (me) {
204                c->joined = 1;
205        }
206}
207
208void imcb_chat_remove_buddy(struct groupchat *c, const char *handle, const char *reason)
209{
210        struct im_connection *ic = c->ic;
211        bee_t *bee = ic->bee;
212        bee_user_t *bu = NULL;
213
214        if (set_getbool(&bee->set, "debug")) {
215                imcb_log(ic, "User %s removed from conversation %p (%s)", handle, c, reason ? reason : "");
216        }
217
218        /* It might be yourself! */
219        if (handle_is_self(ic, handle)) {
220                if (c->joined == 0) {
221                        return;
222                }
223
224                bu = bee->user;
225                c->joined = 0;
226        } else {
227                bu = bee_user_by_handle(bee, ic, handle);
228        }
229
230        if (bee->ui->chat_remove_user && bu) {
231                bee->ui->chat_remove_user(bee, c, bu, reason);
232        }
233}
234
235int bee_chat_msg(bee_t *bee, struct groupchat *c, const char *msg, int flags)
236{
237        struct im_connection *ic = c->ic;
238        char *buf = NULL;
239
240        if ((ic->flags & OPT_DOES_HTML) && (g_strncasecmp(msg, "<html>", 6) != 0)) {
241                buf = escape_html(msg);
242                msg = buf;
243        } else {
244                buf = g_strdup(msg);
245        }
246
247        ic->acc->prpl->chat_msg(c, buf, flags);
248        g_free(buf);
249
250        return 1;
251}
252
253struct groupchat *bee_chat_by_title(bee_t *bee, struct im_connection *ic, const char *title)
254{
255        struct groupchat *c;
256        GSList *l;
257
258        for (l = ic->groupchats; l; l = l->next) {
259                c = l->data;
260                if (strcmp(c->title, title) == 0) {
261                        return c;
262                }
263        }
264
265        return NULL;
266}
267
268void imcb_chat_invite(struct im_connection *ic, const char *name, const char *who, const char *msg)
269{
270        bee_user_t *bu = bee_user_by_handle(ic->bee, ic, who);
271
272        if (bu && ic->bee->ui->chat_invite) {
273                ic->bee->ui->chat_invite(ic->bee, bu, name, msg);
274        }
275}
Note: See TracBrowser for help on using the repository browser.