source: protocols/yahoo/libyahoo2.c @ eb6df6a

Last change on this file since eb6df6a was 5f8ab6a9, checked in by Sven Moritz Hallberg <pesco@…>, at 2010-06-03T10:41:03Z

merge in bitlbee 1.2.5

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