~ubuntu-branches/ubuntu/feisty/irssi/feisty-backports

« back to all changes in this revision

Viewing changes to src/irc/core/ctcp.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
 ctcp.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 "levels.h"
 
24
#include "misc.h"
 
25
#include "special-vars.h"
 
26
#include "settings.h"
 
27
 
 
28
#include "irc-servers.h"
 
29
#include "servers-idle.h"
 
30
#include "ignore.h"
 
31
#include "ctcp.h"
 
32
 
 
33
typedef struct {
 
34
        char *name;
 
35
        int refcount;
 
36
} CTCP_CMD_REC;
 
37
 
 
38
static GSList *ctcp_cmds;
 
39
 
 
40
static CTCP_CMD_REC *ctcp_cmd_find(const char *name)
 
41
{
 
42
        GSList *tmp;
 
43
 
 
44
        for (tmp = ctcp_cmds; tmp != NULL; tmp = tmp->next) {
 
45
                CTCP_CMD_REC *rec = tmp->data;
 
46
 
 
47
                if (g_strcasecmp(rec->name, name) == 0)
 
48
                        return rec;
 
49
        }
 
50
 
 
51
        return NULL;
 
52
}
 
53
 
 
54
void ctcp_register(const char *name)
 
55
{
 
56
        CTCP_CMD_REC *rec;
 
57
 
 
58
        rec = ctcp_cmd_find(name);
 
59
        if (rec == NULL) {
 
60
                rec = g_new0(CTCP_CMD_REC, 1);
 
61
                rec->name = g_strdup(name);
 
62
                g_strup(rec->name);
 
63
 
 
64
                ctcp_cmds = g_slist_append(ctcp_cmds, rec);
 
65
        }
 
66
 
 
67
        rec->refcount++;
 
68
}
 
69
 
 
70
static void ctcp_cmd_destroy(CTCP_CMD_REC *rec)
 
71
{
 
72
        ctcp_cmds = g_slist_remove(ctcp_cmds, rec);
 
73
        g_free(rec->name);
 
74
        g_free(rec);
 
75
}
 
76
 
 
77
void ctcp_unregister(const char *name)
 
78
{
 
79
        CTCP_CMD_REC *rec;
 
80
 
 
81
        rec = ctcp_cmd_find(name);
 
82
        if (rec != NULL && --rec->refcount == 0)
 
83
                ctcp_cmd_destroy(rec);
 
84
}
 
85
 
 
86
static void ctcp_queue_clean(IRC_SERVER_REC *server)
 
87
{
 
88
        GSList *tmp, *next;
 
89
 
 
90
        for (tmp = server->ctcpqueue; tmp != NULL; tmp = next) {
 
91
                next = tmp->next;
 
92
                if (!server_idle_find(server, GPOINTER_TO_INT(tmp->data))) {
 
93
                        server->ctcpqueue =
 
94
                                g_slist_remove(server->ctcpqueue, tmp->data);
 
95
                }
 
96
        }
 
97
}
 
98
 
 
99
/* Send CTCP reply with flood protection */
 
100
void ctcp_send_reply(IRC_SERVER_REC *server, const char *data)
 
101
{
 
102
        int tag;
 
103
 
 
104
        g_return_if_fail(server != NULL);
 
105
        g_return_if_fail(data != NULL);
 
106
 
 
107
        ctcp_queue_clean(server);
 
108
 
 
109
        if ((int)g_slist_length(server->ctcpqueue) >=
 
110
            settings_get_int("max_ctcp_queue"))
 
111
                return;
 
112
 
 
113
        /* Add to first in idle queue */
 
114
        tag = server_idle_add(server, data);
 
115
        server->ctcpqueue =
 
116
                g_slist_append(server->ctcpqueue, GINT_TO_POINTER(tag));
 
117
}
 
118
 
 
119
/* CTCP ping */
 
120
static void ctcp_ping(IRC_SERVER_REC *server, const char *data,
 
121
                      const char *nick)
 
122
{
 
123
        char *str;
 
124
 
 
125
        g_return_if_fail(data != NULL);
 
126
        g_return_if_fail(server != NULL);
 
127
        g_return_if_fail(nick != NULL);
 
128
 
 
129
        if (strlen(data) > 100) {
 
130
                /* Yes, this is kind of a kludge, but people who PING you
 
131
                   with messages this long deserve not to get the reply.
 
132
 
 
133
                   The problem with long messages is that when you send lots
 
134
                   of data to server, it's input buffer gets full and you get
 
135
                   killed from server because of "excess flood".
 
136
 
 
137
                   Irssi's current flood protection doesn't count the message
 
138
                   length, but even if it did, the CTCP flooder would still
 
139
                   be able to at least slow down your possibility to send
 
140
                   messages to server. */
 
141
                return;
 
142
        }
 
143
 
 
144
        str = g_strdup_printf("NOTICE %s :\001PING %s\001", nick, data);
 
145
        ctcp_send_reply(server, str);
 
146
        g_free(str);
 
147
}
 
