2086
|
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 }
|