source: protocols/yahoo/libyahoo2.c @ e960a52

Last change on this file since e960a52 was 4bb50ef, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-03-15T23:53:54Z

Although I have no idea what the author meant with code like
`if(cp != "\005")', I'm sure he feels homesick to QuickBasic. Since BitlBee
doesn't use this function anyway, it doesn't really matter if my fix works.
As long as it keeps the compiler quiet.

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