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