source: protocols/yahoo/libyahoo2.c @ 9034ba0

Last change on this file since 9034ba0 was 9034ba0, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-24T10:57:08Z

Merge complete. It still logs in...

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