source: protocols/yahoo/libyahoo2.c @ 58d285a

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

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

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