src/protocols/toc/toc.c

changeset 2086
007508451e2c
child 2090
bab8b7e309db
equal deleted inserted replaced
2085:4659ae7bc69c 2086:007508451e2c
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
22
23
24 #ifdef HAVE_CONFIG_H
25 #include "../config.h"
26 #endif
27 #include <netdb.h>
28 #include <gtk/gtk.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <time.h>
37 #include <sys/socket.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include "prpl.h"
41 #include "multi.h"
42 #include "gaim.h"
43 #include "proxy.h"
44
45 #include "pixmaps/admin_icon.xpm"
46 #include "pixmaps/aol_icon.xpm"
47 #include "pixmaps/away_icon.xpm"
48 #include "pixmaps/dt_icon.xpm"
49 #include "pixmaps/free_icon.xpm"
50
51 #define REVISION "penguin"
52
53 #define TYPE_SIGNON 1
54 #define TYPE_DATA 2
55 #define TYPE_ERROR 3
56 #define TYPE_SIGNOFF 4
57 #define TYPE_KEEPALIVE 5
58
59 #define FLAPON "FLAPON\r\n\r\n"
60 #define ROAST "Tic/Toc"
61
62 #define TOC_HOST "toc.oscar.aol.com"
63 #define TOC_PORT 9898
64 #define AUTH_HOST "login.oscar.aol.com"
65 #define AUTH_PORT 5190
66 #define LANGUAGE "english"
67
68 #define STATE_OFFLINE 0
69 #define STATE_FLAPON 1
70 #define STATE_SIGNON_REQUEST 2
71 #define STATE_ONLINE 3
72 #define STATE_PAUSE 4
73
74 #define VOICE_UID "09461341-4C7F-11D1-8222-444553540000"
75 #define FILE_SEND_UID "09461343-4C7F-11D1-8222-444553540000"
76 #define IMAGE_UID "09461345-4C7F-11D1-8222-444553540000"
77 #define B_ICON_UID "09461346-4C7F-11D1-8222-444553540000"
78 #define STOCKS_UID "09461347-4C7F-11D1-8222-444553540000"
79 #define FILE_GET_UID "09461348-4C7F-11D1-8222-444553540000"
80 #define GAMES_UID "0946134a-4C7F-11D1-8222-444553540000"
81
82 struct ft_request {
83 struct gaim_connection *gc;
84 char *user;
85 char UID[2048];
86 char *cookie;
87 char *ip;
88 int port;
89 char *message;
90 char *filename;
91 int files;
92 int size;
93 };
94
95 struct buddy_icon {
96 guint32 hash;
97 guint32 len;
98 time_t time;
99 void *data;
100 };
101
102 struct toc_data {
103 int toc_fd;
104 int seqno;
105 int state;
106 };
107
108 struct sflap_hdr {
109 unsigned char ast;
110 unsigned char type;
111 unsigned short seqno;
112 unsigned short len;
113 };
114
115 struct signon {
116 unsigned int ver;
117 unsigned short tag;
118 unsigned short namelen;
119 char username[80];
120 };
121
122 /* constants to identify proto_opts */
123 #define USEROPT_AUTH 0
124 #define USEROPT_AUTHPORT 1
125
126 static GtkWidget *join_chat_spin = NULL;
127 static GtkWidget *join_chat_entry = NULL;
128
129 static void toc_login_callback(gpointer, gint, GdkInputCondition);
130 static void toc_callback(gpointer, gint, GdkInputCondition);
131 static unsigned char *roast_password(char *);
132 static void accept_file_dialog(struct ft_request *);
133
134 /* ok. this function used to take username/password, and return 0 on success.
135 * now, it takes username/password, and returns NULL on error or a new gaim_connection
136 * on success. */
137 static void toc_login(struct aim_user *user)
138 {
139 struct gaim_connection *gc;
140 struct toc_data *tdt;
141 char buf[80];
142
143 gc = new_gaim_conn(user);
144 gc->proto_data = tdt = g_new0(struct toc_data, 1);
145
146 g_snprintf(buf, sizeof buf, "Looking up %s",
147 user->proto_opt[USEROPT_AUTH][0] ? user->proto_opt[USEROPT_AUTH] : TOC_HOST);
148 set_login_progress(gc, 1, buf);
149
150 debug_printf("* Client connects to TOC\n");
151 tdt->toc_fd =
152 proxy_connect(user->proto_opt[USEROPT_AUTH][0] ? user->proto_opt[USEROPT_AUTH] : TOC_HOST,
153 user->proto_opt[USEROPT_AUTHPORT][0] ?
154 atoi(user->proto_opt[USEROPT_AUTHPORT]) : TOC_PORT,
155 toc_login_callback, gc);
156
157 if (!user->gc || (tdt->toc_fd < 0)) {
158 g_snprintf(buf, sizeof(buf), "Connect to %s failed", user->proto_opt[USEROPT_AUTH]);
159 hide_login_progress(gc, buf);
160 signoff(gc);
161 return;
162 }
163 }
164
165 static void toc_login_callback(gpointer data, gint source, GdkInputCondition cond)
166 {
167 struct gaim_connection *gc = data;
168 struct toc_data *tdt;
169 char buf[80];
170
171 if (!g_slist_find(connections, data)) {
172 close(source);
173 return;
174 }
175
176 tdt = gc->proto_data;
177
178 if (source == -1) {
179 /* we didn't successfully connect. tdt->toc_fd is valid here */
180 hide_login_progress(gc, "Unable to connect.");
181 signoff(gc);
182 return;
183 }
184
185 if (tdt->toc_fd == 0)
186 tdt->toc_fd = source;
187
188 debug_printf("* Client sends \"FLAPON\\r\\n\\r\\n\"\n");
189 if (write(tdt->toc_fd, FLAPON, strlen(FLAPON)) < 0) {
190 hide_login_progress(gc, "Disconnected.");
191 signoff(gc);
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 = gdk_input_add(tdt->toc_fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_callback, gc);
200
201 g_snprintf(buf, sizeof(buf), "Signon: %s", gc->username);
202 set_login_progress(gc, 2, buf);
203 }
204
205 static void toc_close(struct gaim_connection *gc)
206 {
207 if (gc->inpa > 0)
208 gdk_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 int sflap_send(struct gaim_connection *gc, char *buf, int olen, int type)
215 {
216 int len;
217 int slen = 0;
218 struct sflap_hdr hdr;
219 char obuf[MSG_LEN];
220 struct toc_data *tdt = (struct toc_data *)gc->proto_data;
221
222 if (tdt->state == STATE_PAUSE)
223 /* TOC has given us the PAUSE message; sending could cause a disconnect
224 * so we just return here like everything went through fine */
225 return 0;
226
227 /* One _last_ 2048 check here! This shouldn't ever
228 * get hit though, hopefully. If it gets hit on an IM
229 * It'll lose the last " and the message won't go through,
230 * but this'll stop a segfault. */
231 if (strlen(buf) > (MSG_LEN - sizeof(hdr))) {
232 debug_printf("message too long, truncating\n");
233 buf[MSG_LEN - sizeof(hdr) - 3] = '"';
234 buf[MSG_LEN - sizeof(hdr) - 2] = '\0';
235 }
236
237 if (olen < 0)
238 len = escape_message(buf);
239 else
240 len = olen;
241 hdr.ast = '*';
242 hdr.type = type;
243 hdr.seqno = htons(tdt->seqno++ & 0xffff);
244 hdr.len = htons(len + (type == TYPE_SIGNON ? 0 : 1));
245
246 memcpy(obuf, &hdr, sizeof(hdr));
247 slen += sizeof(hdr);
248 memcpy(&obuf[slen], buf, len);
249 slen += len;
250 if (type != TYPE_SIGNON) {
251 obuf[slen] = '\0';
252 slen += 1;
253 }
254
255 return write(tdt->toc_fd, obuf, slen);
256 }
257
258 static int wait_reply(struct gaim_connection *gc, char *buffer, size_t buflen)
259 {
260 struct toc_data *tdt = (struct toc_data *)gc->proto_data;
261 struct sflap_hdr *hdr;
262 int ret;
263
264 if (read(tdt->toc_fd, buffer, sizeof(struct sflap_hdr)) < 0) {
265 debug_printf("error, couldn't read flap header\n");
266 return -1;
267 }
268
269 hdr = (struct sflap_hdr *)buffer;
270
271 if (buflen < ntohs(hdr->len)) {
272 /* fake like there's a read error */
273 debug_printf("buffer too small (have %d, need %d)\n", buflen, ntohs(hdr->len));
274 return -1;
275 }
276
277 if (ntohs(hdr->len) > 0) {
278 int count = 0;
279 ret = 0;
280 do {
281 count += ret;
282 ret = read(tdt->toc_fd,
283 buffer + sizeof(struct sflap_hdr) + count, ntohs(hdr->len) - count);
284 } while (count + ret < ntohs(hdr->len) && ret > 0);
285 buffer[sizeof(struct sflap_hdr) + count + ret] = '\0';
286 return ret;
287 } else
288 return 0;
289 }
290
291 static unsigned char *roast_password(char *pass)
292 {
293 /* Trivial "encryption" */
294 static unsigned char rp[256];
295 static char *roast = ROAST;
296 int pos = 2;
297 int x;
298 strcpy(rp, "0x");
299 for (x = 0; (x < 150) && pass[x]; x++)
300 pos += sprintf(&rp[pos], "%02x", pass[x] ^ roast[x % strlen(roast)]);
301 rp[pos] = '\0';
302 return rp;
303 }
304
305 static void toc_got_info(gpointer data, char *url_text)
306 {
307 if (!url_text)
308 return;
309
310 g_show_info_text(url_text);
311 }
312
313 static void toc_callback(gpointer data, gint source, GdkInputCondition condition)
314 {
315 struct gaim_connection *gc = (struct gaim_connection *)data;
316 struct toc_data *tdt = (struct toc_data *)gc->proto_data;
317 struct sflap_hdr *hdr;
318 struct signon so;
319 char buf[8 * 1024], *c;
320 char snd[BUF_LEN * 2];
321
322 if (condition & GDK_INPUT_EXCEPTION) {
323 debug_printf("gdk_input exception! check internet connection\n");
324 hide_login_progress(gc, _("Connection Closed"));
325 signoff(gc);
326 return;
327 }
328
329 /* there's data waiting to be read, so read it. */
330 if (wait_reply(gc, buf, 8 * 1024) <= 0) {
331 hide_login_progress(gc, _("Connection Closed"));
332 signoff(gc);
333 return;
334 }
335
336 if (tdt->state == STATE_FLAPON) {
337 hdr = (struct sflap_hdr *)buf;
338 if (hdr->type != TYPE_SIGNON)
339 debug_printf("problem, hdr->type != TYPE_SIGNON\n");
340 else
341 debug_printf("* TOC sends Client FLAP SIGNON\n");
342 tdt->seqno = ntohs(hdr->seqno);
343 tdt->state = STATE_SIGNON_REQUEST;
344
345 debug_printf("* Client sends TOC FLAP SIGNON\n");
346 g_snprintf(so.username, sizeof(so.username), "%s", gc->username);
347 so.ver = htonl(1);
348 so.tag = htons(1);
349 so.namelen = htons(strlen(so.username));
350 if (sflap_send(gc, (char *)&so, ntohs(so.namelen) + 8, TYPE_SIGNON) < 0) {
351 hide_login_progress(gc, _("Disconnected."));
352 signoff(gc);
353 return;
354 }
355
356 debug_printf("* Client sends TOC \"toc_signon\" message\n");
357 g_snprintf(snd, sizeof snd, "toc_signon %s %d %s %s %s \"%s\"",
358 AUTH_HOST, AUTH_PORT, normalize(gc->username),
359 roast_password(gc->password), LANGUAGE, REVISION);
360 if (sflap_send(gc, snd, -1, TYPE_DATA) < 0) {
361 hide_login_progress(gc, _("Disconnected."));
362 signoff(gc);
363 return;
364 }
365
366 set_login_progress(gc, 3, _("Waiting for reply..."));
367 return;
368 }
369
370 if (tdt->state == STATE_SIGNON_REQUEST) {
371 debug_printf("* TOC sends client SIGN_ON reply\n");
372 if (g_strncasecmp(buf + sizeof(struct sflap_hdr), "SIGN_ON", strlen("SIGN_ON"))) {
373 debug_printf("Didn't get SIGN_ON! buf was: %s\n",
374 buf + sizeof(struct sflap_hdr));
375 hide_login_progress(gc, _("Authentication Failed"));
376 signoff(gc);
377 return;
378 }
379 /* we're supposed to check that it's really TOC v1 here but we know it is ;) */
380 debug_printf("TOC version: %s\n", buf + sizeof(struct sflap_hdr) + 4);
381
382 /* we used to check for the CONFIG here, but we'll wait until we've sent our
383 * version of the config and then the toc_init_done message. we'll come back to
384 * the callback in a better state if we get CONFIG anyway */
385
386 tdt->state = STATE_ONLINE;
387
388 account_online(gc);
389 serv_finish_login(gc);
390
391 do_import(0, gc);
392
393 /* Client sends TOC toc_init_done message */
394 debug_printf("* Client sends TOC toc_init_done message\n");
395 g_snprintf(snd, sizeof snd, "toc_init_done");
396 sflap_send(gc, snd, -1, TYPE_DATA);
397
398 /*
399 g_snprintf(snd, sizeof snd, "toc_set_caps %s %s %s",
400 FILE_SEND_UID, FILE_GET_UID, B_ICON_UID);
401 */
402 g_snprintf(snd, sizeof snd, "toc_set_caps %s %s", FILE_SEND_UID, FILE_GET_UID);
403 sflap_send(gc, snd, -1, TYPE_DATA);
404
405 return;
406 }
407
408 debug_printf("From TOC server: %s\n", buf + sizeof(struct sflap_hdr));
409
410 c = strtok(buf + sizeof(struct sflap_hdr), ":"); /* Ditch the first part */
411
412 if (!g_strcasecmp(c, "SIGN_ON")) {
413 /* we should only get here after a PAUSE */
414 if (tdt->state != STATE_PAUSE)
415 debug_printf("got SIGN_ON but not PAUSE!\n");
416 else {
417 tdt->state = STATE_ONLINE;
418 g_snprintf(snd, sizeof snd, "toc_signon %s %d %s %s %s \"%s\"",
419 AUTH_HOST, AUTH_PORT, normalize(gc->username),
420 roast_password(gc->password), LANGUAGE, REVISION);
421 if (sflap_send(gc, snd, -1, TYPE_DATA) < 0) {
422 hide_login_progress(gc, _("Disconnected."));
423 signoff(gc);
424 return;
425 }
426 do_import(0, gc);
427 g_snprintf(snd, sizeof snd, "toc_init_done");
428 sflap_send(gc, snd, -1, TYPE_DATA);
429 do_error_dialog(_("TOC has come back from its pause. You may now send"
430 " messages again."), _("TOC Resume"));
431 }
432 } else if (!strcasecmp(c, "CONFIG")) {
433 c = strtok(NULL, ":");
434 parse_toc_buddy_list(gc, c, 0);
435 } else if (!strcasecmp(c, "NICK")) {
436 /* ignore NICK so that things get imported/exported properly
437 c = strtok(NULL, ":");
438 g_snprintf(gc->username, sizeof(gc->username), "%s", c);
439 */
440 } else if (!strcasecmp(c, "IM_IN")) {
441 char *away, *message;
442 int a = 0;
443
444 c = strtok(NULL, ":");
445 away = strtok(NULL, ":");
446
447 message = away;
448 while (*message && (*message != ':'))
449 message++;
450 message++;
451
452 a = (away && (*away == 'T')) ? 1 : 0;
453
454 serv_got_im(gc, c, message, a, time((time_t)NULL));
455 } else if (!strcasecmp(c, "UPDATE_BUDDY")) {
456 char *l, *uc;
457 int logged, evil, idle, type = 0;
458 time_t signon, time_idle;
459
460 c = strtok(NULL, ":"); /* name */
461 l = strtok(NULL, ":"); /* online */
462 sscanf(strtok(NULL, ":"), "%d", &evil);
463 sscanf(strtok(NULL, ":"), "%ld", &signon);
464 sscanf(strtok(NULL, ":"), "%d", &idle);
465 uc = strtok(NULL, ":");
466
467 logged = (l && (*l == 'T')) ? 1 : 0;
468
469 if (uc[0] == 'A')
470 type |= UC_AOL;
471 switch (uc[1]) {
472 case 'A':
473 type |= UC_ADMIN;
474 break;
475 case 'U':
476 type |= UC_UNCONFIRMED;
477 break;
478 case 'O':
479 type |= UC_NORMAL;
480 break;
481 default:
482 break;
483 }
484 if (uc[2] == 'U')
485 type |= UC_UNAVAILABLE;
486
487 if (idle) {
488 time(&time_idle);
489 time_idle -= idle * 60;
490 } else
491 time_idle = 0;
492
493 serv_got_update(gc, c, logged, evil, signon, time_idle, type, 0);
494 } else if (!strcasecmp(c, "ERROR")) {
495 c = strtok(NULL, ":");
496 show_error_dialog(c);
497 } else if (!strcasecmp(c, "EVILED")) {
498 int lev;
499 char *name;
500
501 sscanf(strtok(NULL, ":"), "%d", &lev);
502 name = strtok(NULL, ":");
503
504 serv_got_eviled(gc, name, lev);
505 } else if (!strcasecmp(c, "CHAT_JOIN")) {
506 char *name;
507 int id;
508
509 sscanf(strtok(NULL, ":"), "%d", &id);
510 name = strtok(NULL, ":");
511
512 serv_got_joined_chat(gc, id, name);
513 } else if (!strcasecmp(c, "CHAT_IN")) {
514 int id, w;
515 char *m, *who, *whisper;
516
517 sscanf(strtok(NULL, ":"), "%d", &id);
518 who = strtok(NULL, ":");
519 whisper = strtok(NULL, ":");
520 m = whisper;
521 while (*m && (*m != ':'))
522 m++;
523 m++;
524
525 w = (whisper && (*whisper == 'T')) ? 1 : 0;
526
527 serv_got_chat_in(gc, id, who, w, m, time((time_t)NULL));
528 } else if (!strcasecmp(c, "CHAT_UPDATE_BUDDY")) {
529 int id;
530 char *in, *buddy;
531 GSList *bcs = gc->buddy_chats;
532 struct conversation *b = NULL;
533
534 sscanf(strtok(NULL, ":"), "%d", &id);
535 in = strtok(NULL, ":");
536
537 while (bcs) {
538 b = (struct conversation *)bcs->data;
539 if (id == b->id)
540 break;
541 bcs = bcs->next;
542 b = NULL;
543 }
544
545 if (!b)
546 return;
547
548 if (in && (*in == 'T'))
549 while ((buddy = strtok(NULL, ":")) != NULL)
550 add_chat_buddy(b, buddy);
551 else
552 while ((buddy = strtok(NULL, ":")) != NULL)
553 remove_chat_buddy(b, buddy);
554 } else if (!strcasecmp(c, "CHAT_INVITE")) {
555 char *name, *who, *message;
556 int id;
557
558 name = strtok(NULL, ":");
559 sscanf(strtok(NULL, ":"), "%d", &id);
560 who = strtok(NULL, ":");
561 message = strtok(NULL, ":");
562
563 serv_got_chat_invite(gc, name, id, who, message);
564 } else if (!strcasecmp(c, "CHAT_LEFT")) {
565 GSList *bcs = gc->buddy_chats;
566 struct conversation *b = NULL;
567 int id;
568
569 sscanf(strtok(NULL, ":"), "%d", &id);
570
571 while (bcs) {
572 b = (struct conversation *)bcs->data;
573 if (id == b->id)
574 break;
575 b = NULL;
576 bcs = bcs->next;
577 }
578
579 if (!b)
580 return;
581
582 if (b->window) {
583 char error_buf[BUF_LONG];
584 b->gc = NULL;
585 g_snprintf(error_buf, sizeof error_buf, _("You have been disconnected"
586 " from chat room %s."), b->name);
587 do_error_dialog(error_buf, _("Chat Error"));
588 } else
589 serv_got_chat_left(gc, id);
590 } else if (!strcasecmp(c, "GOTO_URL")) {
591 char *name, *url, tmp[256];
592
593 name = strtok(NULL, ":");
594 url = strtok(NULL, ":");
595
596 g_snprintf(tmp, sizeof(tmp), "http://%s:%d/%s",
597 gc->user->proto_opt[USEROPT_AUTH][0] ?
598 gc->user->proto_opt[USEROPT_AUTH] : TOC_HOST,
599 gc->user->proto_opt[USEROPT_AUTHPORT][0] ?
600 atoi(gc->user->proto_opt[USEROPT_AUTHPORT]) : TOC_PORT,
601 url);
602 grab_url(tmp, toc_got_info, NULL);
603 } else if (!strcasecmp(c, "DIR_STATUS")) {
604 } else if (!strcasecmp(c, "ADMIN_NICK_STATUS")) {
605 } else if (!strcasecmp(c, "ADMIN_PASSWD_STATUS")) {
606 do_error_dialog(_("Password Change Successeful"), _("Gaim - Password Change"));
607 } else if (!strcasecmp(c, "PAUSE")) {
608 tdt->state = STATE_PAUSE;
609 do_error_dialog(_("TOC has sent a PAUSE command. When this happens, TOC ignores"
610 " any messages sent to it, and may kick you off if you send a"
611 " message. Gaim will prevent anything from going through. This"
612 " is only temporary, please be patient."), _("TOC Pause"));
613 } else if (!strcasecmp(c, "RVOUS_PROPOSE")) {
614 char *user, *uuid, *cookie;
615 int seq;
616 char *rip, *pip, *vip;
617 int port;
618
619 user = strtok(NULL, ":");
620 uuid = strtok(NULL, ":");
621 cookie = strtok(NULL, ":");
622 sscanf(strtok(NULL, ":"), "%d", &seq);
623 rip = strtok(NULL, ":");
624 pip = strtok(NULL, ":");
625 vip = strtok(NULL, ":");
626 sscanf(strtok(NULL, ":"), "%d", &port);
627
628 if (!strcmp(uuid, FILE_SEND_UID)) {
629 /* they want us to get a file */
630 int unk[4], i;
631 char *messages[4], *tmp, *name;
632 int subtype, files, totalsize = 0;
633 struct ft_request *ft;
634
635 for (i = 0; i < 4; i++) {
636 sscanf(strtok(NULL, ":"), "%d", &unk[i]);
637 if (unk[i] == 10001)
638 break;
639 frombase64(strtok(NULL, ":"), &messages[i], NULL);
640 }
641 frombase64(strtok(NULL, ":"), &tmp, NULL);
642
643 subtype = tmp[1];
644 files = tmp[3];
645
646 totalsize |= (tmp[4] << 24) & 0xff000000;
647 totalsize |= (tmp[5] << 16) & 0x00ff0000;
648 totalsize |= (tmp[6] << 8) & 0x0000ff00;
649 totalsize |= (tmp[7] << 0) & 0x000000ff;
650
651 if (!totalsize) {
652 g_free(tmp);
653 for (i--; i >= 0; i--)
654 g_free(messages[i]);
655 return;
656 }
657
658 name = tmp + 8;
659
660 ft = g_new0(struct ft_request, 1);
661 ft->cookie = g_strdup(cookie);
662 ft->ip = g_strdup(pip);
663 ft->port = port;
664 if (i)
665 ft->message = g_strdup(messages[0]);
666 else
667 ft->message = NULL;
668 ft->filename = g_strdup(name);
669 ft->user = g_strdup(user);
670 ft->size = totalsize;
671 ft->files = files;
672 g_snprintf(ft->UID, sizeof(ft->UID), "%s", FILE_SEND_UID);
673 ft->gc = gc;
674
675 g_free(tmp);
676 for (i--; i >= 0; i--)
677 g_free(messages[i]);
678
679 debug_printf("English translation of RVOUS_PROPOSE: %s requests Send File (i.e."
680 " send a file to you); %s:%d (verified_ip:port), %d files at"
681 " total size of %ld bytes.\n", user, vip, port, files, totalsize);
682 accept_file_dialog(ft);
683 } else if (!strcmp(uuid, FILE_GET_UID)) {
684 /* they want us to send a file */
685 int unk[4], i;
686 char *messages[4], *tmp;
687 struct ft_request *ft;
688
689 for (i = 0; i < 4; i++) {
690 sscanf(strtok(NULL, ":"), "%d", unk + i);
691 if (unk[i] == 10001)
692 break;
693 frombase64(strtok(NULL, ":"), &messages[i], NULL);
694 }
695 frombase64(strtok(NULL, ":"), &tmp, NULL);
696
697 ft = g_new0(struct ft_request, 1);
698 ft->cookie = g_strdup(cookie);
699 ft->ip = g_strdup(pip);
700 ft->port = port;
701 if (i)
702 ft->message = g_strdup(messages[0]);
703 else
704 ft->message = NULL;
705 ft->user = g_strdup(user);
706 g_snprintf(ft->UID, sizeof(ft->UID), "%s", FILE_GET_UID);
707 ft->gc = gc;
708
709 g_free(tmp);
710 for (i--; i >= 0; i--)
711 g_free(messages[i]);
712
713 accept_file_dialog(ft);
714 } else if (!strcmp(uuid, VOICE_UID)) {
715 /* oh goody. voice over ip. fun stuff. */
716 } else if (!strcmp(uuid, B_ICON_UID)) {
717 /*
718 int unk[4], i;
719 char *messages[4];
720 struct buddy_icon *icon;
721
722 for (i = 0; i < 4; i++) {
723 sscanf(strtok(NULL, ":"), "%d", unk + i);
724 if (unk[i] == 10001)
725 break;
726 frombase64(strtok(NULL, ":"), &messages[i], NULL);
727 }
728 frombase64(strtok(NULL, ":"), (char **)&icon, NULL);
729
730 debug_printf("received icon of length %d\n", icon->len);
731 g_free(icon);
732 for (i--; i >= 0; i--)
733 g_free(messages[i]);
734 */
735 } else if (!strcmp(uuid, IMAGE_UID)) {
736 /* aka Direct IM */
737 } else {
738 debug_printf("Don't know what to do with RVOUS UUID %s\n", uuid);
739 /* do we have to do anything here? i think it just times out */
740 }
741 } else {
742 debug_printf("don't know what to do with %s\n", c);
743 }
744 }
745
746 static char *toc_name()
747 {
748 return "TOC";
749 }
750
751 static void toc_send_im(struct gaim_connection *gc, char *name, char *message, int away)
752 {
753 char buf[BUF_LEN * 2];
754
755 escape_text(message);
756 g_snprintf(buf, MSG_LEN - 8, "toc_send_im %s \"%s\"%s", normalize(name),
757 message, ((away) ? " auto" : ""));
758 sflap_send(gc, buf, -1, TYPE_DATA);
759 }
760
761 static void toc_set_config(struct gaim_connection *gc)
762 {
763 char buf[MSG_LEN], snd[BUF_LEN * 2];
764 toc_build_config(gc, buf, MSG_LEN, FALSE);
765 g_snprintf(snd, MSG_LEN, "toc_set_config {%s}", buf);
766 sflap_send(gc, snd, -1, TYPE_DATA);
767 }
768
769 static void toc_get_info(struct gaim_connection *g, char *name)
770 {
771 char buf[BUF_LEN * 2];
772 g_snprintf(buf, MSG_LEN, "toc_get_info %s", normalize(name));
773 sflap_send(g, buf, -1, TYPE_DATA);
774 }
775
776 static void toc_get_dir(struct gaim_connection *g, char *name)
777 {
778 char buf[BUF_LEN * 2];
779 g_snprintf(buf, MSG_LEN, "toc_get_dir %s", normalize(name));
780 sflap_send(g, buf, -1, TYPE_DATA);
781 }
782
783 static void toc_set_dir(struct gaim_connection *g, char *first, char *middle, char *last,
784 char *maiden, char *city, char *state, char *country, int web)
785 {
786 char buf2[BUF_LEN * 4], buf[BUF_LEN];
787 g_snprintf(buf2, sizeof(buf2), "%s:%s:%s:%s:%s:%s:%s:%s", first,
788 middle, last, maiden, city, state, country, (web == 1) ? "Y" : "");
789 escape_text(buf2);
790 g_snprintf(buf, sizeof(buf), "toc_set_dir %s", buf2);
791 sflap_send(g, buf, -1, TYPE_DATA);
792 }
793
794 static void toc_dir_search(struct gaim_connection *g, char *first, char *middle, char *last,
795 char *maiden, char *city, char *state, char *country, char *email)
796 {
797 char buf[BUF_LONG];
798 g_snprintf(buf, sizeof(buf) / 2, "toc_dir_search %s:%s:%s:%s:%s:%s:%s:%s", first, middle,
799 last, maiden, city, state, country, email);
800 debug_printf("Searching for: %s,%s,%s,%s,%s,%s,%s\n", first, middle, last, maiden,
801 city, state, country);
802 sflap_send(g, buf, -1, TYPE_DATA);
803 }
804
805 static void toc_set_away(struct gaim_connection *g, char *state, char *message)
806 {
807 char buf[BUF_LEN * 2];
808 if (g->away)
809 g_free (g->away);
810 g->away = NULL;
811 if (message) {
812 g->away = g_strdup (message);
813 escape_text(message);
814 g_snprintf(buf, MSG_LEN, "toc_set_away \"%s\"", message);
815 } else
816 g_snprintf(buf, MSG_LEN, "toc_set_away \"\"");
817 sflap_send(g, buf, -1, TYPE_DATA);
818 }
819
820 static void toc_set_info(struct gaim_connection *g, char *info)
821 {
822 char buf[BUF_LEN * 2], buf2[BUF_LEN * 2];
823 g_snprintf(buf2, sizeof buf2, "%s", info);
824 escape_text(buf2);
825 g_snprintf(buf, sizeof(buf), "toc_set_info \"%s\n\"", buf2);
826 sflap_send(g, buf, -1, TYPE_DATA);
827 }
828
829 static void toc_change_passwd(struct gaim_connection *g, char *orig, char *new)
830 {
831 char buf[BUF_LEN * 2];
832 g_snprintf(buf, BUF_LONG, "toc_change_passwd %s %s", orig, new);
833 sflap_send(g, buf, strlen(buf), TYPE_DATA);
834 }
835
836 static void toc_add_buddy(struct gaim_connection *g, char *name)
837 {
838 char buf[BUF_LEN * 2];
839 g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", normalize(name));
840 sflap_send(g, buf, -1, TYPE_DATA);
841 toc_set_config(g);
842 }
843
844 static void toc_add_buddies(struct gaim_connection *g, GList * buddies)
845 {
846 char buf[BUF_LEN * 2];
847 int n;
848
849 n = g_snprintf(buf, sizeof(buf), "toc_add_buddy");
850 while (buddies) {
851 if (strlen(normalize(buddies->data)) > MSG_LEN - n - 16) {
852 sflap_send(g, buf, -1, TYPE_DATA);
853 n = g_snprintf(buf, sizeof(buf), "toc_add_buddy");
854 }
855 n += g_snprintf(buf + n, sizeof(buf) - n, " %s", normalize(buddies->data));
856 buddies = buddies->next;
857 }
858 sflap_send(g, buf, -1, TYPE_DATA);
859 }
860
861 static void toc_remove_buddy(struct gaim_connection *g, char *name)
862 {
863 char buf[BUF_LEN * 2];
864 g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", normalize(name));
865 sflap_send(g, buf, -1, TYPE_DATA);
866 toc_set_config(g);
867 }
868
869 static void toc_set_idle(struct gaim_connection *g, int time)
870 {
871 char buf[BUF_LEN * 2];
872 g_snprintf(buf, sizeof(buf), "toc_set_idle %d", time);
873 sflap_send(g, buf, -1, TYPE_DATA);
874 }
875
876 static void toc_warn(struct gaim_connection *g, char *name, int anon)
877 {
878 char send[BUF_LEN * 2];
879 g_snprintf(send, 255, "toc_evil %s %s", name, ((anon) ? "anon" : "norm"));
880 sflap_send(g, send, -1, TYPE_DATA);
881 }
882
883 static void toc_accept_chat(struct gaim_connection *g, int i)
884 {
885 char buf[BUF_LEN * 2];
886 g_snprintf(buf, 255, "toc_chat_accept %d", i);
887 sflap_send(g, buf, -1, TYPE_DATA);
888 }
889
890 static void toc_join_chat(struct gaim_connection *g, int exchange, char *name)
891 {
892 char buf[BUF_LONG];
893 if (!name) {
894 const char *nm;
895 if (!join_chat_entry || !join_chat_spin)
896 return;
897 nm = gtk_entry_get_text(GTK_ENTRY(join_chat_entry));
898 exchange = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(join_chat_spin));
899 if (!name || !strlen(name))
900 return;
901 g_snprintf(buf, sizeof(buf) / 2, "toc_chat_join %d \"%s\"", exchange, nm);
902 } else
903 g_snprintf(buf, sizeof(buf) / 2, "toc_chat_join %d \"%s\"", exchange, name);
904 sflap_send(g, buf, -1, TYPE_DATA);
905 }
906
907 static void toc_chat_invite(struct gaim_connection *g, int id, char *message, char *name)
908 {
909 char buf[BUF_LONG];
910 g_snprintf(buf, sizeof(buf) / 2, "toc_chat_invite %d \"%s\" %s", id, message, normalize(name));
911 sflap_send(g, buf, -1, TYPE_DATA);
912 }
913
914 static void toc_chat_leave(struct gaim_connection *g, int id)
915 {
916 GSList *bcs = g->buddy_chats;
917 struct conversation *b = NULL;
918 char buf[BUF_LEN * 2];
919
920 while (bcs) {
921 b = (struct conversation *)bcs->data;
922 if (id == b->id)
923 break;
924 b = NULL;
925 bcs = bcs->next;
926 }
927
928 if (!b)
929 return; /* can this happen? */
930
931 if (!b->gc) /* TOC already kicked us out of this room */
932 serv_got_chat_left(g, id);
933 else {
934 g_snprintf(buf, 255, "toc_chat_leave %d", id);
935 sflap_send(g, buf, -1, TYPE_DATA);
936 }
937 }
938
939 static void toc_chat_whisper(struct gaim_connection *g, int id, char *who, char *message)
940 {
941 char buf2[BUF_LEN * 2];
942 g_snprintf(buf2, sizeof(buf2), "toc_chat_whisper %d %s \"%s\"", id, who, message);
943 sflap_send(g, buf2, -1, TYPE_DATA);
944 }
945
946 static void toc_chat_send(struct gaim_connection *g, int id, char *message)
947 {
948 char buf[BUF_LEN * 2];
949 escape_text(message);
950 g_snprintf(buf, sizeof(buf), "toc_chat_send %d \"%s\"", id, message);
951 sflap_send(g, buf, -1, TYPE_DATA);
952 }
953
954 static void toc_keepalive(struct gaim_connection *gc)
955 {
956 sflap_send(gc, "", 0, TYPE_KEEPALIVE);
957 }
958
959 static char **toc_list_icon(int uc)
960 {
961 if (uc & UC_UNAVAILABLE)
962 return (char **)away_icon_xpm;
963 if (uc & UC_AOL)
964 return (char **)aol_icon_xpm;
965 if (uc & UC_NORMAL)
966 return (char **)free_icon_xpm;
967 if (uc & UC_ADMIN)
968 return (char **)admin_icon_xpm;
969 if (uc & UC_UNCONFIRMED)
970 return (char **)dt_icon_xpm;
971 return NULL;
972 }
973
974 static void toc_info(GtkObject * obj, char *who)
975 {
976 struct gaim_connection *gc = (struct gaim_connection *)gtk_object_get_user_data(obj);
977 serv_get_info(gc, who);
978 }
979
980 static void toc_dir_info(GtkObject * obj, char *who)
981 {
982 struct gaim_connection *gc = (struct gaim_connection *)gtk_object_get_user_data(obj);
983 serv_get_dir(gc, who);
984 }
985
986 static void des_jc()
987 {
988 join_chat_entry = NULL;
989 join_chat_spin = NULL;
990 }
991
992 static void toc_draw_join_chat(struct gaim_connection *gc, GtkWidget *fbox) {
993 GtkWidget *label;
994 GtkWidget *rowbox;
995 GtkObject *adjust;
996
997 rowbox = gtk_hbox_new(FALSE, 5);
998 gtk_box_pack_start(GTK_BOX(fbox), rowbox, TRUE, TRUE, 0);
999 gtk_widget_show(rowbox);
1000
1001 label = gtk_label_new(_("Join what group:"));
1002 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0);
1003 gtk_signal_connect(GTK_OBJECT(label), "destroy", GTK_SIGNAL_FUNC(des_jc), NULL);
1004 gtk_widget_show(label);
1005
1006 join_chat_entry = gtk_entry_new();
1007 gtk_box_pack_start(GTK_BOX(rowbox), join_chat_entry, TRUE, TRUE, 0);
1008 gtk_widget_grab_focus(join_chat_entry);
1009 gtk_signal_connect(GTK_OBJECT(join_chat_entry), "activate", GTK_SIGNAL_FUNC(do_join_chat), NULL);
1010 gtk_widget_show(join_chat_entry);
1011
1012 rowbox = gtk_hbox_new(FALSE, 5);
1013 gtk_box_pack_start(GTK_BOX(fbox), rowbox, TRUE, TRUE, 0);
1014 gtk_widget_show(rowbox);
1015
1016 label = gtk_label_new(_("Community:"));
1017 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0);
1018 gtk_widget_show(label);
1019
1020 adjust = gtk_adjustment_new(4, 4, 20, 1, 10, 10);
1021 join_chat_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
1022 gtk_widget_set_usize(join_chat_spin, 50, -1);
1023 gtk_box_pack_start(GTK_BOX(rowbox), join_chat_spin, FALSE, FALSE, 0);
1024 gtk_widget_show(join_chat_spin);
1025 }
1026
1027 static void toc_buddy_menu(GtkWidget *menu, struct gaim_connection *gc, char *who)
1028 {
1029 GtkWidget *button;
1030
1031 button = gtk_menu_item_new_with_label(_("Get Info"));
1032 gtk_signal_connect(GTK_OBJECT(button), "activate", GTK_SIGNAL_FUNC(toc_info), who);
1033 gtk_object_set_user_data(GTK_OBJECT(button), gc);
1034 gtk_menu_append(GTK_MENU(menu), button);
1035 gtk_widget_show(button);
1036
1037 button = gtk_menu_item_new_with_label(_("Get Dir Info"));
1038 gtk_signal_connect(GTK_OBJECT(button), "activate", GTK_SIGNAL_FUNC(toc_dir_info), who);
1039 gtk_object_set_user_data(GTK_OBJECT(button), gc);
1040 gtk_menu_append(GTK_MENU(menu), button);
1041 gtk_widget_show(button);
1042 }
1043
1044 static void toc_print_option(GtkEntry *entry, struct aim_user *user)
1045 {
1046 int entrynum;
1047
1048 entrynum = (int)gtk_object_get_user_data(GTK_OBJECT(entry));
1049
1050 if (entrynum == USEROPT_AUTH) {
1051 g_snprintf(user->proto_opt[USEROPT_AUTH],
1052 sizeof(user->proto_opt[USEROPT_AUTH]), "%s", gtk_entry_get_text(entry));
1053 } else if (entrynum == USEROPT_AUTHPORT) {
1054 g_snprintf(user->proto_opt[USEROPT_AUTHPORT],
1055 sizeof(user->proto_opt[USEROPT_AUTHPORT]), "%s", gtk_entry_get_text(entry));
1056 }
1057 }
1058
1059 static void toc_user_opts(GtkWidget *book, struct aim_user *user)
1060 {
1061 /* so here, we create the new notebook page */
1062 GtkWidget *vbox;
1063 GtkWidget *hbox;
1064 GtkWidget *label;
1065 GtkWidget *entry;
1066
1067 vbox = gtk_vbox_new(FALSE, 5);
1068 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
1069 gtk_notebook_append_page(GTK_NOTEBOOK(book), vbox, gtk_label_new("TOC Options"));
1070 gtk_widget_show(vbox);
1071
1072 hbox = gtk_hbox_new(FALSE, 5);
1073 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1074 gtk_widget_show(hbox);
1075
1076 label = gtk_label_new("TOC Host:");
1077 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1078 gtk_widget_show(label);
1079
1080 entry = gtk_entry_new();
1081 gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
1082 gtk_object_set_user_data(GTK_OBJECT(entry), (void *)USEROPT_AUTH);
1083 gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(toc_print_option), user);
1084 if (user->proto_opt[USEROPT_AUTH][0]) {
1085 debug_printf("setting text %s\n", user->proto_opt[USEROPT_AUTH]);
1086 gtk_entry_set_text(GTK_ENTRY(entry), user->proto_opt[USEROPT_AUTH]);
1087 } else
1088 gtk_entry_set_text(GTK_ENTRY(entry), "toc.oscar.aol.com");
1089 gtk_widget_show(entry);
1090
1091 hbox = gtk_hbox_new(FALSE, 0);
1092 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1093 gtk_widget_show(hbox);
1094
1095 label = gtk_label_new("TOC Port:");
1096 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1097 gtk_widget_show(label);
1098
1099 entry = gtk_entry_new();
1100 gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
1101 gtk_object_set_user_data(GTK_OBJECT(entry), (void *)USEROPT_AUTHPORT);
1102 gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(toc_print_option), user);
1103 if (user->proto_opt[USEROPT_AUTHPORT][0]) {
1104 debug_printf("setting text %s\n", user->proto_opt[USEROPT_AUTHPORT]);
1105 gtk_entry_set_text(GTK_ENTRY(entry), user->proto_opt[USEROPT_AUTHPORT]);
1106 } else
1107 gtk_entry_set_text(GTK_ENTRY(entry), "9898");
1108
1109 gtk_widget_show(entry);
1110 }
1111
1112 static void toc_add_permit(struct gaim_connection *gc, char *who)
1113 {
1114 char buf2[BUF_LEN * 2];
1115 if (gc->permdeny != 3)
1116 return;
1117 g_snprintf(buf2, sizeof(buf2), "toc_add_permit %s", normalize(who));
1118 sflap_send(gc, buf2, -1, TYPE_DATA);
1119 toc_set_config(gc);
1120 }
1121
1122 static void toc_add_deny(struct gaim_connection *gc, char *who)
1123 {
1124 char buf2[BUF_LEN * 2];
1125 if (gc->permdeny != 4)
1126 return;
1127 g_snprintf(buf2, sizeof(buf2), "toc_add_deny %s", normalize(who));
1128 sflap_send(gc, buf2, -1, TYPE_DATA);
1129 toc_set_config(gc);
1130 }
1131
1132 static void toc_set_permit_deny(struct gaim_connection *gc)
1133 {
1134 char buf2[BUF_LEN * 2];
1135 GSList *list;
1136 int at;
1137
1138 switch (gc->permdeny) {
1139 case 1:
1140 /* permit all, deny none. to get here reliably we need to have been in permit
1141 * mode, and send an empty toc_add_deny message, which will switch us to deny none */
1142 g_snprintf(buf2, sizeof(buf2), "toc_add_permit ");
1143 sflap_send(gc, buf2, -1, TYPE_DATA);
1144 g_snprintf(buf2, sizeof(buf2), "toc_add_deny ");
1145 sflap_send(gc, buf2, -1, TYPE_DATA);
1146 break;
1147 case 2:
1148 /* deny all, permit none. to get here reliably we need to have been in deny
1149 * mode, and send an empty toc_add_permit message, which will switch us to permit none */
1150 g_snprintf(buf2, sizeof(buf2), "toc_add_deny ");
1151 sflap_send(gc, buf2, -1, TYPE_DATA);
1152 g_snprintf(buf2, sizeof(buf2), "toc_add_permit ");
1153 sflap_send(gc, buf2, -1, TYPE_DATA);
1154 break;
1155 case 3:
1156 /* permit some. we want to switch to deny mode first, then send the toc_add_permit
1157 * message, which will clear and set our permit list. toc sucks. */
1158 g_snprintf(buf2, sizeof(buf2), "toc_add_deny ");
1159 sflap_send(gc, buf2, -1, TYPE_DATA);
1160
1161 at = g_snprintf(buf2, sizeof(buf2), "toc_add_permit ");
1162 list = gc->permit;
1163 while (list) {
1164 at += g_snprintf(buf2 + at, sizeof(buf2) - at, "%s ", normalize(list->data));
1165 if (at > MSG_LEN + 32) { /* from out my ass comes greatness */
1166 sflap_send(gc, buf2, -1, TYPE_DATA);
1167 at = g_snprintf(buf2, sizeof(buf2), "toc_add_permit ");
1168 }
1169 list = list->next;
1170 }
1171 sflap_send(gc, buf2, -1, TYPE_DATA);
1172 break;
1173 case 4:
1174 /* deny some. we want to switch to permit mode first, then send the toc_add_deny
1175 * message, which will clear and set our deny list. toc sucks. */
1176 g_snprintf(buf2, sizeof(buf2), "toc_add_permit ");
1177 sflap_send(gc, buf2, -1, TYPE_DATA);
1178
1179 at = g_snprintf(buf2, sizeof(buf2), "toc_add_deny ");
1180 list = gc->deny;
1181 while (list) {
1182 at += g_snprintf(buf2 + at, sizeof(buf2) - at, "%s ", normalize(list->data));
1183 if (at > MSG_LEN + 32) { /* from out my ass comes greatness */
1184 sflap_send(gc, buf2, -1, TYPE_DATA);
1185 at = g_snprintf(buf2, sizeof(buf2), "toc_add_deny ");
1186 }
1187 list = list->next;
1188 }
1189 sflap_send(gc, buf2, -1, TYPE_DATA);
1190 break;
1191 default:
1192 break;
1193 }
1194 toc_set_config(gc);
1195 }
1196
1197 static void toc_rem_permit(struct gaim_connection *gc, char *who)
1198 {
1199 if (gc->permdeny != 3)
1200 return;
1201 toc_set_permit_deny(gc);
1202 }
1203
1204 static void toc_rem_deny(struct gaim_connection *gc, char *who)
1205 {
1206 if (gc->permdeny != 4)
1207 return;
1208 toc_set_permit_deny(gc);
1209 }
1210
1211 static void toc_draw_new_user(GtkWidget *box)
1212 {
1213 GtkWidget *label;
1214
1215 label = gtk_label_new(_("Unfortunately, currently TOC only allows new user registration by "
1216 "going to http://aim.aol.com/aimnew/Aim/register.adp?promo=106723&pageset=Aim&client=no"
1217 ". Clicking the Register button will open the URL for you."));
1218 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1219 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5);
1220 gtk_widget_show(label);
1221 }
1222
1223 static void toc_do_new_user()
1224 {
1225 open_url(NULL, "http://aim.aol.com/aimnew/Aim/register.adp?promo=106723&pageset=Aim&client=no");
1226 }
1227
1228 static GList *toc_away_states()
1229 {
1230 return g_list_append(NULL, GAIM_AWAY_CUSTOM);
1231 }
1232
1233 static void toc_do_action(struct gaim_connection *gc, char *act)
1234 {
1235 if (!strcmp(act, "Set User Info")) {
1236 show_set_info(gc);
1237 } else if (!strcmp(act, "Set Dir Info")) {
1238 show_set_dir(gc);
1239 } else if (!strcmp(act, "Change Password")) {
1240 show_change_passwd(gc);
1241 }
1242 }
1243
1244 static GList *toc_actions()
1245 {
1246 GList *m = NULL;
1247
1248 m = g_list_append(m, "Set User Info");
1249 m = g_list_append(m, "Set Dir Info");
1250 m = g_list_append(m, "Change Password");
1251
1252 return m;
1253 }
1254
1255 static struct prpl *my_protocol = NULL;
1256
1257 void toc_init(struct prpl *ret)
1258 {
1259 ret->protocol = PROTO_TOC;
1260 ret->options = OPT_PROTO_HTML | OPT_PROTO_CORRECT_TIME;
1261 ret->name = toc_name;
1262 ret->list_icon = toc_list_icon;
1263 ret->away_states = toc_away_states;
1264 ret->actions = toc_actions;
1265 ret->do_action = toc_do_action;
1266 ret->buddy_menu = toc_buddy_menu;
1267 ret->user_opts = toc_user_opts;
1268 ret->draw_new_user = toc_draw_new_user;
1269 ret->do_new_user = toc_do_new_user;
1270 ret->login = toc_login;
1271 ret->close = toc_close;
1272 ret->send_im = toc_send_im;
1273 ret->set_info = toc_set_info;
1274 ret->get_info = toc_get_info;
1275 ret->set_away = toc_set_away;
1276 ret->get_away_msg = NULL;
1277 ret->set_dir = toc_set_dir;
1278 ret->get_dir = toc_get_dir;
1279 ret->dir_search = toc_dir_search;
1280 ret->set_idle = toc_set_idle;
1281 ret->change_passwd = toc_change_passwd;
1282 ret->add_buddy = toc_add_buddy;
1283 ret->add_buddies = toc_add_buddies;
1284 ret->remove_buddy = toc_remove_buddy;
1285 ret->add_permit = toc_add_permit;
1286 ret->add_deny = toc_add_deny;
1287 ret->rem_permit = toc_rem_permit;
1288 ret->rem_deny = toc_rem_deny;
1289 ret->set_permit_deny = toc_set_permit_deny;
1290 ret->warn = toc_warn;
1291 ret->draw_join_chat = toc_draw_join_chat;
1292 ret->accept_chat = toc_accept_chat;
1293 ret->join_chat = toc_join_chat;
1294 ret->chat_invite = toc_chat_invite;
1295 ret->chat_leave = toc_chat_leave;
1296 ret->chat_whisper = toc_chat_whisper;
1297 ret->chat_send = toc_chat_send;
1298 ret->keepalive = toc_keepalive;
1299
1300 my_protocol = ret;
1301 }
1302
1303 #ifndef STATIC
1304
1305 char *gaim_plugin_init(GModule *handle)
1306 {
1307 load_protocol(toc_init, sizeof(struct prpl));
1308 return NULL;
1309 }
1310
1311 void gaim_plugin_remove()
1312 {
1313 struct prpl *p = find_prpl(PROTO_TOC);
1314 if (p == my_protocol)
1315 unload_protocol(p);
1316 }
1317
1318 char *name()
1319 {
1320 return "TOC";
1321 }
1322
1323 char *description()
1324 {
1325 return "Allows gaim to use the TOC protocol.";
1326 }
1327
1328 #endif
1329
1330 /*********
1331 * RVOUS ACTIONS
1332 ********/
1333
1334 struct file_header {
1335 char magic[4]; /* 0 */
1336 short hdrlen; /* 4 */
1337 short hdrtype; /* 6 */
1338 char bcookie[8]; /* 8 */
1339 short encrypt; /* 16 */
1340 short compress; /* 18 */
1341 short totfiles; /* 20 */
1342 short filesleft; /* 22 */
1343 short totparts; /* 24 */
1344 short partsleft; /* 26 */
1345 long totsize; /* 28 */
1346 long size; /* 32 */
1347 long modtime; /* 36 */
1348 long checksum; /* 40 */
1349 long rfrcsum; /* 44 */
1350 long rfsize; /* 48 */
1351 long cretime; /* 52 */
1352 long rfcsum; /* 56 */
1353 long nrecvd; /* 60 */
1354 long recvcsum; /* 64 */
1355 char idstring[32]; /* 68 */
1356 char flags; /* 100 */
1357 char lnameoffset; /* 101 */
1358 char lsizeoffset; /* 102 */
1359 char dummy[69]; /* 103 */
1360 char macfileinfo[16]; /* 172 */
1361 short nencode; /* 188 */
1362 short nlanguage; /* 190 */
1363 char name[64]; /* 192 */
1364 /* 256 */
1365 };
1366
1367 struct file_transfer {
1368 struct file_header hdr;
1369
1370 struct gaim_connection *gc;
1371
1372 char *user;
1373 char *cookie;
1374 char *ip;
1375 int port;
1376 long size;
1377 struct stat st;
1378
1379 GtkWidget *window;
1380 int files;
1381 char *filename;
1382 FILE *file;
1383 int recvsize;
1384
1385 gint inpa;
1386 };
1387
1388 static void debug_header(struct file_transfer *ft) {
1389 struct file_header *f = (struct file_header *)ft;
1390 debug_printf("TOC FT HEADER:\n"
1391 "\t%s %d 0x%04x\n"
1392 "\t%s %d %d\n"
1393 "\t%d %d %d %d %ld %ld\n"
1394 "\t%ld %ld %ld %ld %ld %ld %ld %ld\n"
1395 "\t%s\n"
1396 "\t0x%02x, 0x%02x, 0x%02x\n"
1397 "\t%s %s\n"
1398 "\t%d %d\n"
1399 "\t%s\n",
1400 f->magic, ntohs(f->hdrlen), f->hdrtype,
1401 f->bcookie, ntohs(f->encrypt), ntohs(f->compress),
1402 ntohs(f->totfiles), ntohs(f->filesleft), ntohs(f->totparts),
1403 ntohs(f->partsleft), ntohl(f->totsize), ntohl(f->size),
1404 ntohl(f->modtime), ntohl(f->checksum), ntohl(f->rfrcsum), ntohl(f->rfsize),
1405 ntohl(f->cretime), ntohl(f->rfcsum), ntohl(f->nrecvd),
1406 ntohl(f->recvcsum),
1407 f->idstring,
1408 f->flags, f->lnameoffset, f->lsizeoffset,
1409 f->dummy, f->macfileinfo,
1410 ntohs(f->nencode), ntohs(f->nlanguage),
1411 f->name);
1412 }
1413
1414 static void toc_send_file_callback(gpointer data, gint source, GdkInputCondition cond)
1415 {
1416 char buf[BUF_LONG];
1417 int rt, i;
1418
1419 struct file_transfer *ft = data;
1420
1421 if (cond & GDK_INPUT_EXCEPTION) {
1422 gdk_input_remove(ft->inpa);
1423 close(source);
1424 g_free(ft->filename);
1425 g_free(ft->user);
1426 g_free(ft->ip);
1427 g_free(ft->cookie);
1428 if (ft->file)
1429 fclose(ft->file);
1430 g_free(ft);
1431 return;
1432 }
1433
1434 if (ft->hdr.hdrtype != 0x202) {
1435 char *buf;
1436 frombase64(ft->cookie, &buf, NULL);
1437
1438 read(source, ft, 8);
1439 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8));
1440 debug_header(ft);
1441
1442 ft->hdr.hdrtype = 0x202;
1443 memcpy(ft->hdr.bcookie, buf, 8);
1444 g_free(buf);
1445 ft->hdr.encrypt = 0; ft->hdr.compress = 0;
1446 debug_header(ft);
1447 write(source, ft, 256);
1448
1449 if (ft->files == 1) {
1450 ft->file = fopen(ft->filename, "w");
1451 if (!ft->file) {
1452 buf = g_strdup_printf("Could not open %s for writing!", ft->filename);
1453 do_error_dialog(buf, _("Error"));
1454 g_free(buf);
1455 gdk_input_remove(ft->inpa);
1456 close(source);
1457 g_free(ft->filename);
1458 g_free(ft->user);
1459 g_free(ft->ip);
1460 g_free(ft->cookie);
1461 g_free(ft);
1462 }
1463 } else {
1464 buf = g_strdup_printf("%s/%s", ft->filename, ft->hdr.name);
1465 ft->file = fopen(buf, "w");
1466 g_free(buf);
1467 if (!ft->file) {
1468 buf = g_strdup_printf("Could not open %s/%s for writing!", ft->filename,
1469 ft->hdr.name);
1470 do_error_dialog(buf, _("Error"));
1471 g_free(buf);
1472 gdk_input_remove(ft->inpa);
1473 close(source);
1474 g_free(ft->filename);
1475 g_free(ft->user);
1476 g_free(ft->ip);
1477 g_free(ft->cookie);
1478 g_free(ft);
1479 }
1480 }
1481
1482 return;
1483 }
1484
1485 rt = read(source, buf, MIN(ntohl(ft->hdr.size) - ft->recvsize, 1024));
1486 if (rt < 0) {
1487 do_error_dialog("File transfer failed; other side probably canceled.", "Error");
1488 gdk_input_remove(ft->inpa);
1489 close(source);
1490 g_free(ft->user);
1491 g_free(ft->ip);
1492 g_free(ft->cookie);
1493 if (ft->file)
1494 fclose(ft->file);
1495 g_free(ft);
1496 return;
1497 }
1498 ft->recvsize += rt;
1499 for (i = 0; i < rt; i++)
1500 fprintf(ft->file, "%c", buf[i]);
1501
1502 if (ft->recvsize == ntohl(ft->hdr.size)) {
1503 ft->hdr.hdrtype = htons(0x0204);
1504 ft->hdr.filesleft = htons(ntohs(ft->hdr.filesleft) - 1);
1505 ft->hdr.partsleft = htons(ntohs(ft->hdr.partsleft) - 1);
1506 ft->hdr.recvcsum = ft->hdr.checksum; /* uh... */
1507 ft->hdr.nrecvd = htons(ntohs(ft->hdr.nrecvd) + 1);
1508 ft->hdr.flags = 0;
1509 write(source, ft, 256);
1510 debug_header(ft);
1511 ft->recvsize = 0;
1512 fclose(ft->file);
1513 if (ft->hdr.filesleft == 0) {
1514 gdk_input_remove(ft->inpa);
1515 close(source);
1516 g_free(ft->filename);
1517 g_free(ft->user);
1518 g_free(ft->ip);
1519 g_free(ft->cookie);
1520 g_free(ft);
1521 }
1522 }
1523 }
1524
1525 static void toc_send_file_connect(gpointer data, gint src, GdkInputCondition cond)
1526 {
1527 struct file_transfer *ft = data;
1528
1529 if (src == -1) {
1530 do_error_dialog(_("Could not connect for transfer!"), _("Error"));
1531 g_free(ft->filename);
1532 g_free(ft->cookie);
1533 g_free(ft->user);
1534 g_free(ft->ip);
1535 g_free(ft);
1536 return;
1537 }
1538
1539 ft->inpa = gdk_input_add(src, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_send_file_callback, ft);
1540 }
1541
1542 static void toc_send_file(gpointer a, struct file_transfer *old_ft)
1543 {
1544 struct file_transfer *ft;
1545 const char *dirname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(old_ft->window));
1546 int fd;
1547 struct aim_user *user;
1548 char buf[BUF_LEN * 2];
1549
1550 if (file_is_dir(dirname, old_ft->window))
1551 return;
1552 ft = g_new0(struct file_transfer, 1);
1553 if (old_ft->files == 1)
1554 ft->filename = g_strdup(dirname);
1555 else
1556 ft->filename = g_dirname(dirname);
1557 ft->cookie = g_strdup(old_ft->cookie);
1558 ft->user = g_strdup(old_ft->user);
1559 ft->ip = g_strdup(old_ft->ip);
1560 ft->files = old_ft->files;
1561 ft->port = old_ft->port;
1562 ft->gc = old_ft->gc;
1563 user = ft->gc->user;
1564 gtk_widget_destroy(old_ft->window);
1565
1566 g_snprintf(buf, sizeof(buf), "toc_rvous_accept %s %s %s", ft->user, ft->cookie, FILE_SEND_UID);
1567 sflap_send(ft->gc, buf, -1, TYPE_DATA);
1568
1569 fd =
1570 proxy_connect(ft->ip, ft->port, toc_send_file_connect, ft);
1571 if (fd < 0) {
1572 do_error_dialog(_("Could not connect for transfer!"), _("Error"));
1573 g_free(ft->filename);
1574 g_free(ft->cookie);
1575 g_free(ft->user);
1576 g_free(ft->ip);
1577 g_free(ft);
1578 return;
1579 }
1580 }
1581
1582 static void toc_get_file_callback(gpointer data, gint source, GdkInputCondition cond)
1583 {
1584 char buf[BUF_LONG];
1585
1586 struct file_transfer *ft = data;
1587
1588 if (cond & GDK_INPUT_EXCEPTION) {
1589 do_error_dialog("The file tranfer has been aborted; the other side most likely"
1590 " cancelled.", "Error");
1591 gdk_input_remove(ft->inpa);
1592 close(source);
1593 g_free(ft->filename);
1594 g_free(ft->user);
1595 g_free(ft->ip);
1596 g_free(ft->cookie);
1597 if (ft->file)
1598 fclose(ft->file);
1599 g_free(ft);
1600 return;
1601 }
1602
1603 if (cond & GDK_INPUT_WRITE) {
1604 int remain = MIN(ntohl(ft->hdr.totsize) - ft->recvsize, 1024);
1605 int i;
1606 for (i = 0; i < remain; i++)
1607 fscanf(ft->file, "%c", &buf[i]);
1608 write(source, buf, remain);
1609 ft->recvsize += remain;
1610 if (ft->recvsize == ntohl(ft->hdr.totsize)) {
1611 gdk_input_remove(ft->inpa);
1612 ft->inpa = gdk_input_add(source, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
1613 toc_get_file_callback, ft);
1614 }
1615 return;
1616 }
1617
1618 if (ft->hdr.hdrtype == htons(0x1108)) {
1619 struct tm *fortime;
1620 struct stat st;
1621
1622 read(source, ft, 8);
1623 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8));
1624 debug_header(ft);
1625
1626 stat(ft->filename, &st);
1627 fortime = localtime(&st.st_mtime);
1628 g_snprintf(buf, sizeof(buf), "%2d/%2d/%4d %2d:%2d %8ld %s\r\n",
1629 fortime->tm_mon + 1, fortime->tm_mday, fortime->tm_year + 1900,
1630 fortime->tm_hour + 1, fortime->tm_min + 1, (long)st.st_size,
1631 g_basename(ft->filename));
1632 write(source, buf, ntohl(ft->hdr.size));
1633 return;
1634 }
1635
1636 if (ft->hdr.hdrtype == htons(0x1209)) {
1637 read(source, ft, 8);
1638 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8));
1639 debug_header(ft);
1640 return;
1641 }
1642
1643 if (ft->hdr.hdrtype == htons(0x120b)) {
1644 read(source, ft, 8);
1645 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8));
1646 debug_header(ft);
1647
1648 if (ft->hdr.hdrtype != htons(0x120c)) {
1649 g_snprintf(buf, sizeof(buf), "%s decided to cancel the transfer", ft->user);
1650 do_error_dialog(buf, "Error");
1651 gdk_input_remove(ft->inpa);
1652 close(source);
1653 g_free(ft->filename);
1654 g_free(ft->user);
1655 g_free(ft->ip);
1656 g_free(ft->cookie);
1657 if (ft->file)
1658 fclose(ft->file);
1659 g_free(ft);
1660 return;
1661 }
1662
1663 ft->hdr.hdrtype = 0x0101;
1664 ft->hdr.totfiles = htons(1); ft->hdr.filesleft = htons(1);
1665 ft->hdr.flags = 0x20;
1666 write(source, ft, 256);
1667 return;
1668 }
1669
1670 if (ft->hdr.hdrtype == 0x0101) {
1671 read(source, ft, 8);
1672 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8));
1673 debug_header(ft);
1674
1675 gdk_input_remove(ft->inpa);
1676 ft->inpa = gdk_input_add(source, GDK_INPUT_WRITE | GDK_INPUT_EXCEPTION,
1677 toc_get_file_callback, ft);
1678 return;
1679 }
1680
1681 if (ft->hdr.hdrtype == 0x0202) {
1682 read(source, ft, 8);
1683 read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8));
1684 debug_header(ft);
1685
1686 gdk_input_remove(ft->inpa);
1687 close(source);
1688 g_free(ft->filename);
1689 g_free(ft->user);
1690 g_free(ft->ip);
1691 g_free(ft->cookie);
1692 if (ft->file)
1693 fclose(ft->file);
1694 g_free(ft);
1695 return;
1696 }
1697 }
1698
1699 static void toc_get_file_connect(gpointer data, gint src, GdkInputCondition cond)
1700 {
1701 struct file_transfer *ft = data;
1702 struct file_header *hdr;
1703 char *buf;
1704
1705 if (src == -1) {
1706 do_error_dialog(_("Could not connect for transfer!"), _("Error"));
1707 fclose(ft->file);
1708 g_free(ft->filename);
1709 g_free(ft->cookie);
1710 g_free(ft->user);
1711 g_free(ft->ip);
1712 g_free(ft);
1713 return;
1714 }
1715
1716 hdr = (struct file_header *)ft;
1717 hdr->magic[0] = 'O'; hdr->magic[1] = 'F'; hdr->magic[2] = 'T'; hdr->magic[3] = '2';
1718 hdr->hdrlen = htons(256);
1719 hdr->hdrtype = htons(0x1108);
1720 frombase64(ft->cookie, &buf, NULL);
1721 g_snprintf(hdr->bcookie, 8, "%s", buf);
1722 g_free(buf);
1723 hdr->totfiles = htons(1); hdr->filesleft = htons(1);
1724 hdr->totparts = htons(1); hdr->partsleft = htons(1);
1725 hdr->totsize = htonl((long)ft->st.st_size); /* combined size of all files */
1726 /* size = strlen("mm/dd/yyyy hh:mm sizesize 'name'\r\n") */
1727 hdr->size = htonl(28 + strlen(g_basename(ft->filename))); /* size of listing.txt */
1728 hdr->modtime = htonl(ft->st.st_mtime);
1729 hdr->checksum = htonl(0x89f70000); /* uh... */
1730 g_snprintf(hdr->idstring, 32, "OFT_Windows ICBMFT V1.1 32");
1731 hdr->flags = 0x02;
1732 hdr->lnameoffset = 0x1A;
1733 hdr->lsizeoffset = 0x10;
1734 g_snprintf(hdr->name, 64, "listing.txt");
1735 if (write(src, hdr, 256) < 0) {
1736 do_error_dialog(_("Could not write file header!"), _("Error"));
1737 fclose(ft->file);
1738 g_free(ft->filename);
1739 g_free(ft->cookie);
1740 g_free(ft->user);
1741 g_free(ft->ip);
1742 g_free(ft);
1743 return;
1744 }
1745
1746 ft->inpa = gdk_input_add(src, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_get_file_callback, ft);
1747 }
1748
1749 static void toc_get_file(gpointer a, struct file_transfer *old_ft)
1750 {
1751 struct file_transfer *ft;
1752 const char *dirname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(old_ft->window));
1753 int fd;
1754 struct aim_user *user;
1755 char *buf, buf2[BUF_LEN * 2];
1756
1757 if (file_is_dir(dirname, old_ft->window))
1758 return;
1759 ft = g_new0(struct file_transfer, 1);
1760 ft->filename = g_strdup(dirname);
1761 ft->file = fopen(ft->filename, "r");
1762 if (!ft->file) {
1763 buf = g_strdup_printf("Unable to open %s for transfer!", ft->filename);
1764 do_error_dialog(buf, "Error");
1765 g_free(buf);
1766 g_free(ft->filename);
1767 g_free(ft);
1768 return;
1769 }
1770 if (stat(dirname, &ft->st)) {
1771 buf = g_strdup_printf("Unable to examine %s!", dirname);
1772 do_error_dialog(buf, "Error");
1773 g_free(buf);
1774 g_free(ft->filename);
1775 g_free(ft);
1776 return;
1777 }
1778 ft->cookie = g_strdup(old_ft->cookie);
1779 ft->user = g_strdup(old_ft->user);
1780 ft->ip = g_strdup(old_ft->ip);
1781 ft->port = old_ft->port;
1782 ft->gc = old_ft->gc;
1783 user = ft->gc->user;
1784 gtk_widget_destroy(old_ft->window);
1785
1786 g_snprintf(buf2, sizeof(buf2), "toc_rvous_accept %s %s %s", ft->user, ft->cookie, FILE_GET_UID);
1787 sflap_send(ft->gc, buf2, -1, TYPE_DATA);
1788
1789 fd =
1790 proxy_connect(ft->ip, ft->port, toc_get_file_connect, ft);
1791 if (fd < 0) {
1792 do_error_dialog(_("Could not connect for transfer!"), _("Error"));
1793 fclose(ft->file);
1794 g_free(ft->filename);
1795 g_free(ft->cookie);
1796 g_free(ft->user);
1797 g_free(ft->ip);
1798 g_free(ft);
1799 return;
1800 }
1801 }
1802
1803 static void cancel_callback(gpointer a, struct file_transfer *ft) {
1804 gtk_widget_destroy(ft->window);
1805 if (a == ft->window) {
1806 g_free(ft->cookie);
1807 g_free(ft->user);
1808 g_free(ft->ip);
1809 g_free(ft);
1810 }
1811 }
1812
1813 static void toc_accept_ft(gpointer a, struct ft_request *fr) {
1814 GtkWidget *window;
1815 char buf[BUF_LEN];
1816
1817 struct file_transfer *ft = g_new0(struct file_transfer, 1);
1818 ft->gc = fr->gc;
1819 ft->user = g_strdup(fr->user);
1820 ft->cookie = g_strdup(fr->cookie);
1821 ft->ip = g_strdup(fr->ip);
1822 ft->port = fr->port;
1823 ft->files = fr->files;
1824
1825 ft->window = window = gtk_file_selection_new(_("Gaim - Save As..."));
1826 g_snprintf(buf, sizeof(buf), "%s/%s", g_get_home_dir(), fr->filename ? fr->filename : "");
1827 gtk_file_selection_set_filename(GTK_FILE_SELECTION(window), buf);
1828 gtk_signal_connect(GTK_OBJECT(window), "destroy",
1829 GTK_SIGNAL_FUNC(cancel_callback), ft);
1830 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(ft->window)->cancel_button), "clicked",
1831 GTK_SIGNAL_FUNC(cancel_callback), ft);
1832
1833 if (!strcmp(fr->UID, FILE_SEND_UID))
1834 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button), "clicked",
1835 GTK_SIGNAL_FUNC(toc_send_file), ft);
1836 else
1837 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button), "clicked",
1838 GTK_SIGNAL_FUNC(toc_get_file), ft);
1839
1840 gtk_widget_show(window);
1841 }
1842
1843 static void toc_reject_ft(gpointer a, struct ft_request *ft) {
1844 g_free(ft->user);
1845 g_free(ft->filename);
1846 g_free(ft->ip);
1847 g_free(ft->cookie);
1848 if (ft->message)
1849 g_free(ft->message);
1850 g_free(ft);
1851 }
1852
1853 static void accept_file_dialog(struct ft_request *ft) {
1854 char buf[BUF_LONG];
1855 if (!strcmp(ft->UID, FILE_SEND_UID)) {
1856 /* holy crap. who the fuck would transfer gigabytes through AIM?! */
1857 static char *sizes[4] = { "bytes", "KB", "MB", "GB" };
1858 float size = ft->size;
1859 int index = 0;
1860 while ((index < 4) && (size > 1024)) {
1861 size /= 1024;
1862 index++;
1863 }
1864 g_snprintf(buf, sizeof(buf), _("%s requests %s to accept %d file%s: %s (%.2f %s)%s%s"),
1865 ft->user, ft->gc->username, ft->files, (ft->files == 1) ? "" : "s",
1866 ft->filename, size, sizes[index], (ft->message) ? "\n" : "",
1867 (ft->message) ? ft->message : "");
1868 } else {
1869 g_snprintf(buf, sizeof(buf), _("%s requests you to send them a file"), ft->user);
1870 }
1871 do_ask_dialog(buf, ft, toc_accept_ft, toc_reject_ft);
1872 }

mercurial