source: protocols/yahoo/libyahoo2.c @ 9cb9868

Last change on this file since 9cb9868 was b7d3cc34, checked in by Wilmer van der Gaast <wilmer@…>, at 2005-11-06T18:23:18Z

Initial repository (0.99 release tree)

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