source: protocols/yahoo/libyahoo2.c @ 812a413

Last change on this file since 812a413 was 812a413, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-06-23T18:15:28Z

Added saner base64 encoding function (actually, moved the one from libyahoo2.c
to core, with some changes), which I need for the XML format password garbling.

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