~ubuntu-branches/ubuntu/intrepid/irssi/intrepid-updates

« back to all changes in this revision

Viewing changes to src/irc/core/channel-events.c

  • Committer: Bazaar Package Importer
  • Author(s): David Pashley
  • Date: 2005-12-10 21:25:51 UTC
  • Revision ID: james.westby@ubuntu.com-20051210212551-5qwm108g7inyu2f2
Tags: upstream-0.8.10
ImportĀ upstreamĀ versionĀ 0.8.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 channel-events.c : irssi
 
3
 
 
4
    Copyright (C) 1999-2000 Timo Sirainen
 
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 as published by
 
8
    the Free Software Foundation; either version 2 of the License, or
 
9
    (at your option) any later version.
 
10
 
 
11
    This program is distributed in the hope that it will be useful,
 
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
    GNU General Public License for more details.
 
15
 
 
16
    You should have received a copy of the GNU General Public License
 
17
    along with this program; if not, write to the Free Software
 
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
*/
 
20
 
 
21
#include "module.h"
 
22
#include "signals.h"
 
23
#include "misc.h"
 
24
#include "channels-setup.h"
 
25
#include "settings.h"
 
26
#include "recode.h"
 
27
 
 
28
#include "irc-servers.h"
 
29
#include "irc-channels.h"
 
30
 
 
31
static void check_join_failure(IRC_SERVER_REC *server, const char *channel)
 
32
{
 
33
        CHANNEL_REC *chanrec;
 
34
        char *chan2;
 
35
 
 
36
        if (channel[0] == '!' && channel[1] == '!')
 
37
                channel++; /* server didn't understand !channels */
 
38
 
 
39
        chanrec = channel_find(SERVER(server), channel);
 
40
        if (chanrec == NULL && channel[0] == '!') {
 
41
                /* it probably replied with the full !channel name,
 
42
                   find the channel with the short name.. */
 
43
                chan2 = g_strdup_printf("!%s", channel+6);
 
44
                chanrec = channel_find(SERVER(server), chan2);
 
45
                g_free(chan2);
 
46
        }
 
47
 
 
48
        if (chanrec != NULL && !chanrec->joined) {
 
49
                chanrec->left = TRUE;
 
50
                channel_destroy(chanrec);
 
51
        }
 
52
}
 
53
 
 
54
static void irc_server_event(IRC_SERVER_REC *server, const char *line)
 
55
{
 
56
        char *params, *numeric, *channel;
 
57
 
 
58
        /* We'll be checking "4xx <your nick> <channel>" for channels
 
59
           which we haven't joined yet. 4xx are error codes and should
 
60
           indicate that the join failed. */
 
61
        params = event_get_params(line, 3, &numeric, NULL, &channel);
 
62
 
 
63
        if (numeric[0] == '4')
 
64
                check_join_failure(server, channel);
 
65
 
 
66
        g_free(params);
 
67
}
 
68
 
 
69
static void event_no_such_channel(IRC_SERVER_REC *server, const char *data)
 
70
{
 
71
        CHANNEL_REC *chanrec;
 
72
        CHANNEL_SETUP_REC *setup;
 
73
        char *params, *channel;
 
74
 
 
75
        params = event_get_params(data, 2, NULL, &channel);
 
76
        chanrec = *channel == '!' && channel[1] != '\0' ?
 
77
                channel_find(SERVER(server), channel) : NULL;
 
78
 
 
79
        if (chanrec != NULL) {
 
80
                /* !channel didn't exist, so join failed */
 
81
                setup = channel_setup_find(chanrec->name,
 
82
                                           chanrec->server->connrec->chatnet);
 
83
                if (setup != NULL && setup->autojoin) {
 
84
                        /* it's autojoin channel though, so create it */
 
85
                        irc_send_cmdv(server, "JOIN !%s", chanrec->name);
 
86
                        g_free(params);
 
87
                        return;
 
88
                }
 
89
        }
 
90
 
 
91
        check_join_failure(server, channel);
 
92
        g_free(params);
 
93
}
 
94
 
 
95
static void event_duplicate_channel(IRC_SERVER_REC *server, const char *data)
 
