~ubuntu-branches/ubuntu/trusty/irssi-plugin-xmpp/trusty

« back to all changes in this revision

Viewing changes to src/core/xmpp-protocol.c

  • Committer: Bazaar Package Importer
  • Author(s): David Ammouial
  • Date: 2009-05-12 12:14:44 UTC
  • mfrom: (1.1.3 upstream) (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20090512121444-5jeho5h3zsy4oij7
Tags: 0.13+cvs20090406-1
* New CVS snapshot, built against irssi-dev 0.8.13:
  - New features and bugfixes.
  - Fix segfault when successfully identified (Closes: #521227).
  - Fix build error (Closes: #527697)
* Depend on irssi >=0.8.13, build-depend on irssi-dev >=0.8.13.
* Bump Standards-Version to 3.8.1 (no changes needed).
* Add INTERNAL to documentation files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * $Id: xmpp-protocol.c,v 1.55 2008/04/26 11:01:11 errtu Exp $
3
 
 *
4
 
 * Copyright (C) 2007 Colin DIDIER
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License version 2 as
8
 
 * published by the Free Software Foundation.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License along
16
 
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
 
 */
19
 
 
20
 
#include <sys/types.h>
21
 
#include <sys/utsname.h>
22
 
#include <string.h>
23
 
#include <time.h>
24
 
 
25
 
#include "module.h"
26
 
#include "settings.h"
27
 
#include "signals.h"
28
 
 
29
 
#include "xmpp-protocol.h"
30
 
#include "xmpp-servers.h"
31
 
#include "xmpp-channels.h"
32
 
#include "xmpp-queries.h"
33
 
#include "xmpp-rosters.h"
34
 
#include "xmpp-rosters-tools.h"
35
 
#include "xmpp-tools.h"
36
 
#include "xmpp-xep.h"
37
 
 
38
 
void
39
 
xmpp_send_message(XMPP_SERVER_REC *server, const char *dest,
40
 
    const char *message)
41
 
{
42
 
        LmMessage *msg;
43
 
        LmMessageNode *child;
44
 
        XMPP_ROSTER_RESOURCE_REC *resource;
45
 
        char *jid, *jid_recoded, *message_recoded;
46
 
 
47
 
        g_return_if_fail(IS_XMPP_SERVER(server));
48
 
        g_return_if_fail(dest != NULL);
49
 
        g_return_if_fail(message != NULL);
50
 
 
51
 
        jid = xmpp_rosters_resolve_name(server, dest);
52
 
        jid_recoded = xmpp_recode_out((jid != NULL) ? jid : dest);
53
 
 
54
 
        msg = lm_message_new_with_sub_type(jid_recoded,
55
 
            LM_MESSAGE_TYPE_MESSAGE, LM_MESSAGE_SUB_TYPE_CHAT);
56
 
        g_free(jid_recoded);
57
 
 
58
 
        message_recoded = xmpp_recode_out(message);
59
 
        lm_message_node_add_child(msg->node, "body", message_recoded);
60
 
        g_free(message_recoded);
61
 
 
62
 
        xmpp_rosters_find_user(server->roster, jid, NULL, &resource);
63
 
        if (resource != NULL && resource->composing_id != NULL) {
64
 
                child = lm_message_node_add_child(msg->node, "x", NULL);
65
 
                lm_message_node_set_attribute(child, XMLNS, XMLNS_EVENT);
66
 
                lm_message_node_add_child(child, "id", resource->composing_id);
67
 
                g_free_and_null(resource->composing_id);
68
 
        }
69
 
 
70
 
        lm_send(server, msg, NULL);
71
 
        lm_message_unref(msg);
72
 
 
73
 
        g_free(jid);
74
 
}
75
 
 
76
 
static void
77
 
send_service_unavailable(XMPP_SERVER_REC *server, const char *dest,
78
 
    const char *id)
79
 
{
80
 
        LmMessage *msg;
81
 
        LmMessageNode *child;
82
 
        char *recoded;
83
 
 
84
 
        g_return_if_fail(IS_XMPP_SERVER(server));
85
 
        g_return_if_fail(dest != NULL);
86
 
 
87
 
        recoded = xmpp_recode_out(dest);
88
 
        msg = lm_message_new_with_sub_type(recoded,
89
 
            LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_ERROR);
90
 
        g_free(recoded);
91
 
 
92
 
        if (id != NULL)
93
 
                lm_message_node_set_attribute(msg->node, "id", id);
94
 
 
95
 
        /* <error code='503' type='cancel'> */
96
 
        child = lm_message_node_add_child(msg->node, "error", NULL);
97
 
        lm_message_node_set_attribute(child, "code", "503");
98
 
        lm_message_node_set_attribute(child, "type", "cancel");
99
 
 
100
 
        /* <service-unavailable
101
 
         *    xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> */
102
 
        child = lm_message_node_add_child(child,
103
 
            "service-unavailable", NULL);
104
 
        lm_message_node_set_attribute(child, XMLNS, XMLNS_STANZAS);
105
 
 
106
 
        lm_send(server, msg, NULL);
107
 
        lm_message_unref(msg);
108
 
}
109
 
 
110
 
static void
111
 
sig_own_presence(XMPP_SERVER_REC *server, const int show, const char *status,
112
 
    const int priority)
113
 
{
114
 
        GSList *tmp;
115
 
        LmMessage *msg;
116
 
        const char *show_str, *status_tmp;
117
 
        char *status_recoded, *priority_str;
118
 
 
119
 
        g_return_if_fail(IS_XMPP_SERVER(server));
120
 
 
121
 
        status_tmp = server->away_reason;
122
 
        if (status == NULL && status_tmp != NULL
123
 
            && strcmp(status_tmp, " ") == 0)
124
 
                status_tmp = NULL; 
125
 
 
126
 
        if (!xmpp_presence_changed(show, server->show, status,
127
 
            status_tmp, priority, server->priority))
128
 
                return;
129
 
 
130
 
        switch (show) {
131
 
        case XMPP_PRESENCE_AWAY:
132
 
                show_str = xmpp_presence_show[XMPP_PRESENCE_AWAY];
133
 
                break;
134
 
 
135
 
        case XMPP_PRESENCE_CHAT:
136
 
                show_str = xmpp_presence_show[XMPP_PRESENCE_CHAT];
137
 
                break;
138
 
 
139
 
        case XMPP_PRESENCE_DND:
140
 
                show_str = xmpp_presence_show[XMPP_PRESENCE_DND];
141
 
                break;
142
 
 
143
 
        case XMPP_PRESENCE_XA:
144
 
                show_str = xmpp_presence_show[XMPP_PRESENCE_XA];
145
 
                break;
146
 
        
147
 
        case XMPP_PRESENCE_AVAILABLE:
148
 
        default:
149
 
                show_str = NULL;
150
 
        }
151
 
 
152
 
        /* away */
153
 
        if (show_str != NULL) {
154
 
                server->show = show;
155
 
                signal_emit("event 306", 2, server, server->jid);
156
 
 
157
 
        /* unaway */
158
 
        } else {
159
 
                server->show = XMPP_PRESENCE_AVAILABLE;
160
 
                if (server->usermode_away)
161
 
                        signal_emit("event 305", 2, server, server->jid);
162
 
        }
163
 
 
164
 
        g_free(server->away_reason);
165
 
        server->away_reason = g_strdup(status);
166
 
 
167
 
        status_recoded = xmpp_recode_out(server->away_reason);
168
 
        if (!xmpp_priority_out_of_bound(priority))
169
 
                server->priority = priority;
170
 
        priority_str = g_strdup_printf("%d", server->priority);
171
 
 
172
 
        /* send presence to the server */
173
 
        msg = lm_message_new(NULL, LM_MESSAGE_TYPE_PRESENCE);
174
 
        if (show_str != NULL)
175
 
                lm_message_node_add_child(msg->node, "show", show_str);
176
 
        if (status_recoded != NULL)
177
 
                lm_message_node_add_child(msg->node, "status", status_recoded);
178
 
        lm_message_node_add_child(msg->node, "priority", priority_str);
179
 
        lm_send(server, msg, NULL);
180
 
        lm_message_unref(msg);
181
 
 
182
 
        /* send presence to channels */
183
 
        msg = lm_message_new(NULL, LM_MESSAGE_TYPE_PRESENCE);
184
 
        if (show_str != NULL)
185
 
                lm_message_node_add_child(msg->node, "show", show_str);
186
 
        if (status_recoded != NULL)
187
 
                lm_message_node_add_child(msg->node, "status", status_recoded);
188
 
 
189
 
        for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
190
 
                XMPP_CHANNEL_REC *channel;
191
 
                char *dest_recoded;
192
 
                        
193
 
                channel = XMPP_CHANNEL(tmp->data);
194
 
                if (channel == NULL || !channel->joined)
195
 
                        continue;
196
 
 
197
 
                dest_recoded = xmpp_recode_out(channel->name);
198
 
                lm_message_node_set_attribute(msg->node, "to", dest_recoded);
199
 
                g_free(dest_recoded);
200
 
 
201
 
                lm_send(server, msg, NULL);
202
 
        }
203
 
 
204
 
        lm_message_unref(msg);
205
 
        g_free(status_recoded);
206
 
        g_free(priority_str);
207
 
 
208
 
        if (server->usermode_away && server->away_reason == NULL)
209
 
                server->away_reason = g_strdup(" ");
210
 
}
211
 
 
212
 
 
213
 
/*
214
 
 * XEP-0203: Delayed Delivery
215
 
 * XEP-0091: Delayed Delivery (Obsolete)
216
 
 */
217
 
 
218
 
#define MAX_LEN_TIMESTAMP 255
219
 
 
220
 
static char *
221
 
get_timestamp(LmMessageNode *node)
222
 
{
223
 
        LmMessageNode *child;
224
 
        const char *stamp;
225
 
        char str[MAX_LEN_TIMESTAMP];
226
 
        struct tm tm;
227
 
 
228
 
        /* XEP-0203: Delayed Delivery
229
 
         * <delay xmlns="urn:xmpp:delay" from="jid" stamp="stamp">jid</delay> */
230
 
        if ((child = lm_tools_message_node_find(node, "x", XMLNS,
231
 
            XMLNS_DELAYED_DELIVERY)) != NULL) {
232
 
 
233
 
                stamp = lm_message_node_get_attribute(child, "stamp");
234
 
                if (stamp != NULL
235
 
                    && strptime(stamp, "%Y-%m-%dT%T", &tm) == NULL)
236
 
                        return g_strdup("");
237
 
 
238
 
                /* TODO handle timezone */
239
 
 
240
 
        /* XEP-0091: Delayed Delivery (Obsolete)
241
 
         * <x xmlns="jabber:x:delay" from="jid" stamp="stamp">jid</x> */
242
 
        } else if ((child = lm_tools_message_node_find(node, "x", XMLNS,
243
 
            XMLNS_DELAYED_DELIVERY_OLD)) != NULL) {
244
 
 
245
 
                stamp = lm_message_node_get_attribute(child, "stamp");
246
 
                if (stamp != NULL
247
 
                    && strptime(stamp, "%Y%m%dT%T", &tm) == NULL)
248
 
                        return g_strdup("");
249
 
 
250
 
        } else
251
 
                return NULL;
252
 
 
253
 
        if (strftime(str, MAX_LEN_TIMESTAMP,
254
 
            settings_get_str("xmpp_timestamp_format"), &tm) == 0)
255
 
                return g_strdup("");
256
 
        str[MAX_LEN_TIMESTAMP-1] = '\0';
257
 
        return g_strdup(str);
258
 
}
259
 
 
260
 
 
261
 
/*
262
 
 * Incoming messages handlers
263
 
 */
264
 
 
265
 
static LmHandlerResult
266
 
handle_message(LmMessageHandler *handler, LmConnection *connection,
267
 
    LmMessage *msg, gpointer user_data)
268
 
{
269
 
        XMPP_SERVER_REC *server;
270
 
        XMPP_CHANNEL_REC *channel;
271
 
        LmMessageNode *child, *subchild;
272
 
        char *jid, *text, *stamp;
273
 
 
274
 
        if ((server = XMPP_SERVER(user_data)) == NULL)
275
 
                return LM_HANDLER_RESULT_REMOVE_MESSAGE;
276
 
 
277
 
        jid = xmpp_recode_in(lm_message_node_get_attribute(msg->node, "from"));
278
 
 
279
 
        switch (lm_message_get_sub_type(msg)) {
280
 
        case LM_MESSAGE_SUB_TYPE_ERROR:
281
 
 
282
 
                /* MUC */
283
 
                text = xmpp_extract_channel(jid);
284
 
                channel = xmpp_channel_find(server, text);
285
 
                g_free(text);
286
 
                if (channel != NULL) {
287
 
                        const char *code;
288
 
 
289
 
                        child = lm_message_node_get_child(msg->node, "error");
290
 
                        if (child == NULL)
291
 
                                goto out;
292
 
 
293
 
                        code = lm_message_node_get_attribute(child, "code");
294
 
                        if (code == NULL)
295
 
                                goto out;
296
 
 
297
 
                        if (g_ascii_strcasecmp(code, "401") == 0)
298
 
                                signal_emit("xmpp channel error", 2,
299
 
                                    channel, "not allowed");
300
 
 
301
 
                /* general */
302
 
                } else {
303
 
 
304
 
                        child = lm_message_node_get_child(msg->node, "body");
305
 
                        if (child == NULL)
306
 
                                signal_emit("message xmpp error", 2, server, jid);
307
 
                        else {
308
 
                                text = xmpp_recode_in(child->value);
309
 
                                signal_emit("message xmpp error", 3, server, jid,
310
 
                                    text);
311
 
                                g_free(text);
312
 
                        }
313
 
                }
314
 
 
315
 
                break;
316
 
 
317
 
        case LM_MESSAGE_SUB_TYPE_NOT_SET:
318
 
                if ((child = lm_tools_message_node_find(msg->node,
319
 
                    "x", XMLNS, XMLNS_MUC)) != NULL) {
320
 
 
321
 
                        /* invite */
322
 
                        if ((child = lm_message_node_get_child(child,
323
 
                            "invite")) != NULL) {
324
 
                                char *room, *by, *password, *reason;
325
 
                                const char *to;
326
 
 
327
 
                                room = by = NULL;
328
 
 
329
 
                                subchild = lm_message_node_get_child(
330
 
                                    child->parent, "password");
331
 
                                password = subchild == NULL ? NULL :
332
 
                                    xmpp_recode_in(subchild->value);
333
 
 
334
 
                                subchild = lm_message_node_get_child(
335
 
                                    child, "reason");
336
 
                                reason = subchild == NULL ? NULL :
337
 
                                    xmpp_recode_in(subchild->value);
338
 
 
339
 
                                to = lm_message_node_get_attribute(child,
340
 
                                     "to");
341
 
                                if (to != NULL) {
342
 
                                        room = xmpp_recode_in(to);
343
 
                                        signal_emit("xmpp invite", 5, server,
344
 
                                            room, jid, password, reason);
345
 
                                        g_free(room);
346
 
                                }
347
 
 
348
 
                                g_free(reason); 
349
 
                                g_free(password);
350
 
                        }
351
 
                }
352
 
 
353
 
        case LM_MESSAGE_SUB_TYPE_HEADLINE:
354
 
        case LM_MESSAGE_SUB_TYPE_NORMAL:
355
 
        case LM_MESSAGE_SUB_TYPE_CHAT:
356
 
        /* rfc3921.txt states in 2.1.1. Types of Message:
357
 
         *   if an application receives a message with no 'type' attribute or the
358
 
         *   application does not understand the value of the 'type' attribute
359
 
         *   provided, it MUST consider the message to be of type "normal"
360
 
         * Thus default belongs here, whre LM_MESSAGE_SUB_TYPE_NORMAL is
361
 
         */
362
 
        default:
363
 
                /* XEP-0022: Message Events */
364
 
                child = lm_message_node_get_child(msg->node, "x");
365
 
                if (child != NULL) {
366
 
                        XMPP_QUERY_REC *query;
367
 
 
368
 
                        subchild = lm_message_node_get_child(child,
369
 
                            "composing");
370
 
                        
371
 
                        query = xmpp_query_find(server, jid);
372
 
                        if (query != NULL)
373
 
                                query->composing_visible = (subchild != NULL);
374
 
 
375
 
                        if (subchild != NULL)
376
 
                                signal_emit("xmpp composing show", 2, server,
377
 
                                    jid);
378
 
                        else
379
 
                                signal_emit("xmpp composing hide", 2, server,
380
 
                                    jid);
381
 
                }
382
 
 
383
 
                stamp = get_timestamp(msg->node);
384
 
 
385
 
                /* <subject>text</subject> */
386
 
                child = lm_message_node_get_child(msg->node, "subject");
387
 
                if (child != NULL && child->value != NULL) {
388
 
                        text = xmpp_recode_in(child->value);
389
 
 
390
 
                        if (stamp != NULL)
391
 
                                signal_emit("message xmpp history", 6,
392
 
                                    server, text, jid, jid, stamp,
393
 
                                    GINT_TO_POINTER(SEND_TARGET_NICK));
394
 
                        else
395
 
                                signal_emit("message private", 4, server,
396
 
                                    text, jid, jid);
397
 
 
398
 
                        g_free(text);
399
 
                }
400
 
 
401
 
                /* <body>text</body> */
402
 
                child = lm_message_node_get_child(msg->node, "body");
403
 
                if (child != NULL && child->value != NULL) {
404
 
                        text = xmpp_recode_in(child->value);
405
 
 
406
 
                        if (stamp != NULL) {
407
 
                                if (g_ascii_strncasecmp(text, "/me ", 4) == 0)
408
 
                                        signal_emit(
409
 
                                            "message xmpp history action", 6,
410
 
                                            server, text+4, jid, jid, stamp,
411
 
                                            GINT_TO_POINTER(SEND_TARGET_NICK));
412
 
                                else
413
 
                                        signal_emit("message xmpp history", 6,
414
 
                                            server, text, jid, jid, stamp,
415
 
                                            GINT_TO_POINTER(SEND_TARGET_NICK));
416
 
                        } else {
417
 
                                if (g_ascii_strncasecmp(text, "/me ", 4) == 0)
418
 
                                        signal_emit("message xmpp action", 5,
419
 
                                            server, text+4, jid, jid,
420
 
                                            GINT_TO_POINTER(SEND_TARGET_NICK));
421
 
                                else
422
 
                                        signal_emit("message private", 4, server,
423
 
                                            text, jid, jid);
424
 
                        }
425
 
 
426
 
                        g_free(text);
427
 
                }
428
 
 
429
 
                g_free(stamp);
430
 
                break;
431
 
 
432
 
        case LM_MESSAGE_SUB_TYPE_GROUPCHAT:
433
 
                /* <subject>text</subject> */
434
 
                child = lm_message_node_get_child(msg->node, "subject");
435
 
                if (child != NULL) {
436
 
                        XMPP_CHANNEL_REC *channel;
437
 
                        char *channel_name, *nick;
438
 
 
439
 
                        channel_name = xmpp_extract_channel(jid);
440
 
                        nick =  xmpp_extract_resource(jid);
441
 
 
442
 
                        channel = xmpp_channel_find(server, channel_name);
443
 
                        if (channel == NULL) {
444
 
                                g_free(channel_name);
445
 
                                g_free(nick);
446
 
                                goto out;
447
 
                        }
448
 
 
449
 
                        text = xmpp_recode_in(child->value);
450
 
                        signal_emit("xmpp channel topic", 3, channel, text,
451
 
                            nick);
452
 
                        g_free(text);
453
 
 
454
 
                        g_free(channel_name);
455
 
                        g_free(nick);
456
 
                }
457
 
                
458
 
                /* <body>text</body> */
459
 
                child = lm_message_node_get_child(msg->node, "body");
460
 
                if (child != NULL && child->value != NULL) {
461
 
                        XMPP_CHANNEL_REC *channel;
462
 
                        char *channel_name, *nick;
463
 
                        gboolean own, action;
464
 
 
465
 
                        channel_name = xmpp_extract_channel(jid);
466
 
                        nick =  xmpp_extract_resource(jid);
467
 
                        if (nick == NULL) {
468
 
                                g_free(channel_name);
469
 
                                goto out;
470
 
                        }
471
 
 
472
 
                        channel = xmpp_channel_find(server, channel_name);
473
 
                        own = channel != NULL
474
 
                            && strcmp(nick, channel->nick) == 0 ? TRUE : FALSE;
475
 
 
476
 
                        text = xmpp_recode_in(child->value);
477
 
                        action = g_ascii_strncasecmp(text, "/me ", 4) == 0 ?
478
 
                            TRUE : FALSE;
479
 
                        stamp = get_timestamp(msg->node);
480
 
 
481
 
                        if (stamp != NULL) {
482
 
                                if (action)
483
 
                                        signal_emit(
484
 
                                            "message xmpp history action", 6,
485
 
                                            server, text+4, nick, channel_name,
486
 
                                            stamp,
487
 
                                            GINT_TO_POINTER(SEND_TARGET_CHANNEL));
488
 
                                else
489
 
                                        signal_emit("message xmpp history", 6,
490
 
                                            server, text, nick, channel_name,
491
 
                                            stamp,
492
 
                                            GINT_TO_POINTER(SEND_TARGET_CHANNEL));
493
 
                        } else if (own) {
494
 
                                if (action)
495
 
                                        signal_emit("message xmpp own_action", 4,
496
 
                                            server, text+4, channel_name,
497
 
                                            GINT_TO_POINTER(SEND_TARGET_CHANNEL));
498
 
                                else
499
 
                                        signal_emit("message xmpp own_public", 3,
500
 
                                            server, text, channel_name);
501
 
                        } else {
502
 
                                if (action)
503
 
                                        signal_emit("message xmpp action", 5,
504
 
                                            server, text+4, nick, channel_name,
505
 
                                            GINT_TO_POINTER(SEND_TARGET_CHANNEL));
506
 
                                else
507
 
                                        signal_emit("message public", 5,
508
 
                                            server, text, nick, "",
509
 
                                            channel_name);
510
 
                        }
511
 
 
512
 
                        g_free(text);
513
 
                        g_free(stamp);
514
 
                        g_free(channel_name);
515
 
                        g_free(nick);
516
 
                }
517
 
 
518
 
                break;
519
 
        }
520
 
 
521
 
out:
522
 
        g_free(jid);
523
 
        return LM_HANDLER_RESULT_REMOVE_MESSAGE;
524
 
}
525
 
 
526
 
static LmHandlerResult
527
 
handle_presence(LmMessageHandler *handler, LmConnection *connection,
528
 
    LmMessage *msg, gpointer user_data)
529
 
{
530
 
        XMPP_SERVER_REC *server;
531
 
        XMPP_CHANNEL_REC *channel;
532
 
        LmMessageNode *child, *subchild, *show, *priority;
533
 
        char *jid, *text;
534
 
 
535
 
        if ((server = XMPP_SERVER(user_data)) == NULL)
536
 
                return LM_HANDLER_RESULT_REMOVE_MESSAGE;
537
 
 
538
 
        jid = xmpp_recode_in(lm_message_node_get_attribute(msg->node, "from"));
539
 
 
540
 
        switch (lm_message_get_sub_type(msg)) {
541
 
        case LM_MESSAGE_SUB_TYPE_ERROR:
542
 
 
543
 
                /* MUC */
544
 
                text = xmpp_extract_channel(jid);
545
 
                channel = xmpp_channel_find(server, text);
546
 
                g_free(text);
547
 
                if (channel != NULL) {
548
 
                        const char *code;
549
 
                        char *nick = xmpp_extract_nick(jid);
550
 
 
551
 
                        /* <error code='code'/> */
552
 
                        child = lm_message_node_get_child(msg->node, "error");
553
 
                        if (child == NULL)
554
 
                                goto out;
555
 
                        code = lm_message_node_get_attribute(child, "code");
556
 
                        if (code == NULL)
557
 
                                goto out;
558
 
 
559
 
                        if (!channel->joined) {
560
 
                                /* <error code='401'/> */
561
 
                                if (strcmp(code, "401") == 0)
562
 
                                        signal_emit("xmpp channel joinerror", 2,
563
 
                                            channel, XMPP_CHANNELS_ERROR_PASSWORD_INVALID_OR_MISSING);
564
 
                                /* <error code='403'/> */
565
 
                                else if (strcmp(code, "403") == 0)
566
 
                                        signal_emit("xmpp channel joinerror", 2,
567
 
                                            channel, XMPP_CHANNELS_ERROR_USER_BANNED);
568
 
                                /* <error code='404'/> */
569
 
                                else if (strcmp(code, "404") == 0)
570
 
                                        signal_emit("xmpp channel joinerror", 2,
571
 
                                            channel, XMPP_CHANNELS_ERROR_ROOM_NOT_FOUND);
572
 
                                /* <error code='405'/> */
573
 
                                else if (strcmp(code, "405") == 0)
574
 
                                        signal_emit("xmpp channel joinerror", 2,
575
 
                                            channel, XMPP_CHANNELS_ERROR_ROOM_CREATION_RESTRICTED);
576
 
                                /* <error code='406'/> */
577
 
                                else if (strcmp(code, "406") == 0)
578
 
                                        signal_emit("xmpp channel joinerror", 2,
579
 
                                            channel, XMPP_CHANNELS_ERROR_USE_RESERVED_ROOM_NICK);
580
 
                                /* <error code='407'/> */
581
 
                                else if (strcmp(code, "407") == 0)
582
 
                                        signal_emit("xmpp channel joinerror", 2,
583
 
                                            channel, XMPP_CHANNELS_ERROR_NOT_ON_MEMBERS_LIST);
584
 
                                /* <error code='409'/> */
585
 
                                else if (strcmp(code, "409") == 0)
586
 
                                        signal_emit("xmpp channel joinerror", 2,
587
 
                                            channel, XMPP_CHANNELS_ERROR_NICK_IN_USE);
588
 
                                /* <error code='503'/> */
589
 
                                else if (strcmp(code, "503") == 0)
590
 
                                        signal_emit("xmpp channel joinerror", 2,
591
 
                                            channel, XMPP_CHANNELS_ERROR_MAXIMUM_USERS_REACHED);
592
 
                        } else {
593
 
                                /* <error code='409'/> */
594
 
                                if (strcmp(code, "409") == 0)
595
 
                                        signal_emit("message xmpp channel nick in use",
596
 
                                            2, channel, nick);
597
 
                        }
598
 
 
599
 
                        g_free(nick);
600
 
 
601
 
                /* general */
602
 
                } else
603
 
                        signal_emit("xmpp presence error", 2, server, jid);
604
 
 
605
 
                break;
606
 
 
607
 
        case LM_MESSAGE_SUB_TYPE_SUBSCRIBE:
608
 
                /* <status>text</status> */
609
 
                child = lm_message_node_get_child(msg->node, "status");
610
 
                text = (child != NULL) ? xmpp_recode_in(child->value) : NULL;
611
 
                signal_emit("xmpp presence subscribe", 3, server, jid, text);
612
 
                g_free(text);
613
 
                break;
614
 
 
615
 
        case LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE:
616
 
                signal_emit("xmpp presence unsubscribe", 2, server, jid);
617
 
                break;
618
 
 
619
 
        case LM_MESSAGE_SUB_TYPE_SUBSCRIBED:
620
 
                signal_emit("xmpp presence subscribed", 2, server, jid);
621
 
                break;
622
 
 
623
 
        case LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED:
624
 
                signal_emit("xmpp presence unsubscribed", 2, server, jid);
625
 
                break;
626
 
 
627
 
        case LM_MESSAGE_SUB_TYPE_AVAILABLE:
628
 
 
629
 
                /* MUC */
630
 
                text = xmpp_extract_channel(jid);
631
 
                channel = xmpp_channel_find(server, text);
632
 
                g_free(text);
633
 
                if (channel != NULL) {
634
 
                        const char *item_affiliation, *item_role;
635
 
                        char *nick, *item_jid, *item_nick;
636
 
                        gboolean own, forced, created;
637
 
 
638
 
                        nick = xmpp_extract_nick(jid);
639
 
                        item_affiliation = item_role = NULL;
640
 
                        item_jid = item_nick = NULL;
641
 
                        own = forced = created = FALSE;
642
 
 
643
 
                        /* <x xmlns='http://jabber.org/protocol/muc#user'> */
644
 
                        child = lm_tools_message_node_find(msg->node, "x",
645
 
                            XMLNS, XMLNS_MUC_USER);
646
 
                        if (child != NULL) {
647
 
 
648
 
                                if ((subchild = lm_message_node_get_child(
649
 
                                    child, "item")) != NULL) {
650
 
                                        /* <item affiliation='item_affiliation'
651
 
                                         *     role='item_role'
652
 
                                         *     nick='item_nick'/> */
653
 
                                        item_affiliation =
654
 
                                            lm_message_node_get_attribute(
655
 
                                            subchild, "affiliation");
656
 
                                        item_role =
657
 
                                            lm_message_node_get_attribute(
658
 
                                            subchild, "role");
659
 
                                        item_jid = xmpp_recode_in(
660
 
                                            lm_message_node_get_attribute(
661
 
                                            subchild, "jid"));
662
 
                                        item_nick = xmpp_recode_in(
663
 
                                            lm_message_node_get_attribute(
664
 
                                            subchild, "nick"));
665
 
 
666
 
                                        /* <status code='110'/> */
667
 
                                        own = lm_tools_message_node_find(
668
 
                                            child, "status", "code", "110")
669
 
                                            != NULL ? TRUE : FALSE;
670
 
                                        /* <status code='210'/> */
671
 
                                        forced = lm_tools_message_node_find(
672
 
                                            child, "status", "code", "210")
673
 
                                            != NULL ? TRUE : FALSE;
674
 
                                        /* <status code='201'/> */
675
 
                                        created = lm_tools_message_node_find(
676
 
                                            child, "status", "code", "201")
677
 
                                            != NULL ? TRUE : FALSE;
678
 
                                }
679
 
                        }
680
 
 
681
 
                        if (item_nick != NULL) {
682
 
                                g_free(nick);
683
 
                                nick = item_nick;
684
 
                        }
685
 
 
686
 
                        if (created) {
687
 
                                /* TODO send disco
688
 
                                 * show event IRCTXT_CHANNEL_CREATED */
689
 
                        }
690
 
 
691
 
                        if (own || strcmp(nick, channel->nick) == 0)
692
 
                                signal_emit("xmpp channel nick own_event", 6,
693
 
                                    channel, nick, item_jid, item_affiliation,
694
 
                                    item_role, forced);
695
 
                        else
696
 
                                signal_emit("xmpp channel nick event", 5,
697
 
                                    channel, nick, item_jid, item_affiliation,
698
 
                                    item_role);
699
 
 
700
 
                        /* <status>text</status> */
701
 
                        child = lm_message_node_get_child(msg->node, "status");
702
 
                        text = child != NULL ?
703
 
                            xmpp_recode_in(child->value) : NULL;
704
 
                        /* <show>show</show> */
705
 
                         show = lm_message_node_get_child(msg->node, "show");
706
 
 
707
 
                        signal_emit("xmpp channel nick presence", 4, channel,
708
 
                            nick, (show != NULL) ? show->value : NULL, text);
709
 
 
710
 
                        g_free(item_jid);
711
 
                        g_free(text);
712
 
                        g_free(nick);
713
 
 
714
 
                /* general */
715
 
                } else {
716
 
                        /* <status>text</status> */
717
 
                        child = lm_message_node_get_child(msg->node, "status");
718
 
                        text = (child != NULL) ?
719
 
                            xmpp_recode_in(child->value) : NULL;
720
 
                        /* <show>show</show> */
721
 
                        show = lm_message_node_get_child(msg->node, "show");
722
 
                        /* <priority>priority</priority> */
723
 
                        priority = lm_message_node_get_child(msg->node,
724
 
                            "priority");
725
 
 
726
 
                        signal_emit("xmpp presence update", 5, server, jid,
727
 
                            (show != NULL) ? show->value : NULL, text,
728
 
                            (priority != NULL) ? priority->value : NULL);
729
 
 
730
 
                        g_free(text);
731
 
                }
732
 
 
733
 
                break;
734
 
 
735
 
        case LM_MESSAGE_SUB_TYPE_UNAVAILABLE:
736
 
 
737
 
                /* MUC */
738
 
                text = xmpp_extract_channel(jid);
739
 
                channel = xmpp_channel_find(server, text);
740
 
                g_free(text);
741
 
                if (channel != NULL) {
742
 
                        const char *status_code;
743
 
                        char *nick, *reason, *actor, *item_nick;
744
 
 
745
 
                        nick = xmpp_extract_nick(jid);
746
 
                        status_code = NULL;
747
 
                        reason = actor = item_nick = NULL;
748
 
 
749
 
                        /* <x xmlns='http://jabber.org/protocol/muc#user'> */
750
 
                        child = lm_tools_message_node_find(msg->node, "x",
751
 
                            XMLNS, XMLNS_MUC_USER);
752
 
                        if (child != NULL) {
753
 
 
754
 
                                /* <status code='status_code'/> */
755
 
                                if ((subchild = lm_message_node_get_child(
756
 
                                    child, "status")) != NULL)
757
 
                                        status_code =
758
 
                                            lm_message_node_get_attribute(
759
 
                                            subchild, "code");
760
 
 
761
 
                                /* <item nick='item_nick'> */
762
 
                                if ((child = lm_message_node_get_child(
763
 
                                    child, "item")) != NULL) {
764
 
                                        item_nick = xmpp_recode_in(
765
 
                                            lm_message_node_get_attribute(
766
 
                                            child, "nick"));
767
 
 
768
 
                                        /* <reason>reason</reason>*/
769
 
                                        if ((subchild =
770
 
                                            lm_message_node_get_child(child,
771
 
                                            "reason")) != NULL)
772
 
                                                reason = xmpp_recode_in(
773
 
                                                    subchild->value);
774
 
 
775
 
                                        /* <actor jid='actor'/> */
776
 
                                        if ((subchild =
777
 
                                            lm_message_node_get_child(child,
778
 
                                            "actor")) != NULL)
779
 
                                                actor = xmpp_recode_in(
780
 
                                                    lm_message_node_get_attribute(
781
 
                                                    subchild, "jid"));
782
 
                                }
783
 
                        }
784
 
                        
785
 
                        if (status_code != NULL) {
786
 
 
787
 
                                /* <status code='303'/> */
788
 
                                if (g_ascii_strcasecmp(status_code,
789
 
                                    "303") == 0 && item_nick != NULL)
790
 
                                        signal_emit("xmpp channel nick",
791
 
                                            5, channel, nick, item_nick);
792
 
 
793
 
                                /* <status code='307'/> */
794
 
                                else if (g_ascii_strcasecmp(status_code,
795
 
                                    "307") == 0)
796
 
                                        signal_emit("xmpp channel nick kicked",
797
 
                                            4, channel, nick, actor, reason);
798
 
                                        
799
 
                                /* ban: <status code='301'/> */
800
 
                                else if (g_ascii_strcasecmp(status_code,
801
 
                                    "301") == 0)
802
 
                                        signal_emit("xmpp channel nick kicked",
803
 
                                            4, channel, nick, actor, reason);
804
 
 
805
 
                        } else {
806
 
                                /* <status>text</status> */
807
 
                                child = lm_message_node_get_child(msg->node,
808
 
                                    "status");
809
 
                                text = (child != NULL) ?
810
 
                                    xmpp_recode_in(child->value) : NULL;
811
 
 
812
 
                                signal_emit("xmpp channel nick part", 3,
813
 
                                    channel, nick, text);
814
 
 
815
 
                                g_free(text);
816
 
                        }
817
 
 
818
 
                        g_free(item_nick);
819
 
                        g_free(reason);
820
 
                        g_free(actor);
821
 
                        g_free(nick);
822
 
 
823
 
                /* general */
824
 
                } else {
825
 
                        /* <status>text</status> */
826
 
                        child = lm_message_node_get_child(msg->node, "status");
827
 
                        text = (child != NULL) ?
828
 
                            xmpp_recode_in(child->value) : NULL;
829
 
 
830
 
                        signal_emit("xmpp presence unavailable", 3, server,
831
 
                            jid, text);
832
 
 
833
 
                        g_free(text);
834
 
                }
835
 
 
836
 
                break;
837
 
 
838
 
        default:
839
 
                break;
840
 
        }
841
 
 
842
 
out:
843
 
        g_free(jid);
844
 
        return LM_HANDLER_RESULT_REMOVE_MESSAGE;
845
 
}
846
 
 
847
 
static LmHandlerResult
848
 
handle_iq(LmMessageHandler *handler, LmConnection *connection,
849
 
    LmMessage *msg, gpointer user_data)
850
 
{
851
 
        XMPP_SERVER_REC *server;
852
 
        XMPP_CHANNEL_REC *channel;
853
 
        LmMessageNode *child;
854
 
        const char *id;
855
 
        char *jid, *text;
856
 
 
857
 
        if ((server = XMPP_SERVER(user_data)) == NULL)
858
 
                return LM_HANDLER_RESULT_REMOVE_MESSAGE;
859
 
 
860
 
        jid = xmpp_recode_in(lm_message_node_get_attribute(msg->node, "from"));
861
 
        id = lm_message_node_get_attribute(msg->node, "id");
862
 
 
863
 
        switch (lm_message_get_sub_type(msg)) {
864
 
        case LM_MESSAGE_SUB_TYPE_ERROR:
865
 
                if ((child = lm_message_node_get_child(msg->node,
866
 
                    "error")) != NULL) {
867
 
                        const char *code;
868
 
 
869
 
                        if ((code = lm_message_node_get_attribute(child,
870
 
                            "code")) == NULL)
871
 
                                goto out;
872
 
                        
873
 
                        /* from MUC */
874
 
                        text = xmpp_extract_channel(jid);
875
 
                        channel = xmpp_channel_find(server, text);
876
 
                        g_free(text);
877
 
                        if (channel != NULL) {
878
 
                                /* TODO */
879
 
 
880
 
                        /* from others */
881
 
                        } else {
882
 
                                /* TODO */
883
 
                        }
884
 
 
885
 
                } 
886
 
 
887
 
                break;
888
 
 
889
 
        case LM_MESSAGE_SUB_TYPE_GET:
890
 
                /* XEP-0092: Software Version */
891
 
                if (lm_tools_message_node_find(msg->node,
892
 
                    "query", XMLNS, XMLNS_VERSION) != NULL)
893
 
                        xep_version_send(server, jid, id);
894
 
 
895
 
                else
896
 
                        /* <service-unavailable/> */
897
 
                        send_service_unavailable(server, jid, id);
898
 
 
899
 
                break;
900
 
 
901
 
        case LM_MESSAGE_SUB_TYPE_RESULT:
902
 
                if ((child = lm_tools_message_node_find(msg->node,
903
 
                    "query", XMLNS, XMLNS_ROSTER)) != NULL)
904
 
                        signal_emit("xmpp roster update", 2, server, child);
905
 
 
906
 
                /* XEP-0092: Software Version */
907
 
                else if ((child = lm_tools_message_node_find(msg->node,
908
 
                    "query", XMLNS, XMLNS_VERSION)) != NULL)
909
 
                        xep_version_handle(server, jid, child);
910
 
 
911
 
                /* XEP-0054: vcard-temp */
912
 
                else if ((child = lm_tools_message_node_find(msg->node,
913
 
                    "vCard", XMLNS, XMLNS_VCARD)) != NULL)
914
 
                        xep_vcard_handle(server, jid, child);
915
 
 
916
 
                /* XEP-0030: Service Discovery */
917
 
                else if ((child = lm_tools_message_node_find(msg->node,
918
 
                    "query", XMLNS, XMLNS_DISCO_INFO)) != NULL) {
919
 
 
920
 
                        /* from MUC */
921
 
                        text = xmpp_extract_channel(jid);
922
 
                        channel = xmpp_channel_find(server, text);
923
 
                        g_free(text);
924
 
                        if (channel != NULL)
925
 
                                signal_emit("xmpp channel disco", 2, channel,
926
 
                                    child);
927
 
                        
928
 
                        /* from server */
929
 
                        else if (strcmp(jid, server->host) == 0)
930
 
                                signal_emit("xmpp server disco", 2, server,
931
 
                                    child);
932
 
                        
933
 
                        /* from other */
934
 
                        else {
935
 
                                /* TODO */
936
 
                        }
937
 
 
938
 
                } else
939
 
                        /* XEP-0199: XMPP Ping */
940
 
                        signal_emit("xmpp ping handle", 3, server, jid,
941
 
                            lm_message_node_get_attribute(msg->node, "id"));
942
 
                
943
 
                break;
944
 
 
945
 
        case LM_MESSAGE_SUB_TYPE_SET :
946
 
                if ((child = lm_tools_message_node_find(msg->node,
947
 
                    "query", XMLNS, XMLNS_ROSTER)) != NULL)
948
 
                        signal_emit("xmpp roster update", 2, server, child);
949
 
 
950
 
                break;
951
 
        
952
 
        default:
953
 
                break;
954
 
        }
955
 
 
956
 
out:
957
 
        g_free(jid);
958
 
        return LM_HANDLER_RESULT_REMOVE_MESSAGE;
959
 
}
960
 
 
961
 
static void
962
 
unregister_handlers(XMPP_SERVER_REC *server)
963
 
{
964
 
        if (!IS_XMPP_SERVER(server))
965
 
                return;
966
 
 
967
 
        /* unregister handlers */
968
 
        if (server->hmessage != NULL) {
969
 
                if (lm_message_handler_is_valid(server->hmessage))
970
 
                        lm_message_handler_invalidate(server->hmessage);
971
 
                lm_message_handler_unref(server->hmessage);
972
 
                server->hmessage = NULL;
973
 
        }
974
 
 
975
 
        if (server->hpresence != NULL) {
976
 
                if (lm_message_handler_is_valid(server->hpresence))
977
 
                        lm_message_handler_invalidate(server->hpresence);
978
 
                lm_message_handler_unref(server->hpresence);
979
 
                server->hpresence = NULL;
980
 
        }
981
 
 
982
 
        if (server->hiq != NULL) {
983
 
                if (lm_message_handler_is_valid(server->hiq))
984
 
                        lm_message_handler_invalidate(server->hiq);
985
 
                lm_message_handler_unref(server->hiq);
986
 
                server->hiq = NULL;
987
 
        }
988
 
}
989
 
 
990
 
static void
991
 
register_handlers(XMPP_SERVER_REC *server)
992
 
{
993
 
        if (!IS_XMPP_SERVER(server))
994
 
                return;
995
 
 
996
 
        if (server->hmessage != NULL || server->hpresence != NULL ||
997
 
            server->hiq != NULL)
998
 
                unregister_handlers(server);
999
 
 
1000
 
        /* handle message */
1001
 
        server->hmessage = lm_message_handler_new(
1002
 
            (LmHandleMessageFunction)handle_message, (gpointer)server,
1003
 
            NULL);
1004
 
        lm_connection_register_message_handler(server->lmconn,
1005
 
            server->hmessage, LM_MESSAGE_TYPE_MESSAGE,
1006
 
            LM_HANDLER_PRIORITY_NORMAL);
1007
 
 
1008
 
        /* handle presence */
1009
 
        server->hpresence = lm_message_handler_new(
1010
 
            (LmHandleMessageFunction)handle_presence, (gpointer)server,
1011
 
            NULL);
1012
 
        lm_connection_register_message_handler(server->lmconn,
1013
 
            server->hpresence, LM_MESSAGE_TYPE_PRESENCE,
1014
 
            LM_HANDLER_PRIORITY_NORMAL);
1015
 
 
1016
 
        /* handle iq */
1017
 
        server->hiq = lm_message_handler_new(
1018
 
            (LmHandleMessageFunction)handle_iq, (gpointer)server,
1019
 
            NULL);
1020
 
        lm_connection_register_message_handler(server->lmconn,
1021
 
            server->hiq, LM_MESSAGE_TYPE_IQ,
1022
 
            LM_HANDLER_PRIORITY_NORMAL);
1023
 
 
1024
 
        if (settings_get_bool("xmpp_raw_window"))
1025
 
                signal_emit("xmpp register raw handler", 1, server);
1026
 
}
1027
 
 
1028
 
static LmHandlerResult
1029
 
handle_raw(LmMessageHandler *handler, LmConnection *connection,
1030
 
   LmMessage *msg, gpointer user_data)
1031
 
{
1032
 
        char *text = xmpp_recode_in(lm_message_node_to_string(msg->node));
1033
 
        signal_emit("xmpp raw in", 2, user_data, text);
1034
 
        g_free(text);
1035
 
        return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
1036
 
}
1037
 
 
1038
 
static void
1039
 
unregister_raw_handler(XMPP_SERVER_REC *server)
1040
 
{
1041
 
        if (!IS_XMPP_SERVER(server) || server->hraw == NULL)
1042
 
                return;
1043
 
 
1044
 
        if (lm_message_handler_is_valid(server->hraw))
1045
 
                lm_message_handler_invalidate(server->hraw);
1046
 
        lm_message_handler_unref(server->hraw);
1047
 
        server->hraw = NULL;
1048
 
}
1049
 
 
1050
 
static void
1051
 
register_raw_handler(XMPP_SERVER_REC *server)
1052
 
{
1053
 
        if (!IS_XMPP_SERVER(server) || server->hraw != NULL)
1054
 
                return;
1055
 
 
1056
 
        /* log raw */
1057
 
        server->hraw = lm_message_handler_new(
1058
 
            (LmHandleMessageFunction)handle_raw, (gpointer)server,
1059
 
            NULL);
1060
 
        lm_connection_register_message_handler(server->lmconn,
1061
 
            server->hraw, LM_MESSAGE_TYPE_MESSAGE,
1062
 
            LM_HANDLER_PRIORITY_FIRST);
1063
 
        lm_connection_register_message_handler(server->lmconn,
1064
 
            server->hraw, LM_MESSAGE_TYPE_PRESENCE,
1065
 
            LM_HANDLER_PRIORITY_FIRST);
1066
 
        lm_connection_register_message_handler(server->lmconn,
1067
 
            server->hraw, LM_MESSAGE_TYPE_IQ,
1068
 
            LM_HANDLER_PRIORITY_FIRST);
1069
 
}
1070
 
 
1071
 
void
1072
 
xmpp_protocol_init(void)
1073
 
{
1074
 
        signal_add_first("server connected",
1075
 
            (SIGNAL_FUNC)register_handlers);
1076
 
        signal_add_first("server disconnected",
1077
 
            (SIGNAL_FUNC)unregister_handlers);
1078
 
        signal_add("xmpp register raw handler",
1079
 
            (SIGNAL_FUNC)register_raw_handler);
1080
 
        signal_add("xmpp unregister raw handler",
1081
 
            (SIGNAL_FUNC)unregister_raw_handler);
1082
 
        signal_add_first("xmpp own_presence", (SIGNAL_FUNC)sig_own_presence);
1083
 
        signal_add_first("xmpp server disco",
1084
 
            (SIGNAL_FUNC)xep_disco_server);
1085
 
        signal_add("xmpp composing start", (SIGNAL_FUNC)xep_composing_start);
1086
 
        signal_add("xmpp composing stop", (SIGNAL_FUNC)xep_composing_stop);
1087
 
 
1088
 
        settings_add_int("xmpp", "xmpp_priority", 0);
1089
 
        settings_add_bool("xmpp", "xmpp_send_version", TRUE);
1090
 
        settings_add_bool("xmpp_lookandfeel", "xmpp_raw_window", FALSE);
1091
 
        settings_add_str("xmpp_lookandfeel", "xmpp_timestamp_format",
1092
 
            "%Y-%m-%d %H:%M");
1093
 
}
1094
 
 
1095
 
void
1096
 
xmpp_protocol_deinit(void)
1097
 
{
1098
 
        signal_remove("server connected",
1099
 
            (SIGNAL_FUNC)register_handlers);
1100
 
        signal_remove("server disconnected",
1101
 
            (SIGNAL_FUNC)register_handlers);
1102
 
        signal_remove("xmpp register raw handler",
1103
 
            (SIGNAL_FUNC)register_raw_handler);
1104
 
        signal_remove("xmpp unregister raw handler",
1105
 
            (SIGNAL_FUNC)unregister_raw_handler);
1106
 
        signal_remove("xmpp own_presence", (SIGNAL_FUNC)sig_own_presence);
1107
 
        signal_remove("xmpp server disco", (SIGNAL_FUNC)xep_disco_server);
1108
 
        signal_remove("xmpp composing start", (SIGNAL_FUNC)xep_composing_start);
1109
 
        signal_remove("xmpp composing stop", (SIGNAL_FUNC)xep_composing_stop);
1110
 
}