Yahoo - add buddy authentication
[centerim.git] / libyahoo2 / libyahoo2.c
blobbb99ce60e4a3a84fb365905814ec11306e45abbf
1 /*
2 * libyahoo2: libyahoo2.c
4 * Some code copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
5 * YMSG16 code copyright (C) 2009,
6 * Siddhesh Poyarekar <siddhesh dot poyarekar at gmail dot com>
8 * Yahoo Search copyright (C) 2003, Konstantin Klyagin <konst AT konst.org.ua>
10 * Much of this code was taken and adapted from the yahoo module for
11 * gaim released under the GNU GPL. This code is also released under the
12 * GNU GPL.
14 * This code is derivitive of Gaim <http://gaim.sourceforge.net>
15 * copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
16 * 1998-1999, Adam Fritzler <afritz@marko.net>
17 * 1998-2002, Rob Flynn <rob@marko.net>
18 * 2000-2002, Eric Warmenhoven <eric@warmenhoven.org>
19 * 2001-2002, Brian Macke <macke@strangelove.net>
20 * 2001, Anand Biligiri S <abiligiri@users.sf.net>
21 * 2001, Valdis Kletnieks
22 * 2002, Sean Egan <bj91704@binghamton.edu>
23 * 2002, Toby Gray <toby.gray@ntlworld.com>
25 * This library also uses code from other libraries, namely:
26 * Portions from libfaim copyright 1998, 1999 Adam Fritzler
27 * <afritz@auk.cx>
28 * Portions of Sylpheed copyright 2000-2002 Hiroyuki Yamamoto
29 * <hiro-y@kcn.ne.jp>
31 * YMSG16 authentication code based mostly on write-up at:
32 * http://www.carbonize.co.uk/ymsg16.html
34 * This program is free software; you can redistribute it and/or modify
35 * it under the terms of the GNU General Public License as published by
36 * the Free Software Foundation; either version 2 of the License, or
37 * (at your option) any later version.
39 * This program is distributed in the hope that it will be useful,
40 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42 * GNU General Public License for more details.
44 * You should have received a copy of the GNU General Public License
45 * along with this program; if not, write to the Free Software
46 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
50 #if HAVE_CONFIG_H
51 # include <config.h>
52 #endif
54 #if HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 #include <errno.h>
58 #include <stdio.h>
59 #include <stdarg.h>
61 #if STDC_HEADERS
62 # include <string.h>
63 #else
64 # if !HAVE_STRCHR
65 # define strchr index
66 # define strrchr rindex
67 # endif
68 char *strchr(), *strrchr();
69 # if !HAVE_MEMCPY
70 # define memcpy(d, s, n) bcopy ((s), (d), (n))
71 # define memmove(d, s, n) bcopy ((s), (d), (n))
72 # endif
73 #endif
75 #include <sys/types.h>
77 #include <stdlib.h>
78 #include <ctype.h>
80 #include "sha1.h"
81 #include "md5.h"
82 #include "yahoo2.h"
83 #include "yahoo_httplib.h"
84 #include "yahoo_util.h"
85 #include "yahoo_fn.h"
87 #include "yahoo2_callbacks.h"
88 #include "yahoo_debug.h"
89 #ifdef __MINGW32__
90 #define snprintf _snprintf
91 #define vsnprintf _vsnprintf
92 #endif
94 struct yahoo_callbacks *yc = NULL;
96 void yahoo_register_callbacks(struct yahoo_callbacks *tyc)
98 yc = tyc;
101 #define YAHOO_CALLBACK(x) yc->x
103 static int yahoo_send_data(void *fd, void *data, int len);
104 static void _yahoo_http_connected(int id, void *fd, int error, void *data);
105 static void yahoo_connected(void *fd, int error, void *data);
107 int yahoo_log_message(char *fmt, ...)
109 char out[1024];
110 va_list ap;
111 va_start(ap, fmt);
112 vsnprintf(out, sizeof(out), fmt, ap);
113 va_end(ap);
114 return YAHOO_CALLBACK(ext_yahoo_log) ("%s", out);
117 int yahoo_connect(char *host, int port)
119 return YAHOO_CALLBACK(ext_yahoo_connect) (host, port);
122 static enum yahoo_log_level log_level = YAHOO_LOG_NONE;
124 enum yahoo_log_level yahoo_get_log_level()
126 return log_level;
129 int yahoo_set_log_level(enum yahoo_log_level level)
131 enum yahoo_log_level l = log_level;
132 log_level = level;
133 return l;
136 /* default values for servers */
137 static char *default_pager_hosts[] = { "scs.msg.yahoo.com",
138 "scsa.msg.yahoo.com",
139 "scsb.msg.yahoo.com",
140 "scsc.msg.yahoo.com",
141 NULL};
143 static int pager_port = 5050;
144 static int fallback_ports[] = { 23, 25, 80, 20, 119, 8001, 8002, 5050, 0 };
146 static char filetransfer_host[] = "filetransfer.msg.yahoo.com";
147 static int filetransfer_port = 80;
148 static char webcam_host[] = "webcam.yahoo.com";
149 static int webcam_port = 5100;
150 static char webcam_description[] = "";
151 static char local_host[] = "";
152 static int conn_type = Y_WCM_DSL;
154 static char profile_url[] = "http://profiles.yahoo.com/";
156 struct connect_callback_data {
157 struct yahoo_data *yd;
158 int tag;
159 int i;
160 int server_i;
163 struct yahoo_pair {
164 int key;
165 char *value;
168 struct yahoo_packet {
169 unsigned short int service;
170 unsigned int status;
171 unsigned int id;
172 YList *hash;
175 struct yahoo_search_state {
176 int lsearch_type;
177 char *lsearch_text;
178 int lsearch_gender;
179 int lsearch_agerange;
180 int lsearch_photo;
181 int lsearch_yahoo_only;
182 int lsearch_nstart;
183 int lsearch_nfound;
184 int lsearch_ntotal;
187 struct data_queue {
188 unsigned char *queue;
189 int len;
192 struct yahoo_input_data {
193 struct yahoo_data *yd;
194 struct yahoo_webcam *wcm;
195 struct yahoo_webcam_data *wcd;
196 struct yahoo_search_state *ys;
198 void *fd;
199 enum yahoo_connection_type type;
201 unsigned char *rxqueue;
202 int rxlen;
203 int read_tag;
205 YList *txqueues;
206 int write_tag;
209 struct yahoo_server_settings {
210 char *pager_host;
211 int pager_port;
212 char *filetransfer_host;
213 int filetransfer_port;
214 char *webcam_host;
215 int webcam_port;
216 char *webcam_description;
217 char *local_host;
218 int conn_type;
219 char **pager_host_list;
222 static void yahoo_process_ft_connection(struct yahoo_input_data *yid, int over);
224 static void yahoo_process_filetransfer(struct yahoo_input_data *yid,
225 struct yahoo_packet *pkt);
226 static void yahoo_process_filetransferinfo(struct yahoo_input_data *yid,
227 struct yahoo_packet *pkt);
228 static void yahoo_process_filetransferaccept(struct yahoo_input_data *yid,
229 struct yahoo_packet *pkt);
231 static void *_yahoo_default_server_settings()
233 struct yahoo_server_settings *yss =
234 y_new0(struct yahoo_server_settings, 1);
236 /* Give preference to the default host list
237 * Make sure that only one of the two is set at any time
239 yss->pager_host = NULL;
240 yss->pager_host_list = default_pager_hosts;
242 yss->pager_port = pager_port;
243 yss->filetransfer_host = strdup(filetransfer_host);
244 yss->filetransfer_port = filetransfer_port;
245 yss->webcam_host = strdup(webcam_host);
246 yss->webcam_port = webcam_port;
247 yss->webcam_description = strdup(webcam_description);
248 yss->local_host = strdup(local_host);
249 yss->conn_type = conn_type;
251 return yss;
254 static void *_yahoo_assign_server_settings(va_list ap)
256 struct yahoo_server_settings *yss = _yahoo_default_server_settings();
257 char *key;
258 char *svalue;
259 int nvalue;
260 char **pvalue;
262 while (1) {
263 key = va_arg(ap, char *);
264 if (key == NULL)
265 break;
267 if (!strcmp(key, "pager_host")) {
268 svalue = va_arg(ap, char *);
269 free(yss->pager_host);
270 yss->pager_host = strdup(svalue);
271 yss->pager_host_list = NULL;
272 } else if (!strcmp(key, "pager_host_list")) {
273 pvalue = va_arg(ap, char **);
274 yss->pager_host_list = pvalue;
275 free(yss->pager_host);
276 yss->pager_host = NULL;
277 } else if (!strcmp(key, "pager_port")) {
278 nvalue = va_arg(ap, int);
279 yss->pager_port = nvalue;
280 } else if (!strcmp(key, "filetransfer_host")) {
281 svalue = va_arg(ap, char *);
282 free(yss->filetransfer_host);
283 yss->filetransfer_host = strdup(svalue);
284 } else if (!strcmp(key, "filetransfer_port")) {
285 nvalue = va_arg(ap, int);
286 yss->filetransfer_port = nvalue;
287 } else if (!strcmp(key, "webcam_host")) {
288 svalue = va_arg(ap, char *);
289 free(yss->webcam_host);
290 yss->webcam_host = strdup(svalue);
291 } else if (!strcmp(key, "webcam_port")) {
292 nvalue = va_arg(ap, int);
293 yss->webcam_port = nvalue;
294 } else if (!strcmp(key, "webcam_description")) {
295 svalue = va_arg(ap, char *);
296 free(yss->webcam_description);
297 yss->webcam_description = strdup(svalue);
298 } else if (!strcmp(key, "local_host")) {
299 svalue = va_arg(ap, char *);
300 free(yss->local_host);
301 yss->local_host = strdup(svalue);
302 } else if (!strcmp(key, "conn_type")) {
303 nvalue = va_arg(ap, int);
304 yss->conn_type = nvalue;
305 } else {
306 WARNING(("Unknown key passed to yahoo_init, "
307 "perhaps you didn't terminate the list "
308 "with NULL"));
312 return yss;
315 static void yahoo_free_server_settings(struct yahoo_server_settings *yss)
317 if (!yss)
318 return;
320 free(yss->pager_host);
321 free(yss->filetransfer_host);
322 free(yss->webcam_host);
323 free(yss->webcam_description);
324 free(yss->local_host);
326 free(yss);
329 static YList *conns = NULL;
330 static YList *inputs = NULL;
331 static int last_id = 0;
333 static void add_to_list(struct yahoo_data *yd)
335 conns = y_list_prepend(conns, yd);
338 static struct yahoo_data *find_conn_by_id(int id)
340 YList *l;
341 for (l = conns; l; l = y_list_next(l)) {
342 struct yahoo_data *yd = l->data;
343 if (yd->client_id == id)
344 return yd;
346 return NULL;
349 static void del_from_list(struct yahoo_data *yd)
351 conns = y_list_remove(conns, yd);
354 /* call repeatedly to get the next one */
356 static struct yahoo_input_data * find_input_by_id(int id)
358 YList *l;
359 for(l = inputs; l; l = y_list_next(l)) {
360 struct yahoo_input_data *yid = l->data;
361 if(yid->yd->client_id == id)
362 return yid;
364 return NULL;
368 static struct yahoo_input_data *find_input_by_id_and_webcam_user(int id,
369 const char *who)
371 YList *l;
372 LOG(("find_input_by_id_and_webcam_user"));
373 for (l = inputs; l; l = y_list_next(l)) {
374 struct yahoo_input_data *yid = l->data;
375 if (yid->type == YAHOO_CONNECTION_WEBCAM
376 && yid->yd->client_id == id && yid->wcm && ((who
377 && yid->wcm->user
378 && !strcmp(who, yid->wcm->user))
379 || !(yid->wcm->user && !who)))
380 return yid;
382 return NULL;
385 static struct yahoo_input_data *find_input_by_id_and_type(int id,
386 enum yahoo_connection_type type)
388 YList *l;
389 LOG(("find_input_by_id_and_type"));
390 for (l = inputs; l; l = y_list_next(l)) {
391 struct yahoo_input_data *yid = l->data;
392 if (yid->type == type && yid->yd->client_id == id)
393 return yid;
395 return NULL;
398 static struct yahoo_input_data *find_input_by_id_and_fd(int id, void *fd)
400 YList *l;
401 LOG(("find_input_by_id_and_fd"));
402 for (l = inputs; l; l = y_list_next(l)) {
403 struct yahoo_input_data *yid = l->data;
404 if (yid->fd == fd && yid->yd->client_id == id)
405 return yid;
407 return NULL;
410 static int count_inputs_with_id(int id)
412 int c = 0;
413 YList *l;
414 LOG(("counting %d", id));
415 for (l = inputs; l; l = y_list_next(l)) {
416 struct yahoo_input_data *yid = l->data;
417 if (yid->yd->client_id == id)
418 c++;
420 LOG(("%d", c));
421 return c;
424 extern char *yahoo_crypt(char *, char *);
426 /* Free a buddy list */
427 static void yahoo_free_buddies(YList *list)
429 YList *l;
431 for (l = list; l; l = l->next) {
432 struct yahoo_buddy *bud = l->data;
433 if (!bud)
434 continue;
436 FREE(bud->group);
437 FREE(bud->id);
438 FREE(bud->real_name);
439 if (bud->yab_entry) {
440 FREE(bud->yab_entry->fname);
441 FREE(bud->yab_entry->lname);
442 FREE(bud->yab_entry->nname);
443 FREE(bud->yab_entry->id);
444 FREE(bud->yab_entry->email);
445 FREE(bud->yab_entry->hphone);
446 FREE(bud->yab_entry->wphone);
447 FREE(bud->yab_entry->mphone);
448 FREE(bud->yab_entry);
450 FREE(bud);
451 l->data = bud = NULL;
454 y_list_free(list);
457 /* Free an identities list */
458 static void yahoo_free_identities(YList *list)
460 while (list) {
461 YList *n = list;
462 FREE(list->data);
463 list = y_list_remove_link(list, list);
464 y_list_free_1(n);
468 /* Free webcam data */
469 static void yahoo_free_webcam(struct yahoo_webcam *wcm)
471 if (wcm) {
472 FREE(wcm->user);
473 FREE(wcm->server);
474 FREE(wcm->key);
475 FREE(wcm->description);
476 FREE(wcm->my_ip);
478 FREE(wcm);
481 static void yahoo_free_data(struct yahoo_data *yd)
483 FREE(yd->user);
484 FREE(yd->password);
485 FREE(yd->cookie_y);
486 FREE(yd->cookie_t);
487 FREE(yd->cookie_b);
488 FREE(yd->cookie_c);
489 FREE(yd->login_cookie);
490 FREE(yd->login_id);
492 yahoo_free_buddies(yd->buddies);
493 yahoo_free_buddies(yd->ignore);
494 yahoo_free_identities(yd->identities);
496 yahoo_free_server_settings(yd->server_settings);
498 FREE(yd);
501 #define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4)
503 static struct yahoo_packet *yahoo_packet_new(enum yahoo_service service,
504 enum ypacket_status status, int id)
506 struct yahoo_packet *pkt = y_new0(struct yahoo_packet, 1);
508 pkt->service = service;
509 pkt->status = status;
510 pkt->id = id;
512 return pkt;
515 static void yahoo_packet_hash(struct yahoo_packet *pkt, int key,
516 const char *value)
518 struct yahoo_pair *pair = y_new0(struct yahoo_pair, 1);
519 pair->key = key;
520 pair->value = strdup(value);
521 pkt->hash = y_list_append(pkt->hash, pair);
524 static int yahoo_packet_length(struct yahoo_packet *pkt)
526 YList *l;
528 int len = 0;
530 for (l = pkt->hash; l; l = l->next) {
531 struct yahoo_pair *pair = l->data;
532 int tmp = pair->key;
533 do {
534 tmp /= 10;
535 len++;
536 } while (tmp);
537 len += 2;
538 len += strlen(pair->value);
539 len += 2;
542 return len;
545 #define yahoo_put16(buf, data) ( \
546 (*(buf) = (unsigned char)((data)>>8)&0xff), \
547 (*((buf)+1) = (unsigned char)(data)&0xff), \
549 #define yahoo_get16(buf) ((((*(buf))&0xff)<<8) + ((*((buf)+1)) & 0xff))
550 #define yahoo_put32(buf, data) ( \
551 (*((buf)) = (unsigned char)((data)>>24)&0xff), \
552 (*((buf)+1) = (unsigned char)((data)>>16)&0xff), \
553 (*((buf)+2) = (unsigned char)((data)>>8)&0xff), \
554 (*((buf)+3) = (unsigned char)(data)&0xff), \
556 #define yahoo_get32(buf) ((((*(buf) )&0xff)<<24) + \
557 (((*((buf)+1))&0xff)<<16) + \
558 (((*((buf)+2))&0xff)<< 8) + \
559 (((*((buf)+3))&0xff)))
561 static void yahoo_packet_read(struct yahoo_packet *pkt, unsigned char *data,
562 int len)
564 int pos = 0;
566 while (pos + 1 < len) {
567 char *key, *value = NULL;
568 int accept;
569 int x;
571 struct yahoo_pair *pair = y_new0(struct yahoo_pair, 1);
573 key = malloc(len + 1);
574 x = 0;
575 while (pos + 1 < len) {
576 if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
577 break;
578 key[x++] = data[pos++];
580 key[x] = 0;
581 pos += 2;
582 pair->key = strtol(key, NULL, 10);
583 free(key);
585 accept = x;
587 if (pos + 1 > len) {
588 /* Malformed packet! (Truncated--garbage or something) */
589 accept = 0;
592 /* if x is 0 there was no key, so don't accept it */
593 if (accept)
594 value = malloc(len - pos + 1);
595 x = 0;
596 while (pos + 1 < len) {
597 if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
598 break;
599 if (accept)
600 value[x++] = data[pos++];
602 if (accept)
603 value[x] = 0;
604 pos += 2;
605 if (accept) {
606 pair->value = strdup(value);
607 FREE(value);
608 pkt->hash = y_list_append(pkt->hash, pair);
609 DEBUG_MSG(("Key: %d \tValue: %s", pair->key,
610 pair->value));
611 } else {
612 FREE(pair);
617 static void yahoo_packet_write(struct yahoo_packet *pkt, unsigned char *data)
619 YList *l;
620 int pos = 0;
622 for (l = pkt->hash; l; l = l->next) {
623 struct yahoo_pair *pair = l->data;
624 unsigned char buf[100];
626 snprintf((char *)buf, sizeof(buf), "%d", pair->key);
627 strcpy((char *)data + pos, (char *)buf);
628 pos += strlen((char *)buf);
629 data[pos++] = 0xc0;
630 data[pos++] = 0x80;
632 strcpy((char *)data + pos, pair->value);
633 pos += strlen(pair->value);
634 data[pos++] = 0xc0;
635 data[pos++] = 0x80;
639 static void yahoo_dump_unhandled(struct yahoo_packet *pkt)
641 YList *l;
643 NOTICE(("Service: 0x%02x\tStatus: %d", pkt->service, pkt->status));
644 for (l = pkt->hash; l; l = l->next) {
645 struct yahoo_pair *pair = l->data;
646 NOTICE(("\t%d => %s", pair->key, pair->value));
650 static void yahoo_packet_dump(unsigned char *data, int len)
652 if (yahoo_get_log_level() >= YAHOO_LOG_DEBUG) {
653 int i;
654 for (i = 0; i < len; i++) {
655 if ((i % 8 == 0) && i)
656 YAHOO_CALLBACK(ext_yahoo_log) (" ");
657 if ((i % 16 == 0) && i)
658 YAHOO_CALLBACK(ext_yahoo_log) ("\n");
659 YAHOO_CALLBACK(ext_yahoo_log) ("%02x ", data[i]);
661 YAHOO_CALLBACK(ext_yahoo_log) ("\n");
662 for (i = 0; i < len; i++) {
663 if ((i % 8 == 0) && i)
664 YAHOO_CALLBACK(ext_yahoo_log) (" ");
665 if ((i % 16 == 0) && i)
666 YAHOO_CALLBACK(ext_yahoo_log) ("\n");
667 if (isprint(data[i]))
668 YAHOO_CALLBACK(ext_yahoo_log) (" %c ", data[i]);
669 else
670 YAHOO_CALLBACK(ext_yahoo_log) (" . ");
672 YAHOO_CALLBACK(ext_yahoo_log) ("\n");
676 static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
677 "abcdefghijklmnopqrstuvwxyz" "0123456789._";
678 static void to_y64(unsigned char *out, const unsigned char *in, int inlen)
679 /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
681 for (; inlen >= 3; inlen -= 3) {
682 *out++ = base64digits[in[0] >> 2];
683 *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
684 *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
685 *out++ = base64digits[in[2] & 0x3f];
686 in += 3;
688 if (inlen > 0) {
689 unsigned char fragment;
691 *out++ = base64digits[in[0] >> 2];
692 fragment = (in[0] << 4) & 0x30;
693 if (inlen > 1)
694 fragment |= in[1] >> 4;
695 *out++ = base64digits[fragment];
696 *out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c];
697 *out++ = '-';
699 *out = '\0';
702 static void yahoo_add_to_send_queue(struct yahoo_input_data *yid, void *data,
703 int length)
705 struct data_queue *tx = y_new0(struct data_queue, 1);
706 tx->queue = y_new0(unsigned char, length);
707 tx->len = length;
708 memcpy(tx->queue, data, length);
710 yid->txqueues = y_list_append(yid->txqueues, tx);
712 if (!yid->write_tag)
713 yid->write_tag =
714 YAHOO_CALLBACK(ext_yahoo_add_handler) (yid->yd->
715 client_id, yid->fd, YAHOO_INPUT_WRITE, yid);
718 static void yahoo_send_packet(struct yahoo_input_data *yid,
719 struct yahoo_packet *pkt, int extra_pad)
721 int pktlen = yahoo_packet_length(pkt);
722 int len = YAHOO_PACKET_HDRLEN + pktlen;
723 unsigned char *data;
724 int pos = 0;
726 if (!yid->fd)
727 return;
729 data = y_new0(unsigned char, len + 1);
731 memcpy(data + pos, "YMSG", 4);
732 pos += 4;
733 pos += yahoo_put16(data + pos, YAHOO_PROTO_VER); /* version [latest 12 0x000c] */
734 pos += yahoo_put16(data + pos, 0x0000); /* HIWORD pkt length??? */
735 pos += yahoo_put16(data + pos, pktlen + extra_pad); /* LOWORD pkt length? */
736 pos += yahoo_put16(data + pos, pkt->service); /* service */
737 pos += yahoo_put32(data + pos, pkt->status); /* status [4bytes] */
738 pos += yahoo_put32(data + pos, pkt->id); /* session [4bytes] */
740 yahoo_packet_write(pkt, data + pos);
742 yahoo_packet_dump(data, len);
744 if (yid->type == YAHOO_CONNECTION_FT)
745 yahoo_send_data(yid->fd, data, len);
746 else
747 yahoo_add_to_send_queue(yid, data, len);
748 FREE(data);
751 static void yahoo_packet_free(struct yahoo_packet *pkt)
753 while (pkt->hash) {
754 struct yahoo_pair *pair = pkt->hash->data;
755 YList *tmp;
756 FREE(pair->value);
757 FREE(pair);
758 tmp = pkt->hash;
759 pkt->hash = y_list_remove_link(pkt->hash, pkt->hash);
760 y_list_free_1(tmp);
762 FREE(pkt);
765 static int yahoo_send_data(void *fd, void *data, int len)
767 int ret;
768 int e;
770 if (fd == NULL)
771 return -1;
773 yahoo_packet_dump(data, len);
775 do {
776 ret = YAHOO_CALLBACK(ext_yahoo_write) (fd, data, len);
777 } while (ret == -1 && errno == EINTR);
778 e = errno;
780 if (ret == -1) {
781 LOG(("wrote data: ERR %s", strerror(errno)));
782 } else {
783 LOG(("wrote data: OK"));
786 errno = e;
787 return ret;
790 void yahoo_close(int id)
792 struct yahoo_data *yd = find_conn_by_id(id);
793 if (!yd)
794 return;
796 del_from_list(yd);
798 yahoo_free_data(yd);
799 if (id == last_id)
800 last_id--;
803 static void yahoo_input_close(struct yahoo_input_data *yid)
805 inputs = y_list_remove(inputs, yid);
807 LOG(("yahoo_input_close(read)"));
808 YAHOO_CALLBACK(ext_yahoo_remove_handler) (yid->yd->client_id,
809 yid->read_tag);
810 LOG(("yahoo_input_close(write)"));
811 YAHOO_CALLBACK(ext_yahoo_remove_handler) (yid->yd->client_id,
812 yid->write_tag);
813 yid->read_tag = yid->write_tag = 0;
814 if (yid->fd)
815 YAHOO_CALLBACK(ext_yahoo_close) (yid->fd);
816 yid->fd = 0;
817 FREE(yid->rxqueue);
818 if (count_inputs_with_id(yid->yd->client_id) == 0) {
819 LOG(("closing %d", yid->yd->client_id));
820 yahoo_close(yid->yd->client_id);
822 yahoo_free_webcam(yid->wcm);
823 if (yid->wcd)
824 FREE(yid->wcd);
825 if (yid->ys) {
826 FREE(yid->ys->lsearch_text);
827 FREE(yid->ys);
829 FREE(yid);
832 static int is_same_bud(const void *a, const void *b)
834 const struct yahoo_buddy *subject = a;
835 const struct yahoo_buddy *object = b;
837 return strcmp(subject->id, object->id);
840 static char *getcookie(char *rawcookie)
842 char *cookie = NULL;
843 char *tmpcookie;
844 char *cookieend;
846 if (strlen(rawcookie) < 2)
847 return NULL;
849 tmpcookie = strdup(rawcookie + 2);
850 cookieend = strchr(tmpcookie, ';');
852 if (cookieend)
853 *cookieend = '\0';
855 cookie = strdup(tmpcookie);
856 FREE(tmpcookie);
857 /* cookieend=NULL; not sure why this was there since the value is not preserved in the stack -dd */
859 return cookie;
862 static char *getlcookie(char *cookie)
864 char *tmp;
865 char *tmpend;
866 char *login_cookie = NULL;
868 tmpend = strstr(cookie, "n=");
869 if (tmpend) {
870 tmp = strdup(tmpend + 2);
871 tmpend = strchr(tmp, '&');
872 if (tmpend)
873 *tmpend = '\0';
874 login_cookie = strdup(tmp);
875 FREE(tmp);
878 return login_cookie;
881 static void yahoo_process_notify(struct yahoo_input_data *yid,
882 struct yahoo_packet *pkt)
884 struct yahoo_data *yd = yid->yd;
885 char *msg = NULL;
886 char *from = NULL;
887 char *to = NULL;
888 int stat = 0;
889 int accept = 0;
890 char *ind = NULL;
891 YList *l;
892 for (l = pkt->hash; l; l = l->next) {
893 struct yahoo_pair *pair = l->data;
894 if (pair->key == 4)
895 from = pair->value;
896 if (pair->key == 5)
897 to = pair->value;
898 if (pair->key == 49)
899 msg = pair->value;
900 if (pair->key == 13)
901 stat = atoi(pair->value);
902 if (pair->key == 14)
903 ind = pair->value;
904 if (pair->key == 16) { /* status == -1 */
905 NOTICE((pair->value));
906 return;
911 if (!msg)
912 return;
914 if (!strncasecmp(msg, "TYPING", strlen("TYPING")))
915 YAHOO_CALLBACK(ext_yahoo_typing_notify) (yd->client_id, to,
916 from, stat);
917 else if (!strncasecmp(msg, "GAME", strlen("GAME")))
918 YAHOO_CALLBACK(ext_yahoo_game_notify) (yd->client_id, to, from,
919 stat, ind);
920 else if (!strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) {
921 if (!strcmp(ind, " ")) {
922 YAHOO_CALLBACK(ext_yahoo_webcam_invite) (yd->client_id,
923 to, from);
924 } else {
925 accept = atoi(ind);
926 /* accept the invitation (-1 = deny 1 = accept) */
927 if (accept < 0)
928 accept = 0;
929 YAHOO_CALLBACK(ext_yahoo_webcam_invite_reply) (yd->
930 client_id, to, from, accept);
932 } else
933 LOG(("Got unknown notification: %s", msg));
936 static void yahoo_process_conference(struct yahoo_input_data *yid,
937 struct yahoo_packet *pkt)
939 struct yahoo_data *yd = yid->yd;
940 char *msg = NULL;
941 char *host = NULL;
942 char *who = NULL;
943 char *room = NULL;
944 char *id = NULL;
945 int utf8 = 0;
946 YList *members = NULL;
947 YList *l;
949 for (l = pkt->hash; l; l = l->next) {
950 struct yahoo_pair *pair = l->data;
951 if (pair->key == 50)
952 host = pair->value;
954 if (pair->key == 52) { /* invite */
955 members = y_list_append(members, strdup(pair->value));
957 if (pair->key == 53) /* logon */
958 who = pair->value;
959 if (pair->key == 54) /* decline */
960 who = pair->value;
961 if (pair->key == 55) /* unavailable (status == 2) */
962 who = pair->value;
963 if (pair->key == 56) /* logoff */
964 who = pair->value;
966 if (pair->key == 57)
967 room = pair->value;
969 if (pair->key == 58) /* join message */
970 msg = pair->value;
971 if (pair->key == 14) /* decline/conf message */
972 msg = pair->value;
974 if (pair->key == 13) ;
975 if (pair->key == 16) /* error */
976 msg = pair->value;
978 if (pair->key == 1) /* my id */
979 id = pair->value;
980 if (pair->key == 3) /* message sender */
981 who = pair->value;
983 if (pair->key == 97)
984 utf8 = atoi(pair->value);
987 if (!room)
988 return;
990 if (host) {
991 for (l = members; l; l = l->next) {
992 char *w = l->data;
993 if (!strcmp(w, host))
994 break;
996 if (!l)
997 members = y_list_append(members, strdup(host));
999 /* invite, decline, join, left, message -> status == 1 */
1001 switch (pkt->service) {
1002 case YAHOO_SERVICE_CONFINVITE:
1003 if (pkt->status == 2) ;
1004 else if (members)
1005 YAHOO_CALLBACK(ext_yahoo_got_conf_invite) (yd->
1006 client_id, id, host, room, msg, members);
1007 else if (msg)
1008 YAHOO_CALLBACK(ext_yahoo_error) (yd->client_id, msg, 0,
1009 E_CONFNOTAVAIL);
1010 break;
1011 case YAHOO_SERVICE_CONFADDINVITE:
1012 if (pkt->status == 1)
1013 YAHOO_CALLBACK(ext_yahoo_got_conf_invite) (yd->
1014 client_id, id, host, room, msg, members);
1015 break;
1016 case YAHOO_SERVICE_CONFDECLINE:
1017 if (who)
1018 YAHOO_CALLBACK(ext_yahoo_conf_userdecline) (yd->
1019 client_id, id, who, room, msg);
1020 break;
1021 case YAHOO_SERVICE_CONFLOGON:
1022 if (who)
1023 YAHOO_CALLBACK(ext_yahoo_conf_userjoin) (yd->client_id,
1024 id, who, room);
1025 break;
1026 case YAHOO_SERVICE_CONFLOGOFF:
1027 if (who)
1028 YAHOO_CALLBACK(ext_yahoo_conf_userleave) (yd->client_id,
1029 id, who, room);
1030 break;
1031 case YAHOO_SERVICE_CONFMSG:
1032 if (who)
1033 YAHOO_CALLBACK(ext_yahoo_conf_message) (yd->client_id,
1034 id, who, room, msg, utf8);
1035 break;
1039 static void yahoo_process_chat(struct yahoo_input_data *yid,
1040 struct yahoo_packet *pkt)
1042 char *msg = NULL;
1043 char *id = NULL;
1044 char *who = NULL;
1045 char *room = NULL;
1046 char *topic = NULL;
1047 YList *members = NULL;
1048 struct yahoo_chat_member *currentmember = NULL;
1049 int msgtype = 1;
1050 int utf8 = 0;
1051 int firstjoin = 0;
1052 int membercount = 0;
1053 int chaterr = 0;
1054 YList *l;
1056 yahoo_dump_unhandled(pkt);
1057 for (l = pkt->hash; l; l = l->next) {
1058 struct yahoo_pair *pair = l->data;
1060 if (pair->key == 1) {
1061 /* My identity */
1062 id = pair->value;
1065 if (pair->key == 104) {
1066 /* Room name */
1067 room = pair->value;
1070 if (pair->key == 105) {
1071 /* Room topic */
1072 topic = pair->value;
1075 if (pair->key == 108) {
1076 /* Number of members in this packet */
1077 membercount = atoi(pair->value);
1080 if (pair->key == 109) {
1081 /* message sender */
1082 who = pair->value;
1084 if (pkt->service == YAHOO_SERVICE_CHATJOIN) {
1085 currentmember =
1086 y_new0(struct yahoo_chat_member, 1);
1087 currentmember->id = strdup(pair->value);
1088 members = y_list_append(members, currentmember);
1092 if (pair->key == 110) {
1093 /* age */
1094 if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1095 currentmember->age = atoi(pair->value);
1098 if (pair->key == 113) {
1099 /* attribs */
1100 if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1101 currentmember->attribs = atoi(pair->value);
1104 if (pair->key == 141) {
1105 /* alias */
1106 if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1107 currentmember->alias = strdup(pair->value);
1110 if (pair->key == 142) {
1111 /* location */
1112 if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1113 currentmember->location = strdup(pair->value);
1116 if (pair->key == 130) {
1117 /* first join */
1118 firstjoin = 1;
1121 if (pair->key == 117) {
1122 /* message */
1123 msg = pair->value;
1126 if (pair->key == 124) {
1127 /* Message type */
1128 msgtype = atoi(pair->value);
1130 if (pair->key == 114) {
1131 /* message error not sure what all the pair values mean */
1132 /* but -1 means no session in room */
1133 chaterr = atoi(pair->value);
1137 if (!room) {
1138 if (pkt->service == YAHOO_SERVICE_CHATLOGOUT) { /* yahoo originated chat logout */
1139 YAHOO_CALLBACK(ext_yahoo_chat_yahoologout) (yid->yd->
1140 client_id, id);
1141 return;
1143 if (pkt->service == YAHOO_SERVICE_COMMENT && chaterr) {
1144 YAHOO_CALLBACK(ext_yahoo_chat_yahooerror) (yid->yd->
1145 client_id, id);
1146 return;
1149 WARNING(("We didn't get a room name, ignoring packet"));
1150 return;
1153 switch (pkt->service) {
1154 case YAHOO_SERVICE_CHATJOIN:
1155 if (y_list_length(members) != membercount) {
1156 WARNING(("Count of members doesn't match No. of members we got"));
1158 if (firstjoin && members) {
1159 YAHOO_CALLBACK(ext_yahoo_chat_join) (yid->yd->client_id,
1160 id, room, topic, members, yid->fd);
1161 } else if (who) {
1162 if (y_list_length(members) != 1) {
1163 WARNING(("Got more than 1 member on a normal join"));
1165 /* this should only ever have one, but just in case */
1166 while (members) {
1167 YList *n = members->next;
1168 currentmember = members->data;
1169 YAHOO_CALLBACK(ext_yahoo_chat_userjoin) (yid->
1170 yd->client_id, id, room, currentmember);
1171 y_list_free_1(members);
1172 members = n;
1175 break;
1176 case YAHOO_SERVICE_CHATEXIT:
1177 if (who) {
1178 YAHOO_CALLBACK(ext_yahoo_chat_userleave) (yid->yd->
1179 client_id, id, room, who);
1181 break;
1182 case YAHOO_SERVICE_COMMENT:
1183 if (who) {
1184 YAHOO_CALLBACK(ext_yahoo_chat_message) (yid->yd->
1185 client_id, id, who, room, msg, msgtype, utf8);
1187 break;
1191 static void yahoo_process_message(struct yahoo_input_data *yid,
1192 struct yahoo_packet *pkt)
1194 struct yahoo_data *yd = yid->yd;
1195 YList *l;
1196 YList *messages = NULL;
1198 struct m {
1199 int i_31;
1200 int i_32;
1201 char *to;
1202 char *from;
1203 long tm;
1204 char *msg;
1205 int utf8;
1206 char *gunk;
1207 } *message = y_new0(struct m, 1);
1209 for (l = pkt->hash; l; l = l->next) {
1210 struct yahoo_pair *pair = l->data;
1211 if (pair->key == 1 || pair->key == 4) {
1212 if (!message->from)
1213 message->from = pair->value;
1214 } else if (pair->key == 5)
1215 message->to = pair->value;
1216 else if (pair->key == 15)
1217 message->tm = strtol(pair->value, NULL, 10);
1218 else if (pair->key == 97)
1219 message->utf8 = atoi(pair->value);
1220 /* This comes when the official client sends us a message */
1221 else if (pair->key == 429)
1222 message->gunk = pair->value;
1223 /* user message *//* sys message */
1224 else if (pair->key == 14 || pair->key == 16)
1225 message->msg = pair->value;
1226 else if (pair->key == 31) {
1227 if (message->i_31) {
1228 messages = y_list_append(messages, message);
1229 message = y_new0(struct m, 1);
1231 message->i_31 = atoi(pair->value);
1232 } else if (pair->key == 32)
1233 message->i_32 = atoi(pair->value);
1234 else
1235 LOG(("yahoo_process_message: status: %d, key: %d, value: %s", pkt->status, pair->key, pair->value));
1238 messages = y_list_append(messages, message);
1240 for (l = messages; l; l = l->next) {
1241 message = l->data;
1242 if (pkt->service == YAHOO_SERVICE_SYSMESSAGE) {
1243 YAHOO_CALLBACK(ext_yahoo_system_message) (yd->client_id,
1244 message->to, message->from, message->msg);
1245 } else if (pkt->status <= 2 || pkt->status == 5) {
1246 /* Confirm message receipt if we got the gunk */
1247 if(message->gunk) {
1248 struct yahoo_packet *outpkt;
1250 outpkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE_CONFIRM,
1251 YPACKET_STATUS_DEFAULT, 0);
1252 yahoo_packet_hash(outpkt, 1, yd->user);
1253 yahoo_packet_hash(outpkt, 5, message->from);
1254 yahoo_packet_hash(outpkt, 302, "430");
1255 yahoo_packet_hash(outpkt, 430, message->gunk);
1256 yahoo_packet_hash(outpkt, 303, "430");
1257 yahoo_packet_hash(outpkt, 450, "0");
1258 yahoo_send_packet(yid, outpkt, 0);
1260 yahoo_packet_free(outpkt);
1263 if (!strcmp(message->msg, "<ding>"))
1264 YAHOO_CALLBACK(ext_yahoo_got_buzz) (yd->client_id,
1265 message->to, message->from, message->tm);
1266 else
1267 YAHOO_CALLBACK(ext_yahoo_got_im) (yd->client_id,
1268 message->to, message->from, message->msg,
1269 message->tm, pkt->status, message->utf8);
1270 } else if (pkt->status == 0xffffffff) {
1271 YAHOO_CALLBACK(ext_yahoo_error) (yd->client_id,
1272 message->msg, 0, E_SYSTEM);
1274 FREE(message);
1277 y_list_free(messages);
1281 * Here's what multi-level packets look like. Data in brackets is the value.
1283 * 3 level:
1284 * =======
1286 * 302 (318) - Beginning level 1
1287 * 300 (318) - Begin level 2
1288 * 302 (319) - End level 2 header
1289 * 300 (319) - Begin level 3
1290 * 301 (319) - End level 3
1291 * 303 (319) - End level 2
1292 * 303 (318) - End level 1
1294 * 2 level:
1295 * =======
1297 * 302 (315) - Beginning level 1
1298 * 300 (315) - Begin level 2
1299 * 301 (315) - End level 2
1300 * 303 (315) - End level 1
1303 static void yahoo_process_status(struct yahoo_input_data *yid,
1304 struct yahoo_packet *pkt)
1306 YList *l;
1307 struct yahoo_data *yd = yid->yd;
1309 struct yahoo_process_status_entry *u;
1311 YList *users = 0;
1313 if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
1314 YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id,
1315 YAHOO_LOGIN_DUPL, NULL);
1316 return;
1320 * Status updates may be spread accross multiple packets and not
1321 * even on buddy boundaries, so keeping some state is important.
1322 * So, continue where we left off, and only add a user entry to
1323 * the list once it's complete (301-315 End buddy).
1325 u = yd->half_user;
1327 for (l = pkt->hash; l; l = l->next) {
1328 struct yahoo_pair *pair = l->data;
1330 switch (pair->key) {
1331 case 300: /* Begin buddy */
1332 if (!strcmp(pair->value, "315") && !u) {
1333 u = yd->half_user = y_new0(struct yahoo_process_status_entry, 1);
1335 break;
1336 case 301: /* End buddy */
1337 if (!strcmp(pair->value, "315") && u) {
1338 users = y_list_prepend(users, u);
1339 u = yd->half_user = NULL;
1341 break;
1342 case 0: /* we won't actually do anything with this */
1343 NOTICE(("key %d:%s", pair->key, pair->value));
1344 break;
1345 case 1: /* we don't get the full buddy list here. */
1346 if (!yd->logged_in) {
1347 yd->logged_in = 1;
1348 if (yd->current_status < 0)
1349 yd->current_status = yd->initial_status;
1350 YAHOO_CALLBACK(ext_yahoo_login_response) (yd->
1351 client_id, YAHOO_LOGIN_OK, NULL);
1353 break;
1354 case 8: /* how many online buddies we have */
1355 NOTICE(("key %d:%s", pair->key, pair->value));
1356 break;
1357 case 7: /* the current buddy */
1358 if (!u) {
1359 /* This will only happen in case of a single level message */
1360 u = y_new0(struct yahoo_process_status_entry, 1);
1361 users = y_list_prepend(users, u);
1363 u->name = pair->value;
1364 break;
1365 case 10: /* state */
1366 u->state = strtol(pair->value, NULL, 10);
1367 break;
1368 case 19: /* custom status message */
1369 u->msg = pair->value;
1370 break;
1371 case 47: /* is it an away message or not. Not applicable for YMSG16 anymore */
1372 u->away = atoi(pair->value);
1373 break;
1374 case 137: /* seconds idle */
1375 u->idle = atoi(pair->value);
1376 break;
1377 case 11: /* this is the buddy's session id */
1378 u->buddy_session = atoi(pair->value);
1379 break;
1380 case 17: /* in chat? */
1381 u->f17 = atoi(pair->value);
1382 break;
1383 case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
1384 u->flags = atoi(pair->value);
1385 break;
1386 case 60: /* SMS -> 1 MOBILE USER */
1387 /* sometimes going offline makes this 2, but invisible never sends it */
1388 u->mobile = atoi(pair->value);
1389 break;
1390 case 138:
1391 u->f138 = atoi(pair->value);
1392 break;
1393 case 184:
1394 u->f184 = pair->value;
1395 break;
1396 case 192:
1397 u->f192 = atoi(pair->value);
1398 break;
1399 case 10001:
1400 u->f10001 = atoi(pair->value);
1401 break;
1402 case 10002:
1403 u->f10002 = atoi(pair->value);
1404 break;
1405 case 198:
1406 u->f198 = atoi(pair->value);
1407 break;
1408 case 197:
1409 u->f197 = pair->value;
1410 break;
1411 case 205:
1412 u->f205 = pair->value;
1413 break;
1414 case 213:
1415 u->f213 = atoi(pair->value);
1416 break;
1417 case 16: /* Custom error message */
1418 YAHOO_CALLBACK(ext_yahoo_error) (yd->client_id,
1419 pair->value, 0, E_CUSTOM);
1420 break;
1421 default:
1422 WARNING(("unknown status key %d:%s", pair->key,
1423 pair->value));
1424 break;
1428 while (users) {
1429 YList *t = users;
1430 struct yahoo_process_status_entry *u = users->data;
1432 if (u->name != NULL) {
1433 if (pkt->service ==
1434 YAHOO_SERVICE_LOGOFF
1435 /*|| u->flags == 0 No flags for YMSG16 */ ) {
1436 YAHOO_CALLBACK(ext_yahoo_status_changed) (yd->
1437 client_id, u->name,
1438 YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0);
1439 } else {
1440 /* Key 47 always seems to be 1 for YMSG16 */
1441 if (!u->state)
1442 u->away = 0;
1443 else
1444 u->away = 1;
1446 YAHOO_CALLBACK(ext_yahoo_status_changed) (yd->
1447 client_id, u->name, u->state, u->msg,
1448 u->away, u->idle, u->mobile);
1452 users = y_list_remove_link(users, users);
1453 y_list_free_1(t);
1454 FREE(u);
1458 static void yahoo_process_buddy_list(struct yahoo_input_data *yid,
1459 struct yahoo_packet *pkt)
1461 struct yahoo_data *yd = yid->yd;
1462 YList *l;
1463 int last_packet = 0;
1464 char *cur_group = NULL;
1465 struct yahoo_buddy *newbud = NULL;
1467 /* we could be getting multiple packets here */
1468 for (l = pkt->hash; l; l = l->next) {
1469 struct yahoo_pair *pair = l->data;
1471 switch (pair->key) {
1472 case 300:
1473 case 301:
1474 case 302:
1475 break; /* Separators. Our logic does not need them */
1476 case 303:
1477 if (318 == atoi(pair->value))
1478 last_packet = 1;
1479 break;
1480 case 65:
1481 cur_group = strdup(pair->value);
1482 break;
1483 case 7:
1484 newbud = y_new0(struct yahoo_buddy, 1);
1485 newbud->id = strdup(pair->value);
1486 if (cur_group)
1487 newbud->group = strdup(cur_group);
1488 else if (yd->buddies) {
1489 struct yahoo_buddy *lastbud =
1490 (struct yahoo_buddy *)y_list_nth(yd->
1491 buddies,
1492 y_list_length(yd->buddies) - 1)->data;
1493 newbud->group = strdup(lastbud->group);
1494 } else
1495 newbud->group = strdup("Buddies");
1497 yd->buddies = y_list_append(yd->buddies, newbud);
1499 break;
1503 /* we could be getting multiple packets here */
1504 if (pkt->hash && !last_packet)
1505 return;
1507 /* Logged in */
1508 if (!yd->logged_in) {
1509 yd->logged_in = 1;
1510 if (yd->current_status < 0)
1511 yd->current_status = yd->initial_status;
1512 YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id,
1513 YAHOO_LOGIN_OK, NULL);
1515 yahoo_set_away(yd->client_id, yd->initial_status, NULL,
1516 (yd->initial_status == YAHOO_STATUS_AVAILABLE) ? 0 : 1);
1518 yahoo_get_yab(yd->client_id);
1521 YAHOO_CALLBACK(ext_yahoo_got_buddies) (yd->client_id, yd->buddies);
1525 static void yahoo_process_list(struct yahoo_input_data *yid,
1526 struct yahoo_packet *pkt)
1528 struct yahoo_data *yd = yid->yd;
1529 YList *l;
1531 /* we could be getting multiple packets here */
1532 for (l = pkt->hash; l; l = l->next) {
1533 struct yahoo_pair *pair = l->data;
1535 switch (pair->key) {
1536 case 89: /* identities */
1538 char **identities =
1539 y_strsplit(pair->value, ",", -1);
1540 int i;
1541 for (i = 0; identities[i]; i++)
1542 yd->identities =
1543 y_list_append(yd->identities,
1544 strdup(identities[i]));
1545 y_strfreev(identities);
1547 YAHOO_CALLBACK(ext_yahoo_got_identities) (yd->client_id,
1548 yd->identities);
1549 break;
1550 case 59: /* cookies */
1551 if (pair->value[0] == 'Y') {
1552 FREE(yd->cookie_y);
1553 FREE(yd->login_cookie);
1555 yd->cookie_y = getcookie(pair->value);
1556 yd->login_cookie = getlcookie(yd->cookie_y);
1558 } else if (pair->value[0] == 'T') {
1559 FREE(yd->cookie_t);
1560 yd->cookie_t = getcookie(pair->value);
1562 } else if (pair->value[0] == 'C') {
1563 FREE(yd->cookie_c);
1564 yd->cookie_c = getcookie(pair->value);
1567 break;
1568 case 3: /* my id */
1569 case 90: /* 1 */
1570 case 100: /* 0 */
1571 case 101: /* NULL */
1572 case 102: /* NULL */
1573 case 93: /* 86400/1440 */
1574 break;
1578 if (yd->cookie_y && yd->cookie_t) /* We don't get cookie_c anymore */
1579 YAHOO_CALLBACK(ext_yahoo_got_cookies) (yd->client_id);
1582 static void yahoo_process_verify(struct yahoo_input_data *yid,
1583 struct yahoo_packet *pkt)
1585 struct yahoo_data *yd = yid->yd;
1587 if (pkt->status != 0x01) {
1588 DEBUG_MSG(("expected status: 0x01, got: %d", pkt->status));
1589 YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id,
1590 YAHOO_LOGIN_LOCK, "");
1591 return;
1594 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YPACKET_STATUS_DEFAULT,
1595 yd->session_id);
1597 yahoo_packet_hash(pkt, 1, yd->user);
1598 yahoo_send_packet(yid, pkt, 0);
1600 yahoo_packet_free(pkt);
1604 static void yahoo_process_picture_checksum(struct yahoo_input_data *yid,
1605 struct yahoo_packet *pkt)
1607 struct yahoo_data *yd = yid->yd;
1608 char *from;
1609 char *to;
1610 int checksum = 0;
1611 YList *l;
1613 for (l = pkt->hash; l; l = l->next) {
1614 struct yahoo_pair *pair = l->data;
1616 switch (pair->key) {
1617 case 1:
1618 case 4:
1619 from = pair->value;
1620 case 5:
1621 to = pair->value;
1622 break;
1623 case 212:
1624 break;
1625 case 192:
1626 checksum = atoi(pair->value);
1627 break;
1631 YAHOO_CALLBACK(ext_yahoo_got_buddyicon_checksum) (yd->client_id, to,
1632 from, checksum);
1635 static void yahoo_process_picture(struct yahoo_input_data *yid,
1636 struct yahoo_packet *pkt)
1638 struct yahoo_data *yd = yid->yd;
1639 char *url;
1640 char *from;
1641 char *to;
1642 int status = 0;
1643 int checksum = 0;
1644 YList *l;
1646 for (l = pkt->hash; l; l = l->next) {
1647 struct yahoo_pair *pair = l->data;
1649 switch (pair->key) {
1650 case 1:
1651 case 4: /* sender */
1652 from = pair->value;
1653 break;
1654 case 5: /* we */
1655 to = pair->value;
1656 break;
1657 case 13: /* request / sending */
1658 status = atoi(pair->value);
1659 break;
1660 case 20: /* url */
1661 url = pair->value;
1662 break;
1663 case 192: /*checksum */
1664 checksum = atoi(pair->value);
1665 break;
1669 switch (status) {
1670 case 1: /* this is a request, ignore for now */
1671 YAHOO_CALLBACK(ext_yahoo_got_buddyicon_request) (yd->client_id,
1672 to, from);
1673 break;
1674 case 2: /* this is cool - we get a picture :) */
1675 YAHOO_CALLBACK(ext_yahoo_got_buddyicon) (yd->client_id, to,
1676 from, url, checksum);
1677 break;
1681 static void yahoo_process_picture_upload(struct yahoo_input_data *yid,
1682 struct yahoo_packet *pkt)
1684 struct yahoo_data *yd = yid->yd;
1685 YList *l;
1686 char *url;
1688 if (pkt->status != 1)
1689 return; /* something went wrong */
1691 for (l = pkt->hash; l; l = l->next) {
1692 struct yahoo_pair *pair = l->data;
1694 switch (pair->key) {
1695 case 5: /* we */
1696 break;
1697 case 20: /* url */
1698 url = pair->value;
1699 break;
1700 case 27: /* local filename */
1701 break;
1702 case 38: /* time */
1703 break;
1707 YAHOO_CALLBACK(ext_yahoo_buddyicon_uploaded) (yd->client_id, url);
1710 void yahoo_login(int id, int initial)
1712 struct yahoo_data *yd = find_conn_by_id(id);
1713 struct connect_callback_data *ccd;
1714 struct yahoo_server_settings *yss;
1715 int tag;
1717 char *host;
1719 struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
1720 yid->yd = yd;
1721 yid->type = YAHOO_CONNECTION_PAGER;
1722 inputs = y_list_prepend(inputs, yid);
1724 yd->initial_status = initial;
1725 yss = yd->server_settings;
1727 ccd = y_new0(struct connect_callback_data, 1);
1728 ccd->yd = yd;
1730 host = yss->pager_host;
1732 if (!host)
1733 host = yss->pager_host_list[0];
1735 tag = YAHOO_CALLBACK(ext_yahoo_connect_async) (yd->client_id,
1736 host, yss->pager_port, yahoo_connected, ccd, 0);
1739 * if tag <= 0, then callback has already been called
1740 * so ccd will have been freed
1742 if (tag > 0)
1743 ccd->tag = tag;
1744 else if (tag < 0)
1745 YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id,
1746 YAHOO_LOGIN_SOCK, NULL);
1749 static void yahoo_auth_https(struct yahoo_data *yd)
1751 char url[256];
1752 char *user_encoded, *pass_encoded, *seed_encoded;
1754 struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
1756 yid->yd = yd;
1757 yid->type = YAHOO_CONNECTION_AUTH;
1759 inputs = y_list_prepend(inputs, yid);
1761 user_encoded = yahoo_urlencode(yid->yd->user);
1762 pass_encoded = yahoo_urlencode(yid->yd->password);
1763 seed_encoded = yahoo_urlencode(yid->yd->seed);
1765 snprintf(url, sizeof(url),
1766 "https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts="
1767 "&login=%s&passwd=%s&chal=%s", user_encoded, pass_encoded,
1768 seed_encoded);
1770 yahoo_http_get(yid->yd->client_id, url, NULL, 1, 0,
1771 _yahoo_http_connected, yid);
1773 FREE(user_encoded);
1774 FREE(pass_encoded);
1775 FREE(seed_encoded);
1778 static void yahoo_process_auth(struct yahoo_input_data *yid,
1779 struct yahoo_packet *pkt)
1781 char *seed = NULL;
1782 char *sn = NULL;
1783 YList *l = pkt->hash;
1784 int m = 0;
1785 struct yahoo_data *yd = yid->yd;
1787 while (l) {
1788 struct yahoo_pair *pair = l->data;
1790 switch (pair->key) {
1791 case 94:
1792 seed = pair->value;
1793 break;
1794 case 1:
1795 sn = pair->value;
1796 break;
1797 case 13:
1798 m = atoi(pair->value);
1799 break;
1801 l = l->next;
1804 if (!seed)
1805 return;
1807 yd->seed = strdup(seed);
1809 if (m==2)
1810 yahoo_auth_https(yd);
1811 else {
1812 /* call error */
1813 WARNING(("unknown auth type %d", m));
1814 YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id,
1815 YAHOO_LOGIN_UNKNOWN, NULL);
1819 static void yahoo_send_auth(struct yahoo_data *yd)
1822 struct yahoo_packet *packet;
1824 unsigned char crypt_hash[25];
1826 md5_byte_t result[16];
1827 md5_state_t ctx;
1829 struct yahoo_input_data *yid =
1830 find_input_by_id_and_type(yd->client_id,
1831 YAHOO_CONNECTION_PAGER);
1833 /* HTTPS */
1834 md5_init(&ctx);
1835 md5_append(&ctx, (md5_byte_t *)yd->crumb, strlen(yd->crumb));
1836 md5_append(&ctx, (md5_byte_t *)yd->seed, strlen(yd->seed));
1837 md5_finish(&ctx, result);
1839 to_y64(crypt_hash, result, 16);
1841 packet = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP,
1842 yd->initial_status, yd->session_id);
1843 yahoo_packet_hash(packet, 1, yd->user);
1844 yahoo_packet_hash(packet, 0, yd->user);
1845 yahoo_packet_hash(packet, 277, yd->cookie_y);
1846 yahoo_packet_hash(packet, 278, yd->cookie_t);
1847 yahoo_packet_hash(packet, 307, (char *)crypt_hash);
1848 yahoo_packet_hash(packet, 244, "4194239"); /* Rekkanoryo says this is the build number */
1849 yahoo_packet_hash(packet, 2, yd->user);
1850 yahoo_packet_hash(packet, 2, "1");
1851 yahoo_packet_hash(packet, 59, yd->cookie_b);
1852 yahoo_packet_hash(packet, 98, "us"); /* TODO Put country code */
1853 yahoo_packet_hash(packet, 135, "9.0.0.2152");
1855 yahoo_send_packet(yid, packet, 0);
1857 yahoo_packet_free(packet);
1860 static void yahoo_process_auth_resp(struct yahoo_input_data *yid,
1861 struct yahoo_packet *pkt)
1863 struct yahoo_data *yd = yid->yd;
1864 char *login_id;
1865 char *handle;
1866 char *url = NULL;
1867 int login_status = -1;
1869 YList *l;
1871 for (l = pkt->hash; l; l = l->next) {
1872 struct yahoo_pair *pair = l->data;
1873 if (pair->key == 0)
1874 login_id = pair->value;
1875 else if (pair->key == 1)
1876 handle = pair->value;
1877 else if (pair->key == 20)
1878 url = pair->value;
1879 else if (pair->key == 66)
1880 login_status = atoi(pair->value);
1883 if (pkt->status == YPACKET_STATUS_DISCONNECTED) {
1884 YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id,
1885 login_status, url);
1886 /* yahoo_logoff(yd->client_id); */
1890 static void yahoo_process_mail(struct yahoo_input_data *yid,
1891 struct yahoo_packet *pkt)
1893 struct yahoo_data *yd = yid->yd;
1894 char *who = NULL;
1895 char *email = NULL;
1896 char *subj = NULL;
1897 int count = 0;
1898 YList *l;
1900 for (l = pkt->hash; l; l = l->next) {
1901 struct yahoo_pair *pair = l->data;
1902 if (pair->key == 9)
1903 count = strtol(pair->value, NULL, 10);
1904 else if (pair->key == 43)
1905 who = pair->value;
1906 else if (pair->key == 42)
1907 email = pair->value;
1908 else if (pair->key == 18)
1909 subj = pair->value;
1910 else
1911 LOG(("key: %d => value: %s", pair->key, pair->value));
1914 if (who && email && subj) {
1915 char from[1024];
1916 snprintf(from, sizeof(from), "%s (%s)", who, email);
1917 YAHOO_CALLBACK(ext_yahoo_mail_notify) (yd->client_id, from,
1918 subj, count);
1919 } else if (count > 0)
1920 YAHOO_CALLBACK(ext_yahoo_mail_notify) (yd->client_id, NULL,
1921 NULL, count);
1924 static void yahoo_process_new_contact(struct yahoo_input_data *yid,
1925 struct yahoo_packet *pkt)
1927 struct yahoo_data *yd = yid->yd;
1928 char *me = NULL;
1929 char *who = NULL;
1930 char *msg = NULL;
1931 int online = -1;
1933 YList *l;
1934 for (l = pkt->hash; l; l = l->next) {
1935 struct yahoo_pair *pair = l->data;
1936 if (pair->key == 4)
1937 who = pair->value;
1938 else if (pair->key == 5)
1939 me = pair->value;
1940 else if (pair->key == 14)
1941 msg = pair->value;
1942 else if (pair->key == 13)
1943 online = strtol(pair->value, NULL, 10);
1946 if (pkt->status == 3) { // auth request
1947 YAHOO_CALLBACK(ext_yahoo_auth_request) (yd->client_id, who, msg);
1949 else if (pkt->status == 1) {
1950 /* if (who && online == 1)
1951 YAHOO_CALLBACK(ext_yahoo_contact_added) (yd->client_id, me, who,
1952 msg);
1953 else */if (online == 2)
1954 YAHOO_CALLBACK(ext_yahoo_rejected) (yd->client_id, who, msg);
1958 /* UNUSED? */
1959 static void yahoo_process_contact(struct yahoo_input_data *yid,
1960 struct yahoo_packet *pkt)
1962 struct yahoo_data *yd = yid->yd;
1963 char *id = NULL;
1964 char *who = NULL;
1965 char *msg = NULL;
1966 char *name = NULL;
1967 long tm = 0L;
1968 int state = YAHOO_STATUS_AVAILABLE;
1969 int online = 0;
1970 int away = 0;
1971 int idle = 0;
1972 int mobile = 0;
1974 YList *l;
1976 for (l = pkt->hash; l; l = l->next) {
1977 struct yahoo_pair *pair = l->data;
1978 if (pair->key == 1)
1979 id = pair->value;
1980 else if (pair->key == 3)
1981 who = pair->value;
1982 else if (pair->key == 14)
1983 msg = pair->value;
1984 else if (pair->key == 7)
1985 name = pair->value;
1986 else if (pair->key == 10)
1987 state = strtol(pair->value, NULL, 10);
1988 else if (pair->key == 15)
1989 tm = strtol(pair->value, NULL, 10);
1990 else if (pair->key == 13)
1991 online = strtol(pair->value, NULL, 10);
1992 else if (pair->key == 47)
1993 away = strtol(pair->value, NULL, 10);
1994 else if (pair->key == 137)
1995 idle = strtol(pair->value, NULL, 10);
1996 else if (pair->key == 60)
1997 mobile = strtol(pair->value, NULL, 10);
2001 if (id)
2002 YAHOO_CALLBACK(ext_yahoo_contact_added) (yd->client_id, id, who,
2003 msg);
2004 else if (name)
2005 YAHOO_CALLBACK(ext_yahoo_status_changed) (yd->client_id, name,
2006 state, msg, away, idle, mobile);
2007 else if (pkt->status == 0x07)
2008 YAHOO_CALLBACK(ext_yahoo_rejected) (yd->client_id, who, msg);
2011 static void yahoo_process_buddyadd(struct yahoo_input_data *yid,
2012 struct yahoo_packet *pkt)
2014 struct yahoo_data *yd = yid->yd;
2015 char *who = NULL;
2016 char *where = NULL;
2017 int status = 0;
2018 char *me = NULL;
2020 struct yahoo_buddy *bud = NULL;
2022 YList *l;
2023 for (l = pkt->hash; l; l = l->next) {
2024 struct yahoo_pair *pair = l->data;
2025 if (pair->key == 1)
2026 me = pair->value;
2027 if (pair->key == 7)
2028 who = pair->value;
2029 if (pair->key == 65)
2030 where = pair->value;
2031 if (pair->key == 66)
2032 status = strtol(pair->value, NULL, 10);
2035 if (!who)
2036 return;
2037 if (!where)
2038 where = "Unknown";
2040 bud = y_new0(struct yahoo_buddy, 1);
2041 bud->id = strdup(who);
2042 bud->group = strdup(where);
2043 bud->real_name = NULL;
2045 yd->buddies = y_list_append(yd->buddies, bud);
2047 /* A non-zero status (i've seen 2) seems to mean the buddy is already
2048 * added and is online */
2049 if (status) {
2050 LOG(("Setting online see packet for info"));
2051 yahoo_dump_unhandled(pkt);
2052 YAHOO_CALLBACK(ext_yahoo_status_changed) (yd->client_id, who,
2053 YAHOO_STATUS_AVAILABLE, NULL, 0, 0, 0);
2057 static void yahoo_process_buddydel(struct yahoo_input_data *yid,
2058 struct yahoo_packet *pkt)
2060 struct yahoo_data *yd = yid->yd;
2061 char *who = NULL;
2062 char *where = NULL;
2063 int unk_66 = 0;
2064 char *me = NULL;
2065 struct yahoo_buddy *bud;
2067 YList *buddy;
2069 YList *l;
2070 for (l = pkt->hash; l; l = l->next) {
2071 struct yahoo_pair *pair = l->data;
2072 if (pair->key == 1)
2073 me = pair->value;
2074 else if (pair->key == 7)
2075 who = pair->value;
2076 else if (pair->key == 65)
2077 where = pair->value;
2078 else if (pair->key == 66)
2079 unk_66 = strtol(pair->value, NULL, 10);
2080 else
2081 DEBUG_MSG(("unknown key: %d = %s", pair->key,
2082 pair->value));
2085 if (!who || !where)
2086 return;
2088 bud = y_new0(struct yahoo_buddy, 1);
2089 bud->id = strdup(who);
2090 bud->group = strdup(where);
2092 buddy = y_list_find_custom(yd->buddies, bud, is_same_bud);
2094 FREE(bud->id);
2095 FREE(bud->group);
2096 FREE(bud);
2098 if (buddy) {
2099 bud = buddy->data;
2100 yd->buddies = y_list_remove_link(yd->buddies, buddy);
2101 y_list_free_1(buddy);
2103 FREE(bud->id);
2104 FREE(bud->group);
2105 FREE(bud->real_name);
2106 FREE(bud);
2108 bud = NULL;
2112 static void yahoo_process_ignore(struct yahoo_input_data *yid,
2113 struct yahoo_packet *pkt)
2115 char *who = NULL;
2116 int status = 0;
2117 char *me = NULL;
2118 int un_ignore = 0;
2120 YList *l;
2121 for (l = pkt->hash; l; l = l->next) {
2122 struct yahoo_pair *pair = l->data;
2123 if (pair->key == 0)
2124 who = pair->value;
2125 if (pair->key == 1)
2126 me = pair->value;
2127 if (pair->key == 13) /* 1 == ignore, 2 == unignore */
2128 un_ignore = strtol(pair->value, NULL, 10);
2129 if (pair->key == 66)
2130 status = strtol(pair->value, NULL, 10);
2134 * status
2135 * 0 - ok
2136 * 2 - already in ignore list, could not add
2137 * 3 - not in ignore list, could not delete
2138 * 12 - is a buddy, could not add
2141 /* if(status)
2142 YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, who, 0, status);
2146 static void yahoo_process_voicechat(struct yahoo_input_data *yid,
2147 struct yahoo_packet *pkt)
2149 char *who = NULL;
2150 char *me = NULL;
2151 char *room = NULL;
2152 char *voice_room = NULL;
2154 YList *l;
2155 for (l = pkt->hash; l; l = l->next) {
2156 struct yahoo_pair *pair = l->data;
2157 if (pair->key == 4)
2158 who = pair->value;
2159 if (pair->key == 5)
2160 me = pair->value;
2161 if (pair->key == 13)
2162 voice_room = pair->value;
2163 if (pair->key == 57)
2164 room = pair->value;
2167 NOTICE(("got voice chat invite from %s in %s to identity %s", who, room,
2168 me));
2170 * send: s:0 1:me 5:who 57:room 13:1
2171 * ???? s:4 5:who 10:99 19:-1615114531
2172 * gotr: s:4 5:who 10:99 19:-1615114615
2173 * ???? s:1 5:me 4:who 57:room 13:3room
2174 * got: s:1 5:me 4:who 57:room 13:1room
2175 * rej: s:0 1:me 5:who 57:room 13:3
2176 * rejr: s:4 5:who 10:99 19:-1617114599
2180 static void yahoo_process_ping(struct yahoo_input_data *yid,
2181 struct yahoo_packet *pkt)
2183 char *errormsg = NULL;
2185 YList *l;
2186 for (l = pkt->hash; l; l = l->next) {
2187 struct yahoo_pair *pair = l->data;
2188 if (pair->key == 16)
2189 errormsg = pair->value;
2192 NOTICE(("got ping packet"));
2193 YAHOO_CALLBACK(ext_yahoo_got_ping) (yid->yd->client_id, errormsg);
2196 static void yahoo_process_buddy_change_group(struct yahoo_input_data *yid,
2197 struct yahoo_packet *pkt)
2199 YList *l;
2200 char *me = NULL;
2201 char *who = NULL;
2202 char *old_group = NULL;
2203 char *new_group = NULL;
2205 for (l = pkt->hash; l; l = l->next) {
2206 struct yahoo_pair *pair = l->data;
2207 if (pair->key == 1)
2208 me = pair->value;
2209 if (pair->key == 7)
2210 who = pair->value;
2211 if (pair->key == 224)
2212 old_group = pair->value;
2213 if (pair->key == 264)
2214 new_group = pair->value;
2217 YAHOO_CALLBACK(ext_yahoo_got_buddy_change_group) (yid->yd->client_id,
2218 me, who, old_group, new_group);
2221 static void _yahoo_webcam_get_server_connected(void *fd, int error, void *d)
2223 struct yahoo_input_data *yid = d;
2224 char *who = yid->wcm->user;
2225 char *data = NULL;
2226 char *packet = NULL;
2227 unsigned char magic_nr[] = { 0, 1, 0 };
2228 unsigned char header_len = 8;
2229 unsigned int len = 0;
2230 unsigned int pos = 0;
2232 if (error || !fd) {
2233 FREE(who);
2234 FREE(yid);
2235 return;
2238 yid->fd = fd;
2239 inputs = y_list_prepend(inputs, yid);
2241 /* send initial packet */
2242 if (who)
2243 data = strdup("<RVWCFG>");
2244 else
2245 data = strdup("<RUPCFG>");
2246 yahoo_add_to_send_queue(yid, data, strlen(data));
2247 FREE(data);
2249 /* send data */
2250 if (who) {
2251 data = strdup("g=");
2252 data = y_string_append(data, who);
2253 data = y_string_append(data, "\r\n");
2254 } else {
2255 data = strdup("f=1\r\n");
2257 len = strlen(data);
2258 packet = y_new0(char, header_len + len);
2259 packet[pos++] = header_len;
2260 memcpy(packet + pos, magic_nr, sizeof(magic_nr));
2261 pos += sizeof(magic_nr);
2262 pos += yahoo_put32(packet + pos, len);
2263 memcpy(packet + pos, data, len);
2264 pos += len;
2265 yahoo_add_to_send_queue(yid, packet, pos);
2266 FREE(packet);
2267 FREE(data);
2269 yid->read_tag =
2270 YAHOO_CALLBACK(ext_yahoo_add_handler) (yid->yd->client_id, fd,
2271 YAHOO_INPUT_READ, yid);
2274 static void yahoo_webcam_get_server(struct yahoo_input_data *y, char *who,
2275 char *key)
2277 struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
2278 struct yahoo_server_settings *yss = y->yd->server_settings;
2280 yid->type = YAHOO_CONNECTION_WEBCAM_MASTER;
2281 yid->yd = y->yd;
2282 yid->wcm = y_new0(struct yahoo_webcam, 1);
2283 yid->wcm->user = who ? strdup(who) : NULL;
2284 yid->wcm->direction = who ? YAHOO_WEBCAM_DOWNLOAD : YAHOO_WEBCAM_UPLOAD;
2285 yid->wcm->key = strdup(key);
2287 YAHOO_CALLBACK(ext_yahoo_connect_async) (yid->yd->client_id,
2288 yss->webcam_host, yss->webcam_port,
2289 _yahoo_webcam_get_server_connected, yid, 0);
2293 static YList *webcam_queue = NULL;
2294 static void yahoo_process_webcam_key(struct yahoo_input_data *yid,
2295 struct yahoo_packet *pkt)
2297 char *me = NULL;
2298 char *key = NULL;
2299 char *who = NULL;
2301 YList *l;
2302 yahoo_dump_unhandled(pkt);
2303 for (l = pkt->hash; l; l = l->next) {
2304 struct yahoo_pair *pair = l->data;
2305 if (pair->key == 5)
2306 me = pair->value;
2307 if (pair->key == 61)
2308 key = pair->value;
2311 l = webcam_queue;
2312 if (!l)
2313 return;
2314 who = l->data;
2315 webcam_queue = y_list_remove_link(webcam_queue, webcam_queue);
2316 y_list_free_1(l);
2317 yahoo_webcam_get_server(yid, who, key);
2318 FREE(who);
2321 static void yahoo_packet_process(struct yahoo_input_data *yid,
2322 struct yahoo_packet *pkt)
2324 DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service));
2325 switch (pkt->service) {
2326 case YAHOO_SERVICE_USERSTAT:
2327 case YAHOO_SERVICE_LOGON:
2328 case YAHOO_SERVICE_LOGOFF:
2329 case YAHOO_SERVICE_ISAWAY:
2330 case YAHOO_SERVICE_ISBACK:
2331 case YAHOO_SERVICE_GAMELOGON:
2332 case YAHOO_SERVICE_GAMELOGOFF:
2333 case YAHOO_SERVICE_IDACT:
2334 case YAHOO_SERVICE_IDDEACT:
2335 case YAHOO_SERVICE_Y6_STATUS_UPDATE:
2336 case YAHOO_SERVICE_Y8_STATUS:
2337 yahoo_process_status(yid, pkt);
2338 break;
2339 case YAHOO_SERVICE_NOTIFY:
2340 yahoo_process_notify(yid, pkt);
2341 break;
2342 case YAHOO_SERVICE_MESSAGE:
2343 case YAHOO_SERVICE_GAMEMSG:
2344 case YAHOO_SERVICE_SYSMESSAGE:
2345 yahoo_process_message(yid, pkt);
2346 break;
2347 case YAHOO_SERVICE_NEWMAIL:
2348 yahoo_process_mail(yid, pkt);
2349 break;
2350 case YAHOO_SERVICE_Y7_AUTHORIZATION:
2351 yahoo_process_new_contact(yid, pkt);
2352 break;
2353 case YAHOO_SERVICE_NEWCONTACT:
2354 yahoo_process_contact(yid, pkt);
2355 break;
2356 case YAHOO_SERVICE_LIST:
2357 yahoo_process_list(yid, pkt);
2358 break;
2359 case YAHOO_SERVICE_VERIFY:
2360 yahoo_process_verify(yid, pkt);
2361 break;
2362 case YAHOO_SERVICE_AUTH:
2363 yahoo_process_auth(yid, pkt);
2364 break;
2365 case YAHOO_SERVICE_AUTHRESP:
2366 yahoo_process_auth_resp(yid, pkt);
2367 break;
2368 case YAHOO_SERVICE_CONFINVITE:
2369 case YAHOO_SERVICE_CONFADDINVITE:
2370 case YAHOO_SERVICE_CONFDECLINE:
2371 case YAHOO_SERVICE_CONFLOGON:
2372 case YAHOO_SERVICE_CONFLOGOFF:
2373 case YAHOO_SERVICE_CONFMSG:
2374 yahoo_process_conference(yid, pkt);
2375 break;
2376 case YAHOO_SERVICE_CHATONLINE:
2377 case YAHOO_SERVICE_CHATGOTO:
2378 case YAHOO_SERVICE_CHATJOIN:
2379 case YAHOO_SERVICE_CHATLEAVE:
2380 case YAHOO_SERVICE_CHATEXIT:
2381 case YAHOO_SERVICE_CHATLOGOUT:
2382 case YAHOO_SERVICE_CHATPING:
2383 case YAHOO_SERVICE_COMMENT:
2384 yahoo_process_chat(yid, pkt);
2385 break;
2386 case YAHOO_SERVICE_P2PFILEXFER:
2387 case YAHOO_SERVICE_Y7_FILETRANSFER:
2388 yahoo_process_filetransfer(yid, pkt);
2389 break;
2390 case YAHOO_SERVICE_Y7_FILETRANSFERINFO:
2391 yahoo_process_filetransferinfo(yid, pkt);
2392 break;
2393 case YAHOO_SERVICE_Y7_FILETRANSFERACCEPT:
2394 yahoo_process_filetransferaccept(yid, pkt);
2395 break;
2396 case YAHOO_SERVICE_ADDBUDDY:
2397 yahoo_process_buddyadd(yid, pkt);
2398 break;
2399 case YAHOO_SERVICE_REMBUDDY:
2400 yahoo_process_buddydel(yid, pkt);
2401 break;
2402 case YAHOO_SERVICE_IGNORECONTACT:
2403 yahoo_process_ignore(yid, pkt);
2404 break;
2405 case YAHOO_SERVICE_VOICECHAT:
2406 yahoo_process_voicechat(yid, pkt);
2407 break;
2408 case YAHOO_SERVICE_WEBCAM:
2409 yahoo_process_webcam_key(yid, pkt);
2410 break;
2411 case YAHOO_SERVICE_PING:
2412 yahoo_process_ping(yid, pkt);
2413 break;
2414 case YAHOO_SERVICE_Y7_CHANGE_GROUP:
2415 yahoo_process_buddy_change_group(yid, pkt);
2416 break;
2417 case YAHOO_SERVICE_IDLE:
2418 case YAHOO_SERVICE_MAILSTAT:
2419 case YAHOO_SERVICE_CHATINVITE:
2420 case YAHOO_SERVICE_CALENDAR:
2421 case YAHOO_SERVICE_NEWPERSONALMAIL:
2422 case YAHOO_SERVICE_ADDIDENT:
2423 case YAHOO_SERVICE_ADDIGNORE:
2424 case YAHOO_SERVICE_GOTGROUPRENAME:
2425 case YAHOO_SERVICE_GROUPRENAME:
2426 case YAHOO_SERVICE_PASSTHROUGH2:
2427 case YAHOO_SERVICE_CHATLOGON:
2428 case YAHOO_SERVICE_CHATLOGOFF:
2429 case YAHOO_SERVICE_CHATMSG:
2430 case YAHOO_SERVICE_REJECTCONTACT:
2431 case YAHOO_SERVICE_PEERTOPEER:
2432 WARNING(("unhandled service 0x%02x", pkt->service));
2433 yahoo_dump_unhandled(pkt);
2434 break;
2435 case YAHOO_SERVICE_PICTURE:
2436 yahoo_process_picture(yid, pkt);
2437 break;
2438 case YAHOO_SERVICE_PICTURE_CHECKSUM:
2439 yahoo_process_picture_checksum(yid, pkt);
2440 break;
2441 case YAHOO_SERVICE_PICTURE_UPLOAD:
2442 yahoo_process_picture_upload(yid, pkt);
2443 break;
2444 case YAHOO_SERVICE_Y8_LIST: /* Buddy List */
2445 yahoo_process_buddy_list(yid, pkt);
2446 break;
2447 default:
2448 WARNING(("unknown service 0x%02x", pkt->service));
2449 yahoo_dump_unhandled(pkt);
2450 break;
2454 static struct yahoo_packet *yahoo_getdata(struct yahoo_input_data *yid)
2456 struct yahoo_packet *pkt;
2457 struct yahoo_data *yd = yid->yd;
2458 int pos = 0;
2459 int pktlen;
2461 if (!yd)
2462 return NULL;
2464 DEBUG_MSG(("rxlen is %d", yid->rxlen));
2465 if (yid->rxlen < YAHOO_PACKET_HDRLEN) {
2466 DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN"));
2467 return NULL;
2470 pos += 4; /* YMSG */
2471 pos += 2;
2472 pos += 2;
2474 pktlen = yahoo_get16(yid->rxqueue + pos);
2475 pos += 2;
2476 DEBUG_MSG(("%d bytes to read, rxlen is %d", pktlen, yid->rxlen));
2478 if (yid->rxlen < (YAHOO_PACKET_HDRLEN + pktlen)) {
2479 DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN + pktlen"));
2480 return NULL;
2483 LOG(("reading packet"));
2484 yahoo_packet_dump(yid->rxqueue, YAHOO_PACKET_HDRLEN + pktlen);
2486 pkt = yahoo_packet_new(0, 0, 0);
2488 pkt->service = yahoo_get16(yid->rxqueue + pos);
2489 pos += 2;
2490 pkt->status = yahoo_get32(yid->rxqueue + pos);
2491 pos += 4;
2492 DEBUG_MSG(("Yahoo Service: 0x%02x Status: %d", pkt->service,
2493 pkt->status));
2494 pkt->id = yahoo_get32(yid->rxqueue + pos);
2495 pos += 4;
2497 yd->session_id = pkt->id;
2499 yahoo_packet_read(pkt, yid->rxqueue + pos, pktlen);
2501 yid->rxlen -= YAHOO_PACKET_HDRLEN + pktlen;
2502 DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2503 if (yid->rxlen > 0) {
2504 unsigned char *tmp = y_memdup(yid->rxqueue + YAHOO_PACKET_HDRLEN
2505 + pktlen, yid->rxlen);
2506 FREE(yid->rxqueue);
2507 yid->rxqueue = tmp;
2508 DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen,
2509 yid->rxqueue));
2510 } else {
2511 DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
2512 FREE(yid->rxqueue);
2515 return pkt;
2518 static struct yab *yahoo_yab_read(unsigned char *d, int len)
2520 char *st, *en;
2521 char *data = (char *)d;
2522 struct yab *yab = NULL;
2524 data[len] = '\0';
2526 DEBUG_MSG(("Got yab: %s", data));
2527 st = en = strstr(data, "e0=\"");
2528 if (st) {
2529 yab = y_new0(struct yab, 1);
2531 st += strlen("e0=\"");
2532 en = strchr(st, '"');
2533 *en++ = '\0';
2534 yab->email = yahoo_xmldecode(st);
2537 if (!en)
2538 return NULL;
2540 st = strstr(en, "id=\"");
2541 if (st) {
2542 st += strlen("id=\"");
2543 en = strchr(st, '"');
2544 *en++ = '\0';
2545 yab->yid = atoi(yahoo_xmldecode(st));
2548 st = strstr(en, "fn=\"");
2549 if (st) {
2550 st += strlen("fn=\"");
2551 en = strchr(st, '"');
2552 *en++ = '\0';
2553 yab->fname = yahoo_xmldecode(st);
2556 st = strstr(en, "ln=\"");
2557 if (st) {
2558 st += strlen("ln=\"");
2559 en = strchr(st, '"');
2560 *en++ = '\0';
2561 yab->lname = yahoo_xmldecode(st);
2564 st = strstr(en, "nn=\"");
2565 if (st) {
2566 st += strlen("nn=\"");
2567 en = strchr(st, '"');
2568 *en++ = '\0';
2569 yab->nname = yahoo_xmldecode(st);
2572 st = strstr(en, "yi=\"");
2573 if (st) {
2574 st += strlen("yi=\"");
2575 en = strchr(st, '"');
2576 *en++ = '\0';
2577 yab->id = yahoo_xmldecode(st);
2580 st = strstr(en, "hphone=\"");
2581 if (st) {
2582 st += strlen("hphone=\"");
2583 en = strchr(st, '"');
2584 *en++ = '\0';
2585 yab->hphone = yahoo_xmldecode(st);
2588 st = strstr(en, "wphone=\"");
2589 if (st) {
2590 st += strlen("wphone=\"");
2591 en = strchr(st, '"');
2592 *en++ = '\0';
2593 yab->wphone = yahoo_xmldecode(st);
2596 st = strstr(en, "mphone=\"");
2597 if (st) {
2598 st += strlen("mphone=\"");
2599 en = strchr(st, '"');
2600 *en++ = '\0';
2601 yab->mphone = yahoo_xmldecode(st);
2604 st = strstr(en, "dbid=\"");
2605 if (st) {
2606 st += strlen("dbid=\"");
2607 en = strchr(st, '"');
2608 *en++ = '\0';
2609 yab->dbid = atoi(st);
2612 return yab;
2615 static struct yab *yahoo_getyab(struct yahoo_input_data *yid)
2617 struct yab *yab = NULL;
2618 int pos = 0, end = 0;
2619 struct yahoo_data *yd = yid->yd;
2621 if (!yd)
2622 return NULL;
2624 do {
2625 DEBUG_MSG(("rxlen is %d", yid->rxlen));
2627 if (yid->rxlen <= strlen("<ct"))
2628 return NULL;
2630 /* start with <ct */
2631 while (pos < yid->rxlen - strlen("<ct") + 1
2632 && memcmp(yid->rxqueue + pos, "<ct", strlen("<ct")))
2633 pos++;
2635 if (pos >= yid->rxlen - 1)
2636 return NULL;
2638 end = pos + 2;
2639 /* end with > */
2640 while (end < yid->rxlen - strlen(">")
2641 && memcmp(yid->rxqueue + end, ">", strlen(">")))
2642 end++;
2644 if (end >= yid->rxlen - 1)
2645 return NULL;
2647 yab = yahoo_yab_read(yid->rxqueue + pos, end + 2 - pos);
2649 yid->rxlen -= end + 1;
2650 DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen,
2651 yid->rxqueue));
2652 if (yid->rxlen > 0) {
2653 unsigned char *tmp =
2654 y_memdup(yid->rxqueue + end + 1, yid->rxlen);
2655 FREE(yid->rxqueue);
2656 yid->rxqueue = tmp;
2657 DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen,
2658 yid->rxqueue));
2659 } else {
2660 DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
2661 FREE(yid->rxqueue);
2664 } while (!yab && end < yid->rxlen - 1);
2666 return yab;
2669 static char *yahoo_getwebcam_master(struct yahoo_input_data *yid)
2671 unsigned int pos = 0;
2672 unsigned int len = 0;
2673 unsigned int status = 0;
2674 char *server = NULL;
2675 struct yahoo_data *yd = yid->yd;
2677 if (!yid || !yd)
2678 return NULL;
2680 DEBUG_MSG(("rxlen is %d", yid->rxlen));
2682 len = yid->rxqueue[pos++];
2683 if (yid->rxlen < len)
2684 return NULL;
2686 /* extract status (0 = ok, 6 = webcam not online) */
2687 status = yid->rxqueue[pos++];
2689 if (status == 0) {
2690 pos += 2; /* skip next 2 bytes */
2691 server = y_memdup(yid->rxqueue + pos, 16);
2692 pos += 16;
2693 } else if (status == 6) {
2694 YAHOO_CALLBACK(ext_yahoo_webcam_closed)
2695 (yd->client_id, yid->wcm->user, 4);
2698 /* skip rest of the data */
2700 yid->rxlen -= len;
2701 DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2702 if (yid->rxlen > 0) {
2703 unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
2704 FREE(yid->rxqueue);
2705 yid->rxqueue = tmp;
2706 DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen,
2707 yid->rxqueue));
2708 } else {
2709 DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
2710 FREE(yid->rxqueue);
2713 return server;
2716 static int yahoo_get_webcam_data(struct yahoo_input_data *yid)
2718 unsigned char reason = 0;
2719 unsigned int pos = 0;
2720 unsigned int begin = 0;
2721 unsigned int end = 0;
2722 unsigned int closed = 0;
2723 unsigned char header_len = 0;
2724 char *who;
2725 int connect = 0;
2726 struct yahoo_data *yd = yid->yd;
2728 if (!yd)
2729 return -1;
2731 if (!yid->wcm || !yid->wcd || !yid->rxlen)
2732 return -1;
2734 DEBUG_MSG(("rxlen is %d", yid->rxlen));
2736 /* if we are not reading part of image then read header */
2737 if (!yid->wcd->to_read) {
2738 header_len = yid->rxqueue[pos++];
2739 yid->wcd->packet_type = 0;
2741 if (yid->rxlen < header_len)
2742 return 0;
2744 if (header_len >= 8) {
2745 reason = yid->rxqueue[pos++];
2746 /* next 2 bytes should always be 05 00 */
2747 pos += 2;
2748 yid->wcd->data_size = yahoo_get32(yid->rxqueue + pos);
2749 pos += 4;
2750 yid->wcd->to_read = yid->wcd->data_size;
2752 if (header_len >= 13) {
2753 yid->wcd->packet_type = yid->rxqueue[pos++];
2754 yid->wcd->timestamp = yahoo_get32(yid->rxqueue + pos);
2755 pos += 4;
2758 /* skip rest of header */
2759 pos = header_len;
2762 begin = pos;
2763 pos += yid->wcd->to_read;
2764 if (pos > yid->rxlen)
2765 pos = yid->rxlen;
2767 /* if it is not an image then make sure we have the whole packet */
2768 if (yid->wcd->packet_type != 0x02) {
2769 if ((pos - begin) != yid->wcd->data_size) {
2770 yid->wcd->to_read = 0;
2771 return 0;
2772 } else {
2773 yahoo_packet_dump(yid->rxqueue + begin, pos - begin);
2777 DEBUG_MSG(("packet type %.2X, data length %d", yid->wcd->packet_type,
2778 yid->wcd->data_size));
2780 /* find out what kind of packet we got */
2781 switch (yid->wcd->packet_type) {
2782 case 0x00:
2783 /* user requests to view webcam (uploading) */
2784 if (yid->wcd->data_size &&
2785 yid->wcm->direction == YAHOO_WEBCAM_UPLOAD) {
2786 end = begin;
2787 while (end <= yid->rxlen && yid->rxqueue[end++] != 13) ;
2788 if (end > begin) {
2789 who = y_memdup(yid->rxqueue + begin,
2790 end - begin);
2791 who[end - begin - 1] = 0;
2792 YAHOO_CALLBACK(ext_yahoo_webcam_viewer) (yd->
2793 client_id, who + 2, 2);
2794 FREE(who);
2798 if (yid->wcm->direction == YAHOO_WEBCAM_DOWNLOAD) {
2799 /* timestamp/status field */
2800 /* 0 = declined viewing permission */
2801 /* 1 = accepted viewing permission */
2802 if (yid->wcd->timestamp == 0) {
2803 YAHOO_CALLBACK(ext_yahoo_webcam_closed) (yd->
2804 client_id, yid->wcm->user, 3);
2807 break;
2808 case 0x01: /* status packets?? */
2809 /* timestamp contains status info */
2810 /* 00 00 00 01 = we have data?? */
2811 break;
2812 case 0x02: /* image data */
2813 YAHOO_CALLBACK(ext_yahoo_got_webcam_image) (yd->client_id,
2814 yid->wcm->user, yid->rxqueue + begin,
2815 yid->wcd->data_size, pos - begin, yid->wcd->timestamp);
2816 break;
2817 case 0x05: /* response packets when uploading */
2818 if (!yid->wcd->data_size) {
2819 YAHOO_CALLBACK(ext_yahoo_webcam_data_request) (yd->
2820 client_id, yid->wcd->timestamp);
2822 break;
2823 case 0x07: /* connection is closing */
2824 switch (reason) {
2825 case 0x01: /* user closed connection */
2826 closed = 1;
2827 break;
2828 case 0x0F: /* user cancelled permission */
2829 closed = 2;
2830 break;
2832 YAHOO_CALLBACK(ext_yahoo_webcam_closed) (yd->client_id,
2833 yid->wcm->user, closed);
2834 break;
2835 case 0x0C: /* user connected */
2836 case 0x0D: /* user disconnected */
2837 if (yid->wcd->data_size) {
2838 who = y_memdup(yid->rxqueue + begin, pos - begin + 1);
2839 who[pos - begin] = 0;
2840 if (yid->wcd->packet_type == 0x0C)
2841 connect = 1;
2842 else
2843 connect = 0;
2844 YAHOO_CALLBACK(ext_yahoo_webcam_viewer) (yd->client_id,
2845 who, connect);
2846 FREE(who);
2848 break;
2849 case 0x13: /* user data */
2850 /* i=user_ip (ip of the user we are viewing) */
2851 /* j=user_ext_ip (external ip of the user we */
2852 /* are viewing) */
2853 break;
2854 case 0x17: /* ?? */
2855 break;
2857 yid->wcd->to_read -= pos - begin;
2859 yid->rxlen -= pos;
2860 DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2861 if (yid->rxlen > 0) {
2862 unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
2863 FREE(yid->rxqueue);
2864 yid->rxqueue = tmp;
2865 DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen,
2866 yid->rxqueue));
2867 } else {
2868 DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
2869 FREE(yid->rxqueue);
2872 /* If we read a complete packet return success */
2873 if (!yid->wcd->to_read)
2874 return 1;
2876 return 0;
2879 int yahoo_write_ready(int id, void *fd, void *data)
2881 struct yahoo_input_data *yid = data;
2882 int len;
2883 struct data_queue *tx;
2885 LOG(("write callback: id=%d fd=%p data=%p", id, fd, data));
2886 if (!yid || !yid->txqueues)
2887 return -2;
2889 tx = yid->txqueues->data;
2890 LOG(("writing %d bytes", tx->len));
2891 len = yahoo_send_data(fd, tx->queue, MIN(1024, tx->len));
2893 if (len == -1 && errno == EAGAIN)
2894 return 1;
2896 if (len <= 0) {
2897 int e = errno;
2898 DEBUG_MSG(("len == %d (<= 0)", len));
2899 while (yid->txqueues) {
2900 YList *l = yid->txqueues;
2901 tx = l->data;
2902 free(tx->queue);
2903 free(tx);
2904 yid->txqueues =
2905 y_list_remove_link(yid->txqueues,
2906 yid->txqueues);
2907 y_list_free_1(l);
2909 LOG(("yahoo_write_ready(%d, %p) len < 0", id, fd));
2910 YAHOO_CALLBACK(ext_yahoo_remove_handler) (id, yid->write_tag);
2911 yid->write_tag = 0;
2912 errno = e;
2913 return 0;
2916 tx->len -= len;
2917 if (tx->len > 0) {
2918 unsigned char *tmp = y_memdup(tx->queue + len, tx->len);
2919 FREE(tx->queue);
2920 tx->queue = tmp;
2921 } else {
2922 YList *l = yid->txqueues;
2923 free(tx->queue);
2924 free(tx);
2925 yid->txqueues =
2926 y_list_remove_link(yid->txqueues, yid->txqueues);
2927 y_list_free_1(l);
2929 if(!yid->txqueues)
2930 LOG(("yahoo_write_ready(%d, %d) !yxqueues", id, fd));
2932 if (!yid->txqueues) {
2933 LOG(("yahoo_write_ready(%d, %p) !txqueues", id, fd));
2934 YAHOO_CALLBACK(ext_yahoo_remove_handler) (id,
2935 yid->write_tag);
2936 yid->write_tag = 0;
2940 return 1;
2943 static void yahoo_process_pager_connection(struct yahoo_input_data *yid,
2944 int over)
2946 struct yahoo_packet *pkt;
2947 struct yahoo_data *yd = yid->yd;
2948 int id = yd->client_id;
2950 if (over)
2951 return;
2953 while (find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER)
2954 && (pkt = yahoo_getdata(yid)) != NULL) {
2956 yahoo_packet_process(yid, pkt);
2958 yahoo_packet_free(pkt);
2962 static void yahoo_process_chatcat_connection(struct yahoo_input_data *yid,
2963 int over)
2965 if (over)
2966 return;
2968 if (strstr((char *)yid->rxqueue + (yid->rxlen - 20), "</content>")) {
2969 YAHOO_CALLBACK(ext_yahoo_chat_cat_xml) (yid->yd->client_id,
2970 (char *)yid->rxqueue);
2974 static void yahoo_process_yab_connection(struct yahoo_input_data *yid, int over)
2976 struct yahoo_data *yd = yid->yd;
2977 struct yab *yab;
2978 YList *buds;
2979 int changed = 0;
2980 int id = yd->client_id;
2981 int yab_used = 0;
2983 LOG(("Got data for YAB"));
2985 if (over)
2986 return;
2988 while (find_input_by_id_and_type(id, YAHOO_CONNECTION_YAB)
2989 && (yab = yahoo_getyab(yid)) != NULL) {
2990 if (!yab->id)
2991 continue;
2993 changed = 1;
2994 yab_used = 0;
2995 for (buds = yd->buddies; buds; buds = buds->next) {
2996 struct yahoo_buddy *bud = buds->data;
2997 if (!strcmp(bud->id, yab->id)) {
2998 yab_used = 1;
2999 bud->yab_entry = yab;
3000 if (yab->nname) {
3001 bud->real_name = strdup(yab->nname);
3002 } else if (yab->fname && yab->lname) {
3003 bud->real_name = y_new0(char,
3004 strlen(yab->fname) +
3005 strlen(yab->lname) + 2);
3006 sprintf(bud->real_name, "%s %s",
3007 yab->fname, yab->lname);
3008 } else if (yab->fname) {
3009 bud->real_name = strdup(yab->fname);
3011 break; /* for */
3015 if (!yab_used) {
3016 FREE(yab->fname);
3017 FREE(yab->lname);
3018 FREE(yab->nname);
3019 FREE(yab->id);
3020 FREE(yab->email);
3021 FREE(yab->hphone);
3022 FREE(yab->wphone);
3023 FREE(yab->mphone);
3024 FREE(yab);
3029 if (changed)
3030 YAHOO_CALLBACK(ext_yahoo_got_buddies) (yd->client_id,
3031 yd->buddies);
3034 static void yahoo_process_search_connection(struct yahoo_input_data *yid,
3035 int over)
3037 struct yahoo_found_contact *yct = NULL;
3038 char *p = (char *)yid->rxqueue, *np, *cp;
3039 int k, n;
3040 int start = 0, found = 0, total = 0;
3041 YList *contacts = NULL;
3042 struct yahoo_input_data *pyid =
3043 find_input_by_id_and_type(yid->yd->client_id,
3044 YAHOO_CONNECTION_PAGER);
3046 if (!over || !pyid)
3047 return;
3049 if (p && (p = strstr(p, "\r\n\r\n"))) {
3050 p += 4;
3052 for (k = 0; (p = strchr(p, 4)) && (k < 4); k++) {
3053 p++;
3054 n = atoi(p);
3055 switch (k) {
3056 case 0:
3057 found = pyid->ys->lsearch_nfound = n;
3058 break;
3059 case 2:
3060 start = pyid->ys->lsearch_nstart = n;
3061 break;
3062 case 3:
3063 total = pyid->ys->lsearch_ntotal = n;
3064 break;
3068 if (p)
3069 p++;
3071 k = 0;
3072 while (p && *p) {
3073 cp = p;
3074 np = strchr(p, 4);
3076 if (!np)
3077 break;
3078 *np = 0;
3079 p = np + 1;
3081 switch (k++) {
3082 case 1:
3083 if (strlen(cp) > 2
3084 && y_list_length(contacts) < total) {
3085 yct = y_new0(struct yahoo_found_contact,
3087 contacts = y_list_append(contacts, yct);
3088 yct->id = cp + 2;
3089 } else {
3090 *p = 0;
3092 break;
3093 case 2:
3094 yct->online = !strcmp(cp, "2") ? 1 : 0;
3095 break;
3096 case 3:
3097 yct->gender = cp;
3098 break;
3099 case 4:
3100 yct->age = atoi(cp);
3101 break;
3102 case 5:
3103 /* not worth the context switch for strcmp */
3104 if (cp[0] != '\005' || cp[1] != '\000')
3105 yct->location = cp;
3106 k = 0;
3107 break;
3112 YAHOO_CALLBACK(ext_yahoo_got_search_result) (yid->yd->client_id, found,
3113 start, total, contacts);
3115 while (contacts) {
3116 YList *node = contacts;
3117 contacts = y_list_remove_link(contacts, node);
3118 free(node->data);
3119 y_list_free_1(node);
3123 static void _yahoo_webcam_connected(void *fd, int error, void *d)
3125 struct yahoo_input_data *yid = d;
3126 struct yahoo_webcam *wcm = yid->wcm;
3127 struct yahoo_data *yd = yid->yd;
3128 char conn_type[100];
3129 char *data = NULL;
3130 char *packet = NULL;
3131 unsigned char magic_nr[] = { 1, 0, 0, 0, 1 };
3132 unsigned header_len = 0;
3133 unsigned int len = 0;
3134 unsigned int pos = 0;
3136 if (error || !fd) {
3137 FREE(yid);
3138 return;
3141 yid->fd = fd;
3142 inputs = y_list_prepend(inputs, yid);
3144 LOG(("Connected"));
3145 /* send initial packet */
3146 switch (wcm->direction) {
3147 case YAHOO_WEBCAM_DOWNLOAD:
3148 data = strdup("<REQIMG>");
3149 break;
3150 case YAHOO_WEBCAM_UPLOAD:
3151 data = strdup("<SNDIMG>");
3152 break;
3153 default:
3154 return;
3156 yahoo_add_to_send_queue(yid, data, strlen(data));
3157 FREE(data);
3159 /* send data */
3160 switch (wcm->direction) {
3161 case YAHOO_WEBCAM_DOWNLOAD:
3162 header_len = 8;
3163 data = strdup("a=2\r\nc=us\r\ne=21\r\nu=");
3164 data = y_string_append(data, yd->user);
3165 data = y_string_append(data, "\r\nt=");
3166 data = y_string_append(data, wcm->key);
3167 data = y_string_append(data, "\r\ni=");
3168 data = y_string_append(data, wcm->my_ip);
3169 data = y_string_append(data, "\r\ng=");
3170 data = y_string_append(data, wcm->user);
3171 data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
3172 snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
3173 data = y_string_append(data, conn_type);
3174 data = y_string_append(data, "\r\n");
3175 break;
3176 case YAHOO_WEBCAM_UPLOAD:
3177 header_len = 13;
3178 data = strdup("a=2\r\nc=us\r\nu=");
3179 data = y_string_append(data, yd->user);
3180 data = y_string_append(data, "\r\nt=");
3181 data = y_string_append(data, wcm->key);
3182 data = y_string_append(data, "\r\ni=");
3183 data = y_string_append(data, wcm->my_ip);
3184 data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
3185 snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
3186 data = y_string_append(data, conn_type);
3187 data = y_string_append(data, "\r\nb=");
3188 data = y_string_append(data, wcm->description);
3189 data = y_string_append(data, "\r\n");
3190 break;
3193 len = strlen(data);
3194 packet = y_new0(char, header_len + len);
3195 packet[pos++] = header_len;
3196 packet[pos++] = 0;
3197 switch (wcm->direction) {
3198 case YAHOO_WEBCAM_DOWNLOAD:
3199 packet[pos++] = 1;
3200 packet[pos++] = 0;
3201 break;
3202 case YAHOO_WEBCAM_UPLOAD:
3203 packet[pos++] = 5;
3204 packet[pos++] = 0;
3205 break;
3208 pos += yahoo_put32(packet + pos, len);
3209 if (wcm->direction == YAHOO_WEBCAM_UPLOAD) {
3210 memcpy(packet + pos, magic_nr, sizeof(magic_nr));
3211 pos += sizeof(magic_nr);
3213 memcpy(packet + pos, data, len);
3214 yahoo_add_to_send_queue(yid, packet, header_len + len);
3215 FREE(packet);
3216 FREE(data);
3218 yid->read_tag =
3219 YAHOO_CALLBACK(ext_yahoo_add_handler) (yid->yd->client_id,
3220 yid->fd, YAHOO_INPUT_READ, yid);
3223 static void yahoo_webcam_connect(struct yahoo_input_data *y)
3225 struct yahoo_webcam *wcm = y->wcm;
3226 struct yahoo_input_data *yid;
3227 struct yahoo_server_settings *yss;
3229 if (!wcm || !wcm->server || !wcm->key)
3230 return;
3232 yid = y_new0(struct yahoo_input_data, 1);
3233 yid->type = YAHOO_CONNECTION_WEBCAM;
3234 yid->yd = y->yd;
3236 /* copy webcam data to new connection */
3237 yid->wcm = y->wcm;
3238 y->wcm = NULL;
3240 yss = y->yd->server_settings;
3242 yid->wcd = y_new0(struct yahoo_webcam_data, 1);
3244 LOG(("Connecting to: %s:%d", wcm->server, wcm->port));
3245 YAHOO_CALLBACK(ext_yahoo_connect_async) (y->yd->client_id, wcm->server,
3246 wcm->port, _yahoo_webcam_connected, yid, 0);
3250 static void yahoo_process_webcam_master_connection(struct yahoo_input_data *yid,
3251 int over)
3253 char *server;
3254 struct yahoo_server_settings *yss;
3256 if (over)
3257 return;
3259 server = yahoo_getwebcam_master(yid);
3261 if (server) {
3262 yss = yid->yd->server_settings;
3263 yid->wcm->server = strdup(server);
3264 yid->wcm->port = yss->webcam_port;
3265 yid->wcm->conn_type = yss->conn_type;
3266 yid->wcm->my_ip = strdup(yss->local_host);
3267 if (yid->wcm->direction == YAHOO_WEBCAM_UPLOAD)
3268 yid->wcm->description = strdup(yss->webcam_description);
3269 yahoo_webcam_connect(yid);
3270 FREE(server);
3274 static void yahoo_process_webcam_connection(struct yahoo_input_data *yid,
3275 int over)
3277 int id = yid->yd->client_id;
3278 void *fd = yid->fd;
3280 if (over)
3281 return;
3283 /* as long as we still have packets available keep processing them */
3284 while (find_input_by_id_and_fd(id, fd)
3285 && yahoo_get_webcam_data(yid) == 1) ;
3288 static void yahoo_process_auth_connection(struct yahoo_input_data *yid,
3289 int over)
3291 char *line_end;
3292 char *token;
3293 char *cookie;
3295 int error_code = 0;
3296 int is_ymsgr = 0;
3298 /* Wait till we get everything */
3299 if (!over)
3300 return;
3302 if (!yid->rxqueue) {
3303 LOG(("Whoops! Closed it just like that??\n"));
3304 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3305 YAHOO_LOGIN_UNKNOWN, NULL);
3306 return;
3309 token = strstr((char *)yid->rxqueue, "\r\n\r\n");
3311 if (!token) {
3312 LOG(("Could not find anything after the HTTP headers? huh?\n"));
3313 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3314 YAHOO_LOGIN_UNKNOWN, NULL);
3315 return;
3318 *token = '\0';
3319 token += 4;
3321 /* Skip the first number */
3322 token = strstr(token, "\r\n");
3324 if (!token) {
3325 LOG(("Well I tried to skip the first number and found... nothing\n"));
3326 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3327 YAHOO_LOGIN_UNKNOWN, NULL);
3328 return;
3331 token += 2;
3333 line_end = strstr(token, "\r\n");
3335 if (line_end) {
3336 *line_end = '\0';
3338 line_end += 2;
3341 error_code = atoi((char *)token);
3343 switch (error_code) {
3344 case 0:
3345 /* successful */
3346 break;
3347 case 1212:
3348 /* Incorrect ID or password */
3349 LOG(("Incorrect ID or password\n"));
3350 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3351 YAHOO_LOGIN_PASSWD, NULL);
3353 return;
3354 case 1213:
3355 /* Security lock from too many failed login attempts */
3356 LOG(("Security lock from too many failed login attempts\n"));
3357 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3358 YAHOO_LOGIN_LOCK, "");
3360 return;
3362 case 1214:
3363 /* Security lock */
3364 LOG(("Security lock\n"));
3365 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3366 YAHOO_LOGIN_LOCK, "");
3368 return;
3370 case 1235:
3371 /* User ID not taken yet */
3372 LOG(("User ID not taken yet\n"));
3373 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3374 YAHOO_LOGIN_UNAME, NULL);
3376 return;
3378 case 1216:
3379 /* Seems to be a lock, but shows the same generic User ID/Password failure */
3380 LOG(("Seems to be a lock, but shows the same generic User ID/Password failure\n"));
3381 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3382 YAHOO_LOGIN_PASSWD, NULL);
3384 return;
3385 case 100:
3386 /* Username and password cannot be blank */
3387 LOG(("Username and password cannot be blank\n"));
3388 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3389 YAHOO_LOGIN_PASSWD, NULL);
3391 return;
3392 default:
3393 /* Unknown error code */
3394 LOG(("Unknown Error\n"));
3395 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3396 YAHOO_LOGIN_UNKNOWN, NULL);
3398 return;
3401 if (line_end && !strncmp(line_end, "ymsgr=", 6)) {
3402 is_ymsgr = 1;
3403 } else if (strncmp(line_end, "crumb=", 6)) {
3404 LOG(("Oops! There was no ymsgr=. Where do I get my token from now :("));
3405 LOG(("I got this:\n\n%s\n", line_end));
3406 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3407 YAHOO_LOGIN_UNKNOWN, NULL);
3408 return;
3409 /* Error */
3412 token = line_end + 6;
3414 line_end = strstr(token, "\r\n");
3416 if (line_end) {
3417 *line_end = '\0';
3418 line_end += 2;
3421 /* Go for the crumb */
3422 if (is_ymsgr) {
3423 char url[256];
3424 char *token_enc;
3425 struct yahoo_input_data *crumb_yid =
3426 y_new0(struct yahoo_input_data, 1);
3428 crumb_yid->yd = yid->yd;
3429 crumb_yid->type = YAHOO_CONNECTION_AUTH;
3431 inputs = y_list_prepend(inputs, crumb_yid);
3433 token_enc = yahoo_urlencode(token);
3435 snprintf(url, sizeof(url),
3436 "https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts="
3437 "&token=%s", token_enc);
3439 yahoo_http_get(crumb_yid->yd->client_id, url, NULL, 1, 0,
3440 _yahoo_http_connected, crumb_yid);
3442 FREE(token_enc);
3444 return;
3447 /* token is actually crumb */
3449 if (!line_end) {
3450 /* We did not get our cookies. Cry. */
3451 LOG(("NO Cookies!"));
3452 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3453 YAHOO_LOGIN_UNKNOWN, NULL);
3454 return;
3457 cookie = strstr((char *)yid->rxqueue, "Set-Cookie: Y=");
3459 if (!cookie) {
3460 /* Cry. */
3461 LOG(("NO Y Cookie!"));
3462 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3463 YAHOO_LOGIN_UNKNOWN, NULL);
3464 return;
3467 cookie += 14;
3469 line_end = strstr(cookie, "\r\n");
3470 *line_end = '\0';
3472 yid->yd->cookie_y = strdup(cookie);
3473 *line_end = ';';
3475 cookie = strstr((char *)yid->rxqueue, "Set-Cookie: T=");
3476 if (!cookie) {
3477 /* Cry. */
3478 LOG(("NO T Cookie!"));
3479 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3480 YAHOO_LOGIN_UNKNOWN, NULL);
3481 return;
3484 cookie += 14;
3486 line_end = strstr(cookie, "\r\n");
3487 *line_end = '\0';
3489 yid->yd->cookie_t = strdup(cookie);
3490 *line_end = ';';
3492 cookie = strstr((char *)yid->rxqueue, "Set-Cookie: B=");
3493 if (!cookie) {
3494 /* Cry. */
3495 LOG(("NO B Cookie!"));
3496 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->client_id,
3497 YAHOO_LOGIN_UNKNOWN, NULL);
3498 return;
3501 cookie += 14;
3503 line_end = strstr(cookie, "\r\n");
3504 *line_end = '\0';
3506 yid->yd->cookie_b = strdup(cookie);
3508 yid->yd->crumb = strdup(token);
3510 yahoo_send_auth(yid->yd);
3513 static void (*yahoo_process_connection[]) (struct yahoo_input_data *,
3514 int over) = {
3515 yahoo_process_pager_connection, yahoo_process_ft_connection,
3516 yahoo_process_yab_connection,
3517 yahoo_process_webcam_master_connection,
3518 yahoo_process_webcam_connection,
3519 yahoo_process_chatcat_connection,
3520 yahoo_process_search_connection, yahoo_process_auth_connection};
3522 int yahoo_read_ready(int id, void *fd, void *data)
3524 struct yahoo_input_data *yid = data;
3525 char buf[1024];
3526 int len;
3528 LOG(("read callback: id=%d fd=%p data=%p", id, fd, data));
3529 if (!yid)
3530 return -2;
3532 do {
3533 len = YAHOO_CALLBACK(ext_yahoo_read) (fd, buf, sizeof(buf));
3534 } while (len == -1 && errno == EINTR);
3536 if (len == -1 && (errno == EAGAIN || errno == EINTR)) /* we'll try again later */
3537 return 1;
3539 if (len <= 0) {
3540 int e = errno;
3541 DEBUG_MSG(("len == %d (<= 0)", len));
3543 if (yid->type == YAHOO_CONNECTION_PAGER) {
3544 YAHOO_CALLBACK(ext_yahoo_login_response) (yid->yd->
3545 client_id, YAHOO_LOGIN_SOCK, NULL);
3548 yahoo_process_connection[yid->type] (yid, 1);
3549 yahoo_input_close(yid);
3551 /* no need to return an error, because we've already fixed it */
3552 if (len == 0)
3553 return 1;
3555 errno = e;
3556 LOG(("read error: %s", strerror(errno)));
3557 return -1;
3560 yid->rxqueue =
3561 y_renew(unsigned char, yid->rxqueue, len + yid->rxlen + 1);
3562 memcpy(yid->rxqueue + yid->rxlen, buf, len);
3563 yid->rxlen += len;
3564 yid->rxqueue[yid->rxlen] = 0;
3566 yahoo_process_connection[yid->type] (yid, 0);
3568 return len;
3571 int yahoo_init_with_attributes(const char *username, const char *password, ...)
3573 va_list ap;
3574 struct yahoo_data *yd;
3576 yd = y_new0(struct yahoo_data, 1);
3578 if (!yd)
3579 return 0;
3581 yd->user = strdup(username);
3582 yd->password = strdup(password);
3584 yd->initial_status = -1;
3585 yd->current_status = -1;
3587 yd->client_id = ++last_id;
3589 add_to_list(yd);
3591 va_start(ap, password);
3592 yd->server_settings = _yahoo_assign_server_settings(ap);
3593 va_end(ap);
3595 return yd->client_id;
3598 int yahoo_init(const char *username, const char *password)
3600 return yahoo_init_with_attributes(username, password, NULL);
3603 static void yahoo_connected(void *fd, int error, void *data)
3605 struct connect_callback_data *ccd = data;
3606 struct yahoo_data *yd = ccd->yd;
3607 struct yahoo_packet *pkt;
3608 struct yahoo_input_data *yid;
3609 struct yahoo_server_settings *yss = yd->server_settings;
3611 if (error) {
3612 int tag;
3613 if (fallback_ports[ccd->i]) {
3614 char *host = yss->pager_host;
3616 if (!host)
3617 host = yss->pager_host_list[ccd->server_i];
3619 yss->pager_port = fallback_ports[ccd->i++];
3620 tag = YAHOO_CALLBACK(ext_yahoo_connect_async) (yd->
3621 client_id, host, yss->pager_port,
3622 yahoo_connected, ccd, 0);
3624 if (tag > 0)
3625 ccd->tag = tag;
3626 } else if (yss->pager_host_list
3627 && yss->pager_host_list[ccd->server_i]) {
3629 /* Get back to the default port */
3630 yss->pager_port = pager_port;
3631 ccd->server_i++;
3632 LOG(("Fallback: Connecting to %s:%d", yss->pager_host_list[ccd->server_i], yss->pager_port));
3634 ccd->i = 0;
3635 tag = YAHOO_CALLBACK(ext_yahoo_connect_async) (yd->client_id,
3636 yss->pager_host_list[ccd->server_i], yss->pager_port,
3637 yahoo_connected, ccd, 0);
3638 } else {
3639 FREE(ccd);
3640 YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id,
3641 YAHOO_LOGIN_SOCK, NULL);
3643 return;
3646 FREE(ccd);
3648 /* fd == NULL && error == 0 means connect was cancelled */
3649 if (!fd)
3650 return;
3652 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YPACKET_STATUS_DEFAULT,
3653 yd->session_id);
3654 NOTICE(("Sending initial packet"));
3656 yahoo_packet_hash(pkt, 1, yd->user);
3658 yid = find_input_by_id_and_type(yd->client_id, YAHOO_CONNECTION_PAGER);
3659 yid->fd = fd;
3661 yahoo_send_packet(yid, pkt, 0);
3663 yahoo_packet_free(pkt);
3665 yid->read_tag =
3666 YAHOO_CALLBACK(ext_yahoo_add_handler) (yid->yd->client_id,
3667 yid->fd, YAHOO_INPUT_READ, yid);
3670 void *yahoo_get_fd(int id)
3672 struct yahoo_input_data *yid =
3673 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
3674 if (!yid)
3675 return 0;
3676 else
3677 return yid->fd;
3680 void yahoo_send_buzz(int id, const char *from, const char *who)
3682 yahoo_send_im(id, from, who, "<ding>", 1, 0);
3685 void yahoo_send_im(int id, const char *from, const char *who, const char *what,
3686 int utf8, int picture)
3688 struct yahoo_input_data *yid =
3689 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
3690 struct yahoo_packet *pkt = NULL;
3691 struct yahoo_data *yd;
3692 char pic_str[10];
3694 if (!yid)
3695 return;
3697 yd = yid->yd;
3699 pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE,
3700 yd->session_id);
3702 snprintf(pic_str, sizeof(pic_str), "%d", picture);
3704 if (from && strcmp(from, yd->user))
3705 yahoo_packet_hash(pkt, 0, yd->user);
3706 yahoo_packet_hash(pkt, 1, from ? from : yd->user);
3707 yahoo_packet_hash(pkt, 5, who);
3708 yahoo_packet_hash(pkt, 14, what);
3710 if (utf8)
3711 yahoo_packet_hash(pkt, 97, "1");
3713 yahoo_packet_hash(pkt, 63, ";0"); /* imvironment name; or ;0 */
3714 yahoo_packet_hash(pkt, 64, "0");
3715 yahoo_packet_hash(pkt, 206, pic_str);
3717 yahoo_send_packet(yid, pkt, 0);
3719 yahoo_packet_free(pkt);
3722 void yahoo_send_typing(int id, const char *from, const char *who, int typ)
3724 struct yahoo_input_data *yid =
3725 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
3726 struct yahoo_data *yd;
3727 struct yahoo_packet *pkt = NULL;
3728 if (!yid)
3729 return;
3731 yd = yid->yd;
3732 pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YPACKET_STATUS_NOTIFY,
3733 yd->session_id);
3735 yahoo_packet_hash(pkt, 5, who);
3736 yahoo_packet_hash(pkt, 1, from ? from : yd->user);
3737 yahoo_packet_hash(pkt, 14, " ");
3738 yahoo_packet_hash(pkt, 13, typ ? "1" : "0");
3739 yahoo_packet_hash(pkt, 49, "TYPING");
3741 yahoo_send_packet(yid, pkt, 0);
3743 yahoo_packet_free(pkt);
3746 void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away)
3748 struct yahoo_input_data *yid =
3749 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
3750 struct yahoo_data *yd;
3751 struct yahoo_packet *pkt = NULL;
3752 int old_status;
3753 char s[4];
3755 if (!yid)
3756 return;
3758 yd = yid->yd;
3760 old_status = yd->current_status;
3762 if (msg) {
3763 yd->current_status = YAHOO_STATUS_CUSTOM;
3764 } else {
3765 yd->current_status = state;
3768 /* Thank you libpurple :) */
3769 if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
3770 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE,
3771 YAHOO_STATUS_AVAILABLE, 0);
3772 yahoo_packet_hash(pkt, 13, "2");
3773 yahoo_send_packet(yid, pkt, 0);
3774 yahoo_packet_free(pkt);
3776 return;
3779 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE,
3780 yd->current_status, yd->session_id);
3781 snprintf(s, sizeof(s), "%d", yd->current_status);
3782 yahoo_packet_hash(pkt, 10, s);
3784 if (yd->current_status == YAHOO_STATUS_CUSTOM) {
3785 yahoo_packet_hash(pkt, 19, msg);
3786 } else {
3787 yahoo_packet_hash(pkt, 19, "");
3790 yahoo_packet_hash(pkt, 47, (away == 2) ? "2" : (away) ? "1" : "0");
3792 yahoo_send_packet(yid, pkt, 0);
3793 yahoo_packet_free(pkt);
3795 if (old_status == YAHOO_STATUS_INVISIBLE) {
3796 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE,
3797 YAHOO_STATUS_AVAILABLE, 0);
3798 yahoo_packet_hash(pkt, 13, "1");
3799 yahoo_send_packet(yid, pkt, 0);
3800 yahoo_packet_free(pkt);
3804 void yahoo_logoff(int id)
3806 struct yahoo_input_data *yid =
3807 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
3808 struct yahoo_data *yd;
3809 struct yahoo_packet *pkt = NULL;
3811 if (!yid)
3812 return;
3813 yd = yid->yd;
3815 LOG(("yahoo_logoff: current status: %d", yd->current_status));
3817 if (yd->current_status != -1) {
3818 pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF,
3819 YPACKET_STATUS_DEFAULT, yd->session_id);
3820 yd->current_status = -1;
3822 if (pkt) {
3823 yahoo_send_packet(yid, pkt, 0);
3824 yahoo_packet_free(pkt);
3828 /* do {
3829 yahoo_input_close(yid);
3830 } while((yid = find_input_by_id(id)));*/
3834 void yahoo_get_list(int id)
3836 struct yahoo_input_data *yid =
3837 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
3838 struct yahoo_data *yd;
3839 struct yahoo_packet *pkt = NULL;
3841 if (!yid)
3842 return;
3843 yd = yid->yd;
3845 pkt = yahoo_packet_new(YAHOO_SERVICE_LIST, YPACKET_STATUS_DEFAULT,
3846 yd->session_id);
3847 yahoo_packet_hash(pkt, 1, yd->user);
3848 if (pkt) {
3849 yahoo_send_packet(yid, pkt, 0);
3850 yahoo_packet_free(pkt);
3854 static void _yahoo_http_connected(int id, void *fd, int error, void *data)
3856 struct yahoo_input_data *yid = data;
3857 if (fd == NULL || error) {
3858 inputs = y_list_remove(inputs, yid);
3859 FREE(yid);
3860 return;
3863 yid->fd = fd;
3864 yid->read_tag =
3865 YAHOO_CALLBACK(ext_yahoo_add_handler) (yid->yd->client_id, fd,
3866 YAHOO_INPUT_READ, yid);
3869 /* FIXME Get address book from address.yahoo.com instead */
3870 void yahoo_get_yab(int id)
3872 struct yahoo_data *yd = find_conn_by_id(id);
3873 struct yahoo_input_data *yid;
3874 char url[1024];
3875 char buff[2048];
3877 if (!yd)
3878 return;
3880 yid = y_new0(struct yahoo_input_data, 1);
3881 yid->yd = yd;
3882 yid->type = YAHOO_CONNECTION_YAB;
3884 LOG(("Sending request for Address Book"));
3886 snprintf(url, 1024,
3887 "http://address.yahoo.com/yab/us?v=XM&prog=ymsgr&.intl=us"
3888 "&diffs=1&t=0&tags=short&rt=0&prog-ver=8.1.0.249&useutf8=1&legenc=codepage-1252");
3890 snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
3892 inputs = y_list_prepend(inputs, yid);
3894 yahoo_http_get(yid->yd->client_id, url, buff, 0, 0,
3895 _yahoo_http_connected, yid);
3898 struct yahoo_post_data {
3899 struct yahoo_input_data *yid;
3900 char *data;
3903 static void _yahoo_http_post_connected(int id, void *fd, int error, void *data)
3905 struct yahoo_post_data *yad = data;
3906 struct yahoo_input_data *yid = yad->yid;
3907 char *buff = yad->data;
3909 if (!fd) {
3910 inputs = y_list_remove(inputs, yid);
3911 FREE(yid);
3912 return;
3915 YAHOO_CALLBACK(ext_yahoo_write) (fd, buff, strlen(buff));
3917 yid->fd = fd;
3918 yid->read_tag =
3919 YAHOO_CALLBACK(ext_yahoo_add_handler) (yid->yd->client_id, fd,
3920 YAHOO_INPUT_READ, yid);
3922 FREE(buff);
3923 FREE(yad);
3926 /* FIXME This is also likely affected */
3927 void yahoo_set_yab(int id, struct yab *yab)
3929 struct yahoo_post_data *yad = y_new0(struct yahoo_post_data, 1);
3930 struct yahoo_data *yd = find_conn_by_id(id);
3931 struct yahoo_input_data *yid;
3932 char url[1024];
3933 char buff[1024];
3934 char post[1024];
3935 int size = 0;
3937 if (!yd)
3938 return;
3940 yid = y_new0(struct yahoo_input_data, 1);
3941 yid->type = YAHOO_CONNECTION_YAB;
3942 yid->yd = yd;
3944 if(yab->yid)
3945 size = snprintf(post, sizeof(post), "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
3946 "<ab k=\"%s\" cc=\"%d\">"
3947 "<ct id=\"%d\" e=\"1\" yi=\"%s\" nn=\"%s\" />"
3948 "</ab>", yd->user, 9, yab->yid, /* Don't know why */
3949 yab->id, yab->nname?yab->nname:"");
3950 else
3951 size = snprintf(post, sizeof(post), "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
3952 "<ab k=\"%s\" cc=\"%d\">"
3953 "<ct a=\"1\" yi=\"%s\" nn=\"%s\" />"
3954 "</ab>", yd->user, 1, /* Don't know why */
3955 yab->id, yab->nname?yab->nname:"");
3957 yad->yid = yid;
3958 yad->data = strdup(post);
3960 strcpy(url, "http://address.yahoo.com/yab/us?v=XM&prog=ymsgr&.intl=us"
3961 "&sync=1&tags=short&noclear=1&useutf8=1&legenc=codepage-1252");
3963 snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
3965 inputs = y_list_prepend(inputs, yid);
3967 yahoo_http_post(yid->yd->client_id, url, buff, size,
3968 _yahoo_http_post_connected, yad);
3971 void yahoo_set_identity_status(int id, const char *identity, int active)
3973 struct yahoo_input_data *yid =
3974 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
3975 struct yahoo_data *yd;
3976 struct yahoo_packet *pkt = NULL;
3978 if (!yid)
3979 return;
3980 yd = yid->yd;
3982 pkt = yahoo_packet_new(active ? YAHOO_SERVICE_IDACT :
3983 YAHOO_SERVICE_IDDEACT, YPACKET_STATUS_DEFAULT, yd->session_id);
3984 yahoo_packet_hash(pkt, 3, identity);
3985 if (pkt) {
3986 yahoo_send_packet(yid, pkt, 0);
3987 yahoo_packet_free(pkt);
3991 void yahoo_refresh(int id)
3993 struct yahoo_input_data *yid =
3994 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
3995 struct yahoo_data *yd;
3996 struct yahoo_packet *pkt = NULL;
3998 if (!yid)
3999 return;
4000 yd = yid->yd;
4002 pkt = yahoo_packet_new(YAHOO_SERVICE_USERSTAT, YPACKET_STATUS_DEFAULT,
4003 yd->session_id);
4004 if (pkt) {
4005 yahoo_send_packet(yid, pkt, 0);
4006 yahoo_packet_free(pkt);
4010 void yahoo_keepalive(int id)
4012 struct yahoo_input_data *yid =
4013 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4014 struct yahoo_data *yd;
4015 struct yahoo_packet *pkt = NULL;
4016 if (!yid)
4017 return;
4018 yd = yid->yd;
4020 pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YPACKET_STATUS_DEFAULT,
4021 yd->session_id);
4022 yahoo_send_packet(yid, pkt, 0);
4023 yahoo_packet_free(pkt);
4026 void yahoo_chat_keepalive(int id)
4028 struct yahoo_input_data *yid =
4029 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4030 struct yahoo_data *yd;
4031 struct yahoo_packet *pkt = NULL;
4033 if (!yid)
4034 return;
4036 yd = yid->yd;
4038 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATPING, YPACKET_STATUS_DEFAULT,
4039 yd->session_id);
4040 yahoo_send_packet(yid, pkt, 0);
4041 yahoo_packet_free(pkt);
4044 void yahoo_add_buddy(int id, const char *who, const char *group,
4045 const char *msg)
4047 struct yahoo_input_data *yid =
4048 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4049 struct yahoo_data *yd;
4050 struct yahoo_packet *pkt;
4052 if (!yid)
4053 return;
4054 yd = yid->yd;
4056 if (!yd->logged_in)
4057 return;
4059 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YPACKET_STATUS_DEFAULT,
4060 yd->session_id);
4061 if (msg != NULL) /* add message/request "it's me add me" */
4062 yahoo_packet_hash(pkt, 14, msg);
4063 else
4064 yahoo_packet_hash(pkt, 14, "");
4065 yahoo_packet_hash(pkt, 65, group);
4066 yahoo_packet_hash(pkt, 97, "1");
4067 yahoo_packet_hash(pkt, 1, yd->user);
4068 yahoo_packet_hash(pkt, 302, "319");
4069 yahoo_packet_hash(pkt, 300, "319");
4070 yahoo_packet_hash(pkt, 7, who);
4071 yahoo_packet_hash(pkt, 334, "0");
4072 yahoo_packet_hash(pkt, 301, "319");
4073 yahoo_packet_hash(pkt, 303, "319");
4074 yahoo_send_packet(yid, pkt, 0);
4075 yahoo_packet_free(pkt);
4078 void yahoo_remove_buddy(int id, const char *who, const char *group)
4080 struct yahoo_input_data *yid =
4081 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4082 struct yahoo_data *yd;
4083 struct yahoo_packet *pkt = NULL;
4085 if (!yid)
4086 return;
4087 yd = yid->yd;
4089 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YPACKET_STATUS_DEFAULT,
4090 yd->session_id);
4092 yahoo_packet_hash(pkt, 1, yd->user);
4093 yahoo_packet_hash(pkt, 7, who);
4094 yahoo_packet_hash(pkt, 65, group);
4095 yahoo_send_packet(yid, pkt, 0);
4096 yahoo_packet_free(pkt);
4099 void yahoo_confirm_buddy(int id, const char *who, int reject, const char *msg)
4101 struct yahoo_input_data *yid =
4102 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4103 struct yahoo_data *yd;
4104 struct yahoo_packet *pkt;
4106 if (!yid)
4107 return;
4108 yd = yid->yd;
4110 if (!yd->logged_in)
4111 return;
4113 pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_AUTHORIZATION,
4114 YPACKET_STATUS_DEFAULT, yd->session_id);
4115 yahoo_packet_hash(pkt, 1, yd->user);
4116 yahoo_packet_hash(pkt, 5, who);
4117 if (reject)
4118 yahoo_packet_hash(pkt, 13, "2");
4119 else {
4120 yahoo_packet_hash(pkt, 241, "0");
4121 yahoo_packet_hash(pkt, 13, "1");
4124 yahoo_packet_hash(pkt, 334, "0");
4126 if (reject) {
4127 yahoo_packet_hash(pkt, 14, msg ? msg : "");
4128 yahoo_packet_hash(pkt, 97, "1");
4131 yahoo_send_packet(yid, pkt, 0);
4132 yahoo_packet_free(pkt);
4135 void yahoo_ignore_buddy(int id, const char *who, int unignore)
4137 struct yahoo_input_data *yid =
4138 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4139 struct yahoo_data *yd;
4140 struct yahoo_packet *pkt;
4142 if (!yid)
4143 return;
4144 yd = yid->yd;
4146 if (!yd->logged_in)
4147 return;
4149 pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT,
4150 YPACKET_STATUS_DEFAULT, yd->session_id);
4151 yahoo_packet_hash(pkt, 1, yd->user);
4152 yahoo_packet_hash(pkt, 7, who);
4153 yahoo_packet_hash(pkt, 13, unignore ? "2" : "1");
4154 yahoo_send_packet(yid, pkt, 0);
4155 yahoo_packet_free(pkt);
4158 void yahoo_stealth_buddy(int id, const char *who, int unstealth)
4160 struct yahoo_input_data *yid =
4161 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4162 struct yahoo_data *yd;
4163 struct yahoo_packet *pkt;
4165 if (!yid)
4166 return;
4167 yd = yid->yd;
4169 if (!yd->logged_in)
4170 return;
4172 pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH_PERM,
4173 YPACKET_STATUS_DEFAULT, yd->session_id);
4174 yahoo_packet_hash(pkt, 1, yd->user);
4175 yahoo_packet_hash(pkt, 7, who);
4176 yahoo_packet_hash(pkt, 31, unstealth ? "2" : "1");
4177 yahoo_packet_hash(pkt, 13, "2");
4178 yahoo_send_packet(yid, pkt, 0);
4179 yahoo_packet_free(pkt);
4182 void yahoo_change_buddy_group(int id, const char *who, const char *old_group,
4183 const char *new_group)
4185 struct yahoo_input_data *yid =
4186 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4187 struct yahoo_data *yd;
4188 struct yahoo_packet *pkt = NULL;
4190 if (!yid)
4191 return;
4192 yd = yid->yd;
4194 pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_CHANGE_GROUP,
4195 YPACKET_STATUS_DEFAULT, yd->session_id);
4196 yahoo_packet_hash(pkt, 1, yd->user);
4197 yahoo_packet_hash(pkt, 302, "240");
4198 yahoo_packet_hash(pkt, 300, "240");
4199 yahoo_packet_hash(pkt, 7, who);
4200 yahoo_packet_hash(pkt, 224, old_group);
4201 yahoo_packet_hash(pkt, 264, new_group);
4202 yahoo_packet_hash(pkt, 301, "240");
4203 yahoo_packet_hash(pkt, 303, "240");
4205 yahoo_send_packet(yid, pkt, 0);
4206 yahoo_packet_free(pkt);
4209 void yahoo_group_rename(int id, const char *old_group, const char *new_group)
4211 struct yahoo_input_data *yid =
4212 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4213 struct yahoo_data *yd;
4214 struct yahoo_packet *pkt = NULL;
4216 if (!yid)
4217 return;
4218 yd = yid->yd;
4220 pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME,
4221 YPACKET_STATUS_DEFAULT, yd->session_id);
4222 yahoo_packet_hash(pkt, 1, yd->user);
4223 yahoo_packet_hash(pkt, 65, old_group);
4224 yahoo_packet_hash(pkt, 67, new_group);
4226 yahoo_send_packet(yid, pkt, 0);
4227 yahoo_packet_free(pkt);
4230 void yahoo_conference_addinvite(int id, const char *from, const char *who,
4231 const char *room, const YList *members, const char *msg)
4233 struct yahoo_input_data *yid =
4234 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4235 struct yahoo_data *yd;
4236 struct yahoo_packet *pkt;
4238 if (!yid)
4239 return;
4240 yd = yid->yd;
4242 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFADDINVITE,
4243 YPACKET_STATUS_DEFAULT, yd->session_id);
4245 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4246 yahoo_packet_hash(pkt, 51, who);
4247 yahoo_packet_hash(pkt, 57, room);
4248 yahoo_packet_hash(pkt, 58, msg);
4249 yahoo_packet_hash(pkt, 13, "0");
4250 for (; members; members = members->next) {
4251 yahoo_packet_hash(pkt, 52, (char *)members->data);
4252 yahoo_packet_hash(pkt, 53, (char *)members->data);
4254 /* 52, 53 -> other members? */
4256 yahoo_send_packet(yid, pkt, 0);
4258 yahoo_packet_free(pkt);
4261 void yahoo_conference_invite(int id, const char *from, YList *who,
4262 const char *room, const char *msg)
4264 struct yahoo_input_data *yid =
4265 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4266 struct yahoo_data *yd;
4267 struct yahoo_packet *pkt;
4269 if (!yid)
4270 return;
4271 yd = yid->yd;
4273 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFINVITE, YPACKET_STATUS_DEFAULT,
4274 yd->session_id);
4276 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4277 yahoo_packet_hash(pkt, 50, yd->user);
4278 for (; who; who = who->next) {
4279 yahoo_packet_hash(pkt, 52, (char *)who->data);
4281 yahoo_packet_hash(pkt, 57, room);
4282 yahoo_packet_hash(pkt, 58, msg);
4283 yahoo_packet_hash(pkt, 13, "0");
4285 yahoo_send_packet(yid, pkt, 0);
4287 yahoo_packet_free(pkt);
4290 void yahoo_conference_logon(int id, const char *from, YList *who,
4291 const char *room)
4293 struct yahoo_input_data *yid =
4294 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4295 struct yahoo_data *yd;
4296 struct yahoo_packet *pkt;
4298 if (!yid)
4299 return;
4300 yd = yid->yd;
4302 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGON, YPACKET_STATUS_DEFAULT,
4303 yd->session_id);
4305 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4306 yahoo_packet_hash(pkt, 3, (from ? from : yd->user));
4307 yahoo_packet_hash(pkt, 57, room);
4308 for (; who; who = who->next)
4309 yahoo_packet_hash(pkt, 3, (char *)who->data);
4311 yahoo_send_packet(yid, pkt, 0);
4313 yahoo_packet_free(pkt);
4316 void yahoo_conference_decline(int id, const char *from, YList *who,
4317 const char *room, const char *msg)
4319 struct yahoo_input_data *yid =
4320 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4321 struct yahoo_data *yd;
4322 struct yahoo_packet *pkt;
4324 if (!yid)
4325 return;
4326 yd = yid->yd;
4328 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFDECLINE,
4329 YPACKET_STATUS_DEFAULT, yd->session_id);
4331 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4332 yahoo_packet_hash(pkt, 3, (from ? from : yd->user));
4333 for (; who; who = who->next)
4334 yahoo_packet_hash(pkt, 3, (char *)who->data);
4335 yahoo_packet_hash(pkt, 57, room);
4336 yahoo_packet_hash(pkt, 14, msg);
4338 yahoo_send_packet(yid, pkt, 0);
4340 yahoo_packet_free(pkt);
4343 void yahoo_conference_logoff(int id, const char *from, YList *who,
4344 const char *room)
4346 struct yahoo_input_data *yid =
4347 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4348 struct yahoo_data *yd;
4349 struct yahoo_packet *pkt;
4351 if (!yid)
4352 return;
4353 yd = yid->yd;
4355 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGOFF, YPACKET_STATUS_DEFAULT,
4356 yd->session_id);
4358 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4359 yahoo_packet_hash(pkt, 3, (from ? from : yd->user));
4360 for (; who; who = who->next)
4361 yahoo_packet_hash(pkt, 3, (char *)who->data);
4363 yahoo_packet_hash(pkt, 57, room);
4365 yahoo_send_packet(yid, pkt, 0);
4367 yahoo_packet_free(pkt);
4370 void yahoo_conference_message(int id, const char *from, YList *who,
4371 const char *room, const char *msg, int utf8)
4373 struct yahoo_input_data *yid =
4374 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4375 struct yahoo_data *yd;
4376 struct yahoo_packet *pkt;
4378 if (!yid)
4379 return;
4380 yd = yid->yd;
4382 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFMSG, YPACKET_STATUS_DEFAULT,
4383 yd->session_id);
4385 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4386 yahoo_packet_hash(pkt, 53, (from ? from : yd->user));
4387 for (; who; who = who->next)
4388 yahoo_packet_hash(pkt, 53, (char *)who->data);
4390 yahoo_packet_hash(pkt, 57, room);
4391 yahoo_packet_hash(pkt, 14, msg);
4393 if (utf8)
4394 yahoo_packet_hash(pkt, 97, "1");
4396 yahoo_send_packet(yid, pkt, 0);
4398 yahoo_packet_free(pkt);
4401 void yahoo_get_chatrooms(int id, int chatroomid)
4403 struct yahoo_data *yd = find_conn_by_id(id);
4404 struct yahoo_input_data *yid;
4405 char url[1024];
4406 char buff[1024];
4408 if (!yd)
4409 return;
4411 yid = y_new0(struct yahoo_input_data, 1);
4412 yid->yd = yd;
4413 yid->type = YAHOO_CONNECTION_CHATCAT;
4415 if (chatroomid == 0) {
4416 snprintf(url, 1024,
4417 "http://insider.msg.yahoo.com/ycontent/?chatcat=0");
4418 } else {
4419 snprintf(url, 1024,
4420 "http://insider.msg.yahoo.com/ycontent/?chatroom_%d=0",
4421 chatroomid);
4424 snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
4426 inputs = y_list_prepend(inputs, yid);
4428 yahoo_http_get(yid->yd->client_id, url, buff, 0, 0,
4429 _yahoo_http_connected, yid);
4432 void yahoo_chat_logon(int id, const char *from, const char *room,
4433 const char *roomid)
4435 struct yahoo_input_data *yid =
4436 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4437 struct yahoo_data *yd;
4438 struct yahoo_packet *pkt;
4440 if (!yid)
4441 return;
4443 yd = yid->yd;
4445 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YPACKET_STATUS_DEFAULT,
4446 yd->session_id);
4448 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4449 yahoo_packet_hash(pkt, 109, yd->user);
4450 yahoo_packet_hash(pkt, 6, "abcde");
4452 yahoo_send_packet(yid, pkt, 0);
4454 yahoo_packet_free(pkt);
4456 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YPACKET_STATUS_DEFAULT,
4457 yd->session_id);
4459 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4460 yahoo_packet_hash(pkt, 104, room);
4461 yahoo_packet_hash(pkt, 129, roomid);
4462 yahoo_packet_hash(pkt, 62, "2"); /* ??? */
4464 yahoo_send_packet(yid, pkt, 0);
4466 yahoo_packet_free(pkt);
4469 void yahoo_chat_message(int id, const char *from, const char *room,
4470 const char *msg, const int msgtype, const int utf8)
4472 struct yahoo_input_data *yid =
4473 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4474 struct yahoo_data *yd;
4475 struct yahoo_packet *pkt;
4476 char buf[2];
4478 if (!yid)
4479 return;
4481 yd = yid->yd;
4483 pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YPACKET_STATUS_DEFAULT,
4484 yd->session_id);
4486 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4487 yahoo_packet_hash(pkt, 104, room);
4488 yahoo_packet_hash(pkt, 117, msg);
4490 snprintf(buf, sizeof(buf), "%d", msgtype);
4491 yahoo_packet_hash(pkt, 124, buf);
4493 if (utf8)
4494 yahoo_packet_hash(pkt, 97, "1");
4496 yahoo_send_packet(yid, pkt, 0);
4498 yahoo_packet_free(pkt);
4501 void yahoo_chat_logoff(int id, const char *from)
4503 struct yahoo_input_data *yid =
4504 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4505 struct yahoo_data *yd;
4506 struct yahoo_packet *pkt;
4508 if (!yid)
4509 return;
4511 yd = yid->yd;
4513 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATLOGOUT, YPACKET_STATUS_DEFAULT,
4514 yd->session_id);
4516 yahoo_packet_hash(pkt, 1, (from ? from : yd->user));
4518 yahoo_send_packet(yid, pkt, 0);
4520 yahoo_packet_free(pkt);
4523 void yahoo_buddyicon_request(int id, const char *who)
4525 struct yahoo_input_data *yid =
4526 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4527 struct yahoo_data *yd;
4528 struct yahoo_packet *pkt;
4530 if (!yid)
4531 return;
4533 yd = yid->yd;
4535 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YPACKET_STATUS_DEFAULT,
4537 yahoo_packet_hash(pkt, 4, yd->user);
4538 yahoo_packet_hash(pkt, 5, who);
4539 yahoo_packet_hash(pkt, 13, "1");
4540 yahoo_send_packet(yid, pkt, 0);
4542 yahoo_packet_free(pkt);
4545 void yahoo_send_picture_info(int id, const char *who, const char *url,
4546 int checksum)
4548 struct yahoo_input_data *yid =
4549 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4550 struct yahoo_data *yd;
4551 struct yahoo_packet *pkt;
4552 char checksum_str[10];
4554 if (!yid)
4555 return;
4557 yd = yid->yd;
4559 snprintf(checksum_str, sizeof(checksum_str), "%d", checksum);
4561 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YPACKET_STATUS_DEFAULT,
4563 yahoo_packet_hash(pkt, 1, yd->user);
4564 yahoo_packet_hash(pkt, 4, yd->user);
4565 yahoo_packet_hash(pkt, 5, who);
4566 yahoo_packet_hash(pkt, 13, "2");
4567 yahoo_packet_hash(pkt, 20, url);
4568 yahoo_packet_hash(pkt, 192, checksum_str);
4569 yahoo_send_packet(yid, pkt, 0);
4571 yahoo_packet_free(pkt);
4574 void yahoo_send_picture_update(int id, const char *who, int type)
4576 struct yahoo_input_data *yid =
4577 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4578 struct yahoo_data *yd;
4579 struct yahoo_packet *pkt;
4580 char type_str[10];
4582 if (!yid)
4583 return;
4585 yd = yid->yd;
4587 snprintf(type_str, sizeof(type_str), "%d", type);
4589 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPDATE,
4590 YPACKET_STATUS_DEFAULT, 0);
4591 yahoo_packet_hash(pkt, 1, yd->user);
4592 yahoo_packet_hash(pkt, 5, who);
4593 yahoo_packet_hash(pkt, 206, type_str);
4594 yahoo_send_packet(yid, pkt, 0);
4596 yahoo_packet_free(pkt);
4599 void yahoo_send_picture_checksum(int id, const char *who, int checksum)
4601 struct yahoo_input_data *yid =
4602 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4603 struct yahoo_data *yd;
4604 struct yahoo_packet *pkt;
4605 char checksum_str[10];
4607 if (!yid)
4608 return;
4610 yd = yid->yd;
4612 snprintf(checksum_str, sizeof(checksum_str), "%d", checksum);
4614 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_CHECKSUM,
4615 YPACKET_STATUS_DEFAULT, 0);
4616 yahoo_packet_hash(pkt, 1, yd->user);
4617 if (who != 0)
4618 yahoo_packet_hash(pkt, 5, who);
4619 yahoo_packet_hash(pkt, 192, checksum_str);
4620 yahoo_packet_hash(pkt, 212, "1");
4621 yahoo_send_packet(yid, pkt, 0);
4623 yahoo_packet_free(pkt);
4626 void yahoo_webcam_close_feed(int id, const char *who)
4628 struct yahoo_input_data *yid =
4629 find_input_by_id_and_webcam_user(id, who);
4631 if (yid)
4632 yahoo_input_close(yid);
4635 void yahoo_webcam_get_feed(int id, const char *who)
4637 struct yahoo_input_data *yid =
4638 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4639 struct yahoo_data *yd;
4640 struct yahoo_packet *pkt;
4642 if (!yid)
4643 return;
4646 * add the user to the queue. this is a dirty hack, since
4647 * the yahoo server doesn't tell us who's key it's returning,
4648 * we have to just hope that it sends back keys in the same
4649 * order that we request them.
4650 * The queue is popped in yahoo_process_webcam_key
4652 webcam_queue = y_list_append(webcam_queue, who ? strdup(who) : NULL);
4654 yd = yid->yd;
4656 pkt = yahoo_packet_new(YAHOO_SERVICE_WEBCAM, YPACKET_STATUS_DEFAULT,
4657 yd->session_id);
4659 yahoo_packet_hash(pkt, 1, yd->user);
4660 if (who != NULL)
4661 yahoo_packet_hash(pkt, 5, who);
4662 yahoo_send_packet(yid, pkt, 0);
4664 yahoo_packet_free(pkt);
4667 void yahoo_webcam_send_image(int id, unsigned char *image, unsigned int length,
4668 unsigned int timestamp)
4670 struct yahoo_input_data *yid =
4671 find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
4672 unsigned char *packet;
4673 unsigned char header_len = 13;
4674 unsigned int pos = 0;
4676 if (!yid)
4677 return;
4679 packet = y_new0(unsigned char, header_len);
4681 packet[pos++] = header_len;
4682 packet[pos++] = 0;
4683 packet[pos++] = 5; /* version byte?? */
4684 packet[pos++] = 0;
4685 pos += yahoo_put32(packet + pos, length);
4686 packet[pos++] = 2; /* packet type, image */
4687 pos += yahoo_put32(packet + pos, timestamp);
4688 yahoo_add_to_send_queue(yid, packet, header_len);
4689 FREE(packet);
4691 if (length)
4692 yahoo_add_to_send_queue(yid, image, length);
4695 void yahoo_webcam_accept_viewer(int id, const char *who, int accept)
4697 struct yahoo_input_data *yid =
4698 find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
4699 char *packet = NULL;
4700 char *data = NULL;
4701 unsigned char header_len = 13;
4702 unsigned int pos = 0;
4703 unsigned int len = 0;
4705 if (!yid)
4706 return;
4708 data = strdup("u=");
4709 data = y_string_append(data, (char *)who);
4710 data = y_string_append(data, "\r\n");
4711 len = strlen(data);
4713 packet = y_new0(char, header_len + len);
4714 packet[pos++] = header_len;
4715 packet[pos++] = 0;
4716 packet[pos++] = 5; /* version byte?? */
4717 packet[pos++] = 0;
4718 pos += yahoo_put32(packet + pos, len);
4719 packet[pos++] = 0; /* packet type */
4720 pos += yahoo_put32(packet + pos, accept);
4721 memcpy(packet + pos, data, len);
4722 FREE(data);
4723 yahoo_add_to_send_queue(yid, packet, header_len + len);
4724 FREE(packet);
4727 void yahoo_webcam_invite(int id, const char *who)
4729 struct yahoo_input_data *yid =
4730 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4731 struct yahoo_packet *pkt;
4733 if (!yid)
4734 return;
4736 pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YPACKET_STATUS_NOTIFY,
4737 yid->yd->session_id);
4739 yahoo_packet_hash(pkt, 49, "WEBCAMINVITE");
4740 yahoo_packet_hash(pkt, 14, " ");
4741 yahoo_packet_hash(pkt, 13, "0");
4742 yahoo_packet_hash(pkt, 1, yid->yd->user);
4743 yahoo_packet_hash(pkt, 5, who);
4744 yahoo_send_packet(yid, pkt, 0);
4746 yahoo_packet_free(pkt);
4749 static void yahoo_search_internal(int id, int t, const char *text, int g,
4750 int ar, int photo, int yahoo_only, int startpos, int total)
4752 struct yahoo_data *yd = find_conn_by_id(id);
4753 struct yahoo_input_data *yid;
4754 char url[1024];
4755 char buff[1024];
4756 char *ctext, *p;
4758 if (!yd)
4759 return;
4761 yid = y_new0(struct yahoo_input_data, 1);
4762 yid->yd = yd;
4763 yid->type = YAHOO_CONNECTION_SEARCH;
4766 age range
4767 .ar=1 - 13-18, 2 - 18-25, 3 - 25-35, 4 - 35-50, 5 - 50-70, 6 - 70+
4770 snprintf(buff, sizeof(buff), "&.sq=%%20&.tt=%d&.ss=%d", total,
4771 startpos);
4773 ctext = strdup(text);
4774 while ((p = strchr(ctext, ' ')))
4775 *p = '+';
4777 snprintf(url, 1024,
4778 "http://members.yahoo.com/interests?.oc=m&.kw=%s&.sb=%d&.g=%d&.ar=0%s%s%s",
4779 ctext, t, g, photo ? "&.p=y" : "", yahoo_only ? "&.pg=y" : "",
4780 startpos ? buff : "");
4782 FREE(ctext);
4784 snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
4786 inputs = y_list_prepend(inputs, yid);
4787 yahoo_http_get(yid->yd->client_id, url, buff, 0, 0,
4788 _yahoo_http_connected, yid);
4791 void yahoo_search(int id, enum yahoo_search_type t, const char *text,
4792 enum yahoo_search_gender g, enum yahoo_search_agerange ar, int photo,
4793 int yahoo_only)
4795 struct yahoo_input_data *yid =
4796 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4797 struct yahoo_search_state *yss;
4799 if (!yid)
4800 return;
4802 if (!yid->ys)
4803 yid->ys = y_new0(struct yahoo_search_state, 1);
4805 yss = yid->ys;
4807 FREE(yss->lsearch_text);
4808 yss->lsearch_type = t;
4809 yss->lsearch_text = strdup(text);
4810 yss->lsearch_gender = g;
4811 yss->lsearch_agerange = ar;
4812 yss->lsearch_photo = photo;
4813 yss->lsearch_yahoo_only = yahoo_only;
4815 yahoo_search_internal(id, t, text, g, ar, photo, yahoo_only, 0, 0);
4818 void yahoo_search_again(int id, int start)
4820 struct yahoo_input_data *yid =
4821 find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4822 struct yahoo_search_state *yss;
4824 if (!yid || !yid->ys)
4825 return;
4827 yss = yid->ys;
4829 if (start == -1)
4830 start = yss->lsearch_nstart + yss->lsearch_nfound;
4832 yahoo_search_internal(id, yss->lsearch_type, yss->lsearch_text,
4833 yss->lsearch_gender, yss->lsearch_agerange,
4834 yss->lsearch_photo, yss->lsearch_yahoo_only,
4835 start, yss->lsearch_ntotal);
4838 void yahoo_send_picture(int id, const char *name, unsigned long size,
4839 yahoo_get_fd_callback callback, void *data)
4841 /* Not Implemented */
4844 /* File Transfer */
4845 static YList *active_file_transfers = NULL;
4847 enum {
4848 FT_STATE_HEAD = 1,
4849 FT_STATE_RECV,
4850 FT_STATE_RECV_START,
4851 FT_STATE_SEND
4854 struct send_file_data {
4855 int client_id;
4856 char *id;
4857 char *who;
4858 char *filename;
4859 char *ip_addr;
4860 char *token;
4861 int size;
4863 struct yahoo_input_data *yid;
4864 int state;
4866 yahoo_get_fd_callback callback;
4867 void *data;
4870 static char *yahoo_get_random(void)
4872 int i = 0;
4873 int r = 0;
4874 int c = 0;
4875 char out[25];
4877 out[24] = '\0';
4878 out[23] = '$';
4879 out[22] = '$';
4881 for (i = 0; i < 22; i++) {
4882 if(r == 0)
4883 r = rand();
4885 c = r%61;
4887 if(c<26)
4888 out[i] = c + 'a';
4889 else if (c<52)
4890 out[i] = c - 26 + 'A';
4891 else
4892 out[i] = c - 52 + '0';
4894 r /= 61;
4897 return strdup(out);
4900 static int _are_same_id(const void *sfd1, const void *id)
4902 return strcmp(((struct send_file_data *)sfd1)->id, (char *)id);
4905 static int _are_same_yid(const void *sfd1, const void *yid)
4907 if(((struct send_file_data *)sfd1)->yid == yid)
4908 return 0;
4909 else
4910 return 1;
4913 static struct send_file_data *yahoo_get_active_transfer(char *id)
4915 YList *l = y_list_find_custom(active_file_transfers, id,
4916 _are_same_id);
4918 if(l)
4919 return (struct send_file_data *)l->data;
4921 return NULL;
4924 static struct send_file_data *yahoo_get_active_transfer_with_yid(void *yid)
4926 YList *l = y_list_find_custom(active_file_transfers, yid,
4927 _are_same_yid);
4929 if(l)
4930 return (struct send_file_data *)l->data;
4932 return NULL;
4935 static void yahoo_add_active_transfer(struct send_file_data *sfd)
4937 active_file_transfers = y_list_prepend(active_file_transfers, sfd);
4940 static void yahoo_remove_active_transfer(struct send_file_data *sfd)
4942 active_file_transfers = y_list_remove(active_file_transfers, sfd);
4943 free(sfd->id);
4944 free(sfd->who);
4945 free(sfd->filename);
4946 free(sfd->ip_addr);
4947 FREE(sfd);
4950 static void _yahoo_ft_upload_connected(int id, void *fd, int error, void *data)
4952 struct send_file_data *sfd = data;
4953 struct yahoo_input_data *yid = sfd->yid;
4955 if (!fd) {
4956 inputs = y_list_remove(inputs, yid);
4957 FREE(yid);
4958 return;
4961 sfd->callback(id, fd, error, sfd->data);
4963 yid->fd = fd;
4964 yid->read_tag =
4965 YAHOO_CALLBACK(ext_yahoo_add_handler) (yid->yd->client_id, fd,
4966 YAHOO_INPUT_READ, yid);
4969 static void yahoo_file_transfer_upload(struct yahoo_data *yd,
4970 struct send_file_data *sfd)
4972 char url[256];
4973 char buff[4096];
4974 char *sender_enc = NULL, *recv_enc = NULL, *token_enc = NULL;
4976 struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
4978 yid->yd = yd;
4979 yid->type = YAHOO_CONNECTION_FT;
4981 inputs = y_list_prepend(inputs, yid);
4982 sfd->yid = yid;
4983 sfd->state = FT_STATE_SEND;
4985 token_enc = yahoo_urlencode(sfd->token);
4986 sender_enc = yahoo_urlencode(yd->user);
4987 recv_enc = yahoo_urlencode(sfd->who);
4989 snprintf(url, sizeof(url),
4990 "http://%s/relay?token=%s&sender=%s&recver=%s", sfd->ip_addr,
4991 token_enc, sender_enc, recv_enc);
4993 snprintf(buff, sizeof(buff), "T=%s; Y=%s", yd->cookie_t, yd->cookie_y);
4995 yahoo_http_post(yd->client_id, url, buff, sfd->size,
4996 _yahoo_ft_upload_connected, sfd);
4998 FREE(token_enc);
4999 FREE(sender_enc);
5000 FREE(recv_enc);
5003 static void yahoo_init_ft_recv(struct yahoo_data *yd,
5004 struct send_file_data *sfd)
5006 char url[256];
5007 char buff[1024];
5008 char *sender_enc = NULL, *recv_enc = NULL, *token_enc = NULL;
5010 struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
5012 yid->yd = yd;
5013 yid->type = YAHOO_CONNECTION_FT;
5015 inputs = y_list_prepend(inputs, yid);
5016 sfd->yid = yid;
5017 sfd->state = FT_STATE_HEAD;
5019 token_enc = yahoo_urlencode(sfd->token);
5020 sender_enc = yahoo_urlencode(sfd->who);
5021 recv_enc = yahoo_urlencode(yd->user);
5023 snprintf(url, sizeof(url),
5024 "http://%s/relay?token=%s&sender=%s&recver=%s", sfd->ip_addr,
5025 token_enc, sender_enc, recv_enc);
5027 snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
5029 yahoo_http_head(yid->yd->client_id, url, buff, 0, NULL,
5030 _yahoo_http_connected, yid);
5032 FREE(token_enc);
5033 FREE(sender_enc);
5034 FREE(recv_enc);
5037 static void yahoo_file_transfer_accept(struct yahoo_input_data *yid,
5038 struct send_file_data *sfd)
5040 struct yahoo_packet *pkt;
5042 pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFERACCEPT,
5043 YPACKET_STATUS_DEFAULT, yid->yd->session_id);
5045 yahoo_packet_hash(pkt, 1, yid->yd->user);
5046 yahoo_packet_hash(pkt, 5, sfd->who);
5047 yahoo_packet_hash(pkt, 265, sfd->id);
5048 yahoo_packet_hash(pkt, 27, sfd->filename);
5049 yahoo_packet_hash(pkt, 249, "3");
5050 yahoo_packet_hash(pkt, 251, sfd->token);
5052 yahoo_send_packet(yid, pkt, 0);
5054 yahoo_packet_free(pkt);
5056 yahoo_init_ft_recv(yid->yd, sfd);
5059 static void yahoo_process_filetransferaccept(struct yahoo_input_data *yid,
5060 struct yahoo_packet *pkt)
5062 YList *l;
5063 struct send_file_data *sfd;
5064 char *who = NULL;
5065 char *filename = NULL;
5066 char *id = NULL;
5067 char *token = NULL;
5069 for (l = pkt->hash; l; l = l->next) {
5070 struct yahoo_pair *pair = l->data;
5071 switch (pair->key) {
5072 case 4:
5073 who = pair->value;
5074 break;
5075 case 5:
5076 /* Me... don't care */
5077 break;
5078 case 249:
5079 break;
5080 case 265:
5081 id = pair->value;
5082 break;
5083 case 251:
5084 token = pair->value;
5085 break;
5086 case 27:
5087 filename = pair->value;
5088 break;
5092 sfd = yahoo_get_active_transfer(id);
5094 if (sfd) {
5095 sfd->token = strdup(token);
5097 yahoo_file_transfer_upload(yid->yd, sfd);
5099 else {
5100 YAHOO_CALLBACK(ext_yahoo_file_transfer_done)
5101 (yid->yd->client_id, YAHOO_FILE_TRANSFER_UNKNOWN,
5102 sfd->data);
5104 yahoo_remove_active_transfer(sfd);
5108 static void yahoo_process_filetransferinfo(struct yahoo_input_data *yid,
5109 struct yahoo_packet *pkt)
5111 YList *l;
5112 char *who = NULL;
5113 char *filename = NULL;
5114 char *id = NULL;
5115 char *token = NULL;
5116 char *ip_addr = NULL;
5118 struct send_file_data *sfd;
5120 for (l = pkt->hash; l; l = l->next) {
5121 struct yahoo_pair *pair = l->data;
5122 switch (pair->key) {
5123 case 1:
5124 case 4:
5125 who = pair->value;
5126 break;
5127 case 5:
5128 /* Me... don't care */
5129 break;
5130 case 249:
5131 break;
5132 case 265:
5133 id = pair->value;
5134 break;
5135 case 250:
5136 ip_addr = pair->value;
5137 break;
5138 case 251:
5139 token = pair->value;
5140 break;
5141 case 27:
5142 filename = pair->value;
5143 break;
5147 sfd = yahoo_get_active_transfer(id);
5149 if (sfd) {
5150 sfd->token = strdup(token);
5151 sfd->ip_addr = strdup(ip_addr);
5153 yahoo_file_transfer_accept(yid, sfd);
5155 else {
5156 YAHOO_CALLBACK(ext_yahoo_file_transfer_done)
5157 (yid->yd->client_id, YAHOO_FILE_TRANSFER_UNKNOWN,
5158 sfd->data);
5160 yahoo_remove_active_transfer(sfd);
5164 static void yahoo_send_filetransferinfo(struct yahoo_data *yd,
5165 struct send_file_data *sfd)
5167 struct yahoo_input_data *yid;
5168 struct yahoo_packet *pkt;
5170 yid = find_input_by_id_and_type(yd->client_id, YAHOO_CONNECTION_PAGER);
5171 sfd->ip_addr = YAHOO_CALLBACK(ext_yahoo_get_ip_addr)("relay.yahoo.com");
5173 if (!sfd->ip_addr) {
5174 YAHOO_CALLBACK(ext_yahoo_file_transfer_done)
5175 (yd->client_id, YAHOO_FILE_TRANSFER_RELAY, sfd->data);
5177 yahoo_remove_active_transfer(sfd);
5179 return;
5182 pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFERINFO,
5183 YPACKET_STATUS_DEFAULT, yd->session_id);
5185 yahoo_packet_hash(pkt, 1, yd->user);
5186 yahoo_packet_hash(pkt, 5, sfd->who);
5187 yahoo_packet_hash(pkt, 265, sfd->id);
5188 yahoo_packet_hash(pkt, 27, sfd->filename);
5189 yahoo_packet_hash(pkt, 249, "3");
5190 yahoo_packet_hash(pkt, 250, sfd->ip_addr);
5192 yahoo_send_packet(yid, pkt, 0);
5194 yahoo_packet_free(pkt);
5197 static void yahoo_process_filetransfer(struct yahoo_input_data *yid,
5198 struct yahoo_packet *pkt)
5200 YList *l;
5201 char *who = NULL;
5202 char *filename = NULL;
5203 char *msg = NULL;
5204 char *id = NULL;
5205 int action = 0;
5206 int size = 0;
5207 struct yahoo_data *yd = yid->yd;
5209 struct send_file_data *sfd;
5211 for (l = pkt->hash; l; l = l->next) {
5212 struct yahoo_pair *pair = l->data;
5213 switch (pair->key) {
5214 case 4:
5215 who = pair->value;
5216 break;
5217 case 5:
5218 /* Me... don't care */
5219 break;
5220 case 222:
5221 action = atoi(pair->value);
5222 break;
5223 case 265:
5224 id = pair->value;
5225 break;
5226 case 266: /* Don't know */
5227 break;
5228 case 302: /* Start Data? */
5229 break;
5230 case 300:
5231 break;
5232 case 27:
5233 filename = pair->value;
5234 break;
5235 case 28:
5236 size = atoi(pair->value);
5237 break;
5238 case 14:
5239 msg = pair->value;
5240 case 301: /* End Data? */
5241 break;
5242 case 303:
5243 break;
5248 if (action == YAHOO_FILE_TRANSFER_INIT) {
5249 /* Received a FT request from buddy */
5250 sfd = y_new0(struct send_file_data, 1);
5252 sfd->client_id = yd->client_id;
5253 sfd->id = strdup(id);
5254 sfd->who = strdup(who);
5255 sfd->filename = strdup(filename);
5256 sfd->size = size;
5258 yahoo_add_active_transfer(sfd);
5260 YAHOO_CALLBACK(ext_yahoo_got_file) (yd->client_id, yd->user,
5261 who, msg, filename, size, sfd->id);
5263 else {
5264 /* Response to our request */
5265 sfd = yahoo_get_active_transfer(id);
5267 if (sfd && action == YAHOO_FILE_TRANSFER_ACCEPT) {
5268 yahoo_send_filetransferinfo(yd, sfd);
5270 else if (!sfd || action == YAHOO_FILE_TRANSFER_REJECT) {
5271 YAHOO_CALLBACK(ext_yahoo_file_transfer_done)
5272 (yd->client_id, YAHOO_FILE_TRANSFER_REJECT,
5273 sfd->data);
5275 yahoo_remove_active_transfer(sfd);
5280 void yahoo_send_file(int id, const char *who, const char *msg,
5281 const char *name, unsigned long size,
5282 yahoo_get_fd_callback callback, void *data)
5284 struct yahoo_packet *pkt = NULL;
5285 char size_str[10];
5286 struct yahoo_input_data *yid;
5287 struct yahoo_data *yd;
5288 struct send_file_data *sfd;
5290 yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5291 yd = find_conn_by_id(id);
5292 sfd = y_new0(struct send_file_data, 1);
5294 sfd->client_id = id;
5295 sfd->id = yahoo_get_random();
5296 sfd->who = strdup(who);
5297 sfd->filename = strdup(name);
5298 sfd->size = size;
5299 sfd->callback = callback;
5300 sfd->data = data;
5302 yahoo_add_active_transfer(sfd);
5304 if (!yd)
5305 return;
5307 pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFER,
5308 YPACKET_STATUS_DEFAULT, yd->session_id);
5310 snprintf(size_str, sizeof(size_str), "%ld", size);
5312 yahoo_packet_hash(pkt, 1, yd->user);
5313 yahoo_packet_hash(pkt, 5, who);
5314 yahoo_packet_hash(pkt, 265, sfd->id);
5315 yahoo_packet_hash(pkt, 222, "1");
5316 yahoo_packet_hash(pkt, 266, "1");
5317 yahoo_packet_hash(pkt, 302, "268");
5318 yahoo_packet_hash(pkt, 300, "268");
5319 yahoo_packet_hash(pkt, 27, name);
5320 yahoo_packet_hash(pkt, 28, size_str);
5321 yahoo_packet_hash(pkt, 301, "268");
5322 yahoo_packet_hash(pkt, 303, "268");
5324 yahoo_send_packet(yid, pkt, 0);
5326 yahoo_packet_free(pkt);
5329 void yahoo_send_file_transfer_response(int client_id, int response, char *id, void *data)
5331 struct yahoo_packet *pkt = NULL;
5332 char resp[2];
5333 struct yahoo_input_data *yid;
5335 struct send_file_data *sfd = yahoo_get_active_transfer(id);
5337 sfd->data = data;
5339 yid = find_input_by_id_and_type(client_id, YAHOO_CONNECTION_PAGER);
5341 pkt = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFER,
5342 YPACKET_STATUS_DEFAULT, yid->yd->session_id);
5344 snprintf(resp, sizeof(resp), "%d", response);
5346 yahoo_packet_hash(pkt, 1, yid->yd->user);
5347 yahoo_packet_hash(pkt, 5, sfd->who);
5348 yahoo_packet_hash(pkt, 265, sfd->id);
5349 yahoo_packet_hash(pkt, 222, resp);
5351 yahoo_send_packet(yid, pkt, 0);
5353 yahoo_packet_free(pkt);
5355 if(response == YAHOO_FILE_TRANSFER_REJECT)
5356 yahoo_remove_active_transfer(sfd);
5359 static void yahoo_process_ft_connection(struct yahoo_input_data *yid, int over)
5361 struct send_file_data *sfd;
5362 struct yahoo_data *yd = yid->yd;
5364 sfd = yahoo_get_active_transfer_with_yid(yid);
5366 if (!sfd) {
5367 LOG(("Something funny happened. yid %p has no sfd.\n", yid));
5368 return;
5372 * We want to handle only the complete data with HEAD since we don't
5373 * want a situation where both the GET and HEAD are active.
5374 * With SEND, we really can't do much with partial response
5376 if ((sfd->state == FT_STATE_HEAD || sfd->state == FT_STATE_SEND)
5377 && !over)
5378 return;
5380 if (sfd->state == FT_STATE_HEAD) {
5381 /* Do a GET */
5382 char url[256];
5383 char buff[1024];
5384 char *sender_enc = NULL, *recv_enc = NULL, *token_enc = NULL;
5386 struct yahoo_input_data *yid_ft =
5387 y_new0(struct yahoo_input_data, 1);
5389 yid_ft->yd = yid->yd;
5390 yid_ft->type = YAHOO_CONNECTION_FT;
5392 inputs = y_list_prepend(inputs, yid_ft);
5393 sfd->yid = yid_ft;
5394 sfd->state = FT_STATE_RECV;
5396 token_enc = yahoo_urlencode(sfd->token);
5397 sender_enc = yahoo_urlencode(sfd->who);
5398 recv_enc = yahoo_urlencode(yd->user);
5400 snprintf(url, sizeof(url),
5401 "http://%s/relay?token=%s&sender=%s&recver=%s", sfd->ip_addr,
5402 token_enc, sender_enc, recv_enc);
5404 snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y,
5405 yd->cookie_t);
5408 yahoo_http_get(yd->client_id, url, buff, 1, 1,
5409 _yahoo_http_connected, yid_ft);
5411 FREE(token_enc);
5412 FREE(sender_enc);
5413 FREE(recv_enc);
5415 else if (sfd->state == FT_STATE_RECV ||
5416 sfd->state == FT_STATE_RECV_START) {
5418 unsigned char *data_begin = NULL;
5420 if (yid->rxlen == 0)
5421 yahoo_remove_active_transfer(sfd);
5423 if (sfd->state != FT_STATE_RECV_START &&
5424 (data_begin =
5425 (unsigned char *)strstr((char *)yid->rxqueue,
5426 "\r\n\r\n"))) {
5428 sfd->state = FT_STATE_RECV_START;
5430 yid->rxlen -= 4+(data_begin-yid->rxqueue)/sizeof(char);
5431 data_begin += 4;
5433 if (yid->rxlen > 0)
5434 YAHOO_CALLBACK(ext_yahoo_got_ft_data)
5435 (yd->client_id, data_begin,
5436 yid->rxlen, sfd->data);
5438 else if (sfd->state == FT_STATE_RECV_START)
5439 YAHOO_CALLBACK(ext_yahoo_got_ft_data) (yd->client_id,
5440 yid->rxqueue, yid->rxlen, sfd->data);
5442 FREE(yid->rxqueue);
5443 yid->rxqueue = NULL;
5444 yid->rxlen = 0;
5446 else if (sfd->state == FT_STATE_SEND) {
5447 /* Sent file completed */
5448 int len = 0;
5449 char *off = strstr((char *)yid->rxqueue, "Content-Length: ");
5451 if (off) {
5452 off += 16;
5453 len = atoi(off);
5456 if (len < sfd->size)
5457 YAHOO_CALLBACK(ext_yahoo_file_transfer_done)
5458 (yd->client_id,
5459 YAHOO_FILE_TRANSFER_FAILED, sfd->data);
5460 else
5461 YAHOO_CALLBACK(ext_yahoo_file_transfer_done)
5462 (yd->client_id,
5463 YAHOO_FILE_TRANSFER_DONE, sfd->data);
5465 yahoo_remove_active_transfer(sfd);
5469 /* End File Transfer */
5471 enum yahoo_status yahoo_current_status(int id)
5473 struct yahoo_data *yd = find_conn_by_id(id);
5474 if (!yd)
5475 return YAHOO_STATUS_OFFLINE;
5476 return yd->current_status;
5479 const YList *yahoo_get_buddylist(int id)
5481 struct yahoo_data *yd = find_conn_by_id(id);
5482 if (!yd)
5483 return NULL;
5484 return yd->buddies;
5487 const YList *yahoo_get_ignorelist(int id)
5489 struct yahoo_data *yd = find_conn_by_id(id);
5490 if (!yd)
5491 return NULL;
5492 return yd->ignore;
5495 const YList *yahoo_get_identities(int id)
5497 struct yahoo_data *yd = find_conn_by_id(id);
5498 if (!yd)
5499 return NULL;
5500 return yd->identities;
5503 const char *yahoo_get_cookie(int id, const char *which)
5505 struct yahoo_data *yd = find_conn_by_id(id);
5506 if (!yd)
5507 return NULL;
5508 if (!strncasecmp(which, "y", 1))
5509 return yd->cookie_y;
5510 if (!strncasecmp(which, "b", 1))
5511 return yd->cookie_b;
5512 if (!strncasecmp(which, "t", 1))
5513 return yd->cookie_t;
5514 if (!strncasecmp(which, "c", 1))
5515 return yd->cookie_c;
5516 if (!strncasecmp(which, "login", 5))
5517 return yd->login_cookie;
5518 return NULL;
5521 const char *yahoo_get_profile_url(void)
5523 return profile_url;