96
{
 
97
        CHANNEL_REC *chanrec;
 
98
        char *params, *channel, *p;
 
99
 
 
100
        g_return_if_fail(data != NULL);
 
101
 
 
102
        /* this new addition to ircd breaks completely with older
 
103
           "standards", "nick Duplicate ::!!channel ...." */
 
104
        params = event_get_params(data, 3, NULL, NULL, &channel);
 
105
        p = strchr(channel, ' ');
 
106
        if (p != NULL) *p = '\0';
 
107
 
 
108
        if (channel[0] == '!') {
 
109
                chanrec = channel_find(SERVER(server),
 
110
                                       channel+(channel[1] == '!'));
 
111
                if (chanrec != NULL && !chanrec->names_got) {
 
112
                        chanrec->left = TRUE;
 
113
                        channel_destroy(chanrec);
 
114
                }
 
115
        }
 
116
 
 
117
        g_free(params);
 
118
}
 
119
 
 
120
static void event_target_unavailable(IRC_SERVER_REC *server, const char *data)
 
121
{
 
122
        char *params, *channel;
 
123
 
 
124
        g_return_if_fail(data != NULL);
 
125
 
 
126
        params = event_get_params(data, 2, NULL, &channel);
 
127
        if (ischannel(*channel)) {
 
128
                /* channel is unavailable - try to join again a bit later */
 
129
                check_join_failure(server, channel);
 
130
        }
 
131
 
 
132
        g_free(params);
 
133
}
 
134
 
 
135
static void channel_change_topic(IRC_SERVER_REC *server, const char *channel,
 
136
                                 const char *topic, const char *setby,
 
137
                                 time_t settime)
 
138
{
 
139
        CHANNEL_REC *chanrec;
 
140
        char *recoded = NULL;
 
141
        
 
142
        chanrec = channel_find(SERVER(server), channel);
 
143
        if (chanrec == NULL) return;
 
144
        /* the topic may be send out encoded, so we need to 
 
145
           recode it back or /topic <tab> will not work properly */
 
146
        recoded = recode_in(SERVER(server), topic, channel);
 
147
        if (topic != NULL) {
 
148
                g_free_not_null(chanrec->topic);
 
149
                chanrec->topic = recoded == NULL ? NULL : g_strdup(recoded);
 
150
        }
 
151
        g_free(recoded);
 
152
 
 
153
        g_free_not_null(chanrec->topic_by);
 
154
        chanrec->topic_by = g_strdup(setby);
 
155
        
 
156
        chanrec->topic_time = settime;
 
157
 
 
158
        signal_emit("channel topic changed", 1, chanrec);
 
159
}
 
160
 
 
161
static void event_topic_get(IRC_SERVER_REC *server, const char *data)
 
162
{
 
163
        char *params, *channel, *topic;
 
164
 
 
165
        g_return_if_fail(data != NULL);
 
166
 
 
167
        params = event_get_params(data, 3, NULL, &channel, &topic);
 
168
        channel_change_topic(server, channel, topic, NULL, 0);
 
169
        g_free(params);
 
170
}
 
171
 
 
172
static void event_topic(IRC_SERVER_REC *server, const char *data,
 
173
                        const char *nick, const char *addr)
 
174
{
 
175
        char *params, *channel, *topic, *mask;
 
176
 
 
177
        g_return_if_fail(data != NULL);
 
178
 
 
179
        params = event_get_params(data, 2, &channel, &topic);
 
180
        mask = addr == NULL ? g_strdup(nick) :
 
181
                g_strconcat(nick, "!", addr, NULL);
 
182
        channel_change_topic(server, channel, topic, mask, time(NULL));
 
183
        g_free(mask);
 
184
        g_free(params);
 
185
}
 
186
 
 
187
static void event_topic_info(IRC_SERVER_REC *server, const char *data)
 
188
{
 
189
        char *params, *channel, *topicby, *topictime;
 
190
        time_t t;
 
191
 
 
192
        g_return_if_fail(data != NULL);
 
193
 
 
194
        params = event_get_params(data, 4, NULL, &channel,
 
195
                                  &topicby, &topictime);
 
196
 
 
197
        t = (time_t) atol(topictime);
 
198
        channel_change_topic(server, channel, NULL, topicby, t);
 
199
        g_free(params);
 
200
}
 
201
 
 
202
/* Find any unjoined channel that matches `channel'. Long channel names are
 
203
   also a bit problematic, so find a channel where start of the name matches. */
 
204
static IRC_CHANNEL_REC *channel_find_unjoined(IRC_SERVER_REC *server,
 
205
                                              const char *channel)
 
