source: protocols/yahoo/libyahoo2.c @ 0cbef26

Last change on this file since 0cbef26 was c3e349e, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-03T22:25:36Z

Cleaned up Yahoo! fix: Error handling, and also not crashing when the
connection disappears again before authentication finishes.

  • Property mode set to 100644
File size: 127.3 KB
Line 
1/*
2 * libyahoo2: libyahoo2.c
3 *
4 * Some code copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
5 *
6 * Yahoo Search copyright (C) 2003, Konstantin Klyagin <konst AT konst.org.ua>
7 *
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.
11 *
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>
22 *
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>
28 *
29 *
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.
34 *
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.
39 *
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
43 *
44 */
45
46#ifndef _WIN32
47#include <unistd.h>
48#endif
49#include <errno.h>
50#include <stdio.h>
51#include <stdarg.h>
52
53#if STDC_HEADERS
54# include <string.h>
55#else
56# if !HAVE_STRCHR
57#  define strchr index
58#  define strrchr rindex
59# endif
60char *strchr (), *strrchr ();
61# if !HAVE_MEMCPY
62#  define memcpy(d, s, n) bcopy ((s), (d), (n))
63#  define memmove(d, s, n) bcopy ((s), (d), (n))
64# endif
65#endif
66
67#include <sys/types.h>
68
69#ifdef __MINGW32__
70# include <winsock2.h>
71#endif
72
73#include <stdlib.h>
74#include <ctype.h>
75
76#include "sha1.h"
77#include "md5.h"
78#include "yahoo2.h"
79#include "yahoo_httplib.h"
80#include "yahoo_util.h"
81#include "yahoo_fn.h"
82
83#include "yahoo2_callbacks.h"
84#include "yahoo_debug.h"
85#if defined(__MINGW32__) && !defined(HAVE_GLIB)
86#define snprintf _snprintf
87#define vsnprintf _vsnprintf
88#endif
89
90#include "base64.h"
91#include "http_client.h"
92
93static void yahoo_process_auth_response(struct http_request *req);
94
95#ifdef USE_STRUCT_CALLBACKS
96struct yahoo_callbacks *yc=NULL;
97
98void yahoo_register_callbacks(struct yahoo_callbacks * tyc)
99{
100        yc = tyc;
101}
102
103#define YAHOO_CALLBACK(x)       yc->x
104#else
105#define YAHOO_CALLBACK(x)       x
106#endif
107
108static int yahoo_send_data(int fd, void *data, int len);
109
110int yahoo_log_message(char * fmt, ...)
111{
112        char out[1024];
113        va_list ap;
114        va_start(ap, fmt);
115        vsnprintf(out, sizeof(out), fmt, ap);
116        va_end(ap);
117        return YAHOO_CALLBACK(ext_yahoo_log)("%s", out);
118}
119
120int yahoo_connect(char * host, int port)
121{
122        return YAHOO_CALLBACK(ext_yahoo_connect)(host, port);
123}
124
125static enum yahoo_log_level log_level = YAHOO_LOG_NONE;
126
127enum yahoo_log_level yahoo_get_log_level()
128{
129        return log_level;
130}
131
132int yahoo_set_log_level(enum yahoo_log_level level)
133{
134        enum yahoo_log_level l = log_level;
135        log_level = level;
136        return l;
137}
138
139/* default values for servers */
140static char pager_host[] = "scs.msg.yahoo.com"; 
141static int pager_port = 5050;
142static int fallback_ports[]={23, 25, 80, 20, 119, 8001, 8002, 5050, 0};
143static char filetransfer_host[]="filetransfer.msg.yahoo.com";
144static int filetransfer_port=80;
145static char webcam_host[]="webcam.yahoo.com";
146static int webcam_port=5100;
147static char webcam_description[]="";
148static char local_host[]="";
149static int conn_type=Y_WCM_DSL;
150
151static char profile_url[] = "http://profiles.yahoo.com/";
152
153enum yahoo_service { /* these are easier to see in hex */
154        YAHOO_SERVICE_LOGON = 1,
155        YAHOO_SERVICE_LOGOFF,
156        YAHOO_SERVICE_ISAWAY,
157        YAHOO_SERVICE_ISBACK,
158        YAHOO_SERVICE_IDLE, /* 5 (placemarker) */
159        YAHOO_SERVICE_MESSAGE,
160        YAHOO_SERVICE_IDACT,
161        YAHOO_SERVICE_IDDEACT,
162        YAHOO_SERVICE_MAILSTAT,
163        YAHOO_SERVICE_USERSTAT, /* 0xa */
164        YAHOO_SERVICE_NEWMAIL,
165        YAHOO_SERVICE_CHATINVITE,
166        YAHOO_SERVICE_CALENDAR,
167        YAHOO_SERVICE_NEWPERSONALMAIL,
168        YAHOO_SERVICE_NEWCONTACT,
169        YAHOO_SERVICE_ADDIDENT, /* 0x10 */
170        YAHOO_SERVICE_ADDIGNORE,
171        YAHOO_SERVICE_PING,
172        YAHOO_SERVICE_GOTGROUPRENAME, /* < 1, 36(old), 37(new) */
173        YAHOO_SERVICE_SYSMESSAGE = 0x14,
174        YAHOO_SERVICE_SKINNAME = 0x15,
175        YAHOO_SERVICE_PASSTHROUGH2 = 0x16,
176        YAHOO_SERVICE_CONFINVITE = 0x18,
177        YAHOO_SERVICE_CONFLOGON,
178        YAHOO_SERVICE_CONFDECLINE,
179        YAHOO_SERVICE_CONFLOGOFF,
180        YAHOO_SERVICE_CONFADDINVITE,
181        YAHOO_SERVICE_CONFMSG,
182        YAHOO_SERVICE_CHATLOGON,
183        YAHOO_SERVICE_CHATLOGOFF,
184        YAHOO_SERVICE_CHATMSG = 0x20,
185        YAHOO_SERVICE_GAMELOGON = 0x28,
186        YAHOO_SERVICE_GAMELOGOFF,
187        YAHOO_SERVICE_GAMEMSG = 0x2a,
188        YAHOO_SERVICE_FILETRANSFER = 0x46,
189        YAHOO_SERVICE_VOICECHAT = 0x4A,
190        YAHOO_SERVICE_NOTIFY,
191        YAHOO_SERVICE_VERIFY,
192        YAHOO_SERVICE_P2PFILEXFER,
193        YAHOO_SERVICE_PEERTOPEER = 0x4F,        /* Checks if P2P possible */
194        YAHOO_SERVICE_WEBCAM,
195        YAHOO_SERVICE_AUTHRESP = 0x54,
196        YAHOO_SERVICE_LIST,
197        YAHOO_SERVICE_AUTH = 0x57,
198        YAHOO_SERVICE_AUTHBUDDY = 0x6d,
199        YAHOO_SERVICE_ADDBUDDY = 0x83,
200        YAHOO_SERVICE_REMBUDDY,
201        YAHOO_SERVICE_IGNORECONTACT,    /* > 1, 7, 13 < 1, 66, 13, 0*/
202        YAHOO_SERVICE_REJECTCONTACT,
203        YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */
204        YAHOO_SERVICE_Y7_PING = 0x8A, /* 0 - id and that's it?? */
205        YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/
206        YAHOO_SERVICE_CHATGOTO,
207        YAHOO_SERVICE_CHATJOIN, /* > 1 104-room 129-1600326591 62-2 */
208        YAHOO_SERVICE_CHATLEAVE,
209        YAHOO_SERVICE_CHATEXIT = 0x9b,
210        YAHOO_SERVICE_CHATADDINVITE = 0x9d,
211        YAHOO_SERVICE_CHATLOGOUT = 0xa0,
212        YAHOO_SERVICE_CHATPING,
213        YAHOO_SERVICE_COMMENT = 0xa8,
214        YAHOO_SERVICE_GAME_INVITE = 0xb7,
215        YAHOO_SERVICE_STEALTH_PERM = 0xb9,
216        YAHOO_SERVICE_STEALTH_SESSION = 0xba,
217        YAHOO_SERVICE_AVATAR = 0xbc,
218        YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd,
219        YAHOO_SERVICE_PICTURE = 0xbe,
220        YAHOO_SERVICE_PICTURE_UPDATE = 0xc1,
221        YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2,
222        YAHOO_SERVICE_YAB_UPDATE = 0xc4,
223        YAHOO_SERVICE_Y6_VISIBLE_TOGGLE = 0xc5, /* YMSG13, key 13: 2 = invisible, 1 = visible */
224        YAHOO_SERVICE_Y6_STATUS_UPDATE = 0xc6,  /* YMSG13 */
225        YAHOO_SERVICE_PICTURE_STATUS = 0xc7,    /* YMSG13, key 213: 0 = none, 1 = avatar, 2 = picture */
226        YAHOO_SERVICE_VERIFY_ID_EXISTS = 0xc8,
227        YAHOO_SERVICE_AUDIBLE = 0xd0,
228        YAHOO_SERVICE_Y7_PHOTO_SHARING = 0xd2,
229        YAHOO_SERVICE_Y7_CONTACT_DETAILS = 0xd3,/* YMSG13 */
230        YAHOO_SERVICE_Y7_CHAT_SESSION = 0xd4,
231        YAHOO_SERVICE_Y7_AUTHORIZATION = 0xd6,  /* YMSG13 */
232        YAHOO_SERVICE_Y7_FILETRANSFER = 0xdc,   /* YMSG13 */
233        YAHOO_SERVICE_Y7_FILETRANSFERINFO,      /* YMSG13 */
234        YAHOO_SERVICE_Y7_FILETRANSFERACCEPT,    /* YMSG13 */
235        YAHOO_SERVICE_Y7_MINGLE = 0xe1, /* YMSG13 */
236        YAHOO_SERVICE_Y7_CHANGE_GROUP = 0xe7, /* YMSG13 */
237        YAHOO_SERVICE_Y8_STATUS = 0xf0,                 /* YMSG15 */
238        YAHOO_SERVICE_Y8_LIST = 0Xf1,                   /* YMSG15 */
239        YAHOO_SERVICE_WEBLOGIN = 0x0226,
240        YAHOO_SERVICE_SMS_MSG = 0x02ea
241};
242
243struct yahoo_pair {
244        int key;
245        char *value;
246};
247
248struct yahoo_packet {
249        unsigned short int service;
250        unsigned int status;
251        unsigned int id;
252        YList *hash;
253};
254
255struct yahoo_search_state {
256        int   lsearch_type;
257        char  *lsearch_text;
258        int   lsearch_gender;
259        int   lsearch_agerange;
260        int   lsearch_photo;
261        int   lsearch_yahoo_only;
262        int   lsearch_nstart;
263        int   lsearch_nfound;
264        int   lsearch_ntotal;
265};
266
267struct data_queue {
268        unsigned char *queue;
269        int len;
270};
271
272struct yahoo_input_data {
273        struct yahoo_data *yd;
274        struct yahoo_webcam *wcm;
275        struct yahoo_webcam_data *wcd;
276        struct yahoo_search_state *ys;
277
278        int   fd;
279        enum yahoo_connection_type type;
280       
281        unsigned char   *rxqueue;
282        int   rxlen;
283        int   read_tag;
284
285        YList *txqueues;
286        int   write_tag;
287};
288
289struct yahoo_server_settings {
290        char *pager_host;
291        int   pager_port;
292        char *filetransfer_host;
293        int   filetransfer_port;
294        char *webcam_host;
295        int   webcam_port;
296        char *webcam_description;
297        char *local_host;
298        int   conn_type;
299};
300
301static void * _yahoo_default_server_settings()
302{
303        struct yahoo_server_settings *yss = y_new0(struct yahoo_server_settings, 1);
304
305        yss->pager_host = strdup(pager_host);
306        yss->pager_port = pager_port;
307        yss->filetransfer_host = strdup(filetransfer_host);
308        yss->filetransfer_port = filetransfer_port;
309        yss->webcam_host = strdup(webcam_host);
310        yss->webcam_port = webcam_port;
311        yss->webcam_description = strdup(webcam_description);
312        yss->local_host = strdup(local_host);
313        yss->conn_type = conn_type;
314
315        return yss;
316}
317
318static void * _yahoo_assign_server_settings(va_list ap)
319{
320        struct yahoo_server_settings *yss = _yahoo_default_server_settings();
321        char *key;
322        char *svalue;
323        int   nvalue;
324
325        while(1) {
326                key = va_arg(ap, char *);
327                if(key == NULL)
328                        break;
329
330                if(!strcmp(key, "pager_host")) {
331                        svalue = va_arg(ap, char *);
332                        free(yss->pager_host);
333                        yss->pager_host = strdup(svalue);
334                } else if(!strcmp(key, "pager_port")) {
335                        nvalue = va_arg(ap, int);
336                        yss->pager_port = nvalue;
337                } else if(!strcmp(key, "filetransfer_host")) {
338                        svalue = va_arg(ap, char *);
339                        free(yss->filetransfer_host);
340                        yss->filetransfer_host = strdup(svalue);
341                } else if(!strcmp(key, "filetransfer_port")) {
342                        nvalue = va_arg(ap, int);
343                        yss->filetransfer_port = nvalue;
344                } else if(!strcmp(key, "webcam_host")) {
345                        svalue = va_arg(ap, char *);
346                        free(yss->webcam_host);
347                        yss->webcam_host = strdup(svalue);
348                } else if(!strcmp(key, "webcam_port")) {
349                        nvalue = va_arg(ap, int);
350                        yss->webcam_port = nvalue;
351                } else if(!strcmp(key, "webcam_description")) {
352                        svalue = va_arg(ap, char *);
353                        free(yss->webcam_description);
354                        yss->webcam_description = strdup(svalue);
355                } else if(!strcmp(key, "local_host")) {
356                        svalue = va_arg(ap, char *);
357                        free(yss->local_host);
358                        yss->local_host = strdup(svalue);
359                } else if(!strcmp(key, "conn_type")) {
360                        nvalue = va_arg(ap, int);
361                        yss->conn_type = nvalue;
362                } else {
363                        WARNING(("Unknown key passed to yahoo_init, "
364                                "perhaps you didn't terminate the list "
365                                "with NULL"));
366                }
367        }
368
369        return yss;
370}
371
372static void yahoo_free_server_settings(struct yahoo_server_settings *yss)
373{
374        if(!yss)
375                return;
376
377        free(yss->pager_host);
378        free(yss->filetransfer_host);
379        free(yss->webcam_host);
380        free(yss->webcam_description);
381        free(yss->local_host);
382
383        free(yss);
384}
385
386static YList *conns=NULL;
387static YList *inputs=NULL;
388static int last_id=0;
389
390static void add_to_list(struct yahoo_data *yd)
391{
392        conns = y_list_prepend(conns, yd);
393}
394static struct yahoo_data * find_conn_by_id(int id)
395{
396        YList *l;
397        for(l = conns; l; l = y_list_next(l)) {
398                struct yahoo_data *yd = l->data;
399                if(yd->client_id == id)
400                        return yd;
401        }
402        return NULL;
403}
404static void del_from_list(struct yahoo_data *yd)
405{
406        conns = y_list_remove(conns, yd);
407}
408
409/* call repeatedly to get the next one */
410static struct yahoo_input_data * find_input_by_id(int id)
411{
412        YList *l;
413        for(l = inputs; l; l = y_list_next(l)) {
414                struct yahoo_input_data *yid = l->data;
415                if(yid->yd->client_id == id)
416                        return yid;
417        }
418        return NULL;
419}
420
421static struct yahoo_input_data * find_input_by_id_and_webcam_user(int id, const char * who)
422{
423        YList *l;
424        LOG(("find_input_by_id_and_webcam_user"));
425        for(l = inputs; l; l = y_list_next(l)) {
426                struct yahoo_input_data *yid = l->data;
427                if(yid->type == YAHOO_CONNECTION_WEBCAM && yid->yd->client_id == id
428                                && yid->wcm && 
429                                ((who && yid->wcm->user && !strcmp(who, yid->wcm->user)) ||
430                                 !(yid->wcm->user && !who)))
431                        return yid;
432        }
433        return NULL;
434}
435
436static struct yahoo_input_data * find_input_by_id_and_type(int id, enum yahoo_connection_type type)
437{
438        YList *l;
439        LOG(("find_input_by_id_and_type"));
440        for(l = inputs; l; l = y_list_next(l)) {
441                struct yahoo_input_data *yid = l->data;
442                if(yid->type == type && yid->yd->client_id == id)
443                        return yid;
444        }
445        return NULL;
446}
447
448static struct yahoo_input_data * find_input_by_id_and_fd(int id, int fd)
449{
450        YList *l;
451        LOG(("find_input_by_id_and_fd"));
452        for(l = inputs; l; l = y_list_next(l)) {
453                struct yahoo_input_data *yid = l->data;
454                if(yid->fd == fd && yid->yd->client_id == id)
455                        return yid;
456        }
457        return NULL;
458}
459
460static int count_inputs_with_id(int id)
461{
462        int c=0;
463        YList *l;
464        LOG(("counting %d", id));
465        for(l = inputs; l; l = y_list_next(l)) {
466                struct yahoo_input_data *yid = l->data;
467                if(yid->yd->client_id == id)
468                        c++;
469        }
470        LOG(("%d", c));
471        return c;
472}
473
474
475extern char *yahoo_crypt(char *, char *);
476
477/* Free a buddy list */
478static void yahoo_free_buddies(YList * list)
479{
480        YList *l;
481
482        for(l = list; l; l = l->next)
483        {
484                struct yahoo_buddy *bud = l->data;
485                if(!bud)
486                        continue;
487
488                FREE(bud->group);
489                FREE(bud->id);
490                FREE(bud->real_name);
491                if(bud->yab_entry) {
492                        FREE(bud->yab_entry->fname);
493                        FREE(bud->yab_entry->lname);
494                        FREE(bud->yab_entry->nname);
495                        FREE(bud->yab_entry->id);
496                        FREE(bud->yab_entry->email);
497                        FREE(bud->yab_entry->hphone);
498                        FREE(bud->yab_entry->wphone);
499                        FREE(bud->yab_entry->mphone);
500                        FREE(bud->yab_entry);
501                }
502                FREE(bud);
503                l->data = bud = NULL;
504        }
505
506        y_list_free(list);
507}
508
509/* Free an identities list */
510static void yahoo_free_identities(YList * list)
511{
512        while (list) {
513                YList *n = list;
514                FREE(list->data);
515                list = y_list_remove_link(list, list);
516                y_list_free_1(n);
517        }
518}
519
520/* Free webcam data */
521static void yahoo_free_webcam(struct yahoo_webcam *wcm)
522{
523        if (wcm) {
524                FREE(wcm->user);
525                FREE(wcm->server);
526                FREE(wcm->key);
527                FREE(wcm->description);
528                FREE(wcm->my_ip);
529        }
530        FREE(wcm);
531}
532
533static void yahoo_free_data(struct yahoo_data *yd)
534{
535        FREE(yd->user);
536        FREE(yd->password);
537        FREE(yd->cookie_y);
538        FREE(yd->cookie_t);
539        FREE(yd->cookie_c);
540        FREE(yd->login_cookie);
541        FREE(yd->login_id);
542
543        yahoo_free_buddies(yd->buddies);
544        yahoo_free_buddies(yd->ignore);
545        yahoo_free_identities(yd->identities);
546
547        yahoo_free_server_settings(yd->server_settings);
548
549        FREE(yd);
550}
551
552#define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4)
553
554static struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, 
555                enum yahoo_status status, int id)
556{
557        struct yahoo_packet *pkt = y_new0(struct yahoo_packet, 1);
558
559        pkt->service = service;
560        pkt->status = status;
561        pkt->id = id;
562
563        return pkt;
564}
565
566static void yahoo_packet_hash(struct yahoo_packet *pkt, int key, const char *value)
567{
568        struct yahoo_pair *pair = y_new0(struct yahoo_pair, 1);
569        pair->key = key;
570        pair->value = strdup(value);
571        pkt->hash = y_list_append(pkt->hash, pair);
572}
573
574static int yahoo_packet_length(struct yahoo_packet *pkt)
575{
576        YList *l;
577
578        int len = 0;
579
580        for (l = pkt->hash; l; l = l->next) {
581                struct yahoo_pair *pair = l->data;
582                int tmp = pair->key;
583                do {
584                        tmp /= 10;
585                        len++;
586                } while (tmp);
587                len += 2;
588                len += strlen(pair->value);
589                len += 2;
590        }
591
592        return len;
593}
594
595#define yahoo_put16(buf, data) ( \
596                (*(buf) = (unsigned char)((data)>>8)&0xff), \
597                (*((buf)+1) = (unsigned char)(data)&0xff),  \
598                2)
599#define yahoo_get16(buf) ((((*(buf))&0xff)<<8) + ((*((buf)+1)) & 0xff))
600#define yahoo_put32(buf, data) ( \
601                (*((buf)) = (unsigned char)((data)>>24)&0xff), \
602                (*((buf)+1) = (unsigned char)((data)>>16)&0xff), \
603                (*((buf)+2) = (unsigned char)((data)>>8)&0xff), \
604                (*((buf)+3) = (unsigned char)(data)&0xff), \
605                4)
606#define yahoo_get32(buf) ((((*(buf)   )&0xff)<<24) + \
607                         (((*((buf)+1))&0xff)<<16) + \
608                         (((*((buf)+2))&0xff)<< 8) + \
609                         (((*((buf)+3))&0xff)))
610
611static void yahoo_packet_read(struct yahoo_packet *pkt, unsigned char *data, int len)
612{
613        int pos = 0;
614
615        while (pos + 1 < len) {
616                char *key, *value = NULL;
617                int accept;
618                int x;
619
620                struct yahoo_pair *pair = y_new0(struct yahoo_pair, 1);
621
622                key = malloc(len + 1);
623                x = 0;
624                while (pos + 1 < len) {
625                        if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
626                                break;
627                        key[x++] = data[pos++];
628                }
629                key[x] = 0;
630                pos += 2;
631                pair->key = strtol(key, NULL, 10);
632                free(key);
633               
634                /* Libyahoo2 developer(s) don't seem to have the time to fix
635                   this problem, so for now try to work around it:
636                   
637                   Sometimes we receive an invalid packet with not any more
638                   data at this point. I don't know how to handle this in a
639                   clean way, but let's hope this is clean enough: */
640               
641                if (pos + 1 < len) {
642                        accept = x; 
643                        /* if x is 0 there was no key, so don't accept it */
644                        if (accept)
645                                value = malloc(len - pos + 1);
646                        x = 0;
647                        while (pos + 1 < len) {
648                                if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
649                                        break;
650                                if (accept)
651                                        value[x++] = data[pos++];
652                        }
653                        if (accept)
654                                value[x] = 0;
655                        pos += 2;
656                } else {
657                        accept = 0;
658                }
659               
660                if (accept) {
661                        pair->value = strdup(value);
662                        FREE(value);
663                        pkt->hash = y_list_append(pkt->hash, pair);
664                        DEBUG_MSG(("Key: %d  \tValue: %s", pair->key, pair->value));
665                } else {
666                        FREE(pair);
667                }
668        }
669}
670
671static void yahoo_packet_write(struct yahoo_packet *pkt, unsigned char *data)
672{
673        YList *l;
674        int pos = 0;
675
676        for (l = pkt->hash; l; l = l->next) {
677                struct yahoo_pair *pair = l->data;
678                unsigned char buf[100];
679
680                snprintf((char *)buf, sizeof(buf), "%d", pair->key);
681                strcpy((char *)data + pos, (char *)buf);
682                pos += strlen((char *)buf);
683                data[pos++] = 0xc0;
684                data[pos++] = 0x80;
685
686                strcpy((char *)data + pos, pair->value);
687                pos += strlen(pair->value);
688                data[pos++] = 0xc0;
689                data[pos++] = 0x80;
690        }
691}
692
693static void yahoo_dump_unhandled(struct yahoo_packet *pkt)
694{
695        YList *l;
696
697        NOTICE(("Service: 0x%02x\tStatus: %d", pkt->service, pkt->status));
698        for (l = pkt->hash; l; l = l->next) {
699                struct yahoo_pair *pair = l->data;
700                NOTICE(("\t%d => %s", pair->key, pair->value));
701        }
702}
703
704
705static void yahoo_packet_dump(unsigned char *data, int len)
706{
707        if(yahoo_get_log_level() >= YAHOO_LOG_DEBUG) {
708                int i;
709                for (i = 0; i < len; i++) {
710                        if ((i % 8 == 0) && i)
711                                YAHOO_CALLBACK(ext_yahoo_log)(" ");
712                        if ((i % 16 == 0) && i)
713                                YAHOO_CALLBACK(ext_yahoo_log)("\n");
714                        YAHOO_CALLBACK(ext_yahoo_log)("%02x ", data[i]);
715                }
716                YAHOO_CALLBACK(ext_yahoo_log)("\n");
717                for (i = 0; i < len; i++) {
718                        if ((i % 8 == 0) && i)
719                                YAHOO_CALLBACK(ext_yahoo_log)(" ");
720                        if ((i % 16 == 0) && i)
721                                YAHOO_CALLBACK(ext_yahoo_log)("\n");
722                        if (isprint(data[i]))
723                                YAHOO_CALLBACK(ext_yahoo_log)(" %c ", data[i]);
724                        else
725                                YAHOO_CALLBACK(ext_yahoo_log)(" . ");
726                }
727                YAHOO_CALLBACK(ext_yahoo_log)("\n");
728        }
729}
730
731/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
732static void to_y64(unsigned char *out, const unsigned char *in, int inlen)
733{
734        base64_encode_real(in, inlen, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-");
735}
736
737static void yahoo_add_to_send_queue(struct yahoo_input_data *yid, void *data, int length)
738{
739        struct data_queue *tx = y_new0(struct data_queue, 1);
740        tx->queue = y_new0(unsigned char, length);
741        tx->len = length;
742        memcpy(tx->queue, data, length);
743
744        yid->txqueues = y_list_append(yid->txqueues, tx);
745
746        if(!yid->write_tag)
747                yid->write_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_WRITE, yid);
748}
749
750static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet *pkt, int extra_pad)
751{
752        int pktlen = yahoo_packet_length(pkt);
753        int len = YAHOO_PACKET_HDRLEN + pktlen;
754
755        unsigned char *data;
756        int pos = 0;
757
758        if (yid->fd < 0)
759                return;
760
761        data = y_new0(unsigned char, len + 1);
762
763        memcpy(data + pos, "YMSG", 4); pos += 4;
764        pos += yahoo_put16(data + pos, YAHOO_PROTO_VER);
765        pos += yahoo_put16(data + pos, 0x0000);
766        pos += yahoo_put16(data + pos, pktlen + extra_pad);
767        pos += yahoo_put16(data + pos, pkt->service);
768        pos += yahoo_put32(data + pos, pkt->status);
769        pos += yahoo_put32(data + pos, pkt->id);
770
771        yahoo_packet_write(pkt, data + pos);
772
773        yahoo_packet_dump(data, len);
774       
775        if( yid->type == YAHOO_CONNECTION_FT )
776                yahoo_send_data(yid->fd, data, len);
777        else
778        yahoo_add_to_send_queue(yid, data, len);
779        FREE(data);
780}
781
782static void yahoo_packet_free(struct yahoo_packet *pkt)
783{
784        while (pkt->hash) {
785                struct yahoo_pair *pair = pkt->hash->data;
786                YList *tmp;
787                FREE(pair->value);
788                FREE(pair);
789                tmp = pkt->hash;
790                pkt->hash = y_list_remove_link(pkt->hash, pkt->hash);
791                y_list_free_1(tmp);
792        }
793        FREE(pkt);
794}
795
796static int yahoo_send_data(int fd, void *data, int len)
797{
798        int ret;
799        int e;
800
801        if (fd < 0)
802                return -1;
803
804        yahoo_packet_dump(data, len);
805
806        do {
807                ret = write(fd, data, len);
808        } while(ret == -1 && errno==EINTR);
809        e=errno;
810
811        if (ret == -1)  {
812                LOG(("wrote data: ERR %s", strerror(errno)));
813        } else {
814                LOG(("wrote data: OK"));
815        }
816
817        errno=e;
818        return ret;
819}
820
821void yahoo_close(int id) 
822{
823        struct yahoo_data *yd = find_conn_by_id(id);
824       
825        if(!yd)
826                return;
827
828        del_from_list(yd);
829
830        yahoo_free_data(yd);
831        if(id == last_id)
832                last_id--;
833}
834
835static void yahoo_input_close(struct yahoo_input_data *yid) 
836{
837        inputs = y_list_remove(inputs, yid);
838
839        LOG(("yahoo_input_close(read)")); 
840        YAHOO_CALLBACK(ext_yahoo_remove_handler)(yid->yd->client_id, yid->read_tag);
841        LOG(("yahoo_input_close(write)")); 
842        YAHOO_CALLBACK(ext_yahoo_remove_handler)(yid->yd->client_id, yid->write_tag);
843        yid->read_tag = yid->write_tag = 0;
844        if(yid->fd)
845                close(yid->fd);
846        yid->fd = 0;
847        FREE(yid->rxqueue);
848        if(count_inputs_with_id(yid->yd->client_id) == 0) {
849                LOG(("closing %d", yid->yd->client_id));
850                yahoo_close(yid->yd->client_id);
851        }
852        yahoo_free_webcam(yid->wcm);
853        if(yid->wcd)
854                FREE(yid->wcd);
855        if(yid->ys) {
856                FREE(yid->ys->lsearch_text);
857                FREE(yid->ys);
858        }
859        FREE(yid);
860}
861
862static int is_same_bud(const void * a, const void * b) {
863        const struct yahoo_buddy *subject = a;
864        const struct yahoo_buddy *object = b;
865
866        return strcmp(subject->id, object->id);
867}
868
869static YList * bud_str2list(char *rawlist)
870{
871        YList * l = NULL;
872
873        char **lines;
874        char **split;
875        char **buddies;
876        char **tmp, **bud;
877
878        lines = y_strsplit(rawlist, "\n", -1);
879        for (tmp = lines; *tmp; tmp++) {
880                struct yahoo_buddy *newbud;
881
882                split = y_strsplit(*tmp, ":", 2);
883                if (!split)
884                        continue;
885                if (!split[0] || !split[1]) {
886                        y_strfreev(split);
887                        continue;
888                }
889                buddies = y_strsplit(split[1], ",", -1);
890
891                for (bud = buddies; bud && *bud; bud++) {
892                        newbud = y_new0(struct yahoo_buddy, 1);
893                        newbud->id = strdup(*bud);
894                        newbud->group = strdup(split[0]);
895
896                        if(y_list_find_custom(l, newbud, is_same_bud)) {
897                                FREE(newbud->id);
898                                FREE(newbud->group);
899                                FREE(newbud);
900                                continue;
901                        }
902
903                        newbud->real_name = NULL;
904
905                        l = y_list_append(l, newbud);
906
907                        NOTICE(("Added buddy %s to group %s", newbud->id, newbud->group));
908                }
909
910                y_strfreev(buddies);
911                y_strfreev(split);
912        }
913        y_strfreev(lines);
914
915        return l;
916}
917
918static char * getcookie(char *rawcookie)
919{
920        char * cookie=NULL;
921        char * tmpcookie; 
922        char * cookieend;
923
924        if (strlen(rawcookie) < 2) 
925                return NULL;
926
927        tmpcookie = strdup(rawcookie+2);
928        cookieend = strchr(tmpcookie, ';');
929
930        if(cookieend)
931                *cookieend = '\0';
932
933        cookie = strdup(tmpcookie);
934        FREE(tmpcookie);
935        /* cookieend=NULL;  not sure why this was there since the value is not preserved in the stack -dd */
936
937        return cookie;
938}
939
940static char * getlcookie(char *cookie)
941{
942        char *tmp;
943        char *tmpend;
944        char *login_cookie = NULL;
945
946        tmpend = strstr(cookie, "n=");
947        if(tmpend) {
948                tmp = strdup(tmpend+2);
949                tmpend = strchr(tmp, '&');
950                if(tmpend)
951                        *tmpend='\0';
952                login_cookie = strdup(tmp);
953                FREE(tmp);
954        }
955
956        return login_cookie;
957}
958
959static void yahoo_process_notify(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
960{
961        struct yahoo_data *yd = yid->yd;
962        char *msg = NULL;
963        char *from = NULL;
964        char *to = NULL;
965        int stat = 0;
966        int accept = 0;
967        char *ind = NULL;
968        YList *l;
969        for (l = pkt->hash; l; l = l->next) {
970                struct yahoo_pair *pair = l->data;
971                if (pair->key == 4)
972                        from = pair->value;
973                if (pair->key == 5)
974                        to = pair->value;
975                if (pair->key == 49)
976                        msg = pair->value;
977                if (pair->key == 13)
978                        stat = atoi(pair->value);
979                if (pair->key == 14)
980                        ind = pair->value;
981                if (pair->key == 16) {  /* status == -1 */
982                        NOTICE((pair->value));
983                        return;
984                }
985
986        }
987
988        if (!msg)
989                return;
990       
991        if (!strncasecmp(msg, "TYPING", strlen("TYPING"))) 
992                YAHOO_CALLBACK(ext_yahoo_typing_notify)(yd->client_id, to, from, stat);
993        else if (!strncasecmp(msg, "GAME", strlen("GAME"))) 
994                YAHOO_CALLBACK(ext_yahoo_game_notify)(yd->client_id, to, from, stat);
995        else if (!strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) 
996        {
997                if (!strcmp(ind, " ")) {
998                        YAHOO_CALLBACK(ext_yahoo_webcam_invite)(yd->client_id, to, from);
999                } else {
1000                        accept = atoi(ind);
1001                        /* accept the invitation (-1 = deny 1 = accept) */
1002                        if (accept < 0)
1003                                accept = 0;
1004                        YAHOO_CALLBACK(ext_yahoo_webcam_invite_reply)(yd->client_id, to, from, accept);
1005                }
1006        }
1007        else
1008                LOG(("Got unknown notification: %s", msg));
1009}
1010
1011static void yahoo_process_filetransfer(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1012{
1013        struct yahoo_data *yd = yid->yd;
1014        char *from=NULL;
1015        char *to=NULL;
1016        char *msg=NULL;
1017        char *url=NULL;
1018        long expires=0;
1019
1020        char *service=NULL;
1021
1022        char *filename=NULL;
1023        unsigned long filesize=0L;
1024
1025        YList *l;
1026        for (l = pkt->hash; l; l = l->next) {
1027                struct yahoo_pair *pair = l->data;
1028                if (pair->key == 4)
1029                        from = pair->value;
1030                if (pair->key == 5)
1031                        to = pair->value;
1032                if (pair->key == 14)
1033                        msg = pair->value;
1034                if (pair->key == 20)
1035                        url = pair->value;
1036                if (pair->key == 38)
1037                        expires = atol(pair->value);
1038
1039                if (pair->key == 27)
1040                        filename = pair->value;
1041                if (pair->key == 28)
1042                        filesize = atol(pair->value);
1043
1044                if (pair->key == 49)
1045                        service = pair->value;
1046        }
1047
1048        if(pkt->service == YAHOO_SERVICE_P2PFILEXFER) {
1049                if(strcmp("FILEXFER", service) != 0) {
1050                        WARNING(("unhandled service 0x%02x", pkt->service));
1051                        yahoo_dump_unhandled(pkt);
1052                        return;
1053                }
1054        }
1055
1056        if(msg) {
1057                char *tmp;
1058                tmp = strchr(msg, '\006');
1059                if(tmp)
1060                        *tmp = '\0';
1061        }
1062        if(url && from)
1063                YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, to, from, url, expires, msg, filename, filesize);
1064
1065}
1066
1067static void yahoo_process_conference(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1068{
1069        struct yahoo_data *yd = yid->yd;
1070        char *msg = NULL;
1071        char *host = NULL;
1072        char *who = NULL;
1073        char *room = NULL;
1074        char *id = NULL;
1075        int  utf8 = 0;
1076        YList *members = NULL;
1077        YList *l;
1078       
1079        for (l = pkt->hash; l; l = l->next) {
1080                struct yahoo_pair *pair = l->data;
1081                if (pair->key == 50)
1082                        host = pair->value;
1083               
1084                if (pair->key == 52) {          /* invite */
1085                        members = y_list_append(members, strdup(pair->value));
1086                }
1087                if (pair->key == 53)            /* logon */
1088                        who = pair->value;
1089                if (pair->key == 54)            /* decline */
1090                        who = pair->value;
1091                if (pair->key == 55)            /* unavailable (status == 2) */
1092                        who = pair->value;
1093                if (pair->key == 56)            /* logoff */
1094                        who = pair->value;
1095
1096                if (pair->key == 57)
1097                        room = pair->value;
1098
1099                if (pair->key == 58)            /* join message */
1100                        msg = pair->value;
1101                if (pair->key == 14)            /* decline/conf message */
1102                        msg = pair->value;
1103
1104                if (pair->key == 13)
1105                        ;
1106                if (pair->key == 16)            /* error */
1107                        msg = pair->value;
1108
1109                if (pair->key == 1)             /* my id */
1110                        id = pair->value;
1111                if (pair->key == 3)             /* message sender */
1112                        who = pair->value;
1113
1114                if (pair->key == 97)
1115                        utf8 = atoi(pair->value);
1116        }
1117
1118        if(!room)
1119                return;
1120
1121        if(host) {
1122                for(l = members; l; l = l->next) {
1123                        char * w = l->data;
1124                        if(!strcmp(w, host))
1125                                break;
1126                }
1127                if(!l)
1128                        members = y_list_append(members, strdup(host));
1129        }
1130        /* invite, decline, join, left, message -> status == 1 */
1131
1132        switch(pkt->service) {
1133        case YAHOO_SERVICE_CONFINVITE:
1134                if(pkt->status == 2)
1135                        ;
1136                else if(members)
1137                        YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members);
1138                else if(msg)
1139                        YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, msg, 0, E_CONFNOTAVAIL);
1140                break;
1141        case YAHOO_SERVICE_CONFADDINVITE:
1142                if(pkt->status == 2)
1143                        ;
1144                else
1145                        YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members);
1146                break;
1147        case YAHOO_SERVICE_CONFDECLINE:
1148                if(who)
1149                        YAHOO_CALLBACK(ext_yahoo_conf_userdecline)(yd->client_id, id, who, room, msg);
1150                break;
1151        case YAHOO_SERVICE_CONFLOGON:
1152                if(who)
1153                        YAHOO_CALLBACK(ext_yahoo_conf_userjoin)(yd->client_id, id, who, room);
1154                break;
1155        case YAHOO_SERVICE_CONFLOGOFF:
1156                if(who)
1157                        YAHOO_CALLBACK(ext_yahoo_conf_userleave)(yd->client_id, id, who, room);
1158                break;
1159        case YAHOO_SERVICE_CONFMSG:
1160                if(who)
1161                        YAHOO_CALLBACK(ext_yahoo_conf_message)(yd->client_id, id, who, room, msg, utf8);
1162                break;
1163        }
1164}
1165
1166static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1167{
1168        char *msg = NULL;
1169        char *id = NULL;
1170        char *who = NULL;
1171        char *room = NULL;
1172        char *topic = NULL;
1173        YList *members = NULL;
1174        struct yahoo_chat_member *currentmember = NULL;
1175        int  msgtype = 1;
1176        int  utf8 = 0;
1177        int  firstjoin = 0;
1178        int  membercount = 0;
1179        int  chaterr=0;
1180        YList *l;
1181       
1182        yahoo_dump_unhandled(pkt);
1183        for (l = pkt->hash; l; l = l->next) {
1184                struct yahoo_pair *pair = l->data;
1185
1186                if (pair->key == 1) {
1187                        /* My identity */
1188                        id = pair->value;
1189                }
1190
1191                if (pair->key == 104) {
1192                        /* Room name */
1193                        room = pair->value;
1194                }
1195
1196                if (pair->key == 105) {
1197                        /* Room topic */
1198                        topic = pair->value;
1199                }
1200
1201                if (pair->key == 108) {
1202                        /* Number of members in this packet */
1203                        membercount = atoi(pair->value);
1204                }
1205
1206                if (pair->key == 109) {
1207                        /* message sender */
1208                        who = pair->value;
1209
1210                        if (pkt->service == YAHOO_SERVICE_CHATJOIN) {
1211                                currentmember = y_new0(struct yahoo_chat_member, 1);
1212                                currentmember->id = strdup(pair->value);
1213                                members = y_list_append(members, currentmember);
1214                        }
1215                }
1216
1217                if (pair->key == 110) {
1218                        /* age */
1219                        if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1220                                currentmember->age = atoi(pair->value);
1221                }
1222
1223                if (pair->key == 113) {
1224                        /* attribs */
1225                        if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1226                                currentmember->attribs = atoi(pair->value);
1227                }
1228
1229                if (pair->key == 141) {
1230                        /* alias */
1231                        if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1232                                currentmember->alias = strdup(pair->value);
1233                }
1234
1235                if (pair->key == 142) {
1236                        /* location */
1237                        if (pkt->service == YAHOO_SERVICE_CHATJOIN)
1238                                currentmember->location = strdup(pair->value);
1239                }
1240
1241
1242                if (pair->key == 130) {
1243                        /* first join */
1244                        firstjoin = 1;
1245                }
1246
1247                if (pair->key == 117) {
1248                        /* message */
1249                        msg = pair->value;
1250                }
1251
1252                if (pair->key == 124) {
1253                        /* Message type */
1254                        msgtype = atoi(pair->value);
1255                }
1256                if (pair->key == 114) {
1257                        /* message error not sure what all the pair values mean */
1258                        /* but -1 means no session in room */
1259                        chaterr= atoi(pair->value);
1260                }
1261        }
1262
1263        if(!room) {
1264                if (pkt->service == YAHOO_SERVICE_CHATLOGOUT) { /* yahoo originated chat logout */
1265                        YAHOO_CALLBACK(ext_yahoo_chat_yahoologout)(yid->yd->client_id, id);
1266                        return ;
1267                }
1268                if (pkt->service == YAHOO_SERVICE_COMMENT && chaterr)  {
1269                        YAHOO_CALLBACK(ext_yahoo_chat_yahooerror)(yid->yd->client_id, id);
1270                        return;
1271                }
1272
1273                WARNING(("We didn't get a room name, ignoring packet"));
1274                return;
1275        }
1276
1277        switch(pkt->service) {
1278        case YAHOO_SERVICE_CHATJOIN:
1279                if(y_list_length(members) != membercount) {
1280                        WARNING(("Count of members doesn't match No. of members we got"));
1281                }
1282                if(firstjoin && members) {
1283                        YAHOO_CALLBACK(ext_yahoo_chat_join)(yid->yd->client_id, id, room, topic, members, yid->fd);
1284                } else if(who) {
1285                        if(y_list_length(members) != 1) {
1286                                WARNING(("Got more than 1 member on a normal join"));
1287                        }
1288                        /* this should only ever have one, but just in case */
1289                        while(members) {
1290                                YList *n = members->next;
1291                                currentmember = members->data;
1292                                YAHOO_CALLBACK(ext_yahoo_chat_userjoin)(yid->yd->client_id, id, room, currentmember);
1293                                y_list_free_1(members);
1294                                members=n;
1295                        }
1296                }
1297                break;
1298        case YAHOO_SERVICE_CHATEXIT:
1299                if(who) {
1300                        YAHOO_CALLBACK(ext_yahoo_chat_userleave)(yid->yd->client_id, id, room, who);
1301                }
1302                break;
1303        case YAHOO_SERVICE_COMMENT:
1304                if(who) {
1305                        YAHOO_CALLBACK(ext_yahoo_chat_message)(yid->yd->client_id, id, who, room, msg, msgtype, utf8);
1306                }
1307                break;
1308        }
1309}
1310
1311static void yahoo_process_message(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1312{
1313        struct yahoo_data *yd = yid->yd;
1314        YList *l;
1315        YList * messages = NULL;
1316
1317        struct m {
1318                int  i_31;
1319                int  i_32;
1320                char *to;
1321                char *from;
1322                long tm;
1323                char *msg;
1324                int  utf8;
1325        } *message = y_new0(struct m, 1);
1326
1327        for (l = pkt->hash; l; l = l->next) {
1328                struct yahoo_pair *pair = l->data;
1329                if (pair->key == 1 || pair->key == 4)
1330                {
1331                        if(!message->from)
1332                                message->from = pair->value;
1333                }
1334                else if (pair->key == 5)
1335                        message->to = pair->value;
1336                else if (pair->key == 15)
1337                        message->tm = strtol(pair->value, NULL, 10);
1338                else if (pair->key == 97)
1339                        message->utf8 = atoi(pair->value);
1340                        /* user message */  /* sys message */
1341                else if (pair->key == 14 || pair->key == 16)
1342                        message->msg = pair->value;
1343                else if (pair->key == 31) {
1344                        if(message->i_31) {
1345                                messages = y_list_append(messages, message);
1346                                message = y_new0(struct m, 1);
1347                        }
1348                        message->i_31 = atoi(pair->value);
1349                }
1350                else if (pair->key == 32)
1351                        message->i_32 = atoi(pair->value);
1352                else
1353                        LOG(("yahoo_process_message: status: %d, key: %d, value: %s",
1354                                        pkt->status, pair->key, pair->value));
1355        }
1356
1357        messages = y_list_append(messages, message);
1358
1359        for (l = messages; l; l=l->next) {
1360                message = l->data;
1361                if (pkt->service == YAHOO_SERVICE_SYSMESSAGE) {
1362                        YAHOO_CALLBACK(ext_yahoo_system_message)(yd->client_id, message->msg);
1363                } else if (pkt->status <= 2 || pkt->status == 5) {
1364                        YAHOO_CALLBACK(ext_yahoo_got_im)(yd->client_id, message->to, message->from, message->msg, message->tm, pkt->status, message->utf8);
1365                } else if (pkt->status == 0xffffffff) {
1366                        YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, message->msg, 0, E_SYSTEM);
1367                }
1368                free(message);
1369        }
1370
1371        y_list_free(messages);
1372}
1373
1374
1375static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1376{
1377        YList *l;
1378        struct yahoo_data *yd = yid->yd;
1379
1380        struct user
1381        {
1382                char *name;     /* 7    name */
1383                int   state;    /* 10   state */
1384                int   flags;    /* 13   flags, bit 0 = pager, bit 1 = chat, bit 2 = game */
1385                int   mobile;   /* 60   mobile */
1386                char *msg;      /* 19   custom status message */
1387                int   away;     /* 47   away (or invisible)*/
1388                int   buddy_session;    /* 11   state */
1389                int   f17;      /* 17   in chat? then what about flags? */
1390                int   idle;     /* 137  seconds idle */
1391                int   f138;     /* 138  state */
1392                char *f184;     /* 184  state */
1393                int   f192;     /* 192  state */
1394                int   f10001;   /* 10001        state */
1395                int   f10002;   /* 10002        state */
1396                int   f198;     /* 198  state */
1397                char *f197;     /* 197  state */
1398                char *f205;     /* 205  state */
1399                int   f213;     /* 213  state */
1400        } *u;
1401
1402        YList *users = 0;
1403       
1404        if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
1405                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_DUPL, NULL);
1406                return;
1407        }
1408
1409        for (l = pkt->hash; l; l = l->next) {
1410                struct yahoo_pair *pair = l->data;
1411
1412                switch (pair->key) {
1413                case 0: /* we won't actually do anything with this */
1414                        NOTICE(("key %d:%s", pair->key, pair->value));
1415                        break;
1416                case 1: /* we don't get the full buddy list here. */
1417                        if (!yd->logged_in) {
1418                                yd->logged_in = TRUE;
1419                                if(yd->current_status < 0)
1420                                        yd->current_status = yd->initial_status;
1421                                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
1422                        }
1423                        break;
1424                case 8: /* how many online buddies we have */
1425                        NOTICE(("key %d:%s", pair->key, pair->value));
1426                        break;
1427                case 7: /* the current buddy */
1428                        u = y_new0(struct user, 1);
1429                        u->name = pair->value;
1430                        users = y_list_prepend(users, u);
1431                        break;
1432                case 10: /* state */
1433                        ((struct user*)users->data)->state = strtol(pair->value, NULL, 10);
1434                        break;
1435                case 19: /* custom status message */
1436                        ((struct user*)users->data)->msg = pair->value;
1437                        break;
1438                case 47: /* is it an away message or not */
1439                        ((struct user*)users->data)->away = atoi(pair->value);
1440                        break;
1441                case 137: /* seconds idle */
1442                        ((struct user*)users->data)->idle = atoi(pair->value);
1443                        break;
1444                case 11: /* this is the buddy's session id */
1445                        ((struct user*)users->data)->buddy_session = atoi(pair->value);
1446                        break;
1447                case 17: /* in chat? */
1448                        ((struct user*)users->data)->f17 = atoi(pair->value);
1449                        break;
1450                case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
1451                        ((struct user*)users->data)->flags = atoi(pair->value);
1452                        break;
1453                case 60: /* SMS -> 1 MOBILE USER */
1454                        /* sometimes going offline makes this 2, but invisible never sends it */
1455                        ((struct user*)users->data)->mobile = atoi(pair->value);
1456                        break;
1457                case 138:
1458                        ((struct user*)users->data)->f138 = atoi(pair->value);
1459                        break;
1460                case 184:
1461                        ((struct user*)users->data)->f184 = pair->value;
1462                        break;
1463                case 192:
1464                        ((struct user*)users->data)->f192 = atoi(pair->value);
1465                        break;
1466                case 10001:
1467                        ((struct user*)users->data)->f10001 = atoi(pair->value);
1468                        break;
1469                case 10002:
1470                        ((struct user*)users->data)->f10002 = atoi(pair->value);
1471                        break;
1472                case 198:
1473                        ((struct user*)users->data)->f198 = atoi(pair->value);
1474                        break;
1475                case 197:
1476                        ((struct user*)users->data)->f197 = pair->value;
1477                        break;
1478                case 205:
1479                        ((struct user*)users->data)->f205 = pair->value;
1480                        break;
1481                case 213:
1482                        ((struct user*)users->data)->f213 = atoi(pair->value);
1483                        break;
1484                case 16: /* Custom error message */
1485                        YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0, E_CUSTOM);
1486                        break;
1487                default:
1488                        WARNING(("unknown status key %d:%s", pair->key, pair->value));
1489                        break;
1490                }
1491        }
1492       
1493        while (users) {
1494                YList *t = users;
1495                struct user *u = users->data;
1496
1497                if (u->name != NULL) {
1498                        if (pkt->service == YAHOO_SERVICE_LOGOFF || u->flags == 0) {
1499                                YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0);
1500                        } else {
1501                                YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, u->state, u->msg, u->away, u->idle, u->mobile);
1502                        }
1503                }
1504
1505                users = y_list_remove_link(users, users);
1506                y_list_free_1(t);
1507                FREE(u);
1508        }
1509}
1510
1511static void yahoo_process_buddy_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1512{
1513        struct yahoo_data *yd = yid->yd;
1514        YList *l;
1515        int last_packet = 0;
1516        char *cur_group = NULL;
1517        struct yahoo_buddy *newbud = NULL;
1518
1519        /* we could be getting multiple packets here */
1520        for (l = pkt->hash; l; l = l->next) {
1521                struct yahoo_pair *pair = l->data;
1522
1523                switch(pair->key) {
1524                case 300:
1525                case 301:
1526                case 302:
1527                case 303:
1528                        if ( 315 == atoi(pair->value) )
1529                                last_packet = 1;
1530                        break;
1531                case 65:
1532                        g_free(cur_group);
1533                        cur_group = strdup(pair->value);
1534                        break;
1535                case 7:
1536                        newbud = y_new0(struct yahoo_buddy, 1);
1537                        newbud->id = strdup(pair->value);
1538                        if(cur_group)
1539                                newbud->group = strdup(cur_group);
1540                        else {
1541                                struct yahoo_buddy *lastbud = (struct yahoo_buddy *)y_list_nth(
1542                                                                yd->buddies, y_list_length(yd->buddies)-1)->data;
1543                                newbud->group = strdup(lastbud->group);
1544                        }
1545
1546                        yd->buddies = y_list_append(yd->buddies, newbud);
1547
1548                        break;
1549                }
1550        }
1551       
1552        g_free(cur_group);
1553
1554        /* we could be getting multiple packets here */
1555        if (last_packet)
1556                return;
1557
1558        YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
1559
1560        /*** We login at the very end of the packet communication */
1561        if (!yd->logged_in) {
1562                yd->logged_in = TRUE;
1563                if(yd->current_status < 0)
1564                        yd->current_status = yd->initial_status;
1565                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
1566        }
1567}
1568
1569static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1570{
1571        struct yahoo_data *yd = yid->yd;
1572        YList *l;
1573
1574        if (!yd->logged_in) {
1575                yd->logged_in = TRUE;
1576                if(yd->current_status < 0)
1577                        yd->current_status = yd->initial_status;
1578                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
1579        }
1580
1581        for (l = pkt->hash; l; l = l->next) {
1582                struct yahoo_pair *pair = l->data;
1583
1584                switch(pair->key) {
1585                case 87: /* buddies */
1586                        if(!yd->rawbuddylist)
1587                                yd->rawbuddylist = strdup(pair->value);
1588                        else {
1589                                yd->rawbuddylist = y_string_append(yd->rawbuddylist, pair->value);
1590                        }
1591                        break;
1592
1593                case 88: /* ignore list */
1594                        if(!yd->ignorelist)
1595                                yd->ignorelist = strdup("Ignore:");
1596                        yd->ignorelist = y_string_append(yd->ignorelist, pair->value);
1597                        break;
1598
1599                case 89: /* identities */
1600                        {
1601                        char **identities = y_strsplit(pair->value, ",", -1);
1602                        int i;
1603                        for(i=0; identities[i]; i++)
1604                                yd->identities = y_list_append(yd->identities, 
1605                                                strdup(identities[i]));
1606                        y_strfreev(identities);
1607                        }
1608                        YAHOO_CALLBACK(ext_yahoo_got_identities)(yd->client_id, yd->identities);
1609                        break;
1610                case 59: /* cookies */
1611                        if(yd->ignorelist) {
1612                                yd->ignore = bud_str2list(yd->ignorelist);
1613                                FREE(yd->ignorelist);
1614                                YAHOO_CALLBACK(ext_yahoo_got_ignore)(yd->client_id, yd->ignore);
1615                        }
1616                        if(yd->rawbuddylist) {
1617                                yd->buddies = bud_str2list(yd->rawbuddylist);
1618                                FREE(yd->rawbuddylist);
1619                                YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
1620                        }
1621
1622                        if(pair->value[0]=='Y') {
1623                                FREE(yd->cookie_y);
1624                                FREE(yd->login_cookie);
1625
1626                                yd->cookie_y = getcookie(pair->value);
1627                                yd->login_cookie = getlcookie(yd->cookie_y);
1628
1629                        } else if(pair->value[0]=='T') {
1630                                FREE(yd->cookie_t);
1631                                yd->cookie_t = getcookie(pair->value);
1632
1633                        } else if(pair->value[0]=='C') {
1634                                FREE(yd->cookie_c);
1635                                yd->cookie_c = getcookie(pair->value);
1636                        } 
1637
1638                        if(yd->cookie_y && yd->cookie_t)
1639                                YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id);
1640
1641                        break;
1642                case 3: /* my id */
1643                case 90: /* 1 */
1644                case 100: /* 0 */
1645                case 101: /* NULL */
1646                case 102: /* NULL */
1647                case 93: /* 86400/1440 */
1648                        break;
1649                }
1650        }
1651}
1652
1653static void yahoo_process_verify(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1654{
1655        struct yahoo_data *yd = yid->yd;
1656
1657        if(pkt->status != 0x01) {
1658                DEBUG_MSG(("expected status: 0x01, got: %d", pkt->status));
1659                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOCK, "");
1660                return;
1661        }
1662
1663        pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
1664
1665        yahoo_packet_hash(pkt, 1, yd->user);
1666        yahoo_send_packet(yid, pkt, 0);
1667
1668        yahoo_packet_free(pkt);
1669
1670}
1671
1672static void yahoo_process_picture_checksum( struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1673{
1674        struct yahoo_data *yd = yid->yd;
1675        char *from = NULL;
1676        char *to = NULL;
1677        int checksum = 0;
1678        YList *l;
1679
1680        for(l = pkt->hash; l; l = l->next)
1681        {
1682                struct yahoo_pair *pair = l->data;
1683
1684                switch(pair->key)
1685                {
1686                        case 1:
1687                        case 4:
1688                                from = pair->value;
1689                        case 5:
1690                                to = pair->value;
1691                                break;
1692                        case 212:
1693                                break;
1694                        case 192:
1695                                checksum = atoi( pair->value );
1696                                break;
1697                }
1698        }
1699
1700        YAHOO_CALLBACK(ext_yahoo_got_buddyicon_checksum)(yd->client_id,to,from,checksum);
1701}
1702
1703static void yahoo_process_picture(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1704{
1705        struct yahoo_data *yd = yid->yd;
1706        char *url = NULL;
1707        char *from = NULL;
1708        char *to = NULL;
1709        int status = 0;
1710        int checksum = 0;
1711        YList *l;
1712       
1713        for(l = pkt->hash; l; l = l->next)
1714        {
1715                struct yahoo_pair *pair = l->data;
1716
1717                switch(pair->key)
1718                {
1719                case 1:
1720                case 4:         /* sender */
1721                        from = pair->value;
1722                        break;
1723                case 5:         /* we */
1724                        to = pair->value;
1725                        break;
1726                case 13:                /* request / sending */
1727                        status = atoi( pair->value );
1728                        break;
1729                case 20:                /* url */
1730                        url = pair->value;
1731                        break;
1732                case 192:       /*checksum */
1733                        checksum = atoi( pair->value );
1734                        break;
1735                }
1736        }
1737
1738        switch( status )
1739        {
1740                case 1: /* this is a request, ignore for now */
1741                        YAHOO_CALLBACK(ext_yahoo_got_buddyicon_request)(yd->client_id, to, from);
1742                        break;
1743                case 2: /* this is cool - we get a picture :) */
1744                        YAHOO_CALLBACK(ext_yahoo_got_buddyicon)(yd->client_id,to, from, url, checksum);
1745                        break;
1746        }
1747}
1748
1749static void yahoo_process_picture_upload(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1750{
1751        struct yahoo_data *yd = yid->yd;
1752        YList *l;
1753        char *url = NULL;
1754
1755        if ( pkt->status != 1 )
1756                return;         /* something went wrong */
1757       
1758        for(l = pkt->hash; l; l = l->next)
1759        {
1760                struct yahoo_pair *pair = l->data;
1761
1762                switch(pair->key)
1763                {
1764                        case 5:         /* we */
1765                                break;
1766                        case 20:                /* url */
1767                                url = pair->value;
1768                                break;
1769                        case 27:                /* local filename */
1770                                break;
1771                        case 38:                /* time */
1772                                break;
1773                }
1774        }
1775
1776        YAHOO_CALLBACK(ext_yahoo_buddyicon_uploaded)(yd->client_id, url);
1777}
1778
1779static void yahoo_process_auth_pre_0x0b(struct yahoo_input_data *yid, 
1780                const char *seed, const char *sn)
1781{
1782        struct yahoo_data *yd = yid->yd;
1783       
1784        /* So, Yahoo has stopped supporting its older clients in India, and
1785         * undoubtedly will soon do so in the rest of the world.
1786         *
1787         * The new clients use this authentication method.  I warn you in
1788         * advance, it's bizzare, convoluted, inordinately complicated. 
1789         * It's also no more secure than crypt() was.  The only purpose this
1790         * scheme could serve is to prevent third part clients from connecting
1791         * to their servers.
1792         *
1793         * Sorry, Yahoo.
1794         */
1795
1796        struct yahoo_packet *pack;
1797       
1798        md5_byte_t result[16];
1799        md5_state_t ctx;
1800        char *crypt_result;
1801        unsigned char *password_hash = malloc(25);
1802        unsigned char *crypt_hash = malloc(25);
1803        unsigned char *hash_string_p = malloc(50 + strlen(sn));
1804        unsigned char *hash_string_c = malloc(50 + strlen(sn));
1805       
1806        char checksum;
1807       
1808        int sv;
1809       
1810        unsigned char *result6 = malloc(25);
1811        unsigned char *result96 = malloc(25);
1812
1813        sv = seed[15];
1814        sv = (sv % 8) % 5;
1815
1816        md5_init(&ctx);
1817        md5_append(&ctx, (md5_byte_t *)yd->password, strlen(yd->password));
1818        md5_finish(&ctx, result);
1819        to_y64(password_hash, result, 16);
1820       
1821        md5_init(&ctx);
1822        crypt_result = yahoo_crypt(yd->password, "$1$_2S43d5f$"); 
1823        md5_append(&ctx, (md5_byte_t *)crypt_result, strlen(crypt_result));
1824        md5_finish(&ctx, result);
1825        to_y64(crypt_hash, result, 16);
1826        free(crypt_result);
1827
1828        switch (sv) {
1829        case 0:
1830                checksum = seed[seed[7] % 16];
1831                snprintf((char *)hash_string_p, strlen(sn) + 50,
1832                        "%c%s%s%s", checksum, password_hash, yd->user, seed);
1833                snprintf((char *)hash_string_c, strlen(sn) + 50,
1834                        "%c%s%s%s", checksum, crypt_hash, yd->user, seed);
1835                break;
1836        case 1:
1837                checksum = seed[seed[9] % 16];
1838                snprintf((char *)hash_string_p, strlen(sn) + 50,
1839                        "%c%s%s%s", checksum, yd->user, seed, password_hash);
1840                snprintf((char *)hash_string_c, strlen(sn) + 50,
1841                        "%c%s%s%s", checksum, yd->user, seed, crypt_hash);
1842                break;
1843        case 2:
1844                checksum = seed[seed[15] % 16];
1845                snprintf((char *)hash_string_p, strlen(sn) + 50,
1846                        "%c%s%s%s", checksum, seed, password_hash, yd->user);
1847                snprintf((char *)hash_string_c, strlen(sn) + 50,
1848                        "%c%s%s%s", checksum, seed, crypt_hash, yd->user);
1849                break;
1850        case 3:
1851                checksum = seed[seed[1] % 16];
1852                snprintf((char *)hash_string_p, strlen(sn) + 50,
1853                        "%c%s%s%s", checksum, yd->user, password_hash, seed);
1854                snprintf((char *)hash_string_c, strlen(sn) + 50,
1855                        "%c%s%s%s", checksum, yd->user, crypt_hash, seed);
1856                break;
1857        case 4:
1858                checksum = seed[seed[3] % 16];
1859                snprintf((char *)hash_string_p, strlen(sn) + 50,
1860                        "%c%s%s%s", checksum, password_hash, seed, yd->user);
1861                snprintf((char *)hash_string_c, strlen(sn) + 50,
1862                        "%c%s%s%s", checksum, crypt_hash, seed, yd->user);
1863                break;
1864        }
1865               
1866        md5_init(&ctx); 
1867        md5_append(&ctx, (md5_byte_t *)hash_string_p, strlen((char *)hash_string_p));
1868        md5_finish(&ctx, result);
1869        to_y64(result6, result, 16);
1870
1871        md5_init(&ctx); 
1872        md5_append(&ctx, (md5_byte_t *)hash_string_c, strlen((char *)hash_string_c));
1873        md5_finish(&ctx, result);
1874        to_y64(result96, result, 16);
1875
1876        pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
1877        yahoo_packet_hash(pack, 0, yd->user);
1878        yahoo_packet_hash(pack, 6, (char *)result6);
1879        yahoo_packet_hash(pack, 96, (char *)result96);
1880        yahoo_packet_hash(pack, 1, yd->user);
1881               
1882        yahoo_send_packet(yid, pack, 0);
1883               
1884        FREE(result6);
1885        FREE(result96);
1886        FREE(password_hash);
1887        FREE(crypt_hash);
1888        FREE(hash_string_p);
1889        FREE(hash_string_c);
1890
1891        yahoo_packet_free(pack);
1892
1893}
1894
1895/*
1896 * New auth protocol cracked by Cerulean Studios and sent in to Gaim
1897 */
1898static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *seed, const char *sn)
1899{
1900        struct yahoo_packet *pack = NULL;
1901        struct yahoo_data *yd = yid->yd;
1902
1903        md5_byte_t         result[16];
1904        md5_state_t        ctx;
1905
1906        sha1_state_t       ctx1;
1907        sha1_state_t       ctx2;
1908
1909        char *alphabet1 = "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ";
1910        char *alphabet2 = "F0E1D2C3B4A59687abcdefghijklmnop";
1911
1912        char *challenge_lookup = "qzec2tb3um1olpar8whx4dfgijknsvy5";
1913        char *operand_lookup = "+|&%/*^-";
1914        char *delimit_lookup = ",;";
1915
1916        unsigned char *password_hash = malloc(25);
1917        unsigned char *crypt_hash = malloc(25);
1918        char *crypt_result = NULL;
1919        unsigned char pass_hash_xor1[64];
1920        unsigned char pass_hash_xor2[64];
1921        unsigned char crypt_hash_xor1[64];
1922        unsigned char crypt_hash_xor2[64];
1923        unsigned char chal[7];
1924        char resp_6[100];
1925        char resp_96[100];
1926
1927        unsigned char digest1[20];
1928        unsigned char digest2[20];
1929        unsigned char magic_key_char[4];
1930        const unsigned char *magic_ptr;
1931
1932        unsigned int  magic[64];
1933        unsigned int  magic_work=0;
1934
1935        char comparison_src[20];
1936
1937        int x, j, i;
1938        int cnt = 0;
1939        int magic_cnt = 0;
1940        int magic_len;
1941        int depth =0, table =0;
1942
1943        memset(&pass_hash_xor1, 0, 64);
1944        memset(&pass_hash_xor2, 0, 64);
1945        memset(&crypt_hash_xor1, 0, 64);
1946        memset(&crypt_hash_xor2, 0, 64);
1947        memset(&digest1, 0, 20);
1948        memset(&digest2, 0, 20);
1949        memset(&magic, 0, 64);
1950        memset(&resp_6, 0, 100);
1951        memset(&resp_96, 0, 100);
1952        memset(&magic_key_char, 0, 4);
1953
1954        /*
1955         * Magic: Phase 1.  Generate what seems to be a 30
1956         * byte value (could change if base64
1957         * ends up differently?  I don't remember and I'm
1958         * tired, so use a 64 byte buffer.
1959         */
1960
1961        magic_ptr = (unsigned char *)seed;
1962
1963        while (*magic_ptr != 0) {
1964                char *loc;
1965
1966                /* Ignore parentheses.  */
1967
1968                if (*magic_ptr == '(' || *magic_ptr == ')') {
1969                        magic_ptr++;
1970                        continue;
1971                }
1972
1973                /* Characters and digits verify against
1974                   the challenge lookup.
1975                */
1976
1977                if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) {
1978                        loc = strchr(challenge_lookup, *magic_ptr);
1979                        if (!loc) {
1980                                /* This isn't good */
1981                                continue;
1982                        }
1983
1984                        /* Get offset into lookup table and lsh 3. */
1985
1986                        magic_work = loc - challenge_lookup;
1987                        magic_work <<= 3;
1988
1989                        magic_ptr++;
1990                        continue;
1991                } else {
1992                        unsigned int local_store;
1993
1994                        loc = strchr(operand_lookup, *magic_ptr);
1995                        if (!loc) {
1996                                /* Also not good. */
1997                                continue;
1998                        }
1999
2000                        local_store = loc - operand_lookup;
2001
2002                        /* Oops; how did this happen? */
2003                        if (magic_cnt >= 64) 
2004                                break;
2005
2006                        magic[magic_cnt++] = magic_work | local_store;
2007                        magic_ptr++;
2008                        continue;
2009                }
2010        }
2011
2012        magic_len = magic_cnt;
2013        magic_cnt = 0;
2014
2015        /* Magic: Phase 2.  Take generated magic value and
2016         * sprinkle fairy dust on the values. */
2017
2018        for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) {
2019                unsigned char byte1;
2020                unsigned char byte2;
2021
2022                /* Bad.  Abort.
2023                 */
2024                if (magic_cnt >= magic_len) {
2025                        WARNING(("magic_cnt(%d)  magic_len(%d)", magic_cnt, magic_len))
2026                        break;
2027                }
2028
2029                byte1 = magic[magic_cnt];
2030                byte2 = magic[magic_cnt+1];
2031
2032                byte1 *= 0xcd;
2033                byte1 ^= byte2;
2034
2035                magic[magic_cnt+1] = byte1;
2036        }
2037
2038        /* Magic: Phase 3.  This computes 20 bytes.  The first 4 bytes are used as our magic
2039         * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key
2040         * plus 3 bytes.  The 3 bytes are found by looping, and they represent the offsets
2041         * into particular functions we'll later call to potentially alter the magic key.
2042         *
2043         * %-)
2044         */ 
2045       
2046        magic_cnt = 1; 
2047        x = 0; 
2048       
2049        do { 
2050                unsigned int     bl = 0; 
2051                unsigned int     cl = magic[magic_cnt++]; 
2052               
2053                if (magic_cnt >= magic_len) 
2054                        break; 
2055               
2056                if (cl > 0x7F) { 
2057                        if (cl < 0xe0) 
2058                                bl = cl = (cl & 0x1f) << 6; 
2059                        else { 
2060                                bl = magic[magic_cnt++]; 
2061                              cl = (cl & 0x0f) << 6; 
2062                              bl = ((bl & 0x3f) + cl) << 6; 
2063                        } 
2064                       
2065                        cl = magic[magic_cnt++]; 
2066                        bl = (cl & 0x3f) + bl; 
2067                } else 
2068                        bl = cl; 
2069               
2070                comparison_src[x++] = (bl & 0xff00) >> 8; 
2071                comparison_src[x++] = bl & 0xff; 
2072        } while (x < 20); 
2073
2074        /* Dump magic key into a char for SHA1 action. */
2075       
2076               
2077        for(x = 0; x < 4; x++) 
2078                magic_key_char[x] = comparison_src[x];
2079
2080        /* Compute values for recursive function table! */
2081        memcpy( chal, magic_key_char, 4 );
2082        x = 1;
2083        for( i = 0; i < 0xFFFF && x; i++ )
2084        {
2085                for( j = 0; j < 5 && x; j++ )
2086                {
2087                        chal[4] = i;
2088                        chal[5] = i >> 8;
2089                        chal[6] = j;
2090                        md5_init( &ctx );
2091                        md5_append( &ctx, chal, 7 );
2092                        md5_finish( &ctx, result );
2093                        if( memcmp( comparison_src + 4, result, 16 ) == 0 )
2094                        {
2095                                depth = i;
2096                                table = j;
2097                                x = 0;
2098                        }
2099                }
2100        }
2101
2102        /* Transform magic_key_char using transform table */
2103        x = magic_key_char[3] << 24  | magic_key_char[2] << 16 
2104                | magic_key_char[1] << 8 | magic_key_char[0];
2105        x = yahoo_xfrm( table, depth, x );
2106        x = yahoo_xfrm( table, depth, x );
2107        magic_key_char[0] = x & 0xFF;
2108        magic_key_char[1] = x >> 8 & 0xFF;
2109        magic_key_char[2] = x >> 16 & 0xFF;
2110        magic_key_char[3] = x >> 24 & 0xFF;
2111
2112        /* Get password and crypt hashes as per usual. */
2113        md5_init(&ctx);
2114        md5_append(&ctx, (md5_byte_t *)yd->password,  strlen(yd->password));
2115        md5_finish(&ctx, result);
2116        to_y64(password_hash, result, 16);
2117
2118        md5_init(&ctx);
2119        crypt_result = yahoo_crypt(yd->password, "$1$_2S43d5f$"); 
2120        md5_append(&ctx, (md5_byte_t *)crypt_result, strlen(crypt_result));
2121        md5_finish(&ctx, result);
2122        to_y64(crypt_hash, result, 16);
2123        free(crypt_result);
2124
2125        /* Our first authentication response is based off
2126         * of the password hash. */
2127
2128        for (x = 0; x < (int)strlen((char *)password_hash); x++) 
2129                pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36;
2130
2131        if (cnt < 64) 
2132                memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt);
2133
2134        cnt = 0;
2135
2136        for (x = 0; x < (int)strlen((char *)password_hash); x++) 
2137                pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c;
2138
2139        if (cnt < 64) 
2140                memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt);
2141
2142        sha1_init(&ctx1);
2143        sha1_init(&ctx2);
2144
2145        /* The first context gets the password hash XORed
2146         * with 0x36 plus a magic value
2147         * which we previously extrapolated from our
2148         * challenge. */
2149
2150        sha1_append(&ctx1, pass_hash_xor1, 64);
2151        if (j >= 3 )
2152                ctx1.Length_Low = 0x1ff;
2153        sha1_append(&ctx1, magic_key_char, 4);
2154        sha1_finish(&ctx1, digest1);
2155
2156         /* The second context gets the password hash XORed
2157          * with 0x5c plus the SHA-1 digest
2158          * of the first context. */
2159
2160        sha1_append(&ctx2, pass_hash_xor2, 64);
2161        sha1_append(&ctx2, digest1, 20);
2162        sha1_finish(&ctx2, digest2);
2163
2164        /* Now that we have digest2, use it to fetch
2165         * characters from an alphabet to construct
2166         * our first authentication response. */
2167
2168        for (x = 0; x < 20; x += 2) {
2169                unsigned int    val = 0;
2170                unsigned int    lookup = 0;
2171                char            byte[6];
2172
2173                memset(&byte, 0, 6);
2174
2175                /* First two bytes of digest stuffed
2176                 *  together.
2177                 */
2178
2179                val = digest2[x];
2180                val <<= 8;
2181                val += digest2[x+1];
2182
2183                lookup = (val >> 0x0b);
2184                lookup &= 0x1f;
2185                if (lookup >= strlen(alphabet1))
2186                        break;
2187                sprintf(byte, "%c", alphabet1[lookup]);
2188                strcat(resp_6, byte);
2189                strcat(resp_6, "=");
2190
2191                lookup = (val >> 0x06);
2192                lookup &= 0x1f;
2193                if (lookup >= strlen(alphabet2))
2194                        break;
2195                sprintf(byte, "%c", alphabet2[lookup]);
2196                strcat(resp_6, byte);
2197
2198                lookup = (val >> 0x01);
2199                lookup &= 0x1f;
2200                if (lookup >= strlen(alphabet2))
2201                        break;
2202                sprintf(byte, "%c", alphabet2[lookup]);
2203                strcat(resp_6, byte);
2204
2205                lookup = (val & 0x01);
2206                if (lookup >= strlen(delimit_lookup))
2207                        break;
2208                sprintf(byte, "%c", delimit_lookup[lookup]);
2209                strcat(resp_6, byte);
2210        }
2211
2212        /* Our second authentication response is based off
2213         * of the crypto hash. */
2214
2215        cnt = 0;
2216        memset(&digest1, 0, 20);
2217        memset(&digest2, 0, 20);
2218
2219        for (x = 0; x < (int)strlen((char *)crypt_hash); x++) 
2220                crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36;
2221
2222        if (cnt < 64) 
2223                memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt);
2224
2225        cnt = 0;
2226
2227        for (x = 0; x < (int)strlen((char *)crypt_hash); x++) 
2228                crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c;
2229
2230        if (cnt < 64) 
2231                memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt);
2232
2233        sha1_init(&ctx1);
2234        sha1_init(&ctx2);
2235
2236        /* The first context gets the password hash XORed
2237         * with 0x36 plus a magic value
2238         * which we previously extrapolated from our
2239         * challenge. */
2240
2241        sha1_append(&ctx1, crypt_hash_xor1, 64);
2242        if (j >= 3 )
2243                ctx1.Length_Low = 0x1ff;
2244        sha1_append(&ctx1, magic_key_char, 4);
2245        sha1_finish(&ctx1, digest1);
2246
2247        /* The second context gets the password hash XORed
2248         * with 0x5c plus the SHA-1 digest
2249         * of the first context. */
2250
2251        sha1_append(&ctx2, crypt_hash_xor2, 64);
2252        sha1_append(&ctx2, digest1, 20);
2253        sha1_finish(&ctx2, digest2);
2254
2255        /* Now that we have digest2, use it to fetch
2256         * characters from an alphabet to construct
2257         * our first authentication response.  */
2258
2259        for (x = 0; x < 20; x += 2) {
2260                unsigned int val = 0;
2261                unsigned int lookup = 0;
2262
2263                char byte[6];
2264
2265                memset(&byte, 0, 6);
2266
2267                /* First two bytes of digest stuffed
2268                 *  together. */
2269
2270                val = digest2[x];
2271                val <<= 8;
2272                val += digest2[x+1];
2273
2274                lookup = (val >> 0x0b);
2275                lookup &= 0x1f;
2276                if (lookup >= strlen(alphabet1))
2277                        break;
2278                sprintf(byte, "%c", alphabet1[lookup]);
2279                strcat(resp_96, byte);
2280                strcat(resp_96, "=");
2281
2282                lookup = (val >> 0x06);
2283                lookup &= 0x1f;
2284                if (lookup >= strlen(alphabet2))
2285                        break;
2286                sprintf(byte, "%c", alphabet2[lookup]);
2287                strcat(resp_96, byte);
2288
2289                lookup = (val >> 0x01);
2290                lookup &= 0x1f;
2291                if (lookup >= strlen(alphabet2))
2292                        break;
2293                sprintf(byte, "%c", alphabet2[lookup]);
2294                strcat(resp_96, byte);
2295
2296                lookup = (val & 0x01);
2297                if (lookup >= strlen(delimit_lookup))
2298                        break;
2299                sprintf(byte, "%c", delimit_lookup[lookup]);
2300                strcat(resp_96, byte);
2301        }
2302
2303        pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
2304        yahoo_packet_hash(pack, 0, sn);
2305        yahoo_packet_hash(pack, 6, resp_6);
2306        yahoo_packet_hash(pack, 96, resp_96);
2307        yahoo_packet_hash(pack, 1, sn);
2308        yahoo_send_packet(yid, pack, 0);
2309        yahoo_packet_free(pack);
2310
2311        free(password_hash);
2312        free(crypt_hash);
2313}
2314
2315static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn)
2316{
2317        char *url;
2318
2319        yid->yd->login_cookie = strdup(seed);
2320
2321        url = g_strdup_printf(
2322                "https://login.yahoo.com/config/pwtoken_get?"
2323                "src=ymsgr&ts=&login=%s&passwd=%s&chal=%s",
2324                yid->yd->user, yid->yd->password, seed);
2325
2326        http_dorequest_url(url, yahoo_process_auth_response, yid);
2327       
2328        g_free(url);
2329}
2330
2331static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2332{
2333        char *seed = NULL;
2334        char *sn   = NULL;
2335        YList *l = pkt->hash;
2336        int m = 0;
2337
2338        while (l) {
2339                struct yahoo_pair *pair = l->data;
2340                if (pair->key == 94)
2341                        seed = pair->value;
2342                if (pair->key == 1)
2343                        sn = pair->value;
2344                if (pair->key == 13)
2345                        m = atoi(pair->value);
2346                l = l->next;
2347        }
2348
2349        if (!seed) 
2350                return;
2351
2352        switch (m) {
2353                case 0:
2354                        yahoo_process_auth_pre_0x0b(yid, seed, sn);
2355                        break;
2356                case 1:
2357                        yahoo_process_auth_0x0b(yid, seed, sn);
2358                        break;
2359                case 2:
2360                        /* HTTPS */
2361                        yahoo_process_auth_0x10(yid, seed, sn);
2362                        break;
2363                default:
2364                        /* call error */
2365                        WARNING(("unknown auth type %d", m));
2366                        yahoo_process_auth_0x0b(yid, seed, sn);
2367                        break;
2368        }
2369}
2370
2371static void yahoo_process_auth_resp(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2372{
2373        struct yahoo_data *yd = yid->yd;
2374        char *login_id;
2375        char *handle;
2376        char *url=NULL;
2377        int  login_status=0;
2378
2379        YList *l;
2380
2381        for (l = pkt->hash; l; l = l->next) {
2382                struct yahoo_pair *pair = l->data;
2383                if (pair->key == 0)
2384                        login_id = pair->value;
2385                else if (pair->key == 1)
2386                        handle = pair->value;
2387                else if (pair->key == 20)
2388                        url = pair->value;
2389                else if (pair->key == 66)
2390                        login_status = atoi(pair->value);
2391        }
2392
2393        if(pkt->status == 0xffffffff) {
2394                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, login_status, url);
2395        /*      yahoo_logoff(yd->client_id);*/
2396        }
2397}
2398
2399static void yahoo_process_mail(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2400{
2401        struct yahoo_data *yd = yid->yd;
2402        char *who = NULL;
2403        char *email = NULL;
2404        char *subj = NULL;
2405        int count = 0;
2406        YList *l;
2407
2408        for (l = pkt->hash; l; l = l->next) {
2409                struct yahoo_pair *pair = l->data;
2410                if (pair->key == 9)
2411                        count = strtol(pair->value, NULL, 10);
2412                else if (pair->key == 43)
2413                        who = pair->value;
2414                else if (pair->key == 42)
2415                        email = pair->value;
2416                else if (pair->key == 18)
2417                        subj = pair->value;
2418                else
2419                        LOG(("key: %d => value: %s", pair->key, pair->value));
2420        }
2421
2422        if (who && email && subj) {
2423                char from[1024];
2424                snprintf(from, sizeof(from), "%s (%s)", who, email);
2425                YAHOO_CALLBACK(ext_yahoo_mail_notify)(yd->client_id, from, subj, count);
2426        } else if(count > 0)
2427                YAHOO_CALLBACK(ext_yahoo_mail_notify)(yd->client_id, NULL, NULL, count);
2428}
2429
2430static void yahoo_process_contact(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2431{
2432        struct yahoo_data *yd = yid->yd;
2433        char *id = NULL;
2434        char *who = NULL;
2435        char *msg = NULL;
2436        char *name = NULL;
2437        long tm = 0L;
2438        int state = YAHOO_STATUS_AVAILABLE;
2439        int online = FALSE;
2440        int away = 0;
2441        int idle = 0;
2442        int mobile = 0;
2443
2444        YList *l;
2445
2446        for (l = pkt->hash; l; l = l->next) {
2447                struct yahoo_pair *pair = l->data;
2448                if (pair->key == 1)
2449                        id = pair->value;
2450                else if (pair->key == 3)
2451                        who = pair->value;
2452                else if (pair->key == 14)
2453                        msg = pair->value;
2454                else if (pair->key == 7)
2455                        name = pair->value;
2456                else if (pair->key == 10)
2457                        state = strtol(pair->value, NULL, 10);
2458                else if (pair->key == 15)
2459                        tm = strtol(pair->value, NULL, 10);
2460                else if (pair->key == 13)
2461                        online = strtol(pair->value, NULL, 10);
2462                else if (pair->key == 47)
2463                        away = strtol(pair->value, NULL, 10);
2464                else if (pair->key == 137)
2465                        idle = strtol(pair->value, NULL, 10);
2466                else if (pair->key == 60)
2467                        mobile = strtol(pair->value, NULL, 10);
2468               
2469        }
2470
2471        if (id)
2472                YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, id, who, msg);
2473        else if (name)
2474                YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away, idle, mobile);
2475        else if(pkt->status == 0x07)
2476                YAHOO_CALLBACK(ext_yahoo_rejected)(yd->client_id, who, msg);
2477}
2478
2479static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2480{
2481        struct yahoo_data *yd = yid->yd;
2482        char *who = NULL;
2483        char *where = NULL;
2484        int status = 0;
2485        char *me = NULL;
2486
2487        struct yahoo_buddy *bud=NULL;
2488
2489        YList *l;
2490        for (l = pkt->hash; l; l = l->next) {
2491                struct yahoo_pair *pair = l->data;
2492                if (pair->key == 1)
2493                        me = pair->value;
2494                if (pair->key == 7)
2495                        who = pair->value;
2496                if (pair->key == 65)
2497                        where = pair->value;
2498                if (pair->key == 66)
2499                        status = strtol(pair->value, NULL, 10);
2500        }
2501
2502        yahoo_dump_unhandled(pkt);
2503
2504        if(!who)
2505                return;
2506        if(!where)
2507                where = "Unknown";
2508
2509        /* status: 0 == Successful, 1 == Error (does not exist), 2 == Already in list */
2510        if( status == 0 ) {
2511                bud = y_new0(struct yahoo_buddy, 1);
2512                bud->id = strdup(who);
2513                bud->group = strdup(where);
2514                bud->real_name = NULL;
2515               
2516                yd->buddies = y_list_append(yd->buddies, bud);
2517               
2518                /* Possibly called already, but at least the call above doesn't
2519                   seem to happen every time (not anytime I tried). */
2520                YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, me, who, NULL);
2521        }
2522
2523/*      YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */
2524}
2525
2526static void yahoo_process_buddydel(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2527{
2528        struct yahoo_data *yd = yid->yd;
2529        char *who = NULL;
2530        char *where = NULL;
2531        int unk_66 = 0;
2532        char *me = NULL;
2533        struct yahoo_buddy *bud;
2534
2535        YList *buddy;
2536
2537        YList *l;
2538        for (l = pkt->hash; l; l = l->next) {
2539                struct yahoo_pair *pair = l->data;
2540                if (pair->key == 1)
2541                        me = pair->value;
2542                else if (pair->key == 7)
2543                        who = pair->value;
2544                else if (pair->key == 65)
2545                        where = pair->value;
2546                else if (pair->key == 66)
2547                        unk_66 = strtol(pair->value, NULL, 10);
2548                else
2549                        DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value));
2550        }
2551
2552        if(!who || !where)
2553                return;
2554       
2555        bud = y_new0(struct yahoo_buddy, 1);
2556        bud->id = strdup(who);
2557        bud->group = strdup(where);
2558
2559        buddy = y_list_find_custom(yd->buddies, bud, is_same_bud);
2560
2561        FREE(bud->id);
2562        FREE(bud->group);
2563        FREE(bud);
2564
2565        if(buddy) {
2566                bud = buddy->data;
2567                yd->buddies = y_list_remove_link(yd->buddies, buddy);
2568                y_list_free_1(buddy);
2569
2570                FREE(bud->id);
2571                FREE(bud->group);
2572                FREE(bud->real_name);
2573                FREE(bud);
2574
2575                bud=NULL;
2576        }
2577}
2578
2579static void yahoo_process_ignore(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2580{
2581        char *who = NULL;
2582        int  status = 0;
2583        char *me = NULL;
2584        int  un_ignore = 0;
2585
2586        YList *l;
2587        for (l = pkt->hash; l; l = l->next) {
2588                struct yahoo_pair *pair = l->data;
2589                if (pair->key == 0)
2590                        who = pair->value;
2591                if (pair->key == 1)
2592                        me = pair->value;
2593                if (pair->key == 13) /* 1 == ignore, 2 == unignore */ 
2594                        un_ignore = strtol(pair->value, NULL, 10);
2595                if (pair->key == 66) 
2596                        status = strtol(pair->value, NULL, 10);
2597        }
2598
2599
2600        /*
2601         * status
2602         *      0  - ok
2603         *      2  - already in ignore list, could not add
2604         *      3  - not in ignore list, could not delete
2605         *      12 - is a buddy, could not add
2606         */
2607
2608/*      if(status)
2609                YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, who, 0, status);
2610*/     
2611}
2612
2613static void yahoo_process_voicechat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2614{
2615        char *who = NULL;
2616        char *me = NULL;
2617        char *room = NULL;
2618        char *voice_room = NULL;
2619
2620        YList *l;
2621        for (l = pkt->hash; l; l = l->next) {
2622                struct yahoo_pair *pair = l->data;
2623                if (pair->key == 4)
2624                        who = pair->value;
2625                if (pair->key == 5)
2626                        me = pair->value;
2627                if (pair->key == 13)
2628                        voice_room=pair->value;
2629                if (pair->key == 57) 
2630                        room=pair->value;
2631        }
2632
2633        NOTICE(("got voice chat invite from %s in %s to identity %s", who, room, me));
2634        /*
2635         * send: s:0 1:me 5:who 57:room 13:1
2636         * ????  s:4 5:who 10:99 19:-1615114531
2637         * gotr: s:4 5:who 10:99 19:-1615114615
2638         * ????  s:1 5:me 4:who 57:room 13:3room
2639         * got:  s:1 5:me 4:who 57:room 13:1room
2640         * rej:  s:0 1:me 5:who 57:room 13:3
2641         * rejr: s:4 5:who 10:99 19:-1617114599
2642         */
2643}
2644
2645static void yahoo_process_ping(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2646{
2647        char *errormsg = NULL;
2648       
2649        YList *l;
2650        for (l = pkt->hash; l; l = l->next) {
2651                struct yahoo_pair *pair = l->data;
2652                if (pair->key == 16)
2653                        errormsg = pair->value;
2654        }
2655       
2656        NOTICE(("got ping packet"));
2657        YAHOO_CALLBACK(ext_yahoo_got_ping)(yid->yd->client_id, errormsg);
2658}
2659
2660static void _yahoo_webcam_get_server_connected(int fd, int error, void *d)
2661{
2662        struct yahoo_input_data *yid = d;
2663        char *who = yid->wcm->user;
2664        char *data = NULL;
2665        char *packet = NULL;
2666        unsigned char magic_nr[] = {0, 1, 0};
2667        unsigned char header_len = 8;
2668        unsigned int len = 0;
2669        unsigned int pos = 0;
2670
2671        if(error || fd <= 0) {
2672                FREE(who);
2673                FREE(yid);
2674                return;
2675        }
2676
2677        yid->fd = fd;
2678        inputs = y_list_prepend(inputs, yid);
2679       
2680        /* send initial packet */
2681        if (who)
2682                data = strdup("<RVWCFG>");
2683        else
2684                data = strdup("<RUPCFG>");
2685        yahoo_add_to_send_queue(yid, data, strlen(data));
2686        FREE(data);
2687
2688        /* send data */
2689        if (who)
2690        {
2691                data = strdup("g=");
2692                data = y_string_append(data, who);
2693                data = y_string_append(data, "\r\n");
2694        } else {
2695                data = strdup("f=1\r\n");
2696        }
2697        len = strlen(data);
2698        packet = y_new0(char, header_len + len);
2699        packet[pos++] = header_len;
2700        memcpy(packet + pos, magic_nr, sizeof(magic_nr));
2701        pos += sizeof(magic_nr);
2702        pos += yahoo_put32(packet + pos, len);
2703        memcpy(packet + pos, data, len);
2704        pos += len;
2705        yahoo_add_to_send_queue(yid, packet, pos);
2706        FREE(packet);
2707        FREE(data);
2708
2709        yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, fd, YAHOO_INPUT_READ, yid);
2710}
2711
2712static void yahoo_webcam_get_server(struct yahoo_input_data *y, char *who, char *key)
2713{
2714        struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
2715        struct yahoo_server_settings *yss = y->yd->server_settings;
2716
2717        yid->type = YAHOO_CONNECTION_WEBCAM_MASTER;
2718        yid->yd = y->yd;
2719        yid->wcm = y_new0(struct yahoo_webcam, 1);
2720        yid->wcm->user = who?strdup(who):NULL;
2721        yid->wcm->direction = who?YAHOO_WEBCAM_DOWNLOAD:YAHOO_WEBCAM_UPLOAD;
2722        yid->wcm->key = strdup(key);
2723
2724        YAHOO_CALLBACK(ext_yahoo_connect_async)(yid->yd->client_id, yss->webcam_host, yss->webcam_port, 
2725                        _yahoo_webcam_get_server_connected, yid);
2726
2727}
2728
2729static YList *webcam_queue=NULL;
2730static void yahoo_process_webcam_key(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2731{
2732        char *me = NULL;
2733        char *key = NULL;
2734        char *who = NULL;
2735
2736        YList *l;
2737        yahoo_dump_unhandled(pkt);
2738        for (l = pkt->hash; l; l = l->next) {
2739                struct yahoo_pair *pair = l->data;
2740                if (pair->key == 5)
2741                        me = pair->value;
2742                if (pair->key == 61) 
2743                        key=pair->value;
2744        }
2745
2746        l = webcam_queue;
2747        if(!l)
2748                return;
2749        who = l->data;
2750        webcam_queue = y_list_remove_link(webcam_queue, webcam_queue);
2751        y_list_free_1(l);
2752        yahoo_webcam_get_server(yid, who, key);
2753        FREE(who);
2754}
2755
2756static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2757{
2758        DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service));
2759        switch (pkt->service)
2760        {
2761        case YAHOO_SERVICE_USERSTAT:
2762        case YAHOO_SERVICE_LOGON:
2763        case YAHOO_SERVICE_LOGOFF:
2764        case YAHOO_SERVICE_ISAWAY:
2765        case YAHOO_SERVICE_ISBACK:
2766        case YAHOO_SERVICE_GAMELOGON:
2767        case YAHOO_SERVICE_GAMELOGOFF:
2768        case YAHOO_SERVICE_IDACT:
2769        case YAHOO_SERVICE_IDDEACT:
2770        case YAHOO_SERVICE_Y6_STATUS_UPDATE:
2771        case YAHOO_SERVICE_Y8_STATUS:
2772                yahoo_process_status(yid, pkt);
2773                break;
2774        case YAHOO_SERVICE_NOTIFY:
2775                yahoo_process_notify(yid, pkt);
2776                break;
2777        case YAHOO_SERVICE_MESSAGE:
2778        case YAHOO_SERVICE_GAMEMSG:
2779        case YAHOO_SERVICE_SYSMESSAGE:
2780                yahoo_process_message(yid, pkt);
2781                break;
2782        case YAHOO_SERVICE_NEWMAIL:
2783                yahoo_process_mail(yid, pkt);
2784                break;
2785        case YAHOO_SERVICE_NEWCONTACT:
2786                yahoo_process_contact(yid, pkt);
2787                break;
2788        case YAHOO_SERVICE_LIST:
2789                yahoo_process_list(yid, pkt);
2790                break;
2791        case YAHOO_SERVICE_VERIFY:
2792                yahoo_process_verify(yid, pkt);
2793                break;
2794        case YAHOO_SERVICE_AUTH:
2795                yahoo_process_auth(yid, pkt);
2796                break;
2797        case YAHOO_SERVICE_AUTHRESP:
2798                yahoo_process_auth_resp(yid, pkt);
2799                break;
2800        case YAHOO_SERVICE_CONFINVITE:
2801        case YAHOO_SERVICE_CONFADDINVITE:
2802        case YAHOO_SERVICE_CONFDECLINE:
2803        case YAHOO_SERVICE_CONFLOGON:
2804        case YAHOO_SERVICE_CONFLOGOFF:
2805        case YAHOO_SERVICE_CONFMSG:
2806                yahoo_process_conference(yid, pkt);
2807                break;
2808        case YAHOO_SERVICE_CHATONLINE:
2809        case YAHOO_SERVICE_CHATGOTO:
2810        case YAHOO_SERVICE_CHATJOIN:
2811        case YAHOO_SERVICE_CHATLEAVE:
2812        case YAHOO_SERVICE_CHATEXIT:
2813        case YAHOO_SERVICE_CHATLOGOUT:
2814        case YAHOO_SERVICE_CHATPING:
2815        case YAHOO_SERVICE_COMMENT:
2816                yahoo_process_chat(yid, pkt);
2817                break;
2818        case YAHOO_SERVICE_P2PFILEXFER:
2819        case YAHOO_SERVICE_FILETRANSFER:
2820                yahoo_process_filetransfer(yid, pkt);
2821                break;
2822        case YAHOO_SERVICE_ADDBUDDY:
2823                yahoo_process_buddyadd(yid, pkt);
2824                break;
2825        case YAHOO_SERVICE_REMBUDDY:
2826                yahoo_process_buddydel(yid, pkt);
2827                break;
2828        case YAHOO_SERVICE_IGNORECONTACT:
2829                yahoo_process_ignore(yid, pkt);
2830                break;
2831        case YAHOO_SERVICE_VOICECHAT:
2832                yahoo_process_voicechat(yid, pkt);
2833                break;
2834        case YAHOO_SERVICE_WEBCAM:
2835                yahoo_process_webcam_key(yid, pkt);
2836                break;
2837        case YAHOO_SERVICE_PING:
2838                yahoo_process_ping(yid, pkt);
2839                break;
2840        case YAHOO_SERVICE_IDLE:
2841        case YAHOO_SERVICE_MAILSTAT:
2842        case YAHOO_SERVICE_CHATINVITE:
2843        case YAHOO_SERVICE_CALENDAR:
2844        case YAHOO_SERVICE_NEWPERSONALMAIL:
2845        case YAHOO_SERVICE_ADDIDENT:
2846        case YAHOO_SERVICE_ADDIGNORE:
2847        case YAHOO_SERVICE_GOTGROUPRENAME:
2848        case YAHOO_SERVICE_GROUPRENAME:
2849        case YAHOO_SERVICE_PASSTHROUGH2:
2850        case YAHOO_SERVICE_CHATLOGON:
2851        case YAHOO_SERVICE_CHATLOGOFF:
2852        case YAHOO_SERVICE_CHATMSG:
2853        case YAHOO_SERVICE_REJECTCONTACT:
2854        case YAHOO_SERVICE_PEERTOPEER:
2855                WARNING(("unhandled service 0x%02x", pkt->service));
2856                yahoo_dump_unhandled(pkt);
2857                break;
2858        case YAHOO_SERVICE_PICTURE:
2859                yahoo_process_picture(yid, pkt);
2860                break;
2861        case YAHOO_SERVICE_PICTURE_CHECKSUM:
2862                yahoo_process_picture_checksum(yid, pkt);
2863                break;
2864        case YAHOO_SERVICE_PICTURE_UPLOAD:
2865                yahoo_process_picture_upload(yid, pkt);
2866                break; 
2867        case YAHOO_SERVICE_Y8_LIST:     /* Buddy List */
2868                yahoo_process_buddy_list(yid, pkt);
2869        default:
2870                WARNING(("unknown service 0x%02x", pkt->service));
2871                yahoo_dump_unhandled(pkt);
2872                break;
2873        }
2874}
2875
2876static struct yahoo_packet * yahoo_getdata(struct yahoo_input_data * yid)
2877{
2878        struct yahoo_packet *pkt;
2879        struct yahoo_data *yd = yid->yd;
2880        int pos = 0;
2881        int pktlen;
2882
2883        if(!yd)
2884                return NULL;
2885
2886        DEBUG_MSG(("rxlen is %d", yid->rxlen));
2887        if (yid->rxlen < YAHOO_PACKET_HDRLEN) {
2888                DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN"));
2889                return NULL;
2890        }
2891
2892        pos += 4; /* YMSG */
2893        pos += 2;
2894        pos += 2;
2895
2896        pktlen = yahoo_get16(yid->rxqueue + pos); pos += 2;
2897        DEBUG_MSG(("%d bytes to read, rxlen is %d", 
2898                        pktlen, yid->rxlen));
2899
2900        if (yid->rxlen < (YAHOO_PACKET_HDRLEN + pktlen)) {
2901                DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN + pktlen"));
2902                return NULL;
2903        }
2904
2905        LOG(("reading packet"));
2906        yahoo_packet_dump(yid->rxqueue, YAHOO_PACKET_HDRLEN + pktlen);
2907
2908        pkt = yahoo_packet_new(0, 0, 0);
2909
2910        pkt->service = yahoo_get16(yid->rxqueue + pos); pos += 2;
2911        pkt->status = yahoo_get32(yid->rxqueue + pos); pos += 4;
2912        DEBUG_MSG(("Yahoo Service: 0x%02x Status: %d", pkt->service,
2913                                pkt->status));
2914        pkt->id = yahoo_get32(yid->rxqueue + pos); pos += 4;
2915
2916        yd->session_id = pkt->id;
2917
2918        yahoo_packet_read(pkt, yid->rxqueue + pos, pktlen);
2919
2920        yid->rxlen -= YAHOO_PACKET_HDRLEN + pktlen;
2921        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2922        if (yid->rxlen>0) {
2923                unsigned char *tmp = y_memdup(yid->rxqueue + YAHOO_PACKET_HDRLEN
2924                                + pktlen, yid->rxlen);
2925                FREE(yid->rxqueue);
2926                yid->rxqueue = tmp;
2927                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2928        } else {
2929                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
2930                FREE(yid->rxqueue);
2931        }
2932
2933        return pkt;
2934}
2935
2936static void yahoo_yab_read(struct yab *yab, unsigned char *d, int len)
2937{
2938        char *st, *en;
2939        char *data = (char *)d;
2940        data[len]='\0';
2941
2942        DEBUG_MSG(("Got yab: %s", data));
2943        st = en = strstr(data, "userid=\"");
2944        if(st) {
2945                st += strlen("userid=\"");
2946                en = strchr(st, '"'); *en++ = '\0';
2947                yab->id = yahoo_xmldecode(st);
2948        }
2949
2950        st = strstr(en, "fname=\"");
2951        if(st) {
2952                st += strlen("fname=\"");
2953                en = strchr(st, '"'); *en++ = '\0';
2954                yab->fname = yahoo_xmldecode(st);
2955        }
2956
2957        st = strstr(en, "lname=\"");
2958        if(st) {
2959                st += strlen("lname=\"");
2960                en = strchr(st, '"'); *en++ = '\0';
2961                yab->lname = yahoo_xmldecode(st);
2962        }
2963
2964        st = strstr(en, "nname=\"");
2965        if(st) {
2966                st += strlen("nname=\"");
2967                en = strchr(st, '"'); *en++ = '\0';
2968                yab->nname = yahoo_xmldecode(st);
2969        }
2970
2971        st = strstr(en, "email=\"");
2972        if(st) {
2973                st += strlen("email=\"");
2974                en = strchr(st, '"'); *en++ = '\0';
2975                yab->email = yahoo_xmldecode(st);
2976        }
2977
2978        st = strstr(en, "hphone=\"");
2979        if(st) {
2980                st += strlen("hphone=\"");
2981                en = strchr(st, '"'); *en++ = '\0';
2982                yab->hphone = yahoo_xmldecode(st);
2983        }
2984
2985        st = strstr(en, "wphone=\"");
2986        if(st) {
2987                st += strlen("wphone=\"");
2988                en = strchr(st, '"'); *en++ = '\0';
2989                yab->wphone = yahoo_xmldecode(st);
2990        }
2991
2992        st = strstr(en, "mphone=\"");
2993        if(st) {
2994                st += strlen("mphone=\"");
2995                en = strchr(st, '"'); *en++ = '\0';
2996                yab->mphone = yahoo_xmldecode(st);
2997        }
2998
2999        st = strstr(en, "dbid=\"");
3000        if(st) {
3001                st += strlen("dbid=\"");
3002                en = strchr(st, '"'); *en++ = '\0';
3003                yab->dbid = atoi(st);
3004        }
3005}
3006
3007static struct yab * yahoo_getyab(struct yahoo_input_data *yid)
3008{
3009        struct yab *yab = NULL;
3010        int pos = 0, end=0;
3011        struct yahoo_data *yd = yid->yd;
3012
3013        if(!yd)
3014                return NULL;
3015
3016        DEBUG_MSG(("rxlen is %d", yid->rxlen));
3017
3018        if(yid->rxlen <= strlen("<record"))
3019                return NULL;
3020
3021        /* start with <record */
3022        while(pos < yid->rxlen-strlen("<record")+1 
3023                        && memcmp(yid->rxqueue + pos, "<record", strlen("<record")))
3024                pos++;
3025
3026        if(pos >= yid->rxlen-1)
3027                return NULL;
3028
3029        end = pos+2;
3030        /* end with /> */
3031        while(end < yid->rxlen-strlen("/>")+1 && memcmp(yid->rxqueue + end, "/>", strlen("/>")))
3032                end++;
3033
3034        if(end >= yid->rxlen-1)
3035                return NULL;
3036
3037        yab = y_new0(struct yab, 1);
3038        yahoo_yab_read(yab, yid->rxqueue + pos, end+2-pos);
3039       
3040
3041        yid->rxlen -= end+1;
3042        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3043        if (yid->rxlen>0) {
3044                unsigned char *tmp = y_memdup(yid->rxqueue + end + 1, yid->rxlen);
3045                FREE(yid->rxqueue);
3046                yid->rxqueue = tmp;
3047                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3048        } else {
3049                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3050                FREE(yid->rxqueue);
3051        }
3052
3053
3054        return yab;
3055}
3056
3057static char * yahoo_getwebcam_master(struct yahoo_input_data *yid)
3058{
3059        unsigned int pos=0;
3060        unsigned int len=0;
3061        unsigned int status=0;
3062        char *server=NULL;
3063        struct yahoo_data *yd = yid->yd;
3064
3065        if(!yid || !yd)
3066                return NULL;
3067
3068        DEBUG_MSG(("rxlen is %d", yid->rxlen));
3069
3070        len = yid->rxqueue[pos++];
3071        if (yid->rxlen < len)
3072                return NULL;
3073
3074        /* extract status (0 = ok, 6 = webcam not online) */
3075        status = yid->rxqueue[pos++];
3076
3077        if (status == 0)
3078        {
3079                pos += 2; /* skip next 2 bytes */
3080                server =  y_memdup(yid->rxqueue+pos, 16);
3081                pos += 16;
3082        }
3083        else if (status == 6)
3084        {
3085                YAHOO_CALLBACK(ext_yahoo_webcam_closed)
3086                        (yd->client_id, yid->wcm->user, 4);
3087        }
3088
3089        /* skip rest of the data */
3090
3091        yid->rxlen -= len;
3092        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3093        if (yid->rxlen>0) {
3094                unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
3095                FREE(yid->rxqueue);
3096                yid->rxqueue = tmp;
3097                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3098        } else {
3099                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3100                FREE(yid->rxqueue);
3101        }
3102
3103        return server;
3104}
3105
3106static int yahoo_get_webcam_data(struct yahoo_input_data *yid)
3107{
3108        unsigned char reason=0;
3109        unsigned int pos=0;
3110        unsigned int begin=0;
3111        unsigned int end=0;
3112        unsigned int closed=0;
3113        unsigned char header_len=0;
3114        char *who;
3115        int connect=0;
3116        struct yahoo_data *yd = yid->yd;
3117
3118        if(!yd)
3119                return -1;
3120
3121        if(!yid->wcm || !yid->wcd || !yid->rxlen)
3122                return -1;
3123
3124        DEBUG_MSG(("rxlen is %d", yid->rxlen));
3125
3126        /* if we are not reading part of image then read header */
3127        if (!yid->wcd->to_read)
3128        {
3129                header_len=yid->rxqueue[pos++];
3130                yid->wcd->packet_type=0;
3131
3132                if (yid->rxlen < header_len)
3133                        return 0;
3134
3135                if (header_len >= 8)
3136                {
3137                        reason = yid->rxqueue[pos++];
3138                        /* next 2 bytes should always be 05 00 */
3139                        pos += 2;
3140                        yid->wcd->data_size = yahoo_get32(yid->rxqueue + pos);
3141                        pos += 4;
3142                        yid->wcd->to_read = yid->wcd->data_size;
3143                }
3144                if (header_len >= 13)
3145                {
3146                        yid->wcd->packet_type = yid->rxqueue[pos++];
3147                        yid->wcd->timestamp = yahoo_get32(yid->rxqueue + pos);
3148                        pos += 4;
3149                }
3150
3151                /* skip rest of header */
3152                pos = header_len;
3153        }
3154
3155        begin = pos;
3156        pos += yid->wcd->to_read;
3157        if (pos > yid->rxlen) pos = yid->rxlen;
3158
3159        /* if it is not an image then make sure we have the whole packet */
3160        if (yid->wcd->packet_type != 0x02) {
3161                if ((pos - begin) != yid->wcd->data_size) {
3162                        yid->wcd->to_read = 0;
3163                        return 0;
3164                } else {
3165                        yahoo_packet_dump(yid->rxqueue + begin, pos - begin);
3166                }
3167        }
3168
3169        DEBUG_MSG(("packet type %.2X, data length %d", yid->wcd->packet_type,
3170                yid->wcd->data_size));
3171
3172        /* find out what kind of packet we got */
3173        switch (yid->wcd->packet_type)
3174        {
3175                case 0x00:
3176                        /* user requests to view webcam (uploading) */
3177                        if (yid->wcd->data_size &&
3178                                yid->wcm->direction == YAHOO_WEBCAM_UPLOAD) {
3179                                end = begin;
3180                                while (end <= yid->rxlen &&
3181                                        yid->rxqueue[end++] != 13);
3182                                if (end > begin)
3183                                {
3184                                        who = y_memdup(yid->rxqueue + begin, end - begin);
3185                                        who[end - begin - 1] = 0;
3186                                        YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who + 2, 2);
3187                                        FREE(who);
3188                                }
3189                        }
3190
3191                        if (yid->wcm->direction == YAHOO_WEBCAM_DOWNLOAD) {
3192                                /* timestamp/status field */
3193                                /* 0 = declined viewing permission */
3194                                /* 1 = accepted viewing permission */
3195                                if (yid->wcd->timestamp == 0) {
3196                                        YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, 3);
3197                                }
3198                        }
3199                        break;
3200                case 0x01: /* status packets?? */
3201                        /* timestamp contains status info */
3202                        /* 00 00 00 01 = we have data?? */
3203                        break;
3204                case 0x02: /* image data */
3205                        YAHOO_CALLBACK(ext_yahoo_got_webcam_image)(yd->client_id, 
3206                                        yid->wcm->user, yid->rxqueue + begin,
3207                                        yid->wcd->data_size, pos - begin,
3208                                        yid->wcd->timestamp);
3209                        break;
3210                case 0x05: /* response packets when uploading */
3211                        if (!yid->wcd->data_size) {
3212                                YAHOO_CALLBACK(ext_yahoo_webcam_data_request)(yd->client_id, yid->wcd->timestamp);
3213                        }
3214                        break;
3215                case 0x07: /* connection is closing */
3216                        switch(reason)
3217                        {
3218                                case 0x01: /* user closed connection */
3219                                        closed = 1;
3220                                        break;
3221                                case 0x0F: /* user cancelled permission */
3222                                        closed = 2;
3223                                        break;
3224                        }
3225                        YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, closed);
3226                        break;
3227                case 0x0C: /* user connected */
3228                case 0x0D: /* user disconnected */
3229                        if (yid->wcd->data_size) {
3230                                who = y_memdup(yid->rxqueue + begin, pos - begin + 1);
3231                                who[pos - begin] = 0;
3232                                if (yid->wcd->packet_type == 0x0C)
3233                                        connect=1;
3234                                else
3235                                        connect=0;
3236                                YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who, connect);
3237                                FREE(who);
3238                        }
3239                        break;
3240                case 0x13: /* user data */
3241                        /* i=user_ip (ip of the user we are viewing) */
3242                        /* j=user_ext_ip (external ip of the user we */
3243                        /*                are viewing) */
3244                        break;
3245                case 0x17: /* ?? */
3246                        break;
3247        }
3248        yid->wcd->to_read -= pos - begin;
3249
3250        yid->rxlen -= pos;
3251        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3252        if (yid->rxlen>0) {
3253                unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
3254                FREE(yid->rxqueue);
3255                yid->rxqueue = tmp;
3256                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3257        } else {
3258                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3259                FREE(yid->rxqueue);
3260        }
3261
3262        /* If we read a complete packet return success */
3263        if (!yid->wcd->to_read)
3264                return 1;
3265
3266        return 0;
3267}
3268
3269int yahoo_write_ready(int id, int fd, void *data)
3270{
3271        struct yahoo_input_data *yid = data;
3272        int len;
3273        struct data_queue *tx;
3274
3275        LOG(("write callback: id=%d fd=%d data=%p", id, fd, data));
3276        if(!yid || !yid->txqueues || !find_conn_by_id(id))
3277                return -2;
3278       
3279        tx = yid->txqueues->data;
3280        LOG(("writing %d bytes", tx->len));
3281        len = yahoo_send_data(fd, tx->queue, MIN(1024, tx->len));
3282
3283        if(len == -1 && errno == EAGAIN)
3284                return 1;
3285
3286        if(len <= 0) {
3287                int e = errno;
3288                DEBUG_MSG(("len == %d (<= 0)", len));
3289                while(yid->txqueues) {
3290                        YList *l=yid->txqueues;
3291                        tx = l->data;
3292                        free(tx->queue);
3293                        free(tx);
3294                        yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
3295                        y_list_free_1(l);
3296                }
3297                LOG(("yahoo_write_ready(%d, %d) len < 0", id, fd));
3298                YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
3299                yid->write_tag = 0;
3300                errno=e;
3301                return 0;
3302        }
3303
3304
3305        tx->len -= len;
3306        if(tx->len > 0) {
3307                unsigned char *tmp = y_memdup(tx->queue + len, tx->len);
3308                FREE(tx->queue);
3309                tx->queue = tmp;
3310        } else {
3311                YList *l=yid->txqueues;
3312                free(tx->queue);
3313                free(tx);
3314                yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
3315                y_list_free_1(l);
3316                /*
3317                if(!yid->txqueues)
3318                        LOG(("yahoo_write_ready(%d, %d) !yxqueues", id, fd));
3319                */
3320                if(!yid->txqueues) {
3321                        LOG(("yahoo_write_ready(%d, %d) !yxqueues", id, fd));
3322                        YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
3323                        yid->write_tag = 0;
3324                }
3325        }
3326
3327        return 1;
3328}
3329
3330static void yahoo_process_pager_connection(struct yahoo_input_data *yid, int over)
3331{
3332        struct yahoo_packet *pkt;
3333        struct yahoo_data *yd = yid->yd;
3334        int id = yd->client_id;
3335
3336        if(over)
3337                return;
3338
3339        while (find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER) 
3340                        && (pkt = yahoo_getdata(yid)) != NULL) {
3341
3342                yahoo_packet_process(yid, pkt);
3343
3344                yahoo_packet_free(pkt);
3345        }
3346}
3347
3348static void yahoo_process_ft_connection(struct yahoo_input_data *yid, int over)
3349{
3350}
3351
3352static void yahoo_process_chatcat_connection(struct yahoo_input_data *yid, int over)
3353{
3354        if(over)
3355                return;
3356
3357        if (strstr((char*)yid->rxqueue+(yid->rxlen-20), "</content>")) {
3358                YAHOO_CALLBACK(ext_yahoo_chat_cat_xml)(yid->yd->client_id, (char*)yid->rxqueue);
3359        }
3360}
3361
3362static void yahoo_process_yab_connection(struct yahoo_input_data *yid, int over)
3363{
3364        struct yahoo_data *yd = yid->yd;
3365        struct yab *yab;
3366        YList *buds;
3367        int changed=0;
3368        int id = yd->client_id;
3369
3370        if(over)
3371                return;
3372
3373        while(find_input_by_id_and_type(id, YAHOO_CONNECTION_YAB) 
3374                        && (yab = yahoo_getyab(yid)) != NULL) {
3375                if(!yab->id)
3376                        continue;
3377                changed=1;
3378                for(buds = yd->buddies; buds; buds=buds->next) {
3379                        struct yahoo_buddy * bud = buds->data;
3380                        if(!strcmp(bud->id, yab->id)) {
3381                                bud->yab_entry = yab;
3382                                if(yab->nname) {
3383                                        bud->real_name = strdup(yab->nname);
3384                                } else if(yab->fname && yab->lname) {
3385                                        bud->real_name = y_new0(char, 
3386                                                        strlen(yab->fname)+
3387                                                        strlen(yab->lname)+2
3388                                                        );
3389                                        sprintf(bud->real_name, "%s %s",
3390                                                        yab->fname, yab->lname);
3391                                } else if(yab->fname) {
3392                                        bud->real_name = strdup(yab->fname);
3393                                }
3394                                break; /* for */
3395                        }
3396                }
3397        }
3398
3399        if(changed)
3400                YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
3401}
3402
3403static void yahoo_process_search_connection(struct yahoo_input_data *yid, int over)
3404{
3405        struct yahoo_found_contact *yct=NULL;
3406        char *p = (char *)yid->rxqueue, *np, *cp;
3407        int k, n;
3408        int start=0, found=0, total=0;
3409        YList *contacts=NULL;
3410        struct yahoo_input_data *pyid = find_input_by_id_and_type(yid->yd->client_id, YAHOO_CONNECTION_PAGER);
3411
3412        if(!over || !pyid)
3413                return;
3414
3415        if(p && (p=strstr(p, "\r\n\r\n"))) {
3416                p += 4;
3417
3418                for(k = 0; (p = strchr(p, 4)) && (k < 4); k++) {
3419                        p++;
3420                        n = atoi(p);
3421                        switch(k) {
3422                                case 0: found = pyid->ys->lsearch_nfound = n; break;
3423                                case 2: start = pyid->ys->lsearch_nstart = n; break;
3424                                case 3: total = pyid->ys->lsearch_ntotal = n; break;
3425                        }
3426                }
3427
3428                if(p)
3429                        p++;
3430
3431                k=0;
3432                while(p && *p) {
3433                        cp = p;
3434                        np = strchr(p, 4);
3435
3436                        if(!np)
3437                                break;
3438                        *np = 0;
3439                        p = np+1;
3440
3441                        switch(k++) {
3442                                case 1:
3443                                        if(strlen(cp) > 2 && y_list_length(contacts) < total) {
3444                                                yct = y_new0(struct yahoo_found_contact, 1);
3445                                                contacts = y_list_append(contacts, yct);
3446                                                yct->id = cp+2;
3447                                        } else {
3448                                                *p = 0;
3449                                        }
3450                                        break;
3451                                case 2: 
3452                                        yct->online = !strcmp(cp, "2") ? 1 : 0;
3453                                        break;
3454                                case 3: 
3455                                        yct->gender = cp;
3456                                        break;
3457                                case 4: 
3458                                        yct->age = atoi(cp);
3459                                        break;
3460                                case 5: 
3461                                        if(strcmp(cp, "5") != 0)
3462                                                yct->location = cp;
3463                                        k = 0;
3464                                        break;
3465                        }
3466                }
3467        }
3468
3469        YAHOO_CALLBACK(ext_yahoo_got_search_result)(yid->yd->client_id, found, start, total, contacts);
3470
3471        while(contacts) {
3472                YList *node = contacts;
3473                contacts = y_list_remove_link(contacts, node);
3474                free(node->data);
3475                y_list_free_1(node);
3476        }
3477}
3478
3479static void _yahoo_webcam_connected(int fd, int error, void *d)
3480{
3481        struct yahoo_input_data *yid = d;
3482        struct yahoo_webcam *wcm = yid->wcm;
3483        struct yahoo_data *yd = yid->yd;
3484        char conn_type[100];
3485        char *data=NULL;
3486        char *packet=NULL;
3487        unsigned char magic_nr[] = {1, 0, 0, 0, 1};
3488        unsigned header_len=0;
3489        unsigned int len=0;
3490        unsigned int pos=0;
3491
3492        if(error || fd <= 0) {
3493                FREE(yid);
3494                return;
3495        }
3496
3497        yid->fd = fd;
3498        inputs = y_list_prepend(inputs, yid);
3499
3500        LOG(("Connected"));
3501        /* send initial packet */
3502        switch (wcm->direction)
3503        {
3504                case YAHOO_WEBCAM_DOWNLOAD:
3505                        data = strdup("<REQIMG>");
3506                        break;
3507                case YAHOO_WEBCAM_UPLOAD:       
3508                        data = strdup("<SNDIMG>");
3509                        break;
3510                default:
3511                        return;
3512        }
3513        yahoo_add_to_send_queue(yid, data, strlen(data));
3514        FREE(data);
3515
3516        /* send data */
3517        switch (wcm->direction)
3518        {
3519                case YAHOO_WEBCAM_DOWNLOAD:
3520                        header_len = 8;
3521                        data = strdup("a=2\r\nc=us\r\ne=21\r\nu=");
3522                        data = y_string_append(data, yd->user);
3523                        data = y_string_append(data, "\r\nt=");
3524                        data = y_string_append(data, wcm->key);
3525                        data = y_string_append(data, "\r\ni=");
3526                        data = y_string_append(data, wcm->my_ip);
3527                        data = y_string_append(data, "\r\ng=");
3528                        data = y_string_append(data, wcm->user);
3529                        data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
3530                        snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
3531                        data = y_string_append(data, conn_type);
3532                        data = y_string_append(data, "\r\n");
3533                        break;
3534                case YAHOO_WEBCAM_UPLOAD:
3535                        header_len = 13;
3536                        data = strdup("a=2\r\nc=us\r\nu=");
3537                        data = y_string_append(data, yd->user);
3538                        data = y_string_append(data, "\r\nt=");
3539                        data = y_string_append(data, wcm->key);
3540                        data = y_string_append(data, "\r\ni=");
3541                        data = y_string_append(data, wcm->my_ip);
3542                        data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
3543                        snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
3544                        data = y_string_append(data, conn_type);
3545                        data = y_string_append(data, "\r\nb=");
3546                        data = y_string_append(data, wcm->description);
3547                        data = y_string_append(data, "\r\n");
3548                        break;
3549        }
3550
3551        len = strlen(data);
3552        packet = y_new0(char, header_len + len);
3553        packet[pos++] = header_len;
3554        packet[pos++] = 0;
3555        switch (wcm->direction)
3556        {
3557                case YAHOO_WEBCAM_DOWNLOAD:
3558                        packet[pos++] = 1;
3559                        packet[pos++] = 0;
3560                        break;
3561                case YAHOO_WEBCAM_UPLOAD:
3562                        packet[pos++] = 5;
3563                        packet[pos++] = 0;
3564                        break;
3565        }
3566
3567        pos += yahoo_put32(packet + pos, len);
3568        if (wcm->direction == YAHOO_WEBCAM_UPLOAD)
3569        {
3570                memcpy(packet + pos, magic_nr, sizeof(magic_nr));
3571                pos += sizeof(magic_nr);
3572        }
3573        memcpy(packet + pos, data, len);
3574        yahoo_add_to_send_queue(yid, packet, header_len + len);
3575        FREE(packet);
3576        FREE(data);
3577
3578        yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_READ, yid);
3579}
3580
3581static void yahoo_webcam_connect(struct yahoo_input_data *y)
3582{
3583        struct yahoo_webcam *wcm = y->wcm;
3584        struct yahoo_input_data *yid;
3585        struct yahoo_server_settings *yss;
3586
3587        if (!wcm || !wcm->server || !wcm->key)
3588                return;
3589
3590        yid = y_new0(struct yahoo_input_data, 1);
3591        yid->type = YAHOO_CONNECTION_WEBCAM;
3592        yid->yd = y->yd;
3593
3594        /* copy webcam data to new connection */
3595        yid->wcm = y->wcm;
3596        y->wcm = NULL;
3597
3598        yss = y->yd->server_settings;
3599
3600        yid->wcd = y_new0(struct yahoo_webcam_data, 1);
3601
3602        LOG(("Connecting to: %s:%d", wcm->server, wcm->port));
3603        YAHOO_CALLBACK(ext_yahoo_connect_async)(y->yd->client_id, wcm->server, wcm->port,
3604                        _yahoo_webcam_connected, yid);
3605
3606}
3607
3608static void yahoo_process_webcam_master_connection(struct yahoo_input_data *yid, int over)
3609{
3610        char* server;
3611        struct yahoo_server_settings *yss;
3612
3613        if(over)
3614                return;
3615
3616        server = yahoo_getwebcam_master(yid);
3617
3618        if (server)
3619        {
3620                yss = yid->yd->server_settings;
3621                yid->wcm->server = strdup(server);
3622                yid->wcm->port = yss->webcam_port;
3623                yid->wcm->conn_type = yss->conn_type;
3624                yid->wcm->my_ip = strdup(yss->local_host);
3625                if (yid->wcm->direction == YAHOO_WEBCAM_UPLOAD)
3626                        yid->wcm->description = strdup(yss->webcam_description);
3627                yahoo_webcam_connect(yid);
3628                FREE(server);
3629        }
3630}
3631
3632static void yahoo_process_webcam_connection(struct yahoo_input_data *yid, int over)
3633{
3634        int id = yid->yd->client_id;
3635        int fd = yid->fd;
3636
3637        if(over)
3638                return;
3639
3640        /* as long as we still have packets available keep processing them */
3641        while (find_input_by_id_and_fd(id, fd) 
3642                        && yahoo_get_webcam_data(yid) == 1);
3643}
3644
3645/* #define LOG(x...) printf x */
3646
3647static void yahoo_process_auth_response(struct http_request *req)
3648{
3649        char *line_end;
3650        char *token;
3651        char *cookie;
3652
3653        int error_code = 0;
3654        int is_ymsgr = 0;
3655
3656        struct yahoo_input_data *yid = req->data;
3657
3658        char crypt_hash[25];
3659
3660        md5_byte_t result[16];
3661        md5_state_t ctx;
3662
3663        struct yahoo_packet *packet = NULL;
3664       
3665        if (y_list_find(inputs, yid) == NULL)
3666                return;
3667       
3668        if (req->status_code != 200) {
3669                error_code = 3000 + req->status_code;
3670                goto FAIL;
3671        }
3672
3673        token = req->reply_body;
3674        line_end = strstr(token, "\r\n");
3675
3676        if (line_end) {
3677                *line_end = '\0';
3678
3679                line_end += 2;
3680        }
3681       
3682        if (sscanf(token, "%d", &error_code) != 1) {
3683                error_code = 3000;
3684                goto FAIL;
3685        }
3686
3687        switch(error_code) {
3688                case 0:
3689                        /* successful */
3690                        break;
3691
3692                case 1212:
3693                        LOG(("Incorrect ID or password\n"));
3694                        error_code = YAHOO_LOGIN_PASSWD;
3695                        goto FAIL;
3696
3697                case 1213:
3698                        LOG(("Security lock from too many failed login attempts\n"));
3699                        error_code = YAHOO_LOGIN_LOCK;
3700                        goto FAIL;
3701
3702                case 1214:
3703                        LOG(("Security lock\n"));
3704                        goto FAIL;
3705
3706                case 1235:
3707                        LOG(("User ID not taken yet\n"));
3708                        error_code = YAHOO_LOGIN_UNAME;
3709                        goto FAIL;
3710
3711                case 1216:
3712                        LOG(("Seems to be a lock, but shows the same generic User ID/Password failure\n"));
3713                        goto FAIL;
3714
3715                default:
3716                        /* Unknown error code */
3717                        LOG(("Unknown Error\n"));
3718                        goto FAIL;
3719        }
3720
3721        if ( !strncmp(line_end, "ymsgr=", 6) ) {
3722                is_ymsgr = 1;
3723        }
3724        else if ( strncmp(line_end, "crumb=", 6) ) {
3725                LOG(("Oops! There was no ymsgr=. Where do I get my token from now :("));
3726                LOG(("I got this:\n\n%s\n",line_end));
3727                error_code = 2201;
3728                goto FAIL;
3729        }
3730
3731        token = line_end+6;
3732
3733        line_end = strstr(token, "\r\n");
3734
3735        if(line_end) {
3736                *line_end = '\0';
3737                line_end += 2;
3738        }
3739
3740        /* Go for the crumb */
3741        if(is_ymsgr) {
3742                char *url;
3743
3744                url = g_strdup_printf(
3745                        "https://login.yahoo.com/config/pwtoken_login?"
3746                        "src=ymsgr&ts=&token=%s", token);
3747
3748                http_dorequest_url(url, yahoo_process_auth_response, yid);
3749
3750                g_free(url);
3751
3752                return;
3753        }
3754
3755        /* token is actually crumb */
3756
3757        if(!line_end) {
3758                /* We did not get our cookies. Cry. */
3759        }
3760
3761        if((cookie = strstr(req->reply_headers, "Set-Cookie: Y=")) &&
3762           (line_end = strstr(cookie + 14, "\r\n"))) {
3763                *line_end = '\0';
3764                yid->yd->cookie_y = strdup(cookie + 14);
3765                *line_end = ';';
3766        } else {
3767                /* Cry. */
3768                LOG(("NO Y Cookie!"));
3769                error_code = 2202;
3770                goto FAIL;
3771        }
3772
3773        if((cookie = strstr(req->reply_headers, "Set-Cookie: T=")) &&
3774           (line_end = strstr(cookie + 14, "\r\n"))) {
3775                *line_end = '\0';
3776                yid->yd->cookie_t = strdup(cookie + 14);
3777                *line_end = ';';
3778        } else {
3779                /* Cry. */
3780                LOG(("NO T Cookie!"));
3781                error_code = 2203;
3782                goto FAIL;
3783        }
3784
3785        md5_init(&ctx);
3786        md5_append(&ctx, (md5_byte_t *)token, strlen(token));
3787        md5_append(&ctx, (md5_byte_t *)yid->yd->login_cookie, strlen(yid->yd->login_cookie));
3788        md5_finish(&ctx, result);
3789
3790        to_y64((unsigned char*)crypt_hash, result, 16);
3791
3792        packet = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yid->yd->initial_status, yid->yd->session_id);
3793        yahoo_packet_hash(packet, 1, yid->yd->user);
3794        yahoo_packet_hash(packet, 0, yid->yd->user);
3795        yahoo_packet_hash(packet, 277, yid->yd->cookie_y);
3796        yahoo_packet_hash(packet, 278, yid->yd->cookie_t);
3797        yahoo_packet_hash(packet, 307, crypt_hash);
3798        yahoo_packet_hash(packet, 244, "2097087");      /* Rekkanoryo says this is the build number */
3799        yahoo_packet_hash(packet, 2, yid->yd->user);
3800        yahoo_packet_hash(packet, 2, "1");
3801        yahoo_packet_hash(packet, 98, "us");            /* TODO Put country code */
3802        yahoo_packet_hash(packet, 135, "9.0.0.1389");
3803               
3804        yahoo_send_packet(yid, packet, 0);
3805
3806        yahoo_packet_free(packet);
3807
3808        /* We don't need this anymore */
3809        free(yid->yd->login_cookie);
3810        yid->yd->login_cookie = NULL;
3811       
3812        return;
3813
3814FAIL:
3815        YAHOO_CALLBACK(ext_yahoo_login_response)(yid->yd->client_id, error_code, NULL);
3816}
3817
3818
3819static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = {
3820        yahoo_process_pager_connection,
3821        yahoo_process_ft_connection,
3822        yahoo_process_yab_connection,
3823        yahoo_process_webcam_master_connection,
3824        yahoo_process_webcam_connection,
3825        yahoo_process_chatcat_connection,
3826        yahoo_process_search_connection,
3827};
3828
3829int yahoo_read_ready(int id, int fd, void *data)
3830{
3831        struct yahoo_input_data *yid = data;
3832        char buf[1024];
3833        int len;
3834
3835        LOG(("read callback: id=%d fd=%d data=%p", id, fd, data));
3836        if(!yid)
3837                return -2;
3838
3839       
3840        do {
3841                len = read(fd, buf, sizeof(buf));
3842        } while(len == -1 && errno == EINTR);
3843
3844        if(len == -1 && (errno == EAGAIN||errno == EINTR))      /* we'll try again later */
3845                return 1;
3846
3847        if (len <= 0) {
3848                int e = errno;
3849                DEBUG_MSG(("len == %d (<= 0)", len));
3850
3851                if(yid->type == YAHOO_CONNECTION_PAGER) {
3852                        YAHOO_CALLBACK(ext_yahoo_error)(yid->yd->client_id, "Connection closed by server", 1, E_CONNECTION);
3853                }
3854
3855                yahoo_process_connection[yid->type](yid, 1);
3856                yahoo_input_close(yid);
3857
3858                /* no need to return an error, because we've already fixed it */
3859                if(len == 0)
3860                        return 1;
3861
3862                errno=e;
3863                LOG(("read error: %s", strerror(errno)));
3864                return -1;
3865        }
3866
3867        yid->rxqueue = y_renew(unsigned char, yid->rxqueue, len + yid->rxlen);
3868        memcpy(yid->rxqueue + yid->rxlen, buf, len);
3869        yid->rxlen += len;
3870
3871        yahoo_process_connection[yid->type](yid, 0);
3872
3873        return len;
3874}
3875
3876int yahoo_init_with_attributes(const char *username, const char *password, ...)
3877{
3878        va_list ap;
3879        struct yahoo_data *yd;
3880
3881        yd = y_new0(struct yahoo_data, 1);
3882
3883        if(!yd)
3884                return 0;
3885
3886        yd->user = strdup(username);
3887        yd->password = strdup(password);
3888
3889        yd->initial_status = -1;
3890        yd->current_status = -1;
3891
3892        yd->client_id = ++last_id;
3893
3894        add_to_list(yd);
3895
3896        va_start(ap, password);
3897        yd->server_settings = _yahoo_assign_server_settings(ap);
3898        va_end(ap);
3899
3900        return yd->client_id;
3901}
3902
3903int yahoo_init(const char *username, const char *password)
3904{
3905        return yahoo_init_with_attributes(username, password, NULL);
3906}
3907
3908struct connect_callback_data {
3909        struct yahoo_data *yd;
3910        int tag;
3911        int i;
3912};
3913
3914static void yahoo_connected(int fd, int error, void *data)
3915{
3916        struct connect_callback_data *ccd = data;
3917        struct yahoo_data *yd = ccd->yd;
3918        struct yahoo_packet *pkt;
3919        struct yahoo_input_data *yid;
3920        struct yahoo_server_settings *yss = yd->server_settings;
3921
3922        if(error) {
3923                if(fallback_ports[ccd->i]) {
3924                        int tag;
3925                        yss->pager_port = fallback_ports[ccd->i++];
3926                        tag = YAHOO_CALLBACK(ext_yahoo_connect_async)(yd->client_id, yss->pager_host,
3927                                        yss->pager_port, yahoo_connected, ccd);
3928
3929                        if(tag > 0)
3930                                ccd->tag=tag;
3931                } else {
3932                        FREE(ccd);
3933                        YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_SOCK, NULL);
3934                }
3935                return;
3936        }
3937
3938        FREE(ccd);
3939
3940        /* fd < 0 && error == 0 means connect was cancelled */
3941        if(fd < 0)
3942                return;
3943
3944        pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
3945        NOTICE(("Sending initial packet"));
3946
3947        yahoo_packet_hash(pkt, 1, yd->user);
3948
3949        yid = y_new0(struct yahoo_input_data, 1);
3950        yid->yd = yd;
3951        yid->fd = fd;
3952        inputs = y_list_prepend(inputs, yid);
3953
3954        yahoo_send_packet(yid, pkt, 0);
3955
3956        yahoo_packet_free(pkt);
3957
3958        yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_READ, yid);
3959}
3960
3961void yahoo_login(int id, int initial)
3962{
3963        struct yahoo_data *yd = find_conn_by_id(id);
3964        struct connect_callback_data *ccd;
3965        struct yahoo_server_settings *yss;
3966        int tag;
3967
3968        if(!yd)
3969                return;
3970
3971        yss = yd->server_settings;
3972
3973        yd->initial_status = initial;
3974
3975        ccd = y_new0(struct connect_callback_data, 1);
3976        ccd->yd = yd;
3977        tag = YAHOO_CALLBACK(ext_yahoo_connect_async)(yd->client_id, yss->pager_host, yss->pager_port, 
3978                        yahoo_connected, ccd);
3979
3980        /*
3981         * if tag <= 0, then callback has already been called
3982         * so ccd will have been freed
3983         */
3984        if(tag > 0)
3985                ccd->tag = tag;
3986        else if(tag < 0)
3987                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_SOCK, NULL);
3988}
3989
3990
3991int yahoo_get_fd(int id)
3992{
3993        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
3994        if(!yid)
3995                return 0;
3996        else
3997                return yid->fd;
3998}
3999
4000void yahoo_send_im(int id, const char *from, const char *who, const char *what, int utf8, int picture)
4001{
4002        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4003        struct yahoo_packet *pkt = NULL;
4004        struct yahoo_data *yd;
4005        char pic_str[10];
4006
4007        if(!yid)
4008                return;
4009
4010        yd = yid->yd;
4011
4012        pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, yd->session_id);
4013
4014        snprintf(pic_str, sizeof(pic_str), "%d", picture);
4015       
4016        if(from && strcmp(from, yd->user))
4017                yahoo_packet_hash(pkt, 0, yd->user);
4018        yahoo_packet_hash(pkt, 1, from?from:yd->user);
4019        yahoo_packet_hash(pkt, 5, who);
4020        yahoo_packet_hash(pkt, 14, what);
4021
4022        if(utf8)
4023                yahoo_packet_hash(pkt, 97, "1");
4024
4025        yahoo_packet_hash(pkt, 63, ";0");       /* imvironment name; or ;0 */
4026        yahoo_packet_hash(pkt, 64, "0");
4027        yahoo_packet_hash(pkt, 206, pic_str);
4028
4029
4030        yahoo_send_packet(yid, pkt, 0);
4031
4032        yahoo_packet_free(pkt);
4033}
4034
4035void yahoo_send_typing(int id, const char *from, const char *who, int typ)
4036{
4037        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4038        struct yahoo_data *yd;
4039        struct yahoo_packet *pkt = NULL;
4040        if(!yid)
4041                return;
4042
4043        yd = yid->yd;
4044        pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yd->session_id);
4045
4046        yahoo_packet_hash(pkt, 5, who);
4047        yahoo_packet_hash(pkt, 4, from?from:yd->user);
4048        yahoo_packet_hash(pkt, 14, " ");
4049        yahoo_packet_hash(pkt, 13, typ ? "1" : "0");
4050        yahoo_packet_hash(pkt, 49, "TYPING");
4051
4052        yahoo_send_packet(yid, pkt, 0);
4053
4054        yahoo_packet_free(pkt);
4055}
4056
4057void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away)
4058{
4059        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4060        struct yahoo_data *yd;
4061        struct yahoo_packet *pkt = NULL;
4062        int service;
4063        char s[4];
4064
4065        if(!yid)
4066                return;
4067
4068        yd = yid->yd;
4069
4070        if (msg) {
4071                yd->current_status = YAHOO_STATUS_CUSTOM;
4072        } else {
4073                yd->current_status = state;
4074        }
4075
4076        if (yd->current_status == YAHOO_STATUS_AVAILABLE)
4077                service = YAHOO_SERVICE_ISBACK;
4078        else
4079                service = YAHOO_SERVICE_ISAWAY;
4080         
4081        if ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) {
4082                pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id);
4083                yahoo_packet_hash(pkt, 10, "999");
4084                yahoo_packet_hash(pkt, 47, "2");
4085        }else {
4086                pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, yd->session_id);
4087                snprintf(s, sizeof(s), "%d", yd->current_status);
4088                yahoo_packet_hash(pkt, 10, s);
4089                if (yd->current_status == YAHOO_STATUS_CUSTOM) {
4090                        yahoo_packet_hash(pkt, 19, msg);
4091                        yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
4092                } else {
4093                        yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
4094                }
4095               
4096               
4097               
4098        }
4099
4100        yahoo_send_packet(yid, pkt, 0);
4101        yahoo_packet_free(pkt);
4102}
4103
4104void yahoo_logoff(int id)
4105{
4106        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4107        struct yahoo_data *yd;
4108        struct yahoo_packet *pkt = NULL;
4109
4110        if(!yid)
4111                return;
4112        yd = yid->yd;
4113
4114        LOG(("yahoo_logoff: current status: %d", yd->current_status));
4115
4116        if(yd->current_status != -1) {
4117                pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
4118                yd->current_status = -1;
4119
4120                if (pkt) {
4121                        yahoo_send_packet(yid, pkt, 0);
4122                        yahoo_packet_free(pkt);
4123                }
4124        }
4125
4126        do {
4127                yahoo_input_close(yid);
4128        } while((yid = find_input_by_id(id)));
4129}
4130
4131void yahoo_get_list(int id)
4132{
4133        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4134        struct yahoo_data *yd;
4135        struct yahoo_packet *pkt = NULL;
4136
4137        if(!yid)
4138                return;
4139        yd = yid->yd;
4140
4141        pkt = yahoo_packet_new(YAHOO_SERVICE_LIST, YAHOO_STATUS_AVAILABLE, yd->session_id);
4142        yahoo_packet_hash(pkt, 1, yd->user);
4143        if (pkt) {
4144                yahoo_send_packet(yid, pkt, 0);
4145                yahoo_packet_free(pkt);
4146        }
4147}
4148
4149static void _yahoo_http_connected(int id, int fd, int error, void *data)
4150{
4151        struct yahoo_input_data *yid = data;
4152        if(fd <= 0) {
4153                inputs = y_list_remove(inputs, yid);
4154                FREE(yid);
4155                return;
4156        }
4157
4158        yid->fd = fd;
4159        yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, fd, YAHOO_INPUT_READ, yid);
4160}
4161
4162void yahoo_get_yab(int id)
4163{
4164        struct yahoo_data *yd = find_conn_by_id(id);
4165        struct yahoo_input_data *yid;
4166        char url[1024];
4167        char buff[1024];
4168
4169        if(!yd)
4170                return;
4171
4172        yid = y_new0(struct yahoo_input_data, 1);
4173        yid->yd = yd;
4174        yid->type = YAHOO_CONNECTION_YAB;
4175
4176        snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?ab2=0");
4177
4178        snprintf(buff, sizeof(buff), "Y=%s; T=%s",
4179                        yd->cookie_y, yd->cookie_t);
4180
4181        inputs = y_list_prepend(inputs, yid);
4182
4183        yahoo_http_get(yid->yd->client_id, url, buff, 
4184                        _yahoo_http_connected, yid);
4185}
4186
4187void yahoo_set_yab(int id, struct yab * yab)
4188{
4189        struct yahoo_data *yd = find_conn_by_id(id);
4190        struct yahoo_input_data *yid;
4191        char url[1024];
4192        char buff[1024];
4193        char *temp;
4194        int size = sizeof(url)-1;
4195
4196        if(!yd)
4197                return;
4198
4199        yid = y_new0(struct yahoo_input_data, 1);
4200        yid->type = YAHOO_CONNECTION_YAB;
4201        yid->yd = yd;
4202
4203        strncpy(url, "http://insider.msg.yahoo.com/ycontent/?addab2=0", size);
4204
4205        if(yab->dbid) {
4206                /* change existing yab */
4207                char tmp[32];
4208                strncat(url, "&ee=1&ow=1&id=", size - strlen(url));
4209                snprintf(tmp, sizeof(tmp), "%d", yab->dbid);
4210                strncat(url, tmp, size - strlen(url));
4211        }
4212
4213        if(yab->fname) {
4214                strncat(url, "&fn=", size - strlen(url));
4215                temp = yahoo_urlencode(yab->fname);
4216                strncat(url, temp, size - strlen(url));
4217                free(temp);
4218        }
4219        if(yab->lname) {
4220                strncat(url, "&ln=", size - strlen(url));
4221                temp = yahoo_urlencode(yab->lname);
4222                strncat(url, temp, size - strlen(url));
4223                free(temp);
4224        }
4225        strncat(url, "&yid=", size - strlen(url));
4226        temp = yahoo_urlencode(yab->id);
4227        strncat(url, temp, size - strlen(url));
4228        free(temp);
4229        if(yab->nname) {
4230                strncat(url, "&nn=", size - strlen(url));
4231                temp = yahoo_urlencode(yab->nname);
4232                strncat(url, temp, size - strlen(url));
4233                free(temp);
4234        }
4235        if(yab->email) {
4236                strncat(url, "&e=", size - strlen(url));
4237                temp = yahoo_urlencode(yab->email);
4238                strncat(url, temp, size - strlen(url));
4239                free(temp);
4240        }
4241        if(yab->hphone) {
4242                strncat(url, "&hp=", size - strlen(url));
4243                temp = yahoo_urlencode(yab->hphone);
4244                strncat(url, temp, size - strlen(url));
4245                free(temp);
4246        }
4247        if(yab->wphone) {
4248                strncat(url, "&wp=", size - strlen(url));
4249                temp = yahoo_urlencode(yab->wphone);
4250                strncat(url, temp, size - strlen(url));
4251                free(temp);
4252        }
4253        if(yab->mphone) {
4254                strncat(url, "&mp=", size - strlen(url));
4255                temp = yahoo_urlencode(yab->mphone);
4256                strncat(url, temp, size - strlen(url));
4257                free(temp);
4258        }
4259        strncat(url, "&pp=0", size - strlen(url));
4260
4261        snprintf(buff, sizeof(buff), "Y=%s; T=%s",
4262                        yd->cookie_y, yd->cookie_t);
4263
4264        inputs = y_list_prepend(inputs, yid);
4265
4266        yahoo_http_get(yid->yd->client_id, url, buff, 
4267                        _yahoo_http_connected, yid);
4268}
4269
4270void yahoo_set_identity_status(int id, const char * identity, int active)
4271{
4272        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4273        struct yahoo_data *yd;
4274        struct yahoo_packet *pkt = NULL;
4275
4276        if(!yid)
4277                return;
4278        yd = yid->yd;
4279
4280        pkt = yahoo_packet_new(active?YAHOO_SERVICE_IDACT:YAHOO_SERVICE_IDDEACT,
4281                        YAHOO_STATUS_AVAILABLE, yd->session_id);
4282        yahoo_packet_hash(pkt, 3, identity);
4283        if (pkt) {
4284                yahoo_send_packet(yid, pkt, 0);
4285                yahoo_packet_free(pkt);
4286        }
4287}
4288
4289void yahoo_refresh(int id)
4290{
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;
4294
4295        if(!yid)
4296                return;
4297        yd = yid->yd;
4298
4299        pkt = yahoo_packet_new(YAHOO_SERVICE_USERSTAT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4300        if (pkt) {
4301                yahoo_send_packet(yid, pkt, 0);
4302                yahoo_packet_free(pkt);
4303        }
4304}
4305
4306void yahoo_keepalive(int id)
4307{
4308        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4309        struct yahoo_data *yd;
4310        struct yahoo_packet *pkt=NULL;
4311        if(!yid)
4312                return;
4313        yd = yid->yd;
4314
4315        pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, yd->session_id);
4316        yahoo_send_packet(yid, pkt, 0);
4317        yahoo_packet_free(pkt);
4318}
4319
4320void yahoo_chat_keepalive (int id)
4321{
4322        struct yahoo_input_data *yid = find_input_by_id_and_type (id, YAHOO_CONNECTION_PAGER);
4323        struct yahoo_data *yd;
4324        struct yahoo_packet *pkt = NULL;
4325
4326        if (!yid)
4327            return;
4328
4329        yd = yid->yd;
4330
4331        pkt = yahoo_packet_new (YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, yd->session_id);
4332        yahoo_send_packet (yid, pkt, 0);
4333        yahoo_packet_free (pkt);
4334}
4335
4336void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg)
4337{
4338        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4339        struct yahoo_data *yd;
4340        struct yahoo_packet *pkt;
4341
4342        if(!yid)
4343                return;
4344        yd = yid->yd;
4345
4346        if (!yd->logged_in)
4347                return;
4348
4349        pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4350        yahoo_packet_hash(pkt, 1, yd->user);
4351        yahoo_packet_hash(pkt, 7, who);
4352        yahoo_packet_hash(pkt, 65, group);
4353        if (msg != NULL) /* add message/request "it's me add me" */
4354                yahoo_packet_hash(pkt, 14, msg);
4355        yahoo_send_packet(yid, pkt, 0);
4356        yahoo_packet_free(pkt);
4357}
4358
4359void yahoo_remove_buddy(int id, const char *who, const char *group)
4360{
4361        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4362        struct yahoo_data *yd;
4363        struct yahoo_packet *pkt = NULL;
4364
4365        if(!yid)
4366                return;
4367        yd = yid->yd;
4368
4369        pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4370
4371        yahoo_packet_hash(pkt, 1, yd->user);
4372        yahoo_packet_hash(pkt, 7, who);
4373        yahoo_packet_hash(pkt, 65, group);
4374        yahoo_send_packet(yid, pkt, 0);
4375        yahoo_packet_free(pkt);
4376}
4377
4378void yahoo_reject_buddy(int id, const char *who, const char *msg)
4379{
4380        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4381        struct yahoo_data *yd;
4382        struct yahoo_packet *pkt;
4383
4384        if(!yid)
4385                return;
4386        yd = yid->yd;
4387
4388        if (!yd->logged_in)
4389                return;
4390
4391        pkt = yahoo_packet_new(YAHOO_SERVICE_REJECTCONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4392        yahoo_packet_hash(pkt, 1, yd->user);
4393        yahoo_packet_hash(pkt, 7, who);
4394        yahoo_packet_hash(pkt, 14, msg);
4395        yahoo_send_packet(yid, pkt, 0);
4396        yahoo_packet_free(pkt);
4397}
4398
4399void yahoo_ignore_buddy(int id, const char *who, int unignore)
4400{
4401        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4402        struct yahoo_data *yd;
4403        struct yahoo_packet *pkt;
4404
4405        if(!yid)
4406                return;
4407        yd = yid->yd;
4408
4409        if (!yd->logged_in)
4410                return;
4411
4412        pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4413        yahoo_packet_hash(pkt, 1, yd->user);
4414        yahoo_packet_hash(pkt, 7, who);
4415        yahoo_packet_hash(pkt, 13, unignore?"2":"1");
4416        yahoo_send_packet(yid, pkt, 0);
4417        yahoo_packet_free(pkt);
4418}
4419
4420void yahoo_stealth_buddy(int id, const char *who, int unstealth)
4421{
4422        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4423        struct yahoo_data *yd;
4424        struct yahoo_packet *pkt;
4425
4426        if(!yid)
4427                return;
4428        yd = yid->yd;
4429
4430        if (!yd->logged_in)
4431                return;
4432
4433        pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH_PERM, YAHOO_STATUS_AVAILABLE, yd->session_id);
4434        yahoo_packet_hash(pkt, 1, yd->user);
4435        yahoo_packet_hash(pkt, 7, who);
4436        yahoo_packet_hash(pkt, 31, unstealth?"2":"1");
4437        yahoo_packet_hash(pkt, 13, "2");
4438        yahoo_send_packet(yid, pkt, 0);
4439        yahoo_packet_free(pkt);
4440}
4441
4442void yahoo_change_buddy_group(int id, const char *who, const char *old_group, const char *new_group)
4443{
4444        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4445        struct yahoo_data *yd;
4446        struct yahoo_packet *pkt = NULL;
4447
4448        if(!yid)
4449                return;
4450        yd = yid->yd;
4451
4452        pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4453        yahoo_packet_hash(pkt, 1, yd->user);
4454        yahoo_packet_hash(pkt, 7, who);
4455        yahoo_packet_hash(pkt, 65, new_group);
4456        yahoo_packet_hash(pkt, 14, " ");
4457
4458        yahoo_send_packet(yid, pkt, 0);
4459        yahoo_packet_free(pkt);
4460
4461        pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4462        yahoo_packet_hash(pkt, 1, yd->user);
4463        yahoo_packet_hash(pkt, 7, who);
4464        yahoo_packet_hash(pkt, 65, old_group);
4465        yahoo_send_packet(yid, pkt, 0);
4466        yahoo_packet_free(pkt);
4467}
4468
4469void yahoo_group_rename(int id, const char *old_group, const char *new_group)
4470{
4471        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4472        struct yahoo_data *yd;
4473        struct yahoo_packet *pkt = NULL;
4474
4475        if(!yid)
4476                return;
4477        yd = yid->yd;
4478
4479        pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, yd->session_id);
4480        yahoo_packet_hash(pkt, 1, yd->user);
4481        yahoo_packet_hash(pkt, 65, old_group);
4482        yahoo_packet_hash(pkt, 67, new_group);
4483
4484        yahoo_send_packet(yid, pkt, 0);
4485        yahoo_packet_free(pkt);
4486}
4487
4488void yahoo_conference_addinvite(int id, const char * from, const char *who, const char *room, const YList * members, const char *msg)
4489{
4490        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4491        struct yahoo_data *yd;
4492        struct yahoo_packet *pkt;
4493               
4494        if(!yid)
4495                return;
4496        yd = yid->yd;
4497
4498        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFADDINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4499
4500        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4501        yahoo_packet_hash(pkt, 51, who);
4502        yahoo_packet_hash(pkt, 57, room);
4503        yahoo_packet_hash(pkt, 58, msg);
4504        yahoo_packet_hash(pkt, 13, "0");
4505        for(; members; members = members->next) {
4506                yahoo_packet_hash(pkt, 52, (char *)members->data);
4507                yahoo_packet_hash(pkt, 53, (char *)members->data);
4508        }
4509        /* 52, 53 -> other members? */
4510
4511        yahoo_send_packet(yid, pkt, 0);
4512
4513        yahoo_packet_free(pkt);
4514}
4515
4516void yahoo_conference_invite(int id, const char * from, YList *who, const char *room, const char *msg)
4517{
4518        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4519        struct yahoo_data *yd;
4520        struct yahoo_packet *pkt;
4521               
4522        if(!yid)
4523                return;
4524        yd = yid->yd;
4525
4526        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4527
4528        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4529        yahoo_packet_hash(pkt, 50, yd->user);
4530        for(; who; who = who->next) {
4531                yahoo_packet_hash(pkt, 52, (char *)who->data);
4532        }
4533        yahoo_packet_hash(pkt, 57, room);
4534        yahoo_packet_hash(pkt, 58, msg);
4535        yahoo_packet_hash(pkt, 13, "0");
4536
4537        yahoo_send_packet(yid, pkt, 0);
4538
4539        yahoo_packet_free(pkt);
4540}
4541
4542void yahoo_conference_logon(int id, const char *from, YList *who, const char *room)
4543{
4544        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4545        struct yahoo_data *yd;
4546        struct yahoo_packet *pkt;
4547               
4548        if(!yid)
4549                return;
4550        yd = yid->yd;
4551
4552        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGON, YAHOO_STATUS_AVAILABLE, yd->session_id);
4553
4554        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4555        for(; who; who = who->next) {
4556                yahoo_packet_hash(pkt, 3, (char *)who->data);
4557        }
4558        yahoo_packet_hash(pkt, 57, room);
4559
4560        yahoo_send_packet(yid, pkt, 0);
4561
4562        yahoo_packet_free(pkt);
4563}
4564
4565void yahoo_conference_decline(int id, const char * from, YList *who, const char *room, const char *msg)
4566{
4567        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4568        struct yahoo_data *yd;
4569        struct yahoo_packet *pkt;
4570               
4571        if(!yid)
4572                return;
4573        yd = yid->yd;
4574
4575        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFDECLINE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4576
4577        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4578        for(; who; who = who->next) {
4579                yahoo_packet_hash(pkt, 3, (char *)who->data);
4580        }
4581        yahoo_packet_hash(pkt, 57, room);
4582        yahoo_packet_hash(pkt, 14, msg);
4583
4584        yahoo_send_packet(yid, pkt, 0);
4585
4586        yahoo_packet_free(pkt);
4587}
4588
4589void yahoo_conference_logoff(int id, const char * from, YList *who, const char *room)
4590{
4591        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4592        struct yahoo_data *yd;
4593        struct yahoo_packet *pkt;
4594               
4595        if(!yid)
4596                return;
4597        yd = yid->yd;
4598
4599        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
4600
4601        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4602        for(; who; who = who->next) {
4603                yahoo_packet_hash(pkt, 3, (char *)who->data);
4604        }
4605        yahoo_packet_hash(pkt, 57, room);
4606
4607        yahoo_send_packet(yid, pkt, 0);
4608
4609        yahoo_packet_free(pkt);
4610}
4611
4612void yahoo_conference_message(int id, const char * from, YList *who, const char *room, const char *msg, int utf8)
4613{
4614        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4615        struct yahoo_data *yd;
4616        struct yahoo_packet *pkt;
4617               
4618        if(!yid)
4619                return;
4620        yd = yid->yd;
4621
4622        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFMSG, YAHOO_STATUS_AVAILABLE, yd->session_id);
4623
4624        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4625        for(; who; who = who->next) {
4626                yahoo_packet_hash(pkt, 53, (char *)who->data);
4627        }
4628        yahoo_packet_hash(pkt, 57, room);
4629        yahoo_packet_hash(pkt, 14, msg);
4630
4631        if(utf8)
4632                yahoo_packet_hash(pkt, 97, "1");
4633
4634        yahoo_send_packet(yid, pkt, 0);
4635
4636        yahoo_packet_free(pkt);
4637}
4638
4639void yahoo_get_chatrooms(int id, int chatroomid)
4640{
4641        struct yahoo_data *yd = find_conn_by_id(id);
4642        struct yahoo_input_data *yid;
4643        char url[1024];
4644        char buff[1024];
4645
4646        if(!yd)
4647                return;
4648
4649        yid = y_new0(struct yahoo_input_data, 1);
4650        yid->yd = yd;
4651        yid->type = YAHOO_CONNECTION_CHATCAT;
4652
4653        if (chatroomid == 0) {
4654                snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?chatcat=0");
4655        } else {
4656                snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?chatroom_%d=0",chatroomid);
4657        }
4658
4659        snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
4660
4661        inputs = y_list_prepend(inputs, yid);
4662
4663        yahoo_http_get(yid->yd->client_id, url, buff, _yahoo_http_connected, yid);
4664}
4665
4666void yahoo_chat_logon(int id, const char *from, const char *room, const char *roomid)
4667{
4668        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4669        struct yahoo_data *yd;
4670        struct yahoo_packet *pkt;
4671               
4672        if(!yid)
4673                return;
4674
4675        yd = yid->yd;
4676
4677        pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4678
4679        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4680        yahoo_packet_hash(pkt, 109, yd->user);
4681        yahoo_packet_hash(pkt, 6, "abcde");
4682
4683        yahoo_send_packet(yid, pkt, 0);
4684
4685        yahoo_packet_free(pkt);
4686
4687        pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, yd->session_id);
4688
4689        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4690        yahoo_packet_hash(pkt, 104, room);
4691        yahoo_packet_hash(pkt, 129, roomid);
4692        yahoo_packet_hash(pkt, 62, "2"); /* ??? */
4693
4694        yahoo_send_packet(yid, pkt, 0);
4695
4696        yahoo_packet_free(pkt);
4697}
4698
4699
4700void  yahoo_chat_message(int id, const char *from, const char *room, const char *msg, const int msgtype, const int utf8)
4701{
4702        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4703        struct yahoo_data *yd;
4704        struct yahoo_packet *pkt;
4705        char buf[2];
4706               
4707        if(!yid)
4708                return;
4709
4710        yd = yid->yd;
4711
4712        pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4713
4714        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4715        yahoo_packet_hash(pkt, 104, room);
4716        yahoo_packet_hash(pkt, 117, msg);
4717       
4718        snprintf(buf, sizeof(buf), "%d", msgtype);
4719        yahoo_packet_hash(pkt, 124, buf);
4720
4721        if(utf8)
4722                yahoo_packet_hash(pkt, 97, "1");
4723
4724        yahoo_send_packet(yid, pkt, 0);
4725
4726        yahoo_packet_free(pkt);
4727}
4728
4729
4730void yahoo_chat_logoff(int id, const char *from)
4731{
4732        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4733        struct yahoo_data *yd;
4734        struct yahoo_packet *pkt;
4735               
4736        if(!yid)
4737                return;
4738
4739        yd = yid->yd;
4740
4741        pkt = yahoo_packet_new(YAHOO_SERVICE_CHATLOGOUT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4742
4743        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4744
4745        yahoo_send_packet(yid, pkt, 0);
4746
4747        yahoo_packet_free(pkt);
4748}
4749
4750void yahoo_buddyicon_request(int id, const char *who)
4751{
4752        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4753        struct yahoo_data *yd;
4754        struct yahoo_packet *pkt;
4755
4756        if( !yid )
4757                return;
4758
4759        yd = yid->yd;
4760       
4761        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0);
4762        yahoo_packet_hash(pkt, 4, yd->user);
4763        yahoo_packet_hash(pkt, 5, who);
4764        yahoo_packet_hash(pkt, 13, "1");
4765        yahoo_send_packet(yid, pkt, 0);
4766
4767        yahoo_packet_free(pkt);
4768}
4769
4770void yahoo_send_picture_info(int id, const char *who, const char *url, int checksum)
4771{
4772        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4773        struct yahoo_data *yd;
4774        struct yahoo_packet *pkt;
4775        char checksum_str[10];
4776
4777        if( !yid )
4778                return;
4779
4780        yd = yid->yd;
4781
4782        snprintf(checksum_str, sizeof(checksum_str), "%d", checksum);
4783
4784        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0);
4785        yahoo_packet_hash(pkt, 1, yd->user);
4786        yahoo_packet_hash(pkt, 4, yd->user);
4787        yahoo_packet_hash(pkt, 5, who);
4788        yahoo_packet_hash(pkt, 13, "2");
4789        yahoo_packet_hash(pkt, 20, url);
4790        yahoo_packet_hash(pkt, 192, checksum_str);
4791        yahoo_send_packet(yid, pkt, 0);
4792
4793        yahoo_packet_free(pkt);
4794}
4795
4796void yahoo_send_picture_update(int id, const char *who, int type)
4797{
4798        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4799        struct yahoo_data *yd;
4800        struct yahoo_packet *pkt;
4801        char type_str[10];
4802
4803        if( !yid )
4804                return;
4805
4806        yd = yid->yd;
4807
4808        snprintf(type_str, sizeof(type_str), "%d", type);
4809
4810        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPDATE, YAHOO_STATUS_AVAILABLE, 0);
4811        yahoo_packet_hash(pkt, 1, yd->user);
4812        yahoo_packet_hash(pkt, 5, who);
4813        yahoo_packet_hash(pkt, 206, type_str);
4814        yahoo_send_packet(yid, pkt, 0);
4815
4816        yahoo_packet_free(pkt);
4817}
4818
4819void yahoo_send_picture_checksum(int id, const char *who, int checksum)
4820{
4821        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4822        struct yahoo_data *yd;
4823        struct yahoo_packet *pkt;
4824        char checksum_str[10];
4825
4826        if( !yid )
4827                return;
4828
4829        yd = yid->yd;
4830       
4831        snprintf(checksum_str, sizeof(checksum_str), "%d", checksum);
4832
4833        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_CHECKSUM, YAHOO_STATUS_AVAILABLE, 0);
4834        yahoo_packet_hash(pkt, 1, yd->user);
4835        if( who != 0 )
4836                yahoo_packet_hash(pkt, 5, who);
4837        yahoo_packet_hash(pkt, 192, checksum_str);
4838        yahoo_packet_hash(pkt, 212, "1");
4839        yahoo_send_packet(yid, pkt, 0);
4840
4841        yahoo_packet_free(pkt);
4842}
4843
4844void yahoo_webcam_close_feed(int id, const char *who)
4845{
4846        struct yahoo_input_data *yid = find_input_by_id_and_webcam_user(id, who);
4847
4848        if(yid)
4849                yahoo_input_close(yid);
4850}
4851
4852void yahoo_webcam_get_feed(int id, const char *who)
4853{
4854        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4855        struct yahoo_data *yd;
4856        struct yahoo_packet *pkt;
4857               
4858        if(!yid)
4859                return;
4860
4861        /*
4862         * add the user to the queue.  this is a dirty hack, since
4863         * the yahoo server doesn't tell us who's key it's returning,
4864         * we have to just hope that it sends back keys in the same
4865         * order that we request them.
4866         * The queue is popped in yahoo_process_webcam_key
4867         */
4868        webcam_queue = y_list_append(webcam_queue, who?strdup(who):NULL);
4869
4870        yd = yid->yd;
4871
4872        pkt = yahoo_packet_new(YAHOO_SERVICE_WEBCAM, YAHOO_STATUS_AVAILABLE, yd->session_id);
4873
4874        yahoo_packet_hash(pkt, 1, yd->user);
4875        if (who != NULL)
4876                yahoo_packet_hash(pkt, 5, who);
4877        yahoo_send_packet(yid, pkt, 0);
4878
4879        yahoo_packet_free(pkt);
4880}
4881
4882void yahoo_webcam_send_image(int id, unsigned char *image, unsigned int length, unsigned int timestamp)
4883{
4884        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
4885        unsigned char *packet;
4886        unsigned char header_len = 13;
4887        unsigned int pos = 0;
4888
4889        if (!yid)
4890                return;
4891
4892        packet = y_new0(unsigned char, header_len);
4893
4894        packet[pos++] = header_len;
4895        packet[pos++] = 0;
4896        packet[pos++] = 5; /* version byte?? */
4897        packet[pos++] = 0;
4898        pos += yahoo_put32(packet + pos, length);
4899        packet[pos++] = 2; /* packet type, image */
4900        pos += yahoo_put32(packet + pos, timestamp);
4901        yahoo_add_to_send_queue(yid, packet, header_len);
4902        FREE(packet);
4903
4904        if (length)
4905                yahoo_add_to_send_queue(yid, image, length);
4906}
4907
4908void yahoo_webcam_accept_viewer(int id, const char* who, int accept)
4909{
4910        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
4911        char *packet = NULL;
4912        char *data = NULL;
4913        unsigned char header_len = 13;
4914        unsigned int pos = 0;
4915        unsigned int len = 0;
4916
4917        if (!yid)
4918                return;
4919
4920        data = strdup("u=");
4921        data = y_string_append(data, (char*)who);
4922        data = y_string_append(data, "\r\n");
4923        len = strlen(data);
4924
4925        packet = y_new0(char, header_len + len);
4926        packet[pos++] = header_len;
4927        packet[pos++] = 0;
4928        packet[pos++] = 5; /* version byte?? */
4929        packet[pos++] = 0;
4930        pos += yahoo_put32(packet + pos, len);
4931        packet[pos++] = 0; /* packet type */
4932        pos += yahoo_put32(packet + pos, accept);
4933        memcpy(packet + pos, data, len);
4934        FREE(data);
4935        yahoo_add_to_send_queue(yid, packet, header_len + len);
4936        FREE(packet);
4937}
4938
4939void yahoo_webcam_invite(int id, const char *who)
4940{
4941        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4942        struct yahoo_packet *pkt;
4943               
4944        if(!yid)
4945                return;
4946
4947        pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yid->yd->session_id);
4948
4949        yahoo_packet_hash(pkt, 49, "WEBCAMINVITE");
4950        yahoo_packet_hash(pkt, 14, " ");
4951        yahoo_packet_hash(pkt, 13, "0");
4952        yahoo_packet_hash(pkt, 1, yid->yd->user);
4953        yahoo_packet_hash(pkt, 5, who);
4954        yahoo_send_packet(yid, pkt, 0);
4955
4956        yahoo_packet_free(pkt);
4957}
4958
4959static void yahoo_search_internal(int id, int t, const char *text, int g, int ar, int photo, int yahoo_only, int startpos, int total)
4960{
4961        struct yahoo_data *yd = find_conn_by_id(id);
4962        struct yahoo_input_data *yid;
4963        char url[1024];
4964        char buff[1024];
4965        char *ctext, *p;
4966
4967        if(!yd)
4968                return;
4969
4970        yid = y_new0(struct yahoo_input_data, 1);
4971        yid->yd = yd;
4972        yid->type = YAHOO_CONNECTION_SEARCH;
4973
4974        /*
4975        age range
4976        .ar=1 - 13-18, 2 - 18-25, 3 - 25-35, 4 - 35-50, 5 - 50-70, 6 - 70+
4977        */
4978
4979        snprintf(buff, sizeof(buff), "&.sq=%%20&.tt=%d&.ss=%d", total, startpos);
4980
4981        ctext = strdup(text);
4982        while((p = strchr(ctext, ' ')))
4983                *p = '+';
4984
4985        snprintf(url, 1024, "http://members.yahoo.com/interests?.oc=m&.kw=%s&.sb=%d&.g=%d&.ar=0%s%s%s",
4986                        ctext, t, g, photo ? "&.p=y" : "", yahoo_only ? "&.pg=y" : "",
4987                        startpos ? buff : "");
4988
4989        FREE(ctext);
4990
4991        snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
4992
4993        inputs = y_list_prepend(inputs, yid);
4994        yahoo_http_get(yid->yd->client_id, url, buff, _yahoo_http_connected, yid);
4995}
4996
4997void yahoo_search(int id, enum yahoo_search_type t, const char *text, enum yahoo_search_gender g, enum yahoo_search_agerange ar, 
4998                int photo, int yahoo_only)
4999{
5000        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5001        struct yahoo_search_state *yss;
5002
5003        if(!yid)
5004                return;
5005
5006        if(!yid->ys)
5007                yid->ys = y_new0(struct yahoo_search_state, 1);
5008
5009        yss = yid->ys;
5010
5011        FREE(yss->lsearch_text);
5012        yss->lsearch_type = t;
5013        yss->lsearch_text = strdup(text);
5014        yss->lsearch_gender = g;
5015        yss->lsearch_agerange = ar;
5016        yss->lsearch_photo = photo;
5017        yss->lsearch_yahoo_only = yahoo_only;
5018
5019        yahoo_search_internal(id, t, text, g, ar, photo, yahoo_only, 0, 0);
5020}
5021
5022void yahoo_search_again(int id, int start)
5023{
5024        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5025        struct yahoo_search_state *yss;
5026
5027        if(!yid || !yid->ys)
5028                return;
5029
5030        yss = yid->ys;
5031
5032        if(start == -1)
5033                start = yss->lsearch_nstart + yss->lsearch_nfound;
5034
5035        yahoo_search_internal(id, yss->lsearch_type, yss->lsearch_text, 
5036                        yss->lsearch_gender, yss->lsearch_agerange, 
5037                        yss->lsearch_photo, yss->lsearch_yahoo_only, 
5038                        start, yss->lsearch_ntotal);
5039}
5040
5041struct send_file_data {
5042        struct yahoo_packet *pkt;
5043        yahoo_get_fd_callback callback;
5044        void *user_data;
5045};
5046
5047static void _yahoo_send_picture_connected(int id, int fd, int error, void *data)
5048{
5049        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT);
5050        struct send_file_data *sfd = data;
5051        struct yahoo_packet *pkt = sfd->pkt;
5052        unsigned char buff[1024];
5053
5054        if(fd <= 0) {
5055                sfd->callback(id, fd, error, sfd->user_data);
5056                FREE(sfd);
5057                yahoo_packet_free(pkt);
5058                inputs = y_list_remove(inputs, yid);
5059                FREE(yid);
5060                return;
5061        }
5062
5063        yid->fd = fd;
5064        yahoo_send_packet(yid, pkt, 8);
5065        yahoo_packet_free(pkt);
5066
5067        snprintf((char *)buff, sizeof(buff), "29");
5068        buff[2] = 0xc0;
5069        buff[3] = 0x80;
5070       
5071        write(yid->fd, buff, 4);
5072
5073        /*      YAHOO_CALLBACK(ext_yahoo_add_handler)(nyd->fd, YAHOO_INPUT_READ); */
5074
5075        sfd->callback(id, fd, error, sfd->user_data);
5076        FREE(sfd);
5077        inputs = y_list_remove(inputs, yid);
5078        /*
5079        while(yahoo_tcp_readline(buff, sizeof(buff), nyd->fd) > 0) {
5080        if(!strcmp(buff, ""))
5081        break;
5082}
5083
5084        */
5085        yahoo_input_close(yid);
5086}
5087
5088void yahoo_send_picture(int id, const char *name, unsigned long size,
5089                                                        yahoo_get_fd_callback callback, void *data)
5090{
5091        struct yahoo_data *yd = find_conn_by_id(id);
5092        struct yahoo_input_data *yid;
5093        struct yahoo_server_settings *yss;
5094        struct yahoo_packet *pkt = NULL;
5095        char size_str[10];
5096        char expire_str[10];
5097        long content_length=0;
5098        unsigned char buff[1024];
5099        char url[255];
5100        struct send_file_data *sfd;
5101
5102        if(!yd)
5103                return;
5104
5105        yss = yd->server_settings;
5106
5107        yid = y_new0(struct yahoo_input_data, 1);
5108        yid->yd = yd;
5109        yid->type = YAHOO_CONNECTION_FT;
5110
5111        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id);
5112
5113        snprintf(size_str, sizeof(size_str), "%ld", size);
5114        snprintf(expire_str, sizeof(expire_str), "%ld", (long)604800);
5115
5116        yahoo_packet_hash(pkt, 0, yd->user);
5117        yahoo_packet_hash(pkt, 1, yd->user);
5118        yahoo_packet_hash(pkt, 14, "");
5119        yahoo_packet_hash(pkt, 27, name);
5120        yahoo_packet_hash(pkt, 28, size_str);
5121        yahoo_packet_hash(pkt, 38, expire_str);
5122       
5123
5124        content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt);
5125
5126        snprintf(url, sizeof(url), "http://%s:%d/notifyft",
5127                                yss->filetransfer_host, yss->filetransfer_port);
5128        snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s",
5129                                 yd->cookie_y, yd->cookie_t);
5130        inputs = y_list_prepend(inputs, yid);
5131
5132        sfd = y_new0(struct send_file_data, 1);
5133        sfd->pkt = pkt;
5134        sfd->callback = callback;
5135        sfd->user_data = data;
5136        yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size,
5137                                                _yahoo_send_picture_connected, sfd);
5138}
5139
5140static void _yahoo_send_file_connected(int id, int fd, int error, void *data)
5141{
5142        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT);
5143        struct send_file_data *sfd = data;
5144        struct yahoo_packet *pkt = sfd->pkt;
5145        unsigned char buff[1024];
5146
5147        if(fd <= 0) {
5148                sfd->callback(id, fd, error, sfd->user_data);
5149                FREE(sfd);
5150                yahoo_packet_free(pkt);
5151                inputs = y_list_remove(inputs, yid);
5152                FREE(yid);
5153                return;
5154        }
5155
5156        yid->fd = fd;
5157        yahoo_send_packet(yid, pkt, 8);
5158        yahoo_packet_free(pkt);
5159
5160        snprintf((char *)buff, sizeof(buff), "29");
5161        buff[2] = 0xc0;
5162        buff[3] = 0x80;
5163       
5164        write(yid->fd, buff, 4);
5165
5166/*      YAHOO_CALLBACK(ext_yahoo_add_handler)(nyd->fd, YAHOO_INPUT_READ); */
5167
5168        sfd->callback(id, fd, error, sfd->user_data);
5169        FREE(sfd);
5170        inputs = y_list_remove(inputs, yid);
5171        /*
5172        while(yahoo_tcp_readline(buff, sizeof(buff), nyd->fd) > 0) {
5173                if(!strcmp(buff, ""))
5174                        break;
5175        }
5176
5177        */
5178        yahoo_input_close(yid);
5179}
5180
5181void yahoo_send_file(int id, const char *who, const char *msg, 
5182                const char *name, unsigned long size, 
5183                yahoo_get_fd_callback callback, void *data)
5184{
5185        struct yahoo_data *yd = find_conn_by_id(id);
5186        struct yahoo_input_data *yid;
5187        struct yahoo_server_settings *yss;
5188        struct yahoo_packet *pkt = NULL;
5189        char size_str[10];
5190        long content_length=0;
5191        unsigned char buff[1024];
5192        char url[255];
5193        struct send_file_data *sfd;
5194
5195        if(!yd)
5196                return;
5197
5198        yss = yd->server_settings;
5199
5200        yid = y_new0(struct yahoo_input_data, 1);
5201        yid->yd = yd;
5202        yid->type = YAHOO_CONNECTION_FT;
5203
5204        pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
5205
5206        snprintf(size_str, sizeof(size_str), "%ld", size);
5207
5208        yahoo_packet_hash(pkt, 0, yd->user);
5209        yahoo_packet_hash(pkt, 5, who);
5210        yahoo_packet_hash(pkt, 14, msg);
5211        yahoo_packet_hash(pkt, 27, name);
5212        yahoo_packet_hash(pkt, 28, size_str);
5213
5214        content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt);
5215
5216        snprintf(url, sizeof(url), "http://%s:%d/notifyft", 
5217                        yss->filetransfer_host, yss->filetransfer_port);
5218        snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s",
5219                        yd->cookie_y, yd->cookie_t);
5220        inputs = y_list_prepend(inputs, yid);
5221
5222        sfd = y_new0(struct send_file_data, 1);
5223        sfd->pkt = pkt;
5224        sfd->callback = callback;
5225        sfd->user_data = data;
5226        yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size,
5227                        _yahoo_send_file_connected, sfd);
5228}
5229
5230
5231enum yahoo_status yahoo_current_status(int id)
5232{
5233        struct yahoo_data *yd = find_conn_by_id(id);
5234        if(!yd)
5235                return YAHOO_STATUS_OFFLINE;
5236        return yd->current_status;
5237}
5238
5239const YList * yahoo_get_buddylist(int id)
5240{
5241        struct yahoo_data *yd = find_conn_by_id(id);
5242        if(!yd)
5243                return NULL;
5244        return yd->buddies;
5245}
5246
5247const YList * yahoo_get_ignorelist(int id)
5248{
5249        struct yahoo_data *yd = find_conn_by_id(id);
5250        if(!yd)
5251                return NULL;
5252        return yd->ignore;
5253}
5254
5255const YList * yahoo_get_identities(int id)
5256{
5257        struct yahoo_data *yd = find_conn_by_id(id);
5258        if(!yd)
5259                return NULL;
5260        return yd->identities;
5261}
5262
5263const char * yahoo_get_cookie(int id, const char *which)
5264{
5265        struct yahoo_data *yd = find_conn_by_id(id);
5266        if(!yd)
5267                return NULL;
5268        if(!strncasecmp(which, "y", 1))
5269                return yd->cookie_y;
5270        if(!strncasecmp(which, "t", 1))
5271                return yd->cookie_t;
5272        if(!strncasecmp(which, "c", 1))
5273                return yd->cookie_c;
5274        if(!strncasecmp(which, "login", 5))
5275                return yd->login_cookie;
5276        return NULL;
5277}
5278
5279void yahoo_get_url_handle(int id, const char *url, 
5280                yahoo_get_url_handle_callback callback, void *data)
5281{
5282        struct yahoo_data *yd = find_conn_by_id(id);
5283        if(!yd)
5284                return;
5285
5286        yahoo_get_url_fd(id, url, yd, callback, data);
5287}
5288
5289const char * yahoo_get_profile_url( void )
5290{
5291        return profile_url;
5292}
5293
Note: See TracBrowser for help on using the repository browser.