source: protocols/yahoo/libyahoo2.c @ 7ea8697

Last change on this file since 7ea8697 was 7ea8697, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-10T15:00:16Z

Setting Yahoo! away states works again.

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