206
{
 
207
        GSList *tmp;
 
208
        int len;
 
209
 
 
210
        len = strlen(channel);
 
211
        for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
 
212
                IRC_CHANNEL_REC *rec = tmp->data;
 
213
 
 
214
                if (!IS_IRC_CHANNEL(rec) || rec->joined)
 
215
                        continue;
 
216
 
 
217
                if (g_strncasecmp(channel, rec->name, len) == 0 &&
 
218
                    (len > 20 || rec->name[len] == '\0'))
 
219
                        return rec;
 
220
        }
 
221
 
 
222
        return NULL;
 
223
}
 
224
 
 
225
static void event_join(IRC_SERVER_REC *server, const char *data, const char *nick, const char *address)
 
226
{
 
227
        char *params, *channel, *tmp, *shortchan;
 
228
        IRC_CHANNEL_REC *chanrec;
 
229
 
 
230
        g_return_if_fail(data != NULL);
 
231
 
 
232
        if (g_strcasecmp(nick, server->nick) != 0) {
 
233
                /* someone else joined channel, no need to do anything */
 
234
                return;
 
235
        }
 
236
 
 
237
        if (server->userhost == NULL)
 
238
                server->userhost = g_strdup(address);
 
239
 
 
240
        params = event_get_params(data, 1, &channel);
 
241
        tmp = strchr(channel, 7); /* ^G does something weird.. */
 
242
        if (tmp != NULL) *tmp = '\0';
 
243
 
 
244
        if (*channel != '!' || strlen(channel) < 7)
 
245
                shortchan = NULL;
 
246
        else {
 
247
                /* !channels have 5 chars long identification string before
 
248
                   it's name, it's not known when /join is called so rename
 
249
                   !channel here to !ABCDEchannel */
 
250
                shortchan = g_strdup_printf("!%s", channel+6);
 
251
                chanrec = channel_find_unjoined(server, shortchan);
 
252
                if (chanrec != NULL) {
 
253
                        channel_change_name(CHANNEL(chanrec), channel);
 
254
                        g_free(chanrec->name);
 
255
                        chanrec->name = g_strdup(channel);
 
256
                } else {
 
257
                        /* well, did we join it with full name? if so, and if
 
258
                           this was the first short one, change it's name. */
 
259
                        chanrec = channel_find_unjoined(server, channel);
 
260
                        if (chanrec != NULL &&
 
261
                            irc_channel_find(server, shortchan) == NULL) {
 
262
                                channel_change_visible_name(CHANNEL(chanrec),
 
263
                                                            shortchan);
 
264
                        }
 
265
                }
 
266
        }
 
267
 
 
268
        chanrec = irc_channel_find(server, channel);
 
269
        if (chanrec != NULL && chanrec->joined) {
 
270
                /* already joined this channel - probably a broken proxy that
 
271
                   forgot to send PART between */
 
272
                chanrec->left = TRUE;
 
273
                channel_destroy(CHANNEL(chanrec));
 
274
                chanrec = NULL; }
 
275
 
 
276
        if (chanrec == NULL) {
 
277
                /* look again, because of the channel name cut issues. */
 
278
                chanrec = channel_find_unjoined(server, channel);
 
279
        }
 
280
 
 
281
        if (chanrec == NULL) {
 
282
                /* didn't get here with /join command.. */
 
283
                chanrec = irc_channel_create(server, channel, shortchan, TRUE);
 
284
        }
 
285
 
 
286
        chanrec->joined = TRUE;
 
287
        if (strcmp(chanrec->name, channel) != 0) {
 
288
                g_free(chanrec->name);
 
289
                chanrec->name = g_strdup(channel);
 
290
        }
 
291
 
 
292
        g_free(shortchan);
 
293
        g_free(params);
 
294
}
 
295
 
 
296
static void event_part(IRC_SERVER_REC *server, const char *data, const char *nick)
 
297
{
 
298
        char *params, *channel, *reason;
 
299
        CHANNEL_REC *chanrec;
 
300
 
 
301
        g_return_if_fail(data != NULL);
 
302
 
 
303
        if (g_strcasecmp(nick, server->nick) != 0) {
 
304
                /* someone else part, no need to do anything here */
 
305
                return;
 
306
        }
 
307
 
 
308
        params = event_get_params(data, 2, &channel, &reason);
 
309
 
 
310
        chanrec = channel_find(SERVER(server), channel);
 
311
        if (chanrec != NULL && chanrec->joined) {
 
312
                chanrec->left = TRUE;
 
313
                channel_destroy(chanrec);
 
314
        }
 
315
 
 
316
        g_free(params);
 
317
}
 
318
 
 
319
static void event_kick(IRC_SERVER_REC *server, const char *data)
 
