Mercurial > pidgin
annotate libgaim/protocols/toc/toc.c @ 15113:4a8c368df4ea
[gaim-migrate @ 17899]
Some touchups:
* If one of the parallel connection attempts fails immediately (i.e.
does not time out) then don't cancel the other one.
* Make sure we don't continue on to step 2 of the peer connection
process after we kick off the parallel gaim_proxy_connects(). It
looks like this would happen most of the time, because the
connect_timeout_timer would be added for the verified ip, so it
would NOT be added for the client ip, and so we wouldn't hit the
"return" call because it happens to be in the same block as the
second gaim_timeout_add() call.
* Add the connection timeout timer even if the gaim_proxy_connect() to
the verified ip returns NULL for some crazy reason.
I didn't actually test any of this. I should probably do that when
I get home.
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Wed, 06 Dec 2006 01:29:59 +0000 |
| parents | 89ae31668a9c |
| children |
| rev | line source |
|---|---|
| 14192 | 1 /* |
| 2 * gaim | |
| 3 * | |
| 4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> | |
| 5 * | |
| 6 * This program is free software; you can redistribute it and/or modify | |
| 7 * it under the terms of the GNU General Public License as published by | |
| 8 * the Free Software Foundation; either version 2 of the License, or | |
| 9 * (at your option) any later version. | |
| 10 * | |
| 11 * This program is distributed in the hope that it will be useful, | |
| 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 * GNU General Public License for more details. | |
| 15 * | |
| 16 * You should have received a copy of the GNU General Public License | |
| 17 * along with this program; if not, write to the Free Software | |
| 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 * | |
| 20 */ | |
| 21 #include "internal.h" | |
| 22 | |
| 23 #include "account.h" | |
| 24 #include "accountopt.h" | |
| 25 #include "conversation.h" | |
| 26 #include "debug.h" | |
| 27 #include "notify.h" | |
| 28 #include "privacy.h" | |
| 29 #include "proxy.h" | |
| 30 #include "prpl.h" | |
| 31 #include "request.h" | |
| 32 #include "util.h" | |
| 33 #include "version.h" | |
| 34 | |
| 35 static GaimPlugin *my_protocol = NULL; | |
| 36 | |
| 37 #define REVISION "penguin" | |
| 38 | |
| 39 #define TYPE_SIGNON 1 | |
| 40 #define TYPE_DATA 2 | |
| 41 #define TYPE_ERROR 3 | |
| 42 #define TYPE_SIGNOFF 4 | |
| 43 #define TYPE_KEEPALIVE 5 | |
| 44 | |
| 45 #define FLAPON "FLAPON\r\n\r\n" | |
| 46 #define ROAST "Tic/Toc" | |
| 47 | |
| 48 #define TOC_HOST "toc.oscar.aol.com" | |
| 49 #define TOC_PORT 9898 | |
| 50 #define AUTH_HOST "login.oscar.aol.com" | |
| 51 #define AUTH_PORT 5190 | |
| 52 #define LANGUAGE "english" | |
| 53 | |
| 54 #define STATE_OFFLINE 0 | |
| 55 #define STATE_FLAPON 1 | |
| 56 #define STATE_SIGNON_REQUEST 2 | |
| 57 #define STATE_ONLINE 3 | |
| 58 #define STATE_PAUSE 4 | |
| 59 | |
| 60 #define VOICE_UID "09461341-4C7F-11D1-8222-444553540000" | |
| 61 #define FILE_SEND_UID "09461343-4C7F-11D1-8222-444553540000" | |
| 62 #define IMAGE_UID "09461345-4C7F-11D1-8222-444553540000" | |
| 63 #define B_ICON_UID "09461346-4C7F-11D1-8222-444553540000" | |
| 64 #define STOCKS_UID "09461347-4C7F-11D1-8222-444553540000" | |
| 65 #define FILE_GET_UID "09461348-4C7F-11D1-8222-444553540000" | |
| 66 #define GAMES_UID "0946134a-4C7F-11D1-8222-444553540000" | |
| 67 | |
| 68 #define UC_UNAVAILABLE 0x01 | |
| 69 #define UC_AOL 0x02 | |
| 70 #define UC_ADMIN 0x04 | |
| 71 #define UC_UNCONFIRMED 0x08 | |
| 72 #define UC_NORMAL 0x10 | |
| 73 #define UC_WIRELESS 0x20 | |
| 74 | |
| 75 struct ft_request { | |
| 76 GaimConnection *gc; | |
| 77 char *user; | |
| 78 char UID[2048]; | |
| 79 char *cookie; | |
| 80 char *ip; | |
| 81 int port; | |
| 82 char *message; | |
| 83 char *filename; | |
| 84 int files; | |
| 85 int size; | |
| 86 }; | |
| 87 | |
| 88 struct buddy_icon { | |
| 89 guint32 hash; | |
| 90 guint32 len; | |
| 91 time_t time; | |
| 92 void *data; | |
| 93 }; | |
| 94 | |
| 95 struct toc_data { | |
| 96 int toc_fd; | |
| 97 char toc_ip[20]; | |
| 98 int seqno; | |
| 99 int state; | |
| 100 }; | |
| 101 | |
| 102 struct sflap_hdr { | |
| 103 unsigned char ast; | |
| 104 unsigned char type; | |
| 105 unsigned short seqno; | |
| 106 unsigned short len; | |
| 107 }; | |
| 108 | |
| 109 struct signon { | |
| 110 unsigned int ver; | |
| 111 unsigned short tag; | |
| 112 unsigned short namelen; | |
| 113 char username[80]; | |
| 114 }; | |
| 115 | |
| 116 /* constants to identify proto_opts */ | |
| 117 #define USEROPT_AUTH 0 | |
| 118 #define USEROPT_AUTHPORT 1 | |
| 119 | |
| 120 #define TOC_CONNECT_STEPS 3 | |
| 121 | |
| 122 static void toc_login_callback(gpointer, gint, GaimInputCondition); | |
| 123 static void toc_callback(gpointer, gint, GaimInputCondition); | |
| 124 | |
| 125 /* ok. this function used to take username/password, and return 0 on success. | |
| 126 * now, it takes username/password, and returns NULL on error or a new gaim_connection | |
| 127 * on success. */ | |
| 128 static void toc_login(GaimAccount *account) | |
| 129 { | |
| 130 GaimConnection *gc; | |
| 131 struct toc_data *tdt; | |
| 132 char buf[80]; | |
| 133 | |
| 134 gc = gaim_account_get_connection(account); | |
| 135 gc->proto_data = tdt = g_new0(struct toc_data, 1); | |
| 136 gc->flags |= GAIM_CONNECTION_HTML; | |
| 137 gc->flags |= GAIM_CONNECTION_AUTO_RESP; | |
| 138 | |
| 139 g_snprintf(buf, sizeof buf, _("Looking up %s"), | |
| 140 gaim_account_get_string(account, "server", TOC_HOST)); | |
| 141 gaim_connection_update_progress(gc, buf, 0, TOC_CONNECT_STEPS); | |
| 142 | |
| 143 gaim_debug(GAIM_DEBUG_INFO, "toc", "Client connects to TOC\n"); | |
| 14837 | 144 if (gaim_proxy_connect(gc, account, |
| 14192 | 145 gaim_account_get_string(account, "server", TOC_HOST), |
| 146 gaim_account_get_int(account, "port", TOC_PORT), | |
| 147 toc_login_callback, gc) != 0 || !account->gc) { | |
| 148 g_snprintf(buf, sizeof(buf), _("Connect to %s failed"), | |
| 149 gaim_account_get_string(account, "server", TOC_HOST)); | |
| 150 gaim_connection_error(gc, buf); | |
| 151 return; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 static void toc_login_callback(gpointer data, gint source, GaimInputCondition cond) | |
| 156 { | |
| 157 GaimConnection *gc = data; | |
| 158 struct toc_data *tdt; | |
| 159 char buf[80]; | |
| 160 struct sockaddr_in name; | |
| 161 socklen_t namelen; | |
| 162 | |
| 163 if (!GAIM_CONNECTION_IS_VALID(gc)) { | |
| 164 if (source >= 0) | |
| 165 close(source); | |
| 166 return; | |
| 167 } | |
| 168 | |
| 169 tdt = gc->proto_data; | |
| 170 | |
| 171 if (source == -1) { | |
| 172 /* we didn't successfully connect. tdt->toc_fd is valid here */ | |
| 173 gaim_connection_error(gc, _("Unable to connect.")); | |
| 174 return; | |
| 175 } | |
| 176 tdt->toc_fd = source; | |
| 177 | |
| 178 /* | |
| 179 * Copy the IP that we're connected to. We need this because "GOTO_URL"'s | |
| 180 * should open on the exact server we're connected to. toc.oscar.aol.com | |
| 181 * doesn't work because that hostname resolves to multiple IP addresses. | |
| 182 */ | |
| 183 if (getpeername(tdt->toc_fd, (struct sockaddr *)&name, &namelen) == 0) | |
| 184 strncpy(tdt->toc_ip, inet_ntoa(name.sin_addr), sizeof(tdt->toc_ip)); | |
| 185 else | |
| 186 strncpy(tdt->toc_ip, gaim_account_get_string(gc->account, "server", TOC_HOST), sizeof(tdt->toc_ip)); | |
| 187 | |
| 188 gaim_debug(GAIM_DEBUG_INFO, "toc", | |
| 189 "Client sends \"FLAPON\\r\\n\\r\\n\"\n"); | |
| 190 if (write(tdt->toc_fd, FLAPON, strlen(FLAPON)) < 0) { | |
| 191 gaim_connection_error(gc, _("Disconnected.")); | |
| 192 return; | |
| 193 } | |
| 194 tdt->state = STATE_FLAPON; | |
| 195 | |
| 196 /* i know a lot of people like to look at gaim to see how TOC works. so i'll comment | |
| 197 * on what this does. it's really simple. when there's data ready to be read from the | |
| 198 * toc_fd file descriptor, toc_callback is called, with gc passed as its data arg. */ | |
| 199 gc->inpa = gaim_input_add(tdt->toc_fd, GAIM_INPUT_READ, toc_callback, gc); | |
| 200 | |
| 201 g_snprintf(buf, sizeof(buf), _("Signon: %s"), gaim_account_get_username(gc->account)); | |
| 202 gaim_connection_update_progress(gc, buf, 1, TOC_CONNECT_STEPS); | |
| 203 } | |
| 204 | |
| 205 static void toc_close(GaimConnection *gc) | |
| 206 { | |
| 207 if (gc->inpa > 0) | |
| 208 gaim_input_remove(gc->inpa); | |
| 209 gc->inpa = 0; | |
| 210 close(((struct toc_data *)gc->proto_data)->toc_fd); | |
| 211 g_free(gc->proto_data); | |
| 212 } | |
| 213 | |
| 214 static void toc_build_config(GaimAccount *account, char *s, int len, gboolean show) | |
| 215 { | |
| 216 GaimBlistNode *gnode, *cnode, *bnode; | |
| 217 GaimGroup *g; | |
| 218 GaimBuddy *b; | |
| 219 GSList *plist = account->permit; | |
| 220 GSList *dlist = account->deny; | |
| 221 | |
| 222 int pos = 0; | |
| 223 | |
| 224 if (!account->perm_deny) | |
| 225 account->perm_deny = 1; | |
| 226 | |
| 227 pos += g_snprintf(&s[pos], len - pos, "m %d\n", account->perm_deny); | |
| 228 for(gnode = gaim_get_blist()->root; gnode && len > pos; gnode = gnode->next) { | |
| 229 g = (GaimGroup *)gnode; | |
| 230 if(!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
| 231 continue; | |
| 232 if(gaim_group_on_account(g, account)) { | |
| 233 pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name); | |
| 234 for(cnode = gnode->child; cnode; cnode = cnode->next) { | |
| 235 if(!GAIM_BLIST_NODE_IS_CONTACT(cnode)) | |
| 236 continue; | |
| 237 for(bnode = gnode->child; bnode && len > pos; bnode = bnode->next) { | |
| 238 b = (GaimBuddy *)bnode; | |
| 239 if(!GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
| 240 continue; | |
| 241 if(b->account == account) { | |
| 242 pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", | |
| 243 b->name, | |
| 244 (show && b->alias) ? ":" : "", | |
| 245 (show && b->alias) ? b->alias : ""); | |
| 246 } | |
| 247 } | |
| 248 } | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 while (len > pos && plist) { | |
| 253 pos += g_snprintf(&s[pos], len - pos, "p %s\n", (char *)plist->data); | |
| 254 plist = plist->next; | |
| 255 } | |
| 256 | |
| 257 while (len > pos && dlist) { | |
| 258 pos += g_snprintf(&s[pos], len - pos, "d %s\n", (char *)dlist->data); | |
| 259 dlist = dlist->next; | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 char *escape_message(const char *msg) | |
| 264 { | |
| 265 char *ret; | |
| 266 int i, j; | |
| 267 | |
| 268 if (!msg) | |
| 269 return NULL; | |
| 270 | |
| 271 /* Calculate the length after escaping */ | |
| 272 for (i=0, j=0; msg[i]; i++) | |
| 273 switch (msg[i]) { | |
| 274 case '$': | |
| 275 case '[': | |
| 276 case ']': | |
| 277 case '(': | |
| 278 case ')': | |
| 279 j++; | |
| 280 default: | |
| 281 j++; | |
| 282 } | |
| 283 | |
| 284 /* Allocate a string */ | |
| 285 ret = (char *)g_malloc((j+1) * sizeof(char)); | |
| 286 | |
| 287 /* Copy the string */ | |
| 288 for (i=0, j=0; msg[i]; i++) | |
| 289 switch (msg[i]) { | |
| 290 case '$': | |
| 291 case '[': | |
| 292 case ']': | |
| 293 case '(': | |
| 294 case ')': | |
| 295 ret[j++] = '\\'; | |
| 296 default: | |
| 297 ret[j++] = msg[i]; | |
| 298 } | |
| 299 ret[j] = '\0'; | |
| 300 | |
| 301 return ret; | |
| 302 } | |
| 303 | |
| 304 /* | |
| 305 * Duplicates the input string, replacing each \n with a <BR>, and | |
| 306 * escaping a few other characters. | |
| 307 */ | |
| 308 char *escape_text(const char *msg) | |
| 309 { | |
| 310 char *ret; | |
| 311 int i, j; | |
| 312 | |
| 313 if (!msg) | |
| 314 return NULL; | |
| 315 | |
| 316 /* Calculate the length after escaping */ | |
| 317 for (i=0, j=0; msg[i]; i++) | |
| 318 switch (msg[i]) { | |
| 319 case '\n': | |
| 320 j += 4; | |
| 321 break; | |
| 322 case '{': | |
| 323 case '}': | |
| 324 case '\\': | |
| 325 case '"': | |
| 326 j += 1; | |
| 327 default: | |
| 328 j += 1; | |
| 329 } | |
| 330 | |
| 331 /* Allocate a string */ | |
| 332 ret = (char *)malloc((j+1) * sizeof(char)); | |
| 333 | |
| 334 /* Copy the string */ | |
| 335 for (i=0, j=0; msg[i]; i++) | |
| 336 switch (msg[i]) { | |
| 337 case '\n': | |
| 338 ret[j++] = '<'; | |
| 339 ret[j++] = 'B'; | |
| 340 ret[j++] = 'R'; | |
| 341 ret[j++] = '>'; | |
| 342 break; | |
| 343 case '{': | |
| 344 case '}': | |
| 345 case '\\': | |
| 346 case '"': | |
| 347 ret[j++] = '\\'; | |
| 348 default: | |
| 349 ret[j++] = msg[i]; | |
| 350 } | |
| 351 ret[j] = '\0'; | |
| 352 | |
| 353 return ret; | |
| 354 } | |
| 355 | |
| 356 static int sflap_send(GaimConnection *gc, const char *buf, int olen, int type) | |
| 357 { | |
| 358 struct toc_data *tdt = (struct toc_data *)gc->proto_data; | |
| 359 int len; | |
| 360 int slen = 0; | |
| 361 int ret; | |
| 362 struct sflap_hdr hdr; | |
| 363 char *escaped, *obuf; | |
| 364 | |
| 365 if (tdt->state == STATE_PAUSE) | |
| 366 /* TOC has given us the PAUSE message; sending could cause a disconnect | |
| 367 * so we just return here like everything went through fine */ | |
| 368 return 0; | |
| 369 | |
| 370 if (olen < 0) { | |
| 371 escaped = escape_message(buf); | |
| 372 len = strlen(escaped); | |
| 373 } else { | |
| 374 escaped = g_memdup(buf, olen); | |
| 375 len = olen; | |
| 376 } | |
| 377 | |
| 378 /* | |
| 379 * One _last_ 2048 check here! This shouldn't ever | |
| 380 * get hit though, hopefully. If it gets hit on an IM | |
| 381 * It'll lose the last " and the message won't go through, | |
| 382 * but this'll stop a segfault. | |
| 383 */ | |
| 384 if (len > MSG_LEN) { | |
| 385 gaim_debug(GAIM_DEBUG_WARNING, "toc", "message too long, truncating\n"); | |
| 386 escaped[MSG_LEN - 1] = '\0'; | |
| 387 len = MSG_LEN; | |
| 388 } | |
| 389 | |
| 390 if (olen < 0) | |
| 391 gaim_debug(GAIM_DEBUG_INFO, "toc", "C: %s\n", escaped); | |
| 392 | |
| 393 hdr.ast = '*'; | |
| 394 hdr.type = type; | |
| 395 hdr.seqno = htons(tdt->seqno++ & 0xffff); | |
| 396 hdr.len = htons(len + (type == TYPE_SIGNON ? 0 : 1)); | |
| 397 | |
| 398 obuf = (char *)malloc((sizeof(hdr)+len+1) * sizeof(char)); | |
| 399 memcpy(obuf, &hdr, sizeof(hdr)); | |
| 400 slen += sizeof(hdr); | |
| 401 | |
| 402 memcpy(&obuf[slen], escaped, len); | |
| 403 slen += len; | |
| 404 | |
| 405 if (type != TYPE_SIGNON) { | |
| 406 obuf[slen] = '\0'; | |
| 407 slen += 1; | |
| 408 } | |
| 409 | |
| 410 ret = write(tdt->toc_fd, obuf, slen); | |
| 411 free(obuf); | |
| 412 g_free(escaped); | |
| 413 | |
| 414 return ret; | |
| 415 } | |
| 416 | |
| 14542 | 417 static int toc_send_raw(GaimConnection *gc, const char *buf, int len) |
| 418 { | |
| 419 return sflap_send(gc, buf, len, 2); | |
| 420 } | |
| 421 | |
| 14192 | 422 static int wait_reply(GaimConnection *gc, char *buffer, size_t buflen) |
| 423 { | |
| 424 struct toc_data *tdt = (struct toc_data *)gc->proto_data; | |
| 425 struct sflap_hdr *hdr; | |
| 426 int ret; | |
| 427 | |
| 428 if (read(tdt->toc_fd, buffer, sizeof(struct sflap_hdr)) < 0) { | |
| 429 gaim_debug(GAIM_DEBUG_ERROR, "toc", "Couldn't read flap header\n"); | |
| 430 return -1; | |
| 431 } | |
| 432 | |
| 433 hdr = (struct sflap_hdr *)buffer; | |
| 434 | |
| 435 if (buflen < ntohs(hdr->len)) { | |
| 436 /* fake like there's a read error */ | |
| 437 gaim_debug(GAIM_DEBUG_ERROR, "toc", | |
| 438 "buffer too small (have %d, need %d)\n", | |
| 439 buflen, ntohs(hdr->len)); | |
| 440 return -1; | |
| 441 } | |
| 442 | |
| 443 if (ntohs(hdr->len) > 0) { | |
| 444 int count = 0; | |
| 445 ret = 0; | |
| 446 do { | |
| 447 count += ret; | |
| 448 ret = read(tdt->toc_fd, | |
| 449 buffer + sizeof(struct sflap_hdr) + count, ntohs(hdr->len) - count); | |
| 450 } while (count + ret < ntohs(hdr->len) && ret > 0); | |
| 451 buffer[sizeof(struct sflap_hdr) + count + ret] = '\0'; | |
| 452 return ret; | |
| 453 } else | |
| 454 return 0; | |
| 455 } | |
| 456 | |
| 457 static unsigned char *roast_password(const char *pass) | |
| 458 { | |
| 459 /* Trivial "encryption" */ | |
| 460 static unsigned char rp[256]; | |
| 461 static char *roast = ROAST; | |
| 462 int pos = 2; | |
| 463 int x; | |
| 464 strcpy(rp, "0x"); | |
| 465 for (x = 0; (x < 150) && pass[x]; x++) | |
| 466 pos += sprintf(&rp[pos], "%02x", pass[x] ^ roast[x % strlen(roast)]); | |
| 467 rp[pos] = '\0'; | |
| 468 return rp; | |
| 469 } | |
| 470 | |
| 471 static void toc_got_info(void *data, const char *url_text, size_t len) | |
| 472 { | |
| 473 if (!url_text) | |
| 474 return; | |
| 475 | |
| 476 gaim_notify_formatted(data, NULL, _("Buddy Information"), NULL, | |
| 477 url_text, NULL, NULL); | |
| 478 } | |
| 479 | |
| 480 static char *show_error_message() | |
| 481 { | |
| 482 int no = atoi(strtok(NULL, ":")); | |
| 483 char *w = strtok(NULL, ":"); | |
| 484 static char buf[256]; | |
| 485 | |
| 486 switch(no) { | |
| 487 case 69: | |
| 488 g_snprintf(buf, sizeof(buf), _("Unable to write file %s."), w); | |
| 489 break; | |
| 490 case 169: | |
| 491 g_snprintf(buf, sizeof(buf), _("Unable to read file %s."), w); | |
| 492 break; | |
| 493 case 269: | |
| 494 g_snprintf(buf, sizeof(buf), _("Message too long, last %s bytes truncated."), w); | |
| 495 break; | |
| 496 case 901: | |
| 497 g_snprintf(buf, sizeof(buf), _("%s not currently logged in."), w); | |
| 498 break; | |
| 499 case 902: | |
| 500 g_snprintf(buf, sizeof(buf), _("Warning of %s not allowed."), w); | |
| 501 break; | |
| 502 case 903: | |
| 503 g_snprintf(buf, sizeof(buf), _("A message has been dropped, you are exceeding the server speed limit.")); | |
| 504 break; | |
| 505 case 950: | |
| 506 g_snprintf(buf, sizeof(buf), _("Chat in %s is not available."), w); | |
| 507 break; | |
| 508 case 960: | |
| 509 g_snprintf(buf, sizeof(buf), _("You are sending messages too fast to %s."), w); | |
| 510 break; | |
| 511 case 961: | |
| 512 g_snprintf(buf, sizeof(buf), _("You missed an IM from %s because it was too big."), w); | |
| 513 break; | |
| 514 case 962: | |
| 515 g_snprintf(buf, sizeof(buf), _("You missed an IM from %s because it was sent too fast."), w); | |
| 516 break; | |
| 517 case 970: | |
| 518 g_snprintf(buf, sizeof(buf), _("Failure.")); | |
| 519 break; | |
| 520 case 971: | |
| 521 g_snprintf(buf, sizeof(buf), _("Too many matches.")); | |
| 522 break; | |
| 523 case 972: | |
| 524 g_snprintf(buf, sizeof(buf), _("Need more qualifiers.")); | |
| 525 break; | |
| 526 case 973: | |
| 527 g_snprintf(buf, sizeof(buf), _("Dir service temporarily unavailable.")); | |
| 528 break; | |
| 529 case 974: | |
| 530 g_snprintf(buf, sizeof(buf), _("E-mail lookup restricted.")); | |
| 531 break; | |
| 532 case 975: | |
| 533 g_snprintf(buf, sizeof(buf), _("Keyword ignored.")); | |
| 534 break; | |
| 535 case 976: | |
| 536 g_snprintf(buf, sizeof(buf), _("No keywords.")); | |
| 537 break; | |
| 538 case 977: | |
| 539 g_snprintf(buf, sizeof(buf), _("User has no directory information.")); | |
| 540 /* g_snprintf(buf, sizeof(buf), _("Language not supported.")); */ | |
| 541 break; | |
| 542 case 978: | |
| 543 g_snprintf(buf, sizeof(buf), _("Country not supported.")); | |
| 544 break; | |
| 545 case 979: | |
| 546 g_snprintf(buf, sizeof(buf), _("Failure unknown: %s."), w); | |
| 547 break; | |
| 548 case 980: | |
|
15000
89ae31668a9c
[gaim-migrate @ 17779]
Richard Laager <rlaager@wiktel.com>
parents:
14837
diff
changeset
|
549 g_snprintf(buf, sizeof(buf), _("Incorrect screen name or password.")); |
| 14192 | 550 break; |
| 551 case 981: | |
| 552 g_snprintf(buf, sizeof(buf), _("The service is temporarily unavailable.")); | |
| 553 break; | |
| 554 case 982: | |
| 555 g_snprintf(buf, sizeof(buf), _("Your warning level is currently too high to log in.")); | |
| 556 break; | |
| 557 case 983: | |
| 558 g_snprintf(buf, sizeof(buf), _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); | |
| 559 break; | |
| 560 g_snprintf(buf, sizeof(buf), _("An unknown signon error has occurred: %s."), w); | |
| 561 break; | |
| 562 default: | |
| 563 g_snprintf(buf, sizeof(buf), _("An unknown error, %d, has occurred. Info: %s"), no, w); | |
| 564 } | |
| 565 | |
| 566 return buf; | |
| 567 } | |
| 568 | |
| 569 static void | |
| 570 parse_toc_buddy_list(GaimAccount *account, char *config) | |
| 571 { | |
| 572 char *c; | |
| 573 char current[256]; | |
| 574 GList *buddies = NULL; | |
| 575 | |
| 576 if (config == NULL) | |
| 577 return; | |
| 578 | |
| 579 /* skip "CONFIG:" (if it exists) */ | |
| 580 c = strncmp(config + 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ? | |
| 581 strtok(config, "\n") : | |
| 582 strtok(config + 6 /* sizeof(struct sflap_hdr) */ + strlen("CONFIG:"), "\n"); | |
| 583 do { | |
| 584 if (c == NULL) | |
| 585 break; | |
| 586 if (*c == 'g') { | |
| 587 char *utf8 = NULL; | |
| 588 utf8 = gaim_utf8_try_convert(c + 2); | |
| 589 if (utf8 == NULL) { | |
| 590 g_strlcpy(current, _("Invalid Groupname"), sizeof(current)); | |
| 591 } else { | |
| 592 g_strlcpy(current, utf8, sizeof(current)); | |
| 593 g_free(utf8); | |
| 594 } | |
| 595 if (!gaim_find_group(current)) { | |
| 596 GaimGroup *g = gaim_group_new(current); | |
| 597 gaim_blist_add_group(g, NULL); | |
| 598 } | |
| 599 } else if (*c == 'b') { /*&& !gaim_find_buddy(user, c + 2)) {*/ | |
| 600 char nm[80], sw[388], *a, *utf8 = NULL; | |
| 601 | |
| 602 if ((a = strchr(c + 2, ':')) != NULL) { | |
| 603 *a++ = '\0'; /* nul the : */ | |
| 604 } | |
| 605 | |
| 606 g_strlcpy(nm, c + 2, sizeof(nm)); | |
| 607 if (a) { | |
| 608 utf8 = gaim_utf8_try_convert(a); | |
| 609 if (utf8 == NULL) { | |
| 610 gaim_debug(GAIM_DEBUG_ERROR, "toc blist", | |
| 611 "Failed to convert alias for " | |
| 612 "'%s' to UTF-8\n", nm); | |
| 613 } | |
| 614 } | |
| 615 if (utf8 == NULL) { | |
| 616 sw[0] = '\0'; | |
| 617 } else { | |
| 618 /* This can leave a partial sequence at the end, | |
| 619 * but who cares? */ | |
| 620 g_strlcpy(sw, utf8, sizeof(sw)); | |
| 621 g_free(utf8); | |
| 622 } | |
| 623 | |
| 624 if (!gaim_find_buddy(account, nm)) { | |
| 625 GaimBuddy *b = gaim_buddy_new(account, nm, sw); | |
| 626 GaimGroup *g = gaim_find_group(current); | |
| 627 gaim_blist_add_buddy(b, NULL, g, NULL); | |
| 628 buddies = g_list_append(buddies, b); | |
| 629 } | |
| 630 } else if (*c == 'p') { | |
| 631 gaim_privacy_permit_add(account, c + 2, TRUE); | |
| 632 } else if (*c == 'd') { | |
| 633 gaim_privacy_deny_add(account, c + 2, TRUE); | |
| 634 } else if (!strncmp("toc", c, 3)) { | |
| 635 sscanf(c + strlen(c) - 1, "%d", &account->perm_deny); | |
| 636 gaim_debug(GAIM_DEBUG_MISC, "toc blist", | |
| 637 "permdeny: %d\n", account->perm_deny); | |
| 638 if (account->perm_deny == 0) | |
| 639 account->perm_deny = GAIM_PRIVACY_ALLOW_ALL; | |
| 640 } else if (*c == 'm') { | |
| 641 sscanf(c + 2, "%d", &account->perm_deny); | |
| 642 gaim_debug(GAIM_DEBUG_MISC, "toc blist", | |
| 643 "permdeny: %d\n", account->perm_deny); | |
| 644 if (account->perm_deny == 0) | |
| 645 account->perm_deny = GAIM_PRIVACY_ALLOW_ALL; | |
| 646 } | |
| 647 } while ((c = strtok(NULL, "\n"))); | |
| 648 | |
| 649 if (account->gc) { | |
| 650 if (buddies != NULL) { | |
| 651 gaim_account_add_buddies(account, buddies); | |
| 652 g_list_free(buddies); | |
| 653 } | |
| 654 serv_set_permit_deny(account->gc); | |
| 655 } | |
| 656 g_list_free(buddies); | |
| 657 } | |
| 658 | |
| 659 static void toc_callback(gpointer data, gint source, GaimInputCondition condition) | |
| 660 { | |
| 661 GaimConnection *gc = (GaimConnection *)data; | |
| 662 GaimAccount *account = gaim_connection_get_account(gc); | |
| 663 struct toc_data *tdt = (struct toc_data *)gc->proto_data; | |
| 664 struct sflap_hdr *hdr; | |
| 665 struct signon so; | |
| 666 char buf[8 * 1024], *c; | |
| 667 char snd[BUF_LEN * 2]; | |
| 668 const char *username = gaim_account_get_username(account); | |
| 669 char *password; | |
| 670 GaimBuddy *buddy; | |
| 671 | |
| 672 /* there's data waiting to be read, so read it. */ | |
| 673 if (wait_reply(gc, buf, 8 * 1024) <= 0) { | |
| 674 gaim_connection_error(gc, _("Connection Closed")); | |
| 675 return; | |
| 676 } | |
| 677 | |
| 678 if (tdt->state == STATE_FLAPON) { | |
| 679 hdr = (struct sflap_hdr *)buf; | |
| 680 if (hdr->type != TYPE_SIGNON) | |
| 681 gaim_debug(GAIM_DEBUG_ERROR, "toc", "hdr->type != TYPE_SIGNON\n"); | |
| 682 else | |
| 683 gaim_debug(GAIM_DEBUG_INFO, "toc", | |
| 684 "TOC sends Client FLAP SIGNON\n"); | |
| 685 tdt->seqno = ntohs(hdr->seqno); | |
| 686 tdt->state = STATE_SIGNON_REQUEST; | |
| 687 | |
| 688 gaim_debug(GAIM_DEBUG_INFO, "toc", "Client sends TOC FLAP SIGNON\n"); | |
| 689 g_snprintf(so.username, sizeof(so.username), "%s", username); | |
| 690 so.ver = htonl(1); | |
| 691 so.tag = htons(1); | |
| 692 so.namelen = htons(strlen(so.username)); | |
| 693 if (sflap_send(gc, (char *)&so, ntohs(so.namelen) + 8, TYPE_SIGNON) < 0) { | |
| 694 gaim_connection_error(gc, _("Disconnected.")); | |
| 695 return; | |
| 696 } | |
| 697 | |
| 698 gaim_debug(GAIM_DEBUG_INFO, "toc", | |
| 699 "Client sends TOC \"toc_signon\" message\n"); | |
| 700 /* i hate icq. */ | |
| 701 if (username[0] >= '0' && username[0] <= '9') | |
| 702 password = g_strndup(gaim_connection_get_password(gc), 8); | |
| 703 else | |
| 704 password = g_strdup(gaim_connection_get_password(gc)); | |
| 705 g_snprintf(snd, sizeof snd, "toc_signon %s %d %s %s %s \"%s\"", | |
| 706 AUTH_HOST, AUTH_PORT, gaim_normalize(account, username), | |
| 707 roast_password(password), LANGUAGE, REVISION); | |
| 708 g_free(password); | |
| 709 if (sflap_send(gc, snd, -1, TYPE_DATA) < 0) { | |
| 710 gaim_connection_error(gc, _("Disconnected.")); | |
| 711 return; | |
| 712 } | |
| 713 | |
| 714 gaim_connection_update_progress(gc, _("Waiting for reply..."), 2, TOC_CONNECT_STEPS); | |
| 715 return; | |
| 716 } | |
| 717 | |
| 718 if (tdt->state == STATE_SIGNON_REQUEST) { | |
| 719 gaim_debug(GAIM_DEBUG_INFO, "toc", "TOC sends client SIGN_ON reply\n"); | |
| 720 if (g_ascii_strncasecmp(buf + sizeof(struct sflap_hdr), "SIGN_ON", strlen("SIGN_ON"))) { | |
| 721 gaim_debug(GAIM_DEBUG_ERROR, "toc", | |
| 722 "Didn't get SIGN_ON! buf was: %s\n", | |
| 723 buf + sizeof(struct sflap_hdr)); | |
| 724 if (!g_ascii_strncasecmp(buf + sizeof(struct sflap_hdr), "ERROR", 5)) { | |
| 725 strtok(buf + sizeof(struct sflap_hdr), ":"); | |
| 726 gaim_connection_error(gc, show_error_message()); | |
| 727 } else | |
| 728 gaim_connection_error(gc, _("Authentication failed")); | |
| 729 return; | |
| 730 } | |
| 731 /* we're supposed to check that it's really TOC v1 here but we know it is ;) */ | |
| 732 gaim_debug(GAIM_DEBUG_INFO, "toc", | |
| 733 "TOC version: %s\n", buf + sizeof(struct sflap_hdr) + 8); | |
| 734 | |
| 735 /* we used to check for the CONFIG here, but we'll wait until we've sent our | |
| 736 * version of the config and then the toc_init_done message. we'll come back to | |
| 737 * the callback in a better state if we get CONFIG anyway */ | |
| 738 | |
| 739 tdt->state = STATE_ONLINE; | |
| 740 | |
| 741 gaim_connection_set_state(gc, GAIM_CONNECTED); | |
| 742 | |
| 743 /* | |
| 744 * Add me to my buddy list so that we know the time when | |
| 745 * the server thinks I signed on. | |
| 746 */ | |
| 747 buddy = gaim_buddy_new(account, username, NULL); | |
| 748 /* XXX - Pick a group to add to */ | |
| 749 /* gaim_blist_add(buddy, NULL, g, NULL); */ | |
| 750 gaim_account_add_buddy(gc, buddy); | |
| 751 | |
| 752 /* Client sends TOC toc_init_done message */ | |
| 753 gaim_debug(GAIM_DEBUG_INFO, "toc", | |
| 754 "Client sends TOC toc_init_done message\n"); | |
| 755 g_snprintf(snd, sizeof snd, "toc_init_done"); | |
| 756 sflap_send(gc, snd, -1, TYPE_DATA); | |
| 757 | |
| 758 /* | |
| 759 g_snprintf(snd, sizeof snd, "toc_set_caps %s %s %s", | |
| 760 FILE_SEND_UID, FILE_GET_UID, B_ICON_UID); | |
| 761 */ | |
| 762 g_snprintf(snd, sizeof snd, "toc_set_caps %s %s", FILE_SEND_UID, FILE_GET_UID); | |
| 763 sflap_send(gc, snd, -1, TYPE_DATA); | |
| 764 | |
| 765 return; | |
| 766 } | |
| 767 | |
| 768 gaim_debug(GAIM_DEBUG_INFO, "toc", "S: %s\n", | |
| 769 buf + sizeof(struct sflap_hdr)); | |
| 770 | |
| 771 c = strtok(buf + sizeof(struct sflap_hdr), ":"); /* Ditch the first part */ | |
| 772 | |
| 773 if (!g_ascii_strcasecmp(c, "SIGN_ON")) { | |
| 774 /* we should only get here after a PAUSE */ | |
| 775 if (tdt->state != STATE_PAUSE) | |
| 776 gaim_debug(GAIM_DEBUG_ERROR, "toc", | |
| 777 "got SIGN_ON but not PAUSE!\n"); | |
| 778 else { | |
| 779 tdt->state = STATE_ONLINE; | |
| 780 g_snprintf(snd, sizeof snd, "toc_signon %s %d %s %s %s \"%s\"", | |
| 781 AUTH_HOST, AUTH_PORT, | |
| 782 gaim_normalize(account, gaim_account_get_username(account)), | |
| 783 roast_password(gaim_connection_get_password(gc)), | |
| 784 LANGUAGE, REVISION); | |
| 785 if (sflap_send(gc, snd, -1, TYPE_DATA) < 0) { | |
| 786 gaim_connection_error(gc, _("Disconnected.")); | |
| 787 return; | |
| 788 } | |
| 789 g_snprintf(snd, sizeof snd, "toc_init_done"); | |
| 790 sflap_send(gc, snd, -1, TYPE_DATA); | |
| 791 gaim_notify_info(gc, NULL, | |
| 792 _("TOC has come back from its pause. You may " | |
| 793 "now send messages again."), NULL); | |
| 794 } | |
| 795 } else if (!g_ascii_strcasecmp(c, "CONFIG")) { | |
| 796 c = strtok(NULL, ":"); | |
| 797 parse_toc_buddy_list(account, c); | |
| 798 } else if (!g_ascii_strcasecmp(c, "NICK")) { | |
| 799 /* ignore NICK so that things get imported/exported properly | |
| 800 c = strtok(NULL, ":"); | |
| 801 g_snprintf(gc->username, sizeof(gc->username), "%s", c); | |
| 802 */ | |
| 803 } else if (!g_ascii_strcasecmp(c, "IM_IN")) { | |
| 804 char *away, *message; | |
| 805 int a = 0; | |
| 806 | |
| 807 c = strtok(NULL, ":"); | |
| 808 away = strtok(NULL, ":"); | |
| 809 | |
| 810 message = away; | |
| 811 while (*message && (*message != ':')) | |
| 812 message++; | |
| 813 message++; | |
| 814 | |
| 815 a = (away && (*away == 'T')) ? GAIM_MESSAGE_AUTO_RESP : 0; | |
| 816 | |
| 817 serv_got_im(gc, c, message, a, time(NULL)); | |
| 818 } else if (!g_ascii_strcasecmp(c, "UPDATE_BUDDY")) { | |
| 819 char *l, *uc, *tmp; | |
| 820 gboolean logged_in; | |
| 821 int evil, idle, type = 0; | |
| 822 time_t signon, time_idle; | |
| 823 | |
| 824 c = strtok(NULL, ":"); /* name */ | |
| 825 l = strtok(NULL, ":"); /* online */ | |
| 826 sscanf(strtok(NULL, ":"), "%d", &evil); | |
| 827 sscanf(strtok(NULL, ":"), "%ld", &signon); | |
| 828 sscanf(strtok(NULL, ":"), "%d", &idle); | |
| 829 uc = strtok(NULL, ":"); | |
| 830 | |
| 831 logged_in = (l && (*l == 'T')) ? TRUE : FALSE; | |
| 832 | |
| 833 if (uc[0] == 'A') | |
| 834 type |= UC_AOL; | |
| 835 switch (uc[1]) { | |
| 836 case 'A': | |
| 837 type |= UC_ADMIN; | |
| 838 break; | |
| 839 case 'U': | |
| 840 type |= UC_UNCONFIRMED; | |
| 841 break; | |
| 842 case 'O': | |
| 843 type |= UC_NORMAL; | |
| 844 break; | |
| 845 case 'C': | |
| 846 type |= UC_WIRELESS; | |
| 847 break; | |
| 848 default: | |
| 849 break; | |
| 850 } | |
| 851 if (uc[2] == 'U') | |
| 852 type |= UC_UNAVAILABLE; | |
| 853 | |
| 854 if (idle) { | |
| 855 time(&time_idle); | |
| 856 time_idle -= idle * 60; | |
| 857 } else | |
| 858 time_idle = 0; | |
| 859 | |
| 860 /* | |
| 861 * If we have info for ourselves then set our display name, warning | |
| 862 * level and official time of login. | |
| 863 */ | |
| 864 tmp = g_strdup(gaim_normalize(account, gaim_account_get_username(gc->account))); | |
| 865 if (!strcmp(tmp, gaim_normalize(account, c))) { | |
| 866 gaim_connection_set_display_name(gc, c); | |
| 867 /* XXX - What should the second parameter be here? */ | |
| 868 /* gaim_prpl_got_account_warning_level(account, NULL, evil);*/ | |
| 869 gaim_prpl_got_account_login_time(account, signon); | |
| 870 } | |
| 871 g_free(tmp); | |
| 872 | |
| 873 gaim_prpl_got_user_status(account, c, (logged_in ? "online" : "offline"), NULL); | |
| 874 gaim_prpl_got_user_login_time(account, c, signon); | |
| 875 if (time_idle > 0) | |
| 876 gaim_prpl_got_user_idle(account, c, TRUE, time_idle); | |
| 877 else | |
| 878 gaim_prpl_got_user_idle(account, c, FALSE, 0); | |
| 879 } else if (!g_ascii_strcasecmp(c, "ERROR")) { | |
| 880 gaim_notify_error(gc, NULL, show_error_message(), NULL); | |
| 881 } else if (!g_ascii_strcasecmp(c, "EVILED")) { | |
| 882 int lev; | |
| 883 char *name; | |
| 884 | |
| 885 sscanf(strtok(NULL, ":"), "%d", &lev); | |
| 886 name = strtok(NULL, ":"); | |
| 887 | |
| 888 /* gaim_prpl_got_account_warning_level(account, name, lev); */ | |
| 889 } else if (!g_ascii_strcasecmp(c, "CHAT_JOIN")) { | |
| 890 char *name; | |
| 891 int id; | |
| 892 | |
| 893 sscanf(strtok(NULL, ":"), "%d", &id); | |
| 894 name = strtok(NULL, ":"); | |
| 895 | |
| 896 serv_got_joined_chat(gc, id, name); | |
| 897 } else if (!g_ascii_strcasecmp(c, "CHAT_IN")) { | |
| 898 int id; | |
| 899 GaimMessageFlags flags; | |
| 900 char *m, *who, *whisper; | |
| 901 | |
| 902 sscanf(strtok(NULL, ":"), "%d", &id); | |
| 903 who = strtok(NULL, ":"); | |
| 904 whisper = strtok(NULL, ":"); | |
| 905 m = whisper; | |
| 906 while (*m && (*m != ':')) | |
| 907 m++; | |
| 908 m++; | |
| 909 | |
| 910 flags = (whisper && (*whisper == 'T')) ? GAIM_MESSAGE_WHISPER : 0; | |
| 911 | |
| 912 serv_got_chat_in(gc, id, who, flags, m, time((time_t)NULL)); | |
| 913 } else if (!g_ascii_strcasecmp(c, "CHAT_UPDATE_BUDDY")) { | |
| 914 int id; | |
| 915 char *in, *buddy; | |
| 916 GSList *bcs = gc->buddy_chats; | |
| 917 GaimConversation *b = NULL; | |
| 918 GaimConvChat *chat; | |
| 919 | |
| 920 sscanf(strtok(NULL, ":"), "%d", &id); | |
| 921 in = strtok(NULL, ":"); | |
| 922 | |
| 923 chat = GAIM_CONV_CHAT(b); | |
| 924 | |
| 925 while (bcs) { | |
| 926 b = (GaimConversation *)bcs->data; | |
| 927 if (id == gaim_conv_chat_get_id(chat)) | |
| 928 break; | |
| 929 bcs = bcs->next; | |
| 930 b = NULL; | |
| 931 } | |
| 932 | |
| 933 if (!b) | |
| 934 return; | |
| 935 | |
| 936 if (in && (*in == 'T')) | |
| 937 while ((buddy = strtok(NULL, ":")) != NULL) | |
| 938 gaim_conv_chat_add_user(chat, buddy, NULL, GAIM_CBFLAGS_NONE, TRUE); | |
| 939 else | |
| 940 while ((buddy = strtok(NULL, ":")) != NULL) | |
| 941 gaim_conv_chat_remove_user(chat, buddy, NULL); | |
| 942 } else if (!g_ascii_strcasecmp(c, "CHAT_INVITE")) { | |
| 943 char *name, *who, *message; | |
| 944 int id; | |
| 945 GHashTable *components = g_hash_table_new_full(g_str_hash, g_str_equal, | |
| 946 g_free, g_free); | |
| 947 | |
| 948 name = strtok(NULL, ":"); | |
| 949 sscanf(strtok(NULL, ":"), "%d", &id); | |
| 950 who = strtok(NULL, ":"); | |
| 951 message = strtok(NULL, ":"); | |
| 952 | |
| 953 g_hash_table_replace(components, g_strdup("id"), g_strdup_printf("%d", id)); | |
| 954 | |
| 955 serv_got_chat_invite(gc, name, who, message, components); | |
| 956 } else if (!g_ascii_strcasecmp(c, "CHAT_LEFT")) { | |
| 957 GSList *bcs = gc->buddy_chats; | |
| 958 GaimConversation *b = NULL; | |
| 959 int id; | |
| 960 | |
| 961 sscanf(strtok(NULL, ":"), "%d", &id); | |
| 962 | |
| 963 while (bcs) { | |
| 964 b = (GaimConversation *)bcs->data; | |
| 965 if (id == gaim_conv_chat_get_id(GAIM_CONV_CHAT(b))) | |
| 966 break; | |
| 967 b = NULL; | |
| 968 bcs = bcs->next; | |
| 969 } | |
| 970 | |
| 971 if (!b) | |
| 972 return; | |
| 973 | |
| 974 if (b->window) { | |
| 975 char error_buf[BUF_LONG]; | |
| 976 gaim_conversation_set_account(b, NULL); | |
| 977 g_snprintf(error_buf, sizeof error_buf, _("You have been disconnected" | |
| 978 " from chat room %s."), b->name); | |
| 979 gaim_notify_error(gc, NULL, error_buf, NULL); | |
| 980 } else | |
| 981 serv_got_chat_left(gc, id); | |
| 982 } else if (!g_ascii_strcasecmp(c, "GOTO_URL")) { | |
| 983 char *name, *url, tmp[256]; | |
| 984 | |
| 985 name = strtok(NULL, ":"); | |
| 986 url = strtok(NULL, ":"); | |
| 987 | |
| 988 g_snprintf(tmp, sizeof(tmp), "http://%s:%d/%s", tdt->toc_ip, | |
| 989 gaim_account_get_int(gc->account, "port", TOC_PORT), | |
| 990 url); | |
| 991 gaim_url_fetch(tmp, FALSE, NULL, FALSE, toc_got_info, gc); | |
| 992 } else if (!g_ascii_strcasecmp(c, "DIR_STATUS")) { | |
| 993 } else if (!g_ascii_strcasecmp(c, "ADMIN_NICK_STATUS")) { | |
| 994 } else if (!g_ascii_strcasecmp(c, "ADMIN_PASSWD_STATUS")) { | |
| 995 gaim_notify_info(gc, NULL, _("Password Change Successful"), NULL); | |
| 996 } else if (!g_ascii_strcasecmp(c, "PAUSE")) { | |
| 997 tdt->state = STATE_PAUSE; | |
| 998 gaim_notify_warning(gc, NULL, | |
| 999 _("TOC has sent a PAUSE command."), | |
| 1000 _("When this happens, TOC ignores any messages " | |
| 1001 "sent to it, and may kick you off if you send a" | |
| 1002 " message. Gaim will prevent anything from " | |
| 1003 "going through. This is only temporary, please " | |
| 1004 "be patient.")); | |
| 1005 } else if (!g_ascii_strcasecmp(c, "RVOUS_PROPOSE")) { | |
| 1006 #if 0 | |
| 1007 char *user, *uuid, *cookie; | |
| 1008 int seq; | |
| 1009 char *rip, *pip, *vip, *trillian = NULL; | |
| 1010 int port; | |
| 1011 | |
| 1012 user = strtok(NULL, ":"); | |
| 1013 uuid = strtok(NULL, ":"); | |
| 1014 cookie = strtok(NULL, ":"); | |
| 1015 sscanf(strtok(NULL, ":"), "%d", &seq); | |
| 1016 rip = strtok(NULL, ":"); | |
| 1017 pip = strtok(NULL, ":"); | |
| 1018 vip = strtok(NULL, ":"); | |
| 1019 sscanf(strtok(NULL, ":"), "%d", &port); | |
| 1020 | |
| 1021 if (!strcmp(uuid, FILE_SEND_UID)) { | |
| 1022 /* they want us to get a file */ | |
| 1023 int unk[4], i; | |
| 1024 char *messages[4], *tmp, *name; | |
| 1025 int subtype, files, totalsize = 0; | |
| 1026 struct ft_request *ft; | |
| 1027 | |
| 1028 for (i = 0; i < 4; i++) { | |
| 1029 trillian = strtok(NULL, ":"); | |
| 1030 sscanf(trillian, "%d", &unk[i]); | |
| 1031 if (unk[i] == 10001) | |
| 1032 break; | |
| 1033 /* Trillian likes to send an empty token as a message, rather than | |
| 1034 no message at all. */ | |
| 1035 if (*(trillian + strlen(trillian) +1) != ':') | |
| 1036 frombase64(strtok(NULL, ":"), &messages[i], NULL); | |
| 1037 } | |
| 1038 | |
| 1039 frombase64(strtok(NULL, ":"), &tmp, NULL); | |
| 1040 | |
| 1041 subtype = tmp[1]; | |
| 1042 files = tmp[3]; | |
| 1043 | |
| 1044 totalsize |= (tmp[4] << 24) & 0xff000000; | |
| 1045 totalsize |= (tmp[5] << 16) & 0x00ff0000; | |
| 1046 totalsize |= (tmp[6] << 8) & 0x0000ff00; | |
| 1047 totalsize |= (tmp[7] << 0) & 0x000000ff; | |
| 1048 | |
| 1049 if (!totalsize) { | |
| 1050 g_free(tmp); | |
| 1051 for (i--; i >= 0; i--) | |
| 1052 g_free(messages[i]); | |
| 1053 return; | |
| 1054 } | |
| 1055 | |
| 1056 name = tmp + 8; | |
| 1057 | |
| 1058 ft = g_new0(struct ft_request, 1); | |
| 1059 ft->cookie = g_strdup(cookie); | |
| 1060 ft->ip = g_strdup(pip); | |
| 1061 ft->port = port; | |
| 1062 if (i) | |
| 1063 ft->message = g_strdup(messages[0]); | |
| 1064 else | |
| 1065 ft->message = NULL; | |
| 1066 ft->filename = g_strdup(name); | |
| 1067 ft->user = g_strdup(user); | |
| 1068 ft->size = totalsize; | |
| 1069 ft->files = files; | |
| 1070 g_snprintf(ft->UID, sizeof(ft->UID), "%s", FILE_SEND_UID); | |
| 1071 ft->gc = gc; | |
| 1072 | |
| 1073 g_free(tmp); | |
| 1074 for (i--; i >= 0; i--) | |
| 1075 g_free(messages[i]); | |
| 1076 | |
| 1077 gaim_debug(GAIM_DEBUG_MISC, "toc", | |
| 1078 "English translation of RVOUS_PROPOSE: %s requests " | |
| 1079 "Send File (i.e. send a file to you); %s:%d " | |
| 1080 "(verified_ip:port), %d files at total size of " | |
| 1081 "%d bytes.\n", user, vip, port, files, totalsize); | |
| 1082 accept_file_dialog(ft); | |
| 1083 } else if (!strcmp(uuid, FILE_GET_UID)) { | |
| 1084 /* they want us to send a file */ | |
| 1085 int unk[4], i; | |
| 1086 char *messages[4], *tmp; | |
| 1087 struct ft_request *ft; | |
| 1088 | |
| 1089 for (i = 0; i < 4; i++) { | |
| 1090 sscanf(strtok(NULL, ":"), "%d", unk + i); | |
| 1091 if (unk[i] == 10001) | |
| 1092 break; | |
| 1093 /* Trillian likes to send an empty token as a message, rather than | |
| 1094 no message at all. */ | |
| 1095 if (*(trillian + strlen(trillian) +1) != ':') | |
| 1096 frombase64(strtok(NULL, ":"), &messages[i], NULL); | |
| 1097 } | |
| 1098 frombase64(strtok(NULL, ":"), &tmp, NULL); | |
| 1099 | |
| 1100 ft = g_new0(struct ft_request, 1); | |
| 1101 ft->cookie = g_strdup(cookie); | |
| 1102 ft->ip = g_strdup(pip); | |
| 1103 ft->port = port; | |
| 1104 if (i) | |
| 1105 ft->message = g_strdup(messages[0]); | |
| 1106 else | |
| 1107 ft->message = NULL; | |
| 1108 ft->user = g_strdup(user); | |
| 1109 g_snprintf(ft->UID, sizeof(ft->UID), "%s", FILE_GET_UID); | |
| 1110 ft->gc = gc; | |
| 1111 | |
| 1112 g_free(tmp); | |
| 1113 for (i--; i >= 0; i--) | |
| 1114 g_free(messages[i]); | |
| 1115 | |
| 1116 accept_file_dialog(ft); | |
| 1117 } else if (!strcmp(uuid, VOICE_UID)) { | |
| 1118 /* oh goody. voice over ip. fun stuff. */ | |
| 1119 } else if (!strcmp(uuid, B_ICON_UID)) { | |
| 1120 int unk[4], i; | |
| 1121 char *messages[4]; | |
| 1122 struct buddy_icon *icon; | |
| 1123 | |
| 1124 for (i = 0; i < 4; i++) { | |
| 1125 sscanf(strtok(NULL, ":"), "%d", unk + i); | |
| 1126 if (unk[i] == 10001) | |
| 1127 break; | |
| 1128 frombase64(strtok(NULL, ":"), &messages[i], NULL); | |
| 1129 } | |
| 1130 frombase64(strtok(NULL, ":"), (char **)&icon, NULL); | |
| 1131 | |
| 1132 gaim_debug(GAIM_DEBUG_MISC, "toc", | |
| 1133 "received icon of length %d\n", icon->len); | |
| 1134 g_free(icon); | |
| 1135 for (i--; i >= 0; i--) | |
| 1136 g_free(messages[i]); | |
| 1137 } else if (!strcmp(uuid, IMAGE_UID)) { | |
| 1138 /* aka Direct IM */ | |
| 1139 } else { | |
| 1140 gaim_debug(GAIM_DEBUG_ERROR, "toc", | |
| 1141 "Don't know what to do with RVOUS UUID %s\n", uuid); | |
| 1142 /* do we have to do anything here? i think it just times out */ | |
| 1143 } | |
| 1144 #endif | |
| 1145 } else { | |
| 1146 gaim_debug(GAIM_DEBUG_ERROR, "toc", | |
| 1147 "don't know what to do with %s\n", c); | |
| 1148 } | |
| 1149 } | |
| 1150 | |
| 1151 static int toc_send_im(GaimConnection *gc, const char *name, const char *message, GaimMessageFlags flags) | |
| 1152 { | |
| 1153 char *buf1, *buf2; | |
| 1154 | |
| 1155 #if 1 | |
| 1156 /* This is the old, non-i18n way */ | |
| 1157 buf1 = escape_text(message); | |
| 1158 if (strlen(buf1) + 52 > MSG_LEN) { | |
| 1159 g_free(buf1); | |
| 1160 return -E2BIG; | |
| 1161 } | |
| 1162 buf2 = g_strdup_printf("toc_send_im %s \"%s\"%s", gaim_normalize(gc->account, name), buf1, | |
| 1163 ((flags & GAIM_MESSAGE_AUTO_RESP) ? " auto" : "")); | |
| 1164 g_free(buf1); | |
| 1165 #else | |
| 1166 /* This doesn't work yet. See the comments below for details */ | |
| 1167 buf1 = gaim_strreplace(message, "\"", "\\\""); | |
| 1168 | |
| 1169 /* | |
| 1170 * We still need to determine what encoding should be used and send the | |
| 1171 * message in that encoding. This should be done the same as in | |
| 1172 * oscar_encoding_check() in oscar.c. There is no encoding flag sent | |
| 1173 * along with the message--the TOC to OSCAR proxy server must just | |
| 1174 * use a lil' algorithm to determine what the actual encoding is. | |
| 1175 * | |
| 1176 * After that, you need to convert buf1 to that encoding, and keep track | |
| 1177 * of the length of the resulting string. Then you need to make sure | |
| 1178 * that length is passed to sflap_send(). | |
| 1179 */ | |
| 1180 | |
| 1181 if (strlen(buf1) + 52 > MSG_LEN) { | |
| 1182 g_free(buf1); | |
| 1183 return -E2BIG; | |
| 1184 } | |
| 1185 | |
| 1186 buf2 = g_strdup_printf("toc2_send_im_enc %s F U en \"%s\" %s", gaim_normalize(gc->account, name), buf1, | |
| 1187 ((flags & GAIM_MESSAGE_AUTO_RESP) ? "auto" : "")); | |
| 1188 g_free(buf1); | |
| 1189 #endif | |
| 1190 | |
| 1191 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1192 g_free(buf2); | |
| 1193 | |
| 1194 return 1; | |
| 1195 } | |
| 1196 | |
| 1197 static void toc_set_config(GaimConnection *gc) | |
| 1198 { | |
| 1199 char *buf = g_malloc(MSG_LEN), snd[BUF_LEN * 2]; | |
| 1200 toc_build_config(gc->account, buf, MSG_LEN - strlen("toc_set_config \\{\\}"), FALSE); | |
| 1201 g_snprintf(snd, MSG_LEN, "toc_set_config {%s}", buf); | |
| 1202 sflap_send(gc, snd, -1, TYPE_DATA); | |
| 1203 g_free(buf); | |
| 1204 } | |
| 1205 | |
| 1206 static void toc_get_info(GaimConnection *gc, const char *name) | |
| 1207 { | |
| 1208 char buf[BUF_LEN * 2]; | |
| 1209 g_snprintf(buf, MSG_LEN, "toc_get_info %s", gaim_normalize(gc->account, name)); | |
| 1210 sflap_send(gc, buf, -1, TYPE_DATA); | |
| 1211 } | |
| 1212 | |
| 1213 /* Should be implemented as an Account Action? */ | |
| 1214 static void toc_get_dir(GaimBlistNode *node, gpointer data) | |
| 1215 { | |
| 1216 GaimBuddy *buddy; | |
| 1217 GaimConnection *gc; | |
| 1218 char buf[BUF_LEN * 2]; | |
| 1219 | |
| 1220 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 1221 | |
| 1222 buddy = (GaimBuddy *) node; | |
| 1223 gc = gaim_account_get_connection(buddy->account); | |
| 1224 | |
| 1225 g_snprintf(buf, MSG_LEN, "toc_get_dir %s", | |
| 1226 gaim_normalize(buddy->account, buddy->name)); | |
| 1227 sflap_send(gc, buf, -1, TYPE_DATA); | |
| 1228 } | |
| 1229 | |
| 1230 #if 0 | |
| 1231 /* Should be implemented as an Account Action */ | |
| 1232 static void toc_set_dir(GaimConnection *g, const char *first, const char *middle, const char *last, | |
| 1233 const char *maiden, const char *city, const char *state, const char *country, int web) | |
| 1234 { | |
| 1235 char *buf3, buf2[BUF_LEN * 4], buf[BUF_LEN]; | |
| 1236 g_snprintf(buf2, sizeof(buf2), "%s:%s:%s:%s:%s:%s:%s:%s", first, | |
| 1237 middle, last, maiden, city, state, country, (web == 1) ? "Y" : ""); | |
| 1238 buf3 = escape_text(buf2); | |
| 1239 g_snprintf(buf, sizeof(buf), "toc_set_dir %s", buf3); | |
| 1240 g_free(buf3); | |
| 1241 sflap_send(g, buf, -1, TYPE_DATA); | |
| 1242 } | |
| 1243 #endif | |
| 1244 | |
| 1245 #if 0 | |
| 1246 /* Should be implemented as an Account Action */ | |
| 1247 static void toc_dir_search(GaimConnection *g, const char *first, const char *middle, const char *last, | |
| 1248 const char *maiden, const char *city, const char *state, const char *country, const char *email) | |
| 1249 { | |
| 1250 char buf[BUF_LONG]; | |
| 1251 g_snprintf(buf, sizeof(buf) / 2, "toc_dir_search %s:%s:%s:%s:%s:%s:%s:%s", first, middle, | |
| 1252 last, maiden, city, state, country, email); | |
| 1253 gaim_debug(GAIM_DEBUG_INFO, "toc", | |
| 1254 "Searching for: %s,%s,%s,%s,%s,%s,%s\n", | |
| 1255 first, middle, last, maiden, | |
| 1256 city, state, country); | |
| 1257 sflap_send(g, buf, -1, TYPE_DATA); | |
| 1258 } | |
| 1259 #endif | |
| 1260 | |
| 1261 static void toc_set_status(GaimAccount *account, GaimStatus *status) | |
| 1262 { | |
| 1263 #if 0 /* do we care about TOC any more? */ | |
| 1264 char buf[BUF_LEN * 2]; | |
| 1265 if (gc->away) { | |
| 1266 g_free(gc->away); | |
| 1267 gc->away = NULL; | |
| 1268 } | |
| 1269 if (message) { | |
| 1270 char *tmp; | |
| 1271 gc->away = g_strdup(message); | |
| 1272 tmp = escape_text(message); | |
| 1273 g_snprintf(buf, MSG_LEN, "toc_set_away \"%s\"", tmp); | |
| 1274 g_free(tmp); | |
| 1275 } else | |
| 1276 g_snprintf(buf, MSG_LEN, "toc_set_away \"\""); | |
| 1277 sflap_send(g, buf, -1, TYPE_DATA); | |
| 1278 #endif | |
| 1279 } | |
| 1280 | |
| 1281 static void toc_set_info(GaimConnection *g, const char *info) | |
| 1282 { | |
| 1283 char buf[BUF_LEN * 2], *buf2; | |
| 1284 buf2 = escape_text(info); | |
| 1285 g_snprintf(buf, sizeof(buf), "toc_set_info \"%s\n\"", buf2); | |
| 1286 g_free(buf2); | |
| 1287 sflap_send(g, buf, -1, TYPE_DATA); | |
| 1288 } | |
| 1289 | |
| 1290 static void toc_change_passwd(GaimConnection *g, const char *orig, const char *new) | |
| 1291 { | |
| 1292 char buf[BUF_LEN * 2]; | |
| 1293 g_snprintf(buf, BUF_LONG, "toc_change_passwd %s %s", orig, new); | |
| 1294 sflap_send(g, buf, -1, TYPE_DATA); | |
| 1295 } | |
| 1296 | |
| 1297 static void | |
| 1298 toc_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) | |
| 1299 { | |
| 1300 char buf[BUF_LEN * 2]; | |
| 1301 g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", gaim_normalize(gc->account, buddy->name)); | |
| 1302 sflap_send(gc, buf, -1, TYPE_DATA); | |
| 1303 toc_set_config(gc); | |
| 1304 } | |
| 1305 | |
| 1306 static void toc_add_buddies(GaimConnection *gc, GList *buddies, GList *groups) | |
| 1307 { | |
| 1308 char buf[BUF_LEN * 2]; | |
| 1309 int n; | |
| 1310 GList *cur; | |
| 1311 | |
| 1312 n = g_snprintf(buf, sizeof(buf), "toc_add_buddy"); | |
| 1313 for (cur = buddies; cur != NULL; cur = cur->next) { | |
| 1314 GaimBuddy *buddy = cur->data; | |
| 1315 | |
| 1316 if (strlen(gaim_normalize(gc->account, buddy->name)) + n + 32 > MSG_LEN) { | |
| 1317 sflap_send(gc, buf, -1, TYPE_DATA); | |
| 1318 n = g_snprintf(buf, sizeof(buf), "toc_add_buddy"); | |
| 1319 } | |
| 1320 n += g_snprintf(buf + n, sizeof(buf) - n, " %s", gaim_normalize(gc->account, buddy->name)); | |
| 1321 } | |
| 1322 sflap_send(gc, buf, -1, TYPE_DATA); | |
| 1323 } | |
| 1324 | |
| 1325 static void toc_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) | |
| 1326 { | |
| 1327 char buf[BUF_LEN * 2]; | |
| 1328 g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", gaim_normalize(gc->account, buddy->name)); | |
| 1329 sflap_send(gc, buf, -1, TYPE_DATA); | |
| 1330 toc_set_config(gc); | |
| 1331 } | |
| 1332 | |
| 1333 static void toc_remove_buddies(GaimConnection *gc, GList *buddies, GList *groups) | |
| 1334 { | |
| 1335 char buf[BUF_LEN * 2]; | |
| 1336 int n; | |
| 1337 GList *cur; | |
| 1338 | |
| 1339 n = g_snprintf(buf, sizeof(buf), "toc_remove_buddy"); | |
| 1340 for (cur = buddies; cur != NULL; cur = cur->next) { | |
| 1341 GaimBuddy *buddy = cur->data; | |
| 1342 | |
| 1343 if (strlen(gaim_normalize(gc->account, buddy->name)) + n + 32 > MSG_LEN) { | |
| 1344 sflap_send(gc, buf, -1, TYPE_DATA); | |
| 1345 n = g_snprintf(buf, sizeof(buf), "toc_remove_buddy"); | |
| 1346 } | |
| 1347 n += g_snprintf(buf + n, sizeof(buf) - n, " %s", gaim_normalize(gc->account, buddy->name)); | |
| 1348 } | |
| 1349 sflap_send(gc, buf, -1, TYPE_DATA); | |
| 1350 toc_set_config(gc); | |
| 1351 } | |
| 1352 | |
| 1353 static void toc_set_idle(GaimConnection *g, int time) | |
| 1354 { | |
| 1355 char buf[BUF_LEN * 2]; | |
| 1356 g_snprintf(buf, sizeof(buf), "toc_set_idle %d", time); | |
| 1357 sflap_send(g, buf, -1, TYPE_DATA); | |
| 1358 } | |
| 1359 | |
| 1360 static void toc_warn(GaimConnection *g, const char *name, int anon) | |
| 1361 { | |
| 1362 char send[BUF_LEN * 2]; | |
| 1363 g_snprintf(send, 255, "toc_evil %s %s", name, ((anon) ? "anon" : "norm")); | |
| 1364 sflap_send(g, send, -1, TYPE_DATA); | |
| 1365 } | |
| 1366 | |
| 1367 static GList *toc_chat_info(GaimConnection *gc) | |
| 1368 { | |
| 1369 GList *m = NULL; | |
| 1370 struct proto_chat_entry *pce; | |
| 1371 | |
| 1372 pce = g_new0(struct proto_chat_entry, 1); | |
| 1373 pce->label = _("_Group:"); | |
| 1374 pce->identifier = "room"; | |
| 1375 m = g_list_append(m, pce); | |
| 1376 | |
| 1377 pce = g_new0(struct proto_chat_entry, 1); | |
| 1378 pce->label = _("_Exchange:"); | |
| 1379 pce->identifier = "exchange"; | |
| 1380 pce->is_int = TRUE; | |
| 1381 pce->min = 4; | |
| 1382 pce->max = 20; | |
| 1383 m = g_list_append(m, pce); | |
| 1384 | |
| 1385 return m; | |
| 1386 } | |
| 1387 | |
| 1388 GHashTable *toc_chat_info_defaults(GaimConnection *gc, const char *chat_name) | |
| 1389 { | |
| 1390 GHashTable *defaults; | |
| 1391 | |
| 1392 defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); | |
| 1393 | |
| 1394 if (chat_name != NULL) | |
| 1395 g_hash_table_insert(defaults, "room", g_strdup(chat_name)); | |
| 1396 | |
| 1397 return defaults; | |
| 1398 } | |
| 1399 | |
| 1400 static void toc_join_chat(GaimConnection *g, GHashTable *data) | |
| 1401 { | |
| 1402 char buf[BUF_LONG]; | |
| 1403 char *name, *exchange; | |
| 1404 char *id; | |
| 1405 | |
| 1406 name = g_hash_table_lookup(data, "room"); | |
| 1407 exchange = g_hash_table_lookup(data, "exchange"); | |
| 1408 id = g_hash_table_lookup(data, "id"); | |
| 1409 | |
| 1410 if (id) { | |
| 1411 g_snprintf(buf, 255, "toc_chat_accept %d", atoi(id)); | |
| 1412 } else { | |
| 1413 g_snprintf(buf, sizeof(buf) / 2, "toc_chat_join %d \"%s\"", atoi(exchange), name); | |
| 1414 } | |
| 1415 | |
| 1416 sflap_send(g, buf, -1, TYPE_DATA); | |
| 1417 } | |
| 1418 | |
| 1419 static void toc_chat_invite(GaimConnection *gc, int id, const char *message, const char *name) | |
| 1420 { | |
| 1421 char buf[BUF_LONG]; | |
| 1422 g_snprintf(buf, sizeof(buf) / 2, "toc_chat_invite %d \"%s\" %s", id, | |
| 1423 message ? message : "", gaim_normalize(gc->account, name)); | |
| 1424 sflap_send(gc, buf, -1, TYPE_DATA); | |
| 1425 } | |
| 1426 | |
| 1427 static void toc_chat_leave(GaimConnection *g, int id) | |
| 1428 { | |
| 1429 GSList *bcs = g->buddy_chats; | |
| 1430 GaimConversation *b = NULL; | |
| 1431 char buf[BUF_LEN * 2]; | |
| 1432 | |
| 1433 while (bcs) { | |
| 1434 b = (GaimConversation *)bcs->data; | |
| 1435 if (id == gaim_conv_chat_get_id(GAIM_CONV_CHAT(b))) | |
| 1436 break; | |
| 1437 b = NULL; | |
| 1438 bcs = bcs->next; | |
| 1439 } | |
| 1440 | |
| 1441 if (!b) | |
| 1442 return; /* can this happen? */ | |
| 1443 | |
| 1444 if (gaim_conversation_get_account(b) == NULL) { | |
| 1445 /* TOC already kicked us out of this room */ | |
| 1446 serv_got_chat_left(g, id); | |
| 1447 } | |
| 1448 else { | |
| 1449 g_snprintf(buf, 255, "toc_chat_leave %d", id); | |
| 1450 sflap_send(g, buf, -1, TYPE_DATA); | |
| 1451 } | |
| 1452 } | |
| 1453 | |
| 1454 static void toc_chat_whisper(GaimConnection *gc, int id, const char *who, const char *message) | |
| 1455 { | |
| 1456 char *buf1, *buf2; | |
| 1457 buf1 = escape_text(message); | |
| 1458 buf2 = g_strdup_printf("toc_chat_whisper %d %s \"%s\"", id, gaim_normalize(gc->account, who), buf1); | |
| 1459 g_free(buf1); | |
| 1460 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1461 g_free(buf2); | |
| 1462 } | |
| 1463 | |
| 1464 static int toc_chat_send(GaimConnection *g, int id, const char *message, GaimMessageFlags flags) | |
| 1465 { | |
| 1466 char *buf1, *buf2; | |
| 1467 buf1 = escape_text(message); | |
| 1468 if (strlen(buf1) > 2000) { | |
| 1469 g_free(buf1); | |
| 1470 return -E2BIG; | |
| 1471 } | |
| 1472 buf2 = g_strdup_printf("toc_chat_send %d \"%s\"", id, buf1); | |
| 1473 g_free(buf1); | |
| 1474 sflap_send(g, buf2, -1, TYPE_DATA); | |
| 1475 g_free(buf2); | |
| 1476 return 0; | |
| 1477 } | |
| 1478 | |
| 1479 static void toc_keepalive(GaimConnection *gc) | |
| 1480 { | |
| 1481 sflap_send(gc, "", 0, TYPE_KEEPALIVE); | |
| 1482 } | |
| 1483 | |
| 1484 static const char * | |
| 1485 toc_normalize(const GaimAccount *account, const char *str) | |
| 1486 { | |
| 1487 static char buf[BUF_LEN]; | |
| 1488 char *tmp1, *tmp2; | |
| 1489 int i, j; | |
| 1490 | |
| 1491 g_return_val_if_fail(str != NULL, NULL); | |
| 1492 | |
| 1493 strncpy(buf, str, BUF_LEN); | |
| 1494 for (i=0, j=0; buf[j]; i++, j++) | |
| 1495 { | |
| 1496 while (buf[j] == ' ') | |
| 1497 j++; | |
| 1498 buf[i] = buf[j]; | |
| 1499 } | |
| 1500 buf[i] = '\0'; | |
| 1501 | |
| 1502 tmp1 = g_utf8_strdown(buf, -1); | |
| 1503 tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT); | |
| 1504 g_snprintf(buf, sizeof(buf), "%s", tmp2); | |
| 1505 g_free(tmp2); | |
| 1506 g_free(tmp1); | |
| 1507 | |
| 1508 return buf; | |
| 1509 } | |
| 1510 | |
| 1511 static const char *toc_list_icon(GaimAccount *a, GaimBuddy *b) | |
| 1512 { | |
| 1513 if (!b || (b && b->name && b->name[0] == '+')) { | |
| 1514 if (a != NULL && isdigit(*gaim_account_get_username(a))) | |
| 1515 return "icq"; | |
| 1516 else | |
| 1517 return "aim"; | |
| 1518 } | |
| 1519 | |
| 1520 if (b && b->name && isdigit(b->name[0])) | |
| 1521 return "icq"; | |
| 1522 return "aim"; | |
| 1523 } | |
| 1524 | |
| 1525 static void toc_list_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne) | |
| 1526 { | |
| 1527 char *emblems[4] = {NULL,NULL,NULL,NULL}; | |
| 1528 int i = 0; | |
| 1529 | |
| 1530 if (!GAIM_BUDDY_IS_ONLINE(b)) { | |
| 1531 *se = "offline"; | |
| 1532 return; | |
| 1533 } else { | |
| 1534 if (b->uc & UC_UNAVAILABLE) | |
| 1535 emblems[i++] = "away"; | |
| 1536 if (b->uc & UC_AOL) | |
| 1537 emblems[i++] = "aol"; | |
| 1538 if (b->uc & UC_ADMIN) | |
| 1539 emblems[i++] = "admin"; | |
| 1540 if (b->uc & UC_WIRELESS) | |
| 1541 emblems[i++] = "wireless"; | |
| 1542 } | |
| 1543 *se = emblems[0]; | |
| 1544 *sw = emblems[1]; | |
| 1545 *nw = emblems[2]; | |
| 1546 *ne = emblems[3]; | |
| 1547 } | |
| 1548 | |
| 1549 static GList *toc_blist_node_menu(GaimBlistNode *node) | |
| 1550 { | |
| 1551 GList *m = NULL; | |
| 1552 GaimMenuAction *act; | |
| 1553 | |
| 1554 if(GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
| 1555 act = gaim_menu_action_new(_("Get Dir Info"), | |
| 1556 toc_get_dir, NULL, NULL); | |
| 1557 m = g_list_append(m, act); | |
| 1558 } | |
| 1559 | |
| 1560 return m; | |
| 1561 } | |
| 1562 | |
| 1563 static void toc_add_permit(GaimConnection *gc, const char *who) | |
| 1564 { | |
| 1565 char buf2[BUF_LEN * 2]; | |
| 1566 if (gc->account->perm_deny != 3) | |
| 1567 return; | |
| 1568 g_snprintf(buf2, sizeof(buf2), "toc_add_permit %s", gaim_normalize(gc->account, who)); | |
| 1569 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1570 toc_set_config(gc); | |
| 1571 } | |
| 1572 | |
| 1573 static void toc_add_deny(GaimConnection *gc, const char *who) | |
| 1574 { | |
| 1575 char buf2[BUF_LEN * 2]; | |
| 1576 if (gc->account->perm_deny != 4) | |
| 1577 return; | |
| 1578 g_snprintf(buf2, sizeof(buf2), "toc_add_deny %s", gaim_normalize(gc->account, who)); | |
| 1579 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1580 toc_set_config(gc); | |
| 1581 } | |
| 1582 | |
| 1583 static void toc_set_permit_deny(GaimConnection *gc) | |
| 1584 { | |
| 1585 char buf2[BUF_LEN * 2]; | |
| 1586 GSList *list; | |
| 1587 int at; | |
| 1588 | |
| 1589 switch (gc->account->perm_deny) { | |
| 1590 case 1: | |
| 1591 /* permit all, deny none. to get here reliably we need to have been in permit | |
| 1592 * mode, and send an empty toc_add_deny message, which will switch us to deny none */ | |
| 1593 g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); | |
| 1594 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1595 g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); | |
| 1596 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1597 break; | |
| 1598 case 2: | |
| 1599 /* deny all, permit none. to get here reliably we need to have been in deny | |
| 1600 * mode, and send an empty toc_add_permit message, which will switch us to permit none */ | |
| 1601 g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); | |
| 1602 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1603 g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); | |
| 1604 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1605 break; | |
| 1606 case 3: | |
| 1607 /* permit some. we want to switch to deny mode first, then send the toc_add_permit | |
| 1608 * message, which will clear and set our permit list. toc sucks. */ | |
| 1609 g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); | |
| 1610 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1611 | |
| 1612 at = g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); | |
| 1613 list = gc->account->permit; | |
| 1614 while (list) { | |
| 1615 at += g_snprintf(buf2 + at, sizeof(buf2) - at, "%s ", gaim_normalize(gc->account, list->data)); | |
| 1616 if (at > MSG_LEN + 32) { /* from out my ass comes greatness */ | |
| 1617 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1618 at = g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); | |
| 1619 } | |
| 1620 list = list->next; | |
| 1621 } | |
| 1622 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1623 break; | |
| 1624 case 4: | |
| 1625 /* deny some. we want to switch to permit mode first, then send the toc_add_deny | |
| 1626 * message, which will clear and set our deny list. toc sucks. */ | |
| 1627 g_snprintf(buf2, sizeof(buf2), "toc_add_permit "); | |
| 1628 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1629 | |
| 1630 at = g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); | |
| 1631 list = gc->account->deny; | |
| 1632 while (list) { | |
| 1633 at += g_snprintf(buf2 + at, sizeof(buf2) - at, "%s ", gaim_normalize(gc->account, list->data)); | |
| 1634 if (at > MSG_LEN + 32) { /* from out my ass comes greatness */ | |
| 1635 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1636 at = g_snprintf(buf2, sizeof(buf2), "toc_add_deny "); | |
| 1637 } | |
| 1638 list = list->next; | |
| 1639 } | |
| 1640 sflap_send(gc, buf2, -1, TYPE_DATA); | |
| 1641 break; | |
| 1642 default: | |
| 1643 break; | |
| 1644 } | |
| 1645 toc_set_config(gc); | |
| 1646 } | |
| 1647 | |
| 1648 static void toc_rem_permit(GaimConnection *gc, const char *who) | |
| 1649 { | |
| 1650 if (gc->account->perm_deny != 3) | |
| 1651 return; | |
| 1652 toc_set_permit_deny(gc); | |
| 1653 } | |
| 1654 | |
| 1655 static void toc_rem_deny(GaimConnection *gc, const char *who) | |
| 1656 { | |
| 1657 if (gc->account->perm_deny != 4) | |
| 1658 return; | |
| 1659 toc_set_permit_deny(gc); | |
| 1660 } | |
| 1661 | |
| 1662 static GList *toc_away_states(GaimAccount *account) | |
| 1663 { | |
| 1664 #if 0 /* do we care about TOC any more? */ | |
| 1665 return g_list_append(NULL, GAIM_AWAY_CUSTOM); | |
| 1666 #else | |
| 1667 return NULL; | |
| 1668 #endif | |
| 1669 } | |
| 1670 | |
| 1671 static void | |
| 1672 show_set_info(GaimPluginAction *action) | |
| 1673 { | |
| 1674 GaimConnection *gc = (GaimConnection *) action->context; | |
| 1675 gaim_account_request_change_user_info(gaim_connection_get_account(gc)); | |
| 1676 } | |
| 1677 | |
| 1678 static void | |
| 1679 change_pass(GaimPluginAction *action) | |
| 1680 { | |
| 1681 GaimConnection *gc = (GaimConnection *) action->context; | |
| 1682 gaim_account_request_change_password(gaim_connection_get_account(gc)); | |
| 1683 } | |
| 1684 | |
| 1685 static GList *toc_actions(GaimPlugin *plugin, gpointer context) | |
| 1686 { | |
| 1687 GList *m = NULL; | |
| 1688 GaimPluginAction *act; | |
| 1689 | |
| 1690 act = gaim_plugin_action_new(_("Set User Info"), | |
| 1691 show_set_info); | |
| 1692 m = g_list_append(m, act); | |
| 1693 | |
| 1694 #if 0 | |
| 1695 act = gaim_plugin_action_new(_("Set Dir Info"), | |
| 1696 show_set_dir); | |
| 1697 m = g_list_append(m, act); | |
| 1698 #endif | |
| 1699 | |
| 1700 act = gaim_plugin_action_new(_("Change Password"), | |
| 1701 change_pass); | |
| 1702 m = g_list_append(m, act); | |
| 1703 | |
| 1704 return m; | |
| 1705 } | |
| 1706 | |
| 1707 #if 0 | |
| 1708 /********* | |
| 1709 * RVOUS ACTIONS | |
| 1710 ********/ | |
| 1711 | |
| 1712 struct file_header { | |
| 1713 char magic[4]; /* 0 */ | |
| 1714 short hdrlen; /* 4 */ | |
| 1715 short hdrtype; /* 6 */ | |
| 1716 char bcookie[8]; /* 8 */ | |
| 1717 short encrypt; /* 16 */ | |
| 1718 short compress; /* 18 */ | |
| 1719 short totfiles; /* 20 */ | |
| 1720 short filesleft; /* 22 */ | |
| 1721 short totparts; /* 24 */ | |
| 1722 short partsleft; /* 26 */ | |
| 1723 long totsize; /* 28 */ | |
| 1724 long size; /* 32 */ | |
| 1725 long modtime; /* 36 */ | |
| 1726 long checksum; /* 40 */ | |
| 1727 long rfrcsum; /* 44 */ | |
| 1728 long rfsize; /* 48 */ | |
| 1729 long cretime; /* 52 */ | |
| 1730 long rfcsum; /* 56 */ | |
| 1731 long nrecvd; /* 60 */ | |
| 1732 long recvcsum; /* 64 */ | |
| 1733 char idstring[32]; /* 68 */ | |
| 1734 char flags; /* 100 */ | |
| 1735 char lnameoffset; /* 101 */ | |
| 1736 char lsizeoffset; /* 102 */ | |
| 1737 char dummy[69]; /* 103 */ | |
| 1738 char macfileinfo[16]; /* 172 */ | |
| 1739 short nencode; /* 188 */ | |
| 1740 short nlanguage; /* 190 */ | |
| 1741 char name[64]; /* 192 */ | |
| 1742 /* 256 */ | |
| 1743 }; | |
| 1744 | |
| 1745 struct file_transfer { | |
| 1746 struct file_header hdr; | |
| 1747 | |
| 1748 GaimConnection *gc; | |
| 1749 | |
| 1750 char *user; | |
| 1751 char *cookie; | |
| 1752 char *ip; | |
| 1753 int port; | |
| 1754 long size; | |
| 1755 struct stat st; | |
| 1756 | |
| 1757 GtkWidget *window; | |
| 1758 int files; | |
| 1759 char *filename; | |
| 1760 FILE *file; | |
| 1761 int recvsize; | |
| 1762 | |
| 1763 gint inpa; | |
| 1764 }; | |
| 1765 | |
| 1766 static void debug_header(struct file_transfer *ft) { | |
| 1767 struct file_header *f = (struct file_header *)ft; | |
| 1768 gaim_debug(GAIM_DEBUG_MISC, "toc", "FT HEADER:\n" | |
| 1769 "\t%s %d 0x%04x\n" | |
| 1770 "\t%s %d %d\n" | |
| 1771 "\t%d %d %d %d %d %d\n" | |
| 1772 "\t%d %d %d %d %d %d %d %d\n" | |
| 1773 "\t%s\n" | |
| 1774 "\t0x%02x, 0x%02x, 0x%02x\n" | |
| 1775 "\t%s %s\n" | |
| 1776 "\t%d %d\n" | |
| 1777 "\t%s\n", | |
| 1778 f->magic, ntohs(f->hdrlen), f->hdrtype, | |
| 1779 f->bcookie, ntohs(f->encrypt), ntohs(f->compress), | |
| 1780 ntohs(f->totfiles), ntohs(f->filesleft), ntohs(f->totparts), | |
| 1781 ntohs(f->partsleft), ntohl(f->totsize), ntohl(f->size), | |
| 1782 ntohl(f->modtime), ntohl(f->checksum), ntohl(f->rfrcsum), ntohl(f->rfsize), | |
| 1783 ntohl(f->cretime), ntohl(f->rfcsum), ntohl(f->nrecvd), | |
| 1784 ntohl(f->recvcsum), | |
| 1785 f->idstring, | |
| 1786 f->flags, f->lnameoffset, f->lsizeoffset, | |
| 1787 f->dummy, f->macfileinfo, | |
| 1788 ntohs(f->nencode), ntohs(f->nlanguage), | |
| 1789 f->name); | |
| 1790 } | |
| 1791 | |
| 1792 static void toc_send_file_callback(gpointer data, gint source, GaimInputCondition cond) | |
| 1793 { | |
| 1794 char buf[BUF_LONG]; | |
| 1795 int rt, i; | |
| 1796 | |
| 1797 struct file_transfer *ft = data; | |
| 1798 | |
| 1799 if (ft->hdr.hdrtype != 0x202) { | |
| 1800 char *buf; | |
| 1801 frombase64(ft->cookie, &buf, NULL); | |
| 1802 | |
| 1803 read(source, ft, 8); | |
| 1804 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); | |
| 1805 debug_header(ft); | |
| 1806 | |
| 1807 ft->hdr.hdrtype = 0x202; | |
| 1808 memcpy(ft->hdr.bcookie, buf, 8); | |
| 1809 g_free(buf); | |
| 1810 ft->hdr.encrypt = 0; ft->hdr.compress = 0; | |
| 1811 debug_header(ft); | |
| 1812 write(source, ft, 256); | |
| 1813 | |
| 1814 if (ft->files == 1) { | |
| 1815 ft->file = g_fopen(ft->filename, "w"); | |
| 1816 if (!ft->file) { | |
| 1817 buf = g_strdup_printf(_("Could not open %s for writing!"), ft->filename); | |
| 1818 gaim_notify_error(ft->gc, NULL, buf, strerror(errno)); | |
| 1819 g_free(buf); | |
| 1820 gaim_input_remove(ft->inpa); | |
| 1821 close(source); | |
| 1822 g_free(ft->filename); | |
| 1823 g_free(ft->user); | |
| 1824 g_free(ft->ip); | |
| 1825 g_free(ft->cookie); | |
| 1826 g_free(ft); | |
| 1827 } | |
| 1828 } else { | |
| 1829 buf = g_strdup_printf("%s/%s", ft->filename, ft->hdr.name); | |
| 1830 ft->file = g_fopen(buf, "w"); | |
| 1831 g_free(buf); | |
| 1832 if (!ft->file) { | |
| 1833 buf = g_strdup_printf("Could not open %s/%s for writing!", ft->filename, | |
| 1834 ft->hdr.name); | |
| 1835 gaim_notify_error(ft->gc, NULL, buf, strerror(errno)); | |
| 1836 g_free(buf); | |
| 1837 gaim_input_remove(ft->inpa); | |
| 1838 close(source); | |
| 1839 g_free(ft->filename); | |
| 1840 g_free(ft->user); | |
| 1841 g_free(ft->ip); | |
| 1842 g_free(ft->cookie); | |
| 1843 g_free(ft); | |
| 1844 } | |
| 1845 } | |
| 1846 | |
| 1847 return; | |
| 1848 } | |
| 1849 | |
| 1850 rt = read(source, buf, MIN(ntohl(ft->hdr.size) - ft->recvsize, 1024)); | |
| 1851 if (rt < 0) { | |
| 1852 gaim_notify_error(ft->gc, NULL, | |
| 1853 _("File transfer failed; other side probably " | |
| 1854 "canceled."), NULL); | |
| 1855 gaim_input_remove(ft->inpa); | |
| 1856 close(source); | |
| 1857 g_free(ft->user); | |
| 1858 g_free(ft->ip); | |
| 1859 g_free(ft->cookie); | |
| 1860 if (ft->file) | |
| 1861 fclose(ft->file); | |
| 1862 g_free(ft); | |
| 1863 return; | |
| 1864 } | |
| 1865 ft->recvsize += rt; | |
| 1866 for (i = 0; i < rt; i++) | |
| 1867 fprintf(ft->file, "%c", buf[i]); | |
| 1868 | |
| 1869 if (ft->recvsize == ntohl(ft->hdr.size)) { | |
| 1870 ft->hdr.hdrtype = htons(0x0204); | |
| 1871 ft->hdr.filesleft = htons(ntohs(ft->hdr.filesleft) - 1); | |
| 1872 ft->hdr.partsleft = htons(ntohs(ft->hdr.partsleft) - 1); | |
| 1873 ft->hdr.recvcsum = ft->hdr.checksum; /* uh... */ | |
| 1874 ft->hdr.nrecvd = htons(ntohs(ft->hdr.nrecvd) + 1); | |
| 1875 ft->hdr.flags = 0; | |
| 1876 write(source, ft, 256); | |
| 1877 debug_header(ft); | |
| 1878 ft->recvsize = 0; | |
| 1879 fclose(ft->file); | |
| 1880 if (ft->hdr.filesleft == 0) { | |
| 1881 gaim_input_remove(ft->inpa); | |
| 1882 close(source); | |
| 1883 g_free(ft->filename); | |
| 1884 g_free(ft->user); | |
| 1885 g_free(ft->ip); | |
| 1886 g_free(ft->cookie); | |
| 1887 g_free(ft); | |
| 1888 } | |
| 1889 } | |
| 1890 } | |
| 1891 | |
| 1892 static void toc_send_file_connect(gpointer data, gint src, GaimInputCondition cond) | |
| 1893 { | |
| 1894 struct file_transfer *ft = data; | |
| 1895 | |
| 1896 if (src == -1) { | |
| 1897 gaim_notify_error(ft->gc, NULL, | |
| 1898 _("Could not connect for transfer."), NULL); | |
| 1899 g_free(ft->filename); | |
| 1900 g_free(ft->cookie); | |
| 1901 g_free(ft->user); | |
| 1902 g_free(ft->ip); | |
| 1903 g_free(ft); | |
| 1904 return; | |
| 1905 } | |
| 1906 | |
| 1907 ft->inpa = gaim_input_add(src, GAIM_INPUT_READ, toc_send_file_callback, ft); | |
| 1908 } | |
| 1909 | |
| 1910 static void toc_send_file(gpointer a, struct file_transfer *old_ft) | |
| 1911 { | |
| 1912 struct file_transfer *ft; | |
| 1913 const char *dirname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(old_ft->window)); | |
| 1914 GaimAccount *account; | |
| 1915 char buf[BUF_LEN * 2]; | |
| 1916 | |
| 1917 if (gaim_gtk_check_if_dir(dirname, GTK_FILE_SELECTION(old_ft->window))) | |
| 1918 return; | |
| 1919 ft = g_new0(struct file_transfer, 1); | |
| 1920 if (old_ft->files == 1) | |
| 1921 ft->filename = g_strdup(dirname); | |
| 1922 else | |
| 1923 ft->filename = g_path_get_dirname(dirname); | |
| 1924 ft->cookie = g_strdup(old_ft->cookie); | |
| 1925 ft->user = g_strdup(old_ft->user); | |
| 1926 ft->ip = g_strdup(old_ft->ip); | |
| 1927 ft->files = old_ft->files; | |
| 1928 ft->port = old_ft->port; | |
| 1929 ft->gc = old_ft->gc; | |
| 1930 account = ft->gc->account; | |
| 1931 gtk_widget_destroy(old_ft->window); | |
| 1932 | |
| 1933 g_snprintf(buf, sizeof(buf), "toc_rvous_accept %s %s %s", ft->user, ft->cookie, FILE_SEND_UID); | |
| 1934 sflap_send(ft->gc, buf, -1, TYPE_DATA); | |
| 1935 | |
| 14837 | 1936 if (gaim_proxy_connect(ft->gc, account, ft->ip, ft->port, toc_send_file_connect, ft) != 0) { |
| 14192 | 1937 gaim_notify_error(ft->gc, NULL, |
| 1938 _("Could not connect for transfer."), NULL); | |
| 1939 g_free(ft->filename); | |
| 1940 g_free(ft->cookie); | |
| 1941 g_free(ft->user); | |
| 1942 g_free(ft->ip); | |
| 1943 g_free(ft); | |
| 1944 return; | |
| 1945 } | |
| 1946 } | |
| 1947 | |
| 1948 static void toc_get_file_callback(gpointer data, gint source, GaimInputCondition cond) | |
| 1949 { | |
| 1950 char buf[BUF_LONG]; | |
| 1951 | |
| 1952 struct file_transfer *ft = data; | |
| 1953 | |
| 1954 if (cond & GAIM_INPUT_WRITE) { | |
| 1955 int remain = MIN(ntohl(ft->hdr.totsize) - ft->recvsize, 1024); | |
| 1956 int i; | |
| 1957 for (i = 0; i < remain; i++) | |
| 1958 fscanf(ft->file, "%c", &buf[i]); | |
| 1959 write(source, buf, remain); | |
| 1960 ft->recvsize += remain; | |
| 1961 if (ft->recvsize == ntohl(ft->hdr.totsize)) { | |
| 1962 gaim_input_remove(ft->inpa); | |
| 1963 ft->inpa = gaim_input_add(source, GAIM_INPUT_READ, | |
| 1964 toc_get_file_callback, ft); | |
| 1965 } | |
| 1966 return; | |
| 1967 } | |
| 1968 | |
| 1969 if (ft->hdr.hdrtype == htons(0x1108)) { | |
| 1970 struct tm *fortime; | |
| 1971 struct stat st; | |
| 1972 char *basename; | |
| 1973 | |
| 1974 read(source, ft, 8); | |
| 1975 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); | |
| 1976 debug_header(ft); | |
| 1977 | |
| 1978 g_stat(ft->filename, &st); | |
| 1979 fortime = localtime(&st.st_mtime); | |
| 1980 basename = g_path_get_basename(ft->filename); | |
| 1981 g_snprintf(buf, sizeof(buf), "%2d/%2d/%4d %2d:%2d %8ld %s\r\n", | |
| 1982 fortime->tm_mon + 1, fortime->tm_mday, fortime->tm_year + 1900, | |
| 1983 fortime->tm_hour + 1, fortime->tm_min + 1, (long)st.st_size, | |
| 1984 basename); | |
| 1985 write(source, buf, ntohl(ft->hdr.size)); | |
| 1986 g_free(basename); | |
| 1987 return; | |
| 1988 } | |
| 1989 | |
| 1990 if (ft->hdr.hdrtype == htons(0x1209)) { | |
| 1991 read(source, ft, 8); | |
| 1992 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); | |
| 1993 debug_header(ft); | |
| 1994 return; | |
| 1995 } | |
| 1996 | |
| 1997 if (ft->hdr.hdrtype == htons(0x120b)) { | |
| 1998 read(source, ft, 8); | |
| 1999 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); | |
| 2000 debug_header(ft); | |
| 2001 | |
| 2002 if (ft->hdr.hdrtype != htons(0x120c)) { | |
| 2003 g_snprintf(buf, sizeof(buf), "%s decided to cancel the transfer", ft->user); | |
| 2004 gaim_notify_error(ft->gc, NULL, buf, NULL); | |
| 2005 gaim_input_remove(ft->inpa); | |
| 2006 close(source); | |
| 2007 g_free(ft->filename); | |
| 2008 g_free(ft->user); | |
| 2009 g_free(ft->ip); | |
| 2010 g_free(ft->cookie); | |
| 2011 if (ft->file) | |
| 2012 fclose(ft->file); | |
| 2013 g_free(ft); | |
| 2014 return; | |
| 2015 } | |
| 2016 | |
| 2017 ft->hdr.hdrtype = 0x0101; | |
| 2018 ft->hdr.totfiles = htons(1); ft->hdr.filesleft = htons(1); | |
| 2019 ft->hdr.flags = 0x20; | |
| 2020 write(source, ft, 256); | |
| 2021 return; | |
| 2022 } | |
| 2023 | |
| 2024 if (ft->hdr.hdrtype == 0x0101) { | |
| 2025 read(source, ft, 8); | |
| 2026 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); | |
| 2027 debug_header(ft); | |
| 2028 | |
| 2029 gaim_input_remove(ft->inpa); | |
| 2030 ft->inpa = gaim_input_add(source, GAIM_INPUT_WRITE, | |
| 2031 toc_get_file_callback, ft); | |
| 2032 return; | |
| 2033 } | |
| 2034 | |
| 2035 if (ft->hdr.hdrtype == 0x0202) { | |
| 2036 read(source, ft, 8); | |
| 2037 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8)); | |
| 2038 debug_header(ft); | |
| 2039 | |
| 2040 gaim_input_remove(ft->inpa); | |
| 2041 close(source); | |
| 2042 g_free(ft->filename); | |
| 2043 g_free(ft->user); | |
| 2044 g_free(ft->ip); | |
| 2045 g_free(ft->cookie); | |
| 2046 if (ft->file) | |
| 2047 fclose(ft->file); | |
| 2048 g_free(ft); | |
| 2049 return; | |
| 2050 } | |
| 2051 } | |
| 2052 | |
| 2053 static void toc_get_file_connect(gpointer data, gint src, GaimInputCondition cond) | |
| 2054 { | |
| 2055 struct file_transfer *ft = data; | |
| 2056 struct file_header *hdr; | |
| 2057 char *buf; | |
| 2058 char *basename; | |
| 2059 | |
| 2060 if (src == -1) { | |
| 2061 gaim_notify_error(ft->gc, NULL, | |
| 2062 _("Could not connect for transfer."), NULL); | |
| 2063 fclose(ft->file); | |
| 2064 g_free(ft->filename); | |
| 2065 g_free(ft->cookie); | |
| 2066 g_free(ft->user); | |
| 2067 g_free(ft->ip); | |
| 2068 g_free(ft); | |
| 2069 return; | |
| 2070 } | |
| 2071 | |
| 2072 hdr = (struct file_header *)ft; | |
| 2073 hdr->magic[0] = 'O'; hdr->magic[1] = 'F'; hdr->magic[2] = 'T'; hdr->magic[3] = '2'; | |
| 2074 hdr->hdrlen = htons(256); | |
| 2075 hdr->hdrtype = htons(0x1108); | |
| 14542 | 2076 rombase64(ft->cookie, &buf, NULL); |
| 14192 | 2077 g_snprintf(hdr->bcookie, 8, "%s", buf); |
| 2078 g_free(buf); | |
| 2079 hdr->totfiles = htons(1); hdr->filesleft = htons(1); | |
| 2080 hdr->totparts = htons(1); hdr->partsleft = htons(1); | |
| 2081 hdr->totsize = htonl((long)ft->st.st_size); /* combined size of all files */ | |
| 2082 /* size = strlen("mm/dd/yyyy hh:mm sizesize 'name'\r\n") */ | |
| 2083 basename = g_path_get_basename(ft->filename); | |
| 2084 hdr->size = htonl(28 + strlen(basename)); /* size of listing.txt */ | |
| 2085 g_free(basename); | |
| 2086 hdr->modtime = htonl(ft->st.st_mtime); | |
| 2087 hdr->checksum = htonl(0x89f70000); /* uh... */ | |
| 2088 g_snprintf(hdr->idstring, 32, "OFT_Windows ICBMFT V1.1 32"); | |
| 2089 hdr->flags = 0x02; | |
| 2090 hdr->lnameoffset = 0x1A; | |
| 2091 hdr->lsizeoffset = 0x10; | |
| 2092 g_snprintf(hdr->name, 64, "listing.txt"); | |
| 2093 if (write(src, hdr, 256) < 0) { | |
| 2094 gaim_notify_error(ft->gc, NULL, | |
| 2095 _("Could not write file header. The file will " | |
| 2096 "not be transferred."), NULL); | |
| 2097 fclose(ft->file); | |
| 2098 g_free(ft->filename); | |
| 2099 g_free(ft->cookie); | |
| 2100 g_free(ft->user); | |
| 2101 g_free(ft->ip); | |
| 2102 g_free(ft); | |
| 2103 return; | |
| 2104 } | |
| 2105 | |
| 2106 ft->inpa = gaim_input_add(src, GAIM_INPUT_READ, toc_get_file_callback, ft); | |
| 2107 } | |
| 2108 | |
| 2109 static void toc_get_file(gpointer a, struct file_transfer *old_ft) | |
| 2110 { | |
| 2111 struct file_transfer *ft; | |
| 2112 const char *dirname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(old_ft->window)); | |
| 2113 GaimAccount *account; | |
| 2114 char *buf, buf2[BUF_LEN * 2]; | |
| 2115 | |
| 2116 if (gaim_gtk_check_if_dir(dirname, GTK_FILE_SELECTION(old_ft->window))) | |
| 2117 return; | |
| 2118 ft = g_new0(struct file_transfer, 1); | |
| 2119 ft->filename = g_strdup(dirname); | |
| 2120 ft->file = g_fopen(ft->filename, "r"); | |
| 2121 if (!ft->file) { | |
| 2122 buf = g_strdup_printf("Unable to open %s for transfer.", ft->filename); | |
| 2123 gaim_notify_error(ft->gc, NULL, buf, NULL); | |
| 2124 g_free(buf); | |
| 2125 g_free(ft->filename); | |
| 2126 g_free(ft); | |
| 2127 return; | |
| 2128 } | |
| 2129 if (g_stat(dirname, &ft->st)) { | |
| 2130 buf = g_strdup_printf("Unable to examine %s.", dirname); | |
| 2131 gaim_notify_error(ft->gc, NULL, buf, NULL); | |
| 2132 g_free(buf); | |
| 2133 g_free(ft->filename); | |
| 2134 g_free(ft); | |
| 2135 return; | |
| 2136 } | |
| 2137 ft->cookie = g_strdup(old_ft->cookie); | |
| 2138 ft->user = g_strdup(old_ft->user); | |
| 2139 ft->ip = g_strdup(old_ft->ip); | |
| 2140 ft->port = old_ft->port; | |
| 2141 ft->gc = old_ft->gc; | |
| 2142 account = ft->gc->account; | |
| 2143 gtk_widget_destroy(old_ft->window); | |
| 2144 | |
| 2145 g_snprintf(buf2, sizeof(buf2), "toc_rvous_accept %s %s %s", ft->user, ft->cookie, FILE_GET_UID); | |
| 2146 sflap_send(ft->gc, buf2, -1, TYPE_DATA); | |
| 2147 | |
| 14837 | 2148 if (gaim_proxy_connect(ft->gc, account, ft->ip, ft->port, toc_get_file_connect, ft) < 0) { |
| 14192 | 2149 gaim_notify_error(ft->gc, NULL, |
| 2150 _("Could not connect for transfer."), NULL); | |
| 2151 fclose(ft->file); | |
| 2152 g_free(ft->filename); | |
| 2153 g_free(ft->cookie); | |
| 2154 g_free(ft->user); | |
| 2155 g_free(ft->ip); | |
| 2156 g_free(ft); | |
| 2157 return; | |
| 2158 } | |
| 2159 } | |
| 2160 | |
| 2161 static void cancel_callback(gpointer a, struct file_transfer *ft) { | |
| 2162 gtk_widget_destroy(ft->window); | |
| 2163 if (a == ft->window) { | |
| 2164 g_free(ft->cookie); | |
| 2165 g_free(ft->user); | |
| 2166 g_free(ft->ip); | |
| 2167 g_free(ft); | |
| 2168 } | |
| 2169 } | |
| 2170 | |
| 2171 static void toc_reject_ft(struct ft_request *ft) { | |
| 2172 g_free(ft->user); | |
| 2173 g_free(ft->filename); | |
| 2174 g_free(ft->ip); | |
| 2175 g_free(ft->cookie); | |
| 2176 if (ft->message) | |
| 2177 g_free(ft->message); | |
| 2178 g_free(ft); | |
| 2179 } | |
| 2180 | |
| 2181 | |
| 2182 static void toc_accept_ft(struct ft_request *fr) { | |
| 2183 if(g_list_find(gaim_connections_get_all(), fr->gc)) { | |
| 2184 GtkWidget *window; | |
| 2185 char buf[BUF_LEN]; | |
| 2186 | |
| 2187 struct file_transfer *ft = g_new0(struct file_transfer, 1); | |
| 2188 ft->gc = fr->gc; | |
| 2189 ft->user = g_strdup(fr->user); | |
| 2190 ft->cookie = g_strdup(fr->cookie); | |
| 2191 ft->ip = g_strdup(fr->ip); | |
| 2192 ft->port = fr->port; | |
| 2193 ft->files = fr->files; | |
| 2194 | |
| 2195 ft->window = window = gtk_file_selection_new(_("Gaim - Save As...")); | |
| 2196 g_snprintf(buf, sizeof(buf), "%s/%s", gaim_home_dir(), fr->filename ? fr->filename : ""); | |
| 2197 gtk_file_selection_set_filename(GTK_FILE_SELECTION(window), buf); | |
| 2198 g_signal_connect(G_OBJECT(window), "destroy", | |
| 2199 G_CALLBACK(cancel_callback), ft); | |
| 2200 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(ft->window)->cancel_button), | |
| 2201 "clicked", G_CALLBACK(cancel_callback), ft); | |
| 2202 | |
| 2203 if (!strcmp(fr->UID, FILE_SEND_UID)) | |
| 2204 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(window)->ok_button), | |
| 2205 "clicked", G_CALLBACK(toc_send_file), ft); | |
| 2206 else | |
| 2207 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(window)->ok_button), | |
| 2208 "clicked", G_CALLBACK(toc_get_file), ft); | |
| 2209 | |
| 2210 gtk_widget_show(window); | |
| 2211 } | |
| 2212 | |
| 2213 toc_reject_ft(fr); | |
| 2214 } | |
| 2215 | |
| 2216 static void accept_file_dialog(struct ft_request *ft) { | |
| 2217 char buf[BUF_LONG]; | |
| 2218 if (!strcmp(ft->UID, FILE_SEND_UID)) { | |
| 2219 /* holy crap. who the fuck would transfer gigabytes through AIM?! */ | |
| 2220 static char *sizes[4] = { "bytes", "KB", "MB", "GB" }; | |
| 2221 float size = ft->size; | |
| 2222 int index = 0; | |
| 2223 while ((index < 4) && (size > 1024)) { | |
| 2224 size /= 1024; | |
| 2225 index++; | |
| 2226 } | |
| 2227 g_snprintf(buf, sizeof(buf), | |
| 2228 ngettext( | |
| 2229 "%s requests %s to accept %d file: %s (%.2f %s)%s%s", | |
| 2230 "%s requests %s to accept %d files: %s (%.2f %s)%s%s", | |
| 2231 ft->files), | |
| 2232 ft->user, gaim_account_get_username(ft->gc->account), ft->files, | |
| 2233 ft->filename, size, sizes[index], (ft->message) ? "\n" : "", | |
| 2234 (ft->message) ? ft->message : ""); | |
| 2235 } else { | |
| 2236 g_snprintf(buf, sizeof(buf), _("%s requests you to send them a file"), ft->user); | |
| 2237 } | |
| 2238 | |
| 2239 gaim_request_accept_cancel(ft->gc, NULL, buf, NULL, | |
| 2240 GAIM_DEFAULT_ACTION_NONE, ft, | |
| 2241 G_CALLBACK(toc_accept_ft), | |
| 2242 G_CALLBACK(toc_reject_ft)); | |
| 2243 } | |
| 2244 #endif | |
| 2245 | |
| 2246 static GaimPluginProtocolInfo prpl_info = | |
| 2247 { | |
| 2248 0, | |
| 2249 NULL, /* user_splits */ | |
| 2250 NULL, /* protocol_options */ | |
| 2251 NO_BUDDY_ICONS, /* icon_spec */ | |
| 2252 toc_list_icon, /* list_icon */ | |
| 2253 toc_list_emblems, /* list_emblems */ | |
| 2254 NULL, /* status_text */ | |
| 2255 NULL, /* tooltip_text */ | |
| 2256 toc_away_states, /* away_states */ | |
| 2257 toc_blist_node_menu, /* blist_node_menu */ | |
| 2258 toc_chat_info, /* chat_info */ | |
| 2259 toc_chat_info_defaults, /* chat_info_defaults */ | |
| 2260 toc_login, /* login */ | |
| 2261 toc_close, /* close */ | |
| 2262 toc_send_im, /* send_im */ | |
| 2263 toc_set_info, /* set_info */ | |
| 2264 NULL, /* send_typing */ | |
| 2265 toc_get_info, /* get_info */ | |
| 2266 toc_set_status, /* set_away */ | |
| 2267 toc_set_idle, /* set_idle */ | |
| 2268 toc_change_passwd, /* change_passwd */ | |
| 2269 toc_add_buddy, /* add_buddy */ | |
| 2270 toc_add_buddies, /* add_buddies */ | |
| 2271 toc_remove_buddy, /* remove_buddy */ | |
| 2272 toc_remove_buddies, /* remove_buddies */ | |
| 2273 toc_add_permit, /* add_permit */ | |
| 2274 toc_add_deny, /* add_deny */ | |
| 2275 toc_rem_permit, /* rem_permit */ | |
| 2276 toc_rem_deny, /* rem_deny */ | |
| 2277 toc_set_permit_deny, /* set_permit_deny */ | |
| 2278 toc_join_chat, /* join_chat */ | |
| 2279 NULL, /* reject_chat */ | |
| 2280 NULL, /* get_chat_name */ | |
| 2281 toc_chat_invite, /* chat_invite */ | |
| 2282 toc_chat_leave, /* chat_leave */ | |
| 2283 toc_chat_whisper, /* chat_whisper */ | |
| 2284 toc_chat_send, /* chat_send */ | |
| 2285 toc_keepalive, /* keepalive */ | |
| 2286 NULL, /* register_user */ | |
| 2287 NULL, /* get_cb_info */ | |
| 2288 NULL, /* get_cb_away */ | |
| 2289 NULL, /* alias_buddy */ | |
| 2290 NULL, /* group_buddy */ | |
| 2291 NULL, /* rename_group */ | |
| 2292 NULL, /* buddy_free */ | |
| 2293 NULL, /* convo_closed */ | |
| 2294 toc_normalize, /* normalize */ | |
| 2295 NULL, /* set_buddy_icon */ | |
| 2296 NULL, /* remove_group */ | |
| 2297 NULL, /* get_cb_real_name */ | |
| 2298 NULL, /* set_chat_topic */ | |
| 2299 NULL, /* find_blist_chat */ | |
| 2300 NULL, /* roomlist_get_list */ | |
| 2301 NULL, /* roomlist_cancel */ | |
| 2302 NULL, /* roomlist_expand_category */ | |
| 2303 NULL, /* can_receive_file */ | |
| 2304 NULL, /* send_file */ | |
| 2305 NULL, /* new_xfer */ | |
| 2306 NULL, /* offline_message */ | |
| 2307 NULL, /* whiteboard_prpl_ops */ | |
| 14542 | 2308 toc_send_raw, /* send_raw */ |
| 14192 | 2309 }; |
| 2310 | |
| 2311 static GaimPluginInfo info = | |
| 2312 { | |
| 2313 GAIM_PLUGIN_MAGIC, | |
| 2314 GAIM_MAJOR_VERSION, | |
| 2315 GAIM_MINOR_VERSION, | |
| 2316 GAIM_PLUGIN_PROTOCOL, /**< type */ | |
| 2317 NULL, /**< ui_requirement */ | |
| 2318 0, /**< flags */ | |
| 2319 NULL, /**< dependencies */ | |
| 2320 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
| 2321 | |
| 2322 "prpl-toc", /**< id */ | |
| 2323 "TOC", /**< name */ | |
| 2324 VERSION, /**< version */ | |
| 2325 /** summary */ | |
| 2326 N_("TOC Protocol Plugin"), | |
| 2327 /** description */ | |
| 2328 N_("TOC Protocol Plugin"), | |
| 2329 NULL, /**< author */ | |
| 2330 GAIM_WEBSITE, /**< homepage */ | |
| 2331 | |
| 2332 NULL, /**< load */ | |
| 2333 NULL, /**< unload */ | |
| 2334 NULL, /**< destroy */ | |
| 2335 | |
| 2336 NULL, /**< ui_info */ | |
| 2337 &prpl_info, /**< extra_info */ | |
| 2338 NULL, | |
| 2339 toc_actions | |
| 2340 }; | |
| 2341 | |
| 2342 static void | |
| 2343 init_plugin(GaimPlugin *plugin) | |
| 2344 { | |
| 2345 GaimAccountOption *option; | |
| 2346 | |
| 2347 option = gaim_account_option_string_new(_("Server"), "server", TOC_HOST); | |
| 2348 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
| 2349 option); | |
| 2350 | |
| 2351 option = gaim_account_option_int_new(_("Port"), "port", TOC_PORT); | |
| 2352 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
| 2353 option); | |
| 2354 | |
| 2355 my_protocol = plugin; | |
| 2356 } | |
| 2357 | |
| 2358 GAIM_INIT_PLUGIN(toc, init_plugin, info); |
