source: protocols/yahoo/libyahoo2.c @ 875ad42

Last change on this file since 875ad42 was fcc2da9, checked in by Jelmer Vernooij <jelmer@…>, at 2006-05-26T15:46:51Z

Remove unnecessary Windows-specific code.

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