source: protocols/yahoo/libyahoo2.c @ cfc8d58

Last change on this file since cfc8d58 was cfc8d58, checked in by Wilmer van der Gaast <wilmer@…>, at 2007-04-16T04:31:52Z

Updating the Yahoo! module. This seems to fix handling of incoming away
states/messages, should fix some issues with group chats, and unfortunately
also adds some crap which I don't want to clean up for now.

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