source: protocols/yahoo/libyahoo2.c @ eab8e52

Last change on this file since eab8e52 was 3cd37d7, checked in by Wilmer van der Gaast <wilmer@…>, at 2012-10-20T09:44:59Z

Cleaning up some more Yahoo! symbols.

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