Mercurial > pidgin
annotate src/protocols/irc/parse.c @ 7834:99ffabc6ce73
[gaim-migrate @ 8487]
This patch from Mike Hearn should fix HTTP proxy support for MSN, and
provides another step toward the MSN HTTP access method working. The HTTP
proxy may need testing from other people, but looks like it shouldn't give
any problems.
committer: Tailor Script <tailor@pidgin.im>
| author | Christian Hammond <chipx86@chipx86.com> |
|---|---|
| date | Fri, 12 Dec 2003 00:14:40 +0000 |
| parents | ea2d07ad05a9 |
| children | 828856b7fe30 |
| 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 */ |
| 6718 | 76 { "438", "nn:", irc_msg_nochangenick }, /* Nick may not change */ |
| 6333 | 77 { "442", "nc:", irc_msg_notinchan }, /* Not in channel */ |
| 78 { "473", "nc:", irc_msg_inviteonly }, /* Tried to join invite-only */ | |
| 79 { "474", "nc:", irc_msg_banned }, /* Banned from channel */ | |
| 80 { "482", "nc:", irc_msg_notop }, /* Need to be op to do that */ | |
| 81 { "501", "n:", irc_msg_badmode }, /* Unknown mode flag */ | |
| 6714 | 82 { "515", "nc:", irc_msg_regonly }, /* Registration required */ |
| 6333 | 83 { "invite", "n:", irc_msg_invite }, /* Invited */ |
| 84 { "join", ":", irc_msg_join }, /* Joined a channel */ | |
| 85 { "kick", "cn:", irc_msg_kick }, /* KICK */ | |
| 86 { "mode", "tv:", irc_msg_mode }, /* MODE for channel */ | |
| 87 { "nick", ":", irc_msg_nick }, /* Nick change */ | |
| 88 { "notice", "t:", irc_msg_notice }, /* NOTICE recv */ | |
| 89 { "part", "c:", irc_msg_part }, /* Parted a channel */ | |
| 90 { "ping", ":", irc_msg_ping }, /* Received PING from server */ | |
| 91 { "pong", "v:", irc_msg_pong }, /* Received PONG from server */ | |
| 92 { "privmsg", "t:", irc_msg_privmsg }, /* Received private message */ | |
| 93 { "topic", "c:", irc_msg_topic }, /* TOPIC command */ | |
| 94 { "quit", ":", irc_msg_quit }, /* QUIT notice */ | |
| 95 { "wallops", ":", irc_msg_wallops }, /* WALLOPS command */ | |
| 96 { NULL, NULL, NULL } | |
| 97 }; | |
| 98 | |
| 99 static struct _irc_user_cmd { | |
| 100 char *name; | |
| 101 char *format; | |
| 102 IRCCmdCallback cb; | |
| 103 } _irc_cmds[] = { | |
| 104 { "away", ":", irc_cmd_away }, | |
| 105 { "deop", ":", irc_cmd_op }, | |
| 106 { "devoice", ":", irc_cmd_op }, | |
|
6415
e3be6b9744b7
[gaim-migrate @ 6922]
Christian Hammond <chipx86@chipx86.com>
parents:
6350
diff
changeset
|
107 { "help", "v", irc_cmd_help }, |
| 6333 | 108 { "invite", ":", irc_cmd_invite }, |
| 109 { "j", "cv", irc_cmd_join }, | |
| 110 { "join", "cv", irc_cmd_join }, | |
| 111 { "kick", "n:", irc_cmd_kick }, | |
| 112 { "me", ":", irc_cmd_ctcp_action }, | |
| 113 { "mode", ":", irc_cmd_mode }, | |
| 114 { "msg", "t:", irc_cmd_privmsg }, | |
| 115 { "names", "c", irc_cmd_names }, | |
| 116 { "nick", "n", irc_cmd_nick }, | |
| 117 { "op", ":", irc_cmd_op }, | |
| 118 { "operwall", ":", irc_cmd_wallops }, | |
| 119 { "part", "c:", irc_cmd_part }, | |
| 120 { "ping", "n", irc_cmd_ping }, | |
| 121 { "query", "n:", irc_cmd_query }, | |
| 122 { "quit", ":", irc_cmd_quit }, | |
| 123 { "quote", "*", irc_cmd_quote }, | |
| 124 { "remove", "n:", irc_cmd_remove }, | |
| 125 { "topic", ":", irc_cmd_topic }, | |
| 126 { "umode", ":", irc_cmd_mode }, | |
| 127 { "voice", ":", irc_cmd_op }, | |
| 128 { "wallops", ":", irc_cmd_wallops }, | |
| 129 { "whois", "n", irc_cmd_whois }, | |
| 7631 | 130 { NULL, NULL, NULL } |
| 6333 | 131 }; |
| 132 | |
| 133 static char *irc_send_convert(struct irc_conn *irc, const char *string) | |
| 134 { | |
| 135 char *utf8; | |
| 136 GError *err = NULL; | |
| 137 | |
| 138 utf8 = g_convert(string, strlen(string), | |
| 139 gaim_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET), | |
| 140 "UTF-8", NULL, NULL, &err); | |
| 141 if (err) { | |
| 142 gaim_debug(GAIM_DEBUG_ERROR, "irc", "send conversion error: %s\n", err->message); | |
| 143 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Sending raw, which probably isn't right\n"); | |
| 144 utf8 = g_strdup(string); | |
| 145 } | |
| 146 | |
| 147 return utf8; | |
| 148 } | |
| 149 | |
| 150 static char *irc_recv_convert(struct irc_conn *irc, const char *string) | |
| 151 { | |
| 152 char *utf8; | |
| 153 GError *err = NULL; | |
| 154 | |
| 155 utf8 = g_convert(string, strlen(string), "UTF-8", | |
| 156 gaim_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET), | |
| 157 NULL, NULL, &err); | |
| 158 if (err) { | |
| 159 gaim_debug(GAIM_DEBUG_ERROR, "irc", "recv conversion error: %s\n", err->message); | |
| 160 utf8 = g_strdup(_("(There was an error converting this message. Check the 'Encoding' option in the Account Editor)")); | |
| 161 } | |
| 162 | |
| 163 return utf8; | |
| 164 } | |
| 165 | |
| 166 /* XXX tag closings are not necessarily correctly nested here! If we | |
| 167 * get a ^O or reach the end of the string and there are open | |
| 168 * tags, they are closed in a fixed order ... this means, for | |
| 169 * example, you might see <FONT COLOR="blue">some text <B>with | |
| 170 * various attributes</FONT></B> (notice that B and FONT overlap | |
| 171 * and are not cleanly nested). This is imminently fixable but | |
| 172 * I am not fixing it right now. | |
| 173 */ | |
| 174 char *irc_mirc2html(const char *string) | |
| 175 { | |
| 176 const char *cur, *end; | |
| 177 char fg[3] = "\0\0", bg[3] = "\0\0"; | |
| 178 int fgnum, bgnum; | |
| 6754 | 179 int font = 0, bold = 0, underline = 0; |
| 6333 | 180 GString *decoded = g_string_sized_new(strlen(string)); |
| 181 | |
| 182 cur = string; | |
| 183 do { | |
| 6754 | 184 end = strpbrk(cur, "\002\003\007\017\026\037"); |
| 6333 | 185 |
| 186 decoded = g_string_append_len(decoded, cur, end ? end - cur : strlen(cur)); | |
| 187 cur = end ? end : cur + strlen(cur); | |
| 188 | |
| 189 switch (*cur) { | |
| 190 case '\002': | |
| 191 cur++; | |
| 192 if (!bold) { | |
| 193 decoded = g_string_append(decoded, "<B>"); | |
| 194 bold = TRUE; | |
| 195 } else { | |
| 196 decoded = g_string_append(decoded, "</B>"); | |
| 197 bold = FALSE; | |
| 198 } | |
| 199 break; | |
| 200 case '\003': | |
| 201 cur++; | |
| 202 fg[0] = fg[1] = bg[0] = bg[1] = '\0'; | |
| 203 if (isdigit(*cur)) | |
| 204 fg[0] = *cur++; | |
| 205 if (isdigit(*cur)) | |
| 206 fg[1] = *cur++; | |
| 207 if (*cur == ',') { | |
| 208 cur++; | |
| 209 if (isdigit(*cur)) | |
| 210 bg[0] = *cur++; | |
| 211 if (isdigit(*cur)) | |
| 212 bg[1] = *cur++; | |
| 213 } | |
| 214 if (font) { | |
| 215 decoded = g_string_append(decoded, "</FONT>"); | |
| 216 font = FALSE; | |
| 217 } | |
| 218 | |
| 219 if (fg[0]) { | |
| 220 fgnum = atoi(fg); | |
| 221 if (fgnum < 0 || fgnum > 15) | |
| 222 continue; | |
| 223 font = TRUE; | |
| 224 g_string_append_printf(decoded, "<FONT COLOR=\"%s\"", irc_mirc_colors[fgnum]); | |
| 225 if (bg[0]) { | |
| 226 bgnum = atoi(bg); | |
| 227 if (bgnum >= 0 && bgnum < 16) | |
| 228 g_string_append_printf(decoded, " BACK=\"%s\"", irc_mirc_colors[bgnum]); | |
| 229 } | |
| 230 decoded = g_string_append_c(decoded, '>'); | |
| 231 } | |
| 232 break; | |
| 6754 | 233 case '\037': |
| 234 cur++; | |
| 235 if (!underline) { | |
| 236 decoded = g_string_append(decoded, "<U>"); | |
| 237 underline = TRUE; | |
| 238 } else { | |
| 239 decoded = g_string_append(decoded, "</U>"); | |
| 240 underline = TRUE; | |
| 241 } | |
| 242 break; | |
| 6333 | 243 case '\007': |
| 244 case '\026': | |
| 245 cur++; | |
| 246 break; | |
| 247 case '\017': | |
| 248 cur++; | |
| 249 /* fallthrough */ | |
| 250 case '\000': | |
| 251 if (bold) | |
| 6754 | 252 decoded = g_string_append(decoded, "</B>"); |
| 253 if (underline) | |
| 254 decoded = g_string_append(decoded, "</U>"); | |
| 6333 | 255 if (font) |
| 256 decoded = g_string_append(decoded, "</FONT>"); | |
| 257 break; | |
| 258 default: | |
| 259 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Unexpected mIRC formatting character %d\n", *cur); | |
| 260 } | |
| 261 } while (*cur); | |
| 262 | |
| 263 return g_string_free(decoded, FALSE); | |
| 264 } | |
| 265 | |
| 266 char *irc_parse_ctcp(struct irc_conn *irc, const char *from, const char *to, const char *msg, int notice) | |
| 267 { | |
| 268 GaimConnection *gc; | |
| 269 const char *cur = msg + 1; | |
| 270 char *buf, *ctcp; | |
| 271 time_t timestamp; | |
| 272 | |
| 6754 | 273 /* Note that this is NOT correct w.r.t. multiple CTCPs in one |
| 274 * message and low-level quoting ... but if you want that crap, | |
| 275 * use a real IRC client. */ | |
| 276 | |
| 6333 | 277 if (msg[0] != '\001' || msg[strlen(msg) - 1] != '\001') |
| 278 return g_strdup(msg); | |
| 279 | |
| 280 if (!strncmp(cur, "ACTION ", 7)) { | |
| 281 cur += 7; | |
| 282 buf = g_strdup_printf("/me %s", cur); | |
| 283 buf[strlen(buf) - 1] = '\0'; | |
| 284 return buf; | |
| 285 } else if (!strncmp(cur, "PING ", 5)) { | |
| 286 if (notice) { /* reply */ | |
| 287 sscanf(cur, "PING %lu", ×tamp); | |
| 288 gc = gaim_account_get_connection(irc->account); | |
| 289 if (!gc) | |
| 290 return NULL; | |
| 6350 | 291 buf = g_strdup_printf(_("Reply time from %s: %lu seconds"), from, time(NULL) - timestamp); |
| 6333 | 292 gaim_notify_info(gc, _("PONG"), _("CTCP PING reply"), buf); |
| 293 g_free(buf); | |
| 294 return NULL; | |
| 295 } else { | |
| 296 buf = irc_format(irc, "vt:", "NOTICE", from, msg); | |
| 297 irc_send(irc, buf); | |
| 298 g_free(buf); | |
| 299 gc = gaim_account_get_connection(irc->account); | |
| 300 } | |
| 301 } else if (!strncmp(cur, "VERSION", 7) && !notice) { | |
| 302 buf = irc_format(irc, "vt:", "NOTICE", from, "\001VERSION Gaim IRC\001"); | |
| 303 irc_send(irc, buf); | |
| 304 g_free(buf); | |
| 305 } | |
| 306 | |
| 307 ctcp = g_strdup(msg + 1); | |
| 308 ctcp[strlen(ctcp) - 1] = '\0'; | |
| 309 buf = g_strdup_printf("Received CTCP '%s' (to %s) from %s", ctcp, to, from); | |
| 310 g_free(ctcp); | |
| 311 return buf; | |
| 312 } | |
| 313 | |
| 314 void irc_msg_table_build(struct irc_conn *irc) | |
| 315 { | |
| 316 int i; | |
| 317 | |
| 318 if (!irc || !irc->msgs) { | |
| 319 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a message table on a bogus structure\n"); | |
| 320 return; | |
| 321 } | |
| 322 | |
| 323 for (i = 0; _irc_msgs[i].name; i++) { | |
| 324 g_hash_table_insert(irc->msgs, (gpointer)_irc_msgs[i].name, (gpointer)&_irc_msgs[i]); | |
| 325 } | |
| 326 } | |
| 327 | |
| 328 void irc_cmd_table_build(struct irc_conn *irc) | |
| 329 { | |
| 330 int i; | |
| 331 | |
| 332 if (!irc || !irc->cmds) { | |
| 333 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a command table on a bogus structure\n"); | |
| 334 return; | |
| 335 } | |
| 336 | |
| 337 for (i = 0; _irc_cmds[i].name ; i++) { | |
| 338 g_hash_table_insert(irc->cmds, (gpointer)_irc_cmds[i].name, (gpointer)&_irc_cmds[i]); | |
| 339 } | |
| 340 } | |
| 341 | |
| 342 char *irc_format(struct irc_conn *irc, const char *format, ...) | |
| 343 { | |
| 344 GString *string = g_string_new(""); | |
| 345 char *tok, *tmp; | |
| 346 const char *cur; | |
| 347 va_list ap; | |
| 348 | |
| 349 va_start(ap, format); | |
| 350 for (cur = format; *cur; cur++) { | |
| 351 if (cur != format) | |
| 352 g_string_append_c(string, ' '); | |
| 353 | |
| 354 tok = va_arg(ap, char *); | |
| 355 switch (*cur) { | |
| 356 case 'v': | |
| 357 g_string_append(string, tok); | |
| 358 break; | |
| 359 case ':': | |
| 360 g_string_append_c(string, ':'); | |
| 361 /* no break! */ | |
| 362 case 't': | |
| 363 case 'n': | |
| 364 case 'c': | |
| 365 tmp = irc_send_convert(irc, tok); | |
| 366 g_string_append(string, tmp); | |
| 367 g_free(tmp); | |
| 368 break; | |
| 369 default: | |
| 370 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Invalid format character '%c'\n", *cur); | |
| 371 break; | |
| 372 } | |
| 373 } | |
| 374 va_end(ap); | |
| 375 g_string_append(string, "\r\n"); | |
| 376 return (g_string_free(string, FALSE)); | |
| 377 } | |
| 378 | |
| 379 void irc_parse_msg(struct irc_conn *irc, char *input) | |
| 380 { | |
| 381 struct _irc_msg *msgent; | |
| 382 char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg; | |
| 7631 | 383 guint i; |
| 6333 | 384 |
| 385 if (!strncmp(input, "PING ", 5)) { | |
| 386 msg = irc_format(irc, "vv", "PONG", input + 5); | |
| 387 irc_send(irc, msg); | |
| 388 g_free(msg); | |
| 389 return; | |
| 390 } else if (!strncmp(input, "ERROR ", 6)) { | |
| 391 gaim_connection_error(gaim_account_get_connection(irc->account), _("Disconnected")); | |
| 392 return; | |
| 393 } | |
| 394 | |
| 395 if (input[0] != ':' || (cur = strchr(input, ' ')) == NULL) { | |
| 396 irc_parse_error_cb(irc, input); | |
| 397 return; | |
| 398 } | |
| 399 | |
| 400 from = g_strndup(&input[1], cur - &input[1]); | |
| 401 cur++; | |
| 402 end = strchr(cur, ' '); | |
| 403 if (!end) | |
| 404 end = cur + strlen(cur); | |
| 405 | |
| 406 tmp = g_strndup(cur, end - cur); | |
| 407 msgname = g_ascii_strdown(tmp, -1); | |
| 408 g_free(tmp); | |
| 409 | |
| 410 if ((msgent = g_hash_table_lookup(irc->msgs, msgname)) == NULL) { | |
| 411 irc_msg_default(irc, "", from, &input); | |
| 412 g_free(msgname); | |
| 413 g_free(from); | |
| 414 return; | |
| 415 } | |
| 416 g_free(msgname); | |
| 417 | |
| 418 args = g_new0(char *, strlen(msgent->format)); | |
| 419 for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) { | |
| 420 switch (fmt[i]) { | |
| 421 case 'v': | |
| 422 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 423 args[i] = g_strndup(cur, end - cur); | |
| 424 cur += end - cur; | |
| 425 break; | |
| 426 case 't': | |
| 427 case 'n': | |
| 428 case 'c': | |
| 429 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 430 tmp = g_strndup(cur, end - cur); | |
| 431 args[i] = irc_recv_convert(irc, tmp); | |
| 432 g_free(tmp); | |
| 433 cur += end - cur; | |
| 434 break; | |
| 435 case ':': | |
| 436 if (*cur == ':') cur++; | |
| 437 args[i] = irc_recv_convert(irc, cur); | |
| 438 cur = cur + strlen(cur); | |
| 439 break; | |
| 440 case '*': | |
| 441 args[i] = g_strdup(cur); | |
| 442 cur = cur + strlen(cur); | |
| 443 break; | |
| 444 default: | |
| 445 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]); | |
| 446 break; | |
| 447 } | |
| 448 } | |
| 6970 | 449 tmp = irc_recv_convert(irc, from); |
| 450 (msgent->cb)(irc, msgent->name, tmp, args); | |
| 451 g_free(tmp); | |
| 6333 | 452 for (i = 0; i < strlen(msgent->format); i++) { |
| 453 g_free(args[i]); | |
| 454 } | |
| 455 g_free(args); | |
| 456 g_free(from); | |
| 457 } | |
| 458 | |
| 459 int irc_parse_cmd(struct irc_conn *irc, const char *target, const char *cmdstr) | |
| 460 { | |
| 461 const char *cur, *end, *fmt; | |
| 462 char *tmp, *cmd, **args; | |
| 463 struct _irc_user_cmd *cmdent; | |
| 7631 | 464 guint i; |
| 465 int ret; | |
| 6333 | 466 |
| 467 cur = cmdstr; | |
| 468 end = strchr(cmdstr, ' '); | |
| 469 if (!end) | |
| 470 end = cur + strlen(cur); | |
| 471 | |
| 472 tmp = g_strndup(cur, end - cur); | |
| 473 cmd = g_utf8_strdown(tmp, -1); | |
| 474 g_free(tmp); | |
| 475 | |
| 476 if ((cmdent = g_hash_table_lookup(irc->cmds, cmd)) == NULL) { | |
| 477 ret = irc_cmd_default(irc, cmd, target, &cmdstr); | |
| 478 g_free(cmd); | |
| 479 return ret; | |
| 480 } | |
| 481 | |
| 482 args = g_new0(char *, strlen(cmdent->format)); | |
| 483 for (cur = end, fmt = cmdent->format, i = 0; fmt[i] && *cur++; i++) { | |
| 484 switch (fmt[i]) { | |
| 485 case 'v': | |
| 486 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 487 args[i] = g_strndup(cur, end - cur); | |
| 488 cur += end - cur; | |
| 489 break; | |
| 490 case 't': | |
| 491 case 'n': | |
| 492 case 'c': | |
| 493 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 494 args[i] = g_strndup(cur, end - cur); | |
| 495 cur += end - cur; | |
| 496 break; | |
| 497 case ':': | |
| 498 case '*': | |
| 499 args[i] = g_strdup(cur); | |
| 500 cur = cur + strlen(cur); | |
| 501 break; | |
| 502 default: | |
| 503 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid command format character '%c'\n", fmt[i]); | |
| 504 break; | |
| 505 } | |
| 506 } | |
| 507 ret = (cmdent->cb)(irc, cmd, target, (const char **)args); | |
| 508 for (i = 0; i < strlen(cmdent->format); i++) | |
| 509 g_free(args[i]); | |
| 510 g_free(args); | |
| 511 | |
| 512 g_free(cmd); | |
| 513 return ret; | |
| 514 } | |
| 515 | |
| 516 static void irc_parse_error_cb(struct irc_conn *irc, char *input) | |
| 517 { | |
| 518 gaim_debug(GAIM_DEBUG_WARNING, "irc", "Unrecognized string: %s\n", input); | |
| 519 } |
