source: protocols/yahoo/libyahoo2.c @ c8eeadd

Last change on this file since c8eeadd was 9fca0657, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-15T10:26:25Z

Deal with stupid (on first sight, at least) Yahoo! server behaviour causing
double free()s on testing ATM. Apparently it's perfectly legal to give buddy
information with an "end buddy" marker but no "begin buddy".

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