source: protocols/yahoo/libyahoo2.c @ b38d399

Last change on this file since b38d399 was b38d399, checked in by dequis <dx@…>, at 2014-11-24T05:16:09Z

Use glib functions for base64 decoding/encoding

This fixes several coverity warnings about 'tainted data index sink' and
a fixme about thread safety in the old base64_decode implementation.

Had to adapt the code that used base64_encode_real:

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