source: protocols/yahoo/libyahoo2.c @ 286b28e

Last change on this file since 286b28e was 1be0d26, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-13T00:12:07Z

Fixed handling of contact lists where at least the first contact is not in
any group yet. Crashing is not the right solution.

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