Improve yahoo login verbosity
[centerim.git] / libyahoo2 / libyahoo2.c
blob70efe25ce29e60156f5fd1271c3defb03ed10f05
1 /*
2 * libyahoo2: libyahoo2.c
4 * Some code copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
6 * Yahoo Search copyright (C) 2003, Konstantin Klyagin <konst AT konst.org.ua>
8 * Much of this code was taken and adapted from the yahoo module for
9 * gaim released under the GNU GPL. This code is also released under the
10 * GNU GPL.
12 * This code is derivitive of Gaim <http://gaim.sourceforge.net>
13 * copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
14 * 1998-1999, Adam Fritzler <afritz@marko.net>
15 * 1998-2002, Rob Flynn <rob@marko.net>
16 * 2000-2002, Eric Warmenhoven <eric@warmenhoven.org>
17 * 2001-2002, Brian Macke <macke@strangelove.net>
18 * 2001, Anand Biligiri S <abiligiri@users.sf.net>
19 * 2001, Valdis Kletnieks
20 * 2002, Sean Egan <bj91704@binghamton.edu>
21 * 2002, Toby Gray <toby.gray@ntlworld.com>
23 * This library also uses code from other libraries, namely:
24 * Portions from libfaim copyright 1998, 1999 Adam Fritzler
25 * <afritz@auk.cx>
26 * Portions of Sylpheed copyright 2000-2002 Hiroyuki Yamamoto
27 * <hiro-y@kcn.ne.jp>
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46 #if HAVE_CONFIG_H
47 # include <config.h>
48 #endif
50 #include <unistd.h>
51 #include <errno.h>
52 #include <stdio.h>
53 #include <stdarg.h>
54 #include <curl/curl.h>
56 #if STDC_HEADERS
57 # include <string.h>
58 #else
59 # if !HAVE_STRCHR
60 # define strchr index
61 # define strrchr rindex
62 # endif
63 char *strchr (), *strrchr ();
64 # if !HAVE_MEMCPY
65 # define memcpy(d, s, n) bcopy ((s), (d), (n))
66 # define memmove(d, s, n) bcopy ((s), (d), (n))
67 # endif
68 #endif
70 #include <sys/types.h>
72 #ifdef __MINGW32__
73 # include <winsock2.h>
74 # define write(a,b,c) send(a,b,c,0)
75 # define read(a,b,c) recv(a,b,c,0)
76 #endif
78 #include <stdlib.h>
79 #include <ctype.h>
81 #include "sha.h"
82 #include "md5.h"
83 #include "yahoo2.h"
84 #include "yahoo_httplib.h"
85 #include "yahoo_util.h"
86 #include "yahoo_auth.h"
88 #include "yahoo2_callbacks.h"
89 #include "yahoo_debug.h"
90 #ifdef __MINGW32__
91 #define snprintf _snprintf
92 #define vsnprintf _vsnprintf
93 #endif
95 #ifdef USE_STRUCT_CALLBACKS
96 struct yahoo_callbacks *yc=NULL;
98 static int yahoo_send_data(int fd, void *data, int len);
100 void yahoo_register_callbacks(struct yahoo_callbacks * tyc)
102 yc = tyc;
105 #define YAHOO_CALLBACK(x) yc->x
106 #else
107 #define YAHOO_CALLBACK(x) x
108 #endif
110 char *curl_buffer = NULL;
111 size_t curl_buffer_size = 0;
113 size_t yahoo_handle_curl_write(void *ptr, size_t size, size_t nmemb, void *stream)
115 if (curl_buffer == NULL)
117 curl_buffer = malloc(size*nmemb);
118 curl_buffer_size = 0;
120 else
122 curl_buffer = realloc(curl_buffer, curl_buffer_size + size*nmemb);
124 memcpy(curl_buffer + curl_buffer_size, ptr, size*nmemb);
125 curl_buffer_size += size*nmemb;
126 return size*nmemb;
129 int yahoo_log_message(char * fmt, ...)
131 char out[1024];
132 va_list ap;
133 va_start(ap, fmt);
134 vsnprintf(out, sizeof(out), fmt, ap);
135 va_end(ap);
136 return YAHOO_CALLBACK(ext_yahoo_log)("%s", out);
139 int yahoo_connect(char * host, int port)
141 return YAHOO_CALLBACK(ext_yahoo_connect)(host, port);
144 static enum yahoo_log_level log_level = YAHOO_LOG_WARNING;
146 enum yahoo_log_level yahoo_get_log_level()
148 return log_level;
151 int yahoo_set_log_level(enum yahoo_log_level level)
153 enum yahoo_log_level l = log_level;
154 log_level = level;
155 return l;
158 /* default values for servers */
159 static char pager_host[] = "scs.msg.yahoo.com";
160 static int pager_port = 5050;
161 static int fallback_ports[]={23, 25, 80, 20, 119, 8001, 8002, 5050, 0};
162 static char filetransfer_host[]="filetransfer.msg.yahoo.com";
163 static int filetransfer_port=80;
164 static char webcam_host[]="webcam.yahoo.com";
165 static int webcam_port=5100;
166 static char webcam_description[]="";
167 static char local_host[]="";
168 static int conn_type=Y_WCM_DSL;
170 static char profile_url[] = "http://profiles.yahoo.com/";
172 enum yahoo_service { /* these are easier to see in hex */
173 YAHOO_SERVICE_LOGON = 1,
174 YAHOO_SERVICE_LOGOFF,
175 YAHOO_SERVICE_ISAWAY,
176 YAHOO_SERVICE_ISBACK,
177 YAHOO_SERVICE_IDLE, /* 5 (placemarker) */
178 YAHOO_SERVICE_MESSAGE,
179 YAHOO_SERVICE_IDACT,
180 YAHOO_SERVICE_IDDEACT,
181 YAHOO_SERVICE_MAILSTAT,
182 YAHOO_SERVICE_USERSTAT, /* 0xa */
183 YAHOO_SERVICE_NEWMAIL,
184 YAHOO_SERVICE_CHATINVITE,
185 YAHOO_SERVICE_CALENDAR,
186 YAHOO_SERVICE_NEWPERSONALMAIL,
187 YAHOO_SERVICE_NEWCONTACT,
188 YAHOO_SERVICE_ADDIDENT, /* 0x10 */
189 YAHOO_SERVICE_ADDIGNORE,
190 YAHOO_SERVICE_PING,
191 YAHOO_SERVICE_GOTGROUPRENAME, /* < 1, 36(old), 37(new) */
192 YAHOO_SERVICE_SYSMESSAGE = 0x14,
193 YAHOO_SERVICE_PASSTHROUGH2 = 0x16,
194 YAHOO_SERVICE_CONFINVITE = 0x18,
195 YAHOO_SERVICE_CONFLOGON,
196 YAHOO_SERVICE_CONFDECLINE,
197 YAHOO_SERVICE_CONFLOGOFF,
198 YAHOO_SERVICE_CONFADDINVITE,
199 YAHOO_SERVICE_CONFMSG,
200 YAHOO_SERVICE_CHATLOGON,
201 YAHOO_SERVICE_CHATLOGOFF,
202 YAHOO_SERVICE_CHATMSG = 0x20,
203 YAHOO_SERVICE_GAMELOGON = 0x28,
204 YAHOO_SERVICE_GAMELOGOFF,
205 YAHOO_SERVICE_GAMEMSG = 0x2a,
206 YAHOO_SERVICE_FILETRANSFER = 0x46,
207 YAHOO_SERVICE_VOICECHAT = 0x4A,
208 YAHOO_SERVICE_NOTIFY,
209 YAHOO_SERVICE_VERIFY,
210 YAHOO_SERVICE_P2PFILEXFER,
211 YAHOO_SERVICE_PEERTOPEER = 0x4F, /* Checks if P2P possible */
212 YAHOO_SERVICE_WEBCAM,
213 YAHOO_SERVICE_AUTHRESP = 0x54,
214 YAHOO_SERVICE_LIST,
215 YAHOO_SERVICE_AUTH = 0x57,
216 YAHOO_SERVICE_ADDBUDDY = 0x83,
217 YAHOO_SERVICE_REMBUDDY,
218 YAHOO_SERVICE_IGNORECONTACT, /* > 1, 7, 13 < 1, 66, 13, 0*/
219 YAHOO_SERVICE_REJECTCONTACT,
220 YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */
221 YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/
222 YAHOO_SERVICE_CHATGOTO,
223 YAHOO_SERVICE_CHATJOIN, /* > 1 104-room 129-1600326591 62-2 */
224 YAHOO_SERVICE_CHATLEAVE,
225 YAHOO_SERVICE_CHATEXIT = 0x9b,
226 YAHOO_SERVICE_CHATLOGOUT = 0xa0,
227 YAHOO_SERVICE_CHATPING,
228 YAHOO_SERVICE_COMMENT = 0xa8,
229 YAHOO_SERVICE_STEALTH = 0xb9,
230 YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd,
231 YAHOO_SERVICE_PICTURE = 0xbe,
232 YAHOO_SERVICE_PICTURE_UPDATE = 0xc1,
233 YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2,
234 YAHOO_SERVICE_Y6_STATUS_UPDATE = 0xc6,
235 YAHOO_SERVICE_AUTH_REQ_15 = 0xd6,
236 YAHOO_SERVICE_STATUS_15 = 0xf0,
237 YAHOO_SERVICE_LIST_15 = 0xf1
240 struct yahoo_pair {
241 int key;
242 char *value;
245 struct yahoo_packet {
246 unsigned short int service;
247 unsigned int status;
248 unsigned int id;
249 YList *hash;
252 struct yahoo_search_state {
253 int lsearch_type;
254 char *lsearch_text;
255 int lsearch_gender;
256 int lsearch_agerange;
257 int lsearch_photo;
258 int lsearch_yahoo_only;
259 int lsearch_nstart;
260 int lsearch_nfound;
261 int lsearch_ntotal;
264 struct data_queue {
265 unsigned char *queue;
266 int len;
269 struct yahoo_input_data {
270 struct yahoo_data *yd;
271 struct yahoo_webcam *wcm;
272 struct yahoo_webcam_data *wcd;
273 struct yahoo_search_state *ys;
275 int fd;
276 enum yahoo_connection_type type;
278 unsigned char *rxqueue;
279 int rxlen;
280 int read_tag;
282 YList *txqueues;
283 int write_tag;
286 struct yahoo_server_settings {
287 char *pager_host;
288 int pager_port;
289 char *filetransfer_host;
290 int filetransfer_port;
291 char *webcam_host;
292 int webcam_port;
293 char *webcam_description;
294 char *local_host;
295 int conn_type;
298 struct yahoo_add_request {
299 char *id;
300 char *who;
301 int protocol;
304 static void * _yahoo_default_server_settings()
306 struct yahoo_server_settings *yss = y_new0(struct yahoo_server_settings, 1);
308 yss->pager_host = strdup(pager_host);
309 yss->pager_port = pager_port;
310 yss->filetransfer_host = strdup(filetransfer_host);
311 yss->filetransfer_port = filetransfer_port;
312 yss->webcam_host = strdup(webcam_host);
313 yss->webcam_port = webcam_port;
314 yss->webcam_description = strdup(webcam_description);
315 yss->local_host = strdup(local_host);
316 yss->conn_type = conn_type;
318 return yss;
321 static void * _yahoo_assign_server_settings(va_list ap)
323 struct yahoo_server_settings *yss = _yahoo_default_server_settings();
324 char *key;
325 char *svalue;
326 int nvalue;
328 while(1) {
329 key = va_arg(ap, char *);
330 if(key == NULL)
331 break;
333 if(!strcmp(key, "pager_host")) {
334 svalue = va_arg(ap, char *);
335 free(yss->pager_host);
336 yss->pager_host = strdup(svalue);
337 } else if(!strcmp(key, "pager_port")) {
338 nvalue = va_arg(ap, int);
339 yss->pager_port = nvalue;
340 } else if(!strcmp(key, "filetransfer_host")) {
341 svalue = va_arg(ap, char *);
342 free(yss->filetransfer_host);
343 yss->filetransfer_host = strdup(svalue);
344 } else if(!strcmp(key, "filetransfer_port")) {
345 nvalue = va_arg(ap, int);
346 yss->filetransfer_port = nvalue;
347 } else if(!strcmp(key, "webcam_host")) {
348 svalue = va_arg(ap, char *);
349 free(yss->webcam_host);
350 yss->webcam_host = strdup(svalue);
351 } else if(!strcmp(key, "webcam_port")) {
352 nvalue = va_arg(ap, int);
353 yss->webcam_port = nvalue;
354 } else if(!strcmp(key, "webcam_description")) {
355 svalue = va_arg(ap, char *);
356 free(yss->webcam_description);
357 yss->webcam_description = strdup(svalue);
358 } else if(!strcmp(key, "local_host")) {
359 svalue = va_arg(ap, char *);
360 free(yss->local_host);
361 yss->local_host = strdup(svalue);
362 } else if(!strcmp(key, "conn_type")) {
363 nvalue = va_arg(ap, int);
364 yss->conn_type = nvalue;
365 } else {
366 WARNING(("Unknown key passed to yahoo_init, "
367 "perhaps you didn't terminate the list "
368 "with NULL"));
372 return yss;
375 static void yahoo_free_server_settings(struct yahoo_server_settings *yss)
377 if(!yss)
378 return;
380 free(yss->pager_host);
381 free(yss->filetransfer_host);
382 free(yss->webcam_host);
383 free(yss->webcam_description);
384 free(yss->local_host);
386 free(yss);
389 static YList *conns=NULL;
390 static YList *inputs=NULL;
391 static int last_id=0;
393 static void add_to_list(struct yahoo_data *yd)
395 conns = y_list_prepend(conns, yd);
397 static struct yahoo_data * find_conn_by_id(int id)
399 YList *l;
400 for(l = conns; l; l = y_list_next(l)) {
401 struct yahoo_data *yd = l->data;
402 if(yd->client_id == id)
403 return yd;
405 return NULL;
407 static void del_from_list(struct yahoo_data *yd)
409 conns = y_list_remove(conns, yd);
412 /* call repeatedly to get the next one */
414 static struct yahoo_input_data * find_input_by_id(int id)
416 YList *l;
417 for(l = inputs; l; l = y_list_next(l)) {
418 struct yahoo_input_data *yid = l->data;
419 if(yid->yd->client_id == id)
420 return yid;
422 return NULL;
426 static struct yahoo_input_data * find_input_by_id_and_webcam_user(int id, const char * who)
428 YList *l;
429 LOG(("find_input_by_id_and_webcam_user"));
430 for(l = inputs; l; l = y_list_next(l)) {
431 struct yahoo_input_data *yid = l->data;
432 if(yid->type == YAHOO_CONNECTION_WEBCAM && yid->yd->client_id == id
433 && yid->wcm &&
434 ((who && yid->wcm->user && !strcmp(who, yid->wcm->user)) ||
435 !(yid->wcm->user && !who)))
436 return yid;
438 return NULL;
441 static struct yahoo_input_data * find_input_by_id_and_type(int id, enum yahoo_connection_type type)
443 YList *l;
444 LOG(("find_input_by_id_and_type"));
445 for(l = inputs; l; l = y_list_next(l)) {
446 struct yahoo_input_data *yid = l->data;
447 if(yid->type == type && yid->yd->client_id == id)
448 return yid;
450 return NULL;
453 static struct yahoo_input_data * find_input_by_id_and_fd(int id, int fd)
455 YList *l;
456 LOG(("find_input_by_id_and_fd"));
457 for(l = inputs; l; l = y_list_next(l)) {
458 struct yahoo_input_data *yid = l->data;
459 if(yid->fd == fd && yid->yd->client_id == id)
460 return yid;
462 return NULL;
465 static int count_inputs_with_id(int id)
467 int c=0;
468 YList *l;
469 LOG(("counting %d", id));
470 for(l = inputs; l; l = y_list_next(l)) {
471 struct yahoo_input_data *yid = l->data;
472 if(yid->yd->client_id == id)
473 c++;
475 LOG(("%d", c));
476 return c;
480 extern char *yahoo_crypt(char *, char *);
482 /* Free a buddy list */
483 static void yahoo_free_buddies(YList * list)
485 YList *l;
487 for(l = list; l; l = l->next)
489 struct yahoo_buddy *bud = l->data;
490 if(!bud)
491 continue;
493 FREE(bud->group);
494 FREE(bud->id);
495 FREE(bud->real_name);
496 if(bud->yab_entry) {
497 FREE(bud->yab_entry->fname);
498 FREE(bud->yab_entry->lname);
499 FREE(bud->yab_entry->nname);
500 FREE(bud->yab_entry->id);
501 FREE(bud->yab_entry->email);
502 FREE(bud->yab_entry->hphone);
503 FREE(bud->yab_entry->wphone);
504 FREE(bud->yab_entry->mphone);
505 FREE(bud->yab_entry);
507 FREE(bud);
508 l->data = bud = NULL;
511 y_list_free(list);
514 /* Free an identities list */
515 static void yahoo_free_identities(YList * list)
517 while (list) {
518 YList *n = list;
519 FREE(list->data);
520 list = y_list_remove_link(list, list);
521 y_list_free_1(n);
525 /* Free webcam data */
526 static void yahoo_free_webcam(struct yahoo_webcam *wcm)
528 if (wcm) {
529 FREE(wcm->user);
530 FREE(wcm->server);
531 FREE(wcm->key);
532 FREE(wcm->description);
533 FREE(wcm->my_ip);
535 FREE(wcm);
538 static void yahoo_free_data(struct yahoo_data *yd)
540 FREE(yd->user);
541 FREE(yd->password);
542 FREE(yd->cookie_y);
543 FREE(yd->cookie_t);
544 FREE(yd->cookie_c);
545 FREE(yd->login_cookie);
546 FREE(yd->login_id);
548 yahoo_free_buddies(yd->buddies);
549 yahoo_free_buddies(yd->ignore);
550 yahoo_free_identities(yd->identities);
552 yahoo_free_server_settings(yd->server_settings);
554 FREE(yd);
557 #define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4)
559 static struct yahoo_packet *yahoo_packet_new(enum yahoo_service service,
560 enum yahoo_status status, int id)
562 struct yahoo_packet *pkt = y_new0(struct yahoo_packet, 1);
564 pkt->service = service;
565 pkt->status = status;
566 pkt->id = id;
568 return pkt;
571 static void yahoo_packet_hash(struct yahoo_packet *pkt, int key, const char *value)
573 struct yahoo_pair *pair = y_new0(struct yahoo_pair, 1);
574 pair->key = key;
575 pair->value = strdup(value);
576 pkt->hash = y_list_append(pkt->hash, pair);
579 static int yahoo_packet_length(struct yahoo_packet *pkt)
581 YList *l;
583 int len = 0;
585 for (l = pkt->hash; l; l = l->next) {
586 struct yahoo_pair *pair = l->data;
587 int tmp = pair->key;
588 do {
589 tmp /= 10;
590 len++;
591 } while (tmp);
592 len += 2;
593 len += strlen(pair->value);
594 len += 2;
597 return len;
600 #define yahoo_put16(buf, data) ( \
601 (*(buf) = (unsigned char)((data)>>8)&0xff), \
602 (*((buf)+1) = (unsigned char)(data)&0xff), \
604 #define yahoo_get16(buf) ((((*(buf))&0xff)<<8) + ((*((buf)+1)) & 0xff))
605 #define yahoo_put32(buf, data) ( \
606 (*((buf)) = (unsigned char)((data)>>24)&0xff), \
607 (*((buf)+1) = (unsigned char)((data)>>16)&0xff), \
608 (*((buf)+2) = (unsigned char)((data)>>8)&0xff), \
609 (*((buf)+3) = (unsigned char)(data)&0xff), \
611 #define yahoo_get32(buf) ((((*(buf) )&0xff)<<24) + \
612 (((*((buf)+1))&0xff)<<16) + \
613 (((*((buf)+2))&0xff)<< 8) + \
614 (((*((buf)+3))&0xff)))
616 static void yahoo_packet_read(struct yahoo_packet *pkt, unsigned char *data, int len)
618 int pos = 0;
620 while (pos + 1 < len) {
621 char *key, *value = NULL;
622 int accept;
623 int x;
625 struct yahoo_pair *pair = y_new0(struct yahoo_pair, 1);
627 key = malloc(len + 1);
628 x = 0;
629 while (pos + 1 < len) {
630 if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
631 break;
632 key[x++] = data[pos++];
634 key[x] = 0;
635 pos += 2;
636 pair->key = strtol(key, NULL, 10);
637 free(key);
639 accept = x;
640 /* if x is 0 there was no key, so don't accept it */
641 if (accept)
642 value = malloc(len - pos + 2);
643 x = 0;
644 while (pos + 1 < len) {
645 if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
646 break;
647 if (accept)
648 value[x++] = data[pos++];
650 if (accept)
651 value[x] = 0;
652 pos += 2;
653 if (accept) {
654 pair->value = strdup(value);
655 FREE(value);
656 pkt->hash = y_list_append(pkt->hash, pair);
657 DEBUG_MSG(("Key: %d \tValue: %s", pair->key, pair->value));
658 } else {
659 FREE(pair);
664 static void yahoo_packet_write(struct yahoo_packet *pkt, unsigned char *data)
666 YList *l;
667 int pos = 0;
669 for (l = pkt->hash; l; l = l->next) {
670 struct yahoo_pair *pair = l->data;
671 unsigned char buf[100];
673 snprintf((char *)buf, sizeof(buf), "%d", pair->key);
674 strcpy((char *)data + pos, (char *)buf);
675 pos += strlen((char *)buf);
676 data[pos++] = 0xc0;
677 data[pos++] = 0x80;
679 strcpy((char *)data + pos, pair->value);
680 pos += strlen(pair->value);
681 data[pos++] = 0xc0;
682 data[pos++] = 0x80;
686 static void yahoo_dump_unhandled(struct yahoo_packet *pkt)
688 YList *l;
690 NOTICE(("Service: 0x%02x\tStatus: %d", pkt->service, pkt->status));
691 for (l = pkt->hash; l; l = l->next) {
692 struct yahoo_pair *pair = l->data;
693 NOTICE(("\t%d => %s", pair->key, pair->value));
698 static void yahoo_packet_dump(unsigned char *data, int len)
700 if(yahoo_get_log_level() >= YAHOO_LOG_DEBUG) {
701 int i;
702 for (i = 0; i < len; i++) {
703 if ((i % 8 == 0) && i)
704 YAHOO_CALLBACK(ext_yahoo_log)(" ");
705 if ((i % 16 == 0) && i)
706 YAHOO_CALLBACK(ext_yahoo_log)("\n");
707 YAHOO_CALLBACK(ext_yahoo_log)("%02x ", data[i]);
709 YAHOO_CALLBACK(ext_yahoo_log)("\n");
710 for (i = 0; i < len; i++) {
711 if ((i % 8 == 0) && i)
712 YAHOO_CALLBACK(ext_yahoo_log)(" ");
713 if ((i % 16 == 0) && i)
714 YAHOO_CALLBACK(ext_yahoo_log)("\n");
715 if (isprint(data[i]))
716 YAHOO_CALLBACK(ext_yahoo_log)(" %c ", data[i]);
717 else
718 YAHOO_CALLBACK(ext_yahoo_log)(" . ");
720 YAHOO_CALLBACK(ext_yahoo_log)("\n");
724 static char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
725 "abcdefghijklmnopqrstuvwxyz"
726 "0123456789._";
727 static void to_y64(unsigned char *out, const unsigned char *in, int inlen)
728 /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
730 for (; inlen >= 3; inlen -= 3)
732 *out++ = base64digits[in[0] >> 2];
733 *out++ = base64digits[((in[0]<<4) & 0x30) | (in[1]>>4)];
734 *out++ = base64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)];
735 *out++ = base64digits[in[2] & 0x3f];
736 in += 3;
738 if (inlen > 0)
740 unsigned char fragment;
742 *out++ = base64digits[in[0] >> 2];
743 fragment = (in[0] << 4) & 0x30;
744 if (inlen > 1)
745 fragment |= in[1] >> 4;
746 *out++ = base64digits[fragment];
747 *out++ = (inlen < 2) ? '-'
748 : base64digits[(in[1] << 2) & 0x3c];
749 *out++ = '-';
751 *out = '\0';
754 static void yahoo_add_to_send_queue(struct yahoo_input_data *yid, void *data, int length)
756 struct data_queue *tx = y_new0(struct data_queue, 1);
757 tx->queue = y_new0(unsigned char, length);
758 tx->len = length;
759 memcpy(tx->queue, data, length);
761 yid->txqueues = y_list_append(yid->txqueues, tx);
763 if(!yid->write_tag)
764 yid->write_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_WRITE, yid);
767 static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet *pkt, int extra_pad)
769 int pktlen = yahoo_packet_length(pkt);
770 int len = YAHOO_PACKET_HDRLEN + pktlen;
772 unsigned char *data;
773 int pos = 0;
775 if (yid->fd < 0)
776 return;
778 data = y_new0(unsigned char, len + 1);
780 memcpy(data + pos, "YMSG", 4); pos += 4;
781 pos += yahoo_put16(data + pos, 0x000f);
782 pos += yahoo_put16(data + pos, 0x0000);
783 pos += yahoo_put16(data + pos, pktlen + extra_pad);
784 pos += yahoo_put16(data + pos, pkt->service);
785 pos += yahoo_put32(data + pos, pkt->status);
786 pos += yahoo_put32(data + pos, pkt->id);
788 yahoo_packet_write(pkt, data + pos);
790 yahoo_packet_dump(data, len);
792 if( yid->type == YAHOO_CONNECTION_FT )
793 yahoo_send_data(yid->fd, data, len);
794 else
795 yahoo_add_to_send_queue(yid, data, len);
796 FREE(data);
799 static void yahoo_packet_free(struct yahoo_packet *pkt)
801 while (pkt->hash) {
802 struct yahoo_pair *pair = pkt->hash->data;
803 YList *tmp;
804 FREE(pair->value);
805 FREE(pair);
806 tmp = pkt->hash;
807 pkt->hash = y_list_remove_link(pkt->hash, pkt->hash);
808 y_list_free_1(tmp);
810 FREE(pkt);
813 static int yahoo_send_data(int fd, void *data, int len)
815 int ret;
816 int e;
818 if (fd < 0)
819 return -1;
821 yahoo_packet_dump(data, len);
823 do {
824 ret = write(fd, data, len);
825 } while(ret == -1 && errno==EINTR);
826 e=errno;
828 if (ret == -1) {
829 LOG(("wrote data: ERR %s", strerror(errno)));
830 } else {
831 LOG(("wrote data: OK"));
834 errno=e;
835 return ret;
838 void yahoo_close(int id)
840 struct yahoo_data *yd = find_conn_by_id(id);
841 if(!yd)
842 return;
844 del_from_list(yd);
846 yahoo_free_data(yd);
847 if(id == last_id)
848 last_id--;
851 static void yahoo_input_close(struct yahoo_input_data *yid)
853 inputs = y_list_remove(inputs, yid);
855 LOG(("yahoo_input_close(read)"));
856 YAHOO_CALLBACK(ext_yahoo_remove_handler)(yid->yd->client_id, yid->read_tag);
857 LOG(("yahoo_input_close(write)"));
858 YAHOO_CALLBACK(ext_yahoo_remove_handler)(yid->yd->client_id, yid->write_tag);
859 yid->read_tag = yid->write_tag = 0;
860 if(yid->fd)
861 close(yid->fd);
862 yid->fd = 0;
863 FREE(yid->rxqueue);
864 if(count_inputs_with_id(yid->yd->client_id) == 0) {
865 LOG(("closing %d", yid->yd->client_id));
866 yahoo_close(yid->yd->client_id);
868 yahoo_free_webcam(yid->wcm);
869 if(yid->wcd)
870 FREE(yid->wcd);
871 if(yid->ys) {
872 FREE(yid->ys->lsearch_text);
873 FREE(yid->ys);
875 FREE(yid);
878 static int is_same_bud(const void * a, const void * b) {
879 const struct yahoo_buddy *subject = a;
880 const struct yahoo_buddy *object = b;
882 return strcmp(subject->id, object->id);
885 static YList * bud_str2list(char *rawlist)
887 YList * l = NULL;
889 char **lines;
890 char **split;
891 char **buddies;
892 char **tmp, **bud;
894 lines = y_strsplit(rawlist, "\n", -1);
895 for (tmp = lines; *tmp; tmp++) {
896 struct yahoo_buddy *newbud;
898 split = y_strsplit(*tmp, ":", 2);
899 if (!split)
900 continue;
901 if (!split[0] || !split[1]) {
902 y_strfreev(split);
903 continue;
905 buddies = y_strsplit(split[1], ",", -1);
907 for (bud = buddies; bud && *bud; bud++) {
908 newbud = y_new0(struct yahoo_buddy, 1);
909 newbud->id = strdup(*bud);
910 newbud->group = strdup(split[0]);
912 if(y_list_find_custom(l, newbud, is_same_bud)) {
913 FREE(newbud->id);
914 FREE(newbud->group);
915 FREE(newbud);
916 continue;
919 newbud->real_name = NULL;
921 l = y_list_append(l, newbud);
923 NOTICE(("Added buddy %s to group %s", newbud->id, newbud->group));
926 y_strfreev(buddies);
927 y_strfreev(split);
929 y_strfreev(lines);
931 return l;
934 static char * getcookie(char *rawcookie)
936 char * cookie=NULL;
937 char * tmpcookie;
938 char * cookieend;
940 if (strlen(rawcookie) < 2)
941 return NULL;
943 tmpcookie = strdup(rawcookie+2);
944 cookieend = strchr(tmpcookie, ';');
946 if(cookieend)
947 *cookieend = '\0';
949 cookie = strdup(tmpcookie);
950 FREE(tmpcookie);
951 /* cookieend=NULL; not sure why this was there since the value is not preserved in the stack -dd */
953 return cookie;
956 static char * getlcookie(char *cookie)
958 char *tmp;
959 char *tmpend;
960 char *login_cookie = NULL;
962 tmpend = strstr(cookie, "n=");
963 if(tmpend) {
964 tmp = strdup(tmpend+2);
965 tmpend = strchr(tmp, '&');
966 if(tmpend)
967 *tmpend='\0';
968 login_cookie = strdup(tmp);
969 FREE(tmp);
972 return login_cookie;
975 static void yahoo_process_notify(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
977 struct yahoo_data *yd = yid->yd;
978 char *msg = NULL;
979 char *from = NULL;
980 char *to = NULL;
981 int stat = 0;
982 int accept = 0;
983 char *ind = NULL;
984 YList *l;
985 for (l = pkt->hash; l; l = l->next) {
986 struct yahoo_pair *pair = l->data;
987 if (pair->key == 4)
988 from = pair->value;
989 if (pair->key == 5)
990 to = pair->value;
991 if (pair->key == 49)
992 msg = pair->value;
993 if (pair->key == 13)
994 stat = atoi(pair->value);
995 if (pair->key == 14)
996 ind = pair->value;
997 if (pair->key == 16) { /* status == -1 */
998 NOTICE((pair->value));
999 return;
1004 if (!msg)
1005 return;
1007 if (!strncasecmp(msg, "TYPING", strlen("TYPING")))
1008 YAHOO_CALLBACK(ext_yahoo_typing_notify)(yd->client_id, to, from, stat);
1009 else if (!strncasecmp(msg, "GAME", strlen("GAME")))
1010 YAHOO_CALLBACK(ext_yahoo_game_notify)(yd->client_id, to, from, stat);
1011 else if (!strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE")))
1013 if (!strcmp(ind, " ")) {
1014 YAHOO_CALLBACK(ext_yahoo_webcam_invite)(yd->client_id, to, from);
1015 } else {
1016 accept = atoi(ind);
1017 /* accept the invitation (-1 = deny 1 = accept) */
1018 if (accept < 0)
1019 accept = 0;
1020 YAHOO_CALLBACK(ext_yahoo_webcam_invite_reply)(yd->client_id, to, from, accept);
1023 else
1024 LOG(("Got unknown notification: %s", msg));
1027 static void yahoo_process_filetransfer(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1029 struct yahoo_data *yd = yid->yd;
1030 char *from=NULL;
1031 char *to=NULL;
1032 char *msg=NULL;
1033 char *url=NULL;
1034 long expires=0;
1036 char *service=NULL;
1038 char *filename=NULL;
1039 unsigned long filesize=0L;
1041 YList *l;
1042 for (l = pkt->hash; l; l = l->next) {
1043 struct yahoo_pair *pair = l->data;
1044 if (pair->key == 4)
1045 from = pair->value;
1046 if (pair->key == 5)
1047 to = pair->value;
1048 if (pair->key == 14)
1049 msg = pair->value;
1050 if (pair->key == 20)
1051 url = pair->value;
1052 if (pair->key == 38)
1053 expires = atol(pair->value);
1055 if (pair->key == 27)
1056 filename = pair->value;
1057 if (pair->key == 28)
1058 filesize = atol(pair->value);
1060 if (pair->key == 49)
1061 service = pair->value;
1064 if(pkt->service == YAHOO_SERVICE_P2PFILEXFER) {
1065 if(strcmp("FILEXFER", service) != 0) {
1066 WARNING(("unhandled service 0x%02x", pkt->service));
1067 yahoo_dump_unhandled(pkt);
1068 return;
1072 if(msg) {
1073 char *tmp;
1074 tmp = strchr(msg, '\006');
1075 if(tmp)
1076 *tmp = '\0';
1078 if(url && from)
1079 YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, to, from, url, expires, msg, filename, filesize);
1083 static void yahoo_process_conference(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1085 struct yahoo_data *yd = yid->yd;
1086 char *msg = NULL;
1087 char *host = NULL;
1088 char *who = NULL;
1089 char *room = NULL;
1090 char *id = NULL;
1091 int utf8 = 0;
1092 YList *members = NULL;
1093 YList *l;
1095 for (l = pkt->hash; l; l = l->next) {
1096 struct yahoo_pair *pair = l->data;
1097 if (pair->key == 50)
1098 host = pair->value;
1100 if (pair->key == 52) { /* invite */
1101 members = y_list_append(members, strdup(pair->value));
1103 if (pair->key == 53) /* logon */
1104 who = pair->value;
1105 if (pair->key == 54) /* decline */
1106 who = pair->value;
1107 if (pair->key == 55) /* unavailable (status == 2) */
1108 who = pair->value;
1109 if (pair->key == 56) /* logoff */
1110 who = pair->value;
1112 if (pair->key == 57)
1113 room = pair->value;
1115 if (pair->key == 58) /* join message */
1116 msg = pair->value;
1117 if (pair->key == 14) /* decline/conf message */
1118 msg = pair->value;
1120 if (pair->key == 13)
1122 if (pair->key == 16) /* error */
1123 msg = pair->value;
1125 if (pair->key == 1) /* my id */
1126 id = pair->value;
1127 if (pair->key == 3) /* message sender */
1128 who = pair->value;
1130 if (pair->key == 97)
1131 utf8 = atoi(pair->value);
1134 if(!room)
1135 return;
1137 if(host) {
1138 for(l = members; l; l = l->next) {
1139 char * w = l->data;
1140 if(!strcmp(w, host))
1141 break;
1143 if(!l)
1144 members = y_list_append(members, strdup(host));
1146 /* invite, decline, join, left, message -> status == 1 */
1148 switch(pkt->service) {
1149 case YAHOO_SERVICE_CONFINVITE:
1150 if(pkt->status == 2)
1152 else if(members)
1153 YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, host, room, msg, members);
1154 else if(msg)
1155 YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, msg, 0, E_CONFNOTAVAIL);
1156 break;
1157 case YAHOO_SERVICE_CONFADDINVITE:
1158 if(pkt->status == 2)
1160 else
1161 YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, host, room, msg, members);
1162 break;
1163 case YAHOO_SERVICE_CONFDECLINE:
1164 if(who)
1165 YAHOO_CALLBACK(ext_yahoo_conf_userdecline)(yd->client_id, who, room, msg);
1166 break;
1167 case YAHOO_SERVICE_CONFLOGON:
1168 if(who)
1169 YAHOO_CALLBACK(ext_yahoo_conf_userjoin)(yd->client_id, who, room);
1170 break;
1171 case YAHOO_SERVICE_CONFLOGOFF:
1172 if(who)
1173 YAHOO_CALLBACK(ext_yahoo_conf_userleave)(yd->client_id, who, room);
1174 break;
1175 case YAHOO_SERVICE_CONFMSG:
1176 if(who)
1177 YAHOO_CALLBACK(ext_yahoo_conf_message)(yd->client_id, who, room, msg, utf8);
1178 break;
1182 static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1184 char *msg = NULL;
1185 char *who = NULL;
1186 char *room = NULL;
1187 char *topic = NULL;
1188 YList *members = NULL;
1189 struct yahoo_chat_member *currentmember = NULL;
1190 int msgtype = 1;
1191 int utf8 = 0;
1192 int firstjoin = 0;
1193 int membercount = 0;
1194 int chaterr=0;
1195 YList *l;
1197 yahoo_dump_unhandled(pkt);
1198 for (l = pkt->hash; l; l = l->next) {
1199 struct yahoo_pair *pair = l->data;
1201 if (pair->key == 104) {
1202 /* Room name */
1203 room = pair->value;
1206 if (pair->key == 105) {
1207 /* Room topic */
1208 topic = pair->value;
1211 if (pair->key == 108) {
1212 /* Number of members in this packet */
1213 membercount = atoi(pair->value);
1216 if (pair->key == 109) {
1217 /* message sender */
1218 who = pair->value;
1220 if (pkt->service == YAHOO_SERVICE_CHATJOIN) {
1221 currentmember = y_new0(struct yahoo_chat_member, 1);
1222 currentmember->id = strdup(pair->value);
1223 members = y_list_append(members, currentmember);
1227 if (pair->key == 110) {
1228 /* age */
1229 if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1230 currentmember->age = atoi(pair->value);
1233 if (pair->key == 113) {
1234 /* attribs */
1235 if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1236 currentmember->attribs = atoi(pair->value);
1239 if (pair->key == 141) {
1240 /* alias */
1241 if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1242 currentmember->alias = strdup(pair->value);
1245 if (pair->key == 142) {
1246 /* location */
1247 if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1248 currentmember->location = strdup(pair->value);
1252 if (pair->key == 130) {
1253 /* first join */
1254 firstjoin = 1;
1257 if (pair->key == 117) {
1258 /* message */
1259 msg = pair->value;
1262 if (pair->key == 124) {
1263 /* Message type */
1264 msgtype = atoi(pair->value);
1266 if (pair->key == 114) {
1267 /* message error not sure what all the pair values mean */
1268 /* but -1 means no session in room */
1269 chaterr= atoi(pair->value);
1273 if(!room) {
1274 if (pkt->service == YAHOO_SERVICE_CHATLOGOUT) { /* yahoo originated chat logout */
1275 YAHOO_CALLBACK(ext_yahoo_chat_yahoologout)(yid->yd->client_id);
1276 return ;
1278 if (pkt->service == YAHOO_SERVICE_COMMENT && chaterr) {
1279 YAHOO_CALLBACK(ext_yahoo_chat_yahooerror)(yid->yd->client_id);
1280 return;
1283 WARNING(("We didn't get a room name, ignoring packet"));
1284 return;
1287 switch(pkt->service) {
1288 case YAHOO_SERVICE_CHATJOIN:
1289 if(y_list_length(members) != membercount) {
1290 WARNING(("Count of members doesn't match No. of members we got"));
1292 if(firstjoin && members) {
1293 YAHOO_CALLBACK(ext_yahoo_chat_join)(yid->yd->client_id, room, topic, members, yid->fd);
1294 } else if(who) {
1295 if(y_list_length(members) != 1) {
1296 WARNING(("Got more than 1 member on a normal join"));
1298 /* this should only ever have one, but just in case */
1299 while(members) {
1300 YList *n = members->next;
1301 currentmember = members->data;
1302 YAHOO_CALLBACK(ext_yahoo_chat_userjoin)(yid->yd->client_id, room, currentmember);
1303 y_list_free_1(members);
1304 members=n;
1307 break;
1308 case YAHOO_SERVICE_CHATEXIT:
1309 if(who) {
1310 YAHOO_CALLBACK(ext_yahoo_chat_userleave)(yid->yd->client_id, room, who);
1312 break;
1313 case YAHOO_SERVICE_COMMENT:
1314 if(who) {
1315 YAHOO_CALLBACK(ext_yahoo_chat_message)(yid->yd->client_id, who, room, msg, msgtype, utf8);
1317 break;
1321 static void yahoo_process_message(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1323 struct yahoo_data *yd = yid->yd;
1324 YList *l;
1325 YList * messages = NULL;
1327 struct m {
1328 int i_31;
1329 int i_32;
1330 char *to;
1331 char *from;
1332 long tm;
1333 char *msg;
1334 int utf8;
1335 } *message = y_new0(struct m, 1);
1337 for (l = pkt->hash; l; l = l->next) {
1338 struct yahoo_pair *pair = l->data;
1339 if (pair->key == 1 || pair->key == 4)
1341 if(!message->from)
1342 message->from = pair->value;
1344 else if (pair->key == 5)
1345 message->to = pair->value;
1346 else if (pair->key == 15)
1347 message->tm = strtol(pair->value, NULL, 10);
1348 else if (pair->key == 97)
1349 message->utf8 = atoi(pair->value);
1350 /* user message */ /* sys message */
1351 else if (pair->key == 14 || pair->key == 16)
1352 message->msg = pair->value;
1353 else if (pair->key == 31) {
1354 if(message->i_31) {
1355 messages = y_list_append(messages, message);
1356 message = y_new0(struct m, 1);
1358 message->i_31 = atoi(pair->value);
1360 else if (pair->key == 32)
1361 message->i_32 = atoi(pair->value);
1362 else
1363 LOG(("yahoo_process_message: status: %d, key: %d, value: %s",
1364 pkt->status, pair->key, pair->value));
1367 messages = y_list_append(messages, message);
1369 for (l = messages; l; l=l->next) {
1370 message = l->data;
1371 if (pkt->service == YAHOO_SERVICE_SYSMESSAGE) {
1372 YAHOO_CALLBACK(ext_yahoo_system_message)(yd->client_id, message->msg);
1373 } else if (pkt->status <= 2 || pkt->status == 5) {
1374 YAHOO_CALLBACK(ext_yahoo_got_im)(yd->client_id, message->to, message->from, message->msg, message->tm, pkt->status, message->utf8);
1375 } else if (pkt->status == 0xffffffff) {
1376 YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, message->msg, 0, E_SYSTEM);
1378 free(message);
1381 y_list_free(messages);
1385 static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1387 YList *l;
1388 struct yahoo_data *yd = yid->yd;
1390 struct user
1392 char *name; /* 7 name */
1393 int state; /* 10 state */
1394 int flags; /* 13 flags, bit 0 = pager, bit 1 = chat, bit 2 = game */
1395 int mobile; /* 60 mobile */
1396 char *msg; /* 19 custom status message */
1397 int away; /* 47 away (or invisible)*/
1398 int buddy_session; /* 11 state */
1399 int f17; /* 17 in chat? then what about flags? */
1400 int idle; /* 137 seconds idle */
1401 int f138; /* 138 state */
1402 char *f184; /* 184 state */
1403 int f192; /* 192 state */
1404 int f10001; /* 10001 state */
1405 int f10002; /* 10002 state */
1406 int f198; /* 198 state */
1407 char *f197; /* 197 state */
1408 char *f205; /* 205 state */
1409 int f213; /* 213 state */
1410 } *u;
1412 YList *users = 0;
1414 if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
1415 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_DUPL, NULL);
1416 return;
1419 for (l = pkt->hash; l; l = l->next) {
1420 struct yahoo_pair *pair = l->data;
1422 switch (pair->key) {
1423 case 0: /* we won't actually do anything with this */
1424 NOTICE(("key %d:%s", pair->key, pair->value));
1425 break;
1426 case 1: /* we don't get the full buddy list here. */
1427 if (!yd->logged_in) {
1428 yd->logged_in = TRUE;
1429 if(yd->current_status < 0)
1430 yd->current_status = yd->initial_status;
1431 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
1433 break;
1434 case 8: /* how many online buddies we have */
1435 NOTICE(("key %d:%s", pair->key, pair->value));
1436 break;
1437 case 7: /* the current buddy */
1438 u = y_new0(struct user, 1);
1439 u->name = pair->value;
1440 users = y_list_prepend(users, u);
1441 break;
1442 case 10: /* state */
1443 if (users)
1444 ((struct user*)users->data)->state = strtol(pair->value, NULL, 10);
1445 break;
1446 case 19: /* custom status message */
1447 if (users)
1448 ((struct user*)users->data)->msg = pair->value;
1449 break;
1450 case 47: /* is it an away message or not */
1451 if (users)
1452 ((struct user*)users->data)->away = atoi(pair->value);
1453 break;
1454 case 137: /* seconds idle */
1455 if (users)
1456 ((struct user*)users->data)->idle = atoi(pair->value);
1457 break;
1458 case 11: /* this is the buddy's session id */
1459 if (users)
1460 ((struct user*)users->data)->buddy_session = atoi(pair->value);
1461 break;
1462 case 17: /* in chat? */
1463 if (users)
1464 ((struct user*)users->data)->f17 = atoi(pair->value);
1465 break;
1466 case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
1467 if (users)
1468 ((struct user*)users->data)->flags = atoi(pair->value);
1469 break;
1470 case 60: /* SMS -> 1 MOBILE USER */
1471 /* sometimes going offline makes this 2, but invisible never sends it */
1472 if (users)
1473 ((struct user*)users->data)->mobile = atoi(pair->value);
1474 break;
1475 case 138:
1476 if (users)
1477 ((struct user*)users->data)->f138 = atoi(pair->value);
1478 break;
1479 case 184:
1480 if (users)
1481 ((struct user*)users->data)->f184 = pair->value;
1482 break;
1483 case 192:
1484 if (users)
1485 ((struct user*)users->data)->f192 = atoi(pair->value);
1486 break;
1487 case 10001:
1488 if (users)
1489 ((struct user*)users->data)->f10001 = atoi(pair->value);
1490 break;
1491 case 10002:
1492 if (users)
1493 ((struct user*)users->data)->f10002 = atoi(pair->value);
1494 break;
1495 case 198:
1496 if (users)
1497 ((struct user*)users->data)->f198 = atoi(pair->value);
1498 break;
1499 case 197:
1500 if (users)
1501 ((struct user*)users->data)->f197 = pair->value;
1502 break;
1503 case 205:
1504 if (users)
1505 ((struct user*)users->data)->f205 = pair->value;
1506 break;
1507 case 213:
1508 if (users)
1509 ((struct user*)users->data)->f213 = atoi(pair->value);
1510 break;
1511 case 16: /* Custom error message */
1512 YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0, E_CUSTOM);
1513 break;
1514 default:
1515 WARNING(("unknown status key %d:%s", pair->key, pair->value));
1516 break;
1520 while (users) {
1521 YList *t = users;
1522 struct user *u = users->data;
1524 if (u->name != NULL) {
1525 if (pkt->service == YAHOO_SERVICE_LOGOFF || u->flags == 0) {
1526 YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0);
1527 } else {
1528 YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, u->state, u->msg, u->away, u->idle, u->mobile);
1532 users = y_list_remove_link(users, users);
1533 y_list_free_1(t);
1534 FREE(u);
1538 static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1540 struct yahoo_data *yd = yid->yd;
1541 YList *l;
1543 if (!yd->logged_in) {
1544 struct yahoo_packet *pkt2;
1545 char buff[20];
1546 yd->logged_in = TRUE;
1547 if(yd->current_status < 0)
1548 yd->current_status = yd->initial_status;
1549 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
1551 pkt2 = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, 0);
1553 snprintf(buff, sizeof(buff)-1, "%d", yd->current_status);
1554 yahoo_packet_hash(pkt2, 10, buff);
1555 yahoo_packet_hash(pkt2, 19, "");
1556 yahoo_send_packet(yid, pkt2, 0);
1558 yahoo_packet_free(pkt2);
1561 for (l = pkt->hash; l; l = l->next) {
1562 struct yahoo_pair *pair = l->data;
1564 switch(pair->key) {
1565 case 87: /* buddies */
1566 if(!yd->rawbuddylist)
1567 yd->rawbuddylist = strdup(pair->value);
1568 else {
1569 yd->rawbuddylist = y_string_append(yd->rawbuddylist, pair->value);
1571 break;
1573 case 88: /* ignore list */
1574 if(!yd->ignorelist)
1575 yd->ignorelist = strdup("Ignore:");
1576 yd->ignorelist = y_string_append(yd->ignorelist, pair->value);
1577 break;
1579 case 89: /* identities */
1581 char **identities = y_strsplit(pair->value, ",", -1);
1582 int i;
1583 for(i=0; identities[i]; i++)
1584 yd->identities = y_list_append(yd->identities,
1585 strdup(identities[i]));
1586 y_strfreev(identities);
1588 YAHOO_CALLBACK(ext_yahoo_got_identities)(yd->client_id, yd->identities);
1589 break;
1590 case 59: /* cookies */
1591 if(yd->ignorelist) {
1592 yd->ignore = bud_str2list(yd->ignorelist);
1593 FREE(yd->ignorelist);
1594 YAHOO_CALLBACK(ext_yahoo_got_ignore)(yd->client_id, yd->ignore);
1596 if(yd->rawbuddylist) {
1597 yd->buddies = bud_str2list(yd->rawbuddylist);
1598 FREE(yd->rawbuddylist);
1599 YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
1602 if(pair->value[0]=='Y') {
1603 FREE(yd->cookie_y);
1604 FREE(yd->login_cookie);
1606 yd->cookie_y = getcookie(pair->value);
1607 yd->login_cookie = getlcookie(yd->cookie_y);
1609 } else if(pair->value[0]=='T') {
1610 FREE(yd->cookie_t);
1611 yd->cookie_t = getcookie(pair->value);
1613 } else if(pair->value[0]=='C') {
1614 FREE(yd->cookie_c);
1615 yd->cookie_c = getcookie(pair->value);
1618 if(yd->cookie_y && yd->cookie_t && yd->cookie_c)
1619 YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id);
1621 break;
1622 case 3: /* my id */
1623 case 90: /* 1 */
1624 case 100: /* 0 */
1625 case 101: /* NULL */
1626 case 102: /* NULL */
1627 case 93: /* 86400/1440 */
1628 break;
1634 static void yahoo_process_list_15(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1636 YList *l;
1637 struct yahoo_data *yd = yid->yd;
1639 char *grp = 0, *bud = 0;
1641 l = pkt->hash;
1642 while (l) {
1643 struct yahoo_pair *pair = l->data;
1645 switch (pair->key) {
1646 case 302:
1647 /* This is always 318 before a group, 319 before the first s/n in a group, 320 before any ignored s/n.
1648 * It is not sent for s/n's in a group after the first.
1649 * All ignored s/n's are listed last, so when we see a 320 we clear the group and begin marking the
1650 * s/n's as ignored. It is always followed by an identical 300 key.
1652 if (pair->value && !strcmp(pair->value, "320")) {
1653 /* No longer in any group; this indicates the start of the ignore list. */
1654 l = NULL;
1656 break;
1658 case 65: /* This is the group */
1659 FREE(grp);
1660 grp = strdup(pair->value);
1661 break;
1663 case 7: /* buddy's s/n */
1664 bud = strdup(pair->value);
1666 if (grp) {
1668 /* This buddy is in a group */
1669 struct yahoo_buddy *buddy = y_new0(struct yahoo_buddy, 1);
1670 buddy->id = strdup(bud);
1671 buddy->group = strdup(grp);
1672 buddy->real_name = 0;
1673 buddy->yab_entry = 0;
1674 yd->buddies = y_list_append(yd->buddies, buddy);
1675 } else {
1676 /* This buddy is on the ignore list (and therefore in no group) */
1677 //purple_privacy_deny_add(account, norm_bud, 1);
1679 FREE(bud);
1680 break;
1682 if (l)
1683 l = l->next;
1685 FREE(grp);
1686 YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
1689 static void yahoo_process_auth_15(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1691 YList *l;
1692 struct yahoo_data *yd = yid->yd;
1693 const char *msg = NULL;
1695 if (pkt->status == 1) {
1696 const char *who = NULL;
1697 int response = 0;
1698 l = pkt->hash;
1700 while (l) {
1701 struct yahoo_pair *pair = l->data;
1703 switch (pair->key) {
1704 case 4:
1705 who = pair->value;
1706 break;
1707 case 13:
1708 response = strtol(pair->value, NULL, 10);
1709 break;
1710 case 14:
1711 msg = pair->value;
1712 break;
1714 l = l->next;
1717 if (response == 1) {/* Authorized */
1718 NOTICE(("Received authorization from buddy '%s'.\n", who ? who : "(Unknown Buddy)"));
1719 YAHOO_CALLBACK(ext_yahoo_got_auth_response)(yd->client_id, who ? who : "(Unknown Buddy)", 1, NULL);
1721 else if (response == 2) { /* Declined */
1722 WARNING(("Received authorization decline from buddy '%s'.\n", who ? who : "(Unknown Buddy)"));
1723 YAHOO_CALLBACK(ext_yahoo_got_auth_response)(yd->client_id, who ? who : "(Unknown Buddy)", 0, msg);
1724 } else {
1725 WARNING(("Received unknown authorization response of %d from buddy '%s'.\n", response, who ? who : "(Unknown Buddy)"));
1728 /* Buddy requested authorization to add us. */
1729 else if (pkt->status == 3) {
1730 struct yahoo_add_request *add_req;
1731 const char *firstname = NULL, *lastname = NULL;
1733 l = pkt->hash;
1735 add_req = y_new0(struct yahoo_add_request, 1);
1737 while (l) {
1738 struct yahoo_pair *pair = l->data;
1740 switch (pair->key) {
1741 case 4:
1742 add_req->who = strdup(pair->value);
1743 break;
1744 case 5:
1745 add_req->id = strdup(pair->value);
1746 break;
1747 case 14:
1748 msg = pair->value;
1749 break;
1750 case 216:
1751 firstname = pair->value;
1752 break;
1753 case 241:
1754 add_req->protocol = strtol(pair->value, NULL, 10);
1755 break;
1756 case 254:
1757 lastname = pair->value;
1758 break;
1761 l = l->next;
1764 if (add_req->id && add_req->who) {
1765 char *alias = NULL, *dec_msg = NULL;
1767 /*if (msg)
1768 dec_msg = yahoo_string_decode(msg, FALSE);*/
1769 if (msg)
1770 dec_msg = strdup(msg);
1772 /*if (firstname && lastname)
1773 alias = g_strdup_printf("%s %s", firstname, lastname);
1774 else if (firstname)
1775 alias = g_strdup(firstname);
1776 else if (lastname)
1777 alias = g_strdup(lastname);*/
1779 YAHOO_CALLBACK(ext_yahoo_got_auth_request)(yd->client_id, add_req->who, dec_msg);
1780 FREE(alias);
1781 FREE(dec_msg);
1782 FREE(add_req->id);
1783 FREE(add_req->who);
1784 FREE(add_req);
1785 } else {
1786 FREE(add_req->id);
1787 FREE(add_req->who);
1788 FREE(add_req);
1790 } else {
1791 WARNING(("Received authorization of unknown status (%d).\n", pkt->status));
1795 static void yahoo_process_verify(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1797 struct yahoo_data *yd = yid->yd;
1799 if(pkt->status != 0x01) {
1800 DEBUG_MSG(("expected status: 0x01, got: %d", pkt->status));
1801 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOCK, "");
1802 return;
1805 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
1807 yahoo_packet_hash(pkt, 1, yd->user);
1808 yahoo_send_packet(yid, pkt, 0);
1810 yahoo_packet_free(pkt);
1814 static void yahoo_process_picture_checksum( struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1816 struct yahoo_data *yd = yid->yd;
1817 char *from;
1818 char *to;
1819 int checksum = 0;
1820 YList *l;
1822 for(l = pkt->hash; l; l = l->next)
1824 struct yahoo_pair *pair = l->data;
1826 switch(pair->key)
1828 case 1:
1829 case 4:
1830 from = pair->value;
1831 case 5:
1832 to = pair->value;
1833 break;
1834 case 212:
1835 break;
1836 case 192:
1837 checksum = atoi( pair->value );
1838 break;
1842 // YAHOO_CALLBACK(ext_yahoo_got_buddyicon_checksum)(yd->client_id,to,from,checksum);
1845 static void yahoo_process_picture(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1847 struct yahoo_data *yd = yid->yd;
1848 char *url;
1849 char *from;
1850 char *to;
1851 int status = 0;
1852 int checksum = 0;
1853 YList *l;
1855 return;
1857 for(l = pkt->hash; l; l = l->next)
1859 struct yahoo_pair *pair = l->data;
1861 switch(pair->key)
1863 case 1:
1864 case 4: /* sender */
1865 from = pair->value;
1866 break;
1867 case 5: /* we */
1868 to = pair->value;
1869 break;
1870 case 13: /* request / sending */
1871 status = atoi( pair->value );
1872 break;
1873 case 20: /* url */
1874 url = pair->value;
1875 break;
1876 case 192: /*checksum */
1877 checksum = atoi( pair->value );
1878 break;
1882 switch( status )
1884 case 1: /* this is a request, ignore for now */
1885 YAHOO_CALLBACK(ext_yahoo_got_buddyicon_request)(yd->client_id, to, from);
1886 break;
1887 case 2: /* this is cool - we get a picture :) */
1888 YAHOO_CALLBACK(ext_yahoo_got_buddyicon)(yd->client_id,to, from, url, checksum);
1889 break;
1893 static void yahoo_process_picture_upload(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1895 struct yahoo_data *yd = yid->yd;
1896 YList *l;
1897 char *url;
1899 return;
1901 if ( pkt->status != 1 )
1902 return; /* something went wrong */
1904 for(l = pkt->hash; l; l = l->next)
1906 struct yahoo_pair *pair = l->data;
1908 switch(pair->key)
1910 case 5: /* we */
1911 break;
1912 case 20: /* url */
1913 url = pair->value;
1914 break;
1915 case 27: /* local filename */
1916 break;
1917 case 38: /* time */
1918 break;
1922 YAHOO_CALLBACK(ext_yahoo_buddyicon_uploaded)(yd->client_id, url);
1925 static void yahoo_process_auth_pre_0x0b(struct yahoo_input_data *yid,
1926 const char *seed, const char *sn)
1928 struct yahoo_data *yd = yid->yd;
1930 /* So, Yahoo has stopped supporting its older clients in India, and
1931 * undoubtedly will soon do so in the rest of the world.
1933 * The new clients use this authentication method. I warn you in
1934 * advance, it's bizzare, convoluted, inordinately complicated.
1935 * It's also no more secure than crypt() was. The only purpose this
1936 * scheme could serve is to prevent third part clients from connecting
1937 * to their servers.
1939 * Sorry, Yahoo.
1942 struct yahoo_packet *pack;
1944 md5_byte_t result[16];
1945 md5_state_t ctx;
1946 char *crypt_result;
1947 unsigned char *password_hash = malloc(25);
1948 unsigned char *crypt_hash = malloc(25);
1949 unsigned char *hash_string_p = malloc(50 + strlen(sn));
1950 unsigned char *hash_string_c = malloc(50 + strlen(sn));
1952 char checksum;
1954 int sv;
1956 unsigned char *result6 = malloc(25);
1957 unsigned char *result96 = malloc(25);
1959 sv = seed[15];
1960 sv = (sv % 8) % 5;
1962 md5_init(&ctx);
1963 md5_append(&ctx, (md5_byte_t *)yd->password, strlen(yd->password));
1964 md5_finish(&ctx, result);
1965 to_y64(password_hash, result, 16);
1967 md5_init(&ctx);
1968 crypt_result = yahoo_crypt(yd->password, "$1$_2S43d5f$");
1969 md5_append(&ctx, (md5_byte_t *)crypt_result, strlen(crypt_result));
1970 md5_finish(&ctx, result);
1971 to_y64(crypt_hash, result, 16);
1972 free(crypt_result);
1974 switch (sv) {
1975 case 0:
1976 checksum = seed[seed[7] % 16];
1977 snprintf((char *)hash_string_p, strlen(sn) + 50,
1978 "%c%s%s%s", checksum, password_hash, yd->user, seed);
1979 snprintf((char *)hash_string_c, strlen(sn) + 50,
1980 "%c%s%s%s", checksum, crypt_hash, yd->user, seed);
1981 break;
1982 case 1:
1983 checksum = seed[seed[9] % 16];
1984 snprintf((char *)hash_string_p, strlen(sn) + 50,
1985 "%c%s%s%s", checksum, yd->user, seed, password_hash);
1986 snprintf((char *)hash_string_c, strlen(sn) + 50,
1987 "%c%s%s%s", checksum, yd->user, seed, crypt_hash);
1988 break;
1989 case 2:
1990 checksum = seed[seed[15] % 16];
1991 snprintf((char *)hash_string_p, strlen(sn) + 50,
1992 "%c%s%s%s", checksum, seed, password_hash, yd->user);
1993 snprintf((char *)hash_string_c, strlen(sn) + 50,
1994 "%c%s%s%s", checksum, seed, crypt_hash, yd->user);
1995 break;
1996 case 3:
1997 checksum = seed[seed[1] % 16];
1998 snprintf((char *)hash_string_p, strlen(sn) + 50,
1999 "%c%s%s%s", checksum, yd->user, password_hash, seed);
2000 snprintf((char *)hash_string_c, strlen(sn) + 50,
2001 "%c%s%s%s", checksum, yd->user, crypt_hash, seed);
2002 break;
2003 case 4:
2004 checksum = seed[seed[3] % 16];
2005 snprintf((char *)hash_string_p, strlen(sn) + 50,
2006 "%c%s%s%s", checksum, password_hash, seed, yd->user);
2007 snprintf((char *)hash_string_c, strlen(sn) + 50,
2008 "%c%s%s%s", checksum, crypt_hash, seed, yd->user);
2009 break;
2012 md5_init(&ctx);
2013 md5_append(&ctx, (md5_byte_t *)hash_string_p, strlen((char *)hash_string_p));
2014 md5_finish(&ctx, result);
2015 to_y64(result6, result, 16);
2017 md5_init(&ctx);
2018 md5_append(&ctx, (md5_byte_t *)hash_string_c, strlen((char *)hash_string_c));
2019 md5_finish(&ctx, result);
2020 to_y64(result96, result, 16);
2022 pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
2023 yahoo_packet_hash(pack, 0, yd->user);
2024 yahoo_packet_hash(pack, 6, (char *)result6);
2025 yahoo_packet_hash(pack, 96, (char *)result96);
2026 yahoo_packet_hash(pack, 1, yd->user);
2028 yahoo_send_packet(yid, pack, 0);
2030 FREE(result6);
2031 FREE(result96);
2032 FREE(password_hash);
2033 FREE(crypt_hash);
2034 FREE(hash_string_p);
2035 FREE(hash_string_c);
2037 yahoo_packet_free(pack);
2041 int split_lines(char *s, char *lines[], int max)
2043 int pos = 0;
2044 char *b = strdup(s);
2045 char *p = b;
2046 char *tok;
2048 while (p && (pos<max))
2050 tok = strsep(&p, "\r\n");
2051 if (strlen(tok) == 0)
2052 continue;
2053 lines[pos] = strdup(tok);
2054 pos++;
2057 free(b);
2058 return pos;
2062 * New new auth protocol
2064 static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn)
2066 CURL *curl;
2067 CURLcode ret;
2068 char url[150];
2069 struct yahoo_data *yd = yid->yd;
2070 LOG(("CURL init..."));
2071 curl = curl_easy_init();
2073 if (!curl) // CURL init failed
2075 WARNING(("Yahoo: curl init error"));
2076 return;
2078 LOG(("CURL inited"));
2080 snprintf(url, sizeof(url), "https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=&login=%s&passwd=%s&chal=%s",yd->user, yd->password, seed);
2081 curl_easy_setopt(curl, CURLOPT_URL, url);
2082 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &yahoo_handle_curl_write);
2083 free(curl_buffer);
2084 curl_buffer = NULL;
2086 LOG(("Downloading token"));
2087 ret = curl_easy_perform(curl);
2089 if (ret) // there was error
2091 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOGOFF, NULL);
2092 WARNING(("Yahoo: curl error %d", ret));
2093 curl_easy_cleanup(curl);
2094 return; // deallocate curl data buffer?
2097 if (!curl_buffer) // no data was read
2099 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOGOFF, NULL);
2100 WARNING(("Yahoo: no data read"));
2101 curl_easy_cleanup(curl);
2102 return;
2105 LOG(("Token downloaded"));
2106 char *lines[6];
2107 char *token = NULL;
2109 char *buff = malloc(curl_buffer_size + 1);
2110 memcpy(buff, curl_buffer, curl_buffer_size);
2111 buff[curl_buffer_size] = '\0';
2113 free(curl_buffer);
2114 curl_buffer = NULL;
2116 int n = split_lines(buff, lines, 6);
2117 int i;
2118 int ret_code = -1;
2120 if (n >= 2) // there's some error
2122 ret_code = strtol(lines[0], NULL, 10);
2123 token = strdup(lines[1]+6);
2125 else if (n == 1)
2127 ret_code = strtol(lines[0], NULL, 10);
2130 for (i=0;i<n;i++)
2131 free(lines[i]);
2133 if (ret_code) // error
2135 switch (ret_code)
2137 case 1212:
2138 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_PASSWD, NULL);
2139 break;
2140 case 1213:
2141 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOCK, "Yahoo! website. Too many failed logins.");
2142 break;
2143 case 1235:
2144 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_UNAME, NULL);
2145 break;
2146 case 1214:
2147 case 1236:
2148 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOCK, "Yahoo! website.");
2149 break;
2150 default:
2151 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOGOFF, NULL);
2153 WARNING(("Yahoo: wrong token response - %d (%d lines: '%s')", ret_code, n, buff));
2154 free(token);
2155 free(buff);
2156 curl_easy_cleanup(curl);
2157 return;
2159 free(buff);
2161 LOG(("Token parsed, downloading cookies"));
2162 snprintf(url, sizeof(url), "https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=&token=%s", token);
2163 free(token);
2164 curl_easy_setopt(curl, CURLOPT_URL, url);
2165 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &yahoo_handle_curl_write);
2167 ret = curl_easy_perform(curl);
2169 if (ret) // error with curl
2171 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOGOFF, NULL);
2172 WARNING(("Yahoo: curl error %d", ret));
2173 free(curl_buffer);
2174 curl_buffer = NULL;
2175 curl_easy_cleanup(curl);
2176 return;
2178 LOG(("Cookies downloaded"));
2179 buff = malloc(curl_buffer_size+1);
2180 memcpy(buff, curl_buffer, curl_buffer_size);
2181 buff[curl_buffer_size] = '\0';
2182 free(curl_buffer);
2183 curl_buffer = NULL;
2185 n = split_lines(buff, lines, 6);
2186 ret_code = -1;
2187 free(buff);
2189 char *crumb = NULL;
2191 yd->cookie_y = yd->cookie_t = NULL;
2193 if (n >= 5)
2195 ret_code = strtol(lines[0], NULL, 10);
2196 crumb = strdup(lines[1] + 6);
2197 yd->cookie_y = strdup(lines[2] + 2);
2198 yd->cookie_t = strdup(lines[3] + 2);
2200 else if (n == 1)
2202 ret_code = strtol(lines[0], NULL, 10);
2205 for (i=0;i<n;i++)
2206 free(lines[i]);
2208 if (ret_code)
2209 { // free yd?
2210 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOGOFF, NULL);
2211 WARNING(("Yahoo: wrong crumb response - %d", ret_code));
2212 free(crumb);
2213 free(yd->cookie_y);
2214 free(yd->cookie_t);
2215 yd->cookie_y = yd->cookie_t = NULL;
2216 curl_easy_cleanup(curl);
2217 return;
2219 char crypt[strlen(crumb) + strlen(seed) + 1];
2220 strcpy(crypt, crumb);
2221 strcat(crypt, seed);
2222 free(crumb);
2224 // MD5 happens here
2225 md5_byte_t result[16];
2226 md5_state_t ctx;
2227 char crypt_hash[30];
2228 LOG(("Computing MD5"));
2229 md5_init(&ctx);
2230 md5_append(&ctx, (md5_byte_t *)crypt, strlen(crypt));
2231 md5_finish(&ctx, result);
2232 to_y64(crypt_hash, result, 16);
2234 LOG(("Constructing packet"));
2235 struct yahoo_packet *pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
2236 yahoo_packet_hash(pack, 1, yd->user);
2237 yahoo_packet_hash(pack, 0, yd->user);
2238 yahoo_packet_hash(pack, 277, yd->cookie_y);
2239 yahoo_packet_hash(pack, 278, yd->cookie_t);
2240 yahoo_packet_hash(pack, 307, crypt_hash);
2241 yahoo_packet_hash(pack, 244, YAHOO_CLIENT_VERSION_ID);
2242 yahoo_packet_hash(pack, 2, yd->user);
2243 yahoo_packet_hash(pack, 2, "1");
2244 yahoo_packet_hash(pack, 135, YAHOO_CLIENT_VERSION);
2246 LOG(("Sending login packet"));
2247 yahoo_send_packet(yid, pack, 0);
2248 yahoo_packet_free(pack);
2249 LOG(("Auth 0x10 finished"));
2253 * New auth protocol cracked by Cerulean Studios and sent in to Gaim
2255 static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *seed, const char *sn)
2257 struct yahoo_packet *pack = NULL;
2258 struct yahoo_data *yd = yid->yd;
2260 md5_byte_t result[16];
2261 md5_state_t ctx;
2263 SHA1Context ctx1;
2264 SHA1Context ctx2;
2266 char *alphabet1 = "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ";
2267 char *alphabet2 = "F0E1D2C3B4A59687abcdefghijklmnop";
2269 char *challenge_lookup = "qzec2tb3um1olpar8whx4dfgijknsvy5";
2270 char *operand_lookup = "+|&%/*^-";
2271 char *delimit_lookup = ",;";
2273 unsigned char *password_hash = malloc(25);
2274 unsigned char *crypt_hash = malloc(25);
2275 char *crypt_result = NULL;
2277 unsigned char pass_hash_xor1[64];
2278 unsigned char pass_hash_xor2[64];
2279 unsigned char crypt_hash_xor1[64];
2280 unsigned char crypt_hash_xor2[64];
2281 char resp_6[100];
2282 char resp_96[100];
2284 unsigned char digest1[20];
2285 unsigned char digest2[20];
2286 unsigned char comparison_src[20];
2287 unsigned char magic_key_char[4];
2288 const char *magic_ptr;
2290 unsigned int magic[64];
2291 unsigned int magic_work=0;
2292 unsigned int magic_4 = 0;
2295 int x, y;
2296 int cnt = 0;
2297 int magic_cnt = 0;
2298 int magic_len;
2300 memset(password_hash, 0, 25);
2301 memset(crypt_hash, 0, 25);
2302 memset(&pass_hash_xor1, 0, 64);
2303 memset(&pass_hash_xor2, 0, 64);
2304 memset(&crypt_hash_xor1, 0, 64);
2305 memset(&crypt_hash_xor2, 0, 64);
2306 memset(&digest1, 0, 20);
2307 memset(&digest2, 0, 20);
2308 memset(&magic, 0, 64);
2309 memset(&resp_6, 0, 100);
2310 memset(&resp_96, 0, 100);
2311 memset(&magic_key_char, 0, 4);
2312 memset(&comparison_src, 0, 20);
2315 * Magic: Phase 1. Generate what seems to be a 30
2316 * byte value (could change if base64
2317 * ends up differently? I don't remember and I'm
2318 * tired, so use a 64 byte buffer.
2321 magic_ptr = seed;
2323 while (*magic_ptr != (int)NULL) {
2324 char *loc;
2326 /* Ignore parentheses. */
2328 if (*magic_ptr == '(' || *magic_ptr == ')') {
2329 magic_ptr++;
2330 continue;
2333 /* Characters and digits verify against
2334 the challenge lookup.
2337 if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) {
2338 loc = strchr(challenge_lookup, *magic_ptr);
2339 if (!loc) {
2340 /* This isn't good */
2341 //continue;
2344 /* Get offset into lookup table and lsh 3. */
2346 magic_work = loc - challenge_lookup;
2347 magic_work <<= 3;
2349 magic_ptr++;
2350 continue;
2351 } else {
2352 unsigned int local_store;
2354 loc = strchr(operand_lookup, *magic_ptr);
2355 if (!loc) {
2356 /* Also not good. */
2357 //continue;
2360 local_store = loc - operand_lookup;
2362 /* Oops; how did this happen? */
2363 if (magic_cnt >= 64)
2364 break;
2366 magic[magic_cnt++] = magic_work | local_store;
2367 magic_ptr++;
2368 continue;
2372 magic_len = magic_cnt;
2373 magic_cnt = 0;
2375 /* Magic: Phase 2. Take generated magic value and
2376 * sprinkle fairy dust on the values. */
2378 for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) {
2379 unsigned char byte1;
2380 unsigned char byte2;
2382 /* Bad. Abort. */
2383 if ((magic_cnt >= magic_len)) {
2384 WARNING(("magic_cnt(%d) magic_len(%d)", magic_cnt, magic_len))
2385 break;
2388 byte1 = magic[magic_cnt];
2389 byte2 = magic[magic_cnt+1];
2391 byte1 *= 0xcd;
2392 byte1 ^= byte2;
2394 magic[magic_cnt+1] = byte1;
2398 * Magic: Phase 3. This computes 20 bytes. The first 4 bytes are used as our magic
2399 * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key
2400 * plus 3 bytes. The 3 bytes are found by looping, and they represent the offsets
2401 * into particular functions we'll later call to potentially alter the magic key.
2403 * %-)
2406 magic_cnt = 1;
2407 x = 0;
2409 do {
2410 unsigned int bl = 0;
2411 unsigned int cl = magic[magic_cnt++];
2413 if (magic_cnt >= magic_len)
2414 break;
2416 if (cl > 0x7F) {
2417 if (cl < 0xe0)
2418 bl = cl = (cl & 0x1f) << 6;
2419 else {
2420 bl = magic[magic_cnt++];
2421 cl = (cl & 0x0f) << 6;
2422 bl = ((bl & 0x3f) + cl) << 6;
2425 cl = magic[magic_cnt++];
2426 bl = (cl & 0x3f) + bl;
2427 } else
2428 bl = cl;
2430 comparison_src[x++] = (bl & 0xff00) >> 8;
2431 comparison_src[x++] = bl & 0xff;
2432 } while (x < 20);
2434 /* First four bytes are magic key. */
2435 memcpy(&magic_key_char[0], comparison_src, 4);
2436 magic_4 = magic_key_char[0] | (magic_key_char[1] << 8) |
2437 (magic_key_char[2] << 16) | (magic_key_char[3] << 24);
2440 * Magic: Phase 4. Determine what function to use later by getting outside/inside
2441 * loop values until we match our previous buffer.
2443 for (x = 0; x < 65535; x++) {
2444 int leave = 0;
2446 for (y = 0; y < 5; y++) {
2447 unsigned char test[3];
2449 /* Calculate buffer. */
2450 test[0] = x;
2451 test[1] = x >> 8;
2452 test[2] = y;
2454 md5_init( &ctx );
2455 md5_append( &ctx, magic_key_char, 4 );
2456 md5_append( &ctx, test, 3 );
2457 md5_finish( &ctx, result );
2460 if( memcmp( comparison_src + 4, result, 16 ) == 0 ) {
2461 leave = 1;
2462 break;
2466 if (leave == 1)
2467 break;
2470 /* If y != 0, we need some help. */
2471 if (y != 0) {
2472 unsigned int updated_key;
2474 /* Update magic stuff.
2475 * Call it twice because Yahoo's encryption is super bad ass.
2477 updated_key = yahoo_auth_finalCountdown(magic_4, 0x60, y, x);
2478 updated_key = yahoo_auth_finalCountdown(updated_key, 0x60, y, x);
2480 magic_key_char[0] = updated_key & 0xff;
2481 magic_key_char[1] = (updated_key >> 8) & 0xff;
2482 magic_key_char[2] = (updated_key >> 16) & 0xff;
2483 magic_key_char[3] = (updated_key >> 24) & 0xff;
2486 /* Get password and crypt hashes as per usual. */
2487 md5_init(&ctx);
2488 md5_append(&ctx, (md5_byte_t *)yd->password, strlen(yd->password));
2489 md5_finish(&ctx, result);
2491 to_y64(password_hash, result, 16);
2493 crypt_result = yahoo_crypt(yd->password, "$1$_2S43d5f$");
2495 md5_init(&ctx);
2496 md5_append(&ctx, (md5_byte_t *)crypt_result, strlen(crypt_result));
2497 md5_finish(&ctx, result);
2498 to_y64(crypt_hash, result, 16);
2499 free(crypt_result);
2501 /* Our first authentication response is based off
2502 * of the password hash. */
2504 for (x = 0; x < (int)strlen((char *)password_hash); x++)
2505 pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36;
2507 if (cnt < 64)
2508 memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt);
2510 cnt = 0;
2512 for (x = 0; x < (int)strlen((char *)password_hash); x++)
2513 pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c;
2515 if (cnt < 64)
2516 memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt);
2518 SHA1Init(&ctx1);
2519 SHA1Init(&ctx2);
2521 /* The first context gets the password hash XORed
2522 * with 0x36 plus a magic value
2523 * which we previously extrapolated from our
2524 * challenge. */
2526 SHA1Update(&ctx1, pass_hash_xor1, 64);
2527 if (y >= 3)
2528 ctx1.totalLength = 0x1ff;
2529 SHA1Update(&ctx1, magic_key_char, 4);
2530 SHA1Final(&ctx1, digest1);
2532 /* The second context gets the password hash XORed
2533 * with 0x5c plus the SHA-1 digest
2534 * of the first context. */
2536 SHA1Update(&ctx2, pass_hash_xor2, 64);
2537 SHA1Update(&ctx2, digest1, 20);
2538 SHA1Final(&ctx2, digest2);
2540 /* Now that we have digest2, use it to fetch
2541 * characters from an alphabet to construct
2542 * our first authentication response. */
2544 for (x = 0; x < 20; x += 2) {
2545 unsigned int val = 0;
2546 unsigned int lookup = 0;
2548 char byte[6];
2550 memset(&byte, 0, 6);
2552 /* First two bytes of digest stuffed
2553 * together.
2556 val = digest2[x];
2557 val <<= 8;
2558 val += digest2[x+1];
2560 lookup = (val >> 0x0b);
2561 lookup &= 0x1f;
2562 if (lookup >= strlen(alphabet1))
2563 break;
2564 sprintf(byte, "%c", alphabet1[lookup]);
2565 strcat(resp_6, byte);
2566 strcat(resp_6, "=");
2568 lookup = (val >> 0x06);
2569 lookup &= 0x1f;
2570 if (lookup >= strlen(alphabet2))
2571 break;
2572 sprintf(byte, "%c", alphabet2[lookup]);
2573 strcat(resp_6, byte);
2575 lookup = (val >> 0x01);
2576 lookup &= 0x1f;
2577 if (lookup >= strlen(alphabet2))
2578 break;
2579 sprintf(byte, "%c", alphabet2[lookup]);
2580 strcat(resp_6, byte);
2582 lookup = (val & 0x01);
2583 if (lookup >= strlen(delimit_lookup))
2584 break;
2585 sprintf(byte, "%c", delimit_lookup[lookup]);
2586 strcat(resp_6, byte);
2589 /* Our second authentication response is based off
2590 * of the crypto hash. */
2592 cnt = 0;
2593 memset(&digest1, 0, 20);
2594 memset(&digest2, 0, 20);
2596 for (x = 0; x < (int)strlen((char *)crypt_hash); x++)
2597 crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36;
2599 if (cnt < 64)
2600 memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt);
2602 cnt = 0;
2604 for (x = 0; x < (int)strlen((char *)crypt_hash); x++)
2605 crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c;
2607 if (cnt < 64)
2608 memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt);
2610 SHA1Init(&ctx1);
2611 SHA1Init(&ctx2);
2613 /* The first context gets the password hash XORed
2614 * with 0x36 plus a magic value
2615 * which we previously extrapolated from our
2616 * challenge. */
2618 SHA1Update(&ctx1, crypt_hash_xor1, 64);
2619 if (y >= 3)
2620 ctx1.totalLength = 0x1ff;
2621 SHA1Update(&ctx1, magic_key_char, 4);
2622 SHA1Final(&ctx1, digest1);
2624 /* The second context gets the password hash XORed
2625 * with 0x5c plus the SHA-1 digest
2626 * of the first context. */
2628 SHA1Update(&ctx2, crypt_hash_xor2, 64);
2629 SHA1Update(&ctx2, digest1, 20);
2630 SHA1Final(&ctx2, digest2);
2632 /* Now that we have digest2, use it to fetch
2633 * characters from an alphabet to construct
2634 * our first authentication response. */
2636 for (x = 0; x < 20; x += 2) {
2637 unsigned int val = 0;
2638 unsigned int lookup = 0;
2640 char byte[6];
2642 memset(&byte, 0, 6);
2644 /* First two bytes of digest stuffed
2645 * together. */
2647 val = digest2[x];
2648 val <<= 8;
2649 val += digest2[x+1];
2651 lookup = (val >> 0x0b);
2652 lookup &= 0x1f;
2653 if (lookup >= strlen(alphabet1))
2654 break;
2655 sprintf(byte, "%c", alphabet1[lookup]);
2656 strcat(resp_96, byte);
2657 strcat(resp_96, "=");
2659 lookup = (val >> 0x06);
2660 lookup &= 0x1f;
2661 if (lookup >= strlen(alphabet2))
2662 break;
2663 sprintf(byte, "%c", alphabet2[lookup]);
2664 strcat(resp_96, byte);
2666 lookup = (val >> 0x01);
2667 lookup &= 0x1f;
2668 if (lookup >= strlen(alphabet2))
2669 break;
2670 sprintf(byte, "%c", alphabet2[lookup]);
2671 strcat(resp_96, byte);
2673 lookup = (val & 0x01);
2674 if (lookup >= strlen(delimit_lookup))
2675 break;
2676 sprintf(byte, "%c", delimit_lookup[lookup]);
2677 strcat(resp_96, byte);
2680 pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
2681 yahoo_packet_hash(pack, 0, sn);
2682 yahoo_packet_hash(pack, 6, resp_6);
2683 yahoo_packet_hash(pack, 96, resp_96);
2684 yahoo_packet_hash(pack, 1, sn);
2685 yahoo_packet_hash(pack, 244, YAHOO_CLIENT_VERSION_ID);
2686 yahoo_packet_hash(pack, 135, YAHOO_CLIENT_VERSION);
2688 yahoo_send_packet(yid, pack, 0);
2689 yahoo_packet_free(pack);
2691 free(password_hash);
2692 free(crypt_hash);
2695 static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2697 char *seed = NULL;
2698 char *sn = NULL;
2699 YList *l = pkt->hash;
2700 int m = 0;
2702 while (l) {
2703 struct yahoo_pair *pair = l->data;
2704 if (pair->key == 94)
2705 seed = pair->value;
2706 if (pair->key == 1)
2707 sn = pair->value;
2708 if (pair->key == 13)
2709 m = atoi(pair->value);
2710 l = l->next;
2713 if (!seed)
2714 return;
2716 switch (m) {
2717 case 0:
2718 /*yahoo_process_auth_pre_0x0b(yid, seed, sn);
2719 break;*/
2720 case 1:
2721 case 2:
2722 //yahoo_process_auth_0x0b(yid, seed, sn);
2723 yahoo_process_auth_0x10(yid, seed, sn);
2724 break;
2725 default:
2726 /* call error */
2727 WARNING(("unknown auth type %d", m));
2728 //yahoo_process_auth_0x0b(yid, seed, sn);
2729 yahoo_process_auth_0x10(yid, seed, sn);
2730 break;
2734 static void yahoo_process_auth_resp(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2736 struct yahoo_data *yd = yid->yd;
2737 char *login_id;
2738 char *handle;
2739 char *url=NULL;
2740 int login_status=0;
2742 YList *l;
2744 for (l = pkt->hash; l; l = l->next) {
2745 struct yahoo_pair *pair = l->data;
2746 if (pair->key == 0)
2747 login_id = pair->value;
2748 else if (pair->key == 1)
2749 handle = pair->value;
2750 else if (pair->key == 20)
2751 url = pair->value;
2752 else if (pair->key == 66)
2753 login_status = atoi(pair->value);
2756 if(pkt->status == 0xffffffff) {
2757 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, login_status, url);
2758 /* yahoo_logoff(yd->client_id);*/
2762 static void yahoo_process_mail(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2764 struct yahoo_data *yd = yid->yd;
2765 char *who = NULL;
2766 char *email = NULL;
2767 char *subj = NULL;
2768 int count = 0;
2769 YList *l;
2771 for (l = pkt->hash; l; l = l->next) {
2772 struct yahoo_pair *pair = l->data;
2773 if (pair->key == 9)
2774 count = strtol(pair->value, NULL, 10);
2775 else if (pair->key == 43)
2776 who = pair->value;
2777 else if (pair->key == 42)
2778 email = pair->value;
2779 else if (pair->key == 18)
2780 subj = pair->value;
2781 else
2782 LOG(("key: %d => value: %s", pair->key, pair->value));
2785 if (who && email && subj) {
2786 char from[1024];
2787 snprintf(from, sizeof(from), "%s (%s)", who, email);
2788 YAHOO_CALLBACK(ext_yahoo_mail_notify)(yd->client_id, from, subj, count);
2789 } else if(count > 0)
2790 YAHOO_CALLBACK(ext_yahoo_mail_notify)(yd->client_id, NULL, NULL, count);
2793 static void yahoo_process_contact(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2795 struct yahoo_data *yd = yid->yd;
2796 char *id = NULL;
2797 char *who = NULL;
2798 char *msg = NULL;
2799 char *name = NULL;
2800 long tm = 0L;
2801 int state = YAHOO_STATUS_AVAILABLE;
2802 int online = FALSE;
2803 int away = 0;
2804 int idle = 0;
2805 int mobile = 0;
2807 YList *l;
2809 for (l = pkt->hash; l; l = l->next) {
2810 struct yahoo_pair *pair = l->data;
2811 if (pair->key == 1)
2812 id = pair->value;
2813 else if (pair->key == 3)
2814 who = pair->value;
2815 else if (pair->key == 14)
2816 msg = pair->value;
2817 else if (pair->key == 7)
2818 name = pair->value;
2819 else if (pair->key == 10)
2820 state = strtol(pair->value, NULL, 10);
2821 else if (pair->key == 15)
2822 tm = strtol(pair->value, NULL, 10);
2823 else if (pair->key == 13)
2824 online = strtol(pair->value, NULL, 10);
2825 else if (pair->key == 47)
2826 away = strtol(pair->value, NULL, 10);
2827 else if (pair->key == 137)
2828 idle = strtol(pair->value, NULL, 10);
2829 else if (pair->key == 60)
2830 mobile = strtol(pair->value, NULL, 10);
2834 if (id)
2835 YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, id, who, msg);
2836 else if (name)
2837 YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away, idle, mobile);
2838 else if(pkt->status == 0x07)
2839 YAHOO_CALLBACK(ext_yahoo_rejected)(yd->client_id, who, msg);
2842 static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2844 struct yahoo_data *yd = yid->yd;
2845 char *who = NULL;
2846 char *where = NULL;
2847 int status = 0;
2848 char *me = NULL;
2850 struct yahoo_buddy *bud=NULL;
2852 YList *l;
2853 for (l = pkt->hash; l; l = l->next) {
2854 struct yahoo_pair *pair = l->data;
2855 if (pair->key == 1)
2856 me = pair->value;
2857 if (pair->key == 7)
2858 who = pair->value;
2859 if (pair->key == 65)
2860 where = pair->value;
2861 if (pair->key == 66)
2862 status = strtol(pair->value, NULL, 10);
2865 yahoo_dump_unhandled(pkt);
2867 if(!who)
2868 return;
2869 if(!where)
2870 where = "Unknown";
2872 bud = y_new0(struct yahoo_buddy, 1);
2873 bud->id = strdup(who);
2874 bud->group = strdup(where);
2875 bud->real_name = NULL;
2877 yd->buddies = y_list_append(yd->buddies, bud);
2879 /* YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */
2882 static void yahoo_process_buddydel(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2884 struct yahoo_data *yd = yid->yd;
2885 char *who = NULL;
2886 char *where = NULL;
2887 int unk_66 = 0;
2888 char *me = NULL;
2889 struct yahoo_buddy *bud;
2891 YList *buddy;
2893 YList *l;
2894 for (l = pkt->hash; l; l = l->next) {
2895 struct yahoo_pair *pair = l->data;
2896 if (pair->key == 1)
2897 me = pair->value;
2898 else if (pair->key == 7)
2899 who = pair->value;
2900 else if (pair->key == 65)
2901 where = pair->value;
2902 else if (pair->key == 66)
2903 unk_66 = strtol(pair->value, NULL, 10);
2904 else
2905 DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value));
2908 if(!who || !where)
2909 return;
2911 bud = y_new0(struct yahoo_buddy, 1);
2912 bud->id = strdup(who);
2913 bud->group = strdup(where);
2915 buddy = y_list_find_custom(yd->buddies, bud, is_same_bud);
2917 FREE(bud->id);
2918 FREE(bud->group);
2919 FREE(bud);
2921 if(buddy) {
2922 bud = buddy->data;
2923 yd->buddies = y_list_remove_link(yd->buddies, buddy);
2924 y_list_free_1(buddy);
2926 FREE(bud->id);
2927 FREE(bud->group);
2928 FREE(bud->real_name);
2929 FREE(bud);
2931 bud=NULL;
2935 static void yahoo_process_ignore(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2937 char *who = NULL;
2938 int status = 0;
2939 char *me = NULL;
2940 int un_ignore = 0;
2942 YList *l;
2943 for (l = pkt->hash; l; l = l->next) {
2944 struct yahoo_pair *pair = l->data;
2945 if (pair->key == 0)
2946 who = pair->value;
2947 if (pair->key == 1)
2948 me = pair->value;
2949 if (pair->key == 13) /* 1 == ignore, 2 == unignore */
2950 un_ignore = strtol(pair->value, NULL, 10);
2951 if (pair->key == 66)
2952 status = strtol(pair->value, NULL, 10);
2957 * status
2958 * 0 - ok
2959 * 2 - already in ignore list, could not add
2960 * 3 - not in ignore list, could not delete
2961 * 12 - is a buddy, could not add
2964 /* if(status)
2965 YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, who, 0, status);
2969 static void yahoo_process_voicechat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2971 char *who = NULL;
2972 char *me = NULL;
2973 char *room = NULL;
2974 char *voice_room = NULL;
2976 YList *l;
2977 for (l = pkt->hash; l; l = l->next) {
2978 struct yahoo_pair *pair = l->data;
2979 if (pair->key == 4)
2980 who = pair->value;
2981 if (pair->key == 5)
2982 me = pair->value;
2983 if (pair->key == 13)
2984 voice_room=pair->value;
2985 if (pair->key == 57)
2986 room=pair->value;
2989 NOTICE(("got voice chat invite from %s in %s to identity %s", who, room, me));
2991 * send: s:0 1:me 5:who 57:room 13:1
2992 * ???? s:4 5:who 10:99 19:-1615114531
2993 * gotr: s:4 5:who 10:99 19:-1615114615
2994 * ???? s:1 5:me 4:who 57:room 13:3room
2995 * got: s:1 5:me 4:who 57:room 13:1room
2996 * rej: s:0 1:me 5:who 57:room 13:3
2997 * rejr: s:4 5:who 10:99 19:-1617114599
3001 static void yahoo_process_ping(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
3003 char *errormsg = NULL;
3005 YList *l;
3006 for (l = pkt->hash; l; l = l->next) {
3007 struct yahoo_pair *pair = l->data;
3008 if (pair->key == 16)
3009 errormsg = pair->value;
3012 NOTICE(("got ping packet"));
3013 //YAHOO_CALLBACK(ext_yahoo_got_ping)(yid->yd->client_id, errormsg);
3016 static void _yahoo_webcam_get_server_connected(int fd, int error, void *d)
3018 struct yahoo_input_data *yid = d;
3019 char *who = yid->wcm->user;
3020 char *data = NULL;
3021 char *packet = NULL;
3022 unsigned char magic_nr[] = {0, 1, 0};
3023 unsigned char header_len = 8;
3024 unsigned int len = 0;
3025 unsigned int pos = 0;
3027 if(error || fd <= 0) {
3028 FREE(who);
3029 FREE(yid);
3030 return;
3033 yid->fd = fd;
3034 inputs = y_list_prepend(inputs, yid);
3036 /* send initial packet */
3037 if (who)
3038 data = strdup("<RVWCFG>");
3039 else
3040 data = strdup("<RUPCFG>");
3041 yahoo_add_to_send_queue(yid, data, strlen(data));
3042 FREE(data);
3044 /* send data */
3045 if (who)
3047 data = strdup("g=");
3048 data = y_string_append(data, who);
3049 data = y_string_append(data, "\r\n");
3050 } else {
3051 data = strdup("f=1\r\n");
3053 len = strlen(data);
3054 packet = y_new0(char, header_len + len);
3055 packet[pos++] = header_len;
3056 memcpy(packet + pos, magic_nr, sizeof(magic_nr));
3057 pos += sizeof(magic_nr);
3058 pos += yahoo_put32(packet + pos, len);
3059 memcpy(packet + pos, data, len);
3060 pos += len;
3061 yahoo_add_to_send_queue(yid, packet, pos);
3062 FREE(packet);
3063 FREE(data);
3065 yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, fd, YAHOO_INPUT_READ, yid);
3068 static void yahoo_webcam_get_server(struct yahoo_input_data *y, char *who, char *key)
3070 struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
3071 struct yahoo_server_settings *yss = y->yd->server_settings;
3073 yid->type = YAHOO_CONNECTION_WEBCAM_MASTER;
3074 yid->yd = y->yd;
3075 yid->wcm = y_new0(struct yahoo_webcam, 1);
3076 yid->wcm->user = who?strdup(who):NULL;
3077 yid->wcm->direction = who?YAHOO_WEBCAM_DOWNLOAD:YAHOO_WEBCAM_UPLOAD;
3078 yid->wcm->key = strdup(key);
3080 YAHOO_CALLBACK(ext_yahoo_connect_async)(yid->yd->client_id, yss->webcam_host, yss->webcam_port,
3081 _yahoo_webcam_get_server_connected, yid);
3085 static YList *webcam_queue=NULL;
3086 static void yahoo_process_webcam_key(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
3088 char *me = NULL;
3089 char *key = NULL;
3090 char *who = NULL;
3092 YList *l;
3093 yahoo_dump_unhandled(pkt);
3094 for (l = pkt->hash; l; l = l->next) {
3095 struct yahoo_pair *pair = l->data;
3096 if (pair->key == 5)
3097 me = pair->value;
3098 if (pair->key == 61)
3099 key=pair->value;
3102 l = webcam_queue;
3103 if(!l)
3104 return;
3105 who = l->data;
3106 webcam_queue = y_list_remove_link(webcam_queue, webcam_queue);
3107 y_list_free_1(l);
3108 yahoo_webcam_get_server(yid, who, key);
3109 FREE(who);
3112 static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
3114 DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service));
3115 switch (pkt->service)
3117 case YAHOO_SERVICE_USERSTAT:
3118 case YAHOO_SERVICE_LOGON:
3119 case YAHOO_SERVICE_LOGOFF:
3120 case YAHOO_SERVICE_ISAWAY:
3121 case YAHOO_SERVICE_ISBACK:
3122 case YAHOO_SERVICE_GAMELOGON:
3123 case YAHOO_SERVICE_GAMELOGOFF:
3124 case YAHOO_SERVICE_IDACT:
3125 case YAHOO_SERVICE_IDDEACT:
3126 case YAHOO_SERVICE_STATUS_15:
3127 yahoo_process_status(yid, pkt);
3128 break;
3129 case YAHOO_SERVICE_NOTIFY:
3130 yahoo_process_notify(yid, pkt);
3131 break;
3132 case YAHOO_SERVICE_MESSAGE:
3133 case YAHOO_SERVICE_GAMEMSG:
3134 case YAHOO_SERVICE_SYSMESSAGE:
3135 yahoo_process_message(yid, pkt);
3136 break;
3137 case YAHOO_SERVICE_NEWMAIL:
3138 yahoo_process_mail(yid, pkt);
3139 break;
3140 case YAHOO_SERVICE_NEWCONTACT:
3141 yahoo_process_contact(yid, pkt);
3142 break;
3143 case YAHOO_SERVICE_LIST:
3144 yahoo_process_list(yid, pkt);
3145 break;
3146 case YAHOO_SERVICE_VERIFY:
3147 yahoo_process_verify(yid, pkt);
3148 break;
3149 case YAHOO_SERVICE_AUTH:
3150 yahoo_process_auth(yid, pkt);
3151 break;
3152 case YAHOO_SERVICE_AUTHRESP:
3153 yahoo_process_auth_resp(yid, pkt);
3154 break;
3155 case YAHOO_SERVICE_CONFINVITE:
3156 case YAHOO_SERVICE_CONFADDINVITE:
3157 case YAHOO_SERVICE_CONFDECLINE:
3158 case YAHOO_SERVICE_CONFLOGON:
3159 case YAHOO_SERVICE_CONFLOGOFF:
3160 case YAHOO_SERVICE_CONFMSG:
3161 yahoo_process_conference(yid, pkt);
3162 break;
3163 case YAHOO_SERVICE_CHATONLINE:
3164 case YAHOO_SERVICE_CHATGOTO:
3165 case YAHOO_SERVICE_CHATJOIN:
3166 case YAHOO_SERVICE_CHATLEAVE:
3167 case YAHOO_SERVICE_CHATEXIT:
3168 case YAHOO_SERVICE_CHATLOGOUT:
3169 case YAHOO_SERVICE_CHATPING:
3170 case YAHOO_SERVICE_COMMENT:
3171 yahoo_process_chat(yid, pkt);
3172 break;
3173 case YAHOO_SERVICE_P2PFILEXFER:
3174 case YAHOO_SERVICE_FILETRANSFER:
3175 yahoo_process_filetransfer(yid, pkt);
3176 break;
3177 case YAHOO_SERVICE_ADDBUDDY:
3178 yahoo_process_buddyadd(yid, pkt);
3179 break;
3180 case YAHOO_SERVICE_REMBUDDY:
3181 yahoo_process_buddydel(yid, pkt);
3182 break;
3183 case YAHOO_SERVICE_IGNORECONTACT:
3184 yahoo_process_ignore(yid, pkt);
3185 break;
3186 case YAHOO_SERVICE_VOICECHAT:
3187 yahoo_process_voicechat(yid, pkt);
3188 break;
3189 case YAHOO_SERVICE_WEBCAM:
3190 yahoo_process_webcam_key(yid, pkt);
3191 break;
3192 case YAHOO_SERVICE_PING:
3193 yahoo_process_ping(yid, pkt);
3194 break;
3195 case YAHOO_SERVICE_IDLE:
3196 case YAHOO_SERVICE_MAILSTAT:
3197 case YAHOO_SERVICE_CHATINVITE:
3198 case YAHOO_SERVICE_CALENDAR:
3199 case YAHOO_SERVICE_NEWPERSONALMAIL:
3200 case YAHOO_SERVICE_ADDIDENT:
3201 case YAHOO_SERVICE_ADDIGNORE:
3202 case YAHOO_SERVICE_GOTGROUPRENAME:
3203 case YAHOO_SERVICE_GROUPRENAME:
3204 case YAHOO_SERVICE_PASSTHROUGH2:
3205 case YAHOO_SERVICE_CHATLOGON:
3206 case YAHOO_SERVICE_CHATLOGOFF:
3207 case YAHOO_SERVICE_CHATMSG:
3208 case YAHOO_SERVICE_REJECTCONTACT:
3209 case YAHOO_SERVICE_PEERTOPEER:
3210 WARNING(("unhandled service 0x%02x", pkt->service));
3211 yahoo_dump_unhandled(pkt);
3212 break;
3213 case YAHOO_SERVICE_PICTURE:
3214 yahoo_process_picture(yid, pkt);
3215 break;
3216 case YAHOO_SERVICE_PICTURE_CHECKSUM:
3217 yahoo_process_picture_checksum(yid, pkt);
3218 break;
3219 case YAHOO_SERVICE_PICTURE_UPLOAD:
3220 yahoo_process_picture_upload(yid, pkt);
3221 break;
3222 case YAHOO_SERVICE_LIST_15:
3223 yahoo_process_list_15(yid, pkt);
3224 break;
3225 case YAHOO_SERVICE_AUTH_REQ_15:
3226 yahoo_process_auth_15(yid, pkt);
3227 break;
3228 default:
3229 WARNING(("unknown service 0x%02x", pkt->service));
3230 yahoo_dump_unhandled(pkt);
3231 break;
3235 static struct yahoo_packet * yahoo_getdata(struct yahoo_input_data * yid)
3237 struct yahoo_packet *pkt;
3238 struct yahoo_data *yd = yid->yd;
3239 int pos = 0;
3240 int pktlen;
3242 if(!yd)
3243 return NULL;
3245 DEBUG_MSG(("rxlen is %d", yid->rxlen));
3246 if (yid->rxlen < YAHOO_PACKET_HDRLEN) {
3247 DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN"));
3248 return NULL;
3251 pos += 4; /* YMSG */
3252 pos += 2;
3253 pos += 2;
3255 pktlen = yahoo_get16(yid->rxqueue + pos); pos += 2;
3256 DEBUG_MSG(("%d bytes to read, rxlen is %d",
3257 pktlen, yid->rxlen));
3259 if (yid->rxlen < (YAHOO_PACKET_HDRLEN + pktlen)) {
3260 DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN + pktlen"));
3261 return NULL;
3264 LOG(("reading packet"));
3265 yahoo_packet_dump(yid->rxqueue, YAHOO_PACKET_HDRLEN + pktlen);
3267 pkt = yahoo_packet_new(0, 0, 0);
3269 pkt->service = yahoo_get16(yid->rxqueue + pos); pos += 2;
3270 pkt->status = yahoo_get32(yid->rxqueue + pos); pos += 4;
3271 DEBUG_MSG(("Yahoo Service: 0x%02x Status: %d", pkt->service,
3272 pkt->status));
3273 pkt->id = yahoo_get32(yid->rxqueue + pos); pos += 4;
3275 yd->session_id = pkt->id;
3277 yahoo_packet_read(pkt, yid->rxqueue + pos, pktlen);
3279 yid->rxlen -= YAHOO_PACKET_HDRLEN + pktlen;
3280 DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3281 if (yid->rxlen>0) {
3282 unsigned char *tmp = y_memdup(yid->rxqueue + YAHOO_PACKET_HDRLEN
3283 + pktlen, yid->rxlen);
3284 FREE(yid->rxqueue);
3285 yid->rxqueue = tmp;
3286 DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3287 } else {
3288 DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3289 FREE(yid->rxqueue);
3292 return pkt;
3295 static void yahoo_yab_read(struct yab *yab, unsigned char *d, int len)
3297 char *st, *en;
3298 char *data = (char *)d;
3299 data[len]='\0';
3301 DEBUG_MSG(("Got yab: %s", data));
3302 st = en = strstr(data, "userid=\"");
3303 if(st) {
3304 st += strlen("userid=\"");
3305 en = strchr(st, '"'); *en++ = '\0';
3306 yab->id = yahoo_xmldecode(st);
3309 st = strstr(en, "fname=\"");
3310 if(st) {
3311 st += strlen("fname=\"");
3312 en = strchr(st, '"'); *en++ = '\0';
3313 yab->fname = yahoo_xmldecode(st);
3316 st = strstr(en, "lname=\"");
3317 if(st) {
3318 st += strlen("lname=\"");
3319 en = strchr(st, '"'); *en++ = '\0';
3320 yab->lname = yahoo_xmldecode(st);
3323 st = strstr(en, "nname=\"");
3324 if(st) {
3325 st += strlen("nname=\"");
3326 en = strchr(st, '"'); *en++ = '\0';
3327 yab->nname = yahoo_xmldecode(st);
3330 st = strstr(en, "email=\"");
3331 if(st) {
3332 st += strlen("email=\"");
3333 en = strchr(st, '"'); *en++ = '\0';
3334 yab->email = yahoo_xmldecode(st);
3337 st = strstr(en, "hphone=\"");
3338 if(st) {
3339 st += strlen("hphone=\"");
3340 en = strchr(st, '"'); *en++ = '\0';
3341 yab->hphone = yahoo_xmldecode(st);
3344 st = strstr(en, "wphone=\"");
3345 if(st) {
3346 st += strlen("wphone=\"");
3347 en = strchr(st, '"'); *en++ = '\0';
3348 yab->wphone = yahoo_xmldecode(st);
3351 st = strstr(en, "mphone=\"");
3352 if(st) {
3353 st += strlen("mphone=\"");
3354 en = strchr(st, '"'); *en++ = '\0';
3355 yab->mphone = yahoo_xmldecode(st);
3358 st = strstr(en, "dbid=\"");
3359 if(st) {
3360 st += strlen("dbid=\"");
3361 en = strchr(st, '"'); *en++ = '\0';
3362 yab->dbid = atoi(st);
3366 static struct yab * yahoo_getyab(struct yahoo_input_data *yid)
3368 struct yab *yab = NULL;
3369 int pos = 0, end=0;
3370 struct yahoo_data *yd = yid->yd;
3372 if(!yd)
3373 return NULL;
3375 DEBUG_MSG(("rxlen is %d", yid->rxlen));
3377 if(yid->rxlen <= strlen("<record"))
3378 return NULL;
3380 /* start with <record */
3381 while(pos < yid->rxlen-strlen("<record")+1
3382 && memcmp(yid->rxqueue + pos, "<record", strlen("<record")))
3383 pos++;
3385 if(pos >= yid->rxlen-1)
3386 return NULL;
3388 end = pos+2;
3389 /* end with /> */
3390 while(end < yid->rxlen-strlen("/>")+1 && memcmp(yid->rxqueue + end, "/>", strlen("/>")))
3391 end++;
3393 if(end >= yid->rxlen-1)
3394 return NULL;
3396 yab = y_new0(struct yab, 1);
3397 yahoo_yab_read(yab, yid->rxqueue + pos, end+2-pos);
3400 yid->rxlen -= end+1;
3401 DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3402 if (yid->rxlen>0) {
3403 unsigned char *tmp = y_memdup(yid->rxqueue + end + 1, yid->rxlen);
3404 FREE(yid->rxqueue);
3405 yid->rxqueue = tmp;
3406 DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3407 } else {
3408 DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3409 FREE(yid->rxqueue);
3413 return yab;
3416 static char * yahoo_getwebcam_master(struct yahoo_input_data *yid)
3418 unsigned int pos=0;
3419 unsigned int len=0;
3420 unsigned int status=0;
3421 char *server=NULL;
3422 struct yahoo_data *yd = yid->yd;
3424 if(!yid || !yd)
3425 return NULL;
3427 DEBUG_MSG(("rxlen is %d", yid->rxlen));
3429 len = yid->rxqueue[pos++];
3430 if (yid->rxlen < len)
3431 return NULL;
3433 /* extract status (0 = ok, 6 = webcam not online) */
3434 status = yid->rxqueue[pos++];
3436 if (status == 0)
3438 pos += 2; /* skip next 2 bytes */
3439 server = y_memdup(yid->rxqueue+pos, 16);
3440 pos += 16;
3442 else if (status == 6)
3444 YAHOO_CALLBACK(ext_yahoo_webcam_closed)
3445 (yd->client_id, yid->wcm->user, 4);
3448 /* skip rest of the data */
3450 yid->rxlen -= len;
3451 DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3452 if (yid->rxlen>0) {
3453 unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
3454 FREE(yid->rxqueue);
3455 yid->rxqueue = tmp;
3456 DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3457 } else {
3458 DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3459 FREE(yid->rxqueue);
3462 return server;
3465 static int yahoo_get_webcam_data(struct yahoo_input_data *yid)
3467 unsigned char reason=0;
3468 unsigned int pos=0;
3469 unsigned int begin=0;
3470 unsigned int end=0;
3471 unsigned int closed=0;
3472 unsigned char header_len=0;
3473 char *who;
3474 int connect=0;
3475 struct yahoo_data *yd = yid->yd;
3477 if(!yd)
3478 return -1;
3480 if(!yid->wcm || !yid->wcd || !yid->rxlen)
3481 return -1;
3483 DEBUG_MSG(("rxlen is %d", yid->rxlen));
3485 /* if we are not reading part of image then read header */
3486 if (!yid->wcd->to_read)
3488 header_len=yid->rxqueue[pos++];
3489 yid->wcd->packet_type=0;
3491 if (yid->rxlen < header_len)
3492 return 0;
3494 if (header_len >= 8)
3496 reason = yid->rxqueue[pos++];
3497 /* next 2 bytes should always be 05 00 */
3498 pos += 2;
3499 yid->wcd->data_size = yahoo_get32(yid->rxqueue + pos);
3500 pos += 4;
3501 yid->wcd->to_read = yid->wcd->data_size;
3503 if (header_len >= 13)
3505 yid->wcd->packet_type = yid->rxqueue[pos++];
3506 yid->wcd->timestamp = yahoo_get32(yid->rxqueue + pos);
3507 pos += 4;
3510 /* skip rest of header */
3511 pos = header_len;
3514 begin = pos;
3515 pos += yid->wcd->to_read;
3516 if (pos > yid->rxlen) pos = yid->rxlen;
3518 /* if it is not an image then make sure we have the whole packet */
3519 if (yid->wcd->packet_type != 0x02) {
3520 if ((pos - begin) != yid->wcd->data_size) {
3521 yid->wcd->to_read = 0;
3522 return 0;
3523 } else {
3524 yahoo_packet_dump(yid->rxqueue + begin, pos - begin);
3528 DEBUG_MSG(("packet type %.2X, data length %d", yid->wcd->packet_type,
3529 yid->wcd->data_size));
3531 /* find out what kind of packet we got */
3532 switch (yid->wcd->packet_type)
3534 case 0x00:
3535 /* user requests to view webcam (uploading) */
3536 if (yid->wcd->data_size &&
3537 yid->wcm->direction == YAHOO_WEBCAM_UPLOAD) {
3538 end = begin;
3539 while (end <= yid->rxlen &&
3540 yid->rxqueue[end++] != 13);
3541 if (end > begin)
3543 who = y_memdup(yid->rxqueue + begin, end - begin);
3544 who[end - begin - 1] = 0;
3545 YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who + 2, 2);
3546 FREE(who);
3550 if (yid->wcm->direction == YAHOO_WEBCAM_DOWNLOAD) {
3551 /* timestamp/status field */
3552 /* 0 = declined viewing permission */
3553 /* 1 = accepted viewing permission */
3554 if (yid->wcd->timestamp == 0) {
3555 YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, 3);
3558 break;
3559 case 0x01: /* status packets?? */
3560 /* timestamp contains status info */
3561 /* 00 00 00 01 = we have data?? */
3562 break;
3563 case 0x02: /* image data */
3564 YAHOO_CALLBACK(ext_yahoo_got_webcam_image)(yd->client_id,
3565 yid->wcm->user, yid->rxqueue + begin,
3566 yid->wcd->data_size, pos - begin,
3567 yid->wcd->timestamp);
3568 break;
3569 case 0x05: /* response packets when uploading */
3570 if (!yid->wcd->data_size) {
3571 YAHOO_CALLBACK(ext_yahoo_webcam_data_request)(yd->client_id, yid->wcd->timestamp);
3573 break;
3574 case 0x07: /* connection is closing */
3575 switch(reason)
3577 case 0x01: /* user closed connection */
3578 closed = 1;
3579 break;
3580 case 0x0F: /* user cancelled permission */
3581 closed = 2;
3582 break;
3584 YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, closed);
3585 break;
3586 case 0x0C: /* user connected */
3587 case 0x0D: /* user disconnected */
3588 if (yid->wcd->data_size) {
3589 who = y_memdup(yid->rxqueue + begin, pos - begin + 1);
3590 who[pos - begin] = 0;
3591 if (yid->wcd->packet_type == 0x0C)
3592 connect=1;
3593 else
3594 connect=0;
3595 YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who, connect);
3596 FREE(who);
3598 break;
3599 case 0x13: /* user data */
3600 /* i=user_ip (ip of the user we are viewing) */
3601 /* j=user_ext_ip (external ip of the user we */
3602 /* are viewing) */
3603 break;
3604 case 0x17: /* ?? */
3605 break;
3607 yid->wcd->to_read -= pos - begin;
3609 yid->rxlen -= pos;
3610 DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3611 if (yid->rxlen>0) {
3612 unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
3613 FREE(yid->rxqueue);
3614 yid->rxqueue = tmp;
3615 DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3616 } else {
3617 DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3618 FREE(yid->rxqueue);
3621 /* If we read a complete packet return success */
3622 if (!yid->wcd->to_read)
3623 return 1;
3625 return 0;
3628 int yahoo_write_ready(int id, int fd, void *data)
3630 struct yahoo_input_data *yid = data;
3631 int len;
3632 struct data_queue *tx;
3634 LOG(("write callback: id=%d fd=%d data=%p", id, fd, data));
3635 if(!yid || !yid->txqueues)
3636 return -2;
3638 tx = yid->txqueues->data;
3639 LOG(("writing %d bytes", tx->len));
3640 len = yahoo_send_data(fd, tx->queue, MIN(1024, tx->len));
3642 if(len == -1 && errno == EAGAIN)
3643 return 1;
3645 if(len <= 0) {
3646 int e = errno;
3647 DEBUG_MSG(("len == %d (<= 0)", len));
3648 while(yid->txqueues) {
3649 YList *l=yid->txqueues;
3650 tx = l->data;
3651 free(tx->queue);
3652 free(tx);
3653 yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
3654 y_list_free_1(l);
3656 LOG(("yahoo_write_ready(%d, %d) len < 0", id, fd));
3657 YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
3658 yid->write_tag = 0;
3659 errno=e;
3660 return 0;
3664 tx->len -= len;
3665 if(tx->len > 0) {
3666 unsigned char *tmp = y_memdup(tx->queue + len, tx->len);
3667 FREE(tx->queue);
3668 tx->queue = tmp;
3669 } else {
3670 YList *l=yid->txqueues;
3671 free(tx->queue);
3672 free(tx);
3673 yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
3674 y_list_free_1(l);
3676 if(!yid->txqueues)
3677 LOG(("yahoo_write_ready(%d, %d) !yxqueues", id, fd));
3679 if(!yid->txqueues) {
3680 LOG(("yahoo_write_ready(%d, %d) !yxqueues", id, fd));
3681 YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
3682 yid->write_tag = 0;
3686 return 1;
3689 static void yahoo_process_pager_connection(struct yahoo_input_data *yid, int over)
3691 struct yahoo_packet *pkt;
3692 struct yahoo_data *yd = yid->yd;
3693 int id = yd->client_id;
3695 if(over)
3696 return;
3698 while (find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER)
3699 && (pkt = yahoo_getdata(yid)) != NULL) {
3701 yahoo_packet_process(yid, pkt);
3703 yahoo_packet_free(pkt);
3707 static void yahoo_process_ft_connection(struct yahoo_input_data *yid, int over)
3711 static void yahoo_process_chatcat_connection(struct yahoo_input_data *yid, int over)
3713 if(over)
3714 return;
3716 if (strstr((char*)yid->rxqueue+(yid->rxlen-20), "</content>")) {
3717 YAHOO_CALLBACK(ext_yahoo_chat_cat_xml)(yid->yd->client_id, (char*)yid->rxqueue);
3721 static void yahoo_process_yab_connection(struct yahoo_input_data *yid, int over)
3723 struct yahoo_data *yd = yid->yd;
3724 struct yab *yab;
3725 YList *buds;
3726 int changed=0;
3727 int id = yd->client_id;
3729 if(over)
3730 return;
3732 while(find_input_by_id_and_type(id, YAHOO_CONNECTION_YAB)
3733 && (yab = yahoo_getyab(yid)) != NULL) {
3734 if(!yab->id)
3735 continue;
3736 changed=1;
3737 for(buds = yd->buddies; buds; buds=buds->next) {
3738 struct yahoo_buddy * bud = buds->data;
3739 if(!strcmp(bud->id, yab->id)) {
3740 bud->yab_entry = yab;
3741 if(yab->nname) {
3742 bud->real_name = strdup(yab->nname);
3743 } else if(yab->fname && yab->lname) {
3744 bud->real_name = y_new0(char,
3745 strlen(yab->fname)+
3746 strlen(yab->lname)+2
3748 sprintf(bud->real_name, "%s %s",
3749 yab->fname, yab->lname);
3750 } else if(yab->fname) {
3751 bud->real_name = strdup(yab->fname);
3753 break; /* for */
3758 if(changed)
3759 YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
3762 static void yahoo_process_search_connection(struct yahoo_input_data *yid, int over)
3764 struct yahoo_found_contact *yct=NULL;
3765 char *p = (char *)yid->rxqueue, *np, *cp;
3766 int k, n;
3767 int start=0, found=0, total=0;
3768 YList *contacts=NULL;
3769 struct yahoo_input_data *pyid = find_input_by_id_and_type(yid->yd->client_id, YAHOO_CONNECTION_PAGER);
3771 if(!over || !pyid)
3772 return;
3774 if(p && (p=strstr(p, "\r\n\r\n"))) {
3775 p += 4;
3777 for(k = 0; (p = strchr(p, 4)) && (k < 4); k++) {
3778 p++;
3779 n = atoi(p);
3780 switch(k) {
3781 case 0: found = pyid->ys->lsearch_nfound = n; break;
3782 case 2: start = pyid->ys->lsearch_nstart = n; break;
3783 case 3: total = pyid->ys->lsearch_ntotal = n; break;
3787 if(p)
3788 p++;
3790 k=0;
3791 while(p && *p) {
3792 cp = p;
3793 np = strchr(p, 4);
3795 if(!np)
3796 break;
3797 *np = 0;
3798 p = np+1;
3800 switch(k++) {
3801 case 1:
3802 if(strlen(cp) > 2 && y_list_length(contacts) < total) {
3803 yct = y_new0(struct yahoo_found_contact, 1);
3804 contacts = y_list_append(contacts, yct);
3805 yct->id = cp+2;
3806 } else {
3807 *p = 0;
3809 break;
3810 case 2:
3811 yct->online = !strcmp(cp, "2") ? 1 : 0;
3812 break;
3813 case 3:
3814 yct->gender = cp;
3815 break;
3816 case 4:
3817 yct->age = atoi(cp);
3818 break;
3819 case 5:
3820 if( strcmp(cp,"\005") != 0)
3821 yct->location = cp;
3822 k = 0;
3823 break;
3828 YAHOO_CALLBACK(ext_yahoo_got_search_result)(yid->yd->client_id, found, start, total, contacts);
3830 while(contacts) {
3831 YList *node = contacts;
3832 contacts = y_list_remove_link(contacts, node);
3833 free(node->data);
3834 y_list_free_1(node);
3838 static void _yahoo_webcam_connected(int fd, int error, void *d)
3840 struct yahoo_input_data *yid = d;
3841 struct yahoo_webcam *wcm = yid->wcm;
3842 struct yahoo_data *yd = yid->yd;
3843 char conn_type[100];
3844 char *data=NULL;
3845 char *packet=NULL;
3846 unsigned char magic_nr[] = {1, 0, 0, 0, 1};
3847 unsigned header_len=0;
3848 unsigned int len=0;
3849 unsigned int pos=0;
3851 if(error || fd <= 0) {
3852 FREE(yid);
3853 return;
3856 yid->fd = fd;
3857 inputs = y_list_prepend(inputs, yid);
3859 LOG(("Connected"));
3860 /* send initial packet */
3861 switch (wcm->direction)
3863 case YAHOO_WEBCAM_DOWNLOAD:
3864 data = strdup("<REQIMG>");
3865 break;
3866 case YAHOO_WEBCAM_UPLOAD:
3867 data = strdup("<SNDIMG>");
3868 break;
3869 default:
3870 return;
3872 yahoo_add_to_send_queue(yid, data, strlen(data));
3873 FREE(data);
3875 /* send data */
3876 switch (wcm->direction)
3878 case YAHOO_WEBCAM_DOWNLOAD:
3879 header_len = 8;
3880 data = strdup("a=2\r\nc=us\r\ne=21\r\nu=");
3881 data = y_string_append(data, yd->user);
3882 data = y_string_append(data, "\r\nt=");
3883 data = y_string_append(data, wcm->key);
3884 data = y_string_append(data, "\r\ni=");
3885 data = y_string_append(data, wcm->my_ip);
3886 data = y_string_append(data, "\r\ng=");
3887 data = y_string_append(data, wcm->user);
3888 data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
3889 snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
3890 data = y_string_append(data, conn_type);
3891 data = y_string_append(data, "\r\n");
3892 break;
3893 case YAHOO_WEBCAM_UPLOAD:
3894 header_len = 13;
3895 data = strdup("a=2\r\nc=us\r\nu=");
3896 data = y_string_append(data, yd->user);
3897 data = y_string_append(data, "\r\nt=");
3898 data = y_string_append(data, wcm->key);
3899 data = y_string_append(data, "\r\ni=");
3900 data = y_string_append(data, wcm->my_ip);
3901 data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
3902 snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
3903 data = y_string_append(data, conn_type);
3904 data = y_string_append(data, "\r\nb=");
3905 data = y_string_append(data, wcm->description);
3906 data = y_string_append(data, "\r\n");
3907 break;
3910 len = strlen(data);
3911 packet = y_new0(char, header_len + len);
3912 packet[pos++] = header_len;
3913 packet[pos++] = 0;
3914 switch (wcm->direction)
3916 case YAHOO_WEBCAM_DOWNLOAD:
3917 packet[pos++] = 1;
3918 packet[pos++] = 0;
3919 break;
3920 case YAHOO_WEBCAM_UPLOAD:
3921 packet[pos++] = 5;
3922 packet[pos++] = 0;
3923 break;
3926 pos += yahoo_put32(packet + pos, len);
3927 if (wcm->direction == YAHOO_WEBCAM_UPLOAD)
3929 memcpy(packet + pos, magic_nr, sizeof(magic_nr));
3930 pos += sizeof(magic_nr);
3932 memcpy(packet + pos, data, len);
3933 yahoo_add_to_send_queue(yid, packet, header_len + len);
3934 FREE(packet);
3935 FREE(data);
3937 yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_READ, yid);
3940 static void yahoo_webcam_connect(struct yahoo_input_data *y)
3942 struct yahoo_webcam *wcm = y->wcm;
3943 struct yahoo_input_data *yid;
3944 struct yahoo_server_settings *yss;
3946 if (!wcm || !wcm->server || !wcm->key)
3947 return;
3949 yid = y_new0(struct yahoo_input_data, 1);
3950 yid->type = YAHOO_CONNECTION_WEBCAM;
3951 yid->yd = y->yd;
3953 /* copy webcam data to new connection */
3954 yid->wcm = y->wcm;
3955 y->wcm = NULL;
3957 yss = y->yd->server_settings;
3959 yid->wcd = y_new0(struct yahoo_webcam_data, 1);
3961 LOG(("Connecting to: %s:%d", wcm->server, wcm->port));
3962 YAHOO_CALLBACK(ext_yahoo_connect_async)(y->yd->client_id, wcm->server, wcm->port,
3963 _yahoo_webcam_connected, yid);
3967 static void yahoo_process_webcam_master_connection(struct yahoo_input_data *yid, int over)
3969 char* server;
3970 struct yahoo_server_settings *yss;
3972 if(over)
3973 return;
3975 server = yahoo_getwebcam_master(yid);
3977 if (server)
3979 yss = yid->yd->server_settings;
3980 yid->wcm->server = strdup(server);
3981 yid->wcm->port = yss->webcam_port;
3982 yid->wcm->conn_type = yss->conn_type;
3983 yid->wcm->my_ip = strdup(yss->local_host);
3984 if (yid->wcm->direction == YAHOO_WEBCAM_UPLOAD)
3985 yid->wcm->description = strdup(yss->webcam_description);
3986 yahoo_webcam_connect(yid);
3987 FREE(server);
3991 static void yahoo_process_webcam_connection(struct yahoo_input_data *yid, int over)
3993 int id = yid->yd->client_id;
3994 int fd = yid->fd;
3996 if(over)
3997 return;
3999 /* as long as we still have packets available keep processing them */
4000 while (find_input_by_id_and_fd(id, fd)
4001 && yahoo_get_webcam_data(yid) == 1);
4004 static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = {
4005 yahoo_process_pager_connection,
4006 yahoo_process_ft_connection,
4007 yahoo_process_yab_connection,
4008 yahoo_process_webcam_master_connection,
4009 yahoo_process_webcam_connection,
4010 yahoo_process_chatcat_connection,
4011 yahoo_process_search_connection
4014 int yahoo_read_ready(int id, int fd, void *data)
4016 struct yahoo_input_data *yid = data;
4017 char buf[1024];
4018 int len;
4020 LOG(("read callback: id=%d fd=%d data=%p", id, fd, data));
4021 if(!yid)
4022 return -2;
4025 do {
4026 len = read(fd, buf, sizeof(buf));
4027 } while(len == -1 && errno == EINTR);
4029 if(len == -1 && errno == EAGAIN) /* we'll try again later */
4030 return 1;
4032 if (len <= 0) {
4033 int e = errno;
4034 DEBUG_MSG(("len == %d (<= 0)", len));
4036 if(yid->type == YAHOO_CONNECTION_PAGER) {
4037 YAHOO_CALLBACK(ext_yahoo_error)(yid->yd->client_id, "Connection closed by server", 1, E_CONNECTION);
4040 yahoo_process_connection[yid->type](yid, 1);
4041 yahoo_input_close(yid);
4043 /* no need to return an error, because we've already fixed it */
4044 if(len == 0)
4045 return 1;
4047 errno=e;
4048 LOG(("read error: %s", strerror(errno)));
4049 return -1;
4052 yid->rxqueue = y_renew(unsigned char, yid->rxqueue, len + yid->rxlen);
4053 memcpy(yid->rxqueue + yid->rxlen, buf, len);
4054 yid->rxlen += len;
4056 yahoo_process_connection[yid->type](yid, 0);
4058 return len;
4061 int yahoo_init_with_attributes(const char *username, const char *password, ...)
4063 va_list ap;
4064 struct yahoo_data *yd;
4066 yd = y_new0(struct yahoo_data, 1);
4068 if(!yd)
4069 return 0;
4071 yd->user = strdup(username);
4072 yd->password = strdup(password);
4074 yd->initial_status = -1;
4075 yd->current_status = -1;
4077 yd->client_id = ++last_id;
4079 add_to_list(yd);
4081 va_start(ap, password);
4082 yd->server_settings = _yahoo_assign_server_settings(ap);
4083 va_end(ap);
4085 return yd->client_id;
4088 int yahoo_init(const char *username, const char *password)
4090 return yahoo_init_with_attributes(username, password, (char *)NULL);
4093 struct connect_callback_data {
4094 struct yahoo_data *yd;
4095 int tag;
4096 int i;
4099 static void yahoo_connected(int fd, int error, void *data)
4101 struct connect_callback_data *ccd = data;
4102 struct yahoo_data *yd = ccd->yd;
4103 struct yahoo_packet *pkt;
4104 struct yahoo_input_data *yid;
4105 struct yahoo_server_settings *yss = yd->server_settings;
4107 if(error) {
4108 if(fallback_ports[ccd->i]) {
4109 int tag;
4110 yss->pager_port = fallback_ports[ccd->i++];
4111 tag = YAHOO_CALLBACK(ext_yahoo_connect_async)(yd->client_id, yss->pager_host,
4112 yss->pager_port, yahoo_connected, ccd);
4114 if(tag > 0)
4115 ccd->tag=tag;
4116 } else {
4117 FREE(ccd);
4118 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_SOCK, NULL);
4120 return;
4123 FREE(ccd);
4125 /* fd < 0 && error == 0 means connect was cancelled */
4126 if(fd < 0)
4127 return;
4129 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
4130 NOTICE(("Sending initial packet"));
4132 yahoo_packet_hash(pkt, 1, yd->user);
4134 yid = y_new0(struct yahoo_input_data, 1);
4135 yid->yd = yd;
4136 yid->fd = fd;
4137 inputs = y_list_prepend(inputs, yid);
4139 yahoo_send_packet(yid, pkt, 0);
4141 yahoo_packet_free(pkt);
4143 yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_READ, yid);
4146 void yahoo_login(int id, int initial)
4148 struct yahoo_data *yd = find_conn_by_id(id);
4149 struct connect_callback_data *ccd;
4150 struct yahoo_server_settings *yss;
4151 int tag;
4153 if(!yd)
4154 return;
4156 yss = yd->server_settings;
4158 yd->initial_status = initial;
4160 ccd = y_new0(struct connect_callback_data, 1);
4161 ccd->yd = yd;
4162 tag = YAHOO_CALLBACK(ext_yahoo_connect_async)(yd->client_id, yss->pager_host, yss->pager_port,
4163 yahoo_connected, ccd);
4166 * if tag <= 0, then callback has already been called
4167 * so ccd will have been freed
4169 if(tag > 0)
4170 ccd->tag = tag;
4171 else if(tag < 0)
4172 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_SOCK, NULL);
4176 int yahoo_get_fd(int id)
4178 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4179 if(!yid)
4180 return 0;
4181 else
4182 return yid->fd;
4185 void yahoo_send_im(int id, const char *from, const char *who, const char *what, int utf8, int picture)
4187 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4188 struct yahoo_packet *pkt = NULL;
4189 struct yahoo_data *yd;
4190 char pic_str[10];
4192 if(!yid)
4193 return;
4195 yd = yid->yd;
4197 pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, yd->session_id);
4199 snprintf(pic_str, sizeof(pic_str), "%d", picture);
4201 if(from && strcmp(from, yd->user))
4202 yahoo_packet_hash(pkt, 0, yd->user);
4203 yahoo_packet_hash(pkt, 1, from?from:yd->user);
4204 yahoo_packet_hash(pkt, 5, who);
4205 yahoo_packet_hash(pkt, 14, what);
4207 if(utf8)
4208 yahoo_packet_hash(pkt, 97, "1");
4210 yahoo_packet_hash(pkt, 63, ";0"); /* imvironment name; or ;0 */
4211 yahoo_packet_hash(pkt, 64, "0");
4212 yahoo_packet_hash(pkt, 206, pic_str);
4215 yahoo_send_packet(yid, pkt, 0);
4217 yahoo_packet_free(pkt);
4220 void yahoo_send_typing(int id, const char *from, const char *who, int typ)
4222 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4223 struct yahoo_data *yd;
4224 struct yahoo_packet *pkt = NULL;
4225 if(!yid)
4226 return;
4228 yd = yid->yd;
4229 pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yd->session_id);
4231 yahoo_packet_hash(pkt, 5, who);
4232 yahoo_packet_hash(pkt, 4, from?from:yd->user);
4233 yahoo_packet_hash(pkt, 14, " ");
4234 yahoo_packet_hash(pkt, 13, typ ? "1" : "0");
4235 yahoo_packet_hash(pkt, 49, "TYPING");
4237 yahoo_send_packet(yid, pkt, 0);
4239 yahoo_packet_free(pkt);
4242 void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away)
4244 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4245 struct yahoo_data *yd;
4246 struct yahoo_packet *pkt = NULL;
4247 int service;
4248 char s[4];
4250 if(!yid)
4251 return;
4253 yd = yid->yd;
4255 if (msg) {
4256 yd->current_status = YAHOO_STATUS_CUSTOM;
4257 } else {
4258 yd->current_status = state;
4261 if (yd->current_status == YAHOO_STATUS_AVAILABLE)
4262 service = YAHOO_SERVICE_ISBACK;
4263 else
4264 service = YAHOO_SERVICE_ISAWAY;
4266 if ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) {
4267 pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id);
4268 yahoo_packet_hash(pkt, 10, "999");
4269 yahoo_packet_hash(pkt, 47, "2");
4270 }else {
4271 pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, yd->session_id);
4272 snprintf(s, sizeof(s), "%d", yd->current_status);
4273 yahoo_packet_hash(pkt, 10, s);
4274 if (yd->current_status == YAHOO_STATUS_CUSTOM) {
4275 yahoo_packet_hash(pkt, 19, msg);
4276 yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
4277 } else {
4278 yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
4285 yahoo_send_packet(yid, pkt, 0);
4286 yahoo_packet_free(pkt);
4289 void yahoo_logoff(int id)
4291 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4292 struct yahoo_data *yd;
4293 struct yahoo_packet *pkt = NULL;
4295 if(!yid)
4296 return;
4297 yd = yid->yd;
4299 LOG(("yahoo_logoff: current status: %d", yd->current_status));
4301 if(yd->current_status != -1) {
4302 pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
4303 yd->current_status = -1;
4305 if (pkt) {
4306 yahoo_send_packet(yid, pkt, 0);
4307 yahoo_packet_free(pkt);
4312 /* do {
4313 yahoo_input_close(yid);
4314 } while((yid = find_input_by_id(id)));*/
4318 void yahoo_get_list(int id)
4320 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4321 struct yahoo_data *yd;
4322 struct yahoo_packet *pkt = NULL;
4324 if(!yid)
4325 return;
4326 yd = yid->yd;
4328 pkt = yahoo_packet_new(YAHOO_SERVICE_LIST, YAHOO_STATUS_AVAILABLE, yd->session_id);
4329 yahoo_packet_hash(pkt, 1, yd->user);
4330 if (pkt) {
4331 yahoo_send_packet(yid, pkt, 0);
4332 yahoo_packet_free(pkt);
4336 static void _yahoo_http_connected(int id, int fd, int error, void *data)
4338 struct yahoo_input_data *yid = data;
4339 if(fd <= 0) {
4340 inputs = y_list_remove(inputs, yid);
4341 FREE(yid);
4342 return;
4345 yid->fd = fd;
4346 yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, fd, YAHOO_INPUT_READ, yid);
4349 void yahoo_get_yab(int id)
4351 struct yahoo_data *yd = find_conn_by_id(id);
4352 struct yahoo_input_data *yid;
4353 char url[1024];
4354 char buff[1024];
4356 if(!yd)
4357 return;
4359 yid = y_new0(struct yahoo_input_data, 1);
4360 yid->yd = yd;
4361 yid->type = YAHOO_CONNECTION_YAB;
4363 snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?ab2=0");
4365 snprintf(buff, sizeof(buff), "Y=%s; T=%s",
4366 yd->cookie_y, yd->cookie_t);
4368 inputs = y_list_prepend(inputs, yid);
4370 yahoo_http_get(yid->yd->client_id, url, buff,
4371 _yahoo_http_connected, yid);
4374 void yahoo_set_yab(int id, struct yab * yab)
4376 struct yahoo_data *yd = find_conn_by_id(id);
4377 struct yahoo_input_data *yid;
4378 char url[1024];
4379 char buff[1024];
4380 char *temp;
4381 int size = sizeof(url)-1;
4383 if(!yd)
4384 return;
4386 yid = y_new0(struct yahoo_input_data, 1);
4387 yid->type = YAHOO_CONNECTION_YAB;
4388 yid->yd = yd;
4390 strncpy(url, "http://insider.msg.yahoo.com/ycontent/?addab2=0", size);
4392 if(yab->dbid) {
4393 /* change existing yab */
4394 char tmp[32];
4395 strncat(url, "&ee=1&ow=1&id=", size - strlen(url));
4396 snprintf(tmp, sizeof(tmp), "%d", yab->dbid);
4397 strncat(url, tmp, size - strlen(url));
4400 if(yab->fname) {
4401 strncat(url, "&fn=", size - strlen(url));
4402 temp = yahoo_urlencode(yab->fname);
4403 strncat(url, temp, size - strlen(url));
4404 free(temp);
4406 if(yab->lname) {
4407 strncat(url, "&ln=", size - strlen(url));
4408 temp = yahoo_urlencode(yab->lname);
4409 strncat(url, temp, size - strlen(url));
4410 free(temp);
4412 strncat(url, "&yid=", size - strlen(url));
4413 temp = yahoo_urlencode(yab->id);
4414 strncat(url, temp, size - strlen(url));
4415 free(temp);
4416 if(yab->nname) {
4417 strncat(url, "&nn=", size - strlen(url));
4418 temp = yahoo_urlencode(yab->nname);
4419 strncat(url, temp, size - strlen(url));
4420 free(temp);
4422 if(yab->email) {
4423 strncat(url, "&e=", size - strlen(url));
4424 temp = yahoo_urlencode(yab->email);
4425 strncat(url, temp, size - strlen(url));
4426 free(temp);
4428 if(yab->hphone) {
4429 strncat(url, "&hp=", size - strlen(url));
4430 temp = yahoo_urlencode(yab->hphone);
4431 strncat(url, temp, size - strlen(url));
4432 free(temp);
4434 if(yab->wphone) {
4435 strncat(url, "&wp=", size - strlen(url));
4436 temp = yahoo_urlencode(yab->wphone);
4437 strncat(url, temp, size - strlen(url));
4438 free(temp);
4440 if(yab->mphone) {
4441 strncat(url, "&mp=", size - strlen(url));
4442 temp = yahoo_urlencode(yab->mphone);
4443 strncat(url, temp, size - strlen(url));
4444 free(temp);
4446 strncat(url, "&pp=0", size - strlen(url));
4448 snprintf(buff, sizeof(buff), "Y=%s; T=%s",
4449 yd->cookie_y, yd->cookie_t);
4451 inputs = y_list_prepend(inputs, yid);
4453 yahoo_http_get(yid->yd->client_id, url, buff,
4454 _yahoo_http_connected, yid);
4457 void yahoo_set_identity_status(int id, const char * identity, int active)
4459 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4460 struct yahoo_data *yd;
4461 struct yahoo_packet *pkt = NULL;
4463 if(!yid)
4464 return;
4465 yd = yid->yd;
4467 pkt = yahoo_packet_new(active?YAHOO_SERVICE_IDACT:YAHOO_SERVICE_IDDEACT,
4468 YAHOO_STATUS_AVAILABLE, yd->session_id);
4469 yahoo_packet_hash(pkt, 3, identity);
4470 if (pkt) {
4471 yahoo_send_packet(yid, pkt, 0);
4472 yahoo_packet_free(pkt);
4476 void yahoo_refresh(int id)
4478 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4479 struct yahoo_data *yd;
4480 struct yahoo_packet *pkt = NULL;
4482 if(!yid)
4483 return;
4484 yd = yid->yd;
4486 pkt = yahoo_packet_new(YAHOO_SERVICE_USERSTAT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4487 if (pkt) {
4488 yahoo_send_packet(yid, pkt, 0);
4489 yahoo_packet_free(pkt);
4493 void yahoo_keepalive(int id)
4495 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4496 struct yahoo_data *yd;
4497 struct yahoo_packet *pkt=NULL;
4498 if(!yid)
4499 return;
4500 yd = yid->yd;
4502 pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, yd->session_id);
4503 yahoo_send_packet(yid, pkt, 0);
4504 yahoo_packet_free(pkt);
4507 void yahoo_chat_keepalive (int id)
4509 struct yahoo_input_data *yid = find_input_by_id_and_type (id, YAHOO_CONNECTION_PAGER);
4510 struct yahoo_data *yd;
4511 struct yahoo_packet *pkt = NULL;
4513 if (!yid)
4514 return;
4516 yd = yid->yd;
4518 pkt = yahoo_packet_new (YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, yd->session_id);
4519 yahoo_send_packet (yid, pkt, 0);
4520 yahoo_packet_free (pkt);
4523 void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg)
4525 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4526 struct yahoo_data *yd;
4527 struct yahoo_packet *pkt;
4529 if(!yid)
4530 return;
4531 yd = yid->yd;
4533 if (!yd->logged_in)
4534 return;
4536 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4537 if(msg)
4538 yahoo_packet_hash(pkt, 14, msg);
4539 yahoo_packet_hash(pkt, 65, group);
4540 yahoo_packet_hash(pkt, 97, "1");
4541 yahoo_packet_hash(pkt, 1, yd->user);
4542 yahoo_packet_hash(pkt, 302, "319");
4543 yahoo_packet_hash(pkt, 300, "319");
4544 yahoo_packet_hash(pkt, 7, who);
4545 yahoo_packet_hash(pkt, 334, "0");
4546 yahoo_packet_hash(pkt, 301, "319");
4547 yahoo_packet_hash(pkt, 303, "319");
4549 yahoo_send_packet(yid, pkt, 0);
4550 yahoo_packet_free(pkt);
4553 void yahoo_remove_buddy(int id, const char *who, const char *group)
4555 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4556 struct yahoo_data *yd;
4557 struct yahoo_packet *pkt = NULL;
4559 if(!yid)
4560 return;
4561 yd = yid->yd;
4563 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4565 yahoo_packet_hash(pkt, 1, yd->user);
4566 yahoo_packet_hash(pkt, 7, who);
4567 yahoo_packet_hash(pkt, 65, group);
4568 yahoo_send_packet(yid, pkt, 0);
4569 yahoo_packet_free(pkt);
4572 void yahoo_reject_buddy(int id, const char *who, const char *msg)
4574 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4575 struct yahoo_data *yd;
4576 struct yahoo_packet *pkt;
4578 if(!yid)
4579 return;
4580 yd = yid->yd;
4582 if (!yd->logged_in)
4583 return;
4585 pkt = yahoo_packet_new(YAHOO_SERVICE_REJECTCONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4586 yahoo_packet_hash(pkt, 1, yd->user);
4587 yahoo_packet_hash(pkt, 7, who);
4588 yahoo_packet_hash(pkt, 14, msg);
4589 yahoo_send_packet(yid, pkt, 0);
4590 yahoo_packet_free(pkt);
4593 void yahoo_auth_deny(int id, const char *who)
4595 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4596 struct yahoo_data *yd;
4597 struct yahoo_packet *pkt;
4599 if(!yid)
4600 return;
4601 yd = yid->yd;
4603 if (!yd->logged_in)
4604 return;
4606 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
4607 yahoo_packet_hash(pkt, 1, yd->user);
4608 yahoo_packet_hash(pkt, 5, who);
4609 yahoo_packet_hash(pkt, 13, "2");
4610 yahoo_packet_hash(pkt, 334, "0");
4611 yahoo_packet_hash(pkt, 97, "1");
4612 yahoo_packet_hash(pkt, 14, "");
4613 yahoo_send_packet(yid, pkt, 0);
4614 yahoo_packet_free(pkt);
4618 void yahoo_auth_grant(int id, const char *who)
4620 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4621 struct yahoo_data *yd;
4622 struct yahoo_packet *pkt;
4624 if(!yid)
4625 return;
4626 yd = yid->yd;
4628 if (!yd->logged_in)
4629 return;
4631 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
4632 yahoo_packet_hash(pkt, 1, yd->user);
4633 yahoo_packet_hash(pkt, 5, who);
4634 // yahoo_packet_hash(pkt, 241, 0);
4635 yahoo_packet_hash(pkt, 13, "1");
4636 yahoo_packet_hash(pkt, 334, "0");
4637 yahoo_send_packet(yid, pkt, 0);
4638 yahoo_packet_free(pkt);
4642 void yahoo_ignore_buddy(int id, const char *who, int unignore)
4644 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4645 struct yahoo_data *yd;
4646 struct yahoo_packet *pkt;
4648 if(!yid)
4649 return;
4650 yd = yid->yd;
4652 if (!yd->logged_in)
4653 return;
4655 pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4656 yahoo_packet_hash(pkt, 1, yd->user);
4657 yahoo_packet_hash(pkt, 7, who);
4658 yahoo_packet_hash(pkt, 13, unignore?"2":"1");
4659 yahoo_send_packet(yid, pkt, 0);
4660 yahoo_packet_free(pkt);
4663 void yahoo_stealth_buddy(int id, const char *who, int unstealth)
4665 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4666 struct yahoo_data *yd;
4667 struct yahoo_packet *pkt;
4669 if(!yid)
4670 return;
4671 yd = yid->yd;
4673 if (!yd->logged_in)
4674 return;
4676 pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
4677 yahoo_packet_hash(pkt, 1, yd->user);
4678 yahoo_packet_hash(pkt, 7, who);
4679 yahoo_packet_hash(pkt, 31, unstealth?"2":"1");
4680 yahoo_packet_hash(pkt, 13, "2");
4681 yahoo_send_packet(yid, pkt, 0);
4682 yahoo_packet_free(pkt);
4685 void yahoo_change_buddy_group(int id, const char *who, const char *old_group, const char *new_group)
4687 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4688 struct yahoo_data *yd;
4689 struct yahoo_packet *pkt = NULL;
4691 if(!yid)
4692 return;
4693 yd = yid->yd;
4695 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4696 yahoo_packet_hash(pkt, 1, yd->user);
4697 yahoo_packet_hash(pkt, 7, who);
4698 yahoo_packet_hash(pkt, 65, new_group);
4699 yahoo_packet_hash(pkt, 14, " ");
4701 yahoo_send_packet(yid, pkt, 0);
4702 yahoo_packet_free(pkt);
4704 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4705 yahoo_packet_hash(pkt, 1, yd->user);
4706 yahoo_packet_hash(pkt, 7, who);
4707 yahoo_packet_hash(pkt, 65, old_group);
4708 yahoo_send_packet(yid, pkt, 0);
4709 yahoo_packet_free(pkt);
4712 void yahoo_group_rename(int id, const char *old_group, const char *new_group)
4714 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4715 struct yahoo_data *yd;
4716 struct yahoo_packet *pkt = NULL;
4718 if(!yid)
4719 return;
4720 yd = yid->yd;
4722 pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, yd->session_id);
4723 yahoo_packet_hash(pkt, 1, yd->user);
4724 yahoo_packet_hash(pkt, 65, old_group);
4725 yahoo_packet_hash(pkt, 67, new_group);
4727 yahoo_send_packet(yid, pkt, 0);
4728 yahoo_packet_free(pkt);
4731 void yahoo_conference_addinvite(int id, const char * from, const char *who, const char *room, const YList * members, const char *msg)
4733 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4734 struct yahoo_data *yd;
4735 struct yahoo_packet *pkt;
4737 if(!yid)
4738 return;
4739 yd = yid->yd;
4741 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFADDINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4743 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4744 yahoo_packet_hash(pkt, 51, who);
4745 yahoo_packet_hash(pkt, 57, room);
4746 yahoo_packet_hash(pkt, 58, msg);
4747 yahoo_packet_hash(pkt, 13, "0");
4748 for(; members; members = members->next) {
4749 yahoo_packet_hash(pkt, 52, (char *)members->data);
4750 yahoo_packet_hash(pkt, 53, (char *)members->data);
4752 /* 52, 53 -> other members? */
4754 yahoo_send_packet(yid, pkt, 0);
4756 yahoo_packet_free(pkt);
4759 void yahoo_conference_invite(int id, const char * from, YList *who, const char *room, const char *msg)
4761 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4762 struct yahoo_data *yd;
4763 struct yahoo_packet *pkt;
4765 if(!yid)
4766 return;
4767 yd = yid->yd;
4769 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4771 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4772 yahoo_packet_hash(pkt, 50, yd->user);
4773 for(; who; who = who->next) {
4774 yahoo_packet_hash(pkt, 52, (char *)who->data);
4776 yahoo_packet_hash(pkt, 57, room);
4777 yahoo_packet_hash(pkt, 58, msg);
4778 yahoo_packet_hash(pkt, 13, "0");
4780 yahoo_send_packet(yid, pkt, 0);
4782 yahoo_packet_free(pkt);
4785 void yahoo_conference_logon(int id, const char *from, YList *who, const char *room)
4787 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4788 struct yahoo_data *yd;
4789 struct yahoo_packet *pkt;
4791 if(!yid)
4792 return;
4793 yd = yid->yd;
4795 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGON, YAHOO_STATUS_AVAILABLE, yd->session_id);
4797 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4798 for(; who; who = who->next) {
4799 yahoo_packet_hash(pkt, 3, (char *)who->data);
4801 yahoo_packet_hash(pkt, 57, room);
4803 yahoo_send_packet(yid, pkt, 0);
4805 yahoo_packet_free(pkt);
4808 void yahoo_conference_decline(int id, const char * from, YList *who, const char *room, const char *msg)
4810 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4811 struct yahoo_data *yd;
4812 struct yahoo_packet *pkt;
4814 if(!yid)
4815 return;
4816 yd = yid->yd;
4818 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFDECLINE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4820 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4821 for(; who; who = who->next) {
4822 yahoo_packet_hash(pkt, 3, (char *)who->data);
4824 yahoo_packet_hash(pkt, 57, room);
4825 yahoo_packet_hash(pkt, 14, msg);
4827 yahoo_send_packet(yid, pkt, 0);
4829 yahoo_packet_free(pkt);
4832 void yahoo_conference_logoff(int id, const char * from, YList *who, const char *room)
4834 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4835 struct yahoo_data *yd;
4836 struct yahoo_packet *pkt;
4838 if(!yid)
4839 return;
4840 yd = yid->yd;
4842 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
4844 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4845 for(; who; who = who->next) {
4846 yahoo_packet_hash(pkt, 3, (char *)who->data);
4848 yahoo_packet_hash(pkt, 57, room);
4850 yahoo_send_packet(yid, pkt, 0);
4852 yahoo_packet_free(pkt);
4855 void yahoo_conference_message(int id, const char * from, YList *who, const char *room, const char *msg, int utf8)
4857 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4858 struct yahoo_data *yd;
4859 struct yahoo_packet *pkt;
4861 if(!yid)
4862 return;
4863 yd = yid->yd;
4865 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFMSG, YAHOO_STATUS_AVAILABLE, yd->session_id);
4867 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4868 for(; who; who = who->next) {
4869 yahoo_packet_hash(pkt, 53, (char *)who->data);
4871 yahoo_packet_hash(pkt, 57, room);
4872 yahoo_packet_hash(pkt, 14, msg);
4874 if(utf8)
4875 yahoo_packet_hash(pkt, 97, "1");
4877 yahoo_send_packet(yid, pkt, 0);
4879 yahoo_packet_free(pkt);
4882 void yahoo_get_chatrooms(int id, int chatroomid)
4884 struct yahoo_data *yd = find_conn_by_id(id);
4885 struct yahoo_input_data *yid;
4886 char url[1024];
4887 char buff[1024];
4889 if(!yd)
4890 return;
4892 yid = y_new0(struct yahoo_input_data, 1);
4893 yid->yd = yd;
4894 yid->type = YAHOO_CONNECTION_CHATCAT;
4896 if (chatroomid == 0) {
4897 snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?chatcat=0");
4898 } else {
4899 snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?chatroom_%d=0",chatroomid);
4902 snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
4904 inputs = y_list_prepend(inputs, yid);
4906 yahoo_http_get(yid->yd->client_id, url, buff, _yahoo_http_connected, yid);
4909 void yahoo_chat_logon(int id, const char *from, const char *room, const char *roomid)
4911 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4912 struct yahoo_data *yd;
4913 struct yahoo_packet *pkt;
4915 if(!yid)
4916 return;
4918 yd = yid->yd;
4920 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4922 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4923 yahoo_packet_hash(pkt, 109, yd->user);
4924 yahoo_packet_hash(pkt, 6, "abcde");
4926 yahoo_send_packet(yid, pkt, 0);
4928 yahoo_packet_free(pkt);
4930 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, yd->session_id);
4932 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4933 yahoo_packet_hash(pkt, 104, room);
4934 yahoo_packet_hash(pkt, 129, roomid);
4935 yahoo_packet_hash(pkt, 62, "2"); /* ??? */
4937 yahoo_send_packet(yid, pkt, 0);
4939 yahoo_packet_free(pkt);
4943 void yahoo_chat_message(int id, const char *from, const char *room, const char *msg, const int msgtype, const int utf8)
4945 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4946 struct yahoo_data *yd;
4947 struct yahoo_packet *pkt;
4948 char buf[2];
4950 if(!yid)
4951 return;
4953 yd = yid->yd;
4955 pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4957 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4958 yahoo_packet_hash(pkt, 104, room);
4959 yahoo_packet_hash(pkt, 117, msg);
4961 snprintf(buf, sizeof(buf), "%d", msgtype);
4962 yahoo_packet_hash(pkt, 124, buf);
4964 if(utf8)
4965 yahoo_packet_hash(pkt, 97, "1");
4967 yahoo_send_packet(yid, pkt, 0);
4969 yahoo_packet_free(pkt);
4973 void yahoo_chat_logoff(int id, const char *from)
4975 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4976 struct yahoo_data *yd;
4977 struct yahoo_packet *pkt;
4979 if(!yid)
4980 return;
4982 yd = yid->yd;
4984 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATLOGOUT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4986 yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4988 yahoo_send_packet(yid, pkt, 0);
4990 yahoo_packet_free(pkt);
4993 void yahoo_buddyicon_request(int id, const char *who)
4995 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4996 struct yahoo_data *yd;
4997 struct yahoo_packet *pkt;
4999 if( !yid )
5000 return;
5002 yd = yid->yd;
5004 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0);
5005 yahoo_packet_hash(pkt, 4, yd->user);
5006 yahoo_packet_hash(pkt, 5, who);
5007 yahoo_packet_hash(pkt, 13, "1");
5008 yahoo_send_packet(yid, pkt, 0);
5010 yahoo_packet_free(pkt);
5013 void yahoo_send_picture_info(int id, const char *who, const char *url, int checksum)
5015 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5016 struct yahoo_data *yd;
5017 struct yahoo_packet *pkt;
5018 char checksum_str[10];
5020 if( !yid )
5021 return;
5023 yd = yid->yd;
5025 snprintf(checksum_str, sizeof(checksum_str), "%d", checksum);
5027 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0);
5028 yahoo_packet_hash(pkt, 1, yd->user);
5029 yahoo_packet_hash(pkt, 4, yd->user);
5030 yahoo_packet_hash(pkt, 5, who);
5031 yahoo_packet_hash(pkt, 13, "2");
5032 yahoo_packet_hash(pkt, 20, url);
5033 yahoo_packet_hash(pkt, 192, checksum_str);
5034 yahoo_send_packet(yid, pkt, 0);
5036 yahoo_packet_free(pkt);
5039 void yahoo_send_picture_update(int id, const char *who, int type)
5041 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5042 struct yahoo_data *yd;
5043 struct yahoo_packet *pkt;
5044 char type_str[10];
5046 if( !yid )
5047 return;
5049 yd = yid->yd;
5051 snprintf(type_str, sizeof(type_str), "%d", type);
5053 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPDATE, YAHOO_STATUS_AVAILABLE, 0);
5054 yahoo_packet_hash(pkt, 1, yd->user);
5055 yahoo_packet_hash(pkt, 5, who);
5056 yahoo_packet_hash(pkt, 206, type_str);
5057 yahoo_send_packet(yid, pkt, 0);
5059 yahoo_packet_free(pkt);
5062 void yahoo_send_picture_checksum(int id, const char *who, int checksum)
5064 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5065 struct yahoo_data *yd;
5066 struct yahoo_packet *pkt;
5067 char checksum_str[10];
5069 if( !yid )
5070 return;
5072 yd = yid->yd;
5074 snprintf(checksum_str, sizeof(checksum_str), "%d", checksum);
5076 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_CHECKSUM, YAHOO_STATUS_AVAILABLE, 0);
5077 yahoo_packet_hash(pkt, 1, yd->user);
5078 if( who != 0 )
5079 yahoo_packet_hash(pkt, 5, who);
5080 yahoo_packet_hash(pkt, 192, checksum_str);
5081 yahoo_packet_hash(pkt, 212, "1");
5082 yahoo_send_packet(yid, pkt, 0);
5084 yahoo_packet_free(pkt);
5087 void yahoo_webcam_close_feed(int id, const char *who)
5089 struct yahoo_input_data *yid = find_input_by_id_and_webcam_user(id, who);
5091 if(yid)
5092 yahoo_input_close(yid);
5095 void yahoo_webcam_get_feed(int id, const char *who)
5097 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5098 struct yahoo_data *yd;
5099 struct yahoo_packet *pkt;
5101 if(!yid)
5102 return;
5105 * add the user to the queue. this is a dirty hack, since
5106 * the yahoo server doesn't tell us who's key it's returning,
5107 * we have to just hope that it sends back keys in the same
5108 * order that we request them.
5109 * The queue is popped in yahoo_process_webcam_key
5111 webcam_queue = y_list_append(webcam_queue, who?strdup(who):NULL);
5113 yd = yid->yd;
5115 pkt = yahoo_packet_new(YAHOO_SERVICE_WEBCAM, YAHOO_STATUS_AVAILABLE, yd->session_id);
5117 yahoo_packet_hash(pkt, 1, yd->user);
5118 if (who != NULL)
5119 yahoo_packet_hash(pkt, 5, who);
5120 yahoo_send_packet(yid, pkt, 0);
5122 yahoo_packet_free(pkt);
5125 void yahoo_webcam_send_image(int id, unsigned char *image, unsigned int length, unsigned int timestamp)
5127 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
5128 unsigned char *packet;
5129 unsigned char header_len = 13;
5130 unsigned int pos = 0;
5132 if (!yid)
5133 return;
5135 packet = y_new0(unsigned char, header_len);
5137 packet[pos++] = header_len;
5138 packet[pos++] = 0;
5139 packet[pos++] = 5; /* version byte?? */
5140 packet[pos++] = 0;
5141 pos += yahoo_put32(packet + pos, length);
5142 packet[pos++] = 2; /* packet type, image */
5143 pos += yahoo_put32(packet + pos, timestamp);
5144 yahoo_add_to_send_queue(yid, packet, header_len);
5145 FREE(packet);
5147 if (length)
5148 yahoo_add_to_send_queue(yid, image, length);
5151 void yahoo_webcam_accept_viewer(int id, const char* who, int accept)
5153 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
5154 char *packet = NULL;
5155 char *data = NULL;
5156 unsigned char header_len = 13;
5157 unsigned int pos = 0;
5158 unsigned int len = 0;
5160 if (!yid)
5161 return;
5163 data = strdup("u=");
5164 data = y_string_append(data, (char*)who);
5165 data = y_string_append(data, "\r\n");
5166 len = strlen(data);
5168 packet = y_new0(char, header_len + len);
5169 packet[pos++] = header_len;
5170 packet[pos++] = 0;
5171 packet[pos++] = 5; /* version byte?? */
5172 packet[pos++] = 0;
5173 pos += yahoo_put32(packet + pos, len);
5174 packet[pos++] = 0; /* packet type */
5175 pos += yahoo_put32(packet + pos, accept);
5176 memcpy(packet + pos, data, len);
5177 FREE(data);
5178 yahoo_add_to_send_queue(yid, packet, header_len + len);
5179 FREE(packet);
5182 void yahoo_webcam_invite(int id, const char *who)
5184 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5185 struct yahoo_packet *pkt;
5187 if(!yid)
5188 return;
5190 pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yid->yd->session_id);
5192 yahoo_packet_hash(pkt, 49, "WEBCAMINVITE");
5193 yahoo_packet_hash(pkt, 14, " ");
5194 yahoo_packet_hash(pkt, 13, "0");
5195 yahoo_packet_hash(pkt, 1, yid->yd->user);
5196 yahoo_packet_hash(pkt, 5, who);
5197 yahoo_send_packet(yid, pkt, 0);
5199 yahoo_packet_free(pkt);
5202 static void yahoo_search_internal(int id, int t, const char *text, int g, int ar, int photo, int yahoo_only, int startpos, int total)
5204 struct yahoo_data *yd = find_conn_by_id(id);
5205 struct yahoo_input_data *yid;
5206 char url[1024];
5207 char buff[1024];
5208 char *ctext, *p;
5210 if(!yd)
5211 return;
5213 yid = y_new0(struct yahoo_input_data, 1);
5214 yid->yd = yd;
5215 yid->type = YAHOO_CONNECTION_SEARCH;
5218 age range
5219 .ar=1 - 13-18, 2 - 18-25, 3 - 25-35, 4 - 35-50, 5 - 50-70, 6 - 70+
5222 snprintf(buff, sizeof(buff), "&.sq=%%20&.tt=%d&.ss=%d", total, startpos);
5224 ctext = strdup(text);
5225 while((p = strchr(ctext, ' ')))
5226 *p = '+';
5228 snprintf(url, 1024, "http://members.yahoo.com/interests?.oc=m&.kw=%s&.sb=%d&.g=%d&.ar=0%s%s%s",
5229 ctext, t, g, photo ? "&.p=y" : "", yahoo_only ? "&.pg=y" : "",
5230 startpos ? buff : "");
5232 FREE(ctext);
5234 snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
5236 inputs = y_list_prepend(inputs, yid);
5237 yahoo_http_get(yid->yd->client_id, url, buff, _yahoo_http_connected, yid);
5240 void yahoo_search(int id, enum yahoo_search_type t, const char *text, enum yahoo_search_gender g, enum yahoo_search_agerange ar,
5241 int photo, int yahoo_only)
5243 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5244 struct yahoo_search_state *yss;
5246 if(!yid)
5247 return;
5249 if(!yid->ys)
5250 yid->ys = y_new0(struct yahoo_search_state, 1);
5252 yss = yid->ys;
5254 FREE(yss->lsearch_text);
5255 yss->lsearch_type = t;
5256 yss->lsearch_text = strdup(text);
5257 yss->lsearch_gender = g;
5258 yss->lsearch_agerange = ar;
5259 yss->lsearch_photo = photo;
5260 yss->lsearch_yahoo_only = yahoo_only;
5262 yahoo_search_internal(id, t, text, g, ar, photo, yahoo_only, 0, 0);
5265 void yahoo_search_again(int id, int start)
5267 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5268 struct yahoo_search_state *yss;
5270 if(!yid || !yid->ys)
5271 return;
5273 yss = yid->ys;
5275 if(start == -1)
5276 start = yss->lsearch_nstart + yss->lsearch_nfound;
5278 yahoo_search_internal(id, yss->lsearch_type, yss->lsearch_text,
5279 yss->lsearch_gender, yss->lsearch_agerange,
5280 yss->lsearch_photo, yss->lsearch_yahoo_only,
5281 start, yss->lsearch_ntotal);
5284 struct send_file_data {
5285 struct yahoo_packet *pkt;
5286 yahoo_get_fd_callback callback;
5287 void *user_data;
5290 static void _yahoo_send_picture_connected(int id, int fd, int error, void *data)
5292 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT);
5293 struct send_file_data *sfd = data;
5294 struct yahoo_packet *pkt = sfd->pkt;
5295 unsigned char buff[1024];
5297 if(fd <= 0) {
5298 sfd->callback(id, fd, error, sfd->user_data);
5299 FREE(sfd);
5300 yahoo_packet_free(pkt);
5301 inputs = y_list_remove(inputs, yid);
5302 FREE(yid);
5303 return;
5306 yid->fd = fd;
5307 yahoo_send_packet(yid, pkt, 8);
5308 yahoo_packet_free(pkt);
5310 snprintf((char *)buff, sizeof(buff), "29");
5311 buff[2] = 0xc0;
5312 buff[3] = 0x80;
5314 write(yid->fd, buff, 4);
5316 /* YAHOO_CALLBACK(ext_yahoo_add_handler)(nyd->fd, YAHOO_INPUT_READ); */
5318 sfd->callback(id, fd, error, sfd->user_data);
5319 FREE(sfd);
5320 inputs = y_list_remove(inputs, yid);
5322 while(yahoo_tcp_readline(buff, sizeof(buff), nyd->fd) > 0) {
5323 if(!strcmp(buff, ""))
5324 break;
5328 yahoo_input_close(yid);
5331 void yahoo_send_picture(int id, const char *name, unsigned long size,
5332 yahoo_get_fd_callback callback, void *data)
5334 struct yahoo_data *yd = find_conn_by_id(id);
5335 struct yahoo_input_data *yid;
5336 struct yahoo_server_settings *yss;
5337 struct yahoo_packet *pkt = NULL;
5338 char size_str[10];
5339 char expire_str[10];
5340 long content_length=0;
5341 unsigned char buff[1024];
5342 char url[255];
5343 struct send_file_data *sfd;
5345 if(!yd)
5346 return;
5348 yss = yd->server_settings;
5350 yid = y_new0(struct yahoo_input_data, 1);
5351 yid->yd = yd;
5352 yid->type = YAHOO_CONNECTION_FT;
5354 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id);
5356 snprintf(size_str, sizeof(size_str), "%ld", size);
5357 snprintf(expire_str, sizeof(expire_str), "%ld", (long)604800);
5359 yahoo_packet_hash(pkt, 0, yd->user);
5360 yahoo_packet_hash(pkt, 1, yd->user);
5361 yahoo_packet_hash(pkt, 14, "");
5362 yahoo_packet_hash(pkt, 27, name);
5363 yahoo_packet_hash(pkt, 28, size_str);
5364 yahoo_packet_hash(pkt, 38, expire_str);
5367 content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt);
5369 snprintf(url, sizeof(url), "http://%s:%d/notifyft",
5370 yss->filetransfer_host, yss->filetransfer_port);
5371 snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s",
5372 yd->cookie_y, yd->cookie_t);
5373 inputs = y_list_prepend(inputs, yid);
5375 sfd = y_new0(struct send_file_data, 1);
5376 sfd->pkt = pkt;
5377 sfd->callback = callback;
5378 sfd->user_data = data;
5379 yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size,
5380 _yahoo_send_picture_connected, sfd);
5383 static void _yahoo_send_file_connected(int id, int fd, int error, void *data)
5385 struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT);
5386 struct send_file_data *sfd = data;
5387 struct yahoo_packet *pkt = sfd->pkt;
5388 unsigned char buff[1024];
5390 if(fd <= 0) {
5391 sfd->callback(id, fd, error, sfd->user_data);
5392 FREE(sfd);
5393 yahoo_packet_free(pkt);
5394 inputs = y_list_remove(inputs, yid);
5395 FREE(yid);
5396 return;
5399 yid->fd = fd;
5400 yahoo_send_packet(yid, pkt, 8);
5401 yahoo_packet_free(pkt);
5403 snprintf((char *)buff, sizeof(buff), "29");
5404 buff[2] = 0xc0;
5405 buff[3] = 0x80;
5407 write(yid->fd, buff, 4);
5409 /* YAHOO_CALLBACK(ext_yahoo_add_handler)(nyd->fd, YAHOO_INPUT_READ); */
5411 sfd->callback(id, fd, error, sfd->user_data);
5412 FREE(sfd);
5413 inputs = y_list_remove(inputs, yid);
5415 while(yahoo_tcp_readline(buff, sizeof(buff), nyd->fd) > 0) {
5416 if(!strcmp(buff, ""))
5417 break;
5421 yahoo_input_close(yid);
5424 void yahoo_send_file(int id, const char *who, const char *msg,
5425 const char *name, unsigned long size,
5426 yahoo_get_fd_callback callback, void *data)
5428 struct yahoo_data *yd = find_conn_by_id(id);
5429 struct yahoo_input_data *yid;
5430 struct yahoo_server_settings *yss;
5431 struct yahoo_packet *pkt = NULL;
5432 char size_str[10];
5433 long content_length=0;
5434 unsigned char buff[1024];
5435 char url[255];
5436 struct send_file_data *sfd;
5438 if(!yd)
5439 return;
5441 yss = yd->server_settings;
5443 yid = y_new0(struct yahoo_input_data, 1);
5444 yid->yd = yd;
5445 yid->type = YAHOO_CONNECTION_FT;
5447 pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
5449 snprintf(size_str, sizeof(size_str), "%ld", size);
5451 yahoo_packet_hash(pkt, 0, yd->user);
5452 yahoo_packet_hash(pkt, 5, who);
5453 yahoo_packet_hash(pkt, 14, msg);
5454 yahoo_packet_hash(pkt, 27, name);
5455 yahoo_packet_hash(pkt, 28, size_str);
5457 content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt);
5459 snprintf(url, sizeof(url), "http://%s:%d/notifyft",
5460 yss->filetransfer_host, yss->filetransfer_port);
5461 snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s",
5462 yd->cookie_y, yd->cookie_t);
5463 inputs = y_list_prepend(inputs, yid);
5465 sfd = y_new0(struct send_file_data, 1);
5466 sfd->pkt = pkt;
5467 sfd->callback = callback;
5468 sfd->user_data = data;
5469 yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size,
5470 _yahoo_send_file_connected, sfd);
5474 enum yahoo_status yahoo_current_status(int id)
5476 struct yahoo_data *yd = find_conn_by_id(id);
5477 if(!yd)
5478 return YAHOO_STATUS_OFFLINE;
5479 return yd->current_status;
5482 const YList * yahoo_get_buddylist(int id)
5484 struct yahoo_data *yd = find_conn_by_id(id);
5485 if(!yd)
5486 return NULL;
5487 return yd->buddies;
5490 const YList * yahoo_get_ignorelist(int id)
5492 struct yahoo_data *yd = find_conn_by_id(id);
5493 if(!yd)
5494 return NULL;
5495 return yd->ignore;
5498 const YList * yahoo_get_identities(int id)
5500 struct yahoo_data *yd = find_conn_by_id(id);
5501 if(!yd)
5502 return NULL;
5503 return yd->identities;
5506 const char * yahoo_get_cookie(int id, const char *which)
5508 struct yahoo_data *yd = find_conn_by_id(id);
5509 if(!yd)
5510 return NULL;
5511 if(!strncasecmp(which, "y", 1))
5512 return yd->cookie_y;
5513 if(!strncasecmp(which, "t", 1))
5514 return yd->cookie_t;
5515 if(!strncasecmp(which, "c", 1))
5516 return yd->cookie_c;
5517 if(!strncasecmp(which, "login", 5))
5518 return yd->login_cookie;
5519 return NULL;
5522 void yahoo_get_url_handle(int id, const char *url,
5523 yahoo_get_url_handle_callback callback, void *data)
5525 struct yahoo_data *yd = find_conn_by_id(id);
5526 if(!yd)
5527 return;
5529 yahoo_get_url_fd(id, url, yd, callback, data);
5532 const char * yahoo_get_profile_url( void )
5534 return profile_url;