320
{
 
321
        CHANNEL_REC *chanrec;
 
322
        char *params, *channel, *nick, *reason;
 
323
 
 
324
        g_return_if_fail(data != NULL);
 
325
 
 
326
        params = event_get_params(data, 3, &channel, &nick, &reason);
 
327
 
 
328
        if (g_strcasecmp(nick, server->nick) != 0) {
 
329
                /* someone else was kicked, no need to do anything */
 
330
                g_free(params);
 
331
                return;
 
332
        }
 
333
 
 
334
        chanrec = channel_find(SERVER(server), channel);
 
335
        if (chanrec != NULL) {
 
336
                irc_server_purge_output(server, channel);
 
337
                chanrec->kicked = TRUE;
 
338
                channel_destroy(chanrec);
 
339
        }
 
340
 
 
341
        g_free(params);
 
342
}
 
343
 
 
344
static void event_invite(IRC_SERVER_REC *server, const char *data)
 
345
{
 
346
        char *params, *channel, *shortchan;
 
347
 
 
348
        g_return_if_fail(data != NULL);
 
349
 
 
350
        params = event_get_params(data, 2, NULL, &channel);
 
351
 
 
352
        if (irc_channel_find(server, channel) == NULL) {
 
353
                /* check if we're supposed to autojoin this channel */
 
354
                CHANNEL_SETUP_REC *setup;
 
355
 
 
356
                setup = channel_setup_find(channel, server->connrec->chatnet);
 
357
                if (setup == NULL && channel[0] == '!' &&
 
358
                    strlen(channel) > 6) {
 
359
                        shortchan = g_strdup_printf("!%s", channel+6);
 
360
                        setup = channel_setup_find(shortchan,
 
361
                                                   server->connrec->chatnet);
 
362
                        g_free(shortchan);
 
363
                }
 
364
                if (setup != NULL && setup->autojoin && settings_get_bool("join_auto_chans_on_invite"))
 
365
                        server->channels_join(SERVER(server), channel, TRUE);
 
366
        }
 
367
 
 
368
        g_free_not_null(server->last_invite);
 
369
        server->last_invite = g_strdup(channel);
 
370
        g_free(params);
 
371
}
 
372
 
 
373
void channel_events_init(void)
 
374
{
 
375
        settings_add_bool("misc", "join_auto_chans_on_invite", TRUE);
 
376
 
 
377
        signal_add_first("server event", (SIGNAL_FUNC) irc_server_event);
 
378
        signal_add_first("event 403", (SIGNAL_FUNC) event_no_such_channel); /* no such channel */
 
379
        signal_add_first("event 407", (SIGNAL_FUNC) event_duplicate_channel); /* duplicate channel */
 
380
 
 
381
        signal_add("event topic", (SIGNAL_FUNC) event_topic);
 
382
        signal_add_first("event join", (SIGNAL_FUNC) event_join);
 
383
        signal_add("event part", (SIGNAL_FUNC) event_part);
 
384
        signal_add("event kick", (SIGNAL_FUNC) event_kick);
 
385
        signal_add("event invite", (SIGNAL_FUNC) event_invite);
 
386
        signal_add("event 332", (SIGNAL_FUNC) event_topic_get);
 
387
        signal_add("event 333", (SIGNAL_FUNC) event_topic_info);
 
388
        signal_add_first("event 437", (SIGNAL_FUNC) event_target_unavailable); /* channel/nick unavailable */
 
389
}
 
390
 
 
391
void channel_events_deinit(void)
 
392
{
 
393
        signal_remove("server event", (SIGNAL_FUNC) irc_server_event);
 
394
        signal_remove("event 403", (SIGNAL_FUNC) event_no_such_channel); /* no such channel */
 
395
        signal_remove("event 407", (SIGNAL_FUNC) event_duplicate_channel); /* duplicate channel */
 
396
 
 
397
        signal_remove("event topic", (SIGNAL_FUNC) event_topic);
 
398
        signal_remove("event join", (SIGNAL_FUNC) event_join);
 
399
        signal_remove("event part", (SIGNAL_FUNC) event_part);
 
400
        signal_remove("event kick", (SIGNAL_FUNC) event_kick);
 
401
        signal_remove("event invite", (SIGNAL_FUNC) event_invite);
 
402
        signal_remove("event 332", (SIGNAL_FUNC) event_topic_get);
 
403
        signal_remove("event 333", (SIGNAL_FUNC) event_topic_info);
 
404
        signal_remove("event 437", (SIGNAL_FUNC) event_target_unavailable); /* channel/nick unavailable */
 
405
}