source: protocols/yahoo/libyahoo2.c @ 0a69d7b

Last change on this file since 0a69d7b was c3c2e14, checked in by Wilmer van der Gaast <wilmer@…>, at 2005-11-30T12:12:25Z

Got rid of the config.h includes in IM-code. Now that HAVE_CONFIG_H is
defined, they started to cause problems.

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