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