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

« back to all changes in this revision

Viewing changes to src/core/xmpp-channels.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-channels.c,v 1.31 2008/03/01 17:57:21 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 <string.h>
21
 
 
22
 
#include "module.h"
23
 
#include "channels-setup.h"
24
 
#include "commands.h"
25
 
#include "settings.h"
26
 
#include "signals.h"
27
 
 
28
 
#include "xmpp-channels.h"
29
 
#include "xmpp-nicklist.h"
30
 
#include "xmpp-protocol.h"
31
 
#include "xmpp-rosters-tools.h"
32
 
#include "xmpp-tools.h"
33
 
 
34
 
/*
35
 
 * XEP-0045: Multi-User Chat
36
 
 */
37
 
 
38
 
CHANNEL_REC *
39
 
xmpp_channel_create(XMPP_SERVER_REC *server, const char *name,
40
 
    const char *visible_name, int automatic, const char *nick)
41
 
{
42
 
        XMPP_CHANNEL_REC *rec;
43
 
 
44
 
        g_return_val_if_fail(IS_XMPP_SERVER(server), NULL);
45
 
        g_return_val_if_fail(name != NULL, NULL);
46
 
 
47
 
        rec = g_new0(XMPP_CHANNEL_REC, 1);
48
 
        rec->chat_type = XMPP_PROTOCOL;
49
 
 
50
 
        rec->nick = g_strdup((nick != NULL) ? nick :
51
 
          (*settings_get_str("nick") != '\0') ?
52
 
          settings_get_str("nick") : server->user);
53
 
        rec->features = 0;
54
 
 
55
 
        channel_init((CHANNEL_REC *)rec, SERVER(server), name, visible_name,
56
 
            automatic);
57
 
 
58
 
        return (CHANNEL_REC *)rec;
59
 
}
60
 
 
61
 
void
62
 
xmpp_channel_send_message(XMPP_SERVER_REC *server, const char *name,
63
 
    const char *message)
64
 
{
65
 
        LmMessage *msg;
66
 
        char *room, *message_recoded;
67
 
 
68
 
        g_return_if_fail(IS_XMPP_SERVER(server));
69
 
        g_return_if_fail(name != NULL);
70
 
        g_return_if_fail(message != NULL);
71
 
 
72
 
        room = xmpp_recode_out(name);
73
 
        msg = lm_message_new_with_sub_type(room,
74
 
            LM_MESSAGE_TYPE_MESSAGE, LM_MESSAGE_SUB_TYPE_GROUPCHAT);
75
 
        g_free(room);
76
 
 
77
 
        message_recoded = xmpp_recode_out(message);
78
 
        lm_message_node_add_child(msg->node, "body", message_recoded);
79
 
        g_free(message_recoded);
80
 
 
81
 
        lm_send(server, msg, NULL);
82
 
        lm_message_unref(msg);
83
 
}
84
 
 
85
 
static CHANNEL_REC *
86
 
channel_find_server(SERVER_REC *server, const char *channel_name)
87
 
{
88
 
        GSList *tmp;
89
 
        CHANNEL_REC *channel;
90
 
 
91
 
        for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
92
 
                channel = tmp->data;
93
 
 
94
 
                if (channel->chat_type != server->chat_type)
95
 
                        continue;
96
 
 
97
 
                if (g_strcasecmp(channel_name, channel->name) == 0)
98
 
                        return channel;
99
 
        }
100
 
 
101
 
        return NULL;
102
 
}
103
 
 
104
 
static void
105
 
send_nick(XMPP_CHANNEL_REC *channel, const char *nick)
106
 
{
107
 
        LmMessage *msg;
108
 
        LmMessageNode *child;
109
 
        char *room, *recoded, *str;
110
 
 
111
 
        g_return_if_fail(channel != NULL);
112
 
        g_return_if_fail(IS_XMPP_SERVER(channel->server));
113
 
 
114
 
        if (!channel->server->connected)
115
 
                return;
116
 
 
117
 
        room = g_strconcat(channel->name, "/", nick, NULL);
118
 
        recoded = xmpp_recode_out(room);
119
 
        g_free(room);
120
 
 
121
 
        msg = lm_message_new(recoded, LM_MESSAGE_TYPE_PRESENCE);
122
 
        g_free(recoded);
123
 
 
124
 
        child = lm_message_node_add_child(msg->node, "x", NULL);
125
 
        lm_message_node_set_attribute(child, "xmlns", XMLNS_MUC);
126
 
 
127
 
        if (!channel->joined) {
128
 
                if (channel->key != NULL) {
129
 
                        recoded = xmpp_recode_out(channel->key);
130
 
                        lm_message_node_add_child(child, "password", recoded);
131
 
                        g_free(recoded);
132
 
                }
133
 
 
134
 
                child = lm_message_node_add_child(child, "history", NULL);
135
 
                str = g_strdup_printf("%d",
136
 
                    settings_get_int("xmpp_history_maxstanzas"));
137
 
                lm_message_node_set_attribute(child, "maxstanzas", str);
138
 
                g_free(str);
139
 
 
140
 
                if (channel->server->show != XMPP_PRESENCE_AVAILABLE) {
141
 
                        recoded = xmpp_recode_out(
142
 
                            xmpp_presence_show[channel->server->show]);
143
 
                        lm_message_node_add_child(msg->node, "show", recoded);
144
 
                        g_free(recoded);
145
 
                }
146
 
 
147
 
                if (channel->server->away_reason != NULL) {
148
 
                        recoded = xmpp_recode_out(
149
 
                            channel->server->away_reason);
150
 
                        lm_message_node_add_child(msg->node, "status",
151
 
                            recoded);
152
 
                        g_free(recoded);
153
 
                }
154
 
        }
155
 
 
156
 
        lm_send(channel->server, msg, NULL);
157
 
        lm_message_unref(msg);
158
 
}
159
 
 
160
 
