source: protocols/yahoo/libyahoo2.c @ c36f73b

Last change on this file since c36f73b was c36f73b, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-23T14:35:45Z

This should mostly be a no-op, merging *loads* of whitespace changes from
libyahoo2 so that I can see better what really changed.

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