source: protocols/yahoo/libyahoo2.c @ 5ec4129

Last change on this file since 5ec4129 was 52df5df, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-06-14T01:19:12Z

This seems to fix the Yahoo! logoff code. I have no idea why this was broken
(on purpose) in libyahoo2, but this fix seems to work and at least Valgrind
is still happy. And I actually see myself log off now, and the fd is actually
cleaned up properly.

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