source: protocols/yahoo/libyahoo2.c @ 77bfd07

Last change on this file since 77bfd07 was 77bfd07, checked in by Wilmer van der Gaast <wilmer@…>, at 2007-11-23T23:07:44Z

Replaced GPL-incompatible SHA1 hashing code (and renamed the files in case
I ever need SHA256 ;-)).

  • Property mode set to 100644
File size: 120.4 KB
RevLine 
[b7d3cc34]1/*
2 * libyahoo2: libyahoo2.c
3 *
4 * Some code copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
5 *
6 * Yahoo Search copyright (C) 2003, Konstantin Klyagin <konst AT konst.org.ua>
7 *
8 * Much of this code was taken and adapted from the yahoo module for
9 * gaim released under the GNU GPL.  This code is also released under the
10 * GNU GPL.
11 *
12 * This code is derivitive of Gaim <http://gaim.sourceforge.net>
13 * copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
14 *             1998-1999, Adam Fritzler <afritz@marko.net>
15 *             1998-2002, Rob Flynn <rob@marko.net>
16 *             2000-2002, Eric Warmenhoven <eric@warmenhoven.org>
17 *             2001-2002, Brian Macke <macke@strangelove.net>
18 *                  2001, Anand Biligiri S <abiligiri@users.sf.net>
19 *                  2001, Valdis Kletnieks
20 *                  2002, Sean Egan <bj91704@binghamton.edu>
21 *                  2002, Toby Gray <toby.gray@ntlworld.com>
22 *
23 * This library also uses code from other libraries, namely:
24 *     Portions from libfaim copyright 1998, 1999 Adam Fritzler
25 *     <afritz@auk.cx>
26 *     Portions of Sylpheed copyright 2000-2002 Hiroyuki Yamamoto
27 *     <hiro-y@kcn.ne.jp>
28 *
29 *
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
43 *
44 */
45
46#ifndef _WIN32
47#include <unistd.h>
48#endif
49#include <errno.h>
50#include <stdio.h>
51#include <stdarg.h>
52
53#if STDC_HEADERS
54# include <string.h>
55#else
56# if !HAVE_STRCHR
57#  define strchr index
58#  define strrchr rindex
59# endif
60char *strchr (), *strrchr ();
61# if !HAVE_MEMCPY
62#  define memcpy(d, s, n) bcopy ((s), (d), (n))
63#  define memmove(d, s, n) bcopy ((s), (d), (n))
64# endif
65#endif
66
67#include <sys/types.h>
68
69#ifdef __MINGW32__
70# include <winsock2.h>
71# define write(a,b,c) send(a,b,c,0)
72# define read(a,b,c)  recv(a,b,c,0)
73#endif
74
75#include <stdlib.h>
76#include <ctype.h>
77
[77bfd07]78#include "sha1.h"
[b7d3cc34]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
[7ed3199]92#include "base64.h"
93
[b7d3cc34]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
[cfc8d58]107static int yahoo_send_data(int fd, void *data, int len);
108
[b7d3cc34]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,
[cfc8d58]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
[b7d3cc34]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) */
[812a413]707static void to_y64(unsigned char *out, const unsigned char *in, int inlen)
[b7d3cc34]708{
[7ed3199]709        base64_encode_real(in, inlen, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-");
[b7d3cc34]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       
[cfc8d58]750        if( yid->type == YAHOO_CONNECTION_FT )
751                yahoo_send_data(yid->fd, data, len);
752        else
[b7d3cc34]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;
[cfc8d58]938        char *to = NULL;
[b7d3cc34]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;
[cfc8d58]947                if (pair->key == 5)
948                        to = pair->value;
[b7d3cc34]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"))) 
[cfc8d58]966                YAHOO_CALLBACK(ext_yahoo_typing_notify)(yd->client_id, to, from, stat);
[b7d3cc34]967        else if (!strncasecmp(msg, "GAME", strlen("GAME"))) 
[cfc8d58]968                YAHOO_CALLBACK(ext_yahoo_game_notify)(yd->client_id, to, from, stat);
[b7d3cc34]969        else if (!strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) 
970        {
971                if (!strcmp(ind, " ")) {
[cfc8d58]972                        YAHOO_CALLBACK(ext_yahoo_webcam_invite)(yd->client_id, to, from);
[b7d3cc34]973                } else {
974                        accept = atoi(ind);
975                        /* accept the invitation (-1 = deny 1 = accept) */
976                        if (accept < 0)
977                                accept = 0;
[cfc8d58]978                        YAHOO_CALLBACK(ext_yahoo_webcam_invite_reply)(yd->client_id, to, from, accept);
[b7d3cc34]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)
[cfc8d58]1037                YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, to, from, url, expires, msg, filename, filesize);
[b7d3cc34]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)
[cfc8d58]1111                        YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members);
[b7d3cc34]1112                else if(msg)
[cfc8d58]1113                        YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, msg, 0, E_CONFNOTAVAIL);
[b7d3cc34]1114                break;
1115        case YAHOO_SERVICE_CONFADDINVITE:
1116                if(pkt->status == 2)
1117                        ;
1118                else
[cfc8d58]1119                        YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members);
[b7d3cc34]1120                break;
1121        case YAHOO_SERVICE_CONFDECLINE:
1122                if(who)
[cfc8d58]1123                        YAHOO_CALLBACK(ext_yahoo_conf_userdecline)(yd->client_id, id, who, room, msg);
[b7d3cc34]1124                break;
1125        case YAHOO_SERVICE_CONFLOGON:
1126                if(who)
[cfc8d58]1127                        YAHOO_CALLBACK(ext_yahoo_conf_userjoin)(yd->client_id, id, who, room);
[b7d3cc34]1128                break;
1129        case YAHOO_SERVICE_CONFLOGOFF:
1130                if(who)
[cfc8d58]1131                        YAHOO_CALLBACK(ext_yahoo_conf_userleave)(yd->client_id, id, who, room);
[b7d3cc34]1132                break;
1133        case YAHOO_SERVICE_CONFMSG:
1134                if(who)
[cfc8d58]1135                        YAHOO_CALLBACK(ext_yahoo_conf_message)(yd->client_id, id, who, room, msg, utf8);
[b7d3cc34]1136                break;
1137        }
1138}
1139
1140static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
1141{
1142        char *msg = NULL;
[cfc8d58]1143        char *id = NULL;
[b7d3cc34]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
[cfc8d58]1160                if (pair->key == 1) {
1161                        /* My identity */
1162                        id = pair->value;
1163                }
1164
[b7d3cc34]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 */
[cfc8d58]1239                        YAHOO_CALLBACK(ext_yahoo_chat_yahoologout)(yid->yd->client_id, id);
[b7d3cc34]1240                        return ;
1241                }
1242                if (pkt->service == YAHOO_SERVICE_COMMENT && chaterr)  {
[cfc8d58]1243                        YAHOO_CALLBACK(ext_yahoo_chat_yahooerror)(yid->yd->client_id, id);
1244                        return;
[b7d3cc34]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) {
[cfc8d58]1257                        YAHOO_CALLBACK(ext_yahoo_chat_join)(yid->yd->client_id, id, room, topic, members, yid->fd);
[b7d3cc34]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;
[cfc8d58]1266                                YAHOO_CALLBACK(ext_yahoo_chat_userjoin)(yid->yd->client_id, id, room, currentmember);
[b7d3cc34]1267                                y_list_free_1(members);
1268                                members=n;
1269                        }
1270                }
1271                break;
1272        case YAHOO_SERVICE_CHATEXIT:
1273                if(who) {
[cfc8d58]1274                        YAHOO_CALLBACK(ext_yahoo_chat_userleave)(yid->yd->client_id, id, room, who);
[b7d3cc34]1275                }
1276                break;
1277        case YAHOO_SERVICE_COMMENT:
1278                if(who) {
[cfc8d58]1279                        YAHOO_CALLBACK(ext_yahoo_chat_message)(yid->yd->client_id, id, who, room, msg, msgtype, utf8);
[b7d3cc34]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) {
[cfc8d58]1338                        YAHOO_CALLBACK(ext_yahoo_got_im)(yd->client_id, message->to, message->from, message->msg, message->tm, pkt->status, message->utf8);
[b7d3cc34]1339                } else if (pkt->status == 0xffffffff) {
[cfc8d58]1340                        YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, message->msg, 0, E_SYSTEM);
[b7d3cc34]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;
[cfc8d58]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;
[b7d3cc34]1377       
[cfc8d58]1378        if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
[b7d3cc34]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 */
[cfc8d58]1402                        u = y_new0(struct user, 1);
1403                        u->name = pair->value;
1404                        users = y_list_prepend(users, u);
[b7d3cc34]1405                        break;
1406                case 10: /* state */
[cfc8d58]1407                        ((struct user*)users->data)->state = strtol(pair->value, NULL, 10);
[b7d3cc34]1408                        break;
1409                case 19: /* custom status message */
[cfc8d58]1410                        ((struct user*)users->data)->msg = pair->value;
[b7d3cc34]1411                        break;
1412                case 47: /* is it an away message or not */
[cfc8d58]1413                        ((struct user*)users->data)->away = atoi(pair->value);
[b7d3cc34]1414                        break;
1415                case 137: /* seconds idle */
[cfc8d58]1416                        ((struct user*)users->data)->idle = atoi(pair->value);
[b7d3cc34]1417                        break;
[cfc8d58]1418                case 11: /* this is the buddy's session id */
1419                        ((struct user*)users->data)->buddy_session = atoi(pair->value);
[b7d3cc34]1420                        break;
1421                case 17: /* in chat? */
[cfc8d58]1422                        ((struct user*)users->data)->f17 = atoi(pair->value);
[b7d3cc34]1423                        break;
[cfc8d58]1424                case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
1425                        ((struct user*)users->data)->flags = atoi(pair->value);
[b7d3cc34]1426                        break;
[cfc8d58]1427                case 60: /* SMS -> 1 MOBILE USER */
[b7d3cc34]1428                        /* sometimes going offline makes this 2, but invisible never sends it */
[cfc8d58]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;
[b7d3cc34]1458                case 16: /* Custom error message */
[cfc8d58]1459                        YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0, E_CUSTOM);
[b7d3cc34]1460                        break;
1461                default:
1462                        WARNING(("unknown status key %d:%s", pair->key, pair->value));
1463                        break;
1464                }
1465        }
[cfc8d58]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        }
[b7d3cc34]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
[cfc8d58]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
[b7d3cc34]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
[77bfd07]1822        sha1_state_t       ctx1;
1823        sha1_state_t       ctx2;
[b7d3cc34]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
[77bfd07]1879        while (*magic_ptr != 0) {
[b7d3cc34]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
[77bfd07]2058        sha1_init(&ctx1);
2059        sha1_init(&ctx2);
[b7d3cc34]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
[77bfd07]2066        sha1_append(&ctx1, pass_hash_xor1, 64);
[b7d3cc34]2067        if (j >= 3 )
[77bfd07]2068                ctx1.Length_Low = 0x1ff;
2069        sha1_append(&ctx1, magic_key_char, 4);
2070        sha1_finish(&ctx1, digest1);
[b7d3cc34]2071
2072         /* The second context gets the password hash XORed
2073          * with 0x5c plus the SHA-1 digest
2074          * of the first context. */
2075
[77bfd07]2076        sha1_append(&ctx2, pass_hash_xor2, 64);
2077        sha1_append(&ctx2, digest1, 20);
2078        sha1_finish(&ctx2, digest2);
[b7d3cc34]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
[77bfd07]2149        sha1_init(&ctx1);
2150        sha1_init(&ctx2);
[b7d3cc34]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
[77bfd07]2157        sha1_append(&ctx1, crypt_hash_xor1, 64);
[b7d3cc34]2158        if (j >= 3 )
[77bfd07]2159                ctx1.Length_Low = 0x1ff;
2160        sha1_append(&ctx1, magic_key_char, 4);
2161        sha1_finish(&ctx1, digest1);
[b7d3cc34]2162
2163        /* The second context gets the password hash XORed
2164         * with 0x5c plus the SHA-1 digest
2165         * of the first context. */
2166
[77bfd07]2167        sha1_append(&ctx2, crypt_hash_xor2, 64);
2168        sha1_append(&ctx2, digest1, 20);
2169        sha1_finish(&ctx2, digest2);
[b7d3cc34]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;
[cfc8d58]2337        int idle = 0;
2338        int mobile = 0;
[b7d3cc34]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);
[cfc8d58]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               
[b7d3cc34]2365        }
2366
2367        if (id)
2368                YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, id, who, msg);
2369        else if (name)
[cfc8d58]2370                YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away, idle, mobile);
[b7d3cc34]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
[f0cb961]2405        /* status: 0 == Successful, 1 == Error (does not exist), 2 == Already in list */
2406        if( status == 0 ) {
2407                bud = y_new0(struct yahoo_buddy, 1);
2408                bud->id = strdup(who);
2409                bud->group = strdup(where);
2410                bud->real_name = NULL;
2411               
2412                yd->buddies = y_list_append(yd->buddies, bud);
2413               
2414                /* Possibly called already, but at least the call above doesn't
2415                   seem to happen every time (not anytime I tried). */
2416                YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, me, who, NULL);
2417        }
[b7d3cc34]2418
2419/*      YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */
2420}
2421
2422static void yahoo_process_buddydel(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2423{
2424        struct yahoo_data *yd = yid->yd;
2425        char *who = NULL;
2426        char *where = NULL;
2427        int unk_66 = 0;
2428        char *me = NULL;
2429        struct yahoo_buddy *bud;
2430
2431        YList *buddy;
2432
2433        YList *l;
2434        for (l = pkt->hash; l; l = l->next) {
2435                struct yahoo_pair *pair = l->data;
2436                if (pair->key == 1)
2437                        me = pair->value;
2438                else if (pair->key == 7)
2439                        who = pair->value;
2440                else if (pair->key == 65)
2441                        where = pair->value;
2442                else if (pair->key == 66)
2443                        unk_66 = strtol(pair->value, NULL, 10);
2444                else
2445                        DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value));
2446        }
2447
2448        if(!who || !where)
2449                return;
2450       
2451        bud = y_new0(struct yahoo_buddy, 1);
2452        bud->id = strdup(who);
2453        bud->group = strdup(where);
2454
2455        buddy = y_list_find_custom(yd->buddies, bud, is_same_bud);
2456
2457        FREE(bud->id);
2458        FREE(bud->group);
2459        FREE(bud);
2460
2461        if(buddy) {
2462                bud = buddy->data;
2463                yd->buddies = y_list_remove_link(yd->buddies, buddy);
2464                y_list_free_1(buddy);
2465
2466                FREE(bud->id);
2467                FREE(bud->group);
2468                FREE(bud->real_name);
2469                FREE(bud);
2470
2471                bud=NULL;
2472        }
2473}
2474
2475static void yahoo_process_ignore(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2476{
2477        char *who = NULL;
2478        int  status = 0;
2479        char *me = NULL;
2480        int  un_ignore = 0;
2481
2482        YList *l;
2483        for (l = pkt->hash; l; l = l->next) {
2484                struct yahoo_pair *pair = l->data;
2485                if (pair->key == 0)
2486                        who = pair->value;
2487                if (pair->key == 1)
2488                        me = pair->value;
2489                if (pair->key == 13) /* 1 == ignore, 2 == unignore */ 
2490                        un_ignore = strtol(pair->value, NULL, 10);
2491                if (pair->key == 66) 
2492                        status = strtol(pair->value, NULL, 10);
2493        }
2494
2495
2496        /*
2497         * status
2498         *      0  - ok
2499         *      2  - already in ignore list, could not add
2500         *      3  - not in ignore list, could not delete
2501         *      12 - is a buddy, could not add
2502         */
2503
2504/*      if(status)
[cfc8d58]2505                YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, who, 0, status);
[b7d3cc34]2506*/     
2507}
2508
2509static void yahoo_process_voicechat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2510{
2511        char *who = NULL;
2512        char *me = NULL;
2513        char *room = NULL;
2514        char *voice_room = NULL;
2515
2516        YList *l;
2517        for (l = pkt->hash; l; l = l->next) {
2518                struct yahoo_pair *pair = l->data;
2519                if (pair->key == 4)
2520                        who = pair->value;
2521                if (pair->key == 5)
2522                        me = pair->value;
2523                if (pair->key == 13)
2524                        voice_room=pair->value;
2525                if (pair->key == 57) 
2526                        room=pair->value;
2527        }
2528
[cfc8d58]2529        NOTICE(("got voice chat invite from %s in %s to identity %s", who, room, me));
[b7d3cc34]2530        /*
2531         * send: s:0 1:me 5:who 57:room 13:1
2532         * ????  s:4 5:who 10:99 19:-1615114531
2533         * gotr: s:4 5:who 10:99 19:-1615114615
2534         * ????  s:1 5:me 4:who 57:room 13:3room
2535         * got:  s:1 5:me 4:who 57:room 13:1room
2536         * rej:  s:0 1:me 5:who 57:room 13:3
2537         * rejr: s:4 5:who 10:99 19:-1617114599
2538         */
2539}
2540
[cfc8d58]2541static void yahoo_process_ping(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2542{
2543        char *errormsg = NULL;
2544       
2545        YList *l;
2546        for (l = pkt->hash; l; l = l->next) {
2547                struct yahoo_pair *pair = l->data;
2548                if (pair->key == 16)
2549                        errormsg = pair->value;
2550        }
2551       
2552        NOTICE(("got ping packet"));
2553        YAHOO_CALLBACK(ext_yahoo_got_ping)(yid->yd->client_id, errormsg);
2554}
2555
[b7d3cc34]2556static void _yahoo_webcam_get_server_connected(int fd, int error, void *d)
2557{
2558        struct yahoo_input_data *yid = d;
2559        char *who = yid->wcm->user;
2560        char *data = NULL;
2561        char *packet = NULL;
2562        unsigned char magic_nr[] = {0, 1, 0};
2563        unsigned char header_len = 8;
2564        unsigned int len = 0;
2565        unsigned int pos = 0;
2566
2567        if(error || fd <= 0) {
2568                FREE(who);
2569                FREE(yid);
2570                return;
2571        }
2572
2573        yid->fd = fd;
2574        inputs = y_list_prepend(inputs, yid);
2575       
2576        /* send initial packet */
2577        if (who)
2578                data = strdup("<RVWCFG>");
2579        else
2580                data = strdup("<RUPCFG>");
2581        yahoo_add_to_send_queue(yid, data, strlen(data));
2582        FREE(data);
2583
2584        /* send data */
2585        if (who)
2586        {
2587                data = strdup("g=");
2588                data = y_string_append(data, who);
2589                data = y_string_append(data, "\r\n");
2590        } else {
2591                data = strdup("f=1\r\n");
2592        }
2593        len = strlen(data);
2594        packet = y_new0(char, header_len + len);
2595        packet[pos++] = header_len;
2596        memcpy(packet + pos, magic_nr, sizeof(magic_nr));
2597        pos += sizeof(magic_nr);
2598        pos += yahoo_put32(packet + pos, len);
2599        memcpy(packet + pos, data, len);
2600        pos += len;
2601        yahoo_add_to_send_queue(yid, packet, pos);
2602        FREE(packet);
2603        FREE(data);
2604
2605        yid->read_tag=YAHOO_CALLBACK(ext_yahoo_add_handler)(yid->yd->client_id, fd, YAHOO_INPUT_READ, yid);
2606}
2607
2608static void yahoo_webcam_get_server(struct yahoo_input_data *y, char *who, char *key)
2609{
2610        struct yahoo_input_data *yid = y_new0(struct yahoo_input_data, 1);
2611        struct yahoo_server_settings *yss = y->yd->server_settings;
2612
2613        yid->type = YAHOO_CONNECTION_WEBCAM_MASTER;
2614        yid->yd = y->yd;
2615        yid->wcm = y_new0(struct yahoo_webcam, 1);
2616        yid->wcm->user = who?strdup(who):NULL;
2617        yid->wcm->direction = who?YAHOO_WEBCAM_DOWNLOAD:YAHOO_WEBCAM_UPLOAD;
2618        yid->wcm->key = strdup(key);
2619
2620        YAHOO_CALLBACK(ext_yahoo_connect_async)(yid->yd->client_id, yss->webcam_host, yss->webcam_port, 
2621                        _yahoo_webcam_get_server_connected, yid);
2622
2623}
2624
2625static YList *webcam_queue=NULL;
2626static void yahoo_process_webcam_key(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2627{
2628        char *me = NULL;
2629        char *key = NULL;
2630        char *who = NULL;
2631
2632        YList *l;
2633        yahoo_dump_unhandled(pkt);
2634        for (l = pkt->hash; l; l = l->next) {
2635                struct yahoo_pair *pair = l->data;
2636                if (pair->key == 5)
2637                        me = pair->value;
2638                if (pair->key == 61) 
2639                        key=pair->value;
2640        }
2641
2642        l = webcam_queue;
2643        if(!l)
2644                return;
2645        who = l->data;
2646        webcam_queue = y_list_remove_link(webcam_queue, webcam_queue);
2647        y_list_free_1(l);
2648        yahoo_webcam_get_server(yid, who, key);
2649        FREE(who);
2650}
2651
2652static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
2653{
2654        DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service));
2655        switch (pkt->service)
2656        {
2657        case YAHOO_SERVICE_USERSTAT:
2658        case YAHOO_SERVICE_LOGON:
2659        case YAHOO_SERVICE_LOGOFF:
2660        case YAHOO_SERVICE_ISAWAY:
2661        case YAHOO_SERVICE_ISBACK:
2662        case YAHOO_SERVICE_GAMELOGON:
2663        case YAHOO_SERVICE_GAMELOGOFF:
2664        case YAHOO_SERVICE_IDACT:
2665        case YAHOO_SERVICE_IDDEACT:
2666                yahoo_process_status(yid, pkt);
2667                break;
2668        case YAHOO_SERVICE_NOTIFY:
2669                yahoo_process_notify(yid, pkt);
2670                break;
2671        case YAHOO_SERVICE_MESSAGE:
2672        case YAHOO_SERVICE_GAMEMSG:
2673        case YAHOO_SERVICE_SYSMESSAGE:
2674                yahoo_process_message(yid, pkt);
2675                break;
2676        case YAHOO_SERVICE_NEWMAIL:
2677                yahoo_process_mail(yid, pkt);
2678                break;
2679        case YAHOO_SERVICE_NEWCONTACT:
2680                yahoo_process_contact(yid, pkt);
2681                break;
2682        case YAHOO_SERVICE_LIST:
2683                yahoo_process_list(yid, pkt);
2684                break;
2685        case YAHOO_SERVICE_VERIFY:
2686                yahoo_process_verify(yid, pkt);
2687                break;
2688        case YAHOO_SERVICE_AUTH:
2689                yahoo_process_auth(yid, pkt);
2690                break;
2691        case YAHOO_SERVICE_AUTHRESP:
2692                yahoo_process_auth_resp(yid, pkt);
2693                break;
2694        case YAHOO_SERVICE_CONFINVITE:
2695        case YAHOO_SERVICE_CONFADDINVITE:
2696        case YAHOO_SERVICE_CONFDECLINE:
2697        case YAHOO_SERVICE_CONFLOGON:
2698        case YAHOO_SERVICE_CONFLOGOFF:
2699        case YAHOO_SERVICE_CONFMSG:
2700                yahoo_process_conference(yid, pkt);
2701                break;
2702        case YAHOO_SERVICE_CHATONLINE:
2703        case YAHOO_SERVICE_CHATGOTO:
2704        case YAHOO_SERVICE_CHATJOIN:
2705        case YAHOO_SERVICE_CHATLEAVE:
2706        case YAHOO_SERVICE_CHATEXIT:
2707        case YAHOO_SERVICE_CHATLOGOUT:
2708        case YAHOO_SERVICE_CHATPING:
2709        case YAHOO_SERVICE_COMMENT:
2710                yahoo_process_chat(yid, pkt);
2711                break;
2712        case YAHOO_SERVICE_P2PFILEXFER:
2713        case YAHOO_SERVICE_FILETRANSFER:
2714                yahoo_process_filetransfer(yid, pkt);
2715                break;
2716        case YAHOO_SERVICE_ADDBUDDY:
2717                yahoo_process_buddyadd(yid, pkt);
2718                break;
2719        case YAHOO_SERVICE_REMBUDDY:
2720                yahoo_process_buddydel(yid, pkt);
2721                break;
2722        case YAHOO_SERVICE_IGNORECONTACT:
2723                yahoo_process_ignore(yid, pkt);
2724                break;
2725        case YAHOO_SERVICE_VOICECHAT:
2726                yahoo_process_voicechat(yid, pkt);
2727                break;
2728        case YAHOO_SERVICE_WEBCAM:
2729                yahoo_process_webcam_key(yid, pkt);
2730                break;
[cfc8d58]2731        case YAHOO_SERVICE_PING:
2732                yahoo_process_ping(yid, pkt);
2733                break;
[b7d3cc34]2734        case YAHOO_SERVICE_IDLE:
2735        case YAHOO_SERVICE_MAILSTAT:
2736        case YAHOO_SERVICE_CHATINVITE:
2737        case YAHOO_SERVICE_CALENDAR:
2738        case YAHOO_SERVICE_NEWPERSONALMAIL:
2739        case YAHOO_SERVICE_ADDIDENT:
2740        case YAHOO_SERVICE_ADDIGNORE:
2741        case YAHOO_SERVICE_GOTGROUPRENAME:
2742        case YAHOO_SERVICE_GROUPRENAME:
2743        case YAHOO_SERVICE_PASSTHROUGH2:
2744        case YAHOO_SERVICE_CHATLOGON:
2745        case YAHOO_SERVICE_CHATLOGOFF:
2746        case YAHOO_SERVICE_CHATMSG:
2747        case YAHOO_SERVICE_REJECTCONTACT:
2748        case YAHOO_SERVICE_PEERTOPEER:
2749                WARNING(("unhandled service 0x%02x", pkt->service));
2750                yahoo_dump_unhandled(pkt);
2751                break;
[cfc8d58]2752        case YAHOO_SERVICE_PICTURE:
2753                yahoo_process_picture(yid, pkt);
2754                break;
2755        case YAHOO_SERVICE_PICTURE_CHECKSUM:
2756                yahoo_process_picture_checksum(yid, pkt);
2757                break;
2758        case YAHOO_SERVICE_PICTURE_UPLOAD:
2759                yahoo_process_picture_upload(yid, pkt);
2760                break; 
[b7d3cc34]2761        default:
2762                WARNING(("unknown service 0x%02x", pkt->service));
2763                yahoo_dump_unhandled(pkt);
2764                break;
2765        }
2766}
2767
2768static struct yahoo_packet * yahoo_getdata(struct yahoo_input_data * yid)
2769{
2770        struct yahoo_packet *pkt;
2771        struct yahoo_data *yd = yid->yd;
2772        int pos = 0;
2773        int pktlen;
2774
2775        if(!yd)
2776                return NULL;
2777
2778        DEBUG_MSG(("rxlen is %d", yid->rxlen));
2779        if (yid->rxlen < YAHOO_PACKET_HDRLEN) {
2780                DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN"));
2781                return NULL;
2782        }
2783
2784        pos += 4; /* YMSG */
2785        pos += 2;
2786        pos += 2;
2787
2788        pktlen = yahoo_get16(yid->rxqueue + pos); pos += 2;
2789        DEBUG_MSG(("%d bytes to read, rxlen is %d", 
2790                        pktlen, yid->rxlen));
2791
2792        if (yid->rxlen < (YAHOO_PACKET_HDRLEN + pktlen)) {
2793                DEBUG_MSG(("len < YAHOO_PACKET_HDRLEN + pktlen"));
2794                return NULL;
2795        }
2796
2797        LOG(("reading packet"));
2798        yahoo_packet_dump(yid->rxqueue, YAHOO_PACKET_HDRLEN + pktlen);
2799
2800        pkt = yahoo_packet_new(0, 0, 0);
2801
2802        pkt->service = yahoo_get16(yid->rxqueue + pos); pos += 2;
2803        pkt->status = yahoo_get32(yid->rxqueue + pos); pos += 4;
2804        DEBUG_MSG(("Yahoo Service: 0x%02x Status: %d", pkt->service,
2805                                pkt->status));
2806        pkt->id = yahoo_get32(yid->rxqueue + pos); pos += 4;
2807
2808        yd->session_id = pkt->id;
2809
2810        yahoo_packet_read(pkt, yid->rxqueue + pos, pktlen);
2811
2812        yid->rxlen -= YAHOO_PACKET_HDRLEN + pktlen;
2813        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2814        if (yid->rxlen>0) {
2815                unsigned char *tmp = y_memdup(yid->rxqueue + YAHOO_PACKET_HDRLEN
2816                                + pktlen, yid->rxlen);
2817                FREE(yid->rxqueue);
2818                yid->rxqueue = tmp;
2819                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2820        } else {
2821                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
2822                FREE(yid->rxqueue);
2823        }
2824
2825        return pkt;
2826}
2827
2828static void yahoo_yab_read(struct yab *yab, unsigned char *d, int len)
2829{
2830        char *st, *en;
2831        char *data = (char *)d;
2832        data[len]='\0';
2833
2834        DEBUG_MSG(("Got yab: %s", data));
2835        st = en = strstr(data, "userid=\"");
2836        if(st) {
2837                st += strlen("userid=\"");
2838                en = strchr(st, '"'); *en++ = '\0';
2839                yab->id = yahoo_xmldecode(st);
2840        }
2841
2842        st = strstr(en, "fname=\"");
2843        if(st) {
2844                st += strlen("fname=\"");
2845                en = strchr(st, '"'); *en++ = '\0';
2846                yab->fname = yahoo_xmldecode(st);
2847        }
2848
2849        st = strstr(en, "lname=\"");
2850        if(st) {
2851                st += strlen("lname=\"");
2852                en = strchr(st, '"'); *en++ = '\0';
2853                yab->lname = yahoo_xmldecode(st);
2854        }
2855
2856        st = strstr(en, "nname=\"");
2857        if(st) {
2858                st += strlen("nname=\"");
2859                en = strchr(st, '"'); *en++ = '\0';
2860                yab->nname = yahoo_xmldecode(st);
2861        }
2862
2863        st = strstr(en, "email=\"");
2864        if(st) {
2865                st += strlen("email=\"");
2866                en = strchr(st, '"'); *en++ = '\0';
2867                yab->email = yahoo_xmldecode(st);
2868        }
2869
2870        st = strstr(en, "hphone=\"");
2871        if(st) {
2872                st += strlen("hphone=\"");
2873                en = strchr(st, '"'); *en++ = '\0';
2874                yab->hphone = yahoo_xmldecode(st);
2875        }
2876
2877        st = strstr(en, "wphone=\"");
2878        if(st) {
2879                st += strlen("wphone=\"");
2880                en = strchr(st, '"'); *en++ = '\0';
2881                yab->wphone = yahoo_xmldecode(st);
2882        }
2883
2884        st = strstr(en, "mphone=\"");
2885        if(st) {
2886                st += strlen("mphone=\"");
2887                en = strchr(st, '"'); *en++ = '\0';
2888                yab->mphone = yahoo_xmldecode(st);
2889        }
2890
2891        st = strstr(en, "dbid=\"");
2892        if(st) {
2893                st += strlen("dbid=\"");
2894                en = strchr(st, '"'); *en++ = '\0';
2895                yab->dbid = atoi(st);
2896        }
2897}
2898
2899static struct yab * yahoo_getyab(struct yahoo_input_data *yid)
2900{
2901        struct yab *yab = NULL;
2902        int pos = 0, end=0;
2903        struct yahoo_data *yd = yid->yd;
2904
2905        if(!yd)
2906                return NULL;
2907
2908        DEBUG_MSG(("rxlen is %d", yid->rxlen));
2909
2910        if(yid->rxlen <= strlen("<record"))
2911                return NULL;
2912
2913        /* start with <record */
2914        while(pos < yid->rxlen-strlen("<record")+1 
2915                        && memcmp(yid->rxqueue + pos, "<record", strlen("<record")))
2916                pos++;
2917
2918        if(pos >= yid->rxlen-1)
2919                return NULL;
2920
2921        end = pos+2;
2922        /* end with /> */
2923        while(end < yid->rxlen-strlen("/>")+1 && memcmp(yid->rxqueue + end, "/>", strlen("/>")))
2924                end++;
2925
2926        if(end >= yid->rxlen-1)
2927                return NULL;
2928
2929        yab = y_new0(struct yab, 1);
2930        yahoo_yab_read(yab, yid->rxqueue + pos, end+2-pos);
2931       
2932
2933        yid->rxlen -= end+1;
2934        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2935        if (yid->rxlen>0) {
2936                unsigned char *tmp = y_memdup(yid->rxqueue + end + 1, yid->rxlen);
2937                FREE(yid->rxqueue);
2938                yid->rxqueue = tmp;
2939                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2940        } else {
2941                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
2942                FREE(yid->rxqueue);
2943        }
2944
2945
2946        return yab;
2947}
2948
2949static char * yahoo_getwebcam_master(struct yahoo_input_data *yid)
2950{
2951        unsigned int pos=0;
2952        unsigned int len=0;
2953        unsigned int status=0;
2954        char *server=NULL;
2955        struct yahoo_data *yd = yid->yd;
2956
2957        if(!yid || !yd)
2958                return NULL;
2959
2960        DEBUG_MSG(("rxlen is %d", yid->rxlen));
2961
2962        len = yid->rxqueue[pos++];
2963        if (yid->rxlen < len)
2964                return NULL;
2965
2966        /* extract status (0 = ok, 6 = webcam not online) */
2967        status = yid->rxqueue[pos++];
2968
2969        if (status == 0)
2970        {
2971                pos += 2; /* skip next 2 bytes */
2972                server =  y_memdup(yid->rxqueue+pos, 16);
2973                pos += 16;
2974        }
2975        else if (status == 6)
2976        {
2977                YAHOO_CALLBACK(ext_yahoo_webcam_closed)
2978                        (yd->client_id, yid->wcm->user, 4);
2979        }
2980
2981        /* skip rest of the data */
2982
2983        yid->rxlen -= len;
2984        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2985        if (yid->rxlen>0) {
2986                unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
2987                FREE(yid->rxqueue);
2988                yid->rxqueue = tmp;
2989                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
2990        } else {
2991                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
2992                FREE(yid->rxqueue);
2993        }
2994
2995        return server;
2996}
2997
2998static int yahoo_get_webcam_data(struct yahoo_input_data *yid)
2999{
3000        unsigned char reason=0;
3001        unsigned int pos=0;
3002        unsigned int begin=0;
3003        unsigned int end=0;
3004        unsigned int closed=0;
3005        unsigned char header_len=0;
3006        char *who;
3007        int connect=0;
3008        struct yahoo_data *yd = yid->yd;
3009
3010        if(!yd)
3011                return -1;
3012
3013        if(!yid->wcm || !yid->wcd || !yid->rxlen)
3014                return -1;
3015
3016        DEBUG_MSG(("rxlen is %d", yid->rxlen));
3017
3018        /* if we are not reading part of image then read header */
3019        if (!yid->wcd->to_read)
3020        {
3021                header_len=yid->rxqueue[pos++];
3022                yid->wcd->packet_type=0;
3023
3024                if (yid->rxlen < header_len)
3025                        return 0;
3026
3027                if (header_len >= 8)
3028                {
3029                        reason = yid->rxqueue[pos++];
3030                        /* next 2 bytes should always be 05 00 */
3031                        pos += 2;
3032                        yid->wcd->data_size = yahoo_get32(yid->rxqueue + pos);
3033                        pos += 4;
3034                        yid->wcd->to_read = yid->wcd->data_size;
3035                }
3036                if (header_len >= 13)
3037                {
3038                        yid->wcd->packet_type = yid->rxqueue[pos++];
3039                        yid->wcd->timestamp = yahoo_get32(yid->rxqueue + pos);
3040                        pos += 4;
3041                }
3042
3043                /* skip rest of header */
3044                pos = header_len;
3045        }
3046
3047        begin = pos;
3048        pos += yid->wcd->to_read;
3049        if (pos > yid->rxlen) pos = yid->rxlen;
3050
3051        /* if it is not an image then make sure we have the whole packet */
3052        if (yid->wcd->packet_type != 0x02) {
3053                if ((pos - begin) != yid->wcd->data_size) {
3054                        yid->wcd->to_read = 0;
3055                        return 0;
3056                } else {
3057                        yahoo_packet_dump(yid->rxqueue + begin, pos - begin);
3058                }
3059        }
3060
3061        DEBUG_MSG(("packet type %.2X, data length %d", yid->wcd->packet_type,
3062                yid->wcd->data_size));
3063
3064        /* find out what kind of packet we got */
3065        switch (yid->wcd->packet_type)
3066        {
3067                case 0x00:
3068                        /* user requests to view webcam (uploading) */
3069                        if (yid->wcd->data_size &&
3070                                yid->wcm->direction == YAHOO_WEBCAM_UPLOAD) {
3071                                end = begin;
3072                                while (end <= yid->rxlen &&
3073                                        yid->rxqueue[end++] != 13);
3074                                if (end > begin)
3075                                {
3076                                        who = y_memdup(yid->rxqueue + begin, end - begin);
3077                                        who[end - begin - 1] = 0;
3078                                        YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who + 2, 2);
3079                                        FREE(who);
3080                                }
3081                        }
3082
3083                        if (yid->wcm->direction == YAHOO_WEBCAM_DOWNLOAD) {
3084                                /* timestamp/status field */
3085                                /* 0 = declined viewing permission */
3086                                /* 1 = accepted viewing permission */
3087                                if (yid->wcd->timestamp == 0) {
3088                                        YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, 3);
3089                                }
3090                        }
3091                        break;
3092                case 0x01: /* status packets?? */
3093                        /* timestamp contains status info */
3094                        /* 00 00 00 01 = we have data?? */
3095                        break;
3096                case 0x02: /* image data */
3097                        YAHOO_CALLBACK(ext_yahoo_got_webcam_image)(yd->client_id, 
3098                                        yid->wcm->user, yid->rxqueue + begin,
3099                                        yid->wcd->data_size, pos - begin,
3100                                        yid->wcd->timestamp);
3101                        break;
3102                case 0x05: /* response packets when uploading */
3103                        if (!yid->wcd->data_size) {
3104                                YAHOO_CALLBACK(ext_yahoo_webcam_data_request)(yd->client_id, yid->wcd->timestamp);
3105                        }
3106                        break;
3107                case 0x07: /* connection is closing */
3108                        switch(reason)
3109                        {
3110                                case 0x01: /* user closed connection */
3111                                        closed = 1;
3112                                        break;
3113                                case 0x0F: /* user cancelled permission */
3114                                        closed = 2;
3115                                        break;
3116                        }
3117                        YAHOO_CALLBACK(ext_yahoo_webcam_closed)(yd->client_id, yid->wcm->user, closed);
3118                        break;
3119                case 0x0C: /* user connected */
3120                case 0x0D: /* user disconnected */
3121                        if (yid->wcd->data_size) {
3122                                who = y_memdup(yid->rxqueue + begin, pos - begin + 1);
3123                                who[pos - begin] = 0;
3124                                if (yid->wcd->packet_type == 0x0C)
3125                                        connect=1;
3126                                else
3127                                        connect=0;
3128                                YAHOO_CALLBACK(ext_yahoo_webcam_viewer)(yd->client_id, who, connect);
3129                                FREE(who);
3130                        }
3131                        break;
3132                case 0x13: /* user data */
3133                        /* i=user_ip (ip of the user we are viewing) */
3134                        /* j=user_ext_ip (external ip of the user we */
3135                        /*                are viewing) */
3136                        break;
3137                case 0x17: /* ?? */
3138                        break;
3139        }
3140        yid->wcd->to_read -= pos - begin;
3141
3142        yid->rxlen -= pos;
3143        DEBUG_MSG(("rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3144        if (yid->rxlen>0) {
3145                unsigned char *tmp = y_memdup(yid->rxqueue + pos, yid->rxlen);
3146                FREE(yid->rxqueue);
3147                yid->rxqueue = tmp;
3148                DEBUG_MSG(("new rxlen == %d, rxqueue == %p", yid->rxlen, yid->rxqueue));
3149        } else {
3150                DEBUG_MSG(("freed rxqueue == %p", yid->rxqueue));
3151                FREE(yid->rxqueue);
3152        }
3153
3154        /* If we read a complete packet return success */
3155        if (!yid->wcd->to_read)
3156                return 1;
3157
3158        return 0;
3159}
3160
3161int yahoo_write_ready(int id, int fd, void *data)
3162{
3163        struct yahoo_input_data *yid = data;
3164        int len;
3165        struct data_queue *tx;
3166
3167        LOG(("write callback: id=%d fd=%d data=%p", id, fd, data));
3168        if(!yid || !yid->txqueues)
3169                return -2;
3170       
3171        tx = yid->txqueues->data;
3172        LOG(("writing %d bytes", tx->len));
3173        len = yahoo_send_data(fd, tx->queue, MIN(1024, tx->len));
3174
3175        if(len == -1 && errno == EAGAIN)
3176                return 1;
3177
3178        if(len <= 0) {
3179                int e = errno;
3180                DEBUG_MSG(("len == %d (<= 0)", len));
3181                while(yid->txqueues) {
3182                        YList *l=yid->txqueues;
3183                        tx = l->data;
3184                        free(tx->queue);
3185                        free(tx);
3186                        yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
3187                        y_list_free_1(l);
3188                }
3189                LOG(("yahoo_write_ready(%d, %d) len < 0", id, fd));
3190                YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
3191                yid->write_tag = 0;
3192                errno=e;
3193                return 0;
3194        }
3195
3196
3197        tx->len -= len;
3198        if(tx->len > 0) {
3199                unsigned char *tmp = y_memdup(tx->queue + len, tx->len);
3200                FREE(tx->queue);
3201                tx->queue = tmp;
3202        } else {
3203                YList *l=yid->txqueues;
3204                free(tx->queue);
3205                free(tx);
3206                yid->txqueues = y_list_remove_link(yid->txqueues, yid->txqueues);
3207                y_list_free_1(l);
3208                /*
3209                if(!yid->txqueues)
3210                        LOG(("yahoo_write_ready(%d, %d) !yxqueues", id, fd));
3211                */
3212                if(!yid->txqueues) {
3213                        LOG(("yahoo_write_ready(%d, %d) !yxqueues", id, fd));
3214                        YAHOO_CALLBACK(ext_yahoo_remove_handler)(id, yid->write_tag);
3215                        yid->write_tag = 0;
3216                }
3217        }
3218
3219        return 1;
3220}
3221
3222static void yahoo_process_pager_connection(struct yahoo_input_data *yid, int over)
3223{
3224        struct yahoo_packet *pkt;
3225        struct yahoo_data *yd = yid->yd;
3226        int id = yd->client_id;
3227