Mercurial > pidgin
annotate src/protocols/irc/parse.c @ 6485:70d5122bc3ff
[gaim-migrate @ 6999]
Removed the old event system and replaced it with a much better signal
system. There will most likely be some bugs in this, but it seems to be
working for now. Plugins can now generate their own signals, and other
plugins can find those plugins and connect to them. This could give
plugins a form of IPC. It's also useful for other things. It's rather
flexible, except for the damn marshalling, but there's no way around that
that I or the glib people can see.
committer: Tailor Script <tailor@pidgin.im>
| author | Christian Hammond <chipx86@chipx86.com> |
|---|---|
| date | Mon, 18 Aug 2003 01:03:43 +0000 |
| parents | e3be6b9744b7 |
| children | 0c260c4e753e |
| rev | line source |
|---|---|
| 6333 | 1 /** |
| 2 * @file parse.c | |
| 3 * | |
| 4 * gaim | |
| 5 * | |
| 6 * Copyright (C) 2003, Ethan Blanton <eblanton@cs.purdue.edu> | |
| 7 * | |
| 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 char *irc_mirc2html(const char *string); | |
| 39 | |
| 40 static void irc_parse_error_cb(struct irc_conn *irc, char *input); | |
| 41 | |
| 42 static char *irc_mirc_colors[16] = { | |
| 43 "white", "black", "blue", "dark green", "red", "brown", "purple", | |
| 44 "orange", "yellow", "green", "teal", "cyan", "light blue", | |
| 45 "pink", "grey", "light grey" }; | |
| 46 | |
| 47 /*typedef void (*IRCMsgCallback)(struct irc_conn *irc, char *from, char *name, char **args);*/ | |
| 48 static struct _irc_msg { | |
| 49 char *name; | |
| 50 char *format; | |
| 51 void (*cb)(struct irc_conn *irc, const char *name, const char *from, char **args); | |
| 52 } _irc_msgs[] = { | |
| 53 { "301", "nn:", irc_msg_away }, /* User is away */ | |
| 54 { "303", "n:", irc_msg_ison }, /* ISON reply */ | |
| 55 { "311", "nnvvv:", irc_msg_whois }, /* Whois user */ | |
| 56 { "312", "nnv:", irc_msg_whois }, /* Whois server */ | |
| 57 { "313", "nn:", irc_msg_whois }, /* Whois ircop */ | |
| 58 { "317", "nnvv", irc_msg_whois }, /* Whois idle */ | |
| 59 { "318", "nt:", irc_msg_endwhois }, /* End of WHOIS */ | |
| 60 { "319", "nn:", irc_msg_whois }, /* Whois channels */ | |
| 61 { "320", "nn:", irc_msg_whois }, /* Whois (fn ident) */ | |
| 62 { "324", "ncv:", irc_msg_chanmode }, /* Channel modes */ | |
| 63 { "331", "nc:", irc_msg_topic }, /* No channel topic */ | |
| 64 { "332", "nc:", irc_msg_topic }, /* Channel topic */ | |
| 65 { "333", "*", irc_msg_ignore }, /* Topic setter stuff */ | |
| 66 { "353", "nvc:", irc_msg_names }, /* Names list */ | |
| 67 { "366", "nc:", irc_msg_names }, /* End of names */ | |
| 68 { "372", "n:", irc_msg_motd }, /* MOTD */ | |
| 69 { "375", "n:", irc_msg_motd }, /* Start MOTD */ | |
| 70 { "376", "n:", irc_msg_endmotd }, /* End of MOTD */ | |
| 71 { "401", "nt:", irc_msg_nonick }, /* No such nick/chan */ | |
| 72 { "404", "nt:", irc_msg_nosend }, /* Cannot send to chan */ | |
| 73 { "421", "nv:", irc_msg_unknown }, /* Unknown command */ | |
| 6350 | 74 { "422", "nv:", irc_msg_endmotd }, /* No MOTD available */ |
| 6333 | 75 { "433", "vn:", irc_msg_nickused }, /* Nickname already in use */ |
| 76 { "442", "nc:", irc_msg_notinchan }, /* Not in channel */ | |
| 77 { "473", "nc:", irc_msg_inviteonly }, /* Tried to join invite-only */ | |
| 78 { "474", "nc:", irc_msg_banned }, /* Banned from channel */ | |
| 79 { "482", "nc:", irc_msg_notop }, /* Need to be op to do that */ | |
| 80 { "501", "n:", irc_msg_badmode }, /* Unknown mode flag */ | |
| 81 { "invite", "n:", irc_msg_invite }, /* Invited */ | |
| 82 { "join", ":", irc_msg_join }, /* Joined a channel */ | |
| 83 { "kick", "cn:", irc_msg_kick }, /* KICK */ | |
| 84 { "mode", "tv:", irc_msg_mode }, /* MODE for channel */ | |
| 85 { "nick", ":", irc_msg_nick }, /* Nick change */ | |
| 86 { "notice", "t:", irc_msg_notice }, /* NOTICE recv */ | |
| 87 { "part", "c:", irc_msg_part }, /* Parted a channel */ | |
| 88 { "ping", ":", irc_msg_ping }, /* Received PING from server */ | |
| 89 { "pong", "v:", irc_msg_pong }, /* Received PONG from server */ | |
| 90 { "privmsg", "t:", irc_msg_privmsg }, /* Received private message */ | |
| 91 { "topic", "c:", irc_msg_topic }, /* TOPIC command */ | |
| 92 { "quit", ":", irc_msg_quit }, /* QUIT notice */ | |
| 93 { "wallops", ":", irc_msg_wallops }, /* WALLOPS command */ | |
| 94 { NULL, NULL, NULL } | |
| 95 }; | |
| 96 | |
| 97 static struct _irc_user_cmd { | |
| 98 char *name; | |
| 99 char *format; | |
| 100 IRCCmdCallback cb; | |
| 101 } _irc_cmds[] = { | |
| 102 { "away", ":", irc_cmd_away }, | |
| 103 { "deop", ":", irc_cmd_op }, | |
| 104 { "devoice", ":", irc_cmd_op }, | |
|
6415
e3be6b9744b7
[gaim-migrate @ 6922]
Christian Hammond <chipx86@chipx86.com>
parents:
6350
diff
changeset
|
105 { "help", "v", irc_cmd_help }, |
| 6333 | 106 { "invite", ":", irc_cmd_invite }, |
| 107 { "j", "cv", irc_cmd_join }, | |
| 108 { "join", "cv", irc_cmd_join }, | |
| 109 { "kick", "n:", irc_cmd_kick }, | |
| 110 { "me", ":", irc_cmd_ctcp_action }, | |
| 111 { "mode", ":", irc_cmd_mode }, | |
| 112 { "msg", "t:", irc_cmd_privmsg }, | |
| 113 { "names", "c", irc_cmd_names }, | |
| 114 { "nick", "n", irc_cmd_nick }, | |
| 115 { "op", ":", irc_cmd_op }, | |
| 116 { "operwall", ":", irc_cmd_wallops }, | |
| 117 { "part", "c:", irc_cmd_part }, | |
| 118 { "ping", "n", irc_cmd_ping }, | |
| 119 { "query", "n:", irc_cmd_query }, | |
| 120 { "quit", ":", irc_cmd_quit }, | |
| 121 { "quote", "*", irc_cmd_quote }, | |
| 122 { "remove", "n:", irc_cmd_remove }, | |
| 123 { "topic", ":", irc_cmd_topic }, | |
| 124 { "umode", ":", irc_cmd_mode }, | |
| 125 { "voice", ":", irc_cmd_op }, | |
| 126 { "wallops", ":", irc_cmd_wallops }, | |
| 127 { "whois", "n", irc_cmd_whois }, | |
| 128 { NULL, NULL } | |
| 129 }; | |
| 130 | |
| 131 static char *irc_send_convert(struct irc_conn *irc, const char *string) | |
| 132 { | |
| 133 char *utf8; | |
| 134 GError *err = NULL; | |
| 135 | |
| 136 utf8 = g_convert(string, strlen(string), | |
| 137 gaim_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET), | |
| 138 "UTF-8", NULL, NULL, &err); | |
| 139 if (err) { | |
| 140 gaim_debug(GAIM_DEBUG_ERROR, "irc", "send conversion error: %s\n", err->message); | |
| 141 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Sending raw, which probably isn't right\n"); | |
| 142 utf8 = g_strdup(string); | |
| 143 } | |
| 144 | |
| 145 return utf8; | |
| 146 } | |
| 147 | |
| 148 static char *irc_recv_convert(struct irc_conn *irc, const char *string) | |
| 149 { | |
| 150 char *utf8; | |
| 151 GError *err = NULL; | |
| 152 | |
| 153 utf8 = g_convert(string, strlen(string), "UTF-8", | |
| 154 gaim_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET), | |
| 155 NULL, NULL, &err); | |
| 156 if (err) { | |
| 157 gaim_debug(GAIM_DEBUG_ERROR, "irc", "recv conversion error: %s\n", err->message); | |
| 158 utf8 = g_strdup(_("(There was an error converting this message. Check the 'Encoding' option in the Account Editor)")); | |
| 159 } | |
| 160 | |
| 161 return utf8; | |
| 162 } | |
| 163 | |
| 164 /* XXX tag closings are not necessarily correctly nested here! If we | |
| 165 * get a ^O or reach the end of the string and there are open | |
| 166 * tags, they are closed in a fixed order ... this means, for | |
| 167 * example, you might see <FONT COLOR="blue">some text <B>with | |
| 168 * various attributes</FONT></B> (notice that B and FONT overlap | |
| 169 * and are not cleanly nested). This is imminently fixable but | |
| 170 * I am not fixing it right now. | |
| 171 */ | |
| 172 char *irc_mirc2html(const char *string) | |
| 173 { | |
| 174 const char *cur, *end; | |
| 175 char fg[3] = "\0\0", bg[3] = "\0\0"; | |
| 176 int fgnum, bgnum; | |
| 177 int font = 0, bold = 0; | |
| 178 GString *decoded = g_string_sized_new(strlen(string)); | |
| 179 | |
| 180 cur = string; | |
| 181 do { | |
| 182 end = strpbrk(cur, "\002\003\007\017\026"); | |
| 183 | |
| 184 decoded = g_string_append_len(decoded, cur, end ? end - cur : strlen(cur)); | |
| 185 cur = end ? end : cur + strlen(cur); | |
| 186 | |
| 187 switch (*cur) { | |
| 188 case '\002': | |
| 189 cur++; | |
| 190 if (!bold) { | |
| 191 decoded = g_string_append(decoded, "<B>"); | |
| 192 bold = TRUE; | |
| 193 } else { | |
| 194 decoded = g_string_append(decoded, "</B>"); | |
| 195 bold = FALSE; | |
| 196 } | |
| 197 break; | |
| 198 case '\003': | |
| 199 cur++; | |
| 200 fg[0] = fg[1] = bg[0] = bg[1] = '\0'; | |
| 201 if (isdigit(*cur)) | |
| 202 fg[0] = *cur++; | |
| 203 if (isdigit(*cur)) | |
| 204 fg[1] = *cur++; | |
| 205 if (*cur == ',') { | |
| 206 cur++; | |
| 207 if (isdigit(*cur)) | |
| 208 bg[0] = *cur++; | |
| 209 if (isdigit(*cur)) | |
| 210 bg[1] = *cur++; | |
| 211 } | |
| 212 if (font) { | |
| 213 decoded = g_string_append(decoded, "</FONT>"); | |
| 214 font = FALSE; | |
| 215 } | |
| 216 | |
| 217 if (fg[0]) { | |
| 218 fgnum = atoi(fg); | |
| 219 if (fgnum < 0 || fgnum > 15) | |
| 220 continue; | |
| 221 font = TRUE; | |
| 222 g_string_append_printf(decoded, "<FONT COLOR=\"%s\"", irc_mirc_colors[fgnum]); | |
| 223 if (bg[0]) { | |
| 224 bgnum = atoi(bg); | |
| 225 if (bgnum >= 0 && bgnum < 16) | |
| 226 g_string_append_printf(decoded, " BACK=\"%s\"", irc_mirc_colors[bgnum]); | |
| 227 } | |
| 228 decoded = g_string_append_c(decoded, '>'); | |
| 229 } | |
| 230 break; | |
| 231 case '\007': | |
| 232 case '\026': | |
| 233 cur++; | |
| 234 break; | |
| 235 case '\017': | |
| 236 cur++; | |
| 237 /* fallthrough */ | |
| 238 case '\000': | |
| 239 if (bold) | |
| 240 decoded = g_string_append(decoded, "</BOLD>"); | |
| 241 if (font) | |
| 242 decoded = g_string_append(decoded, "</FONT>"); | |
| 243 break; | |
| 244 default: | |
| 245 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Unexpected mIRC formatting character %d\n", *cur); | |
| 246 } | |
| 247 } while (*cur); | |
| 248 | |
| 249 return g_string_free(decoded, FALSE); | |
| 250 } | |
| 251 | |
| 252 char *irc_parse_ctcp(struct irc_conn *irc, const char *from, const char *to, const char *msg, int notice) | |
| 253 { | |
| 254 GaimConnection *gc; | |
| 255 const char *cur = msg + 1; | |
| 256 char *buf, *ctcp; | |
| 257 time_t timestamp; | |
| 258 | |
| 259 if (msg[0] != '\001' || msg[strlen(msg) - 1] != '\001') | |
| 260 return g_strdup(msg); | |
| 261 | |
| 262 if (!strncmp(cur, "ACTION ", 7)) { | |
| 263 cur += 7; | |
| 264 buf = g_strdup_printf("/me %s", cur); | |
| 265 buf[strlen(buf) - 1] = '\0'; | |
| 266 return buf; | |
| 267 } else if (!strncmp(cur, "PING ", 5)) { | |
| 268 if (notice) { /* reply */ | |
| 269 sscanf(cur, "PING %lu", ×tamp); | |
| 270 gc = gaim_account_get_connection(irc->account); | |
| 271 if (!gc) | |
| 272 return NULL; | |
| 6350 | 273 buf = g_strdup_printf(_("Reply time from %s: %lu seconds"), from, time(NULL) - timestamp); |
| 6333 | 274 gaim_notify_info(gc, _("PONG"), _("CTCP PING reply"), buf); |
| 275 g_free(buf); | |
| 276 return NULL; | |
| 277 } else { | |
| 278 buf = irc_format(irc, "vt:", "NOTICE", from, msg); | |
| 279 irc_send(irc, buf); | |
| 280 g_free(buf); | |
| 281 gc = gaim_account_get_connection(irc->account); | |
| 282 } | |
| 283 } else if (!strncmp(cur, "VERSION", 7) && !notice) { | |
| 284 buf = irc_format(irc, "vt:", "NOTICE", from, "\001VERSION Gaim IRC\001"); | |
| 285 irc_send(irc, buf); | |
| 286 g_free(buf); | |
| 287 } | |
| 288 | |
| 289 ctcp = g_strdup(msg + 1); | |
| 290 ctcp[strlen(ctcp) - 1] = '\0'; | |
| 291 buf = g_strdup_printf("Received CTCP '%s' (to %s) from %s", ctcp, to, from); | |
| 292 g_free(ctcp); | |
| 293 return buf; | |
| 294 } | |
| 295 | |
| 296 void irc_msg_table_build(struct irc_conn *irc) | |
| 297 { | |
| 298 int i; | |
| 299 | |
| 300 if (!irc || !irc->msgs) { | |
| 301 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a message table on a bogus structure\n"); | |
| 302 return; | |
| 303 } | |
| 304 | |
| 305 for (i = 0; _irc_msgs[i].name; i++) { | |
| 306 g_hash_table_insert(irc->msgs, (gpointer)_irc_msgs[i].name, (gpointer)&_irc_msgs[i]); | |
| 307 } | |
| 308 } | |
| 309 | |
| 310 void irc_cmd_table_build(struct irc_conn *irc) | |
| 311 { | |
| 312 int i; | |
| 313 | |
| 314 if (!irc || !irc->cmds) { | |
| 315 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a command table on a bogus structure\n"); | |
| 316 return; | |
| 317 } | |
| 318 | |
| 319 for (i = 0; _irc_cmds[i].name ; i++) { | |
| 320 g_hash_table_insert(irc->cmds, (gpointer)_irc_cmds[i].name, (gpointer)&_irc_cmds[i]); | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 char *irc_format(struct irc_conn *irc, const char *format, ...) | |
| 325 { | |
| 326 GString *string = g_string_new(""); | |
| 327 char *tok, *tmp; | |
| 328 const char *cur; | |
| 329 va_list ap; | |
| 330 | |
| 331 va_start(ap, format); | |
| 332 for (cur = format; *cur; cur++) { | |
| 333 if (cur != format) | |
| 334 g_string_append_c(string, ' '); | |
| 335 | |
| 336 tok = va_arg(ap, char *); | |
| 337 switch (*cur) { | |
| 338 case 'v': | |
| 339 g_string_append(string, tok); | |
| 340 break; | |
| 341 case ':': | |
| 342 g_string_append_c(string, ':'); | |
| 343 /* no break! */ | |
| 344 case 't': | |
| 345 case 'n': | |
| 346 case 'c': | |
| 347 tmp = irc_send_convert(irc, tok); | |
| 348 g_string_append(string, tmp); | |
| 349 g_free(tmp); | |
| 350 break; | |
| 351 default: | |
| 352 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Invalid format character '%c'\n", *cur); | |
| 353 break; | |
| 354 } | |
| 355 } | |
| 356 va_end(ap); | |
| 357 g_string_append(string, "\r\n"); | |
| 358 return (g_string_free(string, FALSE)); | |
| 359 } | |
| 360 | |
| 361 void irc_parse_msg(struct irc_conn *irc, char *input) | |
| 362 { | |
| 363 struct _irc_msg *msgent; | |
| 364 char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg; | |
| 365 int i; | |
| 366 | |
| 367 if (!strncmp(input, "PING ", 5)) { | |
| 368 msg = irc_format(irc, "vv", "PONG", input + 5); | |
| 369 irc_send(irc, msg); | |
| 370 g_free(msg); | |
| 371 return; | |
| 372 } else if (!strncmp(input, "ERROR ", 6)) { | |
| 373 gaim_connection_error(gaim_account_get_connection(irc->account), _("Disconnected")); | |
| 374 return; | |
| 375 } | |
| 376 | |
| 377 if (input[0] != ':' || (cur = strchr(input, ' ')) == NULL) { | |
| 378 irc_parse_error_cb(irc, input); | |
| 379 return; | |
| 380 } | |
| 381 | |
| 382 from = g_strndup(&input[1], cur - &input[1]); | |
| 383 cur++; | |
| 384 end = strchr(cur, ' '); | |
| 385 if (!end) | |
| 386 end = cur + strlen(cur); | |
| 387 | |
| 388 tmp = g_strndup(cur, end - cur); | |
| 389 msgname = g_ascii_strdown(tmp, -1); | |
| 390 g_free(tmp); | |
| 391 | |
| 392 if ((msgent = g_hash_table_lookup(irc->msgs, msgname)) == NULL) { | |
| 393 irc_msg_default(irc, "", from, &input); | |
| 394 g_free(msgname); | |
| 395 g_free(from); | |
| 396 return; | |
| 397 } | |
| 398 g_free(msgname); | |
| 399 | |
| 400 args = g_new0(char *, strlen(msgent->format)); | |
| 401 for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) { | |
| 402 switch (fmt[i]) { | |
| 403 case 'v': | |
| 404 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 405 args[i] = g_strndup(cur, end - cur); | |
| 406 cur += end - cur; | |
| 407 break; | |
| 408 case 't': | |
| 409 case 'n': | |
| 410 case 'c': | |
| 411 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 412 tmp = g_strndup(cur, end - cur); | |
| 413 args[i] = irc_recv_convert(irc, tmp); | |
| 414 g_free(tmp); | |
| 415 cur += end - cur; | |
| 416 break; | |
| 417 case ':': | |
| 418 if (*cur == ':') cur++; | |
| 419 args[i] = irc_recv_convert(irc, cur); | |
| 420 cur = cur + strlen(cur); | |
| 421 break; | |
| 422 case '*': | |
| 423 args[i] = g_strdup(cur); | |
| 424 cur = cur + strlen(cur); | |
| 425 break; | |
| 426 default: | |
| 427 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]); | |
| 428 break; | |
| 429 } | |
| 430 } | |
| 431 (msgent->cb)(irc, msgent->name, from, args); | |
| 432 for (i = 0; i < strlen(msgent->format); i++) { | |
| 433 g_free(args[i]); | |
| 434 } | |
| 435 g_free(args); | |
| 436 g_free(from); | |
| 437 } | |
| 438 | |
| 439 int irc_parse_cmd(struct irc_conn *irc, const char *target, const char *cmdstr) | |
| 440 { | |
| 441 const char *cur, *end, *fmt; | |
| 442 char *tmp, *cmd, **args; | |
| 443 struct _irc_user_cmd *cmdent; | |
| 444 int i, ret; | |
| 445 | |
| 446 cur = cmdstr; | |
| 447 end = strchr(cmdstr, ' '); | |
| 448 if (!end) | |
| 449 end = cur + strlen(cur); | |
| 450 | |
| 451 tmp = g_strndup(cur, end - cur); | |
| 452 cmd = g_utf8_strdown(tmp, -1); | |
| 453 g_free(tmp); | |
| 454 | |
| 455 if ((cmdent = g_hash_table_lookup(irc->cmds, cmd)) == NULL) { | |
| 456 ret = irc_cmd_default(irc, cmd, target, &cmdstr); | |
| 457 g_free(cmd); | |
| 458 return ret; | |
| 459 } | |
| 460 | |
| 461 args = g_new0(char *, strlen(cmdent->format)); | |
| 462 for (cur = end, fmt = cmdent->format, i = 0; fmt[i] && *cur++; i++) { | |
| 463 switch (fmt[i]) { | |
| 464 case 'v': | |
| 465 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 466 args[i] = g_strndup(cur, end - cur); | |
| 467 cur += end - cur; | |
| 468 break; | |
| 469 case 't': | |
| 470 case 'n': | |
| 471 case 'c': | |
| 472 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 473 args[i] = g_strndup(cur, end - cur); | |
| 474 cur += end - cur; | |
| 475 break; | |
| 476 case ':': | |
| 477 case '*': | |
| 478 args[i] = g_strdup(cur); | |
| 479 cur = cur + strlen(cur); | |
| 480 break; | |
| 481 default: | |
| 482 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid command format character '%c'\n", fmt[i]); | |
| 483 break; | |
| 484 } | |
| 485 } | |
| 486 ret = (cmdent->cb)(irc, cmd, target, (const char **)args); | |
| 487 for (i = 0; i < strlen(cmdent->format); i++) | |
| 488 g_free(args[i]); | |
| 489 g_free(args); | |
| 490 | |
| 491 g_free(cmd); | |
| 492 return ret; | |
| 493 } | |
| 494 | |
| 495 static void irc_parse_error_cb(struct irc_conn *irc, char *input) | |
| 496 { | |
| 497 gaim_debug(GAIM_DEBUG_WARNING, "irc", "Unrecognized string: %s\n", input); | |
| 498 } |
