/src/irssi/src/irc/core/irc.c
Line | Count | Source |
1 | | /* |
2 | | irc.c : irssi |
3 | | |
4 | | Copyright (C) 1999 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 along |
17 | | with this program; if not, write to the Free Software Foundation, Inc., |
18 | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | | */ |
20 | | |
21 | | #include "module.h" |
22 | | #include <irssi/src/core/misc.h> |
23 | | #include <irssi/src/core/modules.h> |
24 | | #include <irssi/src/core/net-sendbuffer.h> |
25 | | #include <irssi/src/core/network.h> |
26 | | #include <irssi/src/core/rawlog.h> |
27 | | #include <irssi/src/core/refstrings.h> |
28 | | |
29 | | #include <irssi/src/irc/core/irc-channels.h> |
30 | | #include <irssi/src/irc/core/irc-servers.h> |
31 | | #include <irssi/src/irc/core/servers-redirect.h> |
32 | | |
33 | | char *current_server_event; |
34 | | static int signal_default_event; |
35 | | static int signal_server_event; |
36 | | static int signal_server_event_tags; |
37 | | static int signal_server_incoming; |
38 | | |
39 | | #ifdef BLOCKING_SOCKETS |
40 | | # define MAX_SOCKET_READS 1 |
41 | | #else |
42 | 0 | # define MAX_SOCKET_READS 5 |
43 | | #endif |
44 | | |
45 | | static void strip_params_colon(char *const); |
46 | | |
47 | | /* The core of the irc_send_cmd* functions. If `raw' is TRUE, the `cmd' |
48 | | won't be checked at all if it's 512 bytes or not, or if it contains |
49 | | line feeds or not. Use with extreme caution! */ |
50 | | void irc_send_cmd_full(IRC_SERVER_REC *server, const char *cmd, int irc_send_when, int raw) |
51 | 173k | { |
52 | 173k | GString *str; |
53 | 173k | int len; |
54 | 173k | guint pos; |
55 | 173k | gboolean server_supports_tag; |
56 | | |
57 | 173k | g_return_if_fail(server != NULL); |
58 | 173k | g_return_if_fail(cmd != NULL); |
59 | | |
60 | 173k | if (server->connection_lost) |
61 | 3.08k | return; |
62 | | |
63 | 169k | str = g_string_sized_new(MAX_IRC_USER_TAGS_LEN + 2 /* `@'+SPACE */ + |
64 | 169k | server->max_message_len + 2 /* CR+LF */ + 1 /* `\0' */); |
65 | | |
66 | 169k | if (server->cmdcount == 0) |
67 | 9.58k | irc_servers_start_cmd_timeout(); |
68 | 169k | server->cmdcount++; |
69 | | |
70 | 169k | pos = g_slist_length(server->cmdqueue); |
71 | 169k | if (server->cmdlater > pos / 2) { |
72 | 0 | server->cmdlater = pos / 2; |
73 | 0 | pos = 0; |
74 | 169k | } else { |
75 | 169k | pos -= 2 * server->cmdlater; |
76 | 169k | } |
77 | | |
78 | 169k | if (!raw) { |
79 | 169k | const char *tmp = cmd; |
80 | | |
81 | 169k | server_supports_tag = server->cap_supported != NULL && |
82 | 29.9k | g_hash_table_lookup_extended(server->cap_supported, CAP_MESSAGE_TAGS, NULL, NULL); |
83 | | |
84 | 169k | if (*cmd == '@' && server_supports_tag) { |
85 | 0 | const char *end; |
86 | |
|
87 | 0 | while (*tmp != ' ' && *tmp != '\0') |
88 | 0 | tmp++; |
89 | |
|
90 | 0 | end = tmp; |
91 | |
|
92 | 0 | if (tmp - cmd > MAX_IRC_USER_TAGS_LEN) { |
93 | 0 | g_warning("irc_send_cmd_full(); tags too long(%ld)", tmp - cmd); |
94 | 0 | while (tmp - cmd > MAX_IRC_USER_TAGS_LEN && cmd != tmp - 1) tmp--; |
95 | 0 | while (*tmp != ',' && cmd != tmp - 1) tmp--; |
96 | 0 | } |
97 | 0 | if (cmd != tmp) |
98 | 0 | g_string_append_len(str, cmd, tmp - cmd); |
99 | |
|
100 | 0 | tmp = end; |
101 | 0 | while (*tmp == ' ') tmp++; |
102 | |
|
103 | 0 | if (*tmp != '\0' && str->len > 0) |
104 | 0 | g_string_append_c(str, ' '); |
105 | 0 | } |
106 | 169k | len = strlen(tmp); |
107 | | |
108 | | /* check that we don't send any longer commands |
109 | | than 510 bytes (2 bytes for CR+LF) */ |
110 | 169k | g_string_append_len(str, tmp, len > server->max_message_len ? |
111 | 169k | server->max_message_len : len); |
112 | 169k | } else { |
113 | 0 | g_string_append(str, cmd); |
114 | 0 | } |
115 | | |
116 | 169k | if (!raw) { |
117 | | /* Add CR+LF to command */ |
118 | 169k | g_string_append(str, "\r\n"); |
119 | 169k | } |
120 | | |
121 | 169k | if (irc_send_when == IRC_SEND_NOW) { |
122 | 108k | irc_server_send_and_redirect(server, str, server->redirect_next); |
123 | 108k | g_string_free(str, TRUE); |
124 | 108k | } else if (irc_send_when == IRC_SEND_NEXT) { |
125 | | /* add to queue */ |
126 | 0 | server->cmdqueue = g_slist_prepend(server->cmdqueue, server->redirect_next); |
127 | 0 | server->cmdqueue = g_slist_prepend(server->cmdqueue, g_string_free(str, FALSE)); |
128 | 61.2k | } else if (irc_send_when == IRC_SEND_NORMAL) { |
129 | 54.4k | server->cmdqueue = g_slist_insert(server->cmdqueue, server->redirect_next, pos); |
130 | 54.4k | server->cmdqueue = g_slist_insert(server->cmdqueue, g_string_free(str, FALSE), pos); |
131 | 54.4k | } else if (irc_send_when == IRC_SEND_LATER) { |
132 | 6.79k | server->cmdqueue = g_slist_append(server->cmdqueue, g_string_free(str, FALSE)); |
133 | 6.79k | server->cmdqueue = g_slist_append(server->cmdqueue, server->redirect_next); |
134 | 6.79k | server->cmdlater++; |
135 | 6.79k | } else { |
136 | 0 | g_warn_if_reached(); |
137 | 0 | } |
138 | | |
139 | 169k | server->redirect_next = NULL; |
140 | 169k | } |
141 | | |
142 | | /* Send command to IRC server */ |
143 | | void irc_send_cmd(IRC_SERVER_REC *server, const char *cmd) |
144 | 73.1k | { |
145 | 73.1k | gint64 now; |
146 | 73.1k | int send_now; |
147 | | |
148 | 73.1k | now = g_get_real_time(); |
149 | 73.1k | send_now = now >= server->wait_cmd && |
150 | 72.7k | (server->cmdcount < server->max_cmds_at_once || |
151 | 54.0k | server->cmd_queue_speed <= 0); |
152 | | |
153 | 73.1k | irc_send_cmd_full(server, cmd, send_now ? IRC_SEND_NOW : IRC_SEND_NORMAL, FALSE); |
154 | 73.1k | } |
155 | | |
156 | | /* Send command to IRC server */ |
157 | | void irc_send_cmdv(IRC_SERVER_REC *server, const char *cmd, ...) |
158 | 73.1k | { |
159 | 73.1k | va_list args; |
160 | 73.1k | char *str; |
161 | | |
162 | 73.1k | va_start(args, cmd); |
163 | | |
164 | 73.1k | str = g_strdup_vprintf(cmd, args); |
165 | 73.1k | irc_send_cmd(server, str); |
166 | 73.1k | g_free(str); |
167 | | |
168 | 73.1k | va_end(args); |
169 | 73.1k | } |
170 | | |
171 | | /* Send command to server immediately bypassing all flood protections |
172 | | and queues. */ |
173 | | void irc_send_cmd_now(IRC_SERVER_REC *server, const char *cmd) |
174 | 93.0k | { |
175 | 93.0k | g_return_if_fail(cmd != NULL); |
176 | | |
177 | 93.0k | irc_send_cmd_full(server, cmd, IRC_SEND_NOW, FALSE); |
178 | 93.0k | } |
179 | | |
180 | | /* Send command to server putting it at the beginning of the queue of |
181 | | commands to send -- it will go out as soon as possible in accordance |
182 | | to the flood protection settings. */ |
183 | | void irc_send_cmd_first(IRC_SERVER_REC *server, const char *cmd) |
184 | 0 | { |
185 | 0 | g_return_if_fail(cmd != NULL); |
186 | | |
187 | 0 | irc_send_cmd_full(server, cmd, IRC_SEND_NEXT, FALSE); |
188 | 0 | } |
189 | | |
190 | | /* Send command to server putting it at the end of the queue. */ |
191 | | void irc_send_cmd_later(IRC_SERVER_REC *server, const char *cmd) |
192 | 6.86k | { |
193 | 6.86k | g_return_if_fail(cmd != NULL); |
194 | | |
195 | 6.86k | irc_send_cmd_full(server, cmd, IRC_SEND_LATER, FALSE); |
196 | 6.86k | } |
197 | | |
198 | | static char *split_nicks(const char *cmd, char **pre, char **nicks, char **post, int arg) |
199 | 0 | { |
200 | 0 | char *p; |
201 | |
|
202 | 0 | *pre = g_strdup(cmd); |
203 | 0 | *post = *nicks = NULL; |
204 | |
|
205 | 0 | if (**pre == '@') { |
206 | | /* the message-tags "add" one space separated argument |
207 | | in front of the non message-tagged IRC commands. So |
208 | | the nicks are now off-set by one to the right. */ |
209 | 0 | arg++; |
210 | 0 | } |
211 | |
|
212 | 0 | for (p = *pre; *p != '\0'; p++) { |
213 | 0 | if (*p != ' ') |
214 | 0 | continue; |
215 | | |
216 | 0 | if (arg == 1) { |
217 | | /* text after nicks */ |
218 | 0 | *p++ = '\0'; |
219 | 0 | while (*p == ' ') p++; |
220 | 0 | *post = p; |
221 | 0 | break; |
222 | 0 | } |
223 | | |
224 | | /* find nicks */ |
225 | 0 | while (p[1] == ' ') p++; |
226 | 0 | if (--arg == 1) { |
227 | 0 | *p = '\0'; |
228 | 0 | *nicks = p+1; |
229 | 0 | } |
230 | 0 | } |
231 | |
|
232 | 0 | return *pre; |
233 | 0 | } |
234 | | |
235 | | void irc_send_cmd_split(IRC_SERVER_REC *server, const char *cmd, |
236 | | int nickarg, int max_nicks) |
237 | 0 | { |
238 | 0 | char *str, *pre, *post, *nicks; |
239 | 0 | char **nicklist, **tmp; |
240 | 0 | GString *nickstr; |
241 | 0 | int count; |
242 | |
|
243 | 0 | g_return_if_fail(server != NULL); |
244 | 0 | g_return_if_fail(cmd != NULL); |
245 | | |
246 | 0 | str = split_nicks(cmd, &pre, &nicks, &post, nickarg); |
247 | 0 | if (nicks == NULL) { |
248 | | /* no nicks given? */ |
249 | 0 | g_free(str); |
250 | 0 | return; |
251 | 0 | } |
252 | | |
253 | | /* split the nicks */ |
254 | 0 | nickstr = g_string_new(NULL); |
255 | 0 | nicklist = g_strsplit(nicks, ",", -1); count = 0; |
256 | |
|
257 | 0 | tmp = nicklist; |
258 | 0 | for (;; tmp++) { |
259 | 0 | if (*tmp != NULL) { |
260 | 0 | g_string_append_printf(nickstr, "%s,", *tmp); |
261 | 0 | if (++count < max_nicks) |
262 | 0 | continue; |
263 | 0 | } |
264 | | |
265 | 0 | count = 0; |
266 | 0 | if (nickstr->len > 0) |
267 | 0 | g_string_truncate(nickstr, nickstr->len-1); |
268 | |
|
269 | 0 | if (post == NULL) |
270 | 0 | irc_send_cmdv(server, "%s %s", pre, nickstr->str); |
271 | 0 | else |
272 | 0 | irc_send_cmdv(server, "%s %s %s", pre, nickstr->str, post); |
273 | |
|
274 | 0 | g_string_truncate(nickstr, 0); |
275 | |
|
276 | 0 | if (*tmp == NULL || tmp[1] == NULL) |
277 | 0 | break; |
278 | 0 | } |
279 | 0 | g_strfreev(nicklist); |
280 | 0 | g_string_free(nickstr, TRUE); |
281 | |
|
282 | 0 | g_free(str); |
283 | 0 | } |
284 | | |
285 | | /* Get next parameter */ |
286 | | char *event_get_param(char **data) |
287 | 6.22M | { |
288 | 6.22M | char *pos; |
289 | | |
290 | 6.22M | g_return_val_if_fail(data != NULL, NULL); |
291 | 6.22M | g_return_val_if_fail(*data != NULL, NULL); |
292 | | |
293 | 6.22M | if (**data == ':') { |
294 | | /* last parameter */ |
295 | 81.8k | pos = *data; |
296 | 81.8k | *data += strlen(*data); |
297 | 81.8k | return pos+1; |
298 | 81.8k | } |
299 | | |
300 | 6.14M | pos = *data; |
301 | 99.9M | while (**data != '\0' && **data != ' ') (*data)++; |
302 | 6.14M | if (**data == ' ') *(*data)++ = '\0'; |
303 | | |
304 | 6.14M | return pos; |
305 | 6.22M | } |
306 | | |
307 | | /* Get count parameters from data */ |
308 | | char *event_get_params(const char *data, int count, ...) |
309 | 2.29M | { |
310 | 2.29M | char **str, *tmp, *duprec, *datad; |
311 | 2.29M | gboolean rest; |
312 | 2.29M | va_list args; |
313 | | |
314 | 2.29M | g_return_val_if_fail(data != NULL, NULL); |
315 | | |
316 | 2.29M | va_start(args, count); |
317 | 2.29M | duprec = datad = g_strdup(data); |
318 | | |
319 | 2.29M | rest = count & PARAM_FLAG_GETREST; |
320 | 2.29M | count = PARAM_WITHOUT_FLAGS(count); |
321 | | |
322 | 8.68M | while (count-- > 0) { |
323 | 6.39M | str = (char **) va_arg(args, char **); |
324 | 6.39M | if (count == 0 && rest) { |
325 | | /* Put the rest into the last parameter. */ |
326 | 164k | strip_params_colon(datad); |
327 | 164k | tmp = datad; |
328 | 6.22M | } else { |
329 | 6.22M | tmp = event_get_param(&datad); |
330 | 6.22M | } |
331 | 6.39M | if (str != NULL) *str = tmp; |
332 | 6.39M | } |
333 | 2.29M | va_end(args); |
334 | | |
335 | 2.29M | return duprec; |
336 | 2.29M | } |
337 | | |
338 | | /* Given a string containing <params>, strip any colon prefixing <trailing>. */ |
339 | | static void strip_params_colon(char *const params) |
340 | 164k | { |
341 | 164k | char *s; |
342 | | |
343 | 164k | if (params == NULL) { |
344 | 0 | return; |
345 | 0 | } |
346 | | |
347 | 164k | s = params; |
348 | 825k | while (*s != '\0') { |
349 | 780k | if (*s == ':') { |
350 | 5.78k | memmove(s, s+1, strlen(s+1)+1); |
351 | 5.78k | return; |
352 | 5.78k | } |
353 | | |
354 | 775k | s = strchr(s, ' '); |
355 | 775k | if (s == NULL) { |
356 | 113k | return; |
357 | 113k | } |
358 | | |
359 | 1.59M | while (*s == ' ') { |
360 | 934k | s++; |
361 | 934k | } |
362 | 661k | } |
363 | 164k | } |
364 | | |
365 | | static void irc_server_event(IRC_SERVER_REC *server, const char *line, |
366 | | const char *nick, const char *address) |
367 | 1.03M | { |
368 | 1.03M | const char *signal; |
369 | 1.03M | char *event, *args; |
370 | | |
371 | 1.03M | g_return_if_fail(line != NULL); |
372 | | |
373 | | /* split event / args */ |
374 | 1.03M | event = g_strconcat("event ", line, NULL); |
375 | 1.03M | args = strchr(event+6, ' '); |
376 | 1.03M | if (args != NULL) *args++ = '\0'; else args = ""; |
377 | 1.13M | while (*args == ' ') args++; |
378 | 1.03M | ascii_strdown(event); |
379 | | |
380 | | /* check if event needs to be redirected */ |
381 | 1.03M | signal = server_redirect_get_signal(server, nick, event, args); |
382 | 1.03M | if (signal == NULL) |
383 | 1.03M | signal = event; |
384 | 3.10k | else |
385 | 3.10k | rawlog_redirect(server->rawlog, signal); |
386 | | |
387 | | /* emit it */ |
388 | 1.03M | current_server_event = event+6; |
389 | 1.03M | if (!signal_emit(signal, 4, server, args, nick, address)) |
390 | 346k | signal_emit_id(signal_default_event, 4, server, line, nick, address); |
391 | 1.03M | current_server_event = NULL; |
392 | | |
393 | 1.03M | g_free(event); |
394 | 1.03M | } |
395 | | |
396 | | static void unescape_tag(char *tag) |
397 | 8.68k | { |
398 | 8.68k | char *tmp; |
399 | | |
400 | 8.68k | if (tag == NULL) |
401 | 7.75k | return; |
402 | | |
403 | 929 | tmp = tag; |
404 | 4.51M | for (; *tmp != '\0'; tmp++, tag++) { |
405 | 4.51M | if (*tmp == '\\') { |
406 | 425 | tmp++; |
407 | 425 | if (*tmp == '\0') |
408 | 207 | break; |
409 | 218 | switch (*tmp) { |
410 | 0 | case ':': |
411 | 0 | *tag = ';'; |
412 | 0 | break; |
413 | 0 | case 'n': |
414 | 0 | *tag = '\n'; |
415 | 0 | break; |
416 | 0 | case 'r': |
417 | 0 | *tag = '\r'; |
418 | 0 | break; |
419 | 0 | case 's': |
420 | 0 | *tag = ' '; |
421 | 0 | break; |
422 | 218 | default: |
423 | 218 | *tag = *tmp; |
424 | 218 | break; |
425 | 218 | } |
426 | 4.51M | } else { |
427 | 4.51M | *tag = *tmp; |
428 | 4.51M | } |
429 | 4.51M | } |
430 | 929 | *tag = '\0'; |
431 | 929 | } |
432 | | |
433 | | static gboolean i_str0_equal(const char *s1, const char *s2) |
434 | 1.37k | { |
435 | 1.37k | return g_strcmp0(s1, s2) == 0; |
436 | 1.37k | } |
437 | | |
438 | | GHashTable *irc_parse_message_tags(const char *tags) |
439 | 3.55k | { |
440 | 3.55k | char **split, **tmp, **kv; |
441 | 3.55k | GHashTable *hash; |
442 | | |
443 | 3.55k | hash = g_hash_table_new_full(g_str_hash, (GEqualFunc) i_str0_equal, |
444 | 3.55k | (GDestroyNotify) i_refstr_release, (GDestroyNotify) g_free); |
445 | 3.55k | split = g_strsplit(tags, ";", -1); |
446 | 12.4k | for (tmp = split; *tmp != NULL; tmp++) { |
447 | 8.89k | if (*tmp[0] == '\0') |
448 | 214 | continue; |
449 | 8.68k | kv = g_strsplit(*tmp, "=", 2); |
450 | 8.68k | unescape_tag(kv[1]); |
451 | 8.68k | g_hash_table_replace(hash, i_refstr_intern(kv[0]), |
452 | 8.68k | g_strdup(kv[1] == NULL ? "" : kv[1])); |
453 | 8.68k | g_strfreev(kv); |
454 | 8.68k | } |
455 | 3.55k | g_strfreev(split); |
456 | 3.55k | return hash; |
457 | 3.55k | } |
458 | | |
459 | | static void irc_server_event_tags(IRC_SERVER_REC *server, const char *line, const char *nick, |
460 | | const char *address, const char *tags) |
461 | 1.03M | { |
462 | 1.03M | char *timestr; |
463 | 1.03M | GHashTable *tags_hash = NULL; |
464 | | |
465 | 1.03M | if (tags != NULL && *tags != '\0') { |
466 | 3.55k | tags_hash = irc_parse_message_tags(tags); |
467 | 3.55k | if ((timestr = g_hash_table_lookup(tags_hash, "time")) != NULL) { |
468 | 783 | server_meta_stash(SERVER(server), "time", timestr); |
469 | 783 | } |
470 | 3.55k | } |
471 | | |
472 | 1.03M | if (*line != '\0') |
473 | 1.03M | signal_emit_id(signal_server_event, 4, server, line, nick, address); |
474 | | |
475 | 1.03M | if (tags_hash != NULL) |
476 | 3.55k | g_hash_table_destroy(tags_hash); |
477 | 1.03M | } |
478 | | |
479 | | static char *irc_parse_prefix(char *line, char **nick, char **address, char **tags) |
480 | 1.04M | { |
481 | 1.04M | char *p; |
482 | | |
483 | 1.04M | *nick = *address = *tags = NULL; |
484 | | |
485 | | /* ["@" <tags> SPACE] :<nick> [["!" <user>] "@" <host>] SPACE */ |
486 | | |
487 | 1.04M | if (*line == '@') { |
488 | 3.55k | *tags = ++line; |
489 | 6.75M | while (*line != '\0' && *line != ' ') { |
490 | 6.75M | line++; |
491 | 6.75M | } |
492 | 3.55k | if (*line == ' ') { |
493 | 2.40k | *line++ = '\0'; |
494 | 3.27k | while (*line == ' ') line++; |
495 | 2.40k | } |
496 | 3.55k | } |
497 | | |
498 | 1.04M | if (*line != ':') |
499 | 631k | return line; |
500 | | |
501 | 410k | *nick = ++line; p = NULL; |
502 | 4.98M | while (*line != '\0' && *line != ' ') { |
503 | 4.57M | if (*line == '!' || *line == '@') { |
504 | 35.6k | p = line; |
505 | 35.6k | if (*line == '!') |
506 | 743 | break; |
507 | 35.6k | } |
508 | 4.57M | line++; |
509 | 4.57M | } |
510 | | |
511 | 410k | if (p != NULL) { |
512 | 31.7k | line = p; |
513 | 31.7k | *line++ = '\0'; |
514 | 31.7k | *address = line; |
515 | 708k | while (*line != '\0' && *line != ' ') |
516 | 677k | line++; |
517 | 31.7k | } |
518 | | |
519 | 410k | if (*line == ' ') { |
520 | 403k | *line++ = '\0'; |
521 | 427k | while (*line == ' ') line++; |
522 | 403k | } |
523 | | |
524 | 410k | return line; |
525 | 1.04M | } |
526 | | |
527 | | /* Parse command line sent by server */ |
528 | | static void irc_parse_incoming_line(IRC_SERVER_REC *server, char *line) |
529 | 1.04M | { |
530 | 1.04M | char *nick, *address, *tags; |
531 | | |
532 | 1.04M | g_return_if_fail(server != NULL); |
533 | 1.04M | g_return_if_fail(line != NULL); |
534 | | |
535 | 1.04M | line = irc_parse_prefix(line, &nick, &address, &tags); |
536 | 1.04M | if (*line != '\0' || tags != NULL) |
537 | 1.03M | signal_emit_id(signal_server_event_tags, 5, server, line, nick, address, tags); |
538 | | |
539 | 1.04M | server_meta_clear_all(SERVER(server)); |
540 | 1.04M | } |
541 | | |
542 | | /* input function: handle incoming server messages */ |
543 | | static void irc_parse_incoming(SERVER_REC *server) |
544 | 0 | { |
545 | 0 | char *str; |
546 | 0 | int count; |
547 | 0 | int ret; |
548 | |
|
549 | 0 | g_return_if_fail(server != NULL); |
550 | | |
551 | | /* Some commands can send huge replies and irssi might handle them |
552 | | too slowly, so read only a few times from the socket before |
553 | | letting other tasks to run. */ |
554 | 0 | count = 0; |
555 | 0 | ret = 0; |
556 | 0 | server_ref(server); |
557 | 0 | while (!server->disconnected && |
558 | 0 | (ret = net_sendbuffer_receive_line(server->handle, &str, count < MAX_SOCKET_READS)) > 0) { |
559 | 0 | rawlog_input(server->rawlog, str); |
560 | 0 | signal_emit_id(signal_server_incoming, 2, server, str); |
561 | |
|
562 | 0 | if (server->connection_lost) |
563 | 0 | server_disconnect(server); |
564 | |
|
565 | 0 | count++; |
566 | 0 | } |
567 | 0 | if (ret == -1) { |
568 | | /* connection lost */ |
569 | 0 | server->connection_lost = TRUE; |
570 | 0 | server_disconnect(server); |
571 | 0 | } |
572 | 0 | server_unref(server); |
573 | 0 | } |
574 | | |
575 | | static void irc_init_server(IRC_SERVER_REC *server) |
576 | 0 | { |
577 | 0 | g_return_if_fail(server != NULL); |
578 | | |
579 | 0 | if (!IS_IRC_SERVER(server)) |
580 | 0 | return; |
581 | | |
582 | 0 | server->readtag = i_input_add(net_sendbuffer_handle(server->handle), I_INPUT_READ, |
583 | 0 | (GInputFunction) irc_parse_incoming, server); |
584 | 0 | } |
585 | | |
586 | | void irc_irc_init(void) |
587 | 41.5k | { |
588 | 41.5k | signal_add("server event", (SIGNAL_FUNC) irc_server_event); |
589 | 41.5k | signal_add("server event tags", (SIGNAL_FUNC) irc_server_event_tags); |
590 | 41.5k | signal_add("server connected", (SIGNAL_FUNC) irc_init_server); |
591 | 41.5k | signal_add("server connection switched", (SIGNAL_FUNC) irc_init_server); |
592 | 41.5k | signal_add("server incoming", (SIGNAL_FUNC) irc_parse_incoming_line); |
593 | | |
594 | 41.5k | current_server_event = NULL; |
595 | 41.5k | signal_default_event = signal_get_uniq_id("default event"); |
596 | 41.5k | signal_server_event = signal_get_uniq_id("server event"); |
597 | 41.5k | signal_server_event_tags = signal_get_uniq_id("server event tags"); |
598 | 41.5k | signal_server_incoming = signal_get_uniq_id("server incoming"); |
599 | 41.5k | } |
600 | | |
601 | | void irc_irc_deinit(void) |
602 | 41.5k | { |
603 | 41.5k | signal_remove("server event", (SIGNAL_FUNC) irc_server_event); |
604 | 41.5k | signal_remove("server event tags", (SIGNAL_FUNC) irc_server_event_tags); |
605 | 41.5k | signal_remove("server connected", (SIGNAL_FUNC) irc_init_server); |
606 | 41.5k | signal_remove("server connection switched", (SIGNAL_FUNC) irc_init_server); |
607 | | signal_remove("server incoming", (SIGNAL_FUNC) irc_parse_incoming_line); |
608 | 41.5k | } |