source: protocols/yahoo/libyahoo2.c @ 718e05f

Last change on this file since 718e05f was 178e2f8, checked in by Jelmer Vernooij <jelmer@…>, at 2008-06-28T17:32:41Z

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