Mercurial > pidgin
annotate src/protocols/irc/parse.c @ 8303:4eb4b2a6c604
[gaim-migrate @ 9027]
buddy_chat.c was nothing more than the Join Chat dialog now, and has been
since everything else was moved to gtkconv.c. So, move it to the only file
calling the functions and delete the file.
committer: Tailor Script <tailor@pidgin.im>
| author | Christian Hammond <chipx86@chipx86.com> |
|---|---|
| date | Fri, 20 Feb 2004 23:29:04 +0000 |
| parents | 7a6e30eb7aad |
| children | ffa642240fc1 |
| 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) */ | |
| 8114 | 62 { "321", "*", irc_msg_list }, /* Start of list */ |
| 63 { "322", "ncv:", irc_msg_list }, /* List. */ | |
| 64 { "323", ":", irc_msg_list }, /* End of list. */ | |
| 6333 | 65 { "324", "ncv:", irc_msg_chanmode }, /* Channel modes */ |
| 66 { "331", "nc:", irc_msg_topic }, /* No channel topic */ | |
| 67 { "332", "nc:", irc_msg_topic }, /* Channel topic */ | |
| 68 { "333", "*", irc_msg_ignore }, /* Topic setter stuff */ | |
| 69 { "353", "nvc:", irc_msg_names }, /* Names list */ | |
| 70 { "366", "nc:", irc_msg_names }, /* End of names */ | |
| 71 { "372", "n:", irc_msg_motd }, /* MOTD */ | |
| 72 { "375", "n:", irc_msg_motd }, /* Start MOTD */ | |
| 73 { "376", "n:", irc_msg_endmotd }, /* End of MOTD */ | |
| 74 { "401", "nt:", irc_msg_nonick }, /* No such nick/chan */ | |
| 7877 | 75 { "403", "nc:", irc_msg_nochan }, /* No such channel */ |
| 6333 | 76 { "404", "nt:", irc_msg_nosend }, /* Cannot send to chan */ |
| 77 { "421", "nv:", irc_msg_unknown }, /* Unknown command */ | |
| 6350 | 78 { "422", "nv:", irc_msg_endmotd }, /* No MOTD available */ |
| 6333 | 79 { "433", "vn:", irc_msg_nickused }, /* Nickname already in use */ |
| 6718 | 80 { "438", "nn:", irc_msg_nochangenick }, /* Nick may not change */ |
| 6333 | 81 { "442", "nc:", irc_msg_notinchan }, /* Not in channel */ |
| 82 { "473", "nc:", irc_msg_inviteonly }, /* Tried to join invite-only */ | |
| 83 { "474", "nc:", irc_msg_banned }, /* Banned from channel */ | |
| 84 { "482", "nc:", irc_msg_notop }, /* Need to be op to do that */ | |
| 85 { "501", "n:", irc_msg_badmode }, /* Unknown mode flag */ | |
| 6714 | 86 { "515", "nc:", irc_msg_regonly }, /* Registration required */ |
| 6333 | 87 { "invite", "n:", irc_msg_invite }, /* Invited */ |
| 88 { "join", ":", irc_msg_join }, /* Joined a channel */ | |
| 89 { "kick", "cn:", irc_msg_kick }, /* KICK */ | |
| 90 { "mode", "tv:", irc_msg_mode }, /* MODE for channel */ | |
| 91 { "nick", ":", irc_msg_nick }, /* Nick change */ | |
| 92 { "notice", "t:", irc_msg_notice }, /* NOTICE recv */ | |
| 93 { "part", "c:", irc_msg_part }, /* Parted a channel */ | |
| 94 { "ping", ":", irc_msg_ping }, /* Received PING from server */ | |
| 95 { "pong", "v:", irc_msg_pong }, /* Received PONG from server */ | |
| 96 { "privmsg", "t:", irc_msg_privmsg }, /* Received private message */ | |
| 97 { "topic", "c:", irc_msg_topic }, /* TOPIC command */ | |
| 98 { "quit", ":", irc_msg_quit }, /* QUIT notice */ | |
| 99 { "wallops", ":", irc_msg_wallops }, /* WALLOPS command */ | |
| 100 { NULL, NULL, NULL } | |
| 101 }; | |
| 102 | |
| 103 static struct _irc_user_cmd { | |
| 104 char *name; | |
| 105 char *format; | |
| 106 IRCCmdCallback cb; | |
| 107 } _irc_cmds[] = { | |
| 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 | |
| 271 char *irc_parse_ctcp(struct irc_conn *irc, const char *from, const char *to, const char *msg, int notice) | |
| 272 { | |
| 273 GaimConnection *gc; | |
| 274 const char *cur = msg + 1; | |
| 275 char *buf, *ctcp; | |
| 276 time_t timestamp; | |
| 277 | |
| 6754 | 278 /* Note that this is NOT correct w.r.t. multiple CTCPs in one |
| 279 * message and low-level quoting ... but if you want that crap, | |
| 280 * use a real IRC client. */ | |
| 281 | |
| 6333 | 282 if (msg[0] != '\001' || msg[strlen(msg) - 1] != '\001') |
| 283 return g_strdup(msg); | |
| 284 | |
| 285 if (!strncmp(cur, "ACTION ", 7)) { | |
| 286 cur += 7; | |
| 287 buf = g_strdup_printf("/me %s", cur); | |
| 288 buf[strlen(buf) - 1] = '\0'; | |
| 289 return buf; | |
| 290 } else if (!strncmp(cur, "PING ", 5)) { | |
| 291 if (notice) { /* reply */ | |
| 292 sscanf(cur, "PING %lu", ×tamp); | |
| 293 gc = gaim_account_get_connection(irc->account); | |
| 294 if (!gc) | |
| 295 return NULL; | |
| 6350 | 296 buf = g_strdup_printf(_("Reply time from %s: %lu seconds"), from, time(NULL) - timestamp); |
| 6333 | 297 gaim_notify_info(gc, _("PONG"), _("CTCP PING reply"), buf); |
| 298 g_free(buf); | |
| 299 return NULL; | |
| 300 } else { | |
| 301 buf = irc_format(irc, "vt:", "NOTICE", from, msg); | |
| 302 irc_send(irc, buf); | |
| 303 g_free(buf); | |
| 304 gc = gaim_account_get_connection(irc->account); | |
| 305 } | |
| 306 } else if (!strncmp(cur, "VERSION", 7) && !notice) { | |
| 307 buf = irc_format(irc, "vt:", "NOTICE", from, "\001VERSION Gaim IRC\001"); | |
| 308 irc_send(irc, buf); | |
| 309 g_free(buf); | |
| 310 } | |
| 311 | |
| 312 ctcp = g_strdup(msg + 1); | |
| 313 ctcp[strlen(ctcp) - 1] = '\0'; | |
| 314 buf = g_strdup_printf("Received CTCP '%s' (to %s) from %s", ctcp, to, from); | |
| 315 g_free(ctcp); | |
| 316 return buf; | |
| 317 } | |
| 318 | |
| 319 void irc_msg_table_build(struct irc_conn *irc) | |
| 320 { | |
| 321 int i; | |
| 322 | |
| 323 if (!irc || !irc->msgs) { | |
| 324 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a message table on a bogus structure\n"); | |
| 325 return; | |
| 326 } | |
| 327 | |
| 328 for (i = 0; _irc_msgs[i].name; i++) { | |
| 329 g_hash_table_insert(irc->msgs, (gpointer)_irc_msgs[i].name, (gpointer)&_irc_msgs[i]); | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 void irc_cmd_table_build(struct irc_conn *irc) | |
| 334 { | |
| 335 int i; | |
| 336 | |
| 337 if (!irc || !irc->cmds) { | |
| 338 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Attempt to build a command table on a bogus structure\n"); | |
| 339 return; | |
| 340 } | |
| 341 | |
| 342 for (i = 0; _irc_cmds[i].name ; i++) { | |
| 343 g_hash_table_insert(irc->cmds, (gpointer)_irc_cmds[i].name, (gpointer)&_irc_cmds[i]); | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 char *irc_format(struct irc_conn *irc, const char *format, ...) | |
| 348 { | |
| 349 GString *string = g_string_new(""); | |
| 350 char *tok, *tmp; | |
| 351 const char *cur; | |
| 352 va_list ap; | |
| 353 | |
| 354 va_start(ap, format); | |
| 355 for (cur = format; *cur; cur++) { | |
| 356 if (cur != format) | |
| 357 g_string_append_c(string, ' '); | |
| 358 | |
| 359 tok = va_arg(ap, char *); | |
| 360 switch (*cur) { | |
| 361 case 'v': | |
| 362 g_string_append(string, tok); | |
| 363 break; | |
| 364 case ':': | |
| 365 g_string_append_c(string, ':'); | |
| 366 /* no break! */ | |
| 367 case 't': | |
| 368 case 'n': | |
| 369 case 'c': | |
| 370 tmp = irc_send_convert(irc, tok); | |
| 371 g_string_append(string, tmp); | |
| 372 g_free(tmp); | |
| 373 break; | |
| 374 default: | |
| 375 gaim_debug(GAIM_DEBUG_ERROR, "irc", "Invalid format character '%c'\n", *cur); | |
| 376 break; | |
| 377 } | |
| 378 } | |
| 379 va_end(ap); | |
| 380 g_string_append(string, "\r\n"); | |
| 381 return (g_string_free(string, FALSE)); | |
| 382 } | |
| 383 | |
| 384 void irc_parse_msg(struct irc_conn *irc, char *input) | |
| 385 { | |
| 386 struct _irc_msg *msgent; | |
| 387 char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg; | |
| 7631 | 388 guint i; |
| 6333 | 389 |
| 390 if (!strncmp(input, "PING ", 5)) { | |
| 391 msg = irc_format(irc, "vv", "PONG", input + 5); | |
| 392 irc_send(irc, msg); | |
| 393 g_free(msg); | |
| 394 return; | |
| 395 } else if (!strncmp(input, "ERROR ", 6)) { | |
| 7981 | 396 gaim_connection_error(gaim_account_get_connection(irc->account), _("Disconnected.")); |
| 6333 | 397 return; |
| 398 } | |
| 399 | |
| 400 if (input[0] != ':' || (cur = strchr(input, ' ')) == NULL) { | |
| 401 irc_parse_error_cb(irc, input); | |
| 402 return; | |
| 403 } | |
| 404 | |
| 405 from = g_strndup(&input[1], cur - &input[1]); | |
| 406 cur++; | |
| 407 end = strchr(cur, ' '); | |
| 408 if (!end) | |
| 409 end = cur + strlen(cur); | |
| 410 | |
| 411 tmp = g_strndup(cur, end - cur); | |
| 412 msgname = g_ascii_strdown(tmp, -1); | |
| 413 g_free(tmp); | |
| 414 | |
| 415 if ((msgent = g_hash_table_lookup(irc->msgs, msgname)) == NULL) { | |
| 416 irc_msg_default(irc, "", from, &input); | |
| 417 g_free(msgname); | |
| 418 g_free(from); | |
| 419 return; | |
| 420 } | |
| 421 g_free(msgname); | |
| 422 | |
| 423 args = g_new0(char *, strlen(msgent->format)); | |
| 424 for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) { | |
| 425 switch (fmt[i]) { | |
| 426 case 'v': | |
| 427 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 428 args[i] = g_strndup(cur, end - cur); | |
| 429 cur += end - cur; | |
| 430 break; | |
| 431 case 't': | |
| 432 case 'n': | |
| 433 case 'c': | |
| 434 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 435 tmp = g_strndup(cur, end - cur); | |
| 436 args[i] = irc_recv_convert(irc, tmp); | |
| 437 g_free(tmp); | |
| 438 cur += end - cur; | |
| 439 break; | |
| 440 case ':': | |
| 441 if (*cur == ':') cur++; | |
| 442 args[i] = irc_recv_convert(irc, cur); | |
| 443 cur = cur + strlen(cur); | |
| 444 break; | |
| 445 case '*': | |
| 446 args[i] = g_strdup(cur); | |
| 447 cur = cur + strlen(cur); | |
| 448 break; | |
| 449 default: | |
| 450 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]); | |
| 451 break; | |
| 452 } | |
| 453 } | |
| 6970 | 454 tmp = irc_recv_convert(irc, from); |
| 455 (msgent->cb)(irc, msgent->name, tmp, args); | |
| 456 g_free(tmp); | |
| 6333 | 457 for (i = 0; i < strlen(msgent->format); i++) { |
| 458 g_free(args[i]); | |
| 459 } | |
| 460 g_free(args); | |
| 461 g_free(from); | |
| 462 } | |
| 463 | |
| 464 int irc_parse_cmd(struct irc_conn *irc, const char *target, const char *cmdstr) | |
| 465 { | |
| 466 const char *cur, *end, *fmt; | |
| 467 char *tmp, *cmd, **args; | |
| 468 struct _irc_user_cmd *cmdent; | |
| 7631 | 469 guint i; |
| 470 int ret; | |
| 6333 | 471 |
| 472 cur = cmdstr; | |
| 473 end = strchr(cmdstr, ' '); | |
| 474 if (!end) | |
| 475 end = cur + strlen(cur); | |
| 476 | |
| 477 tmp = g_strndup(cur, end - cur); | |
| 478 cmd = g_utf8_strdown(tmp, -1); | |
| 479 g_free(tmp); | |
| 480 | |
| 481 if ((cmdent = g_hash_table_lookup(irc->cmds, cmd)) == NULL) { | |
| 482 ret = irc_cmd_default(irc, cmd, target, &cmdstr); | |
| 483 g_free(cmd); | |
| 484 return ret; | |
| 485 } | |
| 486 | |
| 487 args = g_new0(char *, strlen(cmdent->format)); | |
| 488 for (cur = end, fmt = cmdent->format, i = 0; fmt[i] && *cur++; i++) { | |
| 489 switch (fmt[i]) { | |
| 490 case 'v': | |
| 491 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 492 args[i] = g_strndup(cur, end - cur); | |
| 493 cur += end - cur; | |
| 494 break; | |
| 495 case 't': | |
| 496 case 'n': | |
| 497 case 'c': | |
| 498 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); | |
| 499 args[i] = g_strndup(cur, end - cur); | |
| 500 cur += end - cur; | |
| 501 break; | |
| 502 case ':': | |
| 503 case '*': | |
| 504 args[i] = g_strdup(cur); | |
| 505 cur = cur + strlen(cur); | |
| 506 break; | |
| 507 default: | |
| 508 gaim_debug(GAIM_DEBUG_ERROR, "irc", "invalid command format character '%c'\n", fmt[i]); | |
| 509 break; | |
| 510 } | |
| 511 } | |
| 512 ret = (cmdent->cb)(irc, cmd, target, (const char **)args); | |
| 513 for (i = 0; i < strlen(cmdent->format); i++) | |
| 514 g_free(args[i]); | |
| 515 g_free(args); | |
| 516 | |
| 517 g_free(cmd); | |
| 518 return ret; | |
| 519 } | |
| 520 | |
| 521 static void irc_parse_error_cb(struct irc_conn *irc, char *input) | |
| 522 { | |
| 523 gaim_debug(GAIM_DEBUG_WARNING, "irc", "Unrecognized string: %s\n", input); | |
| 524 } |
