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