static void
161
 
send_disco(XMPP_CHANNEL_REC *channel)
162
 
{
163
 
        LmMessage *msg;
164
 
        LmMessageNode *child;
165
 
        char *room_recoded;
166
 
 
167
 
        g_return_if_fail(channel != NULL);
168
 
        g_return_if_fail(IS_XMPP_SERVER(channel->server));
169
 
 
170
 
        room_recoded = xmpp_recode_out(channel->name);
171
 
        msg = lm_message_new_with_sub_type(room_recoded,
172
 
            LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET);
173
 
        g_free(room_recoded);
174
 
 
175
 
        child = lm_message_node_add_child(msg->node, "x", NULL);
176
 
        lm_message_node_set_attribute(child, "xmlns", XMLNS_DISCO_INFO);
177
 
 
178
 
        lm_send(channel->server, msg, NULL);
179
 
        lm_message_unref(msg);
180
 
}
181
 
 
182
 
static void
183
 
send_join(XMPP_SERVER_REC *server, XMPP_CHANNEL_REC *channel)
184
 
{
185
 
        g_return_if_fail(IS_XMPP_SERVER(server));
186
 
        g_return_if_fail(channel != NULL);
187
 
 
188
 
        if (!server->connected)
189
 
                return;
190
 
 
191
 
        send_disco(channel);
192
 
        send_nick(channel, channel->nick);
193
 
}
194
 
 
195
 
static void
196
 
channel_join(XMPP_SERVER_REC *server, const char *data, int automatic)
197
 
{
198
 
        XMPP_CHANNEL_REC *channel;
199
 
        char *chanline, *channame, *nick, *key;
200
 
        void *free_arg;
201
 
 
202
 
        g_return_if_fail(IS_XMPP_SERVER(server));
203
 
        g_return_if_fail(data != NULL);
204
 
 
205
 
        g_strstrip((char *)data);
206
 
        if (!server->connected || *data == '\0')
207
 
                return;
208
 
 
209
 
        if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
210
 
            &chanline, &key))
211
 
                return;
212
 
 
213
 
        nick = xmpp_extract_nick(chanline);
214
 
        channame = xmpp_extract_channel(chanline);
215
 
 
216
 
        if (xmpp_channel_find(server, channame) == NULL) {
217
 
                channel = (XMPP_CHANNEL_REC *)xmpp_channel_create(server,
218
 
                    channame, NULL, automatic, nick);
219
 
 
220
 
                channel->key = (key == NULL || *key == '\0') ?
221
 
                    NULL : g_strdup(key);
222
 
                send_join(server, channel);
223
 
        }
224
 
 
225
 
        g_free(nick);
226
 
        g_free(channame);
227
 
        cmd_params_free(free_arg);
228
 
}
229
 
 
230
 
void
231
 
xmpp_channels_join(XMPP_SERVER_REC *server, const char *data, int automatic)
232
 
{
233
 
        /* ignore automatic joins from irssi */
234
 
        if (automatic)
235
 
                return;
236
 
 
237
 
        channel_join(server, data, FALSE);
238
 
}
239
 
 
240
 
void
241
 
xmpp_channels_join_automatic(XMPP_SERVER_REC *server, const char *data)
242
 
{
243
 
        channel_join(server, data, TRUE);
244
 
}
245
 
 
246
 
void
247
 
xmpp_channels_invite(XMPP_SERVER_REC *server, const char *room,
248
 
    const char *dest)
249
 
