source: protocols/yahoo/libyahoo2.c @ 75ec2c8

Last change on this file since 75ec2c8 was be915f5, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-06T18:19:31Z

Yahoo! fixes. Turns out the protocol really is somewhat odd.

  • 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                                YList *last;
1536                                struct yahoo_buddy *lastbud;
1537                               
1538                                for (last = yd->buddies; last && last->next; last = last->next);
1539                                if (last) {
1540                                        lastbud = last->data;
1541                                        newbud->group = strdup(lastbud->group);
1542                                } else {
1543                                        newbud->group = strdup("Buddies");
1544                                }
1545                        }
1546
1547                        yd->buddies = y_list_append(yd->buddies, newbud);
1548
1549                        break;
1550                }
1551        }
1552       
1553        g_free(cur_group);
1554
1555        /* we could be getting multiple packets here */
1556        if (last_packet)
1557                return;
1558
1559        YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
1560
1561        /*** We login at the very end of the packet communication */
1562        if (!yd->logged_in) {
1563                yd->logged_in = TRUE;
1564                if(yd->current_status < 0)
1565                        yd->current_status = yd->initial_status;
1566                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
1567        }
1568}
1569
1570static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1571{
1572        struct yahoo_data *yd = yid->yd;
1573        YList *l;
1574
1575        if (!yd->logged_in) {
1576                yd->logged_in = TRUE;
1577                if(yd->current_status < 0)
1578                        yd->current_status = yd->initial_status;
1579                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
1580        }
1581
1582        for (l = pkt->hash; l; l = l->next) {
1583                struct yahoo_pair *pair = l->data;
1584
1585                switch(pair->key) {
1586                case 87: /* buddies */
1587                        if(!yd->rawbuddylist)
1588                                yd->rawbuddylist = strdup(pair->value);
1589                        else {
1590                                yd->rawbuddylist = y_string_append(yd->rawbuddylist, pair->value);
1591                        }
1592                        break;
1593
1594                case 88: /* ignore list */
1595                        if(!yd->ignorelist)
1596                                yd->ignorelist = strdup("Ignore:");
1597                        yd->ignorelist = y_string_append(yd->ignorelist, pair->value);
1598                        break;
1599
1600                case 89: /* identities */
1601                        {
1602                        char **identities = y_strsplit(pair->value, ",", -1);
1603                        int i;
1604                        for(i=0; identities[i]; i++)
1605                                yd->identities = y_list_append(yd->identities, 
1606                                                strdup(identities[i]));
1607                        y_strfreev(identities);
1608                        }
1609                        YAHOO_CALLBACK(ext_yahoo_got_identities)(yd->client_id, yd->identities);
1610                        break;
1611                case 59: /* cookies */
1612                        if(yd->ignorelist) {
1613                                yd->ignore = bud_str2list(yd->ignorelist);
1614                                FREE(yd->ignorelist);
1615                                YAHOO_CALLBACK(ext_yahoo_got_ignore)(yd->client_id, yd->ignore);
1616                        }
1617                        if(yd->rawbuddylist) {
1618                                yd->buddies = bud_str2list(yd->rawbuddylist);
1619                                FREE(yd->rawbuddylist);
1620                                YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
1621                        }
1622
1623                        if(pair->value[0]=='Y') {
1624                                FREE(yd->cookie_y);
1625                                FREE(yd->login_cookie);
1626
1627                                yd->cookie_y = getcookie(pair->value);
1628                                yd->login_cookie = getlcookie(yd->cookie_y);
1629
1630                        } else if(pair->value[0]=='T') {
1631                                FREE(yd->cookie_t);
1632                                yd->cookie_t = getcookie(pair->value);
1633
1634                        } else if(pair->value[0]=='C') {
1635                                FREE(yd->cookie_c);
1636                                yd->cookie_c = getcookie(pair->value);
1637                        } 
1638
1639                        if(yd->cookie_y && yd->cookie_t)
1640                                YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id);
1641
1642                        break;
1643                case 3: /* my id */
1644                case 90: /* 1 */
1645                case 100: /* 0 */
1646                case 101: /* NULL */
1647                case 102: /* NULL */
1648                case 93: /* 86400/1440 */
1649                        break;
1650                }
1651        }
1652}
1653
1654static void yahoo_process_verify(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1655{
1656        struct yahoo_data *yd = yid->yd;
1657
1658        if(pkt->status != 0x01) {
1659                DEBUG_MSG(("expected status: 0x01, got: %d", pkt->status));
1660                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_LOCK, "");
1661                return;
1662        }
1663
1664        pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
1665
1666        yahoo_packet_hash(pkt, 1, yd->user);
1667        yahoo_send_packet(yid, pkt, 0);
1668
1669        yahoo_packet_free(pkt);
1670
1671}
1672
1673static void yahoo_process_picture_checksum( struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1674{
1675        struct yahoo_data *yd = yid->yd;
1676        char *from = NULL;
1677        char *to = NULL;
1678        int checksum = 0;
1679        YList *l;
1680
1681        for(l = pkt->hash; l; l = l->next)
1682        {
1683                struct yahoo_pair *pair = l->data;
1684
1685                switch(pair->key)
1686                {
1687                        case 1:
1688                        case 4:
1689                                from = pair->value;
1690                        case 5:
1691                                to = pair->value;
1692                                break;
1693                        case 212:
1694                                break;
1695                        case 192:
1696                                checksum = atoi( pair->value );
1697                                break;
1698                }
1699        }
1700
1701        YAHOO_CALLBACK(ext_yahoo_got_buddyicon_checksum)(yd->client_id,to,from,checksum);
1702}
1703
1704static void yahoo_process_picture(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1705{
1706        struct yahoo_data *yd = yid->yd;
1707        char *url = NULL;
1708        char *from = NULL;
1709        char *to = NULL;
1710        int status = 0;
1711        int checksum = 0;
1712        YList *l;
1713       
1714        for(l = pkt->hash; l; l = l->next)
1715        {
1716                struct yahoo_pair *pair = l->data;
1717
1718                switch(pair->key)
1719                {
1720                case 1:
1721                case 4:         /* sender */
1722                        from = pair->value;
1723                        break;
1724                case 5:         /* we */
1725                        to = pair->value;
1726                        break;
1727                case 13:                /* request / sending */
1728                        status = atoi( pair->value );
1729                        break;
1730                case 20:                /* url */
1731                        url = pair->value;
1732                        break;
1733                case 192:       /*checksum */
1734                        checksum = atoi( pair->value );
1735                        break;
1736                }
1737        }
1738
1739        switch( status )
1740        {
1741                case 1: /* this is a request, ignore for now */
1742                        YAHOO_CALLBACK(ext_yahoo_got_buddyicon_request)(yd->client_id, to, from);
1743                        break;
1744                case 2: /* this is cool - we get a picture :) */
1745                        YAHOO_CALLBACK(ext_yahoo_got_buddyicon)(yd->client_id,to, from, url, checksum);
1746                        break;
1747        }
1748}
1749
1750static void yahoo_process_picture_upload(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1751{
1752        struct yahoo_data *yd = yid->yd;
1753        YList *l;
1754        char *url = NULL;
1755
1756        if ( pkt->status != 1 )
1757                return;         /* something went wrong */
1758       
1759        for(l = pkt->hash; l; l = l->next)
1760        {
1761                struct yahoo_pair *pair = l->data;
1762
1763                switch(pair->key)
1764                {
1765                        case 5:         /* we */
1766                                break;
1767                        case 20:                /* url */
1768                                url = pair->value;
1769                                break;
1770                        case 27:                /* local filename */
1771                                break;
1772                        case 38:                /* time */
1773                                break;
1774                }
1775        }
1776
1777        YAHOO_CALLBACK(ext_yahoo_buddyicon_uploaded)(yd->client_id, url);
1778}
1779
1780static void yahoo_process_auth_pre_0x0b(struct yahoo_input_data *yid, 
1781                const char *seed, const char *sn)
1782{
1783        struct yahoo_data *yd = yid->yd;
1784       
1785        /* So, Yahoo has stopped supporting its older clients in India, and
1786         * undoubtedly will soon do so in the rest of the world.
1787         *
1788         * The new clients use this authentication method.  I warn you in
1789         * advance, it's bizzare, convoluted, inordinately complicated. 
1790         * It's also no more secure than crypt() was.  The only purpose this
1791         * scheme could serve is to prevent third part clients from connecting
1792         * to their servers.
1793         *
1794         * Sorry, Yahoo.
1795         */
1796
1797        struct yahoo_packet *pack;
1798       
1799        md5_byte_t result[16];
1800        md5_state_t ctx;
1801        char *crypt_result;
1802        unsigned char *password_hash = malloc(25);
1803        unsigned char *crypt_hash = malloc(25);
1804        unsigned char *hash_string_p = malloc(50 + strlen(sn));
1805        unsigned char *hash_string_c = malloc(50 + strlen(sn));
1806       
1807        char checksum;
1808       
1809        int sv;
1810       
1811        unsigned char *result6 = malloc(25);
1812        unsigned char *result96 = malloc(25);
1813
1814        sv = seed[15];
1815        sv = (sv % 8) % 5;
1816
1817        md5_init(&ctx);
1818        md5_append(&ctx, (md5_byte_t *)yd->password, strlen(yd->password));
1819        md5_finish(&ctx, result);
1820        to_y64(password_hash, result, 16);
1821       
1822        md5_init(&ctx);
1823        crypt_result = yahoo_crypt(yd->password, "$1$_2S43d5f$"); 
1824        md5_append(&ctx, (md5_byte_t *)crypt_result, strlen(crypt_result));
1825        md5_finish(&ctx, result);
1826        to_y64(crypt_hash, result, 16);
1827        free(crypt_result);
1828
1829        switch (sv) {
1830        case 0:
1831                checksum = seed[seed[7] % 16];
1832                snprintf((char *)hash_string_p, strlen(sn) + 50,
1833                        "%c%s%s%s", checksum, password_hash, yd->user, seed);
1834                snprintf((char *)hash_string_c, strlen(sn) + 50,
1835                        "%c%s%s%s", checksum, crypt_hash, yd->user, seed);
1836                break;
1837        case 1:
1838                checksum = seed[seed[9] % 16];
1839                snprintf((char *)hash_string_p, strlen(sn) + 50,
1840                        "%c%s%s%s", checksum, yd->user, seed, password_hash);
1841                snprintf((char *)hash_string_c, strlen(sn) + 50,
1842                        "%c%s%s%s", checksum, yd->user, seed, crypt_hash);
1843                break;
1844        case 2:
1845                checksum = seed[seed[15] % 16];
1846                snprintf((char *)hash_string_p, strlen(sn) + 50,
1847                        "%c%s%s%s", checksum, seed, password_hash, yd->user);
1848                snprintf((char *)hash_string_c, strlen(sn) + 50,
1849                        "%c%s%s%s", checksum, seed, crypt_hash, yd->user);
1850                break;
1851        case 3:
1852                checksum = seed[seed[1] % 16];
1853                snprintf((char *)hash_string_p, strlen(sn) + 50,
1854                        "%c%s%s%s", checksum, yd->user, password_hash, seed);
1855                snprintf((char *)hash_string_c, strlen(sn) + 50,
1856                        "%c%s%s%s", checksum, yd->user, crypt_hash, seed);
1857                break;
1858        case 4:
1859                checksum = seed[seed[3] % 16];
1860                snprintf((char *)hash_string_p, strlen(sn) + 50,
1861                        "%c%s%s%s", checksum, password_hash, seed, yd->user);
1862                snprintf((char *)hash_string_c, strlen(sn) + 50,
1863                        "%c%s%s%s", checksum, crypt_hash, seed, yd->user);
1864                break;
1865        }
1866               
1867        md5_init(&ctx); 
1868        md5_append(&ctx, (md5_byte_t *)hash_string_p, strlen((char *)hash_string_p));
1869        md5_finish(&ctx, result);
1870        to_y64(result6, result, 16);
1871
1872        md5_init(&ctx); 
1873        md5_append(&ctx, (md5_byte_t *)hash_string_c, strlen((char *)hash_string_c));
1874        md5_finish(&ctx, result);
1875        to_y64(result96, result, 16);
1876
1877        pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
1878        yahoo_packet_hash(pack, 0, yd->user);
1879        yahoo_packet_hash(pack, 6, (char *)result6);
1880        yahoo_packet_hash(pack, 96, (char *)result96);
1881        yahoo_packet_hash(pack, 1, yd->user);
1882               
1883        yahoo_send_packet(yid, pack, 0);
1884               
1885        FREE(result6);
1886        FREE(result96);
1887        FREE(password_hash);
1888        FREE(crypt_hash);
1889        FREE(hash_string_p);
1890        FREE(hash_string_c);
1891
1892        yahoo_packet_free(pack);
1893
1894}
1895
1896/*
1897 * New auth protocol cracked by Cerulean Studios and sent in to Gaim
1898 */
1899static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *seed, const char *sn)
1900{
1901        struct yahoo_packet *pack = NULL;
1902        struct yahoo_data *yd = yid->yd;
1903
1904        md5_byte_t         result[16];
1905        md5_state_t        ctx;
1906
1907        sha1_state_t       ctx1;
1908        sha1_state_t       ctx2;
1909
1910        char *alphabet1 = "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ";
1911        char *alphabet2 = "F0E1D2C3B4A59687abcdefghijklmnop";
1912
1913        char *challenge_lookup = "qzec2tb3um1olpar8whx4dfgijknsvy5";
1914        char *operand_lookup = "+|&%/*^-";
1915        char *delimit_lookup = ",;";
1916
1917        unsigned char *password_hash = malloc(25);
1918        unsigned char *crypt_hash = malloc(25);
1919        char *crypt_result = NULL;
1920        unsigned char pass_hash_xor1[64];
1921        unsigned char pass_hash_xor2[64];
1922        unsigned char crypt_hash_xor1[64];
1923        unsigned char crypt_hash_xor2[64];
1924        unsigned char chal[7];
1925        char resp_6[100];
1926        char resp_96[100];
1927
1928        unsigned char digest1[20];
1929        unsigned char digest2[20];
1930        unsigned char magic_key_char[4];
1931        const unsigned char *magic_ptr;
1932
1933        unsigned int  magic[64];
1934        unsigned int  magic_work=0;
1935
1936        char comparison_src[20];
1937
1938        int x, j, i;
1939        int cnt = 0;
1940        int magic_cnt = 0;
1941        int magic_len;
1942        int depth =0, table =0;
1943
1944        memset(&pass_hash_xor1, 0, 64);
1945        memset(&pass_hash_xor2, 0, 64);
1946        memset(&crypt_hash_xor1, 0, 64);
1947        memset(&crypt_hash_xor2, 0, 64);
1948        memset(&digest1, 0, 20);
1949        memset(&digest2, 0, 20);
1950        memset(&magic, 0, 64);
1951        memset(&resp_6, 0, 100);
1952        memset(&resp_96, 0, 100);
1953        memset(&magic_key_char, 0, 4);
1954
1955        /*
1956         * Magic: Phase 1.  Generate what seems to be a 30
1957         * byte value (could change if base64
1958         * ends up differently?  I don't remember and I'm
1959         * tired, so use a 64 byte buffer.
1960         */
1961
1962        magic_ptr = (unsigned char *)seed;
1963
1964        while (*magic_ptr != 0) {
1965                char *loc;
1966
1967                /* Ignore parentheses.  */
1968
1969                if (*magic_ptr == '(' || *magic_ptr == ')') {
1970                        magic_ptr++;
1971                        continue;
1972                }
1973
1974                /* Characters and digits verify against
1975                   the challenge lookup.
1976                */
1977
1978                if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) {
1979                        loc = strchr(challenge_lookup, *magic_ptr);
1980                        if (!loc) {
1981                                /* This isn't good */
1982                                continue;
1983                        }
1984
1985                        /* Get offset into lookup table and lsh 3. */
1986
1987                        magic_work = loc - challenge_lookup;
1988                        magic_work <<= 3;
1989
1990                        magic_ptr++;
1991                        continue;
1992                } else {
1993                        unsigned int local_store;
1994
1995                        loc = strchr(operand_lookup, *magic_ptr);
1996                        if (!loc) {
1997                                /* Also not good. */
1998                                continue;
1999                        }
2000
2001                        local_store = loc - operand_lookup;
2002
2003                        /* Oops; how did this happen? */
2004                        if (magic_cnt >= 64) 
2005                                break;
2006
2007                        magic[magic_cnt++] = magic_work | local_store;
2008                        magic_ptr++;
2009                        continue;
2010                }
2011        }
2012
2013        magic_len = magic_cnt;
2014        magic_cnt = 0;
2015
2016        /* Magic: Phase 2.  Take generated magic value and
2017         * sprinkle fairy dust on the values. */
2018
2019        for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) {
2020                unsigned char byte1;
2021                unsigned char byte2;
2022
2023                /* Bad.  Abort.
2024                 */
2025                if (magic_cnt >= magic_len) {
2026                        WARNING(("magic_cnt(%d)  magic_len(%d)", magic_cnt, magic_len))
2027                        break;
2028                }
2029
2030                byte1 = magic[magic_cnt];
2031                byte2 = magic[magic_cnt+1];
2032
2033                byte1 *= 0xcd;
2034                byte1 ^= byte2;
2035
2036                magic[magic_cnt+1] = byte1;
2037        }
2038
2039        /* Magic: Phase 3.  This computes 20 bytes.  The first 4 bytes are used as our magic
2040         * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key
2041         * plus 3 bytes.  The 3 bytes are found by looping, and they represent the offsets
2042         * into particular functions we'll later call to potentially alter the magic key.
2043         *
2044         * %-)
2045         */ 
2046       
2047        magic_cnt = 1; 
2048        x = 0; 
2049       
2050        do { 
2051                unsigned int     bl = 0; 
2052                unsigned int     cl = magic[magic_cnt++]; 
2053               
2054                if (magic_cnt >= magic_len) 
2055                        break; 
2056               
2057                if (cl > 0x7F) { 
2058                        if (cl < 0xe0) 
2059                                bl = cl = (cl & 0x1f) << 6; 
2060                        else { 
2061                                bl = magic[magic_cnt++]; 
2062                              cl = (cl & 0x0f) << 6; 
2063                              bl = ((bl & 0x3f) + cl) << 6; 
2064                        } 
2065                       
2066                        cl = magic[magic_cnt++]; 
2067                        bl = (cl & 0x3f) + bl; 
2068                } else 
2069                        bl = cl; 
2070               
2071                comparison_src[x++] = (bl & 0xff00) >> 8; 
2072                comparison_src[x++] = bl & 0xff; 
2073        } while (x < 20); 
2074
2075        /* Dump magic key into a char for SHA1 action. */
2076       
2077               
2078        for(x = 0; x < 4; x++) 
2079                magic_key_char[x] = comparison_src[x];
2080
2081        /* Compute values for recursive function table! */
2082        memcpy( chal, magic_key_char, 4 );
2083        x = 1;
2084        for( i = 0; i < 0xFFFF && x; i++ )
2085        {
2086                for( j = 0; j < 5 && x; j++ )
2087                {
2088                        chal[4] = i;
2089                        chal[5] = i >> 8;
2090                        chal[6] = j;
2091                        md5_init( &ctx );
2092                        md5_append( &ctx, chal, 7 );
2093                        md5_finish( &ctx, result );
2094                        if( memcmp( comparison_src + 4, result, 16 ) == 0 )
2095                        {
2096                                depth = i;
2097                                table = j;
2098                                x = 0;
2099                        }
2100                }
2101        }
2102
2103        /* Transform magic_key_char using transform table */
2104        x = magic_key_char[3] << 24  | magic_key_char[2] << 16 
2105                | magic_key_char[1] << 8 | magic_key_char[0];
2106        x = yahoo_xfrm( table, depth, x );
2107        x = yahoo_xfrm( table, depth, x );
2108        magic_key_char[0] = x & 0xFF;
2109        magic_key_char[1] = x >> 8 & 0xFF;
2110        magic_key_char[2] = x >> 16 & 0xFF;
2111        magic_key_char[3] = x >> 24 & 0xFF;
2112
2113        /* Get password and crypt hashes as per usual. */
2114        md5_init(&ctx);
2115        md5_append(&ctx, (md5_byte_t *)yd->password,  strlen(yd->password));
2116        md5_finish(&ctx, result);
2117        to_y64(password_hash, result, 16);
2118
2119        md5_init(&ctx);
2120        crypt_result = yahoo_crypt(yd->password, "$1$_2S43d5f$"); 
2121        md5_append(&ctx, (md5_byte_t *)crypt_result, strlen(crypt_result));
2122        md5_finish(&ctx, result);
2123        to_y64(crypt_hash, result, 16);
2124        free(crypt_result);
2125
2126        /* Our first authentication response is based off
2127         * of the password hash. */
2128
2129        for (x = 0; x < (int)strlen((char *)password_hash); x++) 
2130                pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36;
2131
2132        if (cnt < 64) 
2133                memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt);
2134
2135        cnt = 0;
2136
2137        for (x = 0; x < (int)strlen((char *)password_hash); x++) 
2138                pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c;
2139
2140        if (cnt < 64) 
2141                memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt);
2142
2143        sha1_init(&ctx1);
2144        sha1_init(&ctx2);
2145
2146        /* The first context gets the password hash XORed
2147         * with 0x36 plus a magic value
2148         * which we previously extrapolated from our
2149         * challenge. */
2150
2151        sha1_append(&ctx1, pass_hash_xor1, 64);
2152        if (j >= 3 )
2153                ctx1.Length_Low = 0x1ff;
2154        sha1_append(&ctx1, magic_key_char, 4);
2155        sha1_finish(&ctx1, digest1);
2156
2157         /* The second context gets the password hash XORed
2158          * with 0x5c plus the SHA-1 digest
2159          * of the first context. */
2160
2161        sha1_append(&ctx2, pass_hash_xor2, 64);
2162        sha1_append(&ctx2, digest1, 20);
2163        sha1_finish(&ctx2, digest2);
2164
2165        /* Now that we have digest2, use it to fetch
2166         * characters from an alphabet to construct
2167         * our first authentication response. */
2168
2169        for (x = 0; x < 20; x += 2) {
2170                unsigned int    val = 0;
2171                unsigned int    lookup = 0;
2172                char            byte[6];
2173
2174                memset(&byte, 0, 6);
2175
2176                /* First two bytes of digest stuffed
2177                 *  together.
2178                 */
2179
2180                val = digest2[x];
2181                val <<= 8;
2182                val += digest2[x+1];
2183
2184                lookup = (val >> 0x0b);
2185                lookup &= 0x1f;
2186                if (lookup >= strlen(alphabet1))
2187                        break;
2188                sprintf(byte, "%c", alphabet1[lookup]);
2189                strcat(resp_6, byte);
2190                strcat(resp_6, "=");
2191
2192                lookup = (val >> 0x06);
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                lookup &= 0x1f;
2201                if (lookup >= strlen(alphabet2))
2202                        break;
2203                sprintf(byte, "%c", alphabet2[lookup]);
2204                strcat(resp_6, byte);
2205
2206                lookup = (val & 0x01);
2207                if (lookup >= strlen(delimit_lookup))
2208                        break;
2209                sprintf(byte, "%c", delimit_lookup[lookup]);
2210                strcat(resp_6, byte);
2211        }
2212
2213        /* Our second authentication response is based off
2214         * of the crypto hash. */
2215
2216        cnt = 0;
2217        memset(&digest1, 0, 20);
2218        memset(&digest2, 0, 20);
2219
2220        for (x = 0; x < (int)strlen((char *)crypt_hash); x++) 
2221                crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36;
2222
2223        if (cnt < 64) 
2224                memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt);
2225
2226        cnt = 0;
2227
2228        for (x = 0; x < (int)strlen((char *)crypt_hash); x++) 
2229                crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c;
2230
2231        if (cnt < 64) 
2232                memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt);
2233
2234        sha1_init(&ctx1);
2235        sha1_init(&ctx2);
2236
2237        /* The first context gets the password hash XORed
2238         * with 0x36 plus a magic value
2239         * which we previously extrapolated from our
2240         * challenge. */
2241
2242        sha1_append(&ctx1, crypt_hash_xor1, 64);
2243        if (j >= 3 )
2244                ctx1.Length_Low = 0x1ff;
2245        sha1_append(&ctx1, magic_key_char, 4);
2246        sha1_finish(&ctx1, digest1);
2247
2248        /* The second context gets the password hash XORed
2249         * with 0x5c plus the SHA-1 digest
2250         * of the first context. */
2251
2252        sha1_append(&ctx2, crypt_hash_xor2, 64);
2253        sha1_append(&ctx2, digest1, 20);
2254        sha1_finish(&ctx2, digest2);
2255
2256        /* Now that we have digest2, use it to fetch
2257         * characters from an alphabet to construct
2258         * our first authentication response.  */
2259
2260        for (x = 0; x < 20; x += 2) {
2261                unsigned int val = 0;
2262                unsigned int lookup = 0;
2263
2264                char byte[6];
2265
2266                memset(&byte, 0, 6);
2267
2268                /* First two bytes of digest stuffed
2269                 *  together. */
2270
2271                val = digest2[x];
2272                val <<= 8;
2273                val += digest2[x+1];
2274
2275                lookup = (val >> 0x0b);
2276                lookup &= 0x1f;
2277                if (lookup >= strlen(alphabet1))
2278                        break;
2279                sprintf(byte, "%c", alphabet1[lookup]);
2280                strcat(resp_96, byte);
2281                strcat(resp_96, "=");
2282
2283                lookup = (val >> 0x06);
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                lookup &= 0x1f;
2292                if (lookup >= strlen(alphabet2))
2293                        break;
2294                sprintf(byte, "%c", alphabet2[lookup]);
2295                strcat(resp_96, byte);
2296
2297                lookup = (val & 0x01);
2298                if (lookup >= strlen(delimit_lookup))
2299                        break;
2300                sprintf(byte, "%c", delimit_lookup[lookup]);
2301                strcat(resp_96, byte);
2302        }
2303
2304        pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
2305        yahoo_packet_hash(pack, 0, sn);
2306        yahoo_packet_hash(pack, 6, resp_6);
2307        yahoo_packet_hash(pack, 96, resp_96);
2308        yahoo_packet_hash(pack, 1, sn);
2309        yahoo_send_packet(yid, pack, 0);
2310        yahoo_packet_free(pack);
2311
2312        free(password_hash);
2313        free(crypt_hash);
2314}
2315
2316struct yahoo_https_auth_data
2317{
2318        struct yahoo_input_data *yid;
2319        char *token;
2320        char *chal;
2321};
2322
2323static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had);
2324static void yahoo_https_auth_token_finish(struct http_request *req);
2325static void yahoo_https_auth_init(struct yahoo_https_auth_data *had);
2326static void yahoo_https_auth_finish(struct http_request *req);
2327
2328/* Extract a value from a login.yahoo.com response. Assume CRLF-linebreaks
2329   and FAIL miserably if they're not there... */
2330static char *yahoo_ha_find_key(char *response, char *key)
2331{
2332        char *s, *end;
2333        int len = strlen(key);
2334       
2335        s = response;
2336        do {
2337                if (strncmp(s, key, len) == 0 && s[len] == '=') {
2338                        s += len + 1;
2339                        if ((end = strchr(s, '\r')))
2340                                return g_strndup(s, end - s);
2341                        else
2342                                return g_strdup(s);
2343                }
2344               
2345                if ((s = strchr(s, '\n')))
2346                        s ++;
2347        } while (s && *s);
2348       
2349        return NULL;
2350}
2351
2352static enum yahoo_status yahoo_https_status_parse(int code)
2353{
2354        switch (code)
2355        {
2356                case 1212: return YAHOO_LOGIN_PASSWD;
2357                case 1213: return YAHOO_LOGIN_LOCK;
2358                case 1235: return YAHOO_LOGIN_UNAME;
2359                default: return (enum yahoo_status) code;
2360        }
2361}
2362
2363static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn)
2364{
2365        struct yahoo_https_auth_data *had = g_new0(struct yahoo_https_auth_data, 1);
2366       
2367        had->yid = yid;
2368        had->chal = g_strdup(seed);
2369       
2370        yahoo_https_auth_token_init(had);
2371}
2372
2373static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had)
2374{
2375        struct yahoo_input_data *yid = had->yid;
2376        struct yahoo_data *yd = yid->yd;
2377        struct http_request *req;
2378        char *login, *passwd, *chal;
2379        char *url;
2380       
2381        login = g_strndup(yd->user, 3 * strlen(yd->user));
2382        http_encode(login);
2383        passwd = g_strndup(yd->password, 3 * strlen(yd->password));
2384        http_encode(passwd);
2385        chal = g_strndup(had->chal, 3 * strlen(had->chal));
2386        http_encode(chal);
2387       
2388        url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=%d&login=%s&passwd=%s&chal=%s",
2389                               (int) time(NULL), login, passwd, chal);
2390       
2391        req = http_dorequest_url(url, yahoo_https_auth_token_finish, had);
2392       
2393        g_free(url);
2394        g_free(chal);
2395        g_free(passwd);
2396        g_free(login);
2397}
2398
2399static void yahoo_https_auth_token_finish(struct http_request *req)
2400{
2401        struct yahoo_https_auth_data *had = req->data;
2402        struct yahoo_input_data *yid;
2403        struct yahoo_data *yd;
2404        int st;
2405       
2406        if (y_list_find(inputs, had->yid) == NULL)
2407                return;
2408       
2409        yid = had->yid;
2410        yd = yid->yd;
2411       
2412        if (req->status_code != 200) {
2413                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
2414                goto fail;
2415        }
2416       
2417        if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
2418                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
2419                goto fail;
2420        }
2421       
2422        if ((had->token = yahoo_ha_find_key(req->reply_body, "ymsgr")) == NULL) {
2423                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3001, NULL);
2424                goto fail;
2425        }
2426       
2427        return yahoo_https_auth_init(had);
2428       
2429fail:
2430        g_free(had->token);
2431        g_free(had->chal);
2432        g_free(had);
2433}
2434
2435static void yahoo_https_auth_init(struct yahoo_https_auth_data *had)
2436{
2437        struct http_request *req;
2438        char *url;
2439       
2440        url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=%d&token=%s",
2441                              (int) time(NULL), had->token);
2442       
2443        req = http_dorequest_url(url, yahoo_https_auth_finish, had);
2444       
2445        g_free(url);
2446}
2447
2448static void yahoo_https_auth_finish(struct http_request *req)
2449{
2450        struct yahoo_https_auth_data *had = req->data;
2451        struct yahoo_input_data *yid;
2452        struct yahoo_data *yd;
2453        struct yahoo_packet *pack;
2454        char *crumb = NULL;
2455        int st;
2456       
2457        if (y_list_find(inputs, had->yid) == NULL)
2458                return;
2459       
2460        yid = had->yid;
2461        yd = yid->yd;
2462       
2463        md5_byte_t result[16];
2464        md5_state_t ctx;
2465       
2466        unsigned char yhash[32];
2467
2468        if (req->status_code != 200) {
2469                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
2470                goto fail;
2471        }
2472       
2473        if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
2474                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
2475                goto fail;
2476        }
2477       
2478        if ((yd->cookie_y = yahoo_ha_find_key(req->reply_body, "Y")) == NULL ||
2479            (yd->cookie_t = yahoo_ha_find_key(req->reply_body, "T")) == NULL ||
2480            (crumb = yahoo_ha_find_key(req->reply_body, "crumb")) == NULL) {
2481                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3002, NULL);
2482                goto fail;
2483        }
2484       
2485        md5_init(&ctx); 
2486        md5_append(&ctx, (unsigned char*) crumb, 11);
2487        md5_append(&ctx, (unsigned char*) had->chal, strlen(had->chal));
2488        md5_finish(&ctx, result);
2489        to_y64(yhash, result, 16);
2490
2491        pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
2492        yahoo_packet_hash(pack, 1, yd->user);
2493        yahoo_packet_hash(pack, 0, yd->user);
2494        yahoo_packet_hash(pack, 277, yd->cookie_y);
2495        yahoo_packet_hash(pack, 278, yd->cookie_t);
2496        yahoo_packet_hash(pack, 307, (char*) yhash);
2497        yahoo_packet_hash(pack, 244, "524223");
2498        yahoo_packet_hash(pack, 2, yd->user);
2499        yahoo_packet_hash(pack, 2, "1");
2500        yahoo_packet_hash(pack, 98, "us");
2501        yahoo_packet_hash(pack, 135, "7.5.0.647");
2502       
2503        yahoo_send_packet(yid, pack, 0);
2504               
2505        yahoo_packet_free(pack);
2506       
2507fail:
2508        g_free(crumb);
2509        g_free(had->token);
2510        g_free(had->chal);
2511        g_free(had);
2512}
2513
2514static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2515{
2516        char *seed = NULL;
2517        char *sn   = NULL;
2518        YList *l = pkt->hash;
2519        int m = 0;
2520
2521        while (l) {
2522                struct yahoo_pair *pair = l->data;
2523                if (pair->key == 94)
2524                        seed = pair->value;
2525                if (pair->key == 1)
2526                        sn = pair->value;
2527                if (pair->key == 13)
2528                        m = atoi(pair->value);
2529                l = l->next;
2530        }
2531
2532        if (!seed) 
2533                return;
2534
2535        switch (m) {
2536                case 0:
2537                        yahoo_process_auth_pre_0x0b(yid, seed, sn);
2538                        break;
2539                case 1:
2540                        yahoo_process_auth_0x0b(yid, seed, sn);
2541                        break;
2542                case 2:
2543                        yahoo_process_auth_0x10(yid, seed, sn);
2544                        break;
2545                default:
2546                        /* call error */
2547                        WARNING(("unknown auth type %d", m));
2548                        yahoo_process_auth_0x0b(yid, seed, sn);
2549                        break;
2550        }
2551}
2552
2553static void yahoo_process_auth_resp(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2554{
2555        struct yahoo_data *yd = yid->yd;
2556        char *login_id;
2557        char *handle;
2558        char *url=NULL;
2559        int  login_status=0;
2560
2561        YList *l;
2562
2563        for (l = pkt->hash; l; l = l->next) {
2564                struct yahoo_pair *pair = l->data;
2565                if (pair->key == 0)
2566                        login_id = pair->value;
2567                else if (pair->key == 1)
2568                        handle = pair->value;
2569                else if (pair->key == 20)
2570                        url = pair->value;
2571                else if (pair->key == 66)
2572                        login_status = atoi(pair->value);
2573        }
2574
2575        if(pkt->status == 0xffffffff) {
2576                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, login_status, url);
2577        /*      yahoo_logoff(yd->client_id);*/
2578        }
2579}
2580
2581static void yahoo_process_mail(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2582{
2583        struct yahoo_data *yd = yid->yd;
2584        char *who = NULL;
2585        char *email = NULL;
2586        char *subj = NULL;
2587        int count = 0;
2588        YList *l;
2589
2590        for (l = pkt->hash; l; l = l->next) {
2591                struct yahoo_pair *pair = l->data;
2592                if (pair->key == 9)
2593                        count = strtol(pair->value, NULL, 10);
2594                else if (pair->key == 43)
2595                        who = pair->value;
2596                else if (pair->key == 42)
2597                        email = pair->value;
2598                else if (pair->key == 18)
2599                        subj = pair->value;
2600                else
2601                        LOG(("key: %d => value: %s", pair->key, pair->value));
2602        }
2603
2604        if (who && email && subj) {
2605                char from[1024];
2606                snprintf(from, sizeof(from), "%s (%s)", who, email);
2607                YAHOO_CALLBACK(ext_yahoo_mail_notify)(yd->client_id, from, subj, count);
2608        } else if(count > 0)
2609                YAHOO_CALLBACK(ext_yahoo_mail_notify)(yd->client_id, NULL, NULL, count);
2610}
2611
2612static void yahoo_process_contact(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2613{
2614        struct yahoo_data *yd = yid->yd;
2615        char *id = NULL;
2616        char *who = NULL;
2617        char *msg = NULL;
2618        char *name = NULL;
2619        long tm = 0L;
2620        int state = YAHOO_STATUS_AVAILABLE;
2621        int online = FALSE;
2622        int away = 0;
2623        int idle = 0;
2624        int mobile = 0;
2625
2626        YList *l;
2627
2628        for (l = pkt->hash; l; l = l->next) {
2629                struct yahoo_pair *pair = l->data;
2630                if (pair->key == 1)
2631                        id = pair->value;
2632                else if (pair->key == 3)
2633                        who = pair->value;
2634                else if (pair->key == 14)
2635                        msg = pair->value;
2636                else if (pair->key == 7)
2637                        name = pair->value;
2638                else if (pair->key == 10)
2639                        state = strtol(pair->value, NULL, 10);
2640                else if (pair->key == 15)
2641                        tm = strtol(pair->value, NULL, 10);
2642                else if (pair->key == 13)
2643                        online = strtol(pair->value, NULL, 10);
2644                else if (pair->key == 47)
2645                        away = strtol(pair->value, NULL, 10);
2646                else if (pair->key == 137)
2647                        idle = strtol(pair->value, NULL, 10);
2648                else if (pair->key == 60)
2649                        mobile = strtol(pair->value, NULL, 10);
2650               
2651        }
2652
2653        if (id)
2654                YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, id, who, msg);
2655        else if (name)
2656                YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away, idle, mobile);
2657        else if(pkt->status == 0x07)
2658                YAHOO_CALLBACK(ext_yahoo_rejected)(yd->client_id, who, msg);
2659}
2660
2661static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2662{
2663        struct yahoo_data *yd = yid->yd;
2664        char *who = NULL;
2665        char *where = NULL;
2666        int status = 0;
2667        char *me = NULL;
2668
2669        struct yahoo_buddy *bud=NULL;
2670
2671        YList *l;
2672        for (l = pkt->hash; l; l = l->next) {
2673                struct yahoo_pair *pair = l->data;
2674                if (pair->key == 1)
2675                        me = pair->value;
2676                if (pair->key == 7)
2677                        who = pair->value;
2678                if (pair->key == 65)
2679                        where = pair->value;
2680                if (pair->key == 66)
2681                        status = strtol(pair->value, NULL, 10);
2682        }
2683
2684        yahoo_dump_unhandled(pkt);
2685
2686        if(!who)
2687                return;
2688        if(!where)
2689                where = "Unknown";
2690
2691        /* status: 0 == Successful, 1 == Error (does not exist), 2 == Already in list */
2692        if( status == 0 ) {
2693                bud = y_new0(struct yahoo_buddy, 1);
2694                bud->id = strdup(who);
2695                bud->group = strdup(where);
2696                bud->real_name = NULL;
2697               
2698                yd->buddies = y_list_append(yd->buddies, bud);
2699       
2700                /* Possibly called already, but at least the call above doesn't
2701                   seem to happen every time (not anytime I tried). */
2702                YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, me, who, NULL);
2703        }
2704
2705/*      YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */
2706}
2707
2708static void yahoo_process_contact_ymsg13(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2709{
2710        char* who=NULL;
2711        char* me=NULL; 
2712        char* msg=NULL;
2713        YList *l;
2714        for (l = pkt->hash; l; l = l->next) {
2715                struct yahoo_pair *pair = l->data;
2716                if (pair->key == 4)
2717                        who = pair->value;
2718                else if (pair->key == 5)
2719                        me = pair->value;
2720                else
2721                        DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value));
2722        }
2723
2724        if(pkt->status==3)
2725                YAHOO_CALLBACK(ext_yahoo_contact_auth_request)(yid->yd->client_id, me, who, msg);
2726}
2727
2728static void yahoo_process_buddydel(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2729{
2730        struct yahoo_data *yd = yid->yd;
2731        char *who = NULL;
2732        char *where = NULL;
2733        int unk_66 = 0;
2734        char *me = NULL;
2735        struct yahoo_buddy *bud;
2736
2737        YList *buddy;
2738
2739        YList *l;
2740        for (l = pkt->hash; l; l = l->next) {
2741                struct yahoo_pair *pair = l->data;
2742                if (pair->key == 1)
2743                        me = pair->value;
2744                else if (pair->key == 7)
2745                        who = pair->value;
2746                else if (pair->key == 65)
2747                        where = pair->value;
2748                else if (pair->key == 66)
2749                        unk_66 = strtol(pair->value, NULL, 10);
2750                else
2751                        DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value));
2752        }
2753
2754        if(!who || !where)
2755                return;
2756       
2757        bud = y_new0(struct yahoo_buddy, 1);
2758        bud->id = strdup(who);
2759        bud->group = strdup(where);
2760
2761        buddy = y_list_find_custom(yd->buddies, bud, is_same_bud);
2762
2763        FREE(bud->id);
2764        FREE(bud->group);
2765        FREE(bud);
2766
2767        if(buddy) {
2768                bud = buddy->data;
2769                yd->buddies = y_list_remove_link(yd->buddies, buddy);
2770                y_list_free_1(buddy);
2771
2772                FREE(bud->id);
2773                FREE(bud->group);
2774                FREE(bud->real_name);
2775                FREE(bud);
2776
2777                bud=NULL;
2778        }
2779}
2780
2781static void yahoo_process_ignore(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2782{
2783        char *who = NULL;
2784        int  status = 0;
2785        char *me = NULL;
2786        int  un_ignore = 0;
2787
2788        YList *l;
2789        for (l = pkt->hash; l; l = l->next) {
2790                struct yahoo_pair *pair = l->data;
2791                if (pair->key == 0)
2792                        who = pair->value;
2793                if (pair->key == 1)
2794                        me = pair->value;
2795                if (pair->key == 13) /* 1 == ignore, 2 == unignore */ 
2796                        un_ignore = strtol(pair->value, NULL, 10);
2797                if (pair->key == 66) 
2798                        status = strtol(pair->value, NULL, 10);
2799        }
2800
2801
2802        /*
2803         * status
2804         *      0  - ok
2805         *      2  - already in ignore list, could not add
2806         *      3  - not in ignore list, could not delete
2807         *      12 - is a buddy, could not add
2808         */
2809
2810/*      if(status)
2811                YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, who, 0, status);
2812*/     
2813}
2814
2815static void yahoo_process_voicechat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2816{
2817        char *who = NULL;
2818        char *me = NULL;
2819        char *room = NULL;
2820        char *voice_room = NULL;
2821
2822        YList *l;
2823        for (l = pkt->hash; l; l = l->next) {
2824                struct yahoo_pair *pair = l->data;
2825                if (pair->key == 4)
2826                        who = pair->value;
2827                if (pair->key == 5)
2828                        me = pair->value;
2829                if (pair->key == 13)
2830                        voice_room=pair->value;
2831                if (pair->key == 57) 
2832                        room=pair->value;
2833        }
2834
2835        NOTICE(("got voice chat invite from %s in %s to identity %s", who, room, me));
2836        /*
2837         * send: s:0 1:me 5:who 57:room 13:1
2838         * ????  s:4 5:who 10:99 19:-1615114531
2839         * gotr: s:4 5:who 10:99 19:-1615114615
2840         * ????  s:1 5:me 4:who 57:room 13:3room
2841         * got:  s:1 5:me 4:who 57:room 13:1room
2842         * rej:  s:0 1:me 5:who 57:room 13:3
2843         * rejr: s:4 5:who 10:99 19:-1617114599
2844         */
2845}
2846
2847static void yahoo_process_ping(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2848{
2849        char *errormsg = NULL;
2850       
2851        YList *l;
2852        for (l = pkt->hash; l; l = l->next) {
2853                struct yahoo_pair *pair = l->data;
2854                if (pair->key == 16)
2855                        errormsg = pair->value;
2856        }
2857       
2858        NOTICE(("got ping packet"));
2859        YAHOO_CALLBACK(ext_yahoo_got_ping)(yid->yd->client_id, errormsg);
2860}
2861
2862static void _yahoo_webcam_get_server_connected(int fd, int error, void *d)
2863{
2864        struct yahoo_input_data *yid = d;
2865        char *who = yid->wcm->user;
2866        char *data = NULL;
2867        char *packet = NULL;
2868        unsigned char magic_nr[] = {0, 1, 0};
2869        unsigned char header_len = 8;
2870        unsigned int len = 0;
2871        unsigned int pos = 0;
2872
2873        if(error || fd <= 0) {
2874                FREE(who);
2875                FREE(yid);
2876                return;
2877        }
2878
2879        yid->fd = fd;
2880        inputs = y_list_prepend(inputs, yid);
2881       
2882        /* send initial packet */
2883        if (who)
2884                data = strdup("<RVWCFG>");
2885        else
2886                data = strdup("<RUPCFG>");
2887        yahoo_add_to_send_queue(yid, data, strlen(data));
2888        FREE(data);
2889
2890        /* send data */
2891        if (who)
2892        {
2893                data = strdup("g=");
2894                data = y_string_append(data, who);
2895                data = y_string_append(data, "\r\n");
2896        } else {
2897                data = strdup("f=1\r\n");
2898        }
2899        len = strlen(data);
2900        packet = y_new0(char, header_len + len);
2901        packet[pos++] = header_len;
2902        memcpy(packet + pos, magic_nr, sizeof(magic_nr));
2903        pos += sizeof(magic_nr);
2904        pos += yahoo_put32(packet + pos, len);
2905        memcpy(packet + pos, data, len);
2906        pos += len;
2907        yahoo_add_to_send_queue(yid, packet, pos);
2908        FREE(packet);
2909        FREE(data);
2910
2911        yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, fd, YAHOO_INPUT_READ, yid);
2912}
2913
2914static void yahoo_webcam_get_server(struct yahoo_input_data *y, char *who, char *key)
2915{
2916        struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
2917        struct yahoo_server_settings *yss = y->yd->server_settings;
2918
2919        yid->type = YAHOO_CONNECTION_WEBCAM_MASTER;
2920        yid->yd = y->yd;
2921        yid->wcm = y_new0(struct yahoo_webcam, 1);
2922        yid->wcm->user = who?strdup(who):NULL;
2923        yid->wcm->direction = who?YAHOO_WEBCAM_DOWNLOAD:YAHOO_WEBCAM_UPLOAD;
2924        yid->wcm->key = strdup(key);
2925
2926        YAHOO_CALLBACK(ext_yahoo_connect_async)(yid->yd->client_id, yss->webcam_host, yss->webcam_port, 
2927                        _yahoo_webcam_get_server_connected, yid);
2928
2929}
2930
2931static YList *webcam_queue=NULL;
2932static void yahoo_process_webcam_key(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2933{
2934        char *me = NULL;
2935        char *key = NULL;
2936        char *who = NULL;
2937
2938        YList *l;
2939        // yahoo_dump_unhandled(pkt);
2940        for (l = pkt->hash; l; l = l->next) {
2941                struct yahoo_pair *pair = l->data;
2942                if (pair->key == 5)
2943                        me = pair->value;
2944                if (pair->key == 61) 
2945                        key=pair->value;
2946        }
2947
2948        l = webcam_queue;
2949        if(!l)
2950                return;
2951        who = l->data;
2952        webcam_queue = y_list_remove_link(webcam_queue, webcam_queue);
2953        y_list_free_1(l);
2954        yahoo_webcam_get_server(yid, who, key);
2955        FREE(who);
2956}
2957
2958static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2959{
2960        DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service));
2961        yahoo_dump_unhandled(pkt);
2962        switch (pkt->service)
2963        {
2964        case YAHOO_SERVICE_USERSTAT:
2965        case YAHOO_SERVICE_LOGON:
2966        case YAHOO_SERVICE_LOGOFF:
2967        case YAHOO_SERVICE_ISAWAY:
2968        case YAHOO_SERVICE_ISBACK:
2969        case YAHOO_SERVICE_GAMELOGON:
2970        case YAHOO_SERVICE_GAMELOGOFF:
2971        case YAHOO_SERVICE_IDACT:
2972        case YAHOO_SERVICE_IDDEACT:
2973        case YAHOO_SERVICE_Y6_STATUS_UPDATE:
2974        case YAHOO_SERVICE_YMSG15_STATUS:
2975                yahoo_process_status(yid, pkt);
2976                break;
2977        case YAHOO_SERVICE_NOTIFY:
2978                yahoo_process_notify(yid, pkt);
2979                break;
2980        case YAHOO_SERVICE_MESSAGE:
2981        case YAHOO_SERVICE_GAMEMSG:
2982        case YAHOO_SERVICE_SYSMESSAGE:
2983                yahoo_process_message(yid, pkt);
2984                break;
2985        case YAHOO_SERVICE_NEWMAIL:
2986                yahoo_process_mail(yid, pkt);
2987                break;
2988        case YAHOO_SERVICE_REJECTCONTACT:
2989        case YAHOO_SERVICE_NEWCONTACT:
2990                yahoo_process_contact(yid, pkt);
2991                break;
2992        case YAHOO_SERVICE_LIST:
2993                yahoo_process_list(yid, pkt);
2994                break;
2995        case YAHOO_SERVICE_VERIFY:
2996                yahoo_process_verify(yid, pkt);
2997                break;
2998        case YAHOO_SERVICE_AUTH:
2999                yahoo_process_auth(yid, pkt);
3000                break;
3001        case YAHOO_SERVICE_AUTHRESP:
3002                yahoo_process_auth_resp(yid, pkt);
3003                break;
3004        case YAHOO_SERVICE_CONFINVITE:
3005        case YAHOO_SERVICE_CONFADDINVITE:
3006        case YAHOO_SERVICE_CONFDECLINE:
3007        case YAHOO_SERVICE_CONFLOGON:
3008        case YAHOO_SERVICE_CONFLOGOFF:
3009        case YAHOO_SERVICE_CONFMSG:
3010                yahoo_process_conference(yid, pkt);
3011                break;
3012        case YAHOO_SERVICE_CHATONLINE:
3013        case YAHOO_SERVICE_CHATGOTO:
3014        case YAHOO_SERVICE_CHATJOIN:
3015        case YAHOO_SERVICE_CHATLEAVE:
3016        case YAHOO_SERVICE_CHATEXIT:
3017        case YAHOO_SERVICE_CHATLOGOUT:
3018        case YAHOO_SERVICE_CHATPING:
3019        case YAHOO_SERVICE_COMMENT:
3020                yahoo_process_chat(yid, pkt);
3021                break;
3022        case YAHOO_SERVICE_P2PFILEXFER:
3023        case YAHOO_SERVICE_FILETRANSFER:
3024                yahoo_process_filetransfer(yid, pkt);
3025                break;
3026        case YAHOO_SERVICE_ADDBUDDY:
3027                yahoo_process_buddyadd(yid, pkt);
3028                break;
3029        case YAHOO_SERVICE_CONTACT_YMSG13:
3030                yahoo_process_contact_ymsg13(yid,pkt);
3031                break;
3032        case YAHOO_SERVICE_REMBUDDY:
3033                yahoo_process_buddydel(yid, pkt);
3034                break;
3035        case YAHOO_SERVICE_IGNORECONTACT:
3036                yahoo_process_ignore(yid, pkt);
3037                break;
3038        case YAHOO_SERVICE_VOICECHAT:
3039                yahoo_process_voicechat(yid, pkt);
3040                break;
3041        case YAHOO_SERVICE_WEBCAM:
3042                yahoo_process_webcam_key(yid, pkt);
3043                break;
3044        case YAHOO_SERVICE_PING:
3045                yahoo_process_ping(yid, pkt);
3046                break;
3047        case YAHOO_SERVICE_IDLE:
3048        case YAHOO_SERVICE_MAILSTAT:
3049        case YAHOO_SERVICE_CHATINVITE:
3050        case YAHOO_SERVICE_CALENDAR:
3051        case YAHOO_SERVICE_NEWPERSONALMAIL:
3052        case YAHOO_SERVICE_ADDIDENT:
3053        case YAHOO_SERVICE_ADDIGNORE:
3054        case YAHOO_SERVICE_GOTGROUPRENAME:
3055        case YAHOO_SERVICE_GROUPRENAME:
3056        case YAHOO_SERVICE_PASSTHROUGH2:
3057        case YAHOO_SERVICE_CHATLOGON:
3058        case YAHOO_SERVICE_CHATLOGOFF:
3059        case YAHOO_SERVICE_CHATMSG:
3060        case YAHOO_SERVICE_PEERTOPEER:
3061                WARNING(("unhandled service 0x%02x", pkt->service));
3062                yahoo_dump_unhandled(pkt);
3063                break;
3064        case YAHOO_SERVICE_PICTURE:
3065                yahoo_process_picture(yid, pkt);
3066                break;
3067        case YAHOO_SERVICE_PICTURE_CHECKSUM:
3068                yahoo_process_picture_checksum(yid, pkt);
3069                break;
3070        case YAHOO_SERVICE_PICTURE_UPLOAD:
3071                yahoo_process_picture_upload(yid, pkt);
3072                break; 
3073        case YAHOO_SERVICE_YMSG15_BUDDY_LIST:   /* Buddy List */
3074                yahoo_process_buddy_list(yid, pkt);
3075        default:
3076                WARNING(("unknown service 0x%02x", pkt->service));
3077                yahoo_dump_unhandled(pkt);
3078                break;
3079        }
3080}
3081
3082static struct yahoo_packet * yahoo_getdata(struct yahoo_input_data * yid)
3083{
3084        struct yahoo_packet *pkt;
3085        struct yahoo_data *yd = yid->yd;
3086        int pos = 0;
3087        int pktlen;
3088
3089        if(!yd)
3090                return NULL;
3091
3092        DEBUG_MSG(("rxlen is %d", yid->rxlen));
3093        if (yid->rxlen < YAHOO_PACKET_HDRLEN) {
3094                DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN"));
3095                return NULL;
3096        }
3097
3098        pos += 4; /* YMSG */
3099        pos += 2;
3100        pos += 2;
3101
3102        pktlen = yahoo_get16(yid->rxqueue + pos); pos += 2;
3103        DEBUG_MSG(("%d bytes to read, rxlen is %d", 
3104                        pktlen, yid->rxlen));
3105
3106        if (yid->rxlen < (YAHOO_PACKET_HDRLEN + pktlen)) {
3107                DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN + pktlen"));
3108                return NULL;
3109        }
3110
3111        LOG(("reading packet"));
3112        yahoo_packet_dump(yid->rxqueue, YAHOO_PACKET_HDRLEN + pktlen);
3113
3114        pkt = yahoo_packet_new(0, 0, 0);
3115
3116        pkt->service = yahoo_get16(yid->rxqueue + pos); pos += 2;
3117        pkt->status = yahoo_get32(yid->rxqueue + pos); pos += 4;
3118        DEBUG_MSG(("Yahoo Service: 0x%02x Status: %d", pkt->service,
3119                                pkt->status));
3120        pkt->id = yahoo_get32(yid->rxqueue + pos); pos += 4;
3121
3122        yd->session_id = pkt->id;
3123
3124        yahoo_packet_read(pkt, yid->rxqueue + pos, pktlen);
3125
3126        yid->rxlen -= YAHOO_PACKET_HDRLEN + pktlen;
3127        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3128        if (yid->rxlen>0) {
3129                unsigned char *tmp = y_memdup(yid->rxqueue + YAHOO_PACKET_HDRLEN
3130                                + pktlen, yid->rxlen);
3131                FREE(yid->rxqueue);
3132                yid->rxqueue = tmp;
3133                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3134        } else {
3135                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3136                FREE(yid->rxqueue);
3137        }
3138
3139        return pkt;
3140}
3141
3142static void yahoo_yab_read(struct yab *yab, unsigned char *d, int len)
3143{
3144        char *st, *en;
3145        char *data = (char *)d;
3146        data[len]='\0';
3147
3148        DEBUG_MSG(("Got yab: %s", data));
3149        st = en = strstr(data, "userid=\"");
3150        if(st) {
3151                st += strlen("userid=\"");
3152                en = strchr(st, '"'); *en++ = '\0';
3153                yab->id = yahoo_xmldecode(st);
3154        }
3155
3156        st = strstr(en, "fname=\"");
3157        if(st) {
3158                st += strlen("fname=\"");
3159                en = strchr(st, '"'); *en++ = '\0';
3160                yab->fname = yahoo_xmldecode(st);
3161        }
3162
3163        st = strstr(en, "lname=\"");
3164        if(st) {
3165                st += strlen("lname=\"");
3166                en = strchr(st, '"'); *en++ = '\0';
3167                yab->lname = yahoo_xmldecode(st);
3168        }
3169
3170        st = strstr(en, "nname=\"");
3171        if(st) {
3172                st += strlen("nname=\"");
3173                en = strchr(st, '"'); *en++ = '\0';
3174                yab->nname = yahoo_xmldecode(st);
3175        }
3176
3177        st = strstr(en, "email=\"");
3178        if(st) {
3179                st += strlen("email=\"");
3180                en = strchr(st, '"'); *en++ = '\0';
3181                yab->email = yahoo_xmldecode(st);
3182        }
3183
3184        st = strstr(en, "hphone=\"");
3185        if(st) {
3186                st += strlen("hphone=\"");
3187                en = strchr(st, '"'); *en++ = '\0';
3188                yab->hphone = yahoo_xmldecode(st);
3189        }
3190
3191        st = strstr(en, "wphone=\"");
3192        if(st) {
3193                st += strlen("wphone=\"");
3194                en = strchr(st, '"'); *en++ = '\0';
3195                yab->wphone = yahoo_xmldecode(st);
3196        }
3197
3198        st = strstr(en, "mphone=\"");
3199        if(st) {
3200                st += strlen("mphone=\"");
3201                en = strchr(st, '"'); *en++ = '\0';
3202                yab->mphone = yahoo_xmldecode(st);
3203        }
3204
3205        st = strstr(en, "dbid=\"");
3206        if(st) {
3207                st += strlen("dbid=\"");
3208                en = strchr(st, '"'); *en++ = '\0';
3209                yab->dbid = atoi(st);
3210        }
3211}
3212
3213static struct yab * yahoo_getyab(struct yahoo_input_data *yid)
3214{
3215        struct yab *yab = NULL;
3216        int pos = 0, end=0;
3217        struct yahoo_data *yd = yid->yd;
3218
3219        if(!yd)
3220                return NULL;
3221
3222        DEBUG_MSG(("rxlen is %d", yid->rxlen));
3223
3224        if(yid->rxlen <= strlen("<record"))
3225                return NULL;
3226
3227        /* start with <record */
3228        while(pos < yid->rxlen-strlen("<record")+1 
3229                        && memcmp(yid->rxqueue + pos, "<record", strlen("<record")))
3230                pos++;
3231
3232        if(pos >= yid->rxlen-1)
3233                return NULL;
3234
3235        end = pos+2;
3236        /* end with /> */
3237        while(end < yid->rxlen-strlen("/>")+1 && memcmp(yid->rxqueue + end, "/>", strlen("/>")))
3238                end++;
3239
3240        if(end >= yid->rxlen-1)
3241                return NULL;
3242
3243        yab = y_new0(struct yab, 1);
3244        yahoo_yab_read(yab, yid->rxqueue + pos, end+2-pos);
3245       
3246
3247        yid->rxlen -= end+1;
3248        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3249        if (yid->rxlen>0) {
3250                unsigned char *tmp = y_memdup(yid->rxqueue + end + 1, yid->rxlen);
3251                FREE(yid->rxqueue);
3252                yid->rxqueue = tmp;
3253                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3254        } else {
3255                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3256                FREE(yid->rxqueue);
3257        }
3258
3259
3260        return yab;
3261}
3262
3263static char * yahoo_getwebcam_master(struct yahoo_input_data *yid)
3264{
3265        unsigned int pos=0;
3266        unsigned int len=0;
3267        unsigned int status=0;
3268        char *server=NULL;
3269        struct yahoo_data *yd = yid->yd;
3270
3271        if(!yid || !yd)
3272                return NULL;
3273
3274        DEBUG_MSG(("rxlen is %d", yid->rxlen));
3275
3276        len = yid->rxqueue[pos++];
3277        if (yid->rxlen < len)
3278                return NULL;
3279
3280        /* extract status (0 = ok, 6 = webcam not online) */
3281        status = yid->rxqueue[pos++];
3282
3283        if (status == 0)
3284        {
3285                pos += 2; /* skip next 2 bytes */
3286                server =  y_memdup(yid->rxqueue+pos, 16);
3287                pos += 16;
3288        }
3289        else if (status == 6)
3290        {
3291                YAHOO_CALLBACK(ext_yahoo_webcam_closed)
3292                        (yd->client_id, yid->wcm->user, 4);
3293        }
3294
3295        /* skip rest of the data */
3296
3297        yid->rxlen -= len;
3298        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3299        if (yid->rxlen>0) {
3300                unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
3301                FREE(yid->rxqueue);
3302                yid->rxqueue = tmp;
3303                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3304        } else {
3305                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3306                FREE(yid->rxqueue);
3307        }
3308
3309        return server;
3310}
3311
3312static int yahoo_get_webcam_data(struct yahoo_input_data *yid)
3313{
3314        unsigned char reason=0;
3315        unsigned int pos=0;
3316        unsigned int begin=0;
3317        unsigned int end=0;
3318        unsigned int closed=0;
3319        unsigned char header_len=0;
3320        char *who;
3321        int connect=0;
3322        struct yahoo_data *yd = yid->yd;
3323
3324        if(!yd)
3325                return -1;
3326
3327        if(!yid->wcm || !yid->wcd || !yid->rxlen)
3328                return -1;
3329
3330        DEBUG_MSG(("rxlen is %d", yid->rxlen));
3331
3332        /* if we are not reading part of image then read header */
3333        if (!yid->wcd->to_read)
3334        {
3335                header_len=yid->rxqueue[pos++];
3336                yid->wcd->packet_type=0;
3337
3338                if (yid->rxlen < header_len)
3339                        return 0;
3340
3341                if (header_len >= 8)
3342                {
3343                        reason = yid->rxqueue[pos++];
3344                        /* next 2 bytes should always be 05 00 */
3345                        pos += 2;
3346                        yid->wcd->data_size = yahoo_get32(yid->rxqueue + pos);
3347                        pos += 4;
3348                        yid->wcd->to_read = yid->wcd->data_size;
3349                }
3350                if (header_len >= 13)
3351                {
3352                        yid->wcd->packet_type = yid->rxqueue[pos++];
3353                        yid->wcd->timestamp = yahoo_get32(yid->rxqueue + pos);
3354                        pos += 4;
3355                }
3356
3357                /* skip rest of header */
3358                pos = header_len;
3359        }
3360
3361        begin = pos;
3362        pos += yid->wcd->to_read;
3363        if (pos > yid->rxlen) pos = yid->rxlen;
3364
3365        /* if it is not an image then make sure we have the whole packet */
3366        if (yid->wcd->packet_type != 0x02) {
3367                if ((pos - begin) != yid->wcd->data_size) {
3368                        yid->wcd->to_read = 0;
3369                        return 0;
3370                } else {
3371                        yahoo_packet_dump(yid->rxqueue + begin, pos - begin);
3372                }
3373        }
3374
3375        DEBUG_MSG(("packet type %.2X, data length %d", yid->wcd->packet_type,
3376                yid->wcd->data_size));
3377
3378        /* find out what kind of packet we got */
3379        switch (yid->wcd->packet_type)
3380        {
3381                case 0x00:
3382                        /* user requests to view webcam (uploading) */
3383                        if (yid->wcd->data_size &&
3384                                yid->wcm->direction == YAHOO_WEBCAM_UPLOAD) {
3385                                end = begin;
3386                                while (end <= yid->rxlen &&
3387                                        yid->rxqueue[end++] != 13);
3388                                if (end > begin)
3389                                {
3390                                        who = y_memdup(yid->rxqueue + begin, end - begin);
3391                                        who[end - begin - 1] = 0;
3392                                        YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who + 2, 2);
3393                                        FREE(who);
3394                                }
3395                        }
3396
3397                        if (yid->wcm->direction == YAHOO_WEBCAM_DOWNLOAD) {
3398                                /* timestamp/status field */
3399                                /* 0 = declined viewing permission */
3400                                /* 1 = accepted viewing permission */
3401                                if (yid->wcd->timestamp == 0) {
3402                                        YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, 3);
3403                                }
3404                        }
3405                        break;
3406                case 0x01: /* status packets?? */
3407                        /* timestamp contains status info */
3408                        /* 00 00 00 01 = we have data?? */
3409                        break;
3410                case 0x02: /* image data */
3411                        YAHOO_CALLBACK(ext_yahoo_got_webcam_image)(yd->client_id, 
3412                                        yid->wcm->user, yid->rxqueue + begin,
3413                                        yid->wcd->data_size, pos - begin,
3414                                        yid->wcd->timestamp);
3415                        break;
3416                case 0x05: /* response packets when uploading */
3417                        if (!yid->wcd->data_size) {
3418                                YAHOO_CALLBACK(ext_yahoo_webcam_data_request)(yd->client_id, yid->wcd->timestamp);
3419                        }
3420                        break;
3421                case 0x07: /* connection is closing */
3422                        switch(reason)
3423                        {
3424                                case 0x01: /* user closed connection */
3425                                        closed = 1;
3426                                        break;
3427                                case 0x0F: /* user cancelled permission */
3428                                        closed = 2;
3429                                        break;
3430                        }
3431                        YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, closed);
3432                        break;
3433                case 0x0C: /* user connected */
3434                case 0x0D: /* user disconnected */
3435                        if (yid->wcd->data_size) {
3436                                who = y_memdup(yid->rxqueue + begin, pos - begin + 1);
3437                                who[pos - begin] = 0;
3438                                if (yid->wcd->packet_type == 0x0C)
3439                                        connect=1;
3440                                else
3441                                        connect=0;
3442                                YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who, connect);
3443                                FREE(who);
3444                        }
3445                        break;
3446                case 0x13: /* user data */
3447                        /* i=user_ip (ip of the user we are viewing) */
3448                        /* j=user_ext_ip (external ip of the user we */
3449                        /*                are viewing) */
3450                        break;
3451                case 0x17: /* ?? */
3452                        break;
3453        }
3454        yid->wcd->to_read -= pos - begin;
3455
3456        yid->rxlen -= pos;
3457        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3458        if (yid->rxlen>0) {
3459                unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
3460                FREE(yid->rxqueue);
3461                yid->rxqueue = tmp;
3462                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3463        } else {
3464                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3465                FREE(yid->rxqueue);
3466        }
3467
3468        /* If we read a complete packet return success */
3469        if (!yid->wcd->to_read)
3470                return 1;
3471
3472        return 0;
3473}
3474
3475int yahoo_write_ready(int id, int fd, void *data)
3476{
3477        struct yahoo_input_data *yid = data;
3478        int len;
3479        struct data_queue *tx;
3480
3481        LOG(("write callback: id=%d fd=%d data=%p", id, fd, data));
3482        if(!yid || !yid->txqueues || !find_conn_by_id(id))
3483                return -2;
3484       
3485        tx = yid->txqueues->data;
3486        LOG(("writing %d bytes", tx->len));
3487        len = yahoo_send_data(fd, tx->queue, MIN(1024, tx->len));
3488
3489        if(len == -1 && errno == EAGAIN)
3490                return 1;
3491
3492        if(len <= 0) {
3493                int e = errno;
3494                DEBUG_MSG(("len == %d (<= 0)", len));
3495                while(yid->txqueues) {
3496                        YList *l=yid->txqueues;
3497                        tx = l->data;
3498                        free(tx->queue);
3499                        free(tx);
3500                        yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
3501                        y_list_free_1(l);
3502                }
3503                LOG(("yahoo_write_ready(%d, %d) len < 0", id, fd));
3504                YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
3505                yid->write_tag = 0;
3506                errno=e;
3507                return 0;
3508        }
3509
3510
3511        tx->len -= len;
3512        if(tx->len > 0) {
3513                unsigned char *tmp = y_memdup(tx->queue + len, tx->len);
3514                FREE(tx->queue);
3515                tx->queue = tmp;
3516        } else {
3517                YList *l=yid->txqueues;
3518                free(tx->queue);
3519                free(tx);
3520                yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
3521                y_list_free_1(l);
3522                /*
3523                if(!yid->txqueues)
3524                        LOG(("yahoo_write_ready(%d, %d) !yxqueues", id, fd));
3525                */
3526                if(!yid->txqueues) {
3527                        LOG(("yahoo_write_ready(%d, %d) !yxqueues", id, fd));
3528                        YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
3529                        yid->write_tag = 0;
3530                }
3531        }
3532
3533        return 1;
3534}
3535
3536static void yahoo_process_pager_connection(struct yahoo_input_data *yid, int over)
3537{
3538        struct yahoo_packet *pkt;
3539        struct yahoo_data *yd = yid->yd;
3540        int id = yd->client_id;
3541
3542        if(over)
3543                return;
3544
3545        while (find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER) 
3546                        && (pkt = yahoo_getdata(yid)) != NULL) {
3547
3548                yahoo_packet_process(yid, pkt);
3549
3550                yahoo_packet_free(pkt);
3551        }
3552}
3553
3554static void yahoo_process_ft_connection(struct yahoo_input_data *yid, int over)
3555{
3556}
3557
3558static void yahoo_process_chatcat_connection(struct yahoo_input_data *yid, int over)
3559{
3560        if(over)
3561                return;
3562
3563        if (strstr((char*)yid->rxqueue+(yid->rxlen-20), "</content>")) {
3564                YAHOO_CALLBACK(ext_yahoo_chat_cat_xml)(yid->yd->client_id, (char*)yid->rxqueue);
3565        }
3566}
3567
3568static void yahoo_process_yab_connection(struct yahoo_input_data *yid, int over)
3569{
3570        struct yahoo_data *yd = yid->yd;
3571        struct yab *yab;
3572        YList *buds;
3573        int changed=0;
3574        int id = yd->client_id;
3575
3576        if(over)
3577                return;
3578
3579        while(find_input_by_id_and_type(id, YAHOO_CONNECTION_YAB) 
3580                        && (yab = yahoo_getyab(yid)) != NULL) {
3581                if(!yab->id)
3582                        continue;
3583                changed=1;
3584                for(buds = yd->buddies; buds; buds=buds->next) {
3585                        struct yahoo_buddy * bud = buds->data;
3586                        if(!strcmp(bud->id, yab->id)) {
3587                                bud->yab_entry = yab;
3588                                if(yab->nname) {
3589                                        bud->real_name = strdup(yab->nname);
3590                                } else if(yab->fname && yab->lname) {
3591                                        bud->real_name = y_new0(char, 
3592                                                        strlen(yab->fname)+
3593                                                        strlen(yab->lname)+2
3594                                                        );
3595                                        sprintf(bud->real_name, "%s %s",
3596                                                        yab->fname, yab->lname);
3597                                } else if(yab->fname) {
3598                                        bud->real_name = strdup(yab->fname);
3599                                }
3600                                break; /* for */
3601                        }
3602                }
3603        }
3604
3605        if(changed)
3606                YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
3607}
3608
3609static void yahoo_process_search_connection(struct yahoo_input_data *yid, int over)
3610{
3611        struct yahoo_found_contact *yct=NULL;
3612        char *p = (char *)yid->rxqueue, *np, *cp;
3613        int k, n;
3614        int start=0, found=0, total=0;
3615        YList *contacts=NULL;
3616        struct yahoo_input_data *pyid = find_input_by_id_and_type(yid->yd->client_id, YAHOO_CONNECTION_PAGER);
3617
3618        if(!over || !pyid)
3619                return;
3620
3621        if(p && (p=strstr(p, "\r\n\r\n"))) {
3622                p += 4;
3623
3624                for(k = 0; (p = strchr(p, 4)) && (k < 4); k++) {
3625                        p++;
3626                        n = atoi(p);
3627                        switch(k) {
3628                                case 0: found = pyid->ys->lsearch_nfound = n; break;
3629                                case 2: start = pyid->ys->lsearch_nstart = n; break;
3630                                case 3: total = pyid->ys->lsearch_ntotal = n; break;
3631                        }
3632                }
3633
3634                if(p)
3635                        p++;
3636
3637                k=0;
3638                while(p && *p) {
3639                        cp = p;
3640                        np = strchr(p, 4);
3641
3642                        if(!np)
3643                                break;
3644                        *np = 0;
3645                        p = np+1;
3646
3647                        switch(k++) {
3648                                case 1:
3649                                        if(strlen(cp) > 2 && y_list_length(contacts) < total) {
3650                                                yct = y_new0(struct yahoo_found_contact, 1);
3651                                                contacts = y_list_append(contacts, yct);
3652                                                yct->id = cp+2;
3653                                        } else {
3654                                                *p = 0;
3655                                        }
3656                                        break;
3657                                case 2: 
3658                                        yct->online = !strcmp(cp, "2") ? 1 : 0;
3659                                        break;
3660                                case 3: 
3661                                        yct->gender = cp;
3662                                        break;
3663                                case 4: 
3664                                        yct->age = atoi(cp);
3665                                        break;
3666                                case 5: 
3667                                        if(strcmp(cp, "5") != 0)
3668                                                yct->location = cp;
3669                                        k = 0;
3670                                        break;
3671                        }
3672                }
3673        }
3674
3675        YAHOO_CALLBACK(ext_yahoo_got_search_result)(yid->yd->client_id, found, start, total, contacts);
3676
3677        while(contacts) {
3678                YList *node = contacts;
3679                contacts = y_list_remove_link(contacts, node);
3680                free(node->data);
3681                y_list_free_1(node);
3682        }
3683}
3684
3685static void _yahoo_webcam_connected(int fd, int error, void *d)
3686{
3687        struct yahoo_input_data *yid = d;
3688        struct yahoo_webcam *wcm = yid->wcm;
3689        struct yahoo_data *yd = yid->yd;
3690        char conn_type[100];
3691        char *data=NULL;
3692        char *packet=NULL;
3693        unsigned char magic_nr[] = {1, 0, 0, 0, 1};
3694        unsigned header_len=0;
3695        unsigned int len=0;
3696        unsigned int pos=0;
3697
3698        if(error || fd <= 0) {
3699                FREE(yid);
3700                return;
3701        }
3702
3703        yid->fd = fd;
3704        inputs = y_list_prepend(inputs, yid);
3705
3706        LOG(("Connected"));
3707        /* send initial packet */
3708        switch (wcm->direction)
3709        {
3710                case YAHOO_WEBCAM_DOWNLOAD:
3711                        data = strdup("<REQIMG>");
3712                        break;
3713                case YAHOO_WEBCAM_UPLOAD:       
3714                        data = strdup("<SNDIMG>");
3715                        break;
3716                default:
3717                        return;
3718        }
3719        yahoo_add_to_send_queue(yid, data, strlen(data));
3720        FREE(data);
3721
3722        /* send data */
3723        switch (wcm->direction)
3724        {
3725                case YAHOO_WEBCAM_DOWNLOAD:
3726                        header_len = 8;
3727                        data = strdup("a=2\r\nc=us\r\ne=21\r\nu=");
3728                        data = y_string_append(data, yd->user);
3729                        data = y_string_append(data, "\r\nt=");
3730                        data = y_string_append(data, wcm->key);
3731                        data = y_string_append(data, "\r\ni=");
3732                        data = y_string_append(data, wcm->my_ip);
3733                        data = y_string_append(data, "\r\ng=");
3734                        data = y_string_append(data, wcm->user);
3735                        data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
3736                        snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
3737                        data = y_string_append(data, conn_type);
3738                        data = y_string_append(data, "\r\n");
3739                        break;
3740                case YAHOO_WEBCAM_UPLOAD:
3741                        header_len = 13;
3742                        data = strdup("a=2\r\nc=us\r\nu=");
3743                        data = y_string_append(data, yd->user);
3744                        data = y_string_append(data, "\r\nt=");
3745                        data = y_string_append(data, wcm->key);
3746                        data = y_string_append(data, "\r\ni=");
3747                        data = y_string_append(data, wcm->my_ip);
3748                        data = y_string_append(data, "\r\no=w-2-5-1\r\np=");
3749                        snprintf(conn_type, sizeof(conn_type), "%d", wcm->conn_type);
3750                        data = y_string_append(data, conn_type);
3751                        data = y_string_append(data, "\r\nb=");
3752                        data = y_string_append(data, wcm->description);
3753                        data = y_string_append(data, "\r\n");
3754                        break;
3755        }
3756
3757        len = strlen(data);
3758        packet = y_new0(char, header_len + len);
3759        packet[pos++] = header_len;
3760        packet[pos++] = 0;
3761        switch (wcm->direction)
3762        {
3763                case YAHOO_WEBCAM_DOWNLOAD:
3764                        packet[pos++] = 1;
3765                        packet[pos++] = 0;
3766                        break;
3767                case YAHOO_WEBCAM_UPLOAD:
3768                        packet[pos++] = 5;
3769                        packet[pos++] = 0;
3770                        break;
3771        }
3772
3773        pos += yahoo_put32(packet + pos, len);
3774        if (wcm->direction == YAHOO_WEBCAM_UPLOAD)
3775        {
3776                memcpy(packet + pos, magic_nr, sizeof(magic_nr));
3777                pos += sizeof(magic_nr);
3778        }
3779        memcpy(packet + pos, data, len);
3780        yahoo_add_to_send_queue(yid, packet, header_len + len);
3781        FREE(packet);
3782        FREE(data);
3783
3784        yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_READ, yid);
3785}
3786
3787static void yahoo_webcam_connect(struct yahoo_input_data *y)
3788{
3789        struct yahoo_webcam *wcm = y->wcm;
3790        struct yahoo_input_data *yid;
3791        struct yahoo_server_settings *yss;
3792
3793        if (!wcm || !wcm->server || !wcm->key)
3794                return;
3795
3796        yid = y_new0(struct yahoo_input_data, 1);
3797        yid->type = YAHOO_CONNECTION_WEBCAM;
3798        yid->yd = y->yd;
3799
3800        /* copy webcam data to new connection */
3801        yid->wcm = y->wcm;
3802        y->wcm = NULL;
3803
3804        yss = y->yd->server_settings;
3805
3806        yid->wcd = y_new0(struct yahoo_webcam_data, 1);
3807
3808        LOG(("Connecting to: %s:%d", wcm->server, wcm->port));
3809        YAHOO_CALLBACK(ext_yahoo_connect_async)(y->yd->client_id, wcm->server, wcm->port,
3810                        _yahoo_webcam_connected, yid);
3811
3812}
3813
3814static void yahoo_process_webcam_master_connection(struct yahoo_input_data *yid, int over)
3815{
3816        char* server;
3817        struct yahoo_server_settings *yss;
3818
3819        if(over)
3820                return;
3821
3822        server = yahoo_getwebcam_master(yid);
3823
3824        if (server)
3825        {
3826                yss = yid->yd->server_settings;
3827                yid->wcm->server = strdup(server);
3828                yid->wcm->port = yss->webcam_port;
3829                yid->wcm->conn_type = yss->conn_type;
3830                yid->wcm->my_ip = strdup(yss->local_host);
3831                if (yid->wcm->direction == YAHOO_WEBCAM_UPLOAD)
3832                        yid->wcm->description = strdup(yss->webcam_description);
3833                yahoo_webcam_connect(yid);
3834                FREE(server);
3835        }
3836}
3837
3838static void yahoo_process_webcam_connection(struct yahoo_input_data *yid, int over)
3839{
3840        int id = yid->yd->client_id;
3841        int fd = yid->fd;
3842
3843        if(over)
3844                return;
3845
3846        /* as long as we still have packets available keep processing them */
3847        while (find_input_by_id_and_fd(id, fd) 
3848                        && yahoo_get_webcam_data(yid) == 1);
3849}
3850
3851static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = {
3852        yahoo_process_pager_connection,
3853        yahoo_process_ft_connection,
3854        yahoo_process_yab_connection,
3855        yahoo_process_webcam_master_connection,
3856        yahoo_process_webcam_connection,
3857        yahoo_process_chatcat_connection,
3858        yahoo_process_search_connection,
3859};
3860
3861int yahoo_read_ready(int id, int fd, void *data)
3862{
3863        struct yahoo_input_data *yid = data;
3864        char buf[1024];
3865        int len;
3866
3867        LOG(("read callback: id=%d fd=%d data=%p", id, fd, data));
3868        if(!yid)
3869                return -2;
3870
3871       
3872        do {
3873                len = read(fd, buf, sizeof(buf));
3874        } while(len == -1 && errno == EINTR);
3875
3876        if(len == -1 && (errno == EAGAIN||errno == EINTR))      /* we'll try again later */
3877                return 1;
3878
3879        if (len <= 0) {
3880                int e = errno;
3881                DEBUG_MSG(("len == %d (<= 0)", len));
3882
3883                if(yid->type == YAHOO_CONNECTION_PAGER) {
3884                        YAHOO_CALLBACK(ext_yahoo_error)(yid->yd->client_id, "Connection closed by server", 1, E_CONNECTION);
3885                }
3886
3887                yahoo_process_connection[yid->type](yid, 1);
3888                yahoo_input_close(yid);
3889
3890                /* no need to return an error, because we've already fixed it */
3891                if(len == 0)
3892                        return 1;
3893
3894                errno=e;
3895                LOG(("read error: %s", strerror(errno)));
3896                return -1;
3897        }
3898
3899        yid->rxqueue = y_renew(unsigned char, yid->rxqueue, len + yid->rxlen);
3900        memcpy(yid->rxqueue + yid->rxlen, buf, len);
3901        yid->rxlen += len;
3902
3903        yahoo_process_connection[yid->type](yid, 0);
3904
3905        return len;
3906}
3907
3908int yahoo_init_with_attributes(const char *username, const char *password, ...)
3909{
3910        va_list ap;
3911        struct yahoo_data *yd;
3912
3913        yd = y_new0(struct yahoo_data, 1);
3914
3915        if(!yd)
3916                return 0;
3917
3918        yd->user = strdup(username);
3919        yd->password = strdup(password);
3920
3921        yd->initial_status = -1;
3922        yd->current_status = -1;
3923
3924        yd->client_id = ++last_id;
3925
3926        add_to_list(yd);
3927
3928        va_start(ap, password);
3929        yd->server_settings = _yahoo_assign_server_settings(ap);
3930        va_end(ap);
3931
3932        return yd->client_id;
3933}
3934
3935int yahoo_init(const char *username, const char *password)
3936{
3937        return yahoo_init_with_attributes(username, password, NULL);
3938}
3939
3940struct connect_callback_data {
3941        struct yahoo_data *yd;
3942        int tag;
3943        int i;
3944};
3945
3946static void yahoo_connected(int fd, int error, void *data)
3947{
3948        struct connect_callback_data *ccd = data;
3949        struct yahoo_data *yd = ccd->yd;
3950        struct yahoo_packet *pkt;
3951        struct yahoo_input_data *yid;
3952        struct yahoo_server_settings *yss = yd->server_settings;
3953
3954        if(error) {
3955                if(fallback_ports[ccd->i]) {
3956                        int tag;
3957                        yss->pager_port = fallback_ports[ccd->i++];
3958                        tag = YAHOO_CALLBACK(ext_yahoo_connect_async)(yd->client_id, yss->pager_host,
3959                                        yss->pager_port, yahoo_connected, ccd);
3960
3961                        if(tag > 0)
3962                                ccd->tag=tag;
3963                } else {
3964                        FREE(ccd);
3965                        YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_SOCK, NULL);
3966                }
3967                return;
3968        }
3969
3970        FREE(ccd);
3971
3972        /* fd < 0 && error == 0 means connect was cancelled */
3973        if(fd < 0)
3974                return;
3975
3976        pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
3977        NOTICE(("Sending initial packet"));
3978
3979        yahoo_packet_hash(pkt, 1, yd->user);
3980
3981        yid = y_new0(struct yahoo_input_data, 1);
3982        yid->yd = yd;
3983        yid->fd = fd;
3984        inputs = y_list_prepend(inputs, yid);
3985
3986        yahoo_send_packet(yid, pkt, 0);
3987
3988        yahoo_packet_free(pkt);
3989
3990        yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, yid->fd, YAHOO_INPUT_READ, yid);
3991}
3992
3993void yahoo_login(int id, int initial)
3994{
3995        struct yahoo_data *yd = find_conn_by_id(id);
3996        struct connect_callback_data *ccd;
3997        struct yahoo_server_settings *yss;
3998        int tag;
3999
4000        if(!yd)
4001                return;
4002
4003        yss = yd->server_settings;
4004
4005        yd->initial_status = initial;
4006
4007        ccd = y_new0(struct connect_callback_data, 1);
4008        ccd->yd = yd;
4009        tag = YAHOO_CALLBACK(ext_yahoo_connect_async)(yd->client_id, yss->pager_host, yss->pager_port, 
4010                        yahoo_connected, ccd);
4011
4012        /*
4013         * if tag <= 0, then callback has already been called
4014         * so ccd will have been freed
4015         */
4016        if(tag > 0)
4017                ccd->tag = tag;
4018        else if(tag < 0)
4019                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_SOCK, NULL);
4020}
4021
4022
4023int yahoo_get_fd(int id)
4024{
4025        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4026        if(!yid)
4027                return 0;
4028        else
4029                return yid->fd;
4030}
4031
4032void yahoo_send_im(int id, const char *from, const char *who, const char *what, int utf8, int picture)
4033{
4034        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4035        struct yahoo_packet *pkt = NULL;
4036        struct yahoo_data *yd;
4037        char pic_str[10];
4038
4039        if(!yid)
4040                return;
4041
4042        yd = yid->yd;
4043
4044        pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, yd->session_id);
4045
4046        snprintf(pic_str, sizeof(pic_str), "%d", picture);
4047       
4048        if(from && strcmp(from, yd->user))
4049                yahoo_packet_hash(pkt, 0, yd->user);
4050        yahoo_packet_hash(pkt, 1, from?from:yd->user);
4051        yahoo_packet_hash(pkt, 5, who);
4052        yahoo_packet_hash(pkt, 14, what);
4053
4054        if(utf8)
4055                yahoo_packet_hash(pkt, 97, "1");
4056
4057        yahoo_packet_hash(pkt, 63, ";0");       /* imvironment name; or ;0 */
4058        yahoo_packet_hash(pkt, 64, "0");
4059        yahoo_packet_hash(pkt, 206, pic_str);
4060
4061
4062        yahoo_send_packet(yid, pkt, 0);
4063
4064        yahoo_packet_free(pkt);
4065}
4066
4067void yahoo_send_typing(int id, const char *from, const char *who, int typ)
4068{
4069        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4070        struct yahoo_data *yd;
4071        struct yahoo_packet *pkt = NULL;
4072        if(!yid)
4073                return;
4074
4075        yd = yid->yd;
4076        pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yd->session_id);
4077
4078        yahoo_packet_hash(pkt, 5, who);
4079        yahoo_packet_hash(pkt, 1, from?from:yd->user);
4080        yahoo_packet_hash(pkt, 14, " ");
4081        yahoo_packet_hash(pkt, 13, typ ? "1" : "0");
4082        yahoo_packet_hash(pkt, 49, "TYPING");
4083
4084        yahoo_send_packet(yid, pkt, 0);
4085
4086        yahoo_packet_free(pkt);
4087}
4088
4089void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away)
4090{
4091        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4092        struct yahoo_data *yd;
4093        struct yahoo_packet *pkt = NULL;
4094        int old_status;
4095        char s[4];
4096
4097        if(!yid)
4098                return;
4099
4100        yd = yid->yd;
4101        old_status = yd->current_status;
4102        yd->current_status = state;
4103
4104        /* Thank you libpurple :) */
4105        if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
4106                pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0);
4107                yahoo_packet_hash(pkt, 13, "2");
4108                yahoo_send_packet(yid, pkt, 0);
4109                yahoo_packet_free(pkt);
4110
4111                return;
4112        }
4113
4114        pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, yd->current_status, yd->session_id);
4115        snprintf(s, sizeof(s), "%d", yd->current_status);
4116        yahoo_packet_hash(pkt, 10, s);
4117        yahoo_packet_hash(pkt, 19, msg && state == YAHOO_STATUS_CUSTOM ? msg : "");
4118        yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
4119        yahoo_send_packet(yid, pkt, 0);
4120        yahoo_packet_free(pkt);
4121
4122        if(old_status == YAHOO_STATUS_INVISIBLE) {
4123                pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0);
4124                yahoo_packet_hash(pkt, 13, "1");
4125                yahoo_send_packet(yid, pkt, 0);
4126                yahoo_packet_free(pkt);
4127        }
4128}
4129
4130void yahoo_logoff(int id)
4131{
4132        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4133        struct yahoo_data *yd;
4134        struct yahoo_packet *pkt = NULL;
4135
4136        if(!yid)
4137                return;
4138        yd = yid->yd;
4139
4140        LOG(("yahoo_logoff: current status: %d", yd->current_status));
4141
4142        if(yd->current_status != -1 && 0) {
4143                /* Meh. Don't send this. The event handlers are not going to
4144                   get to do this so it'll just leak memory. And the TCP
4145                   connection reset will hopefully be clear enough. */
4146                pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
4147                yd->current_status = -1;
4148
4149                if (pkt) {
4150                        yahoo_send_packet(yid, pkt, 0);
4151                        yahoo_packet_free(pkt);
4152                }
4153        }
4154
4155        do {
4156                yahoo_input_close(yid);
4157        } while((yid = find_input_by_id(id)));
4158}
4159
4160void yahoo_get_list(int id)
4161{
4162        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4163        struct yahoo_data *yd;
4164        struct yahoo_packet *pkt = NULL;
4165
4166        if(!yid)
4167                return;
4168        yd = yid->yd;
4169
4170        pkt = yahoo_packet_new(YAHOO_SERVICE_LIST, YAHOO_STATUS_AVAILABLE, yd->session_id);
4171        yahoo_packet_hash(pkt, 1, yd->user);
4172        if (pkt) {
4173                yahoo_send_packet(yid, pkt, 0);
4174                yahoo_packet_free(pkt);
4175        }
4176}
4177
4178static void _yahoo_http_connected(int id, int fd, int error, void *data)
4179{
4180        struct yahoo_input_data *yid = data;
4181        if(fd <= 0) {
4182                inputs = y_list_remove(inputs, yid);
4183                FREE(yid);
4184                return;
4185        }
4186
4187        yid->fd = fd;
4188        yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, fd, YAHOO_INPUT_READ, yid);
4189}
4190
4191void yahoo_get_yab(int id)
4192{
4193        struct yahoo_data *yd = find_conn_by_id(id);
4194        struct yahoo_input_data *yid;
4195        char url[1024];
4196        char buff[1024];
4197
4198        if(!yd)
4199                return;
4200
4201        yid = y_new0(struct yahoo_input_data, 1);
4202        yid->yd = yd;
4203        yid->type = YAHOO_CONNECTION_YAB;
4204
4205        snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?ab2=0");
4206
4207        snprintf(buff, sizeof(buff), "Y=%s; T=%s",
4208                        yd->cookie_y, yd->cookie_t);
4209
4210        inputs = y_list_prepend(inputs, yid);
4211
4212        yahoo_http_get(yid->yd->client_id, url, buff, 
4213                        _yahoo_http_connected, yid);
4214}
4215
4216void yahoo_set_yab(int id, struct yab * yab)
4217{
4218        struct yahoo_data *yd = find_conn_by_id(id);
4219        struct yahoo_input_data *yid;
4220        char url[1024];
4221        char buff[1024];
4222        char *temp;
4223        int size = sizeof(url)-1;
4224
4225        if(!yd)
4226                return;
4227
4228        yid = y_new0(struct yahoo_input_data, 1);
4229        yid->type = YAHOO_CONNECTION_YAB;
4230        yid->yd = yd;
4231
4232        strncpy(url, "http://insider.msg.yahoo.com/ycontent/?addab2=0", size);
4233
4234        if(yab->dbid) {
4235                /* change existing yab */
4236                char tmp[32];
4237                strncat(url, "&ee=1&ow=1&id=", size - strlen(url));
4238                snprintf(tmp, sizeof(tmp), "%d", yab->dbid);
4239                strncat(url, tmp, size - strlen(url));
4240        }
4241
4242        if(yab->fname) {
4243                strncat(url, "&fn=", size - strlen(url));
4244                temp = yahoo_urlencode(yab->fname);
4245                strncat(url, temp, size - strlen(url));
4246                free(temp);
4247        }
4248        if(yab->lname) {
4249                strncat(url, "&ln=", size - strlen(url));
4250                temp = yahoo_urlencode(yab->lname);
4251                strncat(url, temp, size - strlen(url));
4252                free(temp);
4253        }
4254        strncat(url, "&yid=", size - strlen(url));
4255        temp = yahoo_urlencode(yab->id);
4256        strncat(url, temp, size - strlen(url));
4257        free(temp);
4258        if(yab->nname) {
4259                strncat(url, "&nn=", size - strlen(url));
4260                temp = yahoo_urlencode(yab->nname);
4261                strncat(url, temp, size - strlen(url));
4262                free(temp);
4263        }
4264        if(yab->email) {
4265                strncat(url, "&e=", size - strlen(url));
4266                temp = yahoo_urlencode(yab->email);
4267                strncat(url, temp, size - strlen(url));
4268                free(temp);
4269        }
4270        if(yab->hphone) {
4271                strncat(url, "&hp=", size - strlen(url));
4272                temp = yahoo_urlencode(yab->hphone);
4273                strncat(url, temp, size - strlen(url));
4274                free(temp);
4275        }
4276        if(yab->wphone) {
4277                strncat(url, "&wp=", size - strlen(url));
4278                temp = yahoo_urlencode(yab->wphone);
4279                strncat(url, temp, size - strlen(url));
4280                free(temp);
4281        }
4282        if(yab->mphone) {
4283                strncat(url, "&mp=", size - strlen(url));
4284                temp = yahoo_urlencode(yab->mphone);
4285                strncat(url, temp, size - strlen(url));
4286                free(temp);
4287        }
4288        strncat(url, "&pp=0", size - strlen(url));
4289
4290        snprintf(buff, sizeof(buff), "Y=%s; T=%s",
4291                        yd->cookie_y, yd->cookie_t);
4292
4293        inputs = y_list_prepend(inputs, yid);
4294
4295        yahoo_http_get(yid->yd->client_id, url, buff, 
4296                        _yahoo_http_connected, yid);
4297}
4298
4299void yahoo_set_identity_status(int id, const char * identity, int active)
4300{
4301        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4302        struct yahoo_data *yd;
4303        struct yahoo_packet *pkt = NULL;
4304
4305        if(!yid)
4306                return;
4307        yd = yid->yd;
4308
4309        pkt = yahoo_packet_new(active?YAHOO_SERVICE_IDACT:YAHOO_SERVICE_IDDEACT,
4310                        YAHOO_STATUS_AVAILABLE, yd->session_id);
4311        yahoo_packet_hash(pkt, 3, identity);
4312        if (pkt) {
4313                yahoo_send_packet(yid, pkt, 0);
4314                yahoo_packet_free(pkt);
4315        }
4316}
4317
4318void yahoo_refresh(int id)
4319{
4320        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4321        struct yahoo_data *yd;
4322        struct yahoo_packet *pkt = NULL;
4323
4324        if(!yid)
4325                return;
4326        yd = yid->yd;
4327
4328        pkt = yahoo_packet_new(YAHOO_SERVICE_USERSTAT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4329        if (pkt) {
4330                yahoo_send_packet(yid, pkt, 0);
4331                yahoo_packet_free(pkt);
4332        }
4333}
4334
4335void yahoo_keepalive(int id)
4336{
4337        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4338        struct yahoo_data *yd;
4339        struct yahoo_packet *pkt=NULL;
4340        if(!yid)
4341                return;
4342        yd = yid->yd;
4343
4344        pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, yd->session_id);
4345        yahoo_send_packet(yid, pkt, 0);
4346        yahoo_packet_free(pkt);
4347}
4348
4349void yahoo_chat_keepalive (int id)
4350{
4351        struct yahoo_input_data *yid = find_input_by_id_and_type (id, YAHOO_CONNECTION_PAGER);
4352        struct yahoo_data *yd;
4353        struct yahoo_packet *pkt = NULL;
4354
4355        if (!yid)
4356            return;
4357
4358        yd = yid->yd;
4359
4360        pkt = yahoo_packet_new (YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, yd->session_id);
4361        yahoo_send_packet (yid, pkt, 0);
4362        yahoo_packet_free (pkt);
4363}
4364
4365void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg)
4366{
4367        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4368        struct yahoo_data *yd;
4369        struct yahoo_packet *pkt;
4370
4371        if(!yid)
4372                return;
4373        yd = yid->yd;
4374
4375        if (!yd->logged_in)
4376                return;
4377
4378        pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YPACKET_STATUS_DEFAULT, yd->session_id);
4379
4380        if (msg != NULL) /* add message/request "it's me add me" */
4381                yahoo_packet_hash(pkt, 14, msg);
4382        else
4383                yahoo_packet_hash(pkt,14,"");
4384
4385        yahoo_packet_hash(pkt, 65, group);
4386        yahoo_packet_hash(pkt, 97, "1");
4387        yahoo_packet_hash(pkt, 1, yd->user);
4388        yahoo_packet_hash(pkt, 302, "319");
4389        yahoo_packet_hash(pkt, 300, "319");
4390        yahoo_packet_hash(pkt, 7, who);
4391        yahoo_packet_hash(pkt, 334, "0");
4392        yahoo_packet_hash(pkt, 301, "319");
4393        yahoo_packet_hash(pkt, 303, "319");
4394
4395
4396        yahoo_send_packet(yid, pkt, 0);
4397        yahoo_packet_free(pkt);
4398}
4399
4400void yahoo_remove_buddy(int id, const char *who, const char *group)
4401{
4402        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4403        struct yahoo_data *yd;
4404        struct yahoo_packet *pkt = NULL;
4405
4406        if(!yid)
4407                return;
4408        yd = yid->yd;
4409
4410        pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4411
4412        yahoo_packet_hash(pkt, 1, yd->user);
4413        yahoo_packet_hash(pkt, 7, who);
4414        yahoo_packet_hash(pkt, 65, group);
4415        yahoo_send_packet(yid, pkt, 0);
4416        yahoo_packet_free(pkt);
4417}
4418
4419void yahoo_accept_buddy_ymsg13(int id,const char* me,const char* who){
4420        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4421        struct yahoo_data *yd;
4422
4423        if(!yid)
4424                return;
4425        yd = yid->yd;
4426
4427        struct yahoo_packet* pkt=NULL;
4428        pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0);
4429
4430        yahoo_packet_hash(pkt,1,me ?: yd->user);       
4431        yahoo_packet_hash(pkt,5,who);
4432        yahoo_packet_hash(pkt,13,"1");
4433        yahoo_packet_hash(pkt,334,"0");
4434        yahoo_send_packet(yid, pkt, 0);
4435        yahoo_packet_free(pkt);
4436}
4437
4438void yahoo_reject_buddy_ymsg13(int id,const char* me,const char* who,const char* msg){
4439        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4440        struct yahoo_data *yd;
4441
4442        if(!yid)
4443                return;
4444        yd = yid->yd;
4445
4446        struct yahoo_packet* pkt=NULL;
4447        pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0);
4448
4449        yahoo_packet_hash(pkt,1,me ?: yd->user);       
4450        yahoo_packet_hash(pkt,5,who);
4451//      yahoo_packet_hash(pkt,241,YAHOO_PROTO_VER);
4452        yahoo_packet_hash(pkt,13,"2");
4453        yahoo_packet_hash(pkt,334,"0");
4454        yahoo_packet_hash(pkt,97,"1");
4455        yahoo_packet_hash(pkt,14,msg?:"");
4456
4457        yahoo_send_packet(yid, pkt, 0);
4458        yahoo_packet_free(pkt);
4459
4460}
4461
4462void yahoo_reject_buddy(int id, const char *who, const char *msg)
4463{
4464        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4465        struct yahoo_data *yd;
4466        struct yahoo_packet *pkt;
4467
4468        if(!yid)
4469                return;
4470        yd = yid->yd;
4471
4472        if (!yd->logged_in)
4473                return;
4474
4475        pkt = yahoo_packet_new(YAHOO_SERVICE_REJECTCONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4476        yahoo_packet_hash(pkt, 1, yd->user);
4477        yahoo_packet_hash(pkt, 7, who);
4478        yahoo_packet_hash(pkt, 14, msg);
4479        yahoo_send_packet(yid, pkt, 0);
4480        yahoo_packet_free(pkt);
4481}
4482
4483void yahoo_ignore_buddy(int id, const char *who, int unignore)
4484{
4485        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4486        struct yahoo_data *yd;
4487        struct yahoo_packet *pkt;
4488
4489        if(!yid)
4490                return;
4491        yd = yid->yd;
4492
4493        if (!yd->logged_in)
4494                return;
4495
4496        pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4497        yahoo_packet_hash(pkt, 1, yd->user);
4498        yahoo_packet_hash(pkt, 7, who);
4499        yahoo_packet_hash(pkt, 13, unignore?"2":"1");
4500        yahoo_send_packet(yid, pkt, 0);
4501        yahoo_packet_free(pkt);
4502}
4503
4504void yahoo_stealth_buddy(int id, const char *who, int unstealth)
4505{
4506        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4507        struct yahoo_data *yd;
4508        struct yahoo_packet *pkt;
4509
4510        if(!yid)
4511                return;
4512        yd = yid->yd;
4513
4514        if (!yd->logged_in)
4515                return;
4516
4517        pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
4518        yahoo_packet_hash(pkt, 1, yd->user);
4519        yahoo_packet_hash(pkt, 7, who);
4520        yahoo_packet_hash(pkt, 31, unstealth?"2":"1");
4521        yahoo_packet_hash(pkt, 13, "2");
4522        yahoo_send_packet(yid, pkt, 0);
4523        yahoo_packet_free(pkt);
4524}
4525
4526void yahoo_change_buddy_group(int id, const char *who, const char *old_group, const char *new_group)
4527{
4528        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4529        struct yahoo_data *yd;
4530        struct yahoo_packet *pkt = NULL;
4531
4532        if(!yid)
4533                return;
4534        yd = yid->yd;
4535
4536        pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4537        yahoo_packet_hash(pkt, 1, yd->user);
4538        yahoo_packet_hash(pkt, 7, who);
4539        yahoo_packet_hash(pkt, 65, new_group);
4540        yahoo_packet_hash(pkt, 14, " ");
4541
4542        yahoo_send_packet(yid, pkt, 0);
4543        yahoo_packet_free(pkt);
4544
4545        pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
4546        yahoo_packet_hash(pkt, 1, yd->user);
4547        yahoo_packet_hash(pkt, 7, who);
4548        yahoo_packet_hash(pkt, 65, old_group);
4549        yahoo_send_packet(yid, pkt, 0);
4550        yahoo_packet_free(pkt);
4551}
4552
4553void yahoo_group_rename(int id, const char *old_group, const char *new_group)
4554{
4555        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4556        struct yahoo_data *yd;
4557        struct yahoo_packet *pkt = NULL;
4558
4559        if(!yid)
4560                return;
4561        yd = yid->yd;
4562
4563        pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, yd->session_id);
4564        yahoo_packet_hash(pkt, 1, yd->user);
4565        yahoo_packet_hash(pkt, 65, old_group);
4566        yahoo_packet_hash(pkt, 67, new_group);
4567
4568        yahoo_send_packet(yid, pkt, 0);
4569        yahoo_packet_free(pkt);
4570}
4571
4572void yahoo_conference_addinvite(int id, const char * from, const char *who, const char *room, const YList * members, const char *msg)
4573{
4574        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4575        struct yahoo_data *yd;
4576        struct yahoo_packet *pkt;
4577               
4578        if(!yid)
4579                return;
4580        yd = yid->yd;
4581
4582        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFADDINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4583
4584        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4585        yahoo_packet_hash(pkt, 51, who);
4586        yahoo_packet_hash(pkt, 57, room);
4587        yahoo_packet_hash(pkt, 58, msg);
4588        yahoo_packet_hash(pkt, 13, "0");
4589        for(; members; members = members->next) {
4590                yahoo_packet_hash(pkt, 52, (char *)members->data);
4591                yahoo_packet_hash(pkt, 53, (char *)members->data);
4592        }
4593        /* 52, 53 -> other members? */
4594
4595        yahoo_send_packet(yid, pkt, 0);
4596
4597        yahoo_packet_free(pkt);
4598}
4599
4600void yahoo_conference_invite(int id, const char * from, YList *who, const char *room, const char *msg)
4601{
4602        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4603        struct yahoo_data *yd;
4604        struct yahoo_packet *pkt;
4605               
4606        if(!yid)
4607                return;
4608        yd = yid->yd;
4609
4610        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4611
4612        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4613        yahoo_packet_hash(pkt, 50, yd->user);
4614        for(; who; who = who->next) {
4615                yahoo_packet_hash(pkt, 52, (char *)who->data);
4616        }
4617        yahoo_packet_hash(pkt, 57, room);
4618        yahoo_packet_hash(pkt, 58, msg);
4619        yahoo_packet_hash(pkt, 13, "0");
4620
4621        yahoo_send_packet(yid, pkt, 0);
4622
4623        yahoo_packet_free(pkt);
4624}
4625
4626void yahoo_conference_logon(int id, const char *from, YList *who, const char *room)
4627{
4628        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4629        struct yahoo_data *yd;
4630        struct yahoo_packet *pkt;
4631               
4632        if(!yid)
4633                return;
4634        yd = yid->yd;
4635
4636        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGON, YAHOO_STATUS_AVAILABLE, yd->session_id);
4637
4638        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4639        for(; who; who = who->next) {
4640                yahoo_packet_hash(pkt, 3, (char *)who->data);
4641        }
4642        yahoo_packet_hash(pkt, 57, room);
4643
4644        yahoo_send_packet(yid, pkt, 0);
4645
4646        yahoo_packet_free(pkt);
4647}
4648
4649void yahoo_conference_decline(int id, const char * from, YList *who, const char *room, const char *msg)
4650{
4651        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4652        struct yahoo_data *yd;
4653        struct yahoo_packet *pkt;
4654               
4655        if(!yid)
4656                return;
4657        yd = yid->yd;
4658
4659        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFDECLINE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4660
4661        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4662        for(; who; who = who->next) {
4663                yahoo_packet_hash(pkt, 3, (char *)who->data);
4664        }
4665        yahoo_packet_hash(pkt, 57, room);
4666        yahoo_packet_hash(pkt, 14, msg);
4667
4668        yahoo_send_packet(yid, pkt, 0);
4669
4670        yahoo_packet_free(pkt);
4671}
4672
4673void yahoo_conference_logoff(int id, const char * from, YList *who, const char *room)
4674{
4675        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4676        struct yahoo_data *yd;
4677        struct yahoo_packet *pkt;
4678               
4679        if(!yid)
4680                return;
4681        yd = yid->yd;
4682
4683        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
4684
4685        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4686        for(; who; who = who->next) {
4687                yahoo_packet_hash(pkt, 3, (char *)who->data);
4688        }
4689        yahoo_packet_hash(pkt, 57, room);
4690
4691        yahoo_send_packet(yid, pkt, 0);
4692
4693        yahoo_packet_free(pkt);
4694}
4695
4696void yahoo_conference_message(int id, const char * from, YList *who, const char *room, const char *msg, int utf8)
4697{
4698        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4699        struct yahoo_data *yd;
4700        struct yahoo_packet *pkt;
4701               
4702        if(!yid)
4703                return;
4704        yd = yid->yd;
4705
4706        pkt = yahoo_packet_new(YAHOO_SERVICE_CONFMSG, YAHOO_STATUS_AVAILABLE, yd->session_id);
4707
4708        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4709        for(; who; who = who->next) {
4710                yahoo_packet_hash(pkt, 53, (char *)who->data);
4711        }
4712        yahoo_packet_hash(pkt, 57, room);
4713        yahoo_packet_hash(pkt, 14, msg);
4714
4715        if(utf8)
4716                yahoo_packet_hash(pkt, 97, "1");
4717
4718        yahoo_send_packet(yid, pkt, 0);
4719
4720        yahoo_packet_free(pkt);
4721}
4722
4723void yahoo_get_chatrooms(int id, int chatroomid)
4724{
4725        struct yahoo_data *yd = find_conn_by_id(id);
4726        struct yahoo_input_data *yid;
4727        char url[1024];
4728        char buff[1024];
4729
4730        if(!yd)
4731                return;
4732
4733        yid = y_new0(struct yahoo_input_data, 1);
4734        yid->yd = yd;
4735        yid->type = YAHOO_CONNECTION_CHATCAT;
4736
4737        if (chatroomid == 0) {
4738                snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?chatcat=0");
4739        } else {
4740                snprintf(url, 1024, "http://insider.msg.yahoo.com/ycontent/?chatroom_%d=0",chatroomid);
4741        }
4742
4743        snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
4744
4745        inputs = y_list_prepend(inputs, yid);
4746
4747        yahoo_http_get(yid->yd->client_id, url, buff, _yahoo_http_connected, yid);
4748}
4749
4750void yahoo_chat_logon(int id, const char *from, const char *room, const char *roomid)
4751{
4752        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4753        struct yahoo_data *yd;
4754        struct yahoo_packet *pkt;
4755               
4756        if(!yid)
4757                return;
4758
4759        yd = yid->yd;
4760
4761        pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YAHOO_STATUS_AVAILABLE, yd->session_id);
4762
4763        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4764        yahoo_packet_hash(pkt, 109, yd->user);
4765        yahoo_packet_hash(pkt, 6, "abcde");
4766
4767        yahoo_send_packet(yid, pkt, 0);
4768
4769        yahoo_packet_free(pkt);
4770
4771        pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, yd->session_id);
4772
4773        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4774        yahoo_packet_hash(pkt, 104, room);
4775        yahoo_packet_hash(pkt, 129, roomid);
4776        yahoo_packet_hash(pkt, 62, "2"); /* ??? */
4777
4778        yahoo_send_packet(yid, pkt, 0);
4779
4780        yahoo_packet_free(pkt);
4781}
4782
4783
4784void  yahoo_chat_message(int id, const char *from, const char *room, const char *msg, const int msgtype, const int utf8)
4785{
4786        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4787        struct yahoo_data *yd;
4788        struct yahoo_packet *pkt;
4789        char buf[2];
4790               
4791        if(!yid)
4792                return;
4793
4794        yd = yid->yd;
4795
4796        pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4797
4798        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4799        yahoo_packet_hash(pkt, 104, room);
4800        yahoo_packet_hash(pkt, 117, msg);
4801       
4802        snprintf(buf, sizeof(buf), "%d", msgtype);
4803        yahoo_packet_hash(pkt, 124, buf);
4804
4805        if(utf8)
4806                yahoo_packet_hash(pkt, 97, "1");
4807
4808        yahoo_send_packet(yid, pkt, 0);
4809
4810        yahoo_packet_free(pkt);
4811}
4812
4813
4814void yahoo_chat_logoff(int id, const char *from)
4815{
4816        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4817        struct yahoo_data *yd;
4818        struct yahoo_packet *pkt;
4819               
4820        if(!yid)
4821                return;
4822
4823        yd = yid->yd;
4824
4825        pkt = yahoo_packet_new(YAHOO_SERVICE_CHATLOGOUT, YAHOO_STATUS_AVAILABLE, yd->session_id);
4826
4827        yahoo_packet_hash(pkt, 1, (from?from:yd->user));
4828
4829        yahoo_send_packet(yid, pkt, 0);
4830
4831        yahoo_packet_free(pkt);
4832}
4833
4834void yahoo_buddyicon_request(int id, const char *who)
4835{
4836        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4837        struct yahoo_data *yd;
4838        struct yahoo_packet *pkt;
4839
4840        if( !yid )
4841                return;
4842
4843        yd = yid->yd;
4844       
4845        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0);
4846        yahoo_packet_hash(pkt, 4, yd->user);
4847        yahoo_packet_hash(pkt, 5, who);
4848        yahoo_packet_hash(pkt, 13, "1");
4849        yahoo_send_packet(yid, pkt, 0);
4850
4851        yahoo_packet_free(pkt);
4852}
4853
4854void yahoo_send_picture_info(int id, const char *who, const char *url, int checksum)
4855{
4856        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4857        struct yahoo_data *yd;
4858        struct yahoo_packet *pkt;
4859        char checksum_str[10];
4860
4861        if( !yid )
4862                return;
4863
4864        yd = yid->yd;
4865
4866        snprintf(checksum_str, sizeof(checksum_str), "%d", checksum);
4867
4868        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0);
4869        yahoo_packet_hash(pkt, 1, yd->user);
4870        yahoo_packet_hash(pkt, 4, yd->user);
4871        yahoo_packet_hash(pkt, 5, who);
4872        yahoo_packet_hash(pkt, 13, "2");
4873        yahoo_packet_hash(pkt, 20, url);
4874        yahoo_packet_hash(pkt, 192, checksum_str);
4875        yahoo_send_packet(yid, pkt, 0);
4876
4877        yahoo_packet_free(pkt);
4878}
4879
4880void yahoo_send_picture_update(int id, const char *who, int type)
4881{
4882        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4883        struct yahoo_data *yd;
4884        struct yahoo_packet *pkt;
4885        char type_str[10];
4886
4887        if( !yid )
4888                return;
4889
4890        yd = yid->yd;
4891
4892        snprintf(type_str, sizeof(type_str), "%d", type);
4893
4894        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPDATE, YAHOO_STATUS_AVAILABLE, 0);
4895        yahoo_packet_hash(pkt, 1, yd->user);
4896        yahoo_packet_hash(pkt, 5, who);
4897        yahoo_packet_hash(pkt, 206, type_str);
4898        yahoo_send_packet(yid, pkt, 0);
4899
4900        yahoo_packet_free(pkt);
4901}
4902
4903void yahoo_send_picture_checksum(int id, const char *who, int checksum)
4904{
4905        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4906        struct yahoo_data *yd;
4907        struct yahoo_packet *pkt;
4908        char checksum_str[10];
4909
4910        if( !yid )
4911                return;
4912
4913        yd = yid->yd;
4914       
4915        snprintf(checksum_str, sizeof(checksum_str), "%d", checksum);
4916
4917        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_CHECKSUM, YAHOO_STATUS_AVAILABLE, 0);
4918        yahoo_packet_hash(pkt, 1, yd->user);
4919        if( who != 0 )
4920                yahoo_packet_hash(pkt, 5, who);
4921        yahoo_packet_hash(pkt, 192, checksum_str);
4922        yahoo_packet_hash(pkt, 212, "1");
4923        yahoo_send_packet(yid, pkt, 0);
4924
4925        yahoo_packet_free(pkt);
4926}
4927
4928void yahoo_webcam_close_feed(int id, const char *who)
4929{
4930        struct yahoo_input_data *yid = find_input_by_id_and_webcam_user(id, who);
4931
4932        if(yid)
4933                yahoo_input_close(yid);
4934}
4935
4936void yahoo_webcam_get_feed(int id, const char *who)
4937{
4938        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
4939        struct yahoo_data *yd;
4940        struct yahoo_packet *pkt;
4941               
4942        if(!yid)
4943                return;
4944
4945        /*
4946         * add the user to the queue.  this is a dirty hack, since
4947         * the yahoo server doesn't tell us who's key it's returning,
4948         * we have to just hope that it sends back keys in the same
4949         * order that we request them.
4950         * The queue is popped in yahoo_process_webcam_key
4951         */
4952        webcam_queue = y_list_append(webcam_queue, who?strdup(who):NULL);
4953
4954        yd = yid->yd;
4955
4956        pkt = yahoo_packet_new(YAHOO_SERVICE_WEBCAM, YAHOO_STATUS_AVAILABLE, yd->session_id);
4957
4958        yahoo_packet_hash(pkt, 1, yd->user);
4959        if (who != NULL)
4960                yahoo_packet_hash(pkt, 5, who);
4961        yahoo_send_packet(yid, pkt, 0);
4962
4963        yahoo_packet_free(pkt);
4964}
4965
4966void yahoo_webcam_send_image(int id, unsigned char *image, unsigned int length, unsigned int timestamp)
4967{
4968        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
4969        unsigned char *packet;
4970        unsigned char header_len = 13;
4971        unsigned int pos = 0;
4972
4973        if (!yid)
4974                return;
4975
4976        packet = y_new0(unsigned char, header_len);
4977
4978        packet[pos++] = header_len;
4979        packet[pos++] = 0;
4980        packet[pos++] = 5; /* version byte?? */
4981        packet[pos++] = 0;
4982        pos += yahoo_put32(packet + pos, length);
4983        packet[pos++] = 2; /* packet type, image */
4984        pos += yahoo_put32(packet + pos, timestamp);
4985        yahoo_add_to_send_queue(yid, packet, header_len);
4986        FREE(packet);
4987
4988        if (length)
4989                yahoo_add_to_send_queue(yid, image, length);
4990}
4991
4992void yahoo_webcam_accept_viewer(int id, const char* who, int accept)
4993{
4994        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_WEBCAM);
4995        char *packet = NULL;
4996        char *data = NULL;
4997        unsigned char header_len = 13;
4998        unsigned int pos = 0;
4999        unsigned int len = 0;
5000
5001        if (!yid)
5002                return;
5003
5004        data = strdup("u=");
5005        data = y_string_append(data, (char*)who);
5006        data = y_string_append(data, "\r\n");
5007        len = strlen(data);
5008
5009        packet = y_new0(char, header_len + len);
5010        packet[pos++] = header_len;
5011        packet[pos++] = 0;
5012        packet[pos++] = 5; /* version byte?? */
5013        packet[pos++] = 0;
5014        pos += yahoo_put32(packet + pos, len);
5015        packet[pos++] = 0; /* packet type */
5016        pos += yahoo_put32(packet + pos, accept);
5017        memcpy(packet + pos, data, len);
5018        FREE(data);
5019        yahoo_add_to_send_queue(yid, packet, header_len + len);
5020        FREE(packet);
5021}
5022
5023void yahoo_webcam_invite(int id, const char *who)
5024{
5025        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5026        struct yahoo_packet *pkt;
5027               
5028        if(!yid)
5029                return;
5030
5031        pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yid->yd->session_id);
5032
5033        yahoo_packet_hash(pkt, 49, "WEBCAMINVITE");
5034        yahoo_packet_hash(pkt, 14, " ");
5035        yahoo_packet_hash(pkt, 13, "0");
5036        yahoo_packet_hash(pkt, 1, yid->yd->user);
5037        yahoo_packet_hash(pkt, 5, who);
5038        yahoo_send_packet(yid, pkt, 0);
5039
5040        yahoo_packet_free(pkt);
5041}
5042
5043static void yahoo_search_internal(int id, int t, const char *text, int g, int ar, int photo, int yahoo_only, int startpos, int total)
5044{
5045        struct yahoo_data *yd = find_conn_by_id(id);
5046        struct yahoo_input_data *yid;
5047        char url[1024];
5048        char buff[1024];
5049        char *ctext, *p;
5050
5051        if(!yd)
5052                return;
5053
5054        yid = y_new0(struct yahoo_input_data, 1);
5055        yid->yd = yd;
5056        yid->type = YAHOO_CONNECTION_SEARCH;
5057
5058        /*
5059        age range
5060        .ar=1 - 13-18, 2 - 18-25, 3 - 25-35, 4 - 35-50, 5 - 50-70, 6 - 70+
5061        */
5062
5063        snprintf(buff, sizeof(buff), "&.sq=%%20&.tt=%d&.ss=%d", total, startpos);
5064
5065        ctext = strdup(text);
5066        while((p = strchr(ctext, ' ')))
5067                *p = '+';
5068
5069        snprintf(url, 1024, "http://members.yahoo.com/interests?.oc=m&.kw=%s&.sb=%d&.g=%d&.ar=0%s%s%s",
5070                        ctext, t, g, photo ? "&.p=y" : "", yahoo_only ? "&.pg=y" : "",
5071                        startpos ? buff : "");
5072
5073        FREE(ctext);
5074
5075        snprintf(buff, sizeof(buff), "Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
5076
5077        inputs = y_list_prepend(inputs, yid);
5078        yahoo_http_get(yid->yd->client_id, url, buff, _yahoo_http_connected, yid);
5079}
5080
5081void yahoo_search(int id, enum yahoo_search_type t, const char *text, enum yahoo_search_gender g, enum yahoo_search_agerange ar, 
5082                int photo, int yahoo_only)
5083{
5084        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5085        struct yahoo_search_state *yss;
5086
5087        if(!yid)
5088                return;
5089
5090        if(!yid->ys)
5091                yid->ys = y_new0(struct yahoo_search_state, 1);
5092
5093        yss = yid->ys;
5094
5095        FREE(yss->lsearch_text);
5096        yss->lsearch_type = t;
5097        yss->lsearch_text = strdup(text);
5098        yss->lsearch_gender = g;
5099        yss->lsearch_agerange = ar;
5100        yss->lsearch_photo = photo;
5101        yss->lsearch_yahoo_only = yahoo_only;
5102
5103        yahoo_search_internal(id, t, text, g, ar, photo, yahoo_only, 0, 0);
5104}
5105
5106void yahoo_search_again(int id, int start)
5107{
5108        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
5109        struct yahoo_search_state *yss;
5110
5111        if(!yid || !yid->ys)
5112                return;
5113
5114        yss = yid->ys;
5115
5116        if(start == -1)
5117                start = yss->lsearch_nstart + yss->lsearch_nfound;
5118
5119        yahoo_search_internal(id, yss->lsearch_type, yss->lsearch_text, 
5120                        yss->lsearch_gender, yss->lsearch_agerange, 
5121                        yss->lsearch_photo, yss->lsearch_yahoo_only, 
5122                        start, yss->lsearch_ntotal);
5123}
5124
5125struct send_file_data {
5126        struct yahoo_packet *pkt;
5127        yahoo_get_fd_callback callback;
5128        void *user_data;
5129};
5130
5131static void _yahoo_send_picture_connected(int id, int fd, int error, void *data)
5132{
5133        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT);
5134        struct send_file_data *sfd = data;
5135        struct yahoo_packet *pkt = sfd->pkt;
5136        unsigned char buff[1024];
5137
5138        if(fd <= 0) {
5139                sfd->callback(id, fd, error, sfd->user_data);
5140                FREE(sfd);
5141                yahoo_packet_free(pkt);
5142                inputs = y_list_remove(inputs, yid);
5143                FREE(yid);
5144                return;
5145        }
5146
5147        yid->fd = fd;
5148        yahoo_send_packet(yid, pkt, 8);
5149        yahoo_packet_free(pkt);
5150
5151        snprintf((char *)buff, sizeof(buff), "29");
5152        buff[2] = 0xc0;
5153        buff[3] = 0x80;
5154       
5155        write(yid->fd, buff, 4);
5156
5157        /*      YAHOO_CALLBACK(ext_yahoo_add_handler)(nyd->fd, YAHOO_INPUT_READ); */
5158
5159        sfd->callback(id, fd, error, sfd->user_data);
5160        FREE(sfd);
5161        inputs = y_list_remove(inputs, yid);
5162        /*
5163        while(yahoo_tcp_readline(buff, sizeof(buff), nyd->fd) > 0) {
5164        if(!strcmp(buff, ""))
5165        break;
5166}
5167
5168        */
5169        yahoo_input_close(yid);
5170}
5171
5172void yahoo_send_picture(int id, const char *name, unsigned long size,
5173                                                        yahoo_get_fd_callback callback, void *data)
5174{
5175        struct yahoo_data *yd = find_conn_by_id(id);
5176        struct yahoo_input_data *yid;
5177        struct yahoo_server_settings *yss;
5178        struct yahoo_packet *pkt = NULL;
5179        char size_str[10];
5180        char expire_str[10];
5181        long content_length=0;
5182        unsigned char buff[1024];
5183        char url[255];
5184        struct send_file_data *sfd;
5185
5186        if(!yd)
5187                return;
5188
5189        yss = yd->server_settings;
5190
5191        yid = y_new0(struct yahoo_input_data, 1);
5192        yid->yd = yd;
5193        yid->type = YAHOO_CONNECTION_FT;
5194
5195        pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id);
5196
5197        snprintf(size_str, sizeof(size_str), "%ld", size);
5198        snprintf(expire_str, sizeof(expire_str), "%ld", (long)604800);
5199
5200        yahoo_packet_hash(pkt, 0, yd->user);
5201        yahoo_packet_hash(pkt, 1, yd->user);
5202        yahoo_packet_hash(pkt, 14, "");
5203        yahoo_packet_hash(pkt, 27, name);
5204        yahoo_packet_hash(pkt, 28, size_str);
5205        yahoo_packet_hash(pkt, 38, expire_str);
5206       
5207
5208        content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt);
5209
5210        snprintf(url, sizeof(url), "http://%s:%d/notifyft",
5211                                yss->filetransfer_host, yss->filetransfer_port);
5212        snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s",
5213                                 yd->cookie_y, yd->cookie_t);
5214        inputs = y_list_prepend(inputs, yid);
5215
5216        sfd = y_new0(struct send_file_data, 1);
5217        sfd->pkt = pkt;
5218        sfd->callback = callback;
5219        sfd->user_data = data;
5220        yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size,
5221                                                _yahoo_send_picture_connected, sfd);
5222}
5223
5224static void _yahoo_send_file_connected(int id, int fd, int error, void *data)
5225{
5226        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT);
5227        struct send_file_data *sfd = data;
5228        struct yahoo_packet *pkt = sfd->pkt;
5229        unsigned char buff[1024];
5230
5231        if(fd <= 0) {
5232                sfd->callback(id, fd, error, sfd->user_data);
5233                FREE(sfd);
5234                yahoo_packet_free(pkt);
5235                inputs = y_list_remove(inputs, yid);
5236                FREE(yid);
5237                return;
5238        }
5239
5240        yid->fd = fd;
5241        yahoo_send_packet(yid, pkt, 8);
5242        yahoo_packet_free(pkt);
5243
5244        snprintf((char *)buff, sizeof(buff), "29");
5245        buff[2] = 0xc0;
5246        buff[3] = 0x80;
5247       
5248        write(yid->fd, buff, 4);
5249
5250/*      YAHOO_CALLBACK(ext_yahoo_add_handler)(nyd->fd, YAHOO_INPUT_READ); */
5251
5252        sfd->callback(id, fd, error, sfd->user_data);
5253        FREE(sfd);
5254        inputs = y_list_remove(inputs, yid);
5255        /*
5256        while(yahoo_tcp_readline(buff, sizeof(buff), nyd->fd) > 0) {
5257                if(!strcmp(buff, ""))
5258                        break;
5259        }
5260
5261        */
5262        yahoo_input_close(yid);
5263}
5264
5265void yahoo_send_file(int id, const char *who, const char *msg, 
5266                const char *name, unsigned long size, 
5267                yahoo_get_fd_callback callback, void *data)
5268{
5269        struct yahoo_data *yd = find_conn_by_id(id);
5270        struct yahoo_input_data *yid;
5271        struct yahoo_server_settings *yss;
5272        struct yahoo_packet *pkt = NULL;
5273        char size_str[10];
5274        long content_length=0;
5275        unsigned char buff[1024];
5276        char url[255];
5277        struct send_file_data *sfd;
5278
5279        if(!yd)
5280                return;
5281
5282        yss = yd->server_settings;
5283
5284        yid = y_new0(struct yahoo_input_data, 1);
5285        yid->yd = yd;
5286        yid->type = YAHOO_CONNECTION_FT;
5287
5288        pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
5289
5290        snprintf(size_str, sizeof(size_str), "%ld", size);
5291
5292        yahoo_packet_hash(pkt, 0, yd->user);
5293        yahoo_packet_hash(pkt, 5, who);
5294        yahoo_packet_hash(pkt, 14, msg);
5295        yahoo_packet_hash(pkt, 27, name);
5296        yahoo_packet_hash(pkt, 28, size_str);
5297
5298        content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt);
5299
5300        snprintf(url, sizeof(url), "http://%s:%d/notifyft", 
5301                        yss->filetransfer_host, yss->filetransfer_port);
5302        snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s",
5303                        yd->cookie_y, yd->cookie_t);
5304        inputs = y_list_prepend(inputs, yid);
5305
5306        sfd = y_new0(struct send_file_data, 1);
5307        sfd->pkt = pkt;
5308        sfd->callback = callback;
5309        sfd->user_data = data;
5310        yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size,
5311                        _yahoo_send_file_connected, sfd);
5312}
5313
5314
5315enum yahoo_status yahoo_current_status(int id)
5316{
5317        struct yahoo_data *yd = find_conn_by_id(id);
5318        if(!yd)
5319                return YAHOO_STATUS_OFFLINE;
5320        return yd->current_status;
5321}
5322
5323const YList * yahoo_get_buddylist(int id)
5324{
5325        struct yahoo_data *yd = find_conn_by_id(id);
5326        if(!yd)
5327                return NULL;
5328        return yd->buddies;
5329}
5330
5331const YList * yahoo_get_ignorelist(int id)
5332{
5333        struct yahoo_data *yd = find_conn_by_id(id);
5334        if(!yd)
5335                return NULL;
5336        return yd->ignore;
5337}
5338
5339const YList * yahoo_get_identities(int id)
5340{
5341        struct yahoo_data *yd = find_conn_by_id(id);
5342        if(!yd)
5343                return NULL;
5344        return yd->identities;
5345}
5346
5347const char * yahoo_get_cookie(int id, const char *which)
5348{
5349        struct yahoo_data *yd = find_conn_by_id(id);
5350        if(!yd)
5351                return NULL;
5352        if(!strncasecmp(which, "y", 1))
5353                return yd->cookie_y;
5354        if(!strncasecmp(which, "t", 1))
5355                return yd->cookie_t;
5356        if(!strncasecmp(which, "c", 1))
5357                return yd->cookie_c;
5358        if(!strncasecmp(which, "login", 5))
5359                return yd->login_cookie;
5360        return NULL;
5361}
5362
5363void yahoo_get_url_handle(int id, const char *url, 
5364                yahoo_get_url_handle_callback callback, void *data)
5365{
5366        struct yahoo_data *yd = find_conn_by_id(id);
5367        if(!yd)
5368                return;
5369
5370        yahoo_get_url_fd(id, url, yd, callback, data);
5371}
5372
5373const char * yahoo_get_profile_url( void )
5374{
5375        return profile_url;
5376}
5377
Note: See TracBrowser for help on using the repository browser.