148
 
 
149
static void ctcp_send_parsed_reply(IRC_SERVER_REC *server, const char *nick,
 
150
                                   const char *cmd, const char *args)
 
151
{
 
152
        char *str, *pstr;
 
153
 
 
154
        g_return_if_fail(server != NULL);
 
155
        g_return_if_fail(nick != NULL);
 
156
 
 
157
        if (*args == '\0')
 
158
                return;
 
159
 
 
160
        pstr = parse_special_string(args, SERVER(server), NULL, "", NULL, 0);
 
161
        str = g_strdup_printf("NOTICE %s :\001%s %s\001", nick, cmd, pstr);
 
162
        ctcp_send_reply(server, str);
 
163
        g_free(str);
 
164
        g_free(pstr);
 
165
}
 
166
 
 
167
/* CTCP version */
 
168
static void ctcp_version(IRC_SERVER_REC *server, const char *data,
 
169
                         const char *nick)
 
170
{
 
171
        ctcp_send_parsed_reply(server, nick, "VERSION",
 
172
                               settings_get_str("ctcp_version_reply"));
 
173
}
 
174
 
 
175
/* CTCP time */
 
176
static void ctcp_time(IRC_SERVER_REC *server, const char *data,
 
177
                      const char *nick)
 
178
{
 
179
        char *str, *reply;
 
180
 
 
181
        g_return_if_fail(server != NULL);
 
182
        g_return_if_fail(nick != NULL);
 
183
 
 
184
        reply = my_asctime(time(NULL));
 
185
        str = g_strdup_printf("NOTICE %s :\001TIME %s\001", nick, reply);
 
186
        ctcp_send_reply(server, str);
 
187
        g_free(str);
 
188
        g_free(reply);
 
189
}
 
190
 
 
191
/* CTCP userinfo */
 
192
static void ctcp_userinfo(IRC_SERVER_REC *server, const char *data,
 
193
                          const char *nick)
 
194
{
 
195
        ctcp_send_parsed_reply(server, nick, "USERINFO",
 
196
                               settings_get_str("ctcp_userinfo_reply"));
 
197
}
 
198
 
 
199
/* CTCP clientinfo */
 
200
static void ctcp_clientinfo(IRC_SERVER_REC *server, const char *data,
 
201
                            const char *nick)
 
202
{
 
203
        GString *str;
 
204
        GSList *tmp;
 
205
 
 
206
        g_return_if_fail(server != NULL);
 
207
        g_return_if_fail(nick != NULL);
 
208
 
 
209
        str = g_string_new(NULL);
 
210
        g_string_sprintf(str, "NOTICE %s :\001CLIENTINFO", nick);
 
211
        for (tmp = ctcp_cmds; tmp != NULL; tmp = tmp->next) {
 
212
                CTCP_CMD_REC *rec = tmp->data;
 
213
 
 
214
                g_string_append_c(str, ' ');
 
215
                g_string_append(str, rec->name);
 
216
        }
 
217
        g_string_append_c(str, '\001');
 
218
 
 
219
        ctcp_send_reply(server, str->str);
 
220
        g_string_free(str, TRUE);
 
221
}
 
222
 
 
223
static void ctcp_msg(IRC_SERVER_REC *server, const char *data,
 
224
                     const char *nick, const char *addr, const char *target)
 
225
{
 
226
        char *args, *str;
 
227
 
 
228
        if (g_strncasecmp(data, "ACTION ", 7) == 0) {
 
229
                /* special treatment for actions */
 
230
                signal_emit("ctcp action", 5, server, data+7,
 
231
                            nick, addr, target);
 
232
                return;
 
233
        }
 
234
 
 
235
        if (ignore_check(SERVER(server), nick, addr, target, data, MSGLEVEL_CTCPS))
 
236
                return;
 
237
 
 
238
        str = g_strconcat("ctcp msg ", data, NULL);
 
239
        args = strchr(str+9, ' ');
 
240
        if (args != NULL) *args++ = '\0'; else args = "";
 
241
 
 
242
        g_strdown(str+9);
 
243
        if (!signal_emit(str, 5, server, args, nick, addr, target)) {
 
244
                signal_emit("default ctcp msg", 5,
 
245
                            server, data, nick, addr, target);
 
246
        }
 
247
        g_free(str);
 
248
}
 
249
 
 
250
static void ctcp_reply(IRC_SERVER_REC *server, const char *data,
 
251
                       const char *nick, const char *addr, const char *target)
 
252
{
 
253
        char *args, *str;
 
254
 
 
255
        if (ignore_check(SERVER(server), nick, addr, target, data, MSGLEVEL_CTCPS))
 
256
                return;
 
257
 
 
258
        str = g_strconcat("ctcp reply ", data, NULL);
 
259
        args = strchr(str+11, ' ');
 
260
        if (args != NULL) *args++ = '\0'; else args = "";
 
261
 
 
262
        g_strdown(str+11);
 
263
        if (!signal_emit(str, 5, server, args, nick, addr, target)) {
 
264
                signal_emit("default ctcp reply", 5,
 
265
                            server, data, nick, addr, target);
 
266
        }
 
267
        g_free(str);
 
268
}
 
