source: protocols/yahoo/libyahoo2.c @ 547c94c

Last change on this file since 547c94c was 547c94c, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-12T22:32:55Z

Merging in some code from libyahoo2-trunk that deals better with (initial)
status updates and cleans up some stale stuff.

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