{
250
 
        XMPP_CHANNEL_REC *channel;
251
 
        LmMessage *msg;
252
 
        LmMessageNode *child, *invite;
253
 
        char *room_recoded, *dest_recoded;
254
 
 
255
 
        g_return_if_fail(IS_XMPP_SERVER(server));
256
 
        g_return_if_fail(room != NULL);
257
 
        g_return_if_fail(dest != NULL);
258
 
        
259
 
        dest_recoded = xmpp_recode_out(dest);
260
 
        msg = lm_message_new(dest_recoded, LM_MESSAGE_TYPE_MESSAGE);
261
 
        g_free(dest_recoded);
262
 
        
263
 
        child = lm_message_node_add_child(msg->node, "x", NULL);
264
 
        lm_message_node_set_attribute(child, "xmlns", XMLNS_MUC);
265
 
 
266
 
        invite = lm_message_node_add_child(child, "invite", NULL);
267
 
        room_recoded = xmpp_recode_out(room);
268
 
        lm_message_node_set_attribute(invite, "to", room_recoded);
269
 
        g_free(room_recoded);
270
 
 
271
 
        if ((channel = xmpp_channel_find(server, room)) != NULL &&
272
 
            channel->key != NULL)
273
 
                lm_message_node_add_child(child, "password",
274
 
                    channel->key);
275
 
 
276
 
        lm_send(server, msg, NULL);
277
 
        lm_message_unref(msg);
278
 
}
279
 
 
280
 
static void
281
 
send_part(XMPP_SERVER_REC *server, XMPP_CHANNEL_REC *channel,
282
 
    const char *reason)
283
 
{
284
 
        LmMessage *msg;
285
 
        LmMessageNode *child;
286
 
        char *room, *room_recoded, *reason_recoded;
287
 
 
288
 
        g_return_if_fail(IS_XMPP_SERVER(server));
289
 
        g_return_if_fail(channel != NULL);
290
 
 
291
 
        if (!server->connected)
292
 
                return;
293
 
 
294
 
        room = g_strconcat(channel->name, "/", channel->nick, NULL);
295
 
        room_recoded = xmpp_recode_out(room);
296
 
        g_free(room);
297
 
 
298
 
        msg = lm_message_new_with_sub_type(room_recoded,
299
 
            LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_UNAVAILABLE);
300
 
        g_free(room_recoded);
301
 
 
302
 
        child = lm_message_node_add_child(msg->node, "x", NULL);
303
 
        lm_message_node_set_attribute(child, "xmlns", XMLNS_MUC);
304
 
 
305
 
        if (reason != NULL) {
306
 
                reason_recoded = xmpp_recode_out(reason);
307
 
                child = lm_message_node_add_child(msg->node, "status",
308
 
                    reason_recoded);
309
 
                g_free(reason_recoded);
310
 
        }
311
 
 
312
 
        lm_send(server, msg, NULL);
313
 
        lm_message_unref(msg);
314
 
}
315
 
 
316
 
static void
317
 
sig_part(XMPP_SERVER_REC *server, const char *channame,
318
 
    const char *reason)
319
 
{
320
 
        XMPP_CHANNEL_REC *channel;
321
 
 
322
 
        g_return_if_fail(IS_XMPP_SERVER(server));
323
 
        g_return_if_fail(channame != NULL);
324
 
 
325
 
        g_strstrip((char *)channame);
326
 
        channel = xmpp_channel_find(server, channame);
327
 
        if (channel != NULL) {
328
 
                send_part(server, channel, reason);
329
 
                channel->left = TRUE;
330
 
 
331
 
                if (channel->ownnick != NULL)
332
 
                        signal_emit("message part", 5, server,
333
 
                            channel->name, channel->ownnick->nick,
334
 
                            channel->ownnick->host, reason);
335
 
 
336
 
                channel_destroy(CHANNEL(channel));
337
 
        }
338
 
}
339
 
 
340
 
static void
341
 
sig_own_nick(XMPP_SERVER_REC *server, const char *channame, const char *nick)
342
 
{
343
 
        XMPP_CHANNEL_REC *channel;
344
 
 
345
 
        g_return_if_fail(IS_XMPP_SERVER(server));
346
 
        g_return_if_fail(channame != NULL);
347
 
        g_return_if_fail(nick != NULL);
348
 
 
349
 
        g_strstrip((char *)channame);
350
 
        channel = xmpp_channel_find(server, channame);
351
 
        if (channel != NULL)
352
 
                send_nick(channel, nick);
353
 
}
354
 
 
355
 
static void
356
 
sig_topic(XMPP_CHANNEL_REC *channel, const char *topic, const char *nick_name)
357
 
{
358
 
        g_return_if_fail(channel != NULL);
359
 
 
360
 
        if (channel->topic != NULL && topic != NULL
361
 
            && strcmp(channel->topic, topic) == 0)
362
 
                return;
363
 
 
364
 
        g_free(channel->topic);
365
 
        channel->topic = (topic != NULL && *topic != '\0') ?
366
 
            g_strdup(topic) : NULL;
367
 
 
368
 
        g_free(channel->topic_by);
369
 
        channel->topic_by = g_strdup(nick_name);
370
 
 
371
 
        signal_emit("channel topic changed", 1, channel);
372
 
 
373
 
        if (channel->joined && nick_name != NULL && *nick_name != '\0')
374
 
                signal_emit("message topic", 5, channel->server, channel->name,
375
 
                    (channel->topic != NULL) ? channel->topic : "",
376
 
                    channel->topic_by, "");
377
 
        else {
378
 
                char *data = g_strconcat(" ", channel->name, " :",
379
 
                    (channel->topic != NULL) ? channel->topic : "", NULL);
380
 
                signal_emit("event 332", 2, channel->server, data);
381
 
                g_free(data);
382
 
        }
383
 
}
384
 
 
385
 
