Mercurial > pidgin.yaz
annotate src/protocols/irc/parse.c @ 9067:1f2bbb359adb
[gaim-migrate @ 9843]
This fixes a bug where the account was always null until you actually
clicked on the account selector, instead of being the first selected
account. The only time this wouldn't happen was when the roomlist was
invoked with /list.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Wed, 26 May 2004 01:13:10 +0000 |
parents | c60f82d78dea |
children | 933a19e3a6b3 |
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); | |
8954 | 150 g_error_free(err); |
6333 | 151 } |
152 | |
153 return utf8; | |
154 } | |
155 | |
156 static char *irc_recv_convert(struct irc_conn *irc, const char *string) | |
157 { | |
158 char *utf8; | |
159 GError *err = NULL; | |
160 | |
161 utf8 = g_convert(string, strlen(string), "UTF-8", | |
162 gaim_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET), | |
163 NULL, NULL, &err); | |
164 if (err) { | |
165 gaim_debug(GAIM_DEBUG_ERROR, "irc", "recv conversion error: %s\n", err->message); | |
166 utf8 = g_strdup(_("(There was an error converting this message. Check the 'Encoding' option in the Account Editor)")); | |
8954 | 167 g_error_free(err); |
6333 | 168 } |
169 | |
170 return utf8; | |
171 } | |
172 | |
173 /* XXX tag closings are not necessarily correctly nested here! If we | |
174 * get a ^O or reach the end of the string and there are open | |
175 * tags, they are closed in a fixed order ... this means, for | |
176 * example, you might see <FONT COLOR="blue">some text <B>with | |
177 * various attributes</FONT></B> (notice that B and FONT overlap | |
178 * and are not cleanly nested). This is imminently fixable but | |
179 * I am not fixing it right now. | |
180 */ | |
181 char *irc_mirc2html(const char *string) | |
182 { | |
183 const char *cur, *end; | |
184 char fg[3] = "\0\0", bg[3] = "\0\0"; | |
185 int fgnum, bgnum; | |
6754 | 186 int font = 0, bold = 0, underline = 0; |
6333 | 187 GString *decoded = g_string_sized_new(strlen(string)); |
188 | |
189 cur = string; | |
190 do { | |
6754 | 191 end = strpbrk(cur, "\002\003\007\017\026\037"); |
6333 | 192 |
193 decoded = g_string_append_len(decoded, cur, end ? end - cur : strlen(cur)); | |
194 cur = end ? end : cur + strlen(cur); | |
195 | |
196 switch (*cur) { | |
197 case '\002': | |
198 cur++; | |
199 if (!bold) { | |
200 decoded = g_string_append(decoded, "<B>"); | |
201 bold = TRUE; | |
202 } else { | |
203 decoded = g_string_append(decoded, "</B>"); | |
204 bold = FALSE; | |
205 } | |
206 break; | |
207 case '\003': | |
208 cur++; | |
209 fg[0] = fg[1] = bg[0] = bg[1] = '\0'; | |
210 if (isdigit(*cur)) | |
211 fg[0] = *cur++; | |
212 if (isdigit(*cur)) | |
213 fg[1] = *cur++; | |
214 if (*cur == ',') { | |
215 cur++; | |
216 if (isdigit(*cur)) | |
217 bg[0] = *cur++; | |
218 if (isdigit(*cur)) | |
219 bg[1] = *cur++; | |
220 } | |
221 if (font) { | |
222 decoded = g_string_append(decoded, "</FONT>"); | |
223 font = FALSE; | |
224 } | |
225 | |
226 if (fg[0]) { | |
227 fgnum = atoi(fg); | |
228 if (fgnum < 0 || fgnum > 15) | |
229 continue; | |
230 font = TRUE; | |
231 g_string_append_printf(decoded, "<FONT COLOR=\"%s\"", irc_mirc_colors[fgnum]); | |
232 if (bg[0]) { | |
233 bgnum = atoi(bg); | |
234 if (bgnum >= 0 && bgnum < 16) | |
235 g_string_append_printf(decoded, " BACK=\"%s\"", irc_mirc_colors[bgnum]); | |
236 } | |
237 decoded = g_string_append_c(decoded, '>'); | |
238 } | |
239 break; | |
6754 | 240 case '\037': |
241 cur++; | |
242 if (!underline) { | |
243 decoded = g_string_append(decoded, "<U>"); | |
244 underline = TRUE; | |
245 } else { | |
246 decoded = g_string_append(decoded, "</U>"); | |
247 underline = TRUE; | |
248 } | |
249 break; | |
6333 | 250 case '\007': |
251 case '\026': | |
252 cur++; | |
253 break; | |
254 case '\017': | |
255 cur++; | |
256 /* fallthrough */ | |
257 case '\000': | |
258 if (bold) | |
6754 | 259 decoded = g_string_append(decoded, "</B>"); |
260 if (underline) | |
261 decoded = g_string_append(decoded, "</U>"); | |
6333 | 262 if (font) |
263 decoded = g_string_append(decoded, "</FONT>"); | |
264 break; | |
265 default: | |
266 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Unexpected mIRC formatting character %d\n", *cur); | |
267 } | |
268 } while (*cur); | |
269 | |
270 return g_string_free(decoded, FALSE); | |
271 } | |
272 | |
8529 | 273 char *irc_mirc2txt (const char *string) |
274 { | |
275 char *result = g_strdup (string); | |
276 int i, j; | |
277 | |
278 for (i = 0, j = 0; result[i]; i++) { | |
279 switch (result[i]) { | |
280 case '\002': | |
281 case '\003': | |
282 case '\007': | |
283 case '\017': | |
284 case '\026': | |
285 case '\037': | |
286 continue; | |
287 default: | |
288 result[j++] = result[i]; | |
289 } | |
290 } | |
291 result[i] = '\0'; | |
292 return result; | |
293 } | |
294 | |
6333 | 295 char *irc_parse_ctcp(struct irc_conn *irc, const char *from, const char *to, const char *msg, int notice) |
296 { | |
297 GaimConnection *gc; | |
298 const char *cur = msg + 1; | |
299 char *buf, *ctcp; | |
300 time_t timestamp; | |
301 | |
6754 | 302 /* Note that this is NOT correct w.r.t. multiple CTCPs in one |
303 * message and low-level quoting ... but if you want that crap, | |
304 * use a real IRC client. */ | |
305 | |
6333 | 306 if (msg[0] != '\001' || msg[strlen(msg) - 1] != '\001') |
307 return g_strdup(msg); | |
308 | |
309 if (!strncmp(cur, "ACTION ", 7)) { | |
310 cur += 7; | |
311 buf = g_strdup_printf("/me %s", cur); | |
312 buf[strlen(buf) - 1] = '\0'; | |
313 return buf; | |
314 } else if (!strncmp(cur, "PING ", 5)) { | |
315 if (notice) { /* reply */ | |
316 sscanf(cur, "PING %lu", ×tamp); | |
317 gc = gaim_account_get_connection(irc->account); | |
318 if (!gc) | |
319 return NULL; | |
6350 | 320 buf = g_strdup_printf(_("Reply time from %s: %lu seconds"), from, time(NULL) - timestamp); |
6333 | 321 gaim_notify_info(gc, _("PONG"), _("CTCP PING reply"), buf); |
322 g_free(buf); | |
323 return NULL; | |
324 } else { | |
325 buf = irc_format(irc, "vt:", "NOTICE", from, msg); | |
326 irc_send(irc, buf); | |
327 g_free(buf); | |
328 gc = gaim_account_get_connection(irc->account); | |
329 } | |
330 } else if (!strncmp(cur, "VERSION", 7) && !notice) { | |
331 buf = irc_format(irc, "vt:", "NOTICE", from, "\001VERSION Gaim IRC\001"); | |
332 irc_send(irc, buf); | |
333 g_free(buf); | |
8351 | 334 } else if (!strncmp(cur, "DCC SEND ", 9)) { |
335 irc_dccsend_recv(irc, from, msg + 10); | |
336 return NULL; | |
6333 | 337 } |
338 | |
339 ctcp = g_strdup(msg + 1); | |
340 ctcp[strlen(ctcp) - 1] = '\0'; | |
341 buf = g_strdup_printf("Received CTCP '%s' (to %s) from %s", ctcp, to, from); | |
342 g_free(ctcp); | |
343 return buf; | |
344 } | |
345 | |
346 void irc_msg_table_build(struct irc_conn *irc) | |
347 { | |
348 int i; | |
349 | |
350 if (!irc || !irc->msgs) { | |
351 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a message table on a bogus structure\n"); | |
352 return; | |
353 } | |
354 | |
355 for (i = 0; _irc_msgs[i].name; i++) { | |
356 g_hash_table_insert(irc->msgs, (gpointer)_irc_msgs[i].name, (gpointer)&_irc_msgs[i]); | |
357 } | |
358 } | |
359 | |
360 void irc_cmd_table_build(struct irc_conn *irc) | |
361 { | |
362 int i; | |
363 | |
364 if (!irc || !irc->cmds) { | |
365 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a command table on a bogus structure\n"); | |
366 return; | |
367 } | |
368 | |
369 for (i = 0; _irc_cmds[i].name ; i++) { | |
370 g_hash_table_insert(irc->cmds, (gpointer)_irc_cmds[i].name, (gpointer)&_irc_cmds[i]); | |
371 } | |
372 } | |
373 | |
374 char *irc_format(struct irc_conn *irc, const char *format, ...) | |
375 { | |
376 GString *string = g_string_new(""); | |
377 char *tok, *tmp; | |
378 const char *cur; | |
379 va_list ap; | |
380 | |
381 va_start(ap, format); | |
382 for (cur = format; *cur; cur++) { | |
383 if (cur != format) | |
384 g_string_append_c(string, ' '); | |
385 | |
386 tok = va_arg(ap, char *); | |
387 switch (*cur) { | |
388 case 'v': | |
389 g_string_append(string, tok); | |
390 break; | |
391 case ':': | |
392 g_string_append_c(string, ':'); | |
393 /* no break! */ | |
394 case 't': | |
395 case 'n': | |
396 case 'c': | |
397 tmp = irc_send_convert(irc, tok); | |
398 g_string_append(string, tmp); | |
399 g_free(tmp); | |
400 break; | |
401 default: | |
402 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Invalid format character '%c'\n", *cur); | |
403 break; | |
404 } | |
405 } | |
406 va_end(ap); | |
407 g_string_append(string, "\r\n"); | |
408 return (g_string_free(string, FALSE)); | |
409 } | |
410 | |
411 void irc_parse_msg(struct irc_conn *irc, char *input) | |
412 { | |
413 struct _irc_msg *msgent; | |
414 char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg; | |
7631 | 415 guint i; |
6333 | 416 |
417 if (!strncmp(input, "PING ", 5)) { | |
418 msg = irc_format(irc, "vv", "PONG", input + 5); | |
419 irc_send(irc, msg); | |
420 g_free(msg); | |
421 return; | |
422 } else if (!strncmp(input, "ERROR ", 6)) { | |
7981 | 423 gaim_connection_error(gaim_account_get_connection(irc->account), _("Disconnected.")); |
6333 | 424 return; |
425 } | |
426 | |
427 if (input[0] != ':' || (cur = strchr(input, ' ')) == NULL) { | |
428 irc_parse_error_cb(irc, input); | |
429 return; | |
430 } | |
431 | |
432 from = g_strndup(&input[1], cur - &input[1]); | |
433 cur++; | |
434 end = strchr(cur, ' '); | |
435 if (!end) | |
436 end = cur + strlen(cur); | |
437 | |
438 tmp = g_strndup(cur, end - cur); | |
439 msgname = g_ascii_strdown(tmp, -1); | |
440 g_free(tmp); | |
441 | |
442 if ((msgent = g_hash_table_lookup(irc->msgs, msgname)) == NULL) { | |
443 irc_msg_default(irc, "", from, &input); | |
444 g_free(msgname); | |
445 g_free(from); | |
446 return; | |
447 } | |
448 g_free(msgname); | |
449 | |
450 args = g_new0(char *, strlen(msgent->format)); | |
451 for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) { | |
452 switch (fmt[i]) { | |
453 case 'v': | |
454 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
455 args[i] = g_strndup(cur, end - cur); | |
456 cur += end - cur; | |
457 break; | |
458 case 't': | |
459 case 'n': | |
460 case 'c': | |
461 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
462 tmp = g_strndup(cur, end - cur); | |
463 args[i] = irc_recv_convert(irc, tmp); | |
464 g_free(tmp); | |
465 cur += end - cur; | |
466 break; | |
467 case ':': | |
468 if (*cur == ':') cur++; | |
469 args[i] = irc_recv_convert(irc, cur); | |
470 cur = cur + strlen(cur); | |
471 break; | |
472 case '*': | |
473 args[i] = g_strdup(cur); | |
474 cur = cur + strlen(cur); | |
475 break; | |
476 default: | |
477 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]); | |
478 break; | |
479 } | |
480 } | |
6970 | 481 tmp = irc_recv_convert(irc, from); |
482 (msgent->cb)(irc, msgent->name, tmp, args); | |
483 g_free(tmp); | |
6333 | 484 for (i = 0; i < strlen(msgent->format); i++) { |
485 g_free(args[i]); | |
486 } | |
487 g_free(args); | |
488 g_free(from); | |
489 } | |
490 | |
491 int irc_parse_cmd(struct irc_conn *irc, const char *target, const char *cmdstr) | |
492 { | |
493 const char *cur, *end, *fmt; | |
494 char *tmp, *cmd, **args; | |
495 struct _irc_user_cmd *cmdent; | |
7631 | 496 guint i; |
497 int ret; | |
6333 | 498 |
499 cur = cmdstr; | |
500 end = strchr(cmdstr, ' '); | |
501 if (!end) | |
502 end = cur + strlen(cur); | |
503 | |
504 tmp = g_strndup(cur, end - cur); | |
505 cmd = g_utf8_strdown(tmp, -1); | |
506 g_free(tmp); | |
507 | |
508 if ((cmdent = g_hash_table_lookup(irc->cmds, cmd)) == NULL) { | |
509 ret = irc_cmd_default(irc, cmd, target, &cmdstr); | |
510 g_free(cmd); | |
511 return ret; | |
512 } | |
513 | |
514 args = g_new0(char *, strlen(cmdent->format)); | |
515 for (cur = end, fmt = cmdent->format, i = 0; fmt[i] && *cur++; i++) { | |
516 switch (fmt[i]) { | |
517 case 'v': | |
518 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
519 args[i] = g_strndup(cur, end - cur); | |
520 cur += end - cur; | |
521 break; | |
522 case 't': | |
523 case 'n': | |
524 case 'c': | |
525 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
526 args[i] = g_strndup(cur, end - cur); | |
527 cur += end - cur; | |
528 break; | |
529 case ':': | |
530 case '*': | |
531 args[i] = g_strdup(cur); | |
532 cur = cur + strlen(cur); | |
533 break; | |
534 default: | |
535 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid command format character '%c'\n", fmt[i]); | |
536 break; | |
537 } | |
538 } | |
539 ret = (cmdent->cb)(irc, cmd, target, (const char **)args); | |
540 for (i = 0; i < strlen(cmdent->format); i++) | |
541 g_free(args[i]); | |
542 g_free(args); | |
543 | |
544 g_free(cmd); | |
545 return ret; | |
546 } | |
547 | |
548 static void irc_parse_error_cb(struct irc_conn *irc, char *input) | |
549 { | |
550 gaim_debug(GAIM_DEBUG_WARNING, "irc", "Unrecognized string: %s\n", input); | |
551 } |