2681
|
1 /*
|
|
2 * gaim
|
|
3 *
|
|
4 * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
|
|
5 * libfaim code copyright 1998, 1999 Adam Fritzler <afritz@auk.cx>
|
|
6 *
|
|
7 * This program is free software; you can redistribute it and/or modify
|
|
8 * it under the terms of the GNU General Public License as published by
|
|
9 * the Free Software Foundation; either version 2 of the License, or
|
|
10 * (at your option) any later version.
|
|
11 *
|
|
12 * This program is distributed in the hope that it will be useful,
|
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15 * GNU General Public License for more details.
|
|
16 *
|
|
17 * You should have received a copy of the GNU General Public License
|
|
18 * along with this program; if not, write to the Free Software
|
|
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
20 *
|
|
21 */
|
|
22
|
|
23 #ifdef HAVE_CONFIG_H
|
|
24 #include "config.h"
|
|
25 #endif
|
|
26
|
|
27
|
|
28 #include <netdb.h>
|
|
29 #include <unistd.h>
|
|
30 #include <errno.h>
|
|
31 #include <netinet/in.h>
|
|
32 #include <arpa/inet.h>
|
|
33 #include <string.h>
|
|
34 #include <stdlib.h>
|
|
35 #include <stdio.h>
|
|
36 #include <time.h>
|
|
37 #include <sys/socket.h>
|
|
38 #include <sys/stat.h>
|
|
39 #include <ctype.h>
|
|
40 #include <crypt.h>
|
|
41 #include "multi.h"
|
|
42 #include "prpl.h"
|
|
43 #include "gaim.h"
|
|
44 #include "proxy.h"
|
|
45
|
|
46 #include "pixmaps/status-away.xpm"
|
|
47 #include "pixmaps/status-here.xpm"
|
|
48 #include "pixmaps/status-idle.xpm"
|
|
49
|
|
50 #define YAHOO_DEBUG
|
|
51
|
|
52 #define USEROPT_MAIL 0
|
|
53
|
|
54 #define USEROPT_PAGERHOST 3
|
|
55 #define YAHOO_PAGER_HOST "scs.yahoo.com"
|
|
56 #define USEROPT_PAGERPORT 4
|
|
57 #define YAHOO_PAGER_PORT 5050
|
|
58
|
|
59 enum yahoo_service {
|
|
60 YAHOO_SERVICE_LOGON = 1,
|
|
61 YAHOO_SERVICE_LOGOFF,
|
|
62 YAHOO_SERVICE_ISAWAY,
|
|
63 YAHOO_SERVICE_ISBACK,
|
|
64 YAHOO_SERVICE_IDLE,
|
|
65 YAHOO_SERVICE_MESSAGE,
|
|
66 YAHOO_SERVICE_IDACT,
|
|
67 YAHOO_SERVICE_IDDEACT,
|
|
68 YAHOO_SERVICE_MAILSTAT,
|
|
69 YAHOO_SERVICE_USERSTAT,
|
|
70 YAHOO_SERVICE_NEWMAIL,
|
|
71 YAHOO_SERVICE_CHATINVITE,
|
|
72 YAHOO_SERVICE_CALENDAR,
|
|
73 YAHOO_SERVICE_NEWPERSONALMAIL,
|
|
74 YAHOO_SERVICE_NEWCONTACT,
|
|
75 YAHOO_SERVICE_ADDIDENT,
|
|
76 YAHOO_SERVICE_ADDIGNORE,
|
|
77 YAHOO_SERVICE_PING,
|
|
78 YAHOO_SERVICE_GROUPRENAME,
|
|
79 YAHOO_SERVICE_SYSMESSAGE = 20,
|
|
80 YAHOO_SERVICE_PASSTHROUGH2 = 22,
|
|
81 YAHOO_SERVICE_CONFINVITE = 24,
|
|
82 YAHOO_SERVICE_CONFLOGON,
|
|
83 YAHOO_SERVICE_CONFDECLINE,
|
|
84 YAHOO_SERVICE_CONFLOGOFF,
|
|
85 YAHOO_SERVICE_CONFADDINVITE,
|
|
86 YAHOO_SERVICE_CONFMSG,
|
|
87 YAHOO_SERVICE_CHATLOGON,
|
|
88 YAHOO_SERVICE_CHATLOGOFF,
|
|
89 YAHOO_SERVICE_CHATMSG = 32,
|
|
90 YAHOO_SERVICE_GAMELOGON = 40,
|
|
91 YAHOO_SERVICE_GAMELOGOFF = 41,
|
|
92 YAHOO_SERVICE_FILETRANSFER = 70,
|
|
93 YAHOO_SERVICE_LIST = 85,
|
|
94 YAHOO_SERVICE_ADDBUDDY = 131,
|
|
95 YAHOO_SERVICE_REMBUDDY = 132
|
|
96 };
|
|
97
|
|
98 enum yahoo_status {
|
|
99 YAHOO_STATUS_AVAILABLE,
|
|
100 YAHOO_STATUS_BRB,
|
|
101 YAHOO_STATUS_BUSY,
|
|
102 YAHOO_STATUS_NOTATHOME,
|
|
103 YAHOO_STATUS_NOTATDESK,
|
|
104 YAHOO_STATUS_NOTINOFFICE,
|
|
105 YAHOO_STATUS_ONPHONE,
|
|
106 YAHOO_STATUS_ONVACATION,
|
|
107 YAHOO_STATUS_OUTTOLUNCH,
|
|
108 YAHOO_STATUS_STEPPEDOUT,
|
|
109 YAHOO_STATUS_INVISIBLE = 12,
|
|
110 YAHOO_STATUS_CUSTOM = 99,
|
|
111 YAHOO_STATUS_IDLE = 999,
|
|
112 YAHOO_STATUS_OFFLINE = 0x5a55aa56
|
|
113 };
|
|
114
|
|
115 struct yahoo_data {
|
|
116 int fd;
|
|
117 guchar *rxqueue;
|
|
118 int rxlen;
|
|
119 GHashTable *hash;
|
|
120 GSList *login;
|
|
121 int current_status;
|
|
122 gboolean logged_in;
|
|
123 };
|
|
124
|
|
125 struct yahoo_pair {
|
|
126 int key;
|
|
127 char *value;
|
|
128 };
|
|
129
|
|
130 struct yahoo_packet {
|
|
131 guint16 service;
|
|
132 guint32 status;
|
|
133 guint32 id;
|
|
134 GSList *hash;
|
|
135 };
|
|
136
|
|
137 struct yahoo_buddy {
|
|
138 char *name;
|
|
139 int state;
|
|
140 char *msg;
|
|
141 };
|
|
142
|
|
143 static char *yahoo_name() {
|
|
144 return "Yahoo";
|
|
145 }
|
|
146
|
|
147 #define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4)
|
|
148
|
|
149 static struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, enum yahoo_status status, int id)
|
|
150 {
|
|
151 struct yahoo_packet *pkt = g_new0(struct yahoo_packet, 1);
|
|
152
|
|
153 pkt->service = service;
|
|
154 pkt->status = status;
|
|
155 pkt->id = id;
|
|
156
|
|
157 return pkt;
|
|
158 }
|
|
159
|
|
160 static void yahoo_packet_hash(struct yahoo_packet *pkt, int key, char *value)
|
|
161 {
|
|
162 struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1);
|
|
163 pair->key = key;
|
|
164 pair->value = g_strdup(value);
|
|
165 pkt->hash = g_slist_append(pkt->hash, pair);
|
|
166 }
|
|
167
|
|
168 static int yahoo_packet_length(struct yahoo_packet *pkt)
|
|
169 {
|
|
170 GSList *l;
|
|
171
|
|
172 int len = 0;
|
|
173
|
|
174 l = pkt->hash;
|
|
175 while (l) {
|
|
176 struct yahoo_pair *pair = l->data;
|
|
177 int tmp = pair->key;
|
|
178 do {
|
|
179 tmp /= 10;
|
|
180 len++;
|
|
181 } while (tmp);
|
|
182 len += 2;
|
|
183 len += strlen(pair->value);
|
|
184 len += 2;
|
|
185 l = l->next;
|
|
186 }
|
|
187
|
|
188 return len;
|
|
189 }
|
|
190
|
|
191 /* sometimes i wish prpls could #include things from other prpls. then i could just
|
|
192 * use the routines from libfaim and not have to admit to knowing how they work. */
|
|
193 #define yahoo_put16(buf, data) ( \
|
|
194 (*(buf) = (u_char)((data)>>8)&0xff), \
|
|
195 (*((buf)+1) = (u_char)(data)&0xff), \
|
|
196 2)
|
|
197 #define yahoo_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff))
|
|
198 #define yahoo_put32(buf, data) ( \
|
|
199 (*((buf)) = (u_char)((data)>>24)&0xff), \
|
|
200 (*((buf)+1) = (u_char)((data)>>16)&0xff), \
|
|
201 (*((buf)+2) = (u_char)((data)>>8)&0xff), \
|
|
202 (*((buf)+3) = (u_char)(data)&0xff), \
|
|
203 4)
|
|
204 #define yahoo_get32(buf) ((((*(buf))<<24)&0xff000000) + \
|
|
205 (((*((buf)+1))<<16)&0x00ff0000) + \
|
|
206 (((*((buf)+2))<< 8)&0x0000ff00) + \
|
|
207 (((*((buf)+3) )&0x000000ff)))
|
|
208
|
|
209 static void yahoo_packet_read(struct yahoo_packet *pkt, guchar *data, int len)
|
|
210 {
|
|
211 int pos = 0;
|
|
212
|
|
213 while (pos + 1 < len) {
|
|
214 char key[64], *value;
|
|
215 int x;
|
|
216
|
|
217 struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1);
|
|
218 pkt->hash = g_slist_append(pkt->hash, pair);
|
|
219
|
|
220 x = 0;
|
|
221 while (pos + 1 < len) {
|
|
222 if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
|
|
223 break;
|
|
224 key[x++] = data[pos++];
|
|
225 }
|
|
226 key[x] = 0;
|
|
227 pos += 2;
|
|
228 pair->key = strtol(key, NULL, 10);
|
|
229
|
|
230 value = g_malloc(len - pos);
|
|
231 x = 0;
|
|
232 while (pos + 1 < len) {
|
|
233 if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
|
|
234 break;
|
|
235 value[x++] = data[pos++];
|
|
236 }
|
|
237 value[x] = 0;
|
|
238 pos += 2;
|
|
239 pair->value = g_strdup(value);
|
|
240 g_free(value);
|
|
241 debug_printf("Key: %d \tValue: %s\n", pair->key, pair->value);
|
|
242 }
|
|
243 }
|
|
244
|
|
245 static void yahoo_packet_write(struct yahoo_packet *pkt, guchar *data)
|
|
246 {
|
|
247 GSList *l = pkt->hash;
|
|
248 int pos = 0;
|
|
249
|
|
250 while (l) {
|
|
251 struct yahoo_pair *pair = l->data;
|
|
252 guchar buf[100];
|
|
253
|
|
254 g_snprintf(buf, sizeof(buf), "%d", pair->key);
|
|
255 strcpy(data + pos, buf);
|
|
256 pos += strlen(buf);
|
|
257 data[pos++] = 0xc0;
|
|
258 data[pos++] = 0x80;
|
|
259
|
|
260 strcpy(data + pos, pair->value);
|
|
261 pos += strlen(pair->value);
|
|
262 data[pos++] = 0xc0;
|
|
263 data[pos++] = 0x80;
|
|
264
|
|
265 l = l->next;
|
|
266 }
|
|
267 }
|
|
268
|
|
269 static void yahoo_packet_dump(guchar *data, int len)
|
|
270 {
|
|
271 #ifdef YAHOO_DEBUG
|
|
272 int i;
|
|
273 for (i = 0; i + 1 < len; i += 2) {
|
|
274 if ((i % 16 == 0) && i)
|
|
275 debug_printf("\n");
|
|
276 debug_printf("%02x", data[i]);
|
|
277 debug_printf("%02x ", data[i+1]);
|
|
278 }
|
|
279 if (i < len)
|
|
280 debug_printf("%02x", data[i]);
|
|
281 debug_printf("\n");
|
|
282 for (i = 0; i < len; i++) {
|
|
283 if ((i % 16 == 0) && i)
|
|
284 debug_printf("\n");
|
|
285 if (isprint(data[i]))
|
|
286 debug_printf("%c ", data[i]);
|
|
287 else
|
|
288 debug_printf(". ");
|
|
289 }
|
|
290 debug_printf("\n");
|
|
291 #endif
|
|
292 }
|
|
293
|
|
294 static int yahoo_send_packet(struct yahoo_data *yd, struct yahoo_packet *pkt)
|
|
295 {
|
|
296 int pktlen = yahoo_packet_length(pkt);
|
|
297 int len = YAHOO_PACKET_HDRLEN + pktlen;
|
|
298 int ret;
|
|
299
|
|
300 guchar *data;
|
|
301 int pos = 0;
|
|
302
|
|
303 if (yd->fd < 0)
|
|
304 return -1;
|
|
305
|
|
306 data = g_malloc0(len + 1);
|
|
307
|
|
308 memcpy(data + pos, "YMSG", 4); pos += 4;
|
|
309 pos += yahoo_put16(data + pos, 0x0600);
|
|
310 pos += yahoo_put16(data + pos, 0x0000);
|
|
311 pos += yahoo_put16(data + pos, pktlen);
|
|
312 pos += yahoo_put16(data + pos, pkt->service);
|
|
313 pos += yahoo_put32(data + pos, pkt->status);
|
|
314 pos += yahoo_put32(data + pos, pkt->id);
|
|
315
|
|
316 yahoo_packet_write(pkt, data + pos);
|
|
317
|
|
318 yahoo_packet_dump(data, len);
|
|
319 ret = write(yd->fd, data, len);
|
|
320
|
|
321 g_free(data);
|
|
322
|
|
323 return ret;
|
|
324 }
|
|
325
|
|
326 static void yahoo_packet_free(struct yahoo_packet *pkt)
|
|
327 {
|
|
328 while (pkt->hash) {
|
|
329 struct yahoo_pair *pair = pkt->hash->data;
|
|
330 g_free(pair->value);
|
|
331 g_free(pair);
|
|
332 pkt->hash = g_slist_remove(pkt->hash, pair);
|
|
333 }
|
|
334 g_free(pkt);
|
|
335 }
|
|
336
|
|
337 static void yahoo_process_logon(struct gaim_connection *gc, struct yahoo_packet *pkt)
|
|
338 {
|
|
339 struct yahoo_data *yd = gc->proto_data;
|
|
340 GSList *l = pkt->hash;
|
|
341 struct yahoo_buddy *buddy = NULL;
|
|
342 struct yahoo_packet *newpkt;
|
|
343 char *name = NULL;
|
|
344 int state = 0;
|
|
345 char *msg = NULL;
|
|
346
|
|
347 while (l) {
|
|
348 struct yahoo_pair *pair = l->data;
|
|
349
|
|
350 switch (pair->key) {
|
|
351 case 0: /* we won't actually do anything with this */
|
|
352 break;
|
|
353 case 1: /* we don't get the full buddy list here. */
|
|
354 account_online(gc);
|
|
355 serv_finish_login(gc);
|
|
356 g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", pair->value);
|
|
357 do_import(gc, NULL);
|
|
358 yd->logged_in = TRUE;
|
|
359
|
|
360 /* this requests the list. i have a feeling that this is very evil */
|
|
361 newpkt = yahoo_packet_new(YAHOO_SERVICE_LIST, YAHOO_STATUS_OFFLINE, 0);
|
|
362 yahoo_send_packet(yd, newpkt);
|
|
363 yahoo_packet_free(newpkt);
|
|
364
|
|
365 break;
|
|
366 case 8: /* how many online buddies we have */
|
|
367 break;
|
|
368 case 7: /* the current buddy */
|
|
369 name = pair->value;
|
|
370 break;
|
|
371 case 10: /* state */
|
|
372 state = strtol(pair->value, NULL, 10);
|
|
373 break;
|
|
374 case 19: /* custom message */
|
|
375 msg = pair->value;
|
|
376 break;
|
|
377 case 11: /* i didn't know what this was in the old protocol either */
|
|
378 break;
|
|
379 case 17: /* in chat? */
|
|
380 break;
|
|
381 case 13: /* in pager, i think this should always be 1 */
|
|
382 /* we don't actually give notification here. we wait until after we've
|
|
383 * gotten the list, so that they get added to the right group */
|
|
384 buddy = g_new0(struct yahoo_buddy, 1);
|
|
385 buddy->name = g_strdup(name);
|
|
386 buddy->state = state;
|
|
387 buddy->msg = msg ? g_strdup(msg) : NULL;
|
|
388 yd->login = g_slist_append(yd->login, buddy);
|
|
389 break;
|
|
390 default:
|
|
391 debug_printf("unknown login key %d\n", pair->key);
|
|
392 break;
|
|
393 }
|
|
394
|
|
395 l = l->next;
|
|
396 }
|
|
397 }
|
|
398
|
|
399 static void yahoo_process_list(struct gaim_connection *gc, struct yahoo_packet *pkt)
|
|
400 {
|
|
401 struct yahoo_data *yd = gc->proto_data;
|
|
402 GSList *l = pkt->hash;
|
|
403 gboolean export = FALSE;
|
|
404
|
|
405 while (l) {
|
|
406 char **lines;
|
|
407 char **split;
|
|
408 char **buddies;
|
|
409 char **tmp, **bud;
|
|
410
|
|
411 struct yahoo_pair *pair = l->data;
|
|
412 l = l->next;
|
|
413
|
|
414 if (pair->key != 87)
|
|
415 continue;
|
|
416
|
|
417 lines = g_strsplit(pair->value, "\n", -1);
|
|
418 for (tmp = lines; *tmp; tmp++) {
|
|
419 split = g_strsplit(*tmp, ":", 2);
|
|
420 buddies = g_strsplit(split[1], ",", -1);
|
|
421 for (bud = buddies; *bud; bud++)
|
|
422 if (!find_buddy(gc, *bud)) {
|
|
423 add_buddy(gc, split[0], *bud, *bud);
|
|
424 export = TRUE;
|
|
425 }
|
|
426 g_strfreev(buddies);
|
|
427 g_strfreev(split);
|
|
428 }
|
|
429 g_strfreev(lines);
|
|
430 }
|
|
431
|
|
432 if (export)
|
|
433 do_export(gc);
|
|
434
|
|
435 while (yd->login) {
|
|
436 struct yahoo_buddy *buddy = yd->login->data;
|
|
437 int status = buddy->state;
|
|
438 yd->login = g_slist_remove(yd->login, buddy);
|
|
439 if (status == YAHOO_STATUS_AVAILABLE)
|
|
440 serv_got_update(gc, buddy->name, 1, 0, 0, 0, 0, 0);
|
|
441 else if (status == YAHOO_STATUS_IDLE)
|
|
442 serv_got_update(gc, buddy->name, 1, 0, 0, time(NULL) - 600, (status << 1), 0);
|
|
443 else
|
|
444 serv_got_update(gc, buddy->name, 1, 0, 0, 0, (status << 1) | UC_UNAVAILABLE, 0);
|
|
445 if (status == YAHOO_STATUS_CUSTOM) {
|
|
446 gpointer val = g_hash_table_lookup(yd->hash, buddy->name);
|
|
447 if (val) {
|
|
448 g_free(val);
|
|
449 g_hash_table_insert(yd->hash, buddy->name, g_strdup(buddy->msg));
|
|
450 } else
|
|
451 g_hash_table_insert(yd->hash, g_strdup(buddy->name), g_strdup(buddy->msg));
|
|
452 }
|
|
453 g_free(buddy->msg);
|
|
454 g_free(buddy->name);
|
|
455 g_free(buddy);
|
|
456 }
|
|
457 }
|
|
458
|
|
459 static void yahoo_process_message(struct gaim_connection *gc, struct yahoo_packet *pkt)
|
|
460 {
|
|
461 char *msg = NULL;
|
|
462 char *from = NULL;
|
|
463 time_t tm = time(NULL);
|
|
464 GSList *l = pkt->hash;
|
|
465
|
|
466 while (l) {
|
|
467 struct yahoo_pair *pair = l->data;
|
|
468 if (pair->key == 4)
|
|
469 from = pair->value;
|
|
470 if (pair->key == 14)
|
|
471 msg = pair->value;
|
|
472 if (pair->key == 15)
|
|
473 tm = strtol(pair->value, NULL, 10);
|
|
474 l = l->next;
|
|
475 }
|
|
476
|
|
477 if (pkt->status == 1) {
|
|
478 strip_linefeed(msg);
|
|
479 serv_got_im(gc, from, msg, 0, tm);
|
|
480 } else if (pkt->status == 2) {
|
|
481 do_error_dialog(_("Your message did not get sent."), _("Gaim - Error"));
|
|
482 }
|
|
483 }
|
|
484
|
|
485 static void yahoo_process_status(struct gaim_connection *gc, struct yahoo_packet *pkt)
|
|
486 {
|
|
487 struct yahoo_data *yd = gc->proto_data;
|
|
488 GSList *l = pkt->hash;
|
|
489 char *name = NULL;
|
|
490 int state = 0;
|
|
491 char *msg = NULL;
|
|
492
|
|
493 while (l) {
|
|
494 struct yahoo_pair *pair = l->data;
|
|
495
|
|
496 switch (pair->key) {
|
|
497 case 7:
|
|
498 name = pair->value;
|
|
499 break;
|
|
500 case 10:
|
|
501 state = strtol(pair->value, NULL, 10);
|
|
502 break;
|
|
503 case 19:
|
|
504 msg = pair->value;
|
|
505 break;
|
|
506 case 11: /* i didn't know what this was in the old protocol either */
|
|
507 break;
|
|
508 case 17: /* in chat? */
|
|
509 break;
|
|
510 case 13:
|
|
511 if (strtol(pair->value, NULL, 10) != 1) {
|
|
512 serv_got_update(gc, name, 0, 0, 0, 0, 0, 0);
|
|
513 break;
|
|
514 }
|
|
515 if (state == YAHOO_STATUS_AVAILABLE)
|
|
516 serv_got_update(gc, name, 1, 0, 0, 0, 0, 0);
|
|
517 else if (state == YAHOO_STATUS_IDLE)
|
|
518 serv_got_update(gc, name, 1, 0, 0, time(NULL) - 600, (state << 1), 0);
|
|
519 else
|
|
520 serv_got_update(gc, name, 1, 0, 0, 0, (state << 1) | UC_UNAVAILABLE, 0);
|
|
521 if (state == YAHOO_STATUS_CUSTOM) {
|
|
522 gpointer val = g_hash_table_lookup(yd->hash, name);
|
|
523 if (val) {
|
|
524 g_free(val);
|
|
525 g_hash_table_insert(yd->hash, name, g_strdup(msg));
|
|
526 } else
|
|
527 g_hash_table_insert(yd->hash, g_strdup(name), g_strdup(msg));
|
|
528 }
|
|
529 break;
|
|
530 }
|
|
531
|
|
532 l = l->next;
|
|
533 }
|
|
534 }
|
|
535
|
|
536 static void yahoo_process_contact(struct gaim_connection *gc, struct yahoo_packet *pkt)
|
|
537 {
|
|
538 char *id = NULL;
|
|
539 char *who = NULL;
|
|
540 char *msg = NULL;
|
|
541 GSList *l = pkt->hash;
|
|
542
|
|
543 while (l) {
|
|
544 struct yahoo_pair *pair = l->data;
|
|
545 if (pair->key == 1)
|
|
546 id = pair->value;
|
|
547 else if (pair->key == 3)
|
|
548 who = pair->value;
|
|
549 else if (pair->key == 14)
|
|
550 msg = pair->value;
|
|
551 l = l->next;
|
|
552 }
|
|
553
|
|
554 show_got_added(gc, id, who, NULL, msg);
|
|
555 }
|
|
556
|
|
557 static void yahoo_process_mail(struct gaim_connection *gc, struct yahoo_packet *pkt)
|
|
558 {
|
|
559 char *who = NULL;
|
|
560 char *email = NULL;
|
|
561 char *subj = NULL;
|
|
562 int count = 0;
|
|
563 GSList *l = pkt->hash;
|
|
564
|
|
565 while (l) {
|
|
566 struct yahoo_pair *pair = l->data;
|
|
567 if (pair->key == 9)
|
|
568 count = strtol(pair->value, NULL, 10);
|
|
569 else if (pair->key == 43)
|
|
570 who = pair->value;
|
|
571 else if (pair->key == 42)
|
|
572 email = pair->value;
|
|
573 else if (pair->key == 18)
|
|
574 subj = pair->value;
|
|
575 l = l->next;
|
|
576 }
|
|
577
|
|
578 connection_has_mail(gc, count, NULL, NULL, "http://mail.yahoo.com/");
|
|
579 }
|
|
580
|
|
581 static void yahoo_packet_process(struct gaim_connection *gc, struct yahoo_packet *pkt)
|
|
582 {
|
|
583 switch (pkt->service)
|
|
584 {
|
|
585 case YAHOO_SERVICE_LOGON:
|
|
586 yahoo_process_logon(gc, pkt);
|
|
587 break;
|
|
588 case YAHOO_SERVICE_ISAWAY:
|
|
589 yahoo_process_status(gc, pkt);
|
|
590 break;
|
|
591 case YAHOO_SERVICE_MESSAGE:
|
|
592 yahoo_process_message(gc, pkt);
|
|
593 break;
|
|
594 case YAHOO_SERVICE_NEWMAIL:
|
|
595 yahoo_process_mail(gc, pkt);
|
|
596 break;
|
|
597 case YAHOO_SERVICE_NEWCONTACT:
|
|
598 yahoo_process_contact(gc, pkt);
|
|
599 break;
|
|
600 case YAHOO_SERVICE_LIST:
|
|
601 yahoo_process_list(gc, pkt);
|
|
602 break;
|
|
603 default:
|
|
604 debug_printf("unhandled service %d\n", pkt->service);
|
|
605 break;
|
|
606 }
|
|
607 }
|
|
608
|
|
609 static void yahoo_pending(gpointer data, gint source, GaimInputCondition cond)
|
|
610 {
|
|
611 struct gaim_connection *gc = data;
|
|
612 struct yahoo_data *yd = gc->proto_data;
|
|
613 char buf[1024];
|
|
614 int len;
|
|
615
|
|
616 len = read(yd->fd, buf, sizeof(buf));
|
|
617
|
|
618 if (len <= 0) {
|
|
619 hide_login_progress(gc, "Unable to read");
|
|
620 signoff(gc);
|
|
621 return;
|
|
622 }
|
|
623
|
|
624 yd->rxqueue = g_realloc(yd->rxqueue, len + yd->rxlen);
|
|
625 memcpy(yd->rxqueue + yd->rxlen, buf, len);
|
|
626 yd->rxlen += len;
|
|
627
|
|
628 while (1) {
|
|
629 struct yahoo_packet *pkt;
|
|
630 int pos = 0;
|
|
631 int pktlen;
|
|
632
|
|
633 if (yd->rxlen < YAHOO_PACKET_HDRLEN)
|
|
634 return;
|
|
635
|
|
636 pos += 4; /* YMSG */
|
|
637 pos += 2;
|
|
638 pos += 2;
|
|
639
|
|
640 pktlen = yahoo_get16(yd->rxqueue + pos); pos += 2;
|
|
641 debug_printf("%d bytes to read, rxlen is %d\n", pktlen, yd->rxlen);
|
|
642
|
|
643 if (yd->rxlen < (YAHOO_PACKET_HDRLEN + pktlen))
|
|
644 return;
|
|
645
|
|
646 yahoo_packet_dump(yd->rxqueue, YAHOO_PACKET_HDRLEN + pktlen);
|
|
647
|
|
648 pkt = yahoo_packet_new(0, 0, 0);
|
|
649
|
|
650 pkt->service = yahoo_get16(yd->rxqueue + pos); pos += 2;
|
|
651 debug_printf("Yahoo Service: %d Status: %d\n", pkt->service, pkt->status);
|
|
652 pkt->status = yahoo_get32(yd->rxqueue + pos); pos += 4;
|
|
653 pkt->id = yahoo_get32(yd->rxqueue + pos); pos += 4;
|
|
654
|
|
655 yahoo_packet_read(pkt, yd->rxqueue + pos, pktlen);
|
|
656
|
|
657 yd->rxlen -= YAHOO_PACKET_HDRLEN + pktlen;
|
|
658 if (yd->rxlen) {
|
|
659 char *tmp = g_memdup(yd->rxqueue + YAHOO_PACKET_HDRLEN + pktlen, yd->rxlen);
|
|
660 g_free(yd->rxqueue);
|
|
661 yd->rxqueue = tmp;
|
|
662 } else {
|
|
663 g_free(yd->rxqueue);
|
|
664 yd->rxqueue = NULL;
|
|
665 }
|
|
666
|
|
667 yahoo_packet_process(gc, pkt);
|
|
668
|
|
669 yahoo_packet_free(pkt);
|
|
670 }
|
|
671 }
|
|
672
|
|
673 static void yahoo_got_connected(gpointer data, gint source, GaimInputCondition cond)
|
|
674 {
|
|
675 struct gaim_connection *gc = data;
|
|
676 struct yahoo_data *yd;
|
|
677 struct yahoo_packet *pkt;
|
|
678
|
|
679 if (!g_slist_find(connections, gc)) {
|
|
680 close(source);
|
|
681 return;
|
|
682 }
|
|
683
|
|
684 if (source < 0) {
|
|
685 hide_login_progress(gc, "Unable to connect");
|
|
686 signoff(gc);
|
|
687 return;
|
|
688 }
|
|
689
|
|
690 yd = gc->proto_data;
|
|
691 yd->fd = source;
|
|
692
|
|
693 pkt = yahoo_packet_new(YAHOO_SERVICE_LOGON, YAHOO_STATUS_AVAILABLE, 0);
|
|
694
|
|
695 yahoo_packet_hash(pkt, 0, gc->username);
|
|
696 yahoo_packet_hash(pkt, 1, gc->username);
|
|
697 yahoo_packet_hash(pkt, 6, crypt(gc->password, "$1$_2S43d5f$"));
|
|
698
|
|
699 yahoo_send_packet(yd, pkt);
|
|
700
|
|
701 yahoo_packet_free(pkt);
|
|
702
|
|
703 gc->inpa = gaim_input_add(yd->fd, GAIM_INPUT_READ, yahoo_pending, gc);
|
|
704 }
|
|
705
|
|
706 static void yahoo_login(struct aim_user *user) {
|
|
707 struct gaim_connection *gc = new_gaim_conn(user);
|
|
708 struct yahoo_data *yd = gc->proto_data = g_new0(struct yahoo_data, 1);
|
|
709
|
|
710 set_login_progress(gc, 1, "Connecting");
|
|
711
|
|
712 yd->fd = -1;
|
|
713 yd->hash = g_hash_table_new(g_str_hash, g_str_equal);
|
|
714
|
|
715 if (!proxy_connect(user->proto_opt[USEROPT_PAGERHOST][0] ?
|
|
716 user->proto_opt[USEROPT_PAGERHOST] : YAHOO_PAGER_HOST,
|
|
717 user->proto_opt[USEROPT_PAGERPORT][0] ?
|
|
718 atoi(user->proto_opt[USEROPT_PAGERPORT]) : YAHOO_PAGER_PORT,
|
|
719 yahoo_got_connected, gc)) {
|
|
720 hide_login_progress(gc, "Connection problem");
|
|
721 signoff(gc);
|
|
722 return;
|
|
723 }
|
|
724
|
|
725 }
|
|
726
|
|
727 static gboolean yahoo_destroy_hash(gpointer key, gpointer val, gpointer data)
|
|
728 {
|
|
729 g_free(key);
|
|
730 g_free(val);
|
|
731 return TRUE;
|
|
732 }
|
|
733
|
|
734 static void yahoo_close(struct gaim_connection *gc) {
|
|
735 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
|
|
736 g_hash_table_foreach_remove(yd->hash, yahoo_destroy_hash, NULL);
|
|
737 g_hash_table_destroy(yd->hash);
|
|
738 if (yd->fd >= 0)
|
|
739 close(yd->fd);
|
|
740 if (yd->rxqueue)
|
|
741 g_free(yd->rxqueue);
|
|
742 while (yd->login) {
|
|
743 struct yahoo_buddy *buddy = yd->login->data;
|
|
744 yd->login = g_slist_remove(yd->login, buddy);
|
|
745 g_free(buddy->msg);
|
|
746 g_free(buddy->name);
|
|
747 g_free(buddy);
|
|
748 }
|
|
749 if (gc->inpa)
|
|
750 gaim_input_remove(gc->inpa);
|
|
751 g_free(yd);
|
|
752 }
|
|
753
|
|
754 static char **yahoo_list_icon(int uc)
|
|
755 {
|
|
756 if ((uc >> 1) == YAHOO_STATUS_IDLE)
|
|
757 return status_idle_xpm;
|
|
758 else if (uc == 0)
|
|
759 return status_here_xpm;
|
|
760 return status_away_xpm;
|
|
761 }
|
|
762
|
|
763 static char *yahoo_get_status_string(enum yahoo_status a)
|
|
764 {
|
|
765 switch (a) {
|
|
766 case YAHOO_STATUS_BRB:
|
|
767 return "Be Right Back";
|
|
768 case YAHOO_STATUS_BUSY:
|
|
769 return "Busy";
|
|
770 case YAHOO_STATUS_NOTATHOME:
|
|
771 return "Not At Home";
|
|
772 case YAHOO_STATUS_NOTATDESK:
|
|
773 return "Not At Desk";
|
|
774 case YAHOO_STATUS_NOTINOFFICE:
|
|
775 return "Not In Office";
|
|
776 case YAHOO_STATUS_ONPHONE:
|
|
777 return "On Phone";
|
|
778 case YAHOO_STATUS_ONVACATION:
|
|
779 return "On Vacation";
|
|
780 case YAHOO_STATUS_OUTTOLUNCH:
|
|
781 return "Out To Lunch";
|
|
782 case YAHOO_STATUS_STEPPEDOUT:
|
|
783 return "Stepped Out";
|
|
784 default:
|
|
785 return NULL;
|
|
786 }
|
|
787 }
|
|
788
|
|
789 static GList *yahoo_buddy_menu(struct gaim_connection *gc, char *who)
|
|
790 {
|
|
791 GList *m = NULL;
|
|
792 struct proto_buddy_menu *pbm;
|
|
793 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
|
|
794 struct buddy *b = find_buddy(gc, who); /* this should never be null. if it is,
|
|
795 segfault and get the bug report. */
|
|
796 static char buf[1024];
|
|
797
|
|
798 if (!(b->uc & UC_UNAVAILABLE))
|
|
799 return NULL;
|
|
800
|
|
801 pbm = g_new0(struct proto_buddy_menu, 1);
|
|
802 if ((b->uc >> 1) != YAHOO_STATUS_CUSTOM)
|
|
803 g_snprintf(buf, sizeof buf, "Status: %s", yahoo_get_status_string(b->uc >> 1));
|
|
804 else
|
|
805 g_snprintf(buf, sizeof buf, "Custom Status: %s",
|
|
806 (char *)g_hash_table_lookup(yd->hash, b->name));
|
|
807 pbm->label = buf;
|
|
808 pbm->callback = NULL;
|
|
809 pbm->gc = gc;
|
|
810 m = g_list_append(m, pbm);
|
|
811
|
|
812 return m;
|
|
813 }
|
|
814
|
|
815 static GList *yahoo_user_opts()
|
|
816 {
|
|
817 GList *m = NULL;
|
|
818 struct proto_user_opt *puo;
|
|
819
|
|
820 puo = g_new0(struct proto_user_opt, 1);
|
|
821 puo->label = "Pager Host:";
|
|
822 puo->def = YAHOO_PAGER_HOST;
|
|
823 puo->pos = USEROPT_PAGERHOST;
|
|
824 m = g_list_append(m, puo);
|
|
825
|
|
826 puo = g_new0(struct proto_user_opt, 1);
|
|
827 puo->label = "Pager Port:";
|
|
828 puo->def = "5050";
|
|
829 puo->pos = USEROPT_PAGERPORT;
|
|
830 m = g_list_append(m, puo);
|
|
831
|
|
832 return m;
|
|
833 }
|
|
834
|
|
835 static void yahoo_act_id(gpointer data, char *entry)
|
|
836 {
|
|
837 struct gaim_connection *gc = data;
|
|
838 struct yahoo_data *yd = gc->proto_data;
|
|
839
|
|
840 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_IDACT, YAHOO_STATUS_AVAILABLE, 0);
|
|
841 yahoo_packet_hash(pkt, 3, entry);
|
|
842 yahoo_send_packet(yd, pkt);
|
|
843 yahoo_packet_free(pkt);
|
|
844
|
|
845 g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", entry);
|
|
846 }
|
|
847
|
|
848 static void yahoo_do_action(struct gaim_connection *gc, char *act)
|
|
849 {
|
|
850 if (!strcmp(act, "Activate ID")) {
|
|
851 do_prompt_dialog("Activate which ID:", gc->displayname, gc, yahoo_act_id, NULL);
|
|
852 }
|
|
853 }
|
|
854
|
|
855 static GList *yahoo_actions() {
|
|
856 GList *m = NULL;
|
|
857
|
|
858 m = g_list_append(m, "Activate ID");
|
|
859
|
|
860 return m;
|
|
861 }
|
|
862
|
|
863 static int yahoo_send_im(struct gaim_connection *gc, char *who, char *what, int flags)
|
|
864 {
|
|
865 struct yahoo_data *yd = gc->proto_data;
|
|
866 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0);
|
|
867
|
|
868 yahoo_packet_hash(pkt, 1, gc->displayname);
|
|
869 yahoo_packet_hash(pkt, 5, who);
|
|
870 yahoo_packet_hash(pkt, 14, what);
|
|
871
|
|
872 yahoo_send_packet(yd, pkt);
|
|
873
|
|
874 yahoo_packet_free(pkt);
|
|
875
|
|
876 return 1;
|
|
877 }
|
|
878
|
|
879 static void yahoo_set_away(struct gaim_connection *gc, char *state, char *msg)
|
|
880 {
|
|
881 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
|
|
882 struct yahoo_packet *pkt;
|
|
883 char s[4];
|
|
884
|
|
885 gc->away = NULL;
|
|
886
|
|
887 if (msg) {
|
|
888 yd->current_status = YAHOO_STATUS_CUSTOM;
|
|
889 gc->away = "";
|
|
890 } else if (state) {
|
|
891 gc->away = "";
|
|
892 if (!strcmp(state, "Available")) {
|
|
893 yd->current_status = YAHOO_STATUS_AVAILABLE;
|
|
894 gc->away = NULL;
|
|
895 } else if (!strcmp(state, "Be Right Back")) {
|
|
896 yd->current_status = YAHOO_STATUS_BRB;
|
|
897 } else if (!strcmp(state, "Busy")) {
|
|
898 yd->current_status = YAHOO_STATUS_BUSY;
|
|
899 } else if (!strcmp(state, "Not At Home")) {
|
|
900 yd->current_status = YAHOO_STATUS_NOTATHOME;
|
|
901 } else if (!strcmp(state, "Not At Desk")) {
|
|
902 yd->current_status = YAHOO_STATUS_NOTATDESK;
|
|
903 } else if (!strcmp(state, "Not In Office")) {
|
|
904 yd->current_status = YAHOO_STATUS_NOTINOFFICE;
|
|
905 } else if (!strcmp(state, "On Phone")) {
|
|
906 yd->current_status = YAHOO_STATUS_ONPHONE;
|
|
907 } else if (!strcmp(state, "On Vacation")) {
|
|
908 yd->current_status = YAHOO_STATUS_ONVACATION;
|
|
909 } else if (!strcmp(state, "Out To Lunch")) {
|
|
910 yd->current_status = YAHOO_STATUS_OUTTOLUNCH;
|
|
911 } else if (!strcmp(state, "Stepped Out")) {
|
|
912 yd->current_status = YAHOO_STATUS_STEPPEDOUT;
|
|
913 } else if (!strcmp(state, "Invisible")) {
|
|
914 yd->current_status = YAHOO_STATUS_INVISIBLE;
|
|
915 } else if (!strcmp(state, GAIM_AWAY_CUSTOM)) {
|
|
916 if (gc->is_idle) {
|
|
917 yd->current_status = YAHOO_STATUS_IDLE;
|
|
918 } else {
|
|
919 yd->current_status = YAHOO_STATUS_AVAILABLE;
|
|
920 }
|
|
921 gc->away = NULL;
|
|
922 }
|
|
923 } else if (gc->is_idle) {
|
|
924 yd->current_status = YAHOO_STATUS_IDLE;
|
|
925 } else {
|
|
926 yd->current_status = YAHOO_STATUS_AVAILABLE;
|
|
927 }
|
|
928
|
|
929 pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, yd->current_status, 0);
|
|
930 g_snprintf(s, sizeof(s), "%d", yd->current_status);
|
|
931 yahoo_packet_hash(pkt, 10, s);
|
|
932 if (yd->current_status == YAHOO_STATUS_CUSTOM)
|
|
933 yahoo_packet_hash(pkt, 19, msg);
|
|
934
|
|
935 yahoo_send_packet(yd, pkt);
|
|
936 yahoo_packet_free(pkt);
|
|
937 }
|
|
938
|
|
939 static void yahoo_set_idle(struct gaim_connection *gc, int idle)
|
|
940 {
|
|
941 struct yahoo_data *yd = gc->proto_data;
|
|
942 struct yahoo_packet *pkt = NULL;
|
|
943
|
|
944 if (idle && yd->current_status == YAHOO_STATUS_AVAILABLE) {
|
|
945 pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_IDLE, 0);
|
|
946 yd->current_status = YAHOO_STATUS_IDLE;
|
|
947 } else if (!idle && yd->current_status == YAHOO_STATUS_IDLE) {
|
|
948 pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_AVAILABLE, 0);
|
|
949 yd->current_status = YAHOO_STATUS_AVAILABLE;
|
|
950 }
|
|
951
|
|
952 if (pkt) {
|
|
953 char buf[4];
|
|
954 g_snprintf(buf, sizeof(buf), "%d", yd->current_status);
|
|
955 yahoo_packet_hash(pkt, 10, buf);
|
|
956 yahoo_send_packet(yd, pkt);
|
|
957 yahoo_packet_free(pkt);
|
|
958 }
|
|
959 }
|
|
960
|
|
961 static GList *yahoo_away_states(struct gaim_connection *gc)
|
|
962 {
|
|
963 GList *m = NULL;
|
|
964
|
|
965 m = g_list_append(m, "Available");
|
|
966 m = g_list_append(m, "Be Right Back");
|
|
967 m = g_list_append(m, "Busy");
|
|
968 m = g_list_append(m, "Not At Home");
|
|
969 m = g_list_append(m, "Not At Desk");
|
|
970 m = g_list_append(m, "Not In Office");
|
|
971 m = g_list_append(m, "On Phone");
|
|
972 m = g_list_append(m, "On Vacation");
|
|
973 m = g_list_append(m, "Out To Lunch");
|
|
974 m = g_list_append(m, "Stepped Out");
|
|
975 m = g_list_append(m, "Invisible");
|
|
976 m = g_list_append(m, GAIM_AWAY_CUSTOM);
|
|
977
|
|
978 return m;
|
|
979 }
|
|
980
|
|
981 static void yahoo_keepalive(struct gaim_connection *gc)
|
|
982 {
|
|
983 struct yahoo_data *yd = gc->proto_data;
|
|
984 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, 0);
|
|
985 yahoo_send_packet(yd, pkt);
|
|
986 yahoo_packet_free(pkt);
|
|
987 }
|
|
988
|
|
989 static void yahoo_add_buddy(struct gaim_connection *gc, char *who)
|
|
990 {
|
|
991 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
|
|
992 struct yahoo_packet *pkt;
|
|
993 struct group *g;
|
|
994 char *group = NULL;
|
|
995
|
|
996 if (!yd->logged_in)
|
|
997 return;
|
|
998
|
|
999 g = find_group_by_buddy(gc, who);
|
|
1000 if (g)
|
|
1001 group = g->name;
|
|
1002 else
|
|
1003 group = "Buddies";
|
|
1004
|
|
1005 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0);
|
|
1006 yahoo_packet_hash(pkt, 1, gc->displayname);
|
|
1007 yahoo_packet_hash(pkt, 7, who);
|
|
1008 yahoo_packet_hash(pkt, 65, group);
|
|
1009 yahoo_send_packet(yd, pkt);
|
|
1010 yahoo_packet_free(pkt);
|
|
1011 }
|
|
1012
|
|
1013 static void yahoo_remove_buddy(struct gaim_connection *gc, char *who, char *group)
|
|
1014 {
|
|
1015 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
|
|
1016
|
|
1017 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0);
|
|
1018 yahoo_packet_hash(pkt, 1, gc->displayname);
|
|
1019 yahoo_packet_hash(pkt, 7, who);
|
|
1020 yahoo_packet_hash(pkt, 65, group);
|
|
1021 yahoo_send_packet(yd, pkt);
|
|
1022 yahoo_packet_free(pkt);
|
|
1023 }
|
|
1024
|
|
1025 static struct prpl *my_protocol = NULL;
|
|
1026
|
|
1027 void yahoo_init(struct prpl *ret) {
|
|
1028 ret->protocol = PROTO_YAHOO;
|
|
1029 ret->options = OPT_PROTO_MAIL_CHECK;
|
|
1030 ret->name = yahoo_name;
|
|
1031 ret->user_opts = yahoo_user_opts;
|
|
1032 ret->login = yahoo_login;
|
|
1033 ret->close = yahoo_close;
|
|
1034 ret->buddy_menu = yahoo_buddy_menu;
|
|
1035 ret->list_icon = yahoo_list_icon;
|
|
1036 ret->actions = yahoo_actions;
|
|
1037 ret->do_action = yahoo_do_action;
|
|
1038 ret->send_im = yahoo_send_im;
|
|
1039 ret->away_states = yahoo_away_states;
|
|
1040 ret->set_away = yahoo_set_away;
|
|
1041 ret->set_idle = yahoo_set_idle;
|
|
1042 ret->keepalive = yahoo_keepalive;
|
|
1043 ret->add_buddy = yahoo_add_buddy;
|
|
1044 ret->remove_buddy = yahoo_remove_buddy;
|
|
1045
|
|
1046 my_protocol = ret;
|
|
1047 }
|
|
1048
|
|
1049 #ifndef STATIC
|
|
1050
|
|
1051 char *gaim_plugin_init(GModule *handle)
|
|
1052 {
|
|
1053 load_protocol(yahoo_init, sizeof(struct prpl));
|
|
1054 return NULL;
|
|
1055 }
|
|
1056
|
|
1057 void gaim_plugin_remove()
|
|
1058 {
|
|
1059 struct prpl *p = find_prpl(PROTO_YAHOO);
|
|
1060 if (p == my_protocol)
|
|
1061 unload_protocol(p);
|
|
1062 }
|
|
1063
|
|
1064 char *name()
|
|
1065 {
|
|
1066 return "Yahoo";
|
|
1067 }
|
|
1068
|
|
1069 char *description()
|
|
1070 {
|
|
1071 return PRPL_DESC("Yahoo");
|
|
1072 }
|
|
1073
|
|
1074 #endif
|