static void
386
 
sig_nick_own_event(XMPP_CHANNEL_REC *channel, const char *nick_name,
387
 
    const char *full_jid, const char *affiliation, const char *role,
388
 
    gboolean forced)
389
 
{
390
 
        XMPP_NICK_REC *nick;
391
 
 
392
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
393
 
        g_return_if_fail(nick_name != NULL);
394
 
 
395
 
        nick = xmpp_nicklist_find(channel, nick_name);
396
 
        if (nick == NULL)
397
 
                signal_emit("xmpp channel nick own_join", 6, channel,
398
 
                    nick_name, full_jid, affiliation, role, forced);
399
 
        else
400
 
                signal_emit("xmpp channel nick mode", 4, channel, nick,
401
 
                    affiliation, role);
402
 
}
403
 
 
404
 
static void
405
 
sig_nick_event(XMPP_CHANNEL_REC *channel, const char *nick_name,
406
 
    const char *full_jid, const char *affiliation, const char *role)
407
 
{
408
 
        XMPP_NICK_REC *nick;
409
 
 
410
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
411
 
        g_return_if_fail(nick_name != NULL);
412
 
 
413
 
        nick = xmpp_nicklist_find(channel, nick_name);
414
 
        if (nick == NULL)
415
 
                signal_emit("xmpp channel nick join", 5, channel, nick_name,
416
 
                    full_jid, affiliation, role);
417
 
        else 
418
 
                signal_emit("xmpp channel nick mode", 4, channel, nick,
419
 
                    affiliation, role);
420
 
}
421
 
 
422
 
static void
423
 
sig_nick_own_join(XMPP_CHANNEL_REC *channel, const char *nick_name,
424
 
    const char *full_jid, const char *affiliation, const char *role,
425
 
    gboolean forced)
426
 
{
427
 
        XMPP_NICK_REC *nick;
428
 
 
429
 
        if (channel->joined)
430
 
                return;
431
 
 
432
 
        nick = xmpp_nicklist_find(channel, nick_name);
433
 
        if (nick != NULL)
434
 
                return;
435
 
 
436
 
        nick = xmpp_nicklist_insert(channel, nick_name, full_jid);
437
 
        nicklist_set_own(CHANNEL(channel), NICK(nick));
438
 
        channel->chanop = channel->ownnick->op;
439
 
        xmpp_nicklist_set_modes(nick,
440
 
            xmpp_nicklist_get_affiliation(affiliation),
441
 
            xmpp_nicklist_get_role(role));
442
 
 
443
 
        channel->names_got = TRUE;
444
 
        channel->joined = TRUE;
445
 
 
446
 
        signal_emit("message join", 4, channel->server, channel->name,
447
 
            nick->nick, nick->host);
448
 
        signal_emit("message xmpp channel mode", 4, channel,
449
 
            nick->nick, nick->affiliation, nick->role);
450
 
 
451
 
        signal_emit("channel joined", 1, channel);
452
 
        signal_emit("channel sync", 1, channel);
453
 
        channel_send_autocommands(CHANNEL(channel));
454
 
 
455
 
        if (forced)
456
 
                signal_emit("xmpp channel nick", 3, channel, channel->nick,
457
 
                    nick->nick);
458
 
 
459
 
        if (*channel->mode == '\0')
460
 
                send_disco(channel);
461
 
}
462
 
 
463
 
static void
464
 
sig_nick_join(XMPP_CHANNEL_REC *channel, const char *nick_name,
465
 
    const char *full_jid, const char *affiliation, const char *role)
466
 
{
467
 
        XMPP_NICK_REC *nick;
468
 
 
469
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
470
 
        g_return_if_fail(nick_name != NULL);
471
 
 
472
 
        nick = xmpp_nicklist_find(channel, nick_name);
473
 
        if (nick != NULL)
474
 
                return;
475
 
 
476
 
        nick = xmpp_nicklist_insert(channel, nick_name, full_jid);
477
 
        xmpp_nicklist_set_modes(nick,
478
 
            xmpp_nicklist_get_affiliation(affiliation),
479
 
            xmpp_nicklist_get_role(role));
480
 
 
481
 
        if (channel->names_got) {
482
 
                signal_emit("message join", 4, channel->server, channel->name,
483
 
                    nick->nick, nick->host);
484
 
                signal_emit("message xmpp channel mode", 4, channel,
485
 
                    nick->nick, nick->affiliation, nick->role);
486
 
        }
487
 
}
488
 
 
489
 
