source: protocols/yahoo/libyahoo2.c @ 7053379

Last change on this file since 7053379 was 7053379, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-12T23:02:29Z

Yahoo! status updates (at least initial ones, I assume) can be too long to
fit into one packet. Yahoo! servers will split them up, and not necessarily
on buddy boundaries. Trying to handle this a little bit better now. (Sadly
I can't test this myself, I can only see this causing troubles on testing
sometimes.)

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