269
 
 
270
static void event_privmsg(IRC_SERVER_REC *server, const char *data,
 
271
                          const char *nick, const char *addr)
 
272
{
 
273
        char *params, *target, *msg;
 
274
        int len;
 
275
 
 
276
        g_return_if_fail(data != NULL);
 
277
 
 
278
        params = event_get_params(data, 2, &target, &msg);
 
279
 
 
280
        /* handle only ctcp messages.. */
 
281
        if (*msg == 1) {
 
282
                /* remove the \001 at beginning and end */
 
283
                msg++;
 
284
                len = strlen(msg);
 
285
                if (msg[len-1] == '\001')
 
286
                        msg[len-1] = '\0';
 
287
 
 
288
                signal_emit("ctcp msg", 5, server, msg, nick, addr, target);
 
289
                signal_stop();
 
290
        }
 
291
 
 
292
        g_free(params);
 
293
}
 
294
 
 
295
static void event_notice(IRC_SERVER_REC *server, const char *data,
 
296
                         const char *nick, const char *addr)
 
297
{
 
298
        char *params, *target, *ptr, *msg;
 
299
 
 
300
        g_return_if_fail(data != NULL);
 
301
 
 
302
        params = event_get_params(data, 2, &target, &msg);
 
303
 
 
304
        /* handle only ctcp replies */
 
305
        if (*msg == 1) {
 
306
                ptr = strrchr(++msg, 1);
 
307
                if (ptr != NULL) *ptr = '\0';
 
308
 
 
309
                signal_emit("ctcp reply", 5, server, msg, nick, addr, target);
 
310
                signal_stop();
 
311
        }
 
312
 
 
313
        g_free(params);
 
314
}
 
315
 
 
316
static void sig_disconnected(IRC_SERVER_REC *server)
 
317
{
 
318
        g_return_if_fail(server != NULL);
 
319
 
 
320
        if (!IS_IRC_SERVER(server))
 
321
                return;
 
322
 
 
323
        g_slist_free(server->ctcpqueue);
 
324
        server->ctcpqueue = NULL;
 
325
}
 
326
 
 
327
void ctcp_init(void)
 
328
{
 
329
        ctcp_cmds = NULL;
 
330
 
 
331
        settings_add_str("misc", "ctcp_version_reply",
 
332
                         PACKAGE" v$J - running on $sysname $sysarch");
 
333
        settings_add_str("misc", "ctcp_userinfo_reply", "$Y");
 
334
        settings_add_int("flood", "max_ctcp_queue", 5);
 
335
 
 
336
        signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
 
337
        signal_add_first("event privmsg", (SIGNAL_FUNC) event_privmsg);
 
338
        signal_add_first("event notice", (SIGNAL_FUNC) event_notice);
 
339
        signal_add("ctcp msg", (SIGNAL_FUNC) ctcp_msg);
 
340
        signal_add("ctcp reply", (SIGNAL_FUNC) ctcp_reply);
 
341
        signal_add("ctcp msg ping", (SIGNAL_FUNC) ctcp_ping);
 
342
        signal_add("ctcp msg version", (SIGNAL_FUNC) ctcp_version);
 
343
        signal_add("ctcp msg time", (SIGNAL_FUNC) ctcp_time);
 
344
        signal_add("ctcp msg userinfo", (SIGNAL_FUNC) ctcp_userinfo);
 
345
        signal_add("ctcp msg clientinfo", (SIGNAL_FUNC) ctcp_clientinfo);
 
346
 
 
347
        ctcp_register("ping");
 
348
        ctcp_register("version");
 
349
        ctcp_register("time");
 
350
        ctcp_register("userinfo");
 
351
        ctcp_register("clientinfo");
 
352
}
 
353
 
 
354
void ctcp_deinit(void)
 
355
{
 
356
        while (ctcp_cmds != NULL)
 
357
                ctcp_cmd_destroy(ctcp_cmds->data);
 
358
 
 
359
        signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
 
360
        signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
 
361
        signal_remove("event notice", (SIGNAL_FUNC) event_notice);
 
362
        signal_remove("ctcp msg", (SIGNAL_FUNC) ctcp_msg);
 
363
        signal_remove("ctcp reply", (SIGNAL_FUNC) ctcp_reply);
 
364
        signal_remove("ctcp msg ping", (SIGNAL_FUNC) ctcp_ping);
 
365
        signal_remove("ctcp msg version", (SIGNAL_FUNC) ctcp_version);
 
366
        signal_remove("ctcp msg time", (SIGNAL_FUNC) ctcp_time);
 
367
        signal_remove("ctcp msg userinfo", (SIGNAL_FUNC) ctcp_userinfo);
 
368
        signal_remove("ctcp msg clientinfo", (SIGNAL_FUNC) ctcp_clientinfo);
 
369
}