static void
490
 
sig_nick_part(XMPP_CHANNEL_REC *channel, const char *nick_name,
491
 
    const char *status)
492
 
{
493
 
        XMPP_NICK_REC *nick;
494
 
 
495
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
496
 
        g_return_if_fail(nick_name != NULL);
497
 
 
498
 
        nick = xmpp_nicklist_find(channel, nick_name);
499
 
        if (nick == NULL)
500
 
                return;
501
 
 
502
 
        signal_emit("message part", 5, channel->server, channel->name,
503
 
            nick->nick, nick->host, status);
504
 
 
505
 
        if (channel->ownnick == NICK(nick)) {
506
 
                channel->left = TRUE;
507
 
                channel_destroy(CHANNEL(channel));
508
 
        } else
509
 
                nicklist_remove(CHANNEL(channel), NICK(nick));
510
 
}
511
 
 
512
 
static void
513
 
sig_nick_mode(XMPP_CHANNEL_REC *channel, XMPP_NICK_REC *nick,
514
 
    const char *affiliation_str, const char *role_str)
515
 
{
516
 
        int affiliation, role;
517
 
 
518
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
519
 
        g_return_if_fail(IS_XMPP_NICK(nick));
520
 
 
521
 
        affiliation = xmpp_nicklist_get_affiliation(affiliation_str);
522
 
        role = xmpp_nicklist_get_role(role_str);
523
 
 
524
 
        if (xmpp_nicklist_modes_changed(nick, affiliation, role)) {
525
 
                xmpp_nicklist_set_modes(nick, affiliation, role);
526
 
 
527
 
                signal_emit("message xmpp channel mode", 4, channel,
528
 
                    nick->nick, affiliation, role);
529
 
        }
530
 
}
531
 
 
532
 
static void
533
 
sig_nick_presence(XMPP_CHANNEL_REC *channel, const char *nick_name,
534
 
    const char *show_str, const char *status)
535
 
{
536
 
        XMPP_NICK_REC *nick;
537
 
        int show;
538
 
 
539
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
540
 
        g_return_if_fail(nick_name != NULL);
541
 
 
542
 
        nick = xmpp_nicklist_find(channel, nick_name);
543
 
        if (nick == NULL)
544
 
                return;
545
 
 
546
 
        show = xmpp_presence_get_show(show_str);
547
 
        if (xmpp_presence_changed(show, nick->show, status, nick->status,
548
 
            0, 0)) {
549
 
                xmpp_nicklist_set_presence(nick, show, status);
550
 
 
551
 
                if (channel->joined && channel->ownnick != NICK(nick)) {
552
 
                        /* TODO show event */
553
 
                }
554
 
        }
555
 
}
556
 
 
557
 
static void
558
 
sig_nick_changed(XMPP_CHANNEL_REC *channel, const char *oldnick,
559
 
    const char *newnick)
560
 
{
561
 
        XMPP_NICK_REC *nick;
562
 
 
563
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
564
 
        g_return_if_fail(oldnick != NULL);
565
 
        g_return_if_fail(newnick != NULL);
566
 
 
567
 
        nick = xmpp_nicklist_find(channel, oldnick);
568
 
        if (nick == NULL)
569
 
                return;
570
 
 
571
 
        xmpp_nicklist_rename(channel, nick, oldnick, newnick);
572
 
 
573
 
        if (channel->ownnick == NICK(nick))
574
 
                signal_emit("message xmpp channel own_nick", 3,
575
 
                    channel, nick, oldnick);
576
 
        else
577
 
                signal_emit("message xmpp channel nick", 3,
578
 
                    channel, nick, oldnick);
579
 
 
580
 
}
581
 
 
582
 
static void
583
 
sig_nick_kicked(XMPP_CHANNEL_REC *channel, const char *nick_name,
584
 
    const char *actor, const char *reason)
585
 
{
586
 
        XMPP_NICK_REC *nick;
587
 
 
588
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
589
 
        g_return_if_fail(nick_name != NULL);
590
 
 
591
 
        nick = xmpp_nicklist_find(channel, nick_name);
592
 
        if (nick == NULL)
593
 
                return;
594
 
 
595
 
        signal_emit("message kick", 6, channel->server, channel->name,
596
 
            nick->nick, (actor != NULL) ? actor : channel->name, nick->host,
597
 
            reason);
598
 
 
599
 
        if (channel->ownnick == NICK(nick)) {
600
 
                channel->kicked = TRUE;
601
 
                channel_destroy(CHANNEL(channel));
602
 
        } else
603
 
                nicklist_remove(CHANNEL(channel), NICK(nick));
604
 
}
605
 
 
606
 
static XMPP_CHANNELS_FEATURES
607
 
disco_parse_channels_features(const char *var, XMPP_CHANNELS_FEATURES features)
608
 
