source: protocols/bee_chat.c @ 7e4f439c

Last change on this file since 7e4f439c was a33ee0f, checked in by jgeboski <jgeboski@…>, at 2016-09-20T03:39:05Z

Added an interface for the listing of existing chatrooms

Several protocols can provide a list of existing chatrooms that a user
is able join. This is crucial for the usage of several protocols, most
notably Purple and Facebook.

Plugins wishing to support this extended functionality must implement
the new prpl->chat_list() function. This implemented function will in
most cases send a remote request for the list of chatrooms. Once the
list of chatrooms is obtained, a bee_chat_info_t GSList must be created
and assigned to the im_connection->chatlist field. Then a call to the
bee_chat_list_finish() is needed to display the list to the user.

The chat list is maintained entirely by the plugin, so it is important
to ensure all pointers related to the chat list remain valid until the
chat list is set to NULL. This list is used internally by bitlbee to
calculate indexes, which then allows the user to join a chat with an
index, rather than some random identifier. It also important to ensure
the list is properly freed whenever it is updated, or when the account
is disconnect via the prpl->logout() function.

On the user interface side of things, the 'chat list' subcommand was
recommissioned. For a user to list the existing chat rooms:

chat list <account id>

Afterwards a user can join a chatroom in the list with its index. This
extends the functionality of the 'chat add' subcommand by adding in
support for the exclamation point operator to denote an index.

chat add <account id> !<index> [channel]

  • Property mode set to 100644
File size: 6.8 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}
276
277void bee_chat_list_finish(struct im_connection *ic)
278{
279        cmd_chat_list_finish(ic);
280}
Note: See TracBrowser for help on using the repository browser.