source: protocols/yahoo/libyahoo2.c @ 5674207

Last change on this file since 5674207 was 99c8f13, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-17T14:48:21Z

Valgrind pointed me at some memory leaks in the Yahoo! codek, including one
that existed for a while already. Fixed.

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