Mercurial > pidgin
annotate src/protocols/irc/parse.c @ 8944:f041cc8d86cf
[gaim-migrate @ 9716]
Fully replace Ignore colors, Ignore font faces and Ignore font sizes with
Ignore formatting on incoming messages.
nosnilmot: I chose not to apply your change to set_away_option because
people should not attempt to set a preference with a NULL value, and
if they do we might as well just have Gaim crash so they know about it.
My reasoning might be flawed. Eh.
Also, Chip and Etan were both against consolidating these options,
so someone might want to keep a patch of this commit handy so we can
revert it, if necessary.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sun, 16 May 2004 05:25:37 +0000 |
parents | 478b6184152d |
children | c60f82d78dea |
rev | line source |
---|---|
6333 | 1 /** |
2 * @file parse.c | |
8351 | 3 * |
6333 | 4 * gaim |
5 * | |
6 * Copyright (C) 2003, Ethan Blanton <eblanton@cs.purdue.edu> | |
8351 | 7 * |
6333 | 8 * This program is free software; you can redistribute it and/or modify |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 */ | |
22 | |
23 #include "internal.h" | |
24 | |
25 #include "accountopt.h" | |
26 #include "conversation.h" | |
27 #include "notify.h" | |
28 #include "debug.h" | |
29 #include "irc.h" | |
30 | |
31 #include <stdio.h> | |
32 #include <stdlib.h> | |
33 #include <ctype.h> | |
34 | |
35 static char *irc_send_convert(struct irc_conn *irc, const char *string); | |
36 static char *irc_recv_convert(struct irc_conn *irc, const char *string); | |
37 | |
38 static void irc_parse_error_cb(struct irc_conn *irc, char *input); | |
39 | |
40 static char *irc_mirc_colors[16] = { | |
41 "white", "black", "blue", "dark green", "red", "brown", "purple", | |
42 "orange", "yellow", "green", "teal", "cyan", "light blue", | |
43 "pink", "grey", "light grey" }; | |
44 | |
45 /*typedef void (*IRCMsgCallback)(struct irc_conn *irc, char *from, char *name, char **args);*/ | |
46 static struct _irc_msg { | |
47 char *name; | |
48 char *format; | |
49 void (*cb)(struct irc_conn *irc, const char *name, const char *from, char **args); | |
50 } _irc_msgs[] = { | |
51 { "301", "nn:", irc_msg_away }, /* User is away */ | |
52 { "303", "n:", irc_msg_ison }, /* ISON reply */ | |
53 { "311", "nnvvv:", irc_msg_whois }, /* Whois user */ | |
54 { "312", "nnv:", irc_msg_whois }, /* Whois server */ | |
55 { "313", "nn:", irc_msg_whois }, /* Whois ircop */ | |
56 { "317", "nnvv", irc_msg_whois }, /* Whois idle */ | |
57 { "318", "nt:", irc_msg_endwhois }, /* End of WHOIS */ | |
58 { "319", "nn:", irc_msg_whois }, /* Whois channels */ | |
59 { "320", "nn:", irc_msg_whois }, /* Whois (fn ident) */ | |
8114 | 60 { "321", "*", irc_msg_list }, /* Start of list */ |
61 { "322", "ncv:", irc_msg_list }, /* List. */ | |
62 { "323", ":", irc_msg_list }, /* End of list. */ | |
6333 | 63 { "324", "ncv:", irc_msg_chanmode }, /* Channel modes */ |
64 { "331", "nc:", irc_msg_topic }, /* No channel topic */ | |
65 { "332", "nc:", irc_msg_topic }, /* Channel topic */ | |
66 { "333", "*", irc_msg_ignore }, /* Topic setter stuff */ | |
67 { "353", "nvc:", irc_msg_names }, /* Names list */ | |
68 { "366", "nc:", irc_msg_names }, /* End of names */ | |
69 { "372", "n:", irc_msg_motd }, /* MOTD */ | |
70 { "375", "n:", irc_msg_motd }, /* Start MOTD */ | |
71 { "376", "n:", irc_msg_endmotd }, /* End of MOTD */ | |
72 { "401", "nt:", irc_msg_nonick }, /* No such nick/chan */ | |
7877 | 73 { "403", "nc:", irc_msg_nochan }, /* No such channel */ |
6333 | 74 { "404", "nt:", irc_msg_nosend }, /* Cannot send to chan */ |
75 { "421", "nv:", irc_msg_unknown }, /* Unknown command */ | |
6350 | 76 { "422", "nv:", irc_msg_endmotd }, /* No MOTD available */ |
6333 | 77 { "433", "vn:", irc_msg_nickused }, /* Nickname already in use */ |
6718 | 78 { "438", "nn:", irc_msg_nochangenick }, /* Nick may not change */ |
6333 | 79 { "442", "nc:", irc_msg_notinchan }, /* Not in channel */ |
80 { "473", "nc:", irc_msg_inviteonly }, /* Tried to join invite-only */ | |
81 { "474", "nc:", irc_msg_banned }, /* Banned from channel */ | |
82 { "482", "nc:", irc_msg_notop }, /* Need to be op to do that */ | |
83 { "501", "n:", irc_msg_badmode }, /* Unknown mode flag */ | |
8404 | 84 { "506", "nc:", irc_msg_nosend }, /* Must identify to send */ |
6714 | 85 { "515", "nc:", irc_msg_regonly }, /* Registration required */ |
6333 | 86 { "invite", "n:", irc_msg_invite }, /* Invited */ |
87 { "join", ":", irc_msg_join }, /* Joined a channel */ | |
88 { "kick", "cn:", irc_msg_kick }, /* KICK */ | |
89 { "mode", "tv:", irc_msg_mode }, /* MODE for channel */ | |
90 { "nick", ":", irc_msg_nick }, /* Nick change */ | |
91 { "notice", "t:", irc_msg_notice }, /* NOTICE recv */ | |
92 { "part", "c:", irc_msg_part }, /* Parted a channel */ | |
93 { "ping", ":", irc_msg_ping }, /* Received PING from server */ | |
94 { "pong", "v:", irc_msg_pong }, /* Received PONG from server */ | |
95 { "privmsg", "t:", irc_msg_privmsg }, /* Received private message */ | |
96 { "topic", "c:", irc_msg_topic }, /* TOPIC command */ | |
97 { "quit", ":", irc_msg_quit }, /* QUIT notice */ | |
98 { "wallops", ":", irc_msg_wallops }, /* WALLOPS command */ | |
99 { NULL, NULL, NULL } | |
100 }; | |
101 | |
102 static struct _irc_user_cmd { | |
103 char *name; | |
104 char *format; | |
105 IRCCmdCallback cb; | |
106 } _irc_cmds[] = { | |
8627 | 107 { "action", ":", irc_cmd_ctcp_action }, |
6333 | 108 { "away", ":", irc_cmd_away }, |
109 { "deop", ":", irc_cmd_op }, | |
110 { "devoice", ":", irc_cmd_op }, | |
6415
e3be6b9744b7
[gaim-migrate @ 6922]
Christian Hammond <chipx86@chipx86.com>
parents:
6350
diff
changeset
|
111 { "help", "v", irc_cmd_help }, |
6333 | 112 { "invite", ":", irc_cmd_invite }, |
113 { "j", "cv", irc_cmd_join }, | |
114 { "join", "cv", irc_cmd_join }, | |
115 { "kick", "n:", irc_cmd_kick }, | |
8114 | 116 { "list", ":", irc_cmd_list }, |
6333 | 117 { "me", ":", irc_cmd_ctcp_action }, |
118 { "mode", ":", irc_cmd_mode }, | |
119 { "msg", "t:", irc_cmd_privmsg }, | |
120 { "names", "c", irc_cmd_names }, | |
121 { "nick", "n", irc_cmd_nick }, | |
122 { "op", ":", irc_cmd_op }, | |
123 { "operwall", ":", irc_cmd_wallops }, | |
124 { "part", "c:", irc_cmd_part }, | |
125 { "ping", "n", irc_cmd_ping }, | |
126 { "query", "n:", irc_cmd_query }, | |
127 { "quit", ":", irc_cmd_quit }, | |
128 { "quote", "*", irc_cmd_quote }, | |
129 { "remove", "n:", irc_cmd_remove }, | |
130 { "topic", ":", irc_cmd_topic }, | |
131 { "umode", ":", irc_cmd_mode }, | |
132 { "voice", ":", irc_cmd_op }, | |
133 { "wallops", ":", irc_cmd_wallops }, | |
134 { "whois", "n", irc_cmd_whois }, | |
7631 | 135 { NULL, NULL, NULL } |
6333 | 136 }; |
137 | |
138 static char *irc_send_convert(struct irc_conn *irc, const char *string) | |
139 { | |
140 char *utf8; | |
141 GError *err = NULL; | |
142 | |
143 utf8 = g_convert(string, strlen(string), | |
144 gaim_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET), | |
145 "UTF-8", NULL, NULL, &err); | |
146 if (err) { | |
147 gaim_debug(GAIM_DEBUG_ERROR, "irc", "send conversion error: %s\n", err->message); | |
148 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Sending raw, which probably isn't right\n"); | |
149 utf8 = g_strdup(string); | |
150 } | |
151 | |
152 return utf8; | |
153 } | |
154 | |
155 static char *irc_recv_convert(struct irc_conn *irc, const char *string) | |
156 { | |
157 char *utf8; | |
158 GError *err = NULL; | |
159 | |
160 utf8 = g_convert(string, strlen(string), "UTF-8", | |
161 gaim_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET), | |
162 NULL, NULL, &err); | |
163 if (err) { | |
164 gaim_debug(GAIM_DEBUG_ERROR, "irc", "recv conversion error: %s\n", err->message); | |
165 utf8 = g_strdup(_("(There was an error converting this message. Check the 'Encoding' option in the Account Editor)")); | |
166 } | |
167 | |
168 return utf8; | |
169 } | |
170 | |
171 /* XXX tag closings are not necessarily correctly nested here! If we | |
172 * get a ^O or reach the end of the string and there are open | |
173 * tags, they are closed in a fixed order ... this means, for | |
174 * example, you might see <FONT COLOR="blue">some text <B>with | |
175 * various attributes</FONT></B> (notice that B and FONT overlap | |
176 * and are not cleanly nested). This is imminently fixable but | |
177 * I am not fixing it right now. | |
178 */ | |
179 char *irc_mirc2html(const char *string) | |
180 { | |
181 const char *cur, *end; | |
182 char fg[3] = "\0\0", bg[3] = "\0\0"; | |
183 int fgnum, bgnum; | |
6754 | 184 int font = 0, bold = 0, underline = 0; |
6333 | 185 GString *decoded = g_string_sized_new(strlen(string)); |
186 | |
187 cur = string; | |
188 do { | |
6754 | 189 end = strpbrk(cur, "\002\003\007\017\026\037"); |
6333 | 190 |
191 decoded = g_string_append_len(decoded, cur, end ? end - cur : strlen(cur)); | |
192 cur = end ? end : cur + strlen(cur); | |
193 | |
194 switch (*cur) { | |
195 case '\002': | |
196 cur++; | |
197 if (!bold) { | |
198 decoded = g_string_append(decoded, "<B>"); | |
199 bold = TRUE; | |
200 } else { | |
201 decoded = g_string_append(decoded, "</B>"); | |
202 bold = FALSE; | |
203 } | |
204 break; | |
205 case '\003': | |
206 cur++; | |
207 fg[0] = fg[1] = bg[0] = bg[1] = '\0'; | |
208 if (isdigit(*cur)) | |
209 fg[0] = *cur++; | |
210 if (isdigit(*cur)) | |
211 fg[1] = *cur++; | |
212 if (*cur == ',') { | |
213 cur++; | |
214 if (isdigit(*cur)) | |
215 bg[0] = *cur++; | |
216 if (isdigit(*cur)) | |
217 bg[1] = *cur++; | |
218 } | |
219 if (font) { | |
220 decoded = g_string_append(decoded, "</FONT>"); | |
221 font = FALSE; | |
222 } | |
223 | |
224 if (fg[0]) { | |
225 fgnum = atoi(fg); | |
226 if (fgnum < 0 || fgnum > 15) | |
227 continue; | |
228 font = TRUE; | |
229 g_string_append_printf(decoded, "<FONT COLOR=\"%s\"", irc_mirc_colors[fgnum]); | |
230 if (bg[0]) { | |
231 bgnum = atoi(bg); | |
232 if (bgnum >= 0 && bgnum < 16) | |
233 g_string_append_printf(decoded, " BACK=\"%s\"", irc_mirc_colors[bgnum]); | |
234 } | |
235 decoded = g_string_append_c(decoded, '>'); | |
236 } | |
237 break; | |
6754 | 238 case '\037': |
239 cur++; | |
240 if (!underline) { | |
241 decoded = g_string_append(decoded, "<U>"); | |
242 underline = TRUE; | |
243 } else { | |
244 decoded = g_string_append(decoded, "</U>"); | |
245 underline = TRUE; | |
246 } | |
247 break; | |
6333 | 248 case '\007': |
249 case '\026': | |
250 cur++; | |
251 break; | |
252 case '\017': | |
253 cur++; | |
254 /* fallthrough */ | |
255 case '\000': | |
256 if (bold) | |
6754 | 257 decoded = g_string_append(decoded, "</B>"); |
258 if (underline) | |
259 decoded = g_string_append(decoded, "</U>"); | |
6333 | 260 if (font) |
261 decoded = g_string_append(decoded, "</FONT>"); | |
262 break; | |
263 default: | |
264 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Unexpected mIRC formatting character %d\n", *cur); | |
265 } | |
266 } while (*cur); | |
267 | |
268 return g_string_free(decoded, FALSE); | |
269 } | |
270 | |
8529 | 271 char *irc_mirc2txt (const char *string) |
272 { | |
273 char *result = g_strdup (string); | |
274 int i, j; | |
275 | |
276 for (i = 0, j = 0; result[i]; i++) { | |
277 switch (result[i]) { | |
278 case '\002': | |
279 case '\003': | |
280 case '\007': | |
281 case '\017': | |
282 case '\026': | |
283 case '\037': | |
284 continue; | |
285 default: | |
286 result[j++] = result[i]; | |
287 } | |
288 } | |
289 result[i] = '\0'; | |
290 return result; | |
291 } | |
292 | |
6333 | 293 char *irc_parse_ctcp(struct irc_conn *irc, const char *from, const char *to, const char *msg, int notice) |
294 { | |
295 GaimConnection *gc; | |
296 const char *cur = msg + 1; | |
297 char *buf, *ctcp; | |
298 time_t timestamp; | |
299 | |
6754 | 300 /* Note that this is NOT correct w.r.t. multiple CTCPs in one |
301 * message and low-level quoting ... but if you want that crap, | |
302 * use a real IRC client. */ | |
303 | |
6333 | 304 if (msg[0] != '\001' || msg[strlen(msg) - 1] != '\001') |
305 return g_strdup(msg); | |
306 | |
307 if (!strncmp(cur, "ACTION ", 7)) { | |
308 cur += 7; | |
309 buf = g_strdup_printf("/me %s", cur); | |
310 buf[strlen(buf) - 1] = '\0'; | |
311 return buf; | |
312 } else if (!strncmp(cur, "PING ", 5)) { | |
313 if (notice) { /* reply */ | |
314 sscanf(cur, "PING %lu", ×tamp); | |
315 gc = gaim_account_get_connection(irc->account); | |
316 if (!gc) | |
317 return NULL; | |
6350 | 318 buf = g_strdup_printf(_("Reply time from %s: %lu seconds"), from, time(NULL) - timestamp); |
6333 | 319 gaim_notify_info(gc, _("PONG"), _("CTCP PING reply"), buf); |
320 g_free(buf); | |
321 return NULL; | |
322 } else { | |
323 buf = irc_format(irc, "vt:", "NOTICE", from, msg); | |
324 irc_send(irc, buf); | |
325 g_free(buf); | |
326 gc = gaim_account_get_connection(irc->account); | |
327 } | |
328 } else if (!strncmp(cur, "VERSION", 7) && !notice) { | |
329 buf = irc_format(irc, "vt:", "NOTICE", from, "\001VERSION Gaim IRC\001"); | |
330 irc_send(irc, buf); | |
331 g_free(buf); | |
8351 | 332 } else if (!strncmp(cur, "DCC SEND ", 9)) { |
333 irc_dccsend_recv(irc, from, msg + 10); | |
334 return NULL; | |
6333 | 335 } |
336 | |
337 ctcp = g_strdup(msg + 1); | |
338 ctcp[strlen(ctcp) - 1] = '\0'; | |
339 buf = g_strdup_printf("Received CTCP '%s' (to %s) from %s", ctcp, to, from); | |
340 g_free(ctcp); | |
341 return buf; | |
342 } | |
343 | |
344 void irc_msg_table_build(struct irc_conn *irc) | |
345 { | |
346 int i; | |
347 | |
348 if (!irc || !irc->msgs) { | |
349 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a message table on a bogus structure\n"); | |
350 return; | |
351 } | |
352 | |
353 for (i = 0; _irc_msgs[i].name; i++) { | |
354 g_hash_table_insert(irc->msgs, (gpointer)_irc_msgs[i].name, (gpointer)&_irc_msgs[i]); | |
355 } | |
356 } | |
357 | |
358 void irc_cmd_table_build(struct irc_conn *irc) | |
359 { | |
360 int i; | |
361 | |
362 if (!irc || !irc->cmds) { | |
363 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a command table on a bogus structure\n"); | |
364 return; | |
365 } | |
366 | |
367 for (i = 0; _irc_cmds[i].name ; i++) { | |
368 g_hash_table_insert(irc->cmds, (gpointer)_irc_cmds[i].name, (gpointer)&_irc_cmds[i]); | |
369 } | |
370 } | |
371 | |
372 char *irc_format(struct irc_conn *irc, const char *format, ...) | |
373 { | |
374 GString *string = g_string_new(""); | |
375 char *tok, *tmp; | |
376 const char *cur; | |
377 va_list ap; | |
378 | |
379 va_start(ap, format); | |
380 for (cur = format; *cur; cur++) { | |
381 if (cur != format) | |
382 g_string_append_c(string, ' '); | |
383 | |
384 tok = va_arg(ap, char *); | |
385 switch (*cur) { | |
386 case 'v': | |
387 g_string_append(string, tok); | |
388 break; | |
389 case ':': | |
390 g_string_append_c(string, ':'); | |
391 /* no break! */ | |
392 case 't': | |
393 case 'n': | |
394 case 'c': | |
395 tmp = irc_send_convert(irc, tok); | |
396 g_string_append(string, tmp); | |
397 g_free(tmp); | |
398 break; | |
399 default: | |
400 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Invalid format character '%c'\n", *cur); | |
401 break; | |
402 } | |
403 } | |
404 va_end(ap); | |
405 g_string_append(string, "\r\n"); | |
406 return (g_string_free(string, FALSE)); | |
407 } | |
408 | |
409 void irc_parse_msg(struct irc_conn *irc, char *input) | |
410 { | |
411 struct _irc_msg *msgent; | |
412 char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg; | |
7631 | 413 guint i; |
6333 | 414 |
415 if (!strncmp(input, "PING ", 5)) { | |
416 msg = irc_format(irc, "vv", "PONG", input + 5); | |
417 irc_send(irc, msg); | |
418 g_free(msg); | |
419 return; | |
420 } else if (!strncmp(input, "ERROR ", 6)) { | |
7981 | 421 gaim_connection_error(gaim_account_get_connection(irc->account), _("Disconnected.")); |
6333 | 422 return; |
423 } | |
424 | |
425 if (input[0] != ':' || (cur = strchr(input, ' ')) == NULL) { | |
426 irc_parse_error_cb(irc, input); | |
427 return; | |
428 } | |
429 | |
430 from = g_strndup(&input[1], cur - &input[1]); | |
431 cur++; | |
432 end = strchr(cur, ' '); | |
433 if (!end) | |
434 end = cur + strlen(cur); | |
435 | |
436 tmp = g_strndup(cur, end - cur); | |
437 msgname = g_ascii_strdown(tmp, -1); | |
438 g_free(tmp); | |
439 | |
440 if ((msgent = g_hash_table_lookup(irc->msgs, msgname)) == NULL) { | |
441 irc_msg_default(irc, "", from, &input); | |
442 g_free(msgname); | |
443 g_free(from); | |
444 return; | |
445 } | |
446 g_free(msgname); | |
447 | |
448 args = g_new0(char *, strlen(msgent->format)); | |
449 for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) { | |
450 switch (fmt[i]) { | |
451 case 'v': | |
452 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
453 args[i] = g_strndup(cur, end - cur); | |
454 cur += end - cur; | |
455 break; | |
456 case 't': | |
457 case 'n': | |
458 case 'c': | |
459 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
460 tmp = g_strndup(cur, end - cur); | |
461 args[i] = irc_recv_convert(irc, tmp); | |
462 g_free(tmp); | |
463 cur += end - cur; | |
464 break; | |
465 case ':': | |
466 if (*cur == ':') cur++; | |
467 args[i] = irc_recv_convert(irc, cur); | |
468 cur = cur + strlen(cur); | |
469 break; | |
470 case '*': | |
471 args[i] = g_strdup(cur); | |
472 cur = cur + strlen(cur); | |
473 break; | |
474 default: | |
475 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]); | |
476 break; | |
477 } | |
478 } | |
6970 | 479 tmp = irc_recv_convert(irc, from); |
480 (msgent->cb)(irc, msgent->name, tmp, args); | |
481 g_free(tmp); | |
6333 | 482 for (i = 0; i < strlen(msgent->format); i++) { |
483 g_free(args[i]); | |
484 } | |
485 g_free(args); | |
486 g_free(from); | |
487 } | |
488 | |
489 int irc_parse_cmd(struct irc_conn *irc, const char *target, const char *cmdstr) | |
490 { | |
491 const char *cur, *end, *fmt; | |
492 char *tmp, *cmd, **args; | |
493 struct _irc_user_cmd *cmdent; | |
7631 | 494 guint i; |
495 int ret; | |
6333 | 496 |
497 cur = cmdstr; | |
498 end = strchr(cmdstr, ' '); | |
499 if (!end) | |
500 end = cur + strlen(cur); | |
501 | |
502 tmp = g_strndup(cur, end - cur); | |
503 cmd = g_utf8_strdown(tmp, -1); | |
504 g_free(tmp); | |
505 | |
506 if ((cmdent = g_hash_table_lookup(irc->cmds, cmd)) == NULL) { | |
507 ret = irc_cmd_default(irc, cmd, target, &cmdstr); | |
508 g_free(cmd); | |
509 return ret; | |
510 } | |
511 | |
512 args = g_new0(char *, strlen(cmdent->format)); | |
513 for (cur = end, fmt = cmdent->format, i = 0; fmt[i] && *cur++; i++) { | |
514 switch (fmt[i]) { | |
515 case 'v': | |
516 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
517 args[i] = g_strndup(cur, end - cur); | |
518 cur += end - cur; | |
519 break; | |
520 case 't': | |
521 case 'n': | |
522 case 'c': | |
523 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
524 args[i] = g_strndup(cur, end - cur); | |
525 cur += end - cur; | |
526 break; | |
527 case ':': | |
528 case '*': | |
529 args[i] = g_strdup(cur); | |
530 cur = cur + strlen(cur); | |
531 break; | |
532 default: | |
533 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid command format character '%c'\n", fmt[i]); | |
534 break; | |
535 } | |
536 } | |
537 ret = (cmdent->cb)(irc, cmd, target, (const char **)args); | |
538 for (i = 0; i < strlen(cmdent->format); i++) | |
539 g_free(args[i]); | |
540 g_free(args); | |
541 | |
542 g_free(cmd); | |
543 return ret; | |
544 } | |
545 | |
546 static void irc_parse_error_cb(struct irc_conn *irc, char *input) | |
547 { | |
548 gaim_debug(GAIM_DEBUG_WARNING, "irc", "Unrecognized string: %s\n", input); | |
549 } |