{
609
 
        g_return_val_if_fail(var != NULL, 0);
610
 
 
611
 
        if (!(features & XMPP_CHANNELS_FEATURE_HIDDEN)
612
 
            && g_ascii_strcasecmp(var, "muc_hidden") == 0)
613
 
                return XMPP_CHANNELS_FEATURE_HIDDEN;
614
 
 
615
 
        if (!(features & XMPP_CHANNELS_FEATURE_MEMBERS_ONLY)
616
 
             && g_ascii_strcasecmp(var, "muc_membersonly") == 0)
617
 
                return XMPP_CHANNELS_FEATURE_MEMBERS_ONLY;
618
 
 
619
 
        if (!(features & XMPP_CHANNELS_FEATURE_MODERATED)
620
 
            && g_ascii_strcasecmp(var, "muc_moderated") == 0)
621
 
                return XMPP_CHANNELS_FEATURE_MODERATED;
622
 
 
623
 
        if (!(features & XMPP_CHANNELS_FEATURE_NONANONYMOUS)
624
 
            && g_ascii_strcasecmp(var, "muc_nonanonymous") == 0)
625
 
                return XMPP_CHANNELS_FEATURE_NONANONYMOUS;
626
 
 
627
 
        if (!(features & XMPP_CHANNELS_FEATURE_OPEN)
628
 
            && g_ascii_strcasecmp(var, "muc_open") == 0)
629
 
                return XMPP_CHANNELS_FEATURE_OPEN;
630
 
 
631
 
        if (!(features & XMPP_CHANNELS_FEATURE_PASSWORD_PROTECTED)
632
 
            && g_ascii_strcasecmp(var, "muc_passwordprotected") == 0)
633
 
                return XMPP_CHANNELS_FEATURE_PASSWORD_PROTECTED;
634
 
 
635
 
        if (!(features & XMPP_CHANNELS_FEATURE_PERSISTENT)
636
 
            && g_ascii_strcasecmp(var, "muc_persistent") == 0)
637
 
                return XMPP_CHANNELS_FEATURE_PERSISTENT;
638
 
 
639
 
        if (!(features & XMPP_CHANNELS_FEATURE_PUBLIC)
640
 
            && g_ascii_strcasecmp(var, "muc_public") == 0)
641
 
                return XMPP_CHANNELS_FEATURE_PUBLIC;
642
 
 
643
 
        if (!(features & XMPP_CHANNELS_FEATURE_SEMIANONYMOUS)
644
 
            && g_ascii_strcasecmp(var, "muc_semianonymous") == 0)
645
 
                return XMPP_CHANNELS_FEATURE_SEMIANONYMOUS;
646
 
 
647
 
        if (!(features & XMPP_CHANNELS_FEATURE_TEMPORARY)
648
 
            && g_ascii_strcasecmp(var, "muc_temporary") == 0)
649
 
                return XMPP_CHANNELS_FEATURE_TEMPORARY;
650
 
 
651
 
        if (!(features & XMPP_CHANNELS_FEATURE_UNMODERATED)
652
 
            && g_ascii_strcasecmp(var, "muc_unmoderated") == 0)
653
 
                return XMPP_CHANNELS_FEATURE_UNMODERATED;
654
 
 
655
 
        if (!(features & XMPP_CHANNELS_FEATURE_UNSECURED)
656
 
            && g_ascii_strcasecmp(var, "muc_unsecured") == 0)
657
 
                return XMPP_CHANNELS_FEATURE_UNSECURED;
658
 
 
659
 
        else
660
 
                return 0;
661
 
}
662
 
 
663
 
static void
664
 
update_channel_modes(XMPP_CHANNEL_REC *channel)
665
 
