source: protocols/yahoo/libyahoo2.c @ 4fefb77

Last change on this file since 4fefb77 was 4fefb77, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-03T19:27:50Z

Yahoo! can log in again. This code still needs major cleanups, use it only
if you're very desparate.

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