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