source: protocols/yahoo/libyahoo2.c @ e71cfbc

Last change on this file since e71cfbc was e71cfbc, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-13T22:33:12Z

Turns out I *did* implement HTTPS auth for Yahoo! myself already, but I
kept it as a patch somewhere in my homedir because I thought I didn't
need it. I like this code more so I'll use it instead.

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