source: protocols/yahoo/libyahoo2.c @ 85d7b85

Last change on this file since 85d7b85 was 85d7b85, checked in by Jelmer Vernooij <jelmer@…>, at 2008-04-02T14:22:57Z

Merge trunk.

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