source: protocols/yahoo/libyahoo2.c @ a59bd11

Last change on this file since a59bd11 was e88fe7da, checked in by Veres Lajos <vlajos@…>, at 2015-08-07T21:53:25Z

typofix - https://github.com/vlajos/misspell_fixer

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