source: protocols/yahoo/libyahoo2.c @ 3f81999

Last change on this file since 3f81999 was 3f81999, checked in by Sven Moritz Hallberg <pesco@…>, at 2010-06-03T10:31:46Z

merge in bitlbee 1.2.4

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