{
666
 
        GString *modes;
667
 
 
668
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
669
 
 
670
 
        modes = g_string_new(NULL);
671
 
 
672
 
        if (channel->features & XMPP_CHANNELS_FEATURE_HIDDEN)
673
 
                g_string_append(modes, "h");
674
 
        if (channel->features & XMPP_CHANNELS_FEATURE_MEMBERS_ONLY)
675
 
                g_string_append(modes, "m");
676
 
        if (channel->features & XMPP_CHANNELS_FEATURE_MODERATED)
677
 
                g_string_append(modes, "M");
678
 
        if (channel->features & XMPP_CHANNELS_FEATURE_NONANONYMOUS)
679
 
                g_string_append(modes, "a");
680
 
        if (channel->features & XMPP_CHANNELS_FEATURE_OPEN)
681
 
                g_string_append(modes, "o");
682
 
        if (channel->features & XMPP_CHANNELS_FEATURE_PASSWORD_PROTECTED)
683
 
                g_string_append(modes, "k");
684
 
        if (channel->features & XMPP_CHANNELS_FEATURE_PERSISTENT)
685
 
                g_string_append(modes, "p");
686
 
        if (channel->features & XMPP_CHANNELS_FEATURE_PUBLIC)
687
 
                g_string_append(modes, "u");
688
 
        if (channel->features & XMPP_CHANNELS_FEATURE_SEMIANONYMOUS)
689
 
                g_string_append(modes, "b");
690
 
        if (channel->features & XMPP_CHANNELS_FEATURE_TEMPORARY)
691
 
                g_string_append(modes, "t");
692
 
        if (channel->features & XMPP_CHANNELS_FEATURE_UNMODERATED)
693
 
                g_string_append(modes, "n");
694
 
        if (channel->features & XMPP_CHANNELS_FEATURE_UNSECURED)
695
 
                g_string_append(modes, "d");
696
 
 
697
 
        if (channel->features & XMPP_CHANNELS_FEATURE_PASSWORD_PROTECTED
698
 
            && channel->key != NULL)
699
 
                g_string_append_printf(modes, " %s", channel->key);
700
 
 
701
 
        if (strcmp(modes->str, channel->mode) != 0) {
702
 
                g_free(channel->mode);
703
 
                channel->mode = modes->str;
704
 
 
705
 
                signal_emit("channel mode changed", 2, channel, channel->name);
706
 
        }
707
 
 
708
 
        g_string_free(modes, FALSE);
709
 
}
710
 
 
711
 
static void
712
 
sig_disco(XMPP_CHANNEL_REC *channel, LmMessageNode *query)
713
 
{
714
 
        LmMessageNode *item;
715
 
        const char *var;
716
 
 
717
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
718
 
        g_return_if_fail(query != NULL);
719
 
 
720
 
        channel->features = 0;
721
 
        for (item = query->children; item != NULL; item = item->next) {
722
 
                if (g_ascii_strcasecmp(item->name, "feature") != 0)
723
 
                        continue;
724
 
 
725
 
                /* <feature var='var'/> */
726
 
                var = lm_message_node_get_attribute(item, "var");
727
 
                if (var != NULL)
728
 
                        channel->features |= disco_parse_channels_features(var,
729
 
                            channel->features);
730
 
        }
731
 
        update_channel_modes(channel);
732
 
}
733
 
 
734
 
static void
735
 
sig_joinerror(XMPP_CHANNEL_REC *channel, int error)
736
 
{
737
 
        g_return_if_fail(IS_XMPP_CHANNEL(channel));
738
 
 
739
 
        /* retry with alternate nick */
740
 
        if (error == XMPP_CHANNELS_ERROR_USE_RESERVED_ROOM_NICK
741
 
            || error == XMPP_CHANNELS_ERROR_NICK_IN_USE) {
742
 
                const char *altnick = settings_get_str("alternate_nick");
743
 
 
744
 
                if (altnick != NULL && *altnick != '\0'
745
 
                    && strcmp(channel->nick, altnick) != 0) {
746
 
                        g_free(channel->nick);
747
 
                        channel->nick = g_strdup(altnick);
748
 
                } else {
749
 
                        char *str = g_strdup_printf("%s_", channel->nick);
750
 
                        g_free(channel->nick);
751
 
                        channel->nick = str;
752
 
                }
753
 
 
754
 
                send_join(channel->server, channel);
755
 
                return;
756
 
        }
757
 
 
758
 
        channel_destroy(CHANNEL(channel));
759
 
}
760
 
 
761
 
static void
762
 
sig_channel_created(XMPP_CHANNEL_REC *channel)
763
 
{
764
 
        if (!IS_XMPP_CHANNEL(channel))
765
 
                return;
766
 
 
767
 
        if (channel->nicks != NULL)
768
 
                g_hash_table_destroy(channel->nicks);
769
 
        channel->nicks = g_hash_table_new((GHashFunc)g_str_hash,
770
 
            (GCompareFunc)g_str_equal);
771
 
}
772
 
 
773
 
static void
774
 
sig_channel_destroyed(XMPP_CHANNEL_REC *channel)
775
 
{
776
 
        if (!IS_XMPP_CHANNEL(channel))
777
 
                return;
778
 
 
779
 
        if (!channel->server->disconnected && !channel->left)
780
 
                send_part(channel->server, channel,
781
 
                    settings_get_str("part_message"));
782
 
 
783
 
        g_free(channel->nick);
784
 
}
785
 
 
786
 
static void
787
 
sig_event_connected(SERVER_REC *server)
788
 
{
789
 
        GSList *tmp;
790
 
        CHANNEL_SETUP_REC *channel_setup;
791
 
 
792
 
        if (!IS_XMPP_SERVER(server)
793
 
            || server->connrec->no_autojoin_channels)
794
 
                return;
795
 
 
796
 
        /* autojoin channels */
797
 
        for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) {
798
 
                channel_setup = tmp->data;
799
 
 
800
 
                if (IS_XMPP_CHANNEL_SETUP(channel_setup)
801
 
                    && channel_setup->autojoin
802
 
                    && strcmp(channel_setup->chatnet,
803
 
                    server->connrec->chatnet) == 0)
804
 
                        xmpp_channels_join_automatic(XMPP_SERVER(server),
805
 
                            channel_setup->name);
806
 
        }
807
 
}
808
 
 
809
 
static void
810
 
sig_server_connected(SERVER_REC *server)
811
 
{
812
 
        if (!IS_XMPP_SERVER(server))
813
 
                return;
814
 
 
815
 
        server->channel_find_func = channel_find_server;
816
 
        server->channels_join = (void (*)(SERVER_REC *, const char *, int))
817
 
            xmpp_channels_join;
818
 
}
819
 
 
820
 
void
821
 
xmpp_channels_init(void)
822
 
{
823
 
        signal_add("xmpp channels part", (SIGNAL_FUNC)sig_part);
824
 
        signal_add("xmpp channels own_nick", (SIGNAL_FUNC)sig_own_nick);
825
 
        signal_add("xmpp channel topic", (SIGNAL_FUNC)sig_topic);
826
 
        signal_add("xmpp channel nick own_event",
827
 
            (SIGNAL_FUNC)sig_nick_own_event);
828
 
        signal_add("xmpp channel nick event", (SIGNAL_FUNC)sig_nick_event);
829
 
        signal_add("xmpp channel nick own_join",
830
 
            (SIGNAL_FUNC)sig_nick_own_join);
831
 
        signal_add("xmpp channel nick join", (SIGNAL_FUNC)sig_nick_join);
832
 
        signal_add("xmpp channel nick part", (SIGNAL_FUNC)sig_nick_part);
833
 
        signal_add("xmpp channel nick mode", (SIGNAL_FUNC)sig_nick_mode);
834
 
        signal_add("xmpp channel nick presence",
835
 
            (SIGNAL_FUNC)sig_nick_presence);
836
 
        signal_add("xmpp channel nick", (SIGNAL_FUNC)sig_nick_changed);
837
 
        signal_add("xmpp channel nick kicked", (SIGNAL_FUNC)sig_nick_kicked);
838
 
        signal_add("xmpp channel disco", (SIGNAL_FUNC)sig_disco);
839
 
        signal_add_last("xmpp channel joinerror", (SIGNAL_FUNC)sig_joinerror);
840
 
        signal_add_last("channel created", (SIGNAL_FUNC)sig_channel_created);
841
 
        signal_add("channel destroyed", (SIGNAL_FUNC)sig_channel_destroyed);
842
 
        signal_add_last("event connected", (SIGNAL_FUNC)sig_event_connected);
843
 
        signal_add_first("server connected",
844
 
            (SIGNAL_FUNC)sig_server_connected);
845
 
 
846
 
        settings_add_int("xmpp_lookandfeel", "xmpp_history_maxstanzas", 30);
847
 
}
848
 
 
849
 
void
850
 
xmpp_channels_deinit(void)
851
 
{
852
 
        signal_remove("xmpp channels part", (SIGNAL_FUNC)sig_part);
853
 
        signal_remove("xmpp channels own_nick", (SIGNAL_FUNC)sig_own_nick);
854
 
        signal_remove("xmpp channel topic", (SIGNAL_FUNC)sig_topic);
855
 
        signal_remove("xmpp channel nick own_event",
856
 
            (SIGNAL_FUNC)sig_nick_own_event);
857
 
        signal_remove("xmpp channel nick event", (SIGNAL_FUNC)sig_nick_event);
858
 
        signal_remove("xmpp channel nick own_join",
859
 
            (SIGNAL_FUNC)sig_nick_own_join);
860
 
        signal_remove("xmpp channel nick join", (SIGNAL_FUNC)sig_nick_join);
861
 
        signal_remove("xmpp channel nick part", (SIGNAL_FUNC)sig_nick_part);
862
 
        signal_remove("xmpp channel nick mode", (SIGNAL_FUNC)sig_nick_mode);
863
 
        signal_remove("xmpp channel nick presence",
864
 
            (SIGNAL_FUNC)sig_nick_presence);
865
 
        signal_remove("xmpp channel nick", (SIGNAL_FUNC)sig_nick_changed);
866
 
        signal_remove("xmpp channel nick kicked", (SIGNAL_FUNC)sig_nick_kicked);
867
 
        signal_remove("xmpp channel disco", (SIGNAL_FUNC)sig_disco);
868
 
        signal_remove("xmpp channel joinerror", (SIGNAL_FUNC)sig_joinerror);
869
 
        signal_remove("channel created", (SIGNAL_FUNC)sig_channel_created);
870
 
        signal_remove("channel destroyed",(SIGNAL_FUNC)sig_channel_destroyed);
871
 
        signal_remove("event connected", (SIGNAL_FUNC)sig_event_connected);
872
 
        signal_remove("server connected", (SIGNAL_FUNC)sig_server_connected);
873
 
}