comparison src/protocols/oscar/oscar.c @ 2086:424a40f12a6c

[gaim-migrate @ 2096] moving protocols from plugins/ to src/protocols. making it so that you can select which protocols are compiled statically. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Tue, 31 Jul 2001 01:00:39 +0000
parents
children b66aca8e8dce
comparison
equal deleted inserted replaced
2085:7ebb4322f89b 2086:424a40f12a6c
1 /*
2 * gaim
3 *
4 * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
5 * libfaim code copyright 1998, 1999 Adam Fritzler <afritz@auk.cx>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "../config.h"
25 #endif
26
27
28 #include <netdb.h>
29 #include <gtk/gtk.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <time.h>
38 #include <sys/socket.h>
39 #include <sys/stat.h>
40 #include "multi.h"
41 #include "prpl.h"
42 #include "gaim.h"
43 #include "aim.h"
44 #include "proxy.h"
45
46 #if USE_PIXBUF
47 #include <gdk-pixbuf/gdk-pixbuf.h>
48 #include <gdk-pixbuf/gdk-pixbuf-loader.h>
49 #endif
50
51 /*#include "pixmaps/cancel.xpm"*/
52 #include "pixmaps/admin_icon.xpm"
53 #include "pixmaps/aol_icon.xpm"
54 #include "pixmaps/away_icon.xpm"
55 #include "pixmaps/dt_icon.xpm"
56 #include "pixmaps/free_icon.xpm"
57
58 /* constants to identify proto_opts */
59 #define USEROPT_AUTH 0
60 #define USEROPT_AUTHPORT 1
61
62 #define AIMHASHDATA "http://gaim.sourceforge.net/aim_data.php3"
63
64 static int gaim_caps = AIM_CAPS_CHAT |
65 #if USE_PIXBUF
66 AIM_CAPS_BUDDYICON |
67 #endif
68 AIM_CAPS_GETFILE |
69 AIM_CAPS_IMIMAGE;
70
71 static GtkWidget *join_chat_spin = NULL;
72 static GtkWidget *join_chat_entry = NULL;
73
74 struct oscar_data {
75 struct aim_session_t *sess;
76 struct aim_conn_t *conn;
77
78 guint cnpa;
79 guint paspa;
80
81 int create_exchange;
82 char *create_name;
83
84 gboolean conf;
85 gboolean reqemail;
86 gboolean chpass;
87 char *oldp;
88 char *newp;
89
90 GSList *oscar_chats;
91 GSList *direct_ims;
92 GSList *getfiles;
93 GSList *hasicons;
94
95 gboolean killme;
96 };
97
98 struct chat_connection {
99 char *name;
100 char *show; /* AOL did something funny to us */
101 int exchange;
102 int fd; /* this is redundant since we have the conn below */
103 struct aim_conn_t *conn;
104 int inpa;
105 int id;
106 struct gaim_connection *gc; /* i hate this. */
107 struct conversation *cnv; /* bah. */
108 };
109
110 struct direct_im {
111 struct gaim_connection *gc;
112 char name[80];
113 struct conversation *cnv;
114 int watcher;
115 struct aim_conn_t *conn;
116 };
117
118 struct ask_direct {
119 struct gaim_connection *gc;
120 char *sn;
121 struct aim_directim_priv *priv;
122 };
123
124 struct ask_getfile {
125 struct gaim_connection *gc;
126 char *sn;
127 char *cookie;
128 char *ip;
129 };
130
131 struct getfile_transfer {
132 struct gaim_connection *gc;
133 char *receiver;
134 char *filename;
135 struct aim_conn_t *conn;
136 struct aim_fileheader_t *fh;
137 int gip;
138 int gop;
139 FILE *listing;
140 FILE *file;
141 GtkWidget *window;
142 GtkWidget *meter;
143 GtkWidget *label;
144 long pos;
145 long size;
146 };
147
148 #if USE_PIXBUF
149 struct icon_req {
150 char *user;
151 time_t timestamp;
152 unsigned long length;
153 gpointer data;
154 gboolean request;
155 GdkPixbufAnimation *anim;
156 GdkPixbuf *unanim;
157 struct conversation *cnv;
158 GtkWidget *pix;
159 int curframe;
160 int timer;
161 };
162 #endif
163
164 static struct direct_im *find_direct_im(struct oscar_data *od, char *who) {
165 GSList *d = od->direct_ims;
166 char *n = g_strdup(normalize(who));
167 struct direct_im *m = NULL;
168
169 while (d) {
170 m = (struct direct_im *)d->data;
171 if (!strcmp(n, normalize(m->name)))
172 break;
173 m = NULL;
174 d = d->next;
175 }
176
177 g_free(n);
178 return m;
179 }
180
181 /*
182 static struct getfile_transfer *find_getfile_transfer(struct oscar_data *od, struct aim_conn_t *conn) {
183 GSList *g = od->getfiles;
184 struct getfile_transfer *n = NULL;
185
186 while (g) {
187 n = (struct getfile_transfer *)g->data;
188 if (n->conn == conn)
189 return n;
190 n = NULL;
191 g = g->next;
192 }
193
194 return n;
195 }
196 */
197
198 static char *extract_name(char *name) {
199 char *tmp;
200 int i, j;
201 char *x = strchr(name, '-');
202 if (!x) return NULL;
203 x = strchr(++x, '-');
204 if (!x) return NULL;
205 tmp = g_strdup(++x);
206
207 for (i = 0, j = 0; x[i]; i++) {
208 if (x[i] != '%')
209 tmp[j++] = x[i];
210 else {
211 char hex[3];
212 hex[0] = x[++i];
213 hex[1] = x[++i];
214 hex[2] = 0;
215 sscanf(hex, "%x", (int *)&tmp[j++]);
216 }
217 }
218
219 tmp[j] = 0;
220 return tmp;
221 }
222
223 static struct chat_connection *find_oscar_chat(struct gaim_connection *gc, int id) {
224 GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
225 struct chat_connection *c = NULL;
226 if (gc->protocol != PROTO_OSCAR) return NULL;
227
228 while (g) {
229 c = (struct chat_connection *)g->data;
230 if (c->id == id)
231 break;
232 g = g->next;
233 c = NULL;
234 }
235
236 return c;
237 }
238
239 static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc,
240 struct aim_conn_t *conn) {
241 GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
242 struct chat_connection *c = NULL;
243
244 while (g) {
245 c = (struct chat_connection *)g->data;
246 if (c->conn == conn)
247 break;
248 g = g->next;
249 c = NULL;
250 }
251
252 return c;
253 }
254
255 static int gaim_parse_auth_resp (struct aim_session_t *, struct command_rx_struct *, ...);
256 static int gaim_parse_login (struct aim_session_t *, struct command_rx_struct *, ...);
257 static int gaim_server_ready (struct aim_session_t *, struct command_rx_struct *, ...);
258 static int gaim_handle_redirect (struct aim_session_t *, struct command_rx_struct *, ...);
259 static int gaim_info_change (struct aim_session_t *, struct command_rx_struct *, ...);
260 static int gaim_account_confirm (struct aim_session_t *, struct command_rx_struct *, ...);
261 static int gaim_parse_oncoming (struct aim_session_t *, struct command_rx_struct *, ...);
262 static int gaim_parse_offgoing (struct aim_session_t *, struct command_rx_struct *, ...);
263 static int gaim_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *, ...);
264 static int gaim_parse_misses (struct aim_session_t *, struct command_rx_struct *, ...);
265 static int gaim_parse_user_info (struct aim_session_t *, struct command_rx_struct *, ...);
266 static int gaim_parse_motd (struct aim_session_t *, struct command_rx_struct *, ...);
267 static int gaim_chatnav_info (struct aim_session_t *, struct command_rx_struct *, ...);
268 static int gaim_chat_join (struct aim_session_t *, struct command_rx_struct *, ...);
269 static int gaim_chat_leave (struct aim_session_t *, struct command_rx_struct *, ...);
270 static int gaim_chat_info_update (struct aim_session_t *, struct command_rx_struct *, ...);
271 static int gaim_chat_incoming_msg(struct aim_session_t *, struct command_rx_struct *, ...);
272 static int gaim_parse_msgack (struct aim_session_t *, struct command_rx_struct *, ...);
273 static int gaim_parse_ratechange (struct aim_session_t *, struct command_rx_struct *, ...);
274 static int gaim_parse_evilnotify (struct aim_session_t *, struct command_rx_struct *, ...);
275 static int gaim_parse_searcherror(struct aim_session_t *, struct command_rx_struct *, ...);
276 static int gaim_parse_searchreply(struct aim_session_t *, struct command_rx_struct *, ...);
277 static int gaim_bosrights (struct aim_session_t *, struct command_rx_struct *, ...);
278 static int gaim_rateresp (struct aim_session_t *, struct command_rx_struct *, ...);
279 static int gaim_reportinterval (struct aim_session_t *, struct command_rx_struct *, ...);
280 static int gaim_parse_msgerr (struct aim_session_t *, struct command_rx_struct *, ...);
281 static int gaim_parse_buddyrights(struct aim_session_t *, struct command_rx_struct *, ...);
282 static int gaim_parse_locerr (struct aim_session_t *, struct command_rx_struct *, ...);
283 static int gaim_parse_genericerr (struct aim_session_t *, struct command_rx_struct *, ...);
284 static int gaim_memrequest (struct aim_session_t *, struct command_rx_struct *, ...);
285
286 static int gaim_directim_initiate (struct aim_session_t *, struct command_rx_struct *, ...);
287 static int gaim_directim_incoming (struct aim_session_t *, struct command_rx_struct *, ...);
288 static int gaim_directim_disconnect(struct aim_session_t *, struct command_rx_struct *, ...);
289 static int gaim_directim_typing (struct aim_session_t *, struct command_rx_struct *, ...);
290
291 static char *msgerrreason[] = {
292 "Invalid error",
293 "Invalid SNAC",
294 "Rate to host",
295 "Rate to client",
296 "Not logged in",
297 "Service unavailable",
298 "Service not defined",
299 "Obsolete SNAC",
300 "Not supported by host",
301 "Not supported by client",
302 "Refused by client",
303 "Reply too big",
304 "Responses lost",
305 "Request denied",
306 "Busted SNAC payload",
307 "Insufficient rights",
308 "In local permit/deny",
309 "Too evil (sender)",
310 "Too evil (receiver)",
311 "User temporarily unavailable",
312 "No match",
313 "List overflow",
314 "Request ambiguous",
315 "Queue full",
316 "Not while on AOL"
317 };
318 static int msgerrreasonlen = 25;
319
320 static void oscar_callback(gpointer data, gint source,
321 GdkInputCondition condition) {
322 struct aim_conn_t *conn = (struct aim_conn_t *)data;
323 struct aim_session_t *sess = aim_conn_getsess(conn);
324 struct gaim_connection *gc = sess ? sess->aux_data : NULL;
325 struct oscar_data *odata;
326
327 if (!gc) {
328 /* gc is null. we return, else we seg SIGSEG on next line. */
329 debug_printf("oscar callback for closed connection (1).\n");
330 return;
331 }
332
333 odata = (struct oscar_data *)gc->proto_data;
334
335 if (!g_slist_find(connections, gc)) {
336 /* oh boy. this is probably bad. i guess the only thing we
337 * can really do is return? */
338 debug_printf("oscar callback for closed connection (2).\n");
339 return;
340 }
341
342 if (condition & GDK_INPUT_EXCEPTION) {
343 hide_login_progress(gc, _("Disconnected."));
344 signoff(gc);
345 return;
346 }
347 if (condition & GDK_INPUT_READ) {
348 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
349 debug_printf("got information on rendezvous\n");
350 if (aim_handlerendconnect(odata->sess, conn) < 0) {
351 debug_printf(_("connection error (rend)\n"));
352 }
353 } else {
354 if (aim_get_command(odata->sess, conn) >= 0) {
355 aim_rxdispatch(odata->sess);
356 if (odata->killme)
357 signoff(gc);
358 } else {
359 if ((conn->type == AIM_CONN_TYPE_BOS) ||
360 !(aim_getconn_type(odata->sess, AIM_CONN_TYPE_BOS))) {
361 debug_printf(_("major connection error\n"));
362 hide_login_progress(gc, _("Disconnected."));
363 signoff(gc);
364 } else if (conn->type == AIM_CONN_TYPE_CHAT) {
365 struct chat_connection *c = find_oscar_chat_by_conn(gc, conn);
366 char buf[BUF_LONG];
367 debug_printf("disconnected from chat room %s\n", c->name);
368 c->conn = NULL;
369 if (c->inpa > 0)
370 gdk_input_remove(c->inpa);
371 c->inpa = 0;
372 c->fd = -1;
373 aim_conn_kill(odata->sess, &conn);
374 sprintf(buf, _("You have been disconnected from chat room %s."), c->name);
375 do_error_dialog(buf, _("Chat Error!"));
376 } else if (conn->type == AIM_CONN_TYPE_CHATNAV) {
377 if (odata->cnpa > 0)
378 gdk_input_remove(odata->cnpa);
379 odata->cnpa = 0;
380 debug_printf("removing chatnav input watcher\n");
381 if (odata->create_exchange) {
382 odata->create_exchange = 0;
383 g_free(odata->create_name);
384 odata->create_name = NULL;
385 do_error_dialog(_("Chat is currently unavailable"),
386 _("Gaim - Chat"));
387 }
388 aim_conn_kill(odata->sess, &conn);
389 } else if (conn->type == AIM_CONN_TYPE_AUTH) {
390 if (odata->paspa > 0)
391 gdk_input_remove(odata->paspa);
392 odata->paspa = 0;
393 debug_printf("removing authconn input watcher\n");
394 aim_conn_kill(odata->sess, &conn);
395 } else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
396 debug_printf("No handler for rendezvous disconnect (%d).\n",
397 source);
398 aim_conn_kill(odata->sess, &conn);
399 } else {
400 debug_printf("holy crap! generic connection error! %d\n",
401 conn->type);
402 aim_conn_kill(odata->sess, &conn);
403 }
404 }
405 }
406 }
407 }
408
409 static void oscar_debug(struct aim_session_t *sess, int level, const char *format, va_list va) {
410 char *s = g_strdup_vprintf(format, va);
411 char buf[256];
412 char *t;
413 struct gaim_connection *gc = sess->aux_data;
414
415 g_snprintf(buf, sizeof(buf), "%s %d: ", gc->username, level);
416 t = g_strconcat(buf, s, NULL);
417 debug_printf(t);
418 if (t[strlen(t)-1] != '\n')
419 debug_printf("\n");
420 g_free(t);
421 g_free(s);
422 }
423
424 static void oscar_login_connect(gpointer data, gint source, GdkInputCondition cond)
425 {
426 struct gaim_connection *gc = data;
427 struct oscar_data *odata;
428 struct aim_session_t *sess;
429 struct aim_conn_t *conn;
430
431 if (!g_slist_find(connections, gc)) {
432 close(source);
433 return;
434 }
435
436 odata = gc->proto_data;
437 sess = odata->sess;
438 conn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH);
439
440 if (source < 0) {
441 hide_login_progress(gc, _("Couldn't connect to host"));
442 signoff(gc);
443 return;
444 }
445
446 aim_conn_completeconnect(sess, conn);
447 gc->inpa = gdk_input_add(conn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
448 oscar_callback, conn);
449 debug_printf(_("Password sent, waiting for response\n"));
450 }
451
452 static void oscar_login(struct aim_user *user) {
453 struct aim_session_t *sess;
454 struct aim_conn_t *conn;
455 char buf[256];
456 struct gaim_connection *gc = new_gaim_conn(user);
457 struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1);
458 odata->create_exchange = 0;
459
460 debug_printf(_("Logging in %s\n"), user->username);
461
462 sess = g_new0(struct aim_session_t, 1);
463
464 aim_session_init(sess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 0);
465 aim_setdebuggingcb(sess, oscar_debug);
466
467 /* we need an immediate queue because we don't use a while-loop to
468 * see if things need to be sent. */
469 aim_tx_setenqueue(sess, AIM_TX_IMMEDIATE, NULL);
470 odata->sess = sess;
471 sess->aux_data = gc;
472
473 conn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL);
474 if (conn == NULL) {
475 debug_printf(_("internal connection error\n"));
476 hide_login_progress(gc, _("Unable to login to AIM"));
477 signoff(gc);
478 return;
479 }
480
481 g_snprintf(buf, sizeof(buf), _("Signon: %s"), gc->username);
482 set_login_progress(gc, 2, buf);
483
484 aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0);
485 aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0);
486
487 conn->status |= AIM_CONN_STATUS_INPROGRESS;
488 conn->fd = proxy_connect(user->proto_opt[USEROPT_AUTH][0] ?
489 user->proto_opt[USEROPT_AUTH] : FAIM_LOGIN_SERVER,
490 user->proto_opt[USEROPT_AUTHPORT][0] ?
491 atoi(user->proto_opt[USEROPT_AUTHPORT]) : FAIM_LOGIN_PORT,
492 oscar_login_connect, gc);
493 if (conn->fd < 0) {
494 hide_login_progress(gc, _("Couldn't connect to host"));
495 signoff(gc);
496 return;
497 }
498 aim_request_login(sess, conn, gc->username);
499 }
500
501 static void oscar_close(struct gaim_connection *gc) {
502 struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
503 if (gc->protocol != PROTO_OSCAR) return;
504
505 while (odata->oscar_chats) {
506 struct chat_connection *n = odata->oscar_chats->data;
507 if (n->inpa > 0)
508 gdk_input_remove(n->inpa);
509 g_free(n->name);
510 g_free(n->show);
511 odata->oscar_chats = g_slist_remove(odata->oscar_chats, n);
512 g_free(n);
513 }
514 while (odata->direct_ims) {
515 struct direct_im *n = odata->direct_ims->data;
516 if (n->watcher > 0)
517 gdk_input_remove(n->watcher);
518 odata->direct_ims = g_slist_remove(odata->direct_ims, n);
519 g_free(n);
520 }
521 #if USE_PIXBUF
522 while (odata->hasicons) {
523 struct icon_req *n = odata->hasicons->data;
524 if (n->anim)
525 gdk_pixbuf_animation_unref(n->anim);
526 if (n->unanim)
527 gdk_pixbuf_unref(n->unanim);
528 if (n->timer)
529 gtk_timeout_remove(n->timer);
530 if (n->cnv && n->pix)
531 gtk_container_remove(GTK_CONTAINER(n->cnv->bbox), n->pix);
532 g_free(n->user);
533 if (n->data)
534 g_free(n->data);
535 odata->hasicons = g_slist_remove(odata->hasicons, n);
536 g_free(n);
537 }
538 #endif
539 if (gc->inpa > 0)
540 gdk_input_remove(gc->inpa);
541 if (odata->cnpa > 0)
542 gdk_input_remove(odata->cnpa);
543 if (odata->paspa > 0)
544 gdk_input_remove(odata->paspa);
545 aim_session_kill(odata->sess);
546 g_free(odata->sess);
547 odata->sess = NULL;
548 g_free(gc->proto_data);
549 gc->proto_data = NULL;
550 debug_printf(_("Signed off.\n"));
551 }
552
553 static void oscar_bos_connect(gpointer data, gint source, GdkInputCondition cond) {
554 struct gaim_connection *gc = data;
555 struct oscar_data *odata;
556 struct aim_session_t *sess;
557 struct aim_conn_t *bosconn;
558
559 if (!g_slist_find(connections, gc)) {
560 close(source);
561 return;
562 }
563
564 odata = gc->proto_data;
565 sess = odata->sess;
566 bosconn = odata->conn;
567
568 if (source < 0) {
569 hide_login_progress(gc, _("Could Not Connect"));
570 signoff(gc);
571 return;
572 }
573
574 aim_conn_completeconnect(sess, bosconn);
575 gc->inpa = gdk_input_add(bosconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
576 oscar_callback, bosconn);
577 set_login_progress(gc, 4, _("Connection established, cookie sent"));
578 }
579
580 int gaim_parse_auth_resp(struct aim_session_t *sess,
581 struct command_rx_struct *command, ...) {
582 va_list ap;
583 struct aim_conn_t *bosconn = NULL;
584 char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL;
585 unsigned char *cookie = NULL;
586 int errorcode = 0, regstatus = 0;
587 int latestbuild = 0, latestbetabuild = 0;
588 char *latestrelease = NULL, *latestbeta = NULL;
589 char *latestreleaseurl = NULL, *latestbetaurl = NULL;
590 char *latestreleaseinfo = NULL, *latestbetainfo = NULL;
591 int i; char *host; int port;
592 struct aim_user *user;
593
594 struct gaim_connection *gc = sess->aux_data;
595 struct oscar_data *od = gc->proto_data;
596 user = gc->user;
597 port = user->proto_opt[USEROPT_AUTHPORT][0] ?
598 atoi(user->proto_opt[USEROPT_AUTHPORT]) : FAIM_LOGIN_PORT,
599
600 va_start(ap, command);
601 sn = va_arg(ap, char *);
602 errorcode = va_arg(ap, int);
603 errurl = va_arg(ap, char *);
604 regstatus = va_arg(ap, int);
605 email = va_arg(ap, char *);
606 bosip = va_arg(ap, char *);
607 cookie = va_arg(ap, unsigned char *);
608
609 latestrelease = va_arg(ap, char *);
610 latestbuild = va_arg(ap, int);
611 latestreleaseurl = va_arg(ap, char *);
612 latestreleaseinfo = va_arg(ap, char *);
613
614 latestbeta = va_arg(ap, char *);
615 latestbetabuild = va_arg(ap, int);
616 latestbetaurl = va_arg(ap, char *);
617 latestbetainfo = va_arg(ap, char *);
618
619 va_end(ap);
620
621 debug_printf("inside auth_resp (Screen name: %s)\n", sn);
622
623 if (errorcode || !bosip || !cookie) {
624 switch (errorcode) {
625 case 0x05:
626 /* Incorrect nick/password */
627 hide_login_progress(gc, _("Incorrect nickname or password."));
628 plugin_event(event_error, (void *)980, 0, 0, 0);
629 break;
630 case 0x11:
631 /* Suspended account */
632 hide_login_progress(gc, _("Your account is currently suspended."));
633 break;
634 case 0x18:
635 /* connecting too frequently */
636 hide_login_progress(gc, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
637 plugin_event(event_error, (void *)983, 0, 0, 0);
638 break;
639 case 0x1c:
640 /* client too old */
641 hide_login_progress(gc, _("The client version you are using is too old. Please upgrade at " WEBSITE));
642 plugin_event(event_error, (void *)989, 0, 0, 0);
643 break;
644 default:
645 hide_login_progress(gc, _("Authentication Failed"));
646 break;
647 }
648 debug_printf("Login Error Code 0x%04x\n", errorcode);
649 debug_printf("Error URL: %s\n", errurl);
650 od->killme = TRUE;
651 return 1;
652 }
653
654
655 debug_printf("Reg status: %2d\n", regstatus);
656 if (email) {
657 debug_printf("Email: %s\n", email);
658 } else {
659 debug_printf("Email is NULL\n");
660 }
661 debug_printf("BOSIP: %s\n", bosip);
662 if (latestbeta)
663 debug_printf("Latest WinAIM beta version %s, build %d, at %s (%s)\n",
664 latestbeta, latestbetabuild, latestbetaurl, latestbetainfo);
665 if (latestrelease)
666 debug_printf("Latest WinAIM released version %s, build %d, at %s (%s)\n",
667 latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo);
668 debug_printf("Closing auth connection...\n");
669 aim_conn_kill(sess, &command->conn);
670
671 bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, NULL);
672 if (bosconn == NULL) {
673 hide_login_progress(gc, _("Internal Error"));
674 od->killme = TRUE;
675 return 0;
676 }
677
678 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, gaim_bosrights, 0);
679 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, gaim_rateresp, 0); /* rate info */
680 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0);
681 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, gaim_server_ready, 0);
682 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
683 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, gaim_handle_redirect, 0);
684 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, gaim_reportinterval, 0);
685 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, gaim_parse_buddyrights, 0);
686 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, gaim_parse_oncoming, 0);
687 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, gaim_parse_offgoing, 0);
688 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, gaim_parse_incoming_im, 0);
689 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, gaim_parse_locerr, 0);
690 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, gaim_parse_misses, 0);
691 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, gaim_parse_ratechange, 0);
692 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, gaim_parse_evilnotify, 0);
693 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOK, AIM_CB_LOK_ERROR, gaim_parse_searcherror, 0);
694 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOK, 0x0003, gaim_parse_searchreply, 0);
695 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, gaim_parse_msgerr, 0);
696 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parse_user_info, 0);
697 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, gaim_parse_msgack, 0);
698 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, gaim_parse_motd, 0);
699 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, gaim_parse_genericerr, 0);
700 aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, gaim_parse_genericerr, 0);
701 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, gaim_parse_genericerr, 0);
702 aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, gaim_memrequest, 0);
703
704 ((struct oscar_data *)gc->proto_data)->conn = bosconn;
705 for (i = 0; i < (int)strlen(bosip); i++) {
706 if (bosip[i] == ':') {
707 port = atoi(&(bosip[i+1]));
708 break;
709 }
710 }
711 host = g_strndup(bosip, i);
712 bosconn->status |= AIM_CONN_STATUS_INPROGRESS;
713 bosconn->fd = proxy_connect(host, port, oscar_bos_connect, gc);
714 g_free(host);
715 if (bosconn->fd < 0) {
716 hide_login_progress(gc, _("Could Not Connect"));
717 od->killme = TRUE;
718 return 0;
719 }
720 aim_auth_sendcookie(sess, bosconn, cookie);
721 gdk_input_remove(gc->inpa);
722 return 1;
723 }
724
725 struct pieceofcrap {
726 struct gaim_connection *gc;
727 unsigned long offset;
728 unsigned long len;
729 char *modname;
730 int fd;
731 struct aim_conn_t *conn;
732 unsigned int inpa;
733 };
734
735 static void damn_you(gpointer data, gint source, GdkInputCondition c)
736 {
737 struct pieceofcrap *pos = data;
738 struct oscar_data *od = pos->gc->proto_data;
739 char in = '\0';
740 int x = 0;
741 unsigned char m[17];
742
743 while (read(pos->fd, &in, 1) == 1) {
744 if (in == '\n')
745 x++;
746 else if (in != '\r')
747 x = 0;
748 if (x == 2)
749 break;
750 in = '\0';
751 }
752 if (in != '\n') {
753 do_error_dialog("Gaim was unable to get a valid hash for logging into AIM."
754 " You may be disconnected shortly.", "Login Error");
755 gdk_input_remove(pos->inpa);
756 close(pos->fd);
757 g_free(pos);
758 return;
759 }
760 read(pos->fd, m, 16);
761 m[16] = '\0';
762 debug_printf("Sending hash: ");
763 for (x = 0; x < 16; x++)
764 debug_printf("%02x ", (unsigned char)m[x]);
765 debug_printf("\n");
766 gdk_input_remove(pos->inpa);
767 close(pos->fd);
768 aim_sendmemblock(od->sess, pos->conn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH);
769 g_free(pos);
770 }
771
772 static void straight_to_hell(gpointer data, gint source, GdkInputCondition cond) {
773 struct pieceofcrap *pos = data;
774 char buf[BUF_LONG];
775
776 if (source < 0) {
777 do_error_dialog("Gaim was unable to get a valid hash for logging into AIM."
778 " You may be disconnected shortly.", "Login Error");
779 if (pos->modname)
780 g_free(pos->modname);
781 g_free(pos);
782 return;
783 }
784
785 g_snprintf(buf, sizeof(buf), "GET " AIMHASHDATA
786 "?offset=%ld&len=%ld&modname=%s HTTP/1.0\n\n",
787 pos->offset, pos->len, pos->modname ? pos->modname : "");
788 write(pos->fd, buf, strlen(buf));
789 if (pos->modname)
790 g_free(pos->modname);
791 pos->inpa = gdk_input_add(pos->fd, GDK_INPUT_READ, damn_you, pos);
792 return;
793 }
794
795 /* size of icbmui.ocm, the largest module in AIM 3.5 */
796 #define AIM_MAX_FILE_SIZE 98304
797
798 int gaim_memrequest(struct aim_session_t *sess,
799 struct command_rx_struct *command, ...) {
800 va_list ap;
801 struct pieceofcrap *pos;
802 unsigned long offset, len;
803 char *modname;
804 int fd;
805
806 va_start(ap, command);
807 offset = va_arg(ap, unsigned long);
808 len = va_arg(ap, unsigned long);
809 modname = va_arg(ap, char *);
810 va_end(ap);
811
812 debug_printf("offset: %d, len: %d, file: %s\n", offset, len, modname ? modname : "aim.exe");
813 if (len == 0) {
814 debug_printf("len is 0, hashing NULL\n");
815 aim_sendmemblock(sess, command->conn, offset, len, NULL,
816 AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
817 return 1;
818 }
819 /* uncomment this when you're convinced it's right. remember, it's been wrong before.
820 if (offset > AIM_MAX_FILE_SIZE || len > AIM_MAX_FILE_SIZE) {
821 char *buf;
822 int i = 8;
823 if (modname)
824 i += strlen(modname);
825 buf = g_malloc(i);
826 i = 0;
827 if (modname) {
828 memcpy(buf, modname, strlen(modname));
829 i += strlen(modname);
830 }
831 buf[i++] = offset & 0xff;
832 buf[i++] = (offset >> 8) & 0xff;
833 buf[i++] = (offset >> 16) & 0xff;
834 buf[i++] = (offset >> 24) & 0xff;
835 buf[i++] = len & 0xff;
836 buf[i++] = (len >> 8) & 0xff;
837 buf[i++] = (len >> 16) & 0xff;
838 buf[i++] = (len >> 24) & 0xff;
839 debug_printf("len + offset is invalid, hashing request\n");
840 aim_sendmemblock(sess, command->conn, offset, i, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
841 g_free(buf);
842 return 1;
843 }
844 */
845
846 pos = g_new0(struct pieceofcrap, 1);
847 pos->gc = sess->aux_data;
848 pos->conn = command->conn;
849
850 pos->offset = offset;
851 pos->len = len;
852 pos->modname = modname ? g_strdup(modname) : NULL;
853
854 fd = proxy_connect("gaim.sourceforge.net", 80, straight_to_hell, pos);
855 if (fd < 0) {
856 if (pos->modname)
857 g_free(pos->modname);
858 g_free(pos);
859 do_error_dialog("Gaim was unable to get a valid hash for logging into AIM."
860 " You may be disconnected shortly.", "Login Error");
861 }
862 pos->fd = fd;
863
864 return 1;
865 }
866
867 int gaim_parse_login(struct aim_session_t *sess,
868 struct command_rx_struct *command, ...) {
869 #if 0
870 struct client_info_s info = {"gaim", 4, 1, 2010, "us", "en", 0x0004, 0x0000, 0x04b};
871 #else
872 struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD;
873 #endif
874 char *key;
875 va_list ap;
876 struct gaim_connection *gc = sess->aux_data;
877
878 va_start(ap, command);
879 key = va_arg(ap, char *);
880 va_end(ap);
881
882 aim_send_login(sess, command->conn, gc->username, gc->password, &info, key);
883 return 1;
884 }
885
886 int gaim_server_ready(struct aim_session_t *sess,
887 struct command_rx_struct *command, ...) {
888 static int id = 1;
889 struct gaim_connection *gc = sess->aux_data;
890 struct oscar_data *od = gc->proto_data;
891 struct chat_connection *chatcon;
892 switch (command->conn->type) {
893 case AIM_CONN_TYPE_AUTH:
894 aim_auth_setversions(sess, command->conn);
895 aim_bos_reqrate(sess, command->conn);
896 debug_printf("done with AUTH ServerReady\n");
897 if (od->chpass) {
898 debug_printf("changing password\n");
899 aim_auth_changepasswd(sess, command->conn, od->newp, od->oldp);
900 g_free(od->oldp);
901 g_free(od->newp);
902 od->chpass = FALSE;
903 }
904 if (od->conf) {
905 debug_printf("confirming account\n");
906 aim_auth_reqconfirm(sess, command->conn);
907 od->conf = FALSE;
908 }
909 if (od->reqemail) {
910 debug_printf("requesting email\n");
911 aim_auth_getinfo(sess, command->conn, 0x0011);
912 od->reqemail = FALSE;
913 }
914 break;
915 case AIM_CONN_TYPE_BOS:
916 aim_setversions(sess, command->conn);
917 aim_bos_reqrate(sess, command->conn); /* request rate info */
918 debug_printf("done with BOS ServerReady\n");
919 break;
920 case AIM_CONN_TYPE_CHATNAV:
921 debug_printf("chatnav: got server ready\n");
922 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, gaim_chatnav_info, 0);
923 aim_bos_reqrate(sess, command->conn);
924 aim_bos_ackrateresp(sess, command->conn);
925 aim_chatnav_clientready(sess, command->conn);
926 aim_chatnav_reqrights(sess, command->conn);
927 break;
928 case AIM_CONN_TYPE_CHAT:
929 debug_printf("chat: got server ready\n");
930 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, gaim_chat_join, 0);
931 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, gaim_chat_leave, 0);
932 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, gaim_chat_info_update, 0);
933 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, gaim_chat_incoming_msg, 0);
934 aim_bos_reqrate(sess, command->conn);
935 aim_bos_ackrateresp(sess, command->conn);
936 aim_chat_clientready(sess, command->conn);
937 chatcon = find_oscar_chat_by_conn(gc, command->conn);
938 chatcon->id = id;
939 chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show);
940 break;
941 case AIM_CONN_TYPE_RENDEZVOUS:
942 break;
943 default: /* huh? */
944 debug_printf("server ready: got unexpected connection type %04x\n", command->conn->type);
945 break;
946 }
947 return 1;
948 }
949
950 static void oscar_chatnav_connect(gpointer data, gint source, GdkInputCondition cond)
951 {
952 struct gaim_connection *gc = data;
953 struct oscar_data *odata;
954 struct aim_session_t *sess;
955 struct aim_conn_t *tstconn;
956
957 if (!g_slist_find(connections, gc)) {
958 close(source);
959 return;
960 }
961
962 odata = gc->proto_data;
963 sess = odata->sess;
964 tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_CHATNAV);
965
966 if (source < 0) {
967 aim_conn_kill(sess, &tstconn);
968 debug_printf("unable to connect to chatnav server\n");
969 return;
970 }
971
972 aim_conn_completeconnect(sess, tstconn);
973 odata->cnpa = gdk_input_add(tstconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
974 oscar_callback, tstconn);
975 debug_printf("chatnav: connected\n");
976 }
977
978 static void oscar_auth_connect(gpointer data, gint source, GdkInputCondition cond)
979 {
980 struct gaim_connection *gc = data;
981 struct oscar_data *odata;
982 struct aim_session_t *sess;
983 struct aim_conn_t *tstconn;
984
985 if (!g_slist_find(connections, gc)) {
986 close(source);
987 return;
988 }
989
990 odata = gc->proto_data;
991 sess = odata->sess;
992 tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH);
993
994 if (source < 0) {
995 aim_conn_kill(sess, &tstconn);
996 debug_printf("unable to connect to authorizer\n");
997 return;
998 }
999
1000 aim_conn_completeconnect(sess, tstconn);
1001 odata->paspa = gdk_input_add(tstconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
1002 oscar_callback, tstconn);
1003 debug_printf("chatnav: connected\n");
1004 }
1005
1006 static void oscar_chat_connect(gpointer data, gint source, GdkInputCondition cond)
1007 {
1008 struct chat_connection *ccon = data;
1009 struct gaim_connection *gc = ccon->gc;
1010 struct oscar_data *odata;
1011 struct aim_session_t *sess;
1012 struct aim_conn_t *tstconn;
1013
1014 if (!g_slist_find(connections, gc)) {
1015 close(source);
1016 g_free(ccon->show);
1017 g_free(ccon->name);
1018 g_free(ccon);
1019 return;
1020 }
1021
1022 odata = gc->proto_data;
1023 sess = odata->sess;
1024 tstconn = ccon->conn;
1025
1026 if (source < 0) {
1027 aim_conn_kill(sess, &tstconn);
1028 g_free(ccon->show);
1029 g_free(ccon->name);
1030 g_free(ccon);
1031 return;
1032 }
1033
1034 aim_conn_completeconnect(sess, ccon->conn);
1035 ccon->inpa = gdk_input_add(tstconn->fd,
1036 GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
1037 oscar_callback, tstconn);
1038 odata->oscar_chats = g_slist_append(odata->oscar_chats, ccon);
1039 aim_chat_attachname(tstconn, ccon->name);
1040 }
1041
1042 int gaim_handle_redirect(struct aim_session_t *sess,
1043 struct command_rx_struct *command, ...) {
1044 va_list ap;
1045 int serviceid;
1046 char *ip;
1047 unsigned char *cookie;
1048 struct gaim_connection *gc = sess->aux_data;
1049 struct aim_user *user = gc->user;
1050 struct aim_conn_t *tstconn;
1051 int i;
1052 char *host;
1053 int port;
1054
1055 port = user->proto_opt[USEROPT_AUTHPORT][0] ?
1056 atoi(user->proto_opt[USEROPT_AUTHPORT]) : FAIM_LOGIN_PORT,
1057
1058 va_start(ap, command);
1059 serviceid = va_arg(ap, int);
1060 ip = va_arg(ap, char *);
1061 cookie = va_arg(ap, unsigned char *);
1062
1063 for (i = 0; i < (int)strlen(ip); i++) {
1064 if (ip[i] == ':') {
1065 port = atoi(&(ip[i+1]));
1066 break;
1067 }
1068 }
1069 host = g_strndup(ip, i);
1070
1071 switch(serviceid) {
1072 case 0x7: /* Authorizer */
1073 debug_printf("Reconnecting with authorizor...\n");
1074 tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL);
1075 if (tstconn == NULL) {
1076 debug_printf("unable to reconnect with authorizer\n");
1077 g_free(host);
1078 return 1;
1079 }
1080 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
1081 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, gaim_rateresp, 0);
1082 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, gaim_info_change, 0);
1083 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, gaim_info_change, 0);
1084 aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, gaim_account_confirm, 0);
1085
1086 tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
1087 tstconn->fd = proxy_connect(host, port, oscar_auth_connect, gc);
1088 if (tstconn->fd < 0) {
1089 aim_conn_kill(sess, &tstconn);
1090 debug_printf("unable to reconnect with authorizer\n");
1091 g_free(host);
1092 return 1;
1093 }
1094 aim_auth_sendcookie(sess, tstconn, cookie);
1095 break;
1096 case 0xd: /* ChatNav */
1097 tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, NULL);
1098 if (tstconn == NULL) {
1099 debug_printf("unable to connect to chatnav server\n");
1100 g_free(host);
1101 return 1;
1102 }
1103 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
1104
1105 tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
1106 tstconn->fd = proxy_connect(host, port, oscar_chatnav_connect, gc);
1107 if (tstconn->fd < 0) {
1108 aim_conn_kill(sess, &tstconn);
1109 debug_printf("unable to connect to chatnav server\n");
1110 g_free(host);
1111 return 1;
1112 }
1113 aim_auth_sendcookie(sess, tstconn, cookie);
1114 break;
1115 case 0xe: /* Chat */
1116 {
1117 char *roomname = va_arg(ap, char *);
1118 int exchange = va_arg(ap, int);
1119 struct chat_connection *ccon;
1120 tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, NULL);
1121 if (tstconn == NULL) {
1122 debug_printf("unable to connect to chat server\n");
1123 g_free(host);
1124 return 1;
1125 }
1126
1127 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
1128 ccon = g_new0(struct chat_connection, 1);
1129 ccon->conn = tstconn;
1130 ccon->gc = gc;
1131 ccon->fd = -1;
1132 ccon->name = g_strdup(roomname);
1133 ccon->exchange = exchange;
1134 ccon->show = extract_name(roomname);
1135
1136 ccon->conn->status |= AIM_CONN_STATUS_INPROGRESS;
1137 ccon->conn->fd = proxy_connect(host, port, oscar_chat_connect, ccon);
1138 if (ccon->conn->fd < 0) {
1139 aim_conn_kill(sess, &tstconn);
1140 debug_printf("unable to connect to chat server\n");
1141 g_free(host);
1142 g_free(ccon->show);
1143 g_free(ccon->name);
1144 g_free(ccon);
1145 return 1;
1146 }
1147 aim_auth_sendcookie(sess, tstconn, cookie);
1148 debug_printf("Connected to chat room %s exchange %d\n", roomname, exchange);
1149 }
1150 break;
1151 default: /* huh? */
1152 debug_printf("got redirect for unknown service 0x%04x\n", serviceid);
1153 break;
1154 }
1155
1156 va_end(ap);
1157
1158 g_free(host);
1159 return 1;
1160 }
1161
1162 int gaim_parse_oncoming(struct aim_session_t *sess,
1163 struct command_rx_struct *command, ...) {
1164 struct aim_userinfo_s *info;
1165 time_t time_idle;
1166 int type = 0;
1167 struct gaim_connection *gc = sess->aux_data;
1168
1169 va_list ap;
1170 va_start(ap, command);
1171 info = va_arg(ap, struct aim_userinfo_s *);
1172 va_end(ap);
1173
1174 if (info->flags & AIM_FLAG_UNCONFIRMED)
1175 type |= UC_UNCONFIRMED;
1176 else if (info->flags & AIM_FLAG_ADMINISTRATOR)
1177 type |= UC_ADMIN;
1178 else if (info->flags & AIM_FLAG_AOL)
1179 type |= UC_AOL;
1180 else if (info->flags & AIM_FLAG_FREE)
1181 type |= UC_NORMAL;
1182 if (info->flags & AIM_FLAG_AWAY)
1183 type |= UC_UNAVAILABLE;
1184
1185 if (info->idletime) {
1186 time(&time_idle);
1187 time_idle -= info->idletime*60;
1188 } else
1189 time_idle = 0;
1190
1191 serv_got_update(gc, info->sn, 1, info->warnlevel/10, info->onlinesince,
1192 time_idle, type, info->capabilities);
1193
1194 return 1;
1195 }
1196
1197 int gaim_parse_offgoing(struct aim_session_t *sess,
1198 struct command_rx_struct *command, ...) {
1199 struct aim_userinfo_s *info;
1200 va_list ap;
1201 struct gaim_connection *gc = sess->aux_data;
1202
1203 va_start(ap, command);
1204 info = va_arg(ap, struct aim_userinfo_s *);
1205 va_end(ap);
1206
1207 serv_got_update(gc, info->sn, 0, 0, 0, 0, 0, 0);
1208
1209 return 1;
1210 }
1211
1212 static void cancel_direct_im(gpointer w, struct ask_direct *d) {
1213 debug_printf("Freeing DirectIM prompts.\n");
1214
1215 g_free(d->sn);
1216 g_free(d);
1217 }
1218
1219 static void delete_direct_im(gpointer w, struct direct_im *d) {
1220 struct oscar_data *od = (struct oscar_data *)d->gc->proto_data;
1221
1222 od->direct_ims = g_slist_remove(od->direct_ims, d);
1223 gdk_input_remove(d->watcher);
1224 aim_conn_kill(od->sess, &d->conn);
1225 g_free(d);
1226 }
1227
1228 static void oscar_directim_callback(gpointer data, gint source, GdkInputCondition condition) {
1229 struct direct_im *dim = data;
1230 struct gaim_connection *gc = dim->gc;
1231 struct oscar_data *od = gc->proto_data;
1232 char buf[256];
1233
1234 if (!g_slist_find(connections, gc)) {
1235 g_free(dim);
1236 return;
1237 }
1238
1239 if (source < 0) {
1240 g_free(dim);
1241 return;
1242 }
1243
1244 aim_conn_completeconnect(od->sess, dim->conn);
1245 if (!(dim->cnv = find_conversation(dim->name))) dim->cnv = new_conversation(dim->name);
1246 g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), dim->name);
1247 write_to_conv(dim->cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL));
1248
1249 od->direct_ims = g_slist_append(od->direct_ims, dim);
1250
1251 gtk_signal_connect(GTK_OBJECT(dim->cnv->window), "destroy",
1252 GTK_SIGNAL_FUNC(delete_direct_im), dim);
1253
1254 dim->watcher = gdk_input_add(dim->conn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
1255 oscar_callback, dim->conn);
1256 }
1257
1258 static int accept_direct_im(gpointer w, struct ask_direct *d) {
1259 struct gaim_connection *gc = d->gc;
1260 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
1261 struct direct_im *dim;
1262 char *host; int port = FAIM_LOGIN_PORT;
1263 int i;
1264
1265 debug_printf("Accepted DirectIM.\n");
1266
1267 dim = find_direct_im(od, d->sn);
1268 if (dim) {
1269 cancel_direct_im(w, d); /* 40 */
1270 return TRUE;
1271 }
1272 dim = g_new0(struct direct_im, 1);
1273 dim->gc = d->gc;
1274 g_snprintf(dim->name, sizeof dim->name, "%s", d->sn);
1275
1276 if ((dim->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL)) == NULL) {
1277 g_free(dim);
1278 cancel_direct_im(w, d);
1279 return TRUE;
1280 }
1281 dim->conn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
1282 dim->conn->priv = d->priv;
1283 aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING,
1284 gaim_directim_incoming, 0);
1285 aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT,
1286 gaim_directim_disconnect, 0);
1287 aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING,
1288 gaim_directim_typing, 0);
1289
1290 for (i = 0; i < (int)strlen(d->priv->ip); i++) {
1291 if (d->priv->ip[i] == ':') {
1292 port = atoi(&(d->priv->ip[i+1]));
1293 break;
1294 }
1295 }
1296 host = g_strndup(d->priv->ip, i);
1297 dim->conn->status |= AIM_CONN_STATUS_INPROGRESS;
1298 dim->conn->fd = proxy_connect(host, port, oscar_directim_callback, dim);
1299 g_free(host);
1300 if (dim->conn->fd < 0) {
1301 aim_conn_kill(od->sess, &dim->conn);
1302 g_free(dim);
1303 cancel_direct_im(w, d);
1304 return TRUE;
1305 }
1306
1307 cancel_direct_im(w, d);
1308
1309 return TRUE;
1310 }
1311
1312 /*
1313 static void cancel_getfile(gpointer w, struct ask_getfile *g) {
1314 g_free(g->ip);
1315 g_free(g->cookie);
1316 g_free(g->sn);
1317 g_free(g);
1318 }
1319
1320 static void cancel_getfile_file(GtkObject *obj, struct ask_getfile *g) {
1321 GtkWidget *w = gtk_object_get_user_data(obj);
1322 gtk_widget_destroy(w);
1323 cancel_getfile(w, g);
1324 }
1325
1326 static void cancel_getfile_cancel(GtkObject *obj, struct ask_getfile *g) {
1327 GtkWidget *w = gtk_object_get_user_data(obj);
1328 gtk_widget_destroy(w);
1329 }
1330
1331 static void interrupt_getfile(GtkObject *obj, struct getfile_transfer *gt) {
1332 struct gaim_connection *gc = gt->gc;
1333 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
1334
1335 gtk_widget_destroy(gt->window);
1336 gdk_input_remove(gt->gip);
1337 if (gt->gop > 0)
1338 gdk_input_remove(gt->gop);
1339 aim_conn_kill(od->sess, &gt->conn);
1340 od->getfiles = g_slist_remove(od->getfiles, gt);
1341 g_free(gt->receiver);
1342 g_free(gt->filename);
1343 fclose(gt->listing);
1344 g_free(gt);
1345 }
1346
1347 static int gaim_getfile_filereq(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1348 struct gaim_connection *gc = sess->aux_data;
1349 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
1350 struct getfile_transfer *gt;
1351 char buf[2048];
1352 GtkWidget *label;
1353 GtkWidget *button;
1354
1355 va_list ap;
1356 struct aim_conn_t *oftconn;
1357 struct aim_fileheader_t *fh;
1358 char *cookie;
1359
1360 va_start(ap, command);
1361 oftconn = va_arg(ap, struct aim_conn_t *);
1362 fh = va_arg(ap, struct aim_fileheader_t *);
1363 cookie = va_arg(ap, char *);
1364 va_end(ap);
1365
1366 gt = find_getfile_transfer(od, oftconn);
1367
1368 if (gt->window)
1369 return 1;
1370
1371 gt->window = gtk_dialog_new();
1372 gtk_window_set_title(GTK_WINDOW(gt->window), _("Gaim - File Transfer"));
1373 gtk_widget_realize(gt->window);
1374 aol_icon(gt->window->window);
1375
1376 g_snprintf(buf, sizeof buf, _("Sending %s to %s"), fh->name, gt->receiver);
1377 label = gtk_label_new(buf);
1378 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(gt->window)->vbox), label, FALSE, FALSE, 5);
1379 gtk_widget_show(label);
1380
1381 gt->meter = gtk_progress_bar_new();
1382 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(gt->window)->action_area), gt->meter, FALSE, FALSE, 5);
1383 gtk_widget_show(gt->meter);
1384
1385 gt->label = gtk_label_new("0 %");
1386 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(gt->window)->action_area), gt->label, FALSE, FALSE, 5);
1387 gtk_widget_show(gt->label);
1388
1389 button = picture_button(gt->window, _("Cancel"), cancel_xpm);
1390 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(gt->window)->action_area), button, FALSE, FALSE, 5);
1391 gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(interrupt_getfile), gt);
1392
1393 gtk_widget_show(gt->window);
1394
1395 return 1;
1396 }
1397
1398 static void getfile_send_callback(gpointer data, gint source, GdkInputCondition condition) {
1399 struct getfile_transfer *gt = (struct getfile_transfer *)data;
1400 int result;
1401
1402 result = aim_getfile_send_chunk(gt->conn, gt->file, gt->fh, -1, 1024);
1403 gt->pos += result;
1404 if (result == 0) {
1405 gdk_input_remove(gt->gop); gt->gop = 0;
1406 } else if (result == -1) {
1407 do_error_dialog(_("Error in transfer"), "Gaim");
1408 gdk_input_remove(gt->gop); gt->gop = 0;
1409 interrupt_getfile(NULL, gt);
1410 }
1411 }
1412
1413 static int gaim_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1414 struct gaim_connection *gc = sess->aux_data;
1415 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
1416 struct getfile_transfer *gt;
1417
1418 va_list ap;
1419 struct aim_conn_t *oftconn;
1420 struct aim_fileheader_t *fh;
1421 char *cookie;
1422
1423 va_start(ap, command);
1424 oftconn = va_arg(ap, struct aim_conn_t *);
1425 fh = va_arg(ap, struct aim_fileheader_t *);
1426 cookie = va_arg(ap, char *);
1427 va_end(ap);
1428
1429 gt = find_getfile_transfer(od, oftconn);
1430
1431 if (gt->gop > 0) {
1432 debug_printf("already have output watcher?\n");
1433 return 1;
1434 }
1435
1436 if ((gt->file = fopen(gt->filename, "r")) == NULL) {
1437 interrupt_getfile(NULL, gt);
1438 return 1;
1439 }
1440 gt->pos = 0;
1441 gt->fh = g_memdup(fh, sizeof(struct aim_fileheader_t));
1442 fseek(gt->file, 0, SEEK_SET);
1443
1444 gt->gop = gdk_input_add(gt->conn->fd, GDK_INPUT_WRITE, getfile_send_callback, gt);
1445
1446 return 1;
1447 }
1448
1449 static int gaim_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1450 struct gaim_connection *gc = sess->aux_data;
1451 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
1452 struct getfile_transfer *gt;
1453
1454 va_list ap;
1455 struct aim_conn_t *conn;
1456 struct aim_fileheader_t *fh;
1457
1458 va_start(ap, command);
1459 conn = va_arg(ap, struct aim_conn_t *);
1460 fh = va_arg(ap, struct aim_fileheader_t *);
1461 va_end(ap);
1462
1463 gt = find_getfile_transfer(od, conn);
1464
1465 gtk_widget_destroy(gt->window);
1466 gt->window = NULL;
1467 do_error_dialog(_("Transfer complete."), "Gaim");
1468
1469 return 1;
1470 }
1471
1472 static int gaim_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1473 struct gaim_connection *gc = sess->aux_data;
1474 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
1475 struct getfile_transfer *gt;
1476
1477 va_list ap;
1478 struct aim_conn_t *conn;
1479 char *sn;
1480
1481 va_start(ap, command);
1482 conn = va_arg(ap, struct aim_conn_t *);
1483 sn = va_arg(ap, char *);
1484 va_end(ap);
1485
1486 gt = find_getfile_transfer(od, conn);
1487 od->getfiles = g_slist_remove(od->getfiles, gt);
1488 gdk_input_remove(gt->gip);
1489 if (gt->gop > 0)
1490 gdk_input_remove(gt->gop);
1491 g_free(gt->receiver);
1492 g_free(gt->filename);
1493 aim_conn_kill(sess, &conn);
1494 fclose(gt->listing);
1495 g_free(gt);
1496
1497 debug_printf("getfile disconnect\n");
1498
1499 return 1;
1500 }
1501
1502 static void oscar_getfile_callback(gpointer data, gint source, GdkInputCondition condition) {
1503 struct getfile_transfer *gf = data;
1504 struct gaim_connection *gc = gf->gc;
1505 struct oscar_data *od = gc->proto_data;
1506
1507 gdk_input_remove(gf->gip);
1508 gf->gip = gdk_input_add(source, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, oscar_callback, gf->conn);
1509
1510 aim_conn_addhandler(od->sess, gf->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ, gaim_getfile_filereq, 0);
1511 aim_conn_addhandler(od->sess, gf->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, gaim_getfile_filesend, 0);
1512 aim_conn_addhandler(od->sess, gf->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, gaim_getfile_complete, 0);
1513 aim_conn_addhandler(od->sess, gf->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, gaim_getfile_disconnect, 0);
1514 }
1515
1516 static void do_getfile(GtkObject *obj, struct ask_getfile *g) {
1517 GtkWidget *w = gtk_object_get_user_data(obj);
1518 char *filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(w));
1519 struct gaim_connection *gc = g->gc;
1520 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
1521 struct getfile_transfer *gf;
1522 struct stat st;
1523 struct tm *ft;
1524 char tmppath[256];
1525 FILE *file;
1526 static int current = 0;
1527 struct aim_conn_t *newconn;
1528
1529 if (file_is_dir(filename, w))
1530 return;
1531
1532 if (stat(filename, &st) != 0) {
1533 gtk_widget_destroy(w);
1534 do_error_dialog(_("Error examining file"), _("GetFile Error"));
1535 cancel_getfile(w, g);
1536 return;
1537 }
1538
1539 g_snprintf(tmppath, sizeof tmppath, "/%s/gaim%d%d", g_get_tmp_dir(), getpid(), current++);
1540 if ((file = fopen(tmppath, "w+")) == NULL) {
1541 gtk_widget_destroy(w);
1542 do_error_dialog(_("Could not open temporary file, aborting"), _("GetFile Error"));
1543 cancel_getfile(w, g);
1544 return;
1545 }
1546
1547 gf = g_new0(struct getfile_transfer, 1);
1548 gf->gc = gc;
1549 gf->filename = g_strdup(filename);
1550 gf->listing = file;
1551 gf->receiver = g_strdup(g->sn);
1552 gf->size = st.st_size;
1553
1554 ft = localtime(&st.st_ctime);
1555 fprintf(file, "%2d/%2d/%4d %2d:%2d %8ld ",
1556 ft->tm_mon + 1, ft->tm_mday, ft->tm_year + 1900,
1557 ft->tm_hour + 1, ft->tm_min + 1, (long)st.st_size);
1558 fprintf(file, "%s\r\n", g_basename(filename));
1559 rewind(file);
1560
1561 aim_oft_registerlisting(od->sess, file, "");
1562 if ((newconn = aim_accepttransfer(od->sess, od->conn, g->sn, g->cookie, g->ip, file, AIM_CAPS_GETFILE)) == NULL) {
1563 od->sess->flags ^= AIM_SESS_FLAGS_NONBLOCKCONNECT;
1564 do_error_dialog(_("Error connecting for transfer"), _("GetFile Error"));
1565 g_free(gf->filename);
1566 fclose(file);
1567 g_free(gf);
1568 gtk_widget_destroy(w);
1569 return;
1570 }
1571
1572 gtk_widget_destroy(w);
1573
1574 od->getfiles = g_slist_append(od->getfiles, gf);
1575 gf->conn = newconn;
1576 gf->gip = gdk_input_add(newconn->fd, GDK_INPUT_WRITE, oscar_getfile_callback, gf);
1577 }
1578
1579 static int accept_getfile(gpointer w, struct ask_getfile *g) {
1580 GtkWidget *window;
1581 window = gtk_file_selection_new(_("Gaim - Send File..."));
1582 gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(window));
1583 gtk_object_set_user_data(GTK_OBJECT(window), window);
1584 gtk_signal_connect(GTK_OBJECT(window), "destroy",
1585 GTK_SIGNAL_FUNC(cancel_getfile_file), g);
1586 gtk_object_set_user_data(GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button), window);
1587 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button), "clicked",
1588 GTK_SIGNAL_FUNC(do_getfile), g);
1589 gtk_object_set_user_data(GTK_OBJECT(GTK_FILE_SELECTION(window)->cancel_button), window);
1590 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(window)->cancel_button), "clicked",
1591 GTK_SIGNAL_FUNC(cancel_getfile_cancel), g);
1592 gtk_widget_show(window);
1593
1594 return TRUE;
1595 }
1596 */
1597
1598 #if USE_PIXBUF
1599 static gboolean redraw_anim(gpointer data)
1600 {
1601 int delay;
1602 struct icon_req *ir = data;
1603 GList *frames;
1604 GdkPixbufFrame *frame;
1605 GdkPixbuf *buf;
1606 GdkPixmap *pm; GdkBitmap *bm;
1607 GdkPixmap *src;
1608 GdkGC *gc;
1609
1610 if (!ir->cnv || !g_list_find(conversations, ir->cnv)) {
1611 debug_printf("I think this is a bug.\n");
1612 return FALSE;
1613 }
1614
1615 frames = gdk_pixbuf_animation_get_frames(ir->anim);
1616 frame = g_list_nth_data(frames, ir->curframe);
1617 buf = gdk_pixbuf_frame_get_pixbuf(frame);
1618 switch (gdk_pixbuf_frame_get_action(frame)) {
1619 case GDK_PIXBUF_FRAME_RETAIN:
1620 gdk_pixbuf_render_pixmap_and_mask(buf, &src, NULL, 0);
1621 gtk_pixmap_get(GTK_PIXMAP(ir->pix), &pm, &bm);
1622 gc = gdk_gc_new(pm);
1623 gdk_draw_pixmap(pm, gc, src, 0, 0,
1624 gdk_pixbuf_frame_get_x_offset(frame),
1625 gdk_pixbuf_frame_get_y_offset(frame),
1626 -1, -1);
1627 gdk_pixmap_unref(src);
1628 gtk_widget_queue_draw(ir->pix);
1629 gdk_gc_unref(gc);
1630 break;
1631 case GDK_PIXBUF_FRAME_DISPOSE:
1632 gdk_pixbuf_render_pixmap_and_mask(buf, &pm, &bm, 0);
1633 gtk_pixmap_set(GTK_PIXMAP(ir->pix), pm, bm);
1634 gdk_pixmap_unref(pm);
1635 if (bm)
1636 gdk_bitmap_unref(bm);
1637 break;
1638 case GDK_PIXBUF_FRAME_REVERT:
1639 frame = frames->data;
1640 buf = gdk_pixbuf_frame_get_pixbuf(frame);
1641 gdk_pixbuf_render_pixmap_and_mask(buf, &pm, &bm, 0);
1642 gtk_pixmap_set(GTK_PIXMAP(ir->pix), pm, bm);
1643 gdk_pixmap_unref(pm);
1644 if (bm)
1645 gdk_bitmap_unref(bm);
1646 break;
1647 }
1648 ir->curframe = (ir->curframe + 1) % g_list_length(frames);
1649 delay = MAX(gdk_pixbuf_frame_get_delay_time(frame), 13);
1650 ir->timer = gtk_timeout_add(delay * 10, redraw_anim, ir);
1651 return FALSE;
1652 }
1653 #endif
1654
1655 int gaim_parse_incoming_im(struct aim_session_t *sess,
1656 struct command_rx_struct *command, ...) {
1657 int channel;
1658 struct aim_userinfo_s *userinfo;
1659 va_list ap;
1660 struct gaim_connection *gc = sess->aux_data;
1661
1662 va_start(ap, command);
1663 channel = va_arg(ap, int);
1664 userinfo = va_arg(ap, struct aim_userinfo_s *);
1665
1666 /* channel 1: standard message */
1667 if (channel == 1) {
1668 char *tmp = g_malloc(BUF_LONG);
1669 struct aim_incomingim_ch1_args *args;
1670
1671 args = va_arg(ap, struct aim_incomingim_ch1_args *);
1672 va_end(ap);
1673
1674 #if USE_PIXBUF
1675 if (args->icbmflags & AIM_IMFLAGS_HASICON) {
1676 struct oscar_data *od = gc->proto_data;
1677 struct icon_req *ir;
1678 GSList *h = od->hasicons;
1679 char *who = normalize(userinfo->sn);
1680 debug_printf("%s has an icon\n", userinfo->sn);
1681 while (h) {
1682 ir = h->data;
1683 if (!strcmp(ir->user, who))
1684 break;
1685 h = h->next;
1686 }
1687 if (!h) {
1688 ir = g_new0(struct icon_req, 1);
1689 ir->user = g_strdup(who);
1690 od->hasicons = g_slist_append(od->hasicons, ir);
1691 }
1692 if (args->iconstamp > ir->timestamp)
1693 ir->request = TRUE;
1694 ir->timestamp = args->iconstamp;
1695 }
1696 #endif
1697
1698 /*
1699 * Quickly convert it to eight bit format, replacing
1700 * non-ASCII UNICODE characters with their equivelent
1701 * HTML entity.
1702 */
1703 if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1704 int i;
1705
1706 for (i = 0, tmp[0] = '\0'; i < args->msglen; i += 2) {
1707 unsigned short uni;
1708
1709 uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1710
1711 if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1712
1713 g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "%c", uni);
1714
1715 } else { /* something else, do UNICODE entity */
1716 g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "&#%04x;", uni);
1717 }
1718 }
1719 } else
1720 g_snprintf(tmp, BUF_LONG, "%s", args->msg);
1721
1722 serv_got_im(gc, userinfo->sn, tmp, args->icbmflags & AIM_IMFLAGS_AWAY, time(NULL));
1723 g_free(tmp);
1724 } else if (channel == 2) {
1725 struct aim_incomingim_ch2_args *args;
1726 args = va_arg(ap, struct aim_incomingim_ch2_args *);
1727 va_end(ap);
1728 if (args->reqclass & AIM_CAPS_CHAT) {
1729 char *name = extract_name(args->info.chat.roominfo.name);
1730 serv_got_chat_invite(gc,
1731 name ? name : args->info.chat.roominfo.name,
1732 args->info.chat.roominfo.exchange,
1733 userinfo->sn,
1734 args->info.chat.msg);
1735 if (name)
1736 g_free(name);
1737 } else if (args->reqclass & AIM_CAPS_SENDFILE) {
1738 } else if (args->reqclass & AIM_CAPS_GETFILE) {
1739 /*
1740 char *ip, *cookie;
1741 struct ask_getfile *g = g_new0(struct ask_getfile, 1);
1742 char buf[256];
1743
1744 userinfo = va_arg(ap, struct aim_userinfo_s *);
1745 ip = va_arg(ap, char *);
1746 cookie = va_arg(ap, char *);
1747 va_end(ap);
1748
1749 debug_printf("%s received getfile request from %s (%s), cookie = %s\n",
1750 gc->username, userinfo->sn, ip, cookie);
1751
1752 g->gc = gc;
1753 g->sn = g_strdup(userinfo->sn);
1754 g->cookie = g_strdup(cookie);
1755 g->ip = g_strdup(ip);
1756 g_snprintf(buf, sizeof buf, "%s has just asked to get a file from %s.",
1757 userinfo->sn, gc->username);
1758 do_ask_dialog(buf, g, accept_getfile, cancel_getfile);
1759 */
1760 } else if (args->reqclass & AIM_CAPS_VOICE) {
1761 } else if (args->reqclass & AIM_CAPS_BUDDYICON) {
1762 #if USE_PIXBUF
1763 struct oscar_data *od = gc->proto_data;
1764 GSList *h = od->hasicons;
1765 struct icon_req *ir = NULL;
1766 char *who;
1767 struct conversation *c;
1768
1769 GdkPixbufLoader *load;
1770 GList *frames;
1771 GdkPixbuf *buf;
1772 GdkPixmap *pm;
1773 GdkBitmap *bm;
1774
1775 who = normalize(userinfo->sn);
1776
1777 while (h) {
1778 ir = h->data;
1779 if (!strcmp(who, ir->user))
1780 break;
1781 h = h->next;
1782
1783 }
1784
1785 if (!h || ((c = find_conversation(userinfo->sn)) == NULL) || (c->gc != gc)) {
1786 debug_printf("got buddy icon for %s but didn't want it\n", userinfo->sn);
1787 return 1;
1788 }
1789
1790 if (ir->pix && ir->cnv)
1791 gtk_container_remove(GTK_CONTAINER(ir->cnv->bbox), ir->pix);
1792 ir->pix = NULL;
1793 ir->cnv = NULL;
1794 if (ir->data)
1795 g_free(ir->data);
1796 if (ir->anim)
1797 gdk_pixbuf_animation_unref(ir->anim);
1798 ir->anim = NULL;
1799 if (ir->unanim)
1800 gdk_pixbuf_unref(ir->unanim);
1801 ir->unanim = NULL;
1802 if (ir->timer)
1803 gtk_timeout_remove(ir->timer);
1804 ir->timer = 0;
1805
1806 ir->length = args->info.icon.length;
1807
1808 if (!ir->length)
1809 return 1;
1810
1811 ir->data = g_memdup(args->info.icon.icon, args->info.icon.length);
1812
1813 load = gdk_pixbuf_loader_new();
1814 gdk_pixbuf_loader_write(load, ir->data, ir->length);
1815 ir->anim = gdk_pixbuf_loader_get_animation(load);
1816
1817 if (ir->anim) {
1818 frames = gdk_pixbuf_animation_get_frames(ir->anim);
1819 buf = gdk_pixbuf_frame_get_pixbuf(frames->data);
1820 gdk_pixbuf_render_pixmap_and_mask(buf, &pm, &bm, 0);
1821
1822 if (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1) {
1823 int delay =
1824 MAX(gdk_pixbuf_frame_get_delay_time(frames->data), 13);
1825 ir->curframe = 1;
1826 ir->timer = gtk_timeout_add(delay * 10, redraw_anim, ir);
1827 }
1828 } else {
1829 ir->unanim = gdk_pixbuf_loader_get_pixbuf(load);
1830 if (!ir->unanim) {
1831 gdk_pixbuf_loader_close(load);
1832 return 1;
1833 }
1834 gdk_pixbuf_render_pixmap_and_mask(ir->unanim, &pm, &bm, 0);
1835 }
1836
1837 ir->cnv = c;
1838 ir->pix = gtk_pixmap_new(pm, bm);
1839 gtk_box_pack_start(GTK_BOX(c->bbox), ir->pix, FALSE, FALSE, 5);
1840 if (ir->anim && (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1))
1841 gtk_widget_set_usize(ir->pix, gdk_pixbuf_animation_get_width(ir->anim),
1842 gdk_pixbuf_animation_get_height(ir->anim));
1843 gtk_widget_show(ir->pix);
1844 gdk_pixmap_unref(pm);
1845 if (bm)
1846 gdk_bitmap_unref(bm);
1847
1848 gdk_pixbuf_loader_close(load);
1849
1850 #endif
1851 } else if (args->reqclass & AIM_CAPS_IMIMAGE) {
1852 struct ask_direct *d = g_new0(struct ask_direct, 1);
1853 char buf[256];
1854
1855 debug_printf("%s received direct im request from %s (%s)\n",
1856 gc->username, userinfo->sn, args->info.directim->ip);
1857
1858 d->gc = gc;
1859 d->sn = g_strdup(userinfo->sn);
1860 d->priv = args->info.directim;
1861 g_snprintf(buf, sizeof buf, "%s has just asked to directly connect to %s.",
1862 userinfo->sn, gc->username);
1863 do_ask_dialog(buf, d, accept_direct_im, cancel_direct_im);
1864 } else {
1865 debug_printf("Unknown reqclass %d\n", args->reqclass);
1866 }
1867 }
1868
1869 return 1;
1870 }
1871
1872 int gaim_parse_misses(struct aim_session_t *sess,
1873 struct command_rx_struct *command, ...) {
1874 va_list ap;
1875 unsigned short chan, nummissed, reason;
1876 struct aim_userinfo_s *userinfo;
1877 char buf[1024];
1878
1879 va_start(ap, command);
1880 chan = (unsigned short)va_arg(ap, unsigned int);
1881 userinfo = va_arg(ap, struct aim_userinfo_s *);
1882 nummissed = (unsigned short)va_arg(ap, unsigned int);
1883 reason = (unsigned short)va_arg(ap, unsigned int);
1884 va_end(ap);
1885
1886 switch(reason) {
1887 case 1:
1888 /* message too large */
1889 sprintf(buf, _("You missed a message from %s because it was too large."), userinfo->sn);
1890 do_error_dialog(buf, _("Gaim - Error"));
1891 plugin_event(event_error, (void *)961, 0, 0, 0);
1892 break;
1893 default:
1894 sprintf(buf, _("You missed a message from %s for unknown reasons."), userinfo->sn);
1895 do_error_dialog(buf, _("Gaim - Error"));
1896 plugin_event(event_error, (void *)970, 0, 0, 0);
1897 break;
1898 }
1899
1900 return 1;
1901 }
1902
1903 int gaim_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1904 va_list ap;
1905 unsigned short reason;
1906
1907 va_start(ap, command);
1908 reason = va_arg(ap, int);
1909 va_end(ap);
1910
1911 debug_printf("snac threw error (reason 0x%04x: %s\n", reason,
1912 (reason < msgerrreasonlen) ? msgerrreason[reason] : "unknown");
1913
1914 return 1;
1915 }
1916
1917 int gaim_parse_msgerr(struct aim_session_t *sess,
1918 struct command_rx_struct *command, ...) {
1919 va_list ap;
1920 char *destn;
1921 unsigned short reason;
1922 char buf[1024];
1923
1924 va_start(ap, command);
1925 reason = (unsigned short)va_arg(ap, unsigned int);
1926 destn = va_arg(ap, char *);
1927 va_end(ap);
1928
1929 sprintf(buf, _("Your message to %s did not get sent: %s"), destn,
1930 (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown"));
1931 do_error_dialog(buf, _("Gaim - Error"));
1932
1933 return 1;
1934 }
1935
1936 int gaim_parse_locerr(struct aim_session_t *sess,
1937 struct command_rx_struct *command, ...) {
1938 va_list ap;
1939 char *destn;
1940 unsigned short reason;
1941 char buf[1024];
1942
1943 va_start(ap, command);
1944 reason = (unsigned short)va_arg(ap, unsigned int);
1945 destn = va_arg(ap, char *);
1946 va_end(ap);
1947
1948 sprintf(buf, _("User information for %s unavailable: %s"), destn,
1949 (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown"));
1950 do_error_dialog(buf, _("Gaim - Error"));
1951
1952 return 1;
1953 }
1954
1955 static char *images(int flags) {
1956 static char buf[1024];
1957 g_snprintf(buf, sizeof(buf), "%s%s%s%s",
1958 (flags & AIM_FLAG_UNCONFIRMED) ? "<IMG SRC=\"dt_icon.gif\">" : "",
1959 (flags & AIM_FLAG_AOL) ? "<IMG SRC=\"aol_icon.gif\">" : "",
1960 (flags & AIM_FLAG_ADMINISTRATOR) ? "<IMG SRC=\"admin_icon.gif\">" : "",
1961 (flags & AIM_FLAG_FREE) ? "<IMG SRC=\"free_icon.gif\">" : "");
1962 return buf;
1963 }
1964
1965 int gaim_parse_user_info(struct aim_session_t *sess,
1966 struct command_rx_struct *command, ...) {
1967 struct aim_userinfo_s *info;
1968 char *prof_enc = NULL, *prof = NULL;
1969 unsigned short infotype;
1970 char buf[BUF_LONG];
1971 struct gaim_connection *gc = sess->aux_data;
1972 va_list ap;
1973 char *asc;
1974
1975 va_start(ap, command);
1976 info = va_arg(ap, struct aim_userinfo_s *);
1977 prof_enc = va_arg(ap, char *);
1978 prof = va_arg(ap, char *);
1979 infotype = (unsigned short)va_arg(ap, unsigned int);
1980 va_end(ap);
1981
1982 if (info->membersince)
1983 asc = g_strdup_printf("Member Since : <B>%s</B><BR>\n",
1984 asctime(localtime(&info->membersince)));
1985 else
1986 asc = g_strdup("");
1987
1988 g_snprintf(buf, sizeof buf,
1989 _("Username : <B>%s</B> %s <BR>\n"
1990 "%s"
1991 "Warning Level : <B>%d %%</B><BR>\n"
1992 "Online Since : <B>%s</B><BR>\n"
1993 "Idle Minutes : <B>%d</B>\n<BR>\n<HR><BR>\n"
1994 "%s"
1995 "<br><BODY BGCOLOR=WHITE><hr><I>Legend:</I><br><br>"
1996 "<IMG SRC=\"free_icon.gif\"> : Normal AIM User<br>"
1997 "<IMG SRC=\"aol_icon.gif\"> : AOL User <br>"
1998 "<IMG SRC=\"dt_icon.gif\"> : Trial AIM User <br>"
1999 "<IMG SRC=\"admin_icon.gif\"> : Administrator"),
2000 info->sn, images(info->flags),
2001 asc,
2002 info->warnlevel/10,
2003 asctime(localtime(&info->onlinesince)),
2004 info->idletime,
2005 (prof && strlen(prof)) ?
2006 (infotype == AIM_GETINFO_GENERALINFO ?
2007 prof :
2008 away_subs(prof, gc->username))
2009 :
2010 (infotype == AIM_GETINFO_GENERALINFO ?
2011 _("<i>No Information Provided</i>") :
2012 _("<i>User has no away message</i>")));
2013
2014 g_show_info_text(away_subs(buf, gc->username));
2015
2016 g_free(asc);
2017
2018 return 1;
2019 }
2020
2021 int gaim_parse_motd(struct aim_session_t *sess,
2022 struct command_rx_struct *command, ...) {
2023 char *msg;
2024 unsigned short id;
2025 va_list ap;
2026 char buildbuf[150];
2027
2028 va_start(ap, command);
2029 id = (unsigned short)va_arg(ap, unsigned int);
2030 msg = va_arg(ap, char *);
2031 va_end(ap);
2032
2033 aim_getbuildstring(buildbuf, sizeof(buildbuf));
2034
2035 debug_printf("MOTD: %s (%d)\n", msg ? msg : "Unknown", id);
2036 debug_printf("Gaim %s / Libfaim %s\n", VERSION, buildbuf);
2037 if (id != 4)
2038 do_error_dialog(_("Your connection may be lost."),
2039 _("AOL error"));
2040
2041 return 1;
2042 }
2043
2044 int gaim_chatnav_info(struct aim_session_t *sess,
2045 struct command_rx_struct *command, ...) {
2046 va_list ap;
2047 unsigned short type;
2048 struct gaim_connection *gc = sess->aux_data;
2049 struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
2050
2051 va_start(ap, command);
2052 type = (unsigned short)va_arg(ap, unsigned int);
2053
2054 switch(type) {
2055 case 0x0002: {
2056 int maxrooms;
2057 struct aim_chat_exchangeinfo *exchanges;
2058 int exchangecount, i = 0;
2059
2060 maxrooms = (unsigned char)va_arg(ap, unsigned int);
2061 exchangecount = va_arg(ap, int);
2062 exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
2063 va_end(ap);
2064
2065 debug_printf("chat info: Chat Rights:\n");
2066 debug_printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
2067 debug_printf("chat info: \tExchange List: (%d total)\n", exchangecount);
2068 while (i < exchangecount)
2069 debug_printf("chat info: \t\t%d\n", exchanges[i++].number);
2070 if (odata->create_exchange) {
2071 debug_printf("creating room %s\n", odata->create_name);
2072 aim_chatnav_createroom(sess, command->conn, odata->create_name,
2073 odata->create_exchange);
2074 odata->create_exchange = 0;
2075 g_free(odata->create_name);
2076 odata->create_name = NULL;
2077 }
2078 }
2079 break;
2080 case 0x0008: {
2081 char *fqcn, *name, *ck;
2082 unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
2083 unsigned char createperms;
2084 unsigned long createtime;
2085
2086 fqcn = va_arg(ap, char *);
2087 instance = (unsigned short)va_arg(ap, unsigned int);
2088 exchange = (unsigned short)va_arg(ap, unsigned int);
2089 flags = (unsigned short)va_arg(ap, unsigned int);
2090 createtime = va_arg(ap, unsigned long);
2091 maxmsglen = (unsigned short)va_arg(ap, unsigned int);
2092 maxoccupancy = (unsigned short)va_arg(ap, unsigned int);
2093 createperms = (unsigned char)va_arg(ap, int);
2094 unknown = (unsigned short)va_arg(ap, unsigned int);
2095 name = va_arg(ap, char *);
2096 ck = va_arg(ap, char *);
2097 va_end(ap);
2098
2099 debug_printf("created room: %s %d %d %d %lu %d %d %d %d %s %s\n",
2100 fqcn,
2101 exchange, instance, flags,
2102 createtime,
2103 maxmsglen, maxoccupancy, createperms, unknown,
2104 name, ck);
2105 aim_chat_join(odata->sess, odata->conn, exchange, ck);
2106 }
2107 break;
2108 default:
2109 va_end(ap);
2110 debug_printf("chatnav info: unknown type (%04x)\n", type);
2111 break;
2112 }
2113 return 1;
2114 }
2115
2116 int gaim_chat_join(struct aim_session_t *sess,
2117 struct command_rx_struct *command, ...) {
2118 va_list ap;
2119 int count, i = 0;
2120 struct aim_userinfo_s *info;
2121 struct gaim_connection *g = sess->aux_data;
2122
2123 struct chat_connection *c = NULL;
2124
2125 va_start(ap, command);
2126 count = va_arg(ap, int);
2127 info = va_arg(ap, struct aim_userinfo_s *);
2128 va_end(ap);
2129
2130 c = find_oscar_chat_by_conn(g, command->conn);
2131 if (!c)
2132 return 1;
2133
2134 while (i < count)
2135 add_chat_buddy(c->cnv, info[i++].sn);
2136
2137 return 1;
2138 }
2139
2140 int gaim_chat_leave(struct aim_session_t *sess,
2141 struct command_rx_struct *command, ...) {
2142 va_list ap;
2143 int count, i = 0;
2144 struct aim_userinfo_s *info;
2145 struct gaim_connection *g = sess->aux_data;
2146
2147 struct chat_connection *c = NULL;
2148
2149 va_start(ap, command);
2150 count = va_arg(ap, int);
2151 info = va_arg(ap, struct aim_userinfo_s *);
2152 va_end(ap);
2153
2154 c = find_oscar_chat_by_conn(g, command->conn);
2155 if (!c)
2156 return 1;
2157
2158 while (i < count)
2159 remove_chat_buddy(c->cnv, info[i++].sn);
2160
2161 return 1;
2162 }
2163
2164 int gaim_chat_info_update(struct aim_session_t *sess,
2165 struct command_rx_struct *command, ...) {
2166 debug_printf("inside chat_info_update\n");
2167 return 1;
2168 }
2169
2170 int gaim_chat_incoming_msg(struct aim_session_t *sess,
2171 struct command_rx_struct *command, ...) {
2172 va_list ap;
2173 struct aim_userinfo_s *info;
2174 char *msg;
2175 struct gaim_connection *gc = sess->aux_data;
2176 struct chat_connection *ccon = find_oscar_chat_by_conn(gc, command->conn);
2177 char *tmp;
2178
2179 va_start(ap, command);
2180 info = va_arg(ap, struct aim_userinfo_s *);
2181 msg = va_arg(ap, char *);
2182
2183 tmp = g_malloc(BUF_LONG);
2184 g_snprintf(tmp, BUF_LONG, "%s", msg);
2185 serv_got_chat_in(gc, ccon->id, info->sn, 0, tmp, time((time_t)NULL));
2186 g_free(tmp);
2187
2188 return 1;
2189 }
2190
2191 /*
2192 * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option.
2193 */
2194 int gaim_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2195 va_list ap;
2196 unsigned short type;
2197 char *sn = NULL;
2198
2199 va_start(ap, command);
2200 type = (unsigned short)va_arg(ap, unsigned int);
2201 sn = va_arg(ap, char *);
2202 va_end(ap);
2203
2204 debug_printf("Sent message to %s.\n", sn);
2205
2206 return 1;
2207 }
2208
2209 int gaim_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2210 static char *codes[5] = {"invalid",
2211 "change",
2212 "warning",
2213 "limit",
2214 "limit cleared"};
2215 va_list ap;
2216 int code;
2217 unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
2218 unsigned long currentavg, maxavg;
2219
2220 va_start(ap, command);
2221 code = va_arg(ap, int);
2222 rateclass= va_arg(ap, int);
2223 windowsize = va_arg(ap, unsigned long);
2224 clear = va_arg(ap, unsigned long);
2225 alert = va_arg(ap, unsigned long);
2226 limit = va_arg(ap, unsigned long);
2227 disconnect = va_arg(ap, unsigned long);
2228 currentavg = va_arg(ap, unsigned long);
2229 maxavg = va_arg(ap, unsigned long);
2230 va_end(ap);
2231
2232 debug_printf("rate %s (paramid 0x%04lx): curavg = %ld, maxavg = %ld, alert at %ld, "
2233 "clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
2234 (code < 5) ? codes[code] : codes[0],
2235 rateclass,
2236 currentavg, maxavg,
2237 alert, clear,
2238 limit, disconnect,
2239 windowsize);
2240
2241 if (code == AIM_RATE_CODE_CHANGE) {
2242 if (currentavg >= clear)
2243 aim_conn_setlatency(command->conn, 0);
2244 } else if (code == AIM_RATE_CODE_WARNING) {
2245 aim_conn_setlatency(command->conn, windowsize/4);
2246 } else if (code == AIM_RATE_CODE_LIMIT) {
2247 aim_conn_setlatency(command->conn, windowsize/2);
2248 } else if (code == AIM_RATE_CODE_CLEARLIMIT) {
2249 aim_conn_setlatency(command->conn, 0);
2250 }
2251
2252 return 1;
2253 }
2254
2255 int gaim_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2256 va_list ap;
2257 int newevil;
2258 struct aim_userinfo_s *userinfo;
2259 struct gaim_connection *gc = sess->aux_data;
2260
2261 va_start(ap, command);
2262 newevil = va_arg(ap, int);
2263 userinfo = va_arg(ap, struct aim_userinfo_s *);
2264 va_end(ap);
2265
2266 serv_got_eviled(gc, (userinfo && userinfo->sn[0]) ? userinfo->sn : NULL, newevil / 10);
2267
2268 return 1;
2269 }
2270
2271 int gaim_rateresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2272 struct gaim_connection *gc = sess->aux_data;
2273 switch (command->conn->type) {
2274 case AIM_CONN_TYPE_BOS:
2275 aim_bos_ackrateresp(sess, command->conn);
2276 aim_bos_reqpersonalinfo(sess, command->conn);
2277 aim_bos_reqlocaterights(sess, command->conn);
2278 aim_bos_setprofile(sess, command->conn, gc->user->user_info, NULL, gaim_caps);
2279 aim_bos_reqbuddyrights(sess, command->conn);
2280
2281 account_online(gc);
2282 serv_finish_login(gc);
2283
2284 if (bud_list_cache_exists(gc))
2285 do_import(NULL, gc);
2286
2287 debug_printf("buddy list loaded\n");
2288
2289 aim_addicbmparam(sess, command->conn);
2290 aim_bos_reqicbmparaminfo(sess, command->conn);
2291
2292 aim_bos_reqrights(sess, command->conn);
2293 aim_bos_setgroupperm(sess, command->conn, AIM_FLAG_ALLUSERS);
2294 aim_bos_setprivacyflags(sess, command->conn, AIM_PRIVFLAGS_ALLOWIDLE |
2295 AIM_PRIVFLAGS_ALLOWMEMBERSINCE);
2296
2297 break;
2298 case AIM_CONN_TYPE_AUTH:
2299 aim_bos_ackrateresp(sess, command->conn);
2300 aim_auth_clientready(sess, command->conn);
2301 debug_printf("connected to auth (admin)\n");
2302 break;
2303 default:
2304 debug_printf("got rate response for unhandled connection type %04x\n",
2305 command->conn->type);
2306 break;
2307 }
2308
2309 return 1;
2310 }
2311
2312 int gaim_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2313 if (command->data) {
2314 debug_printf("minimum report interval: %d (seconds?)\n", aimutil_get16(command->data+10));
2315 } else
2316 debug_printf("NULL minimum report interval!\n");
2317 return 1;
2318 }
2319
2320 int gaim_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2321 va_list ap;
2322 unsigned short maxbuddies, maxwatchers;
2323
2324 va_start(ap, command);
2325 maxbuddies = (unsigned short)va_arg(ap, unsigned int);
2326 maxwatchers = (unsigned short)va_arg(ap, unsigned int);
2327 va_end(ap);
2328
2329 debug_printf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
2330
2331 return 1;
2332 }
2333
2334 int gaim_bosrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2335 unsigned short maxpermits, maxdenies;
2336 va_list ap;
2337
2338 va_start(ap, command);
2339 maxpermits = (unsigned short)va_arg(ap, unsigned int);
2340 maxdenies = (unsigned short)va_arg(ap, unsigned int);
2341 va_end(ap);
2342
2343 debug_printf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
2344
2345 aim_bos_clientready(sess, command->conn);
2346
2347 aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV);
2348
2349 return 1;
2350 }
2351
2352 int gaim_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2353 va_list ap;
2354 char *address, *SNs;
2355 int i, num;
2356 char *buf;
2357 int at = 0, len;
2358
2359 va_start(ap, command);
2360 address = va_arg(ap, char *);
2361 num = va_arg(ap, int);
2362 SNs = va_arg(ap, char *);
2363 va_end(ap);
2364
2365 len = num * (MAXSNLEN + 1) + 1024;
2366 buf = g_malloc(len);
2367 at += g_snprintf(buf + at, len - at, "<B>%s has the following screen names:</B><BR>", address);
2368 for (i = 0; i < num; i++)
2369 at += g_snprintf(buf + at, len - at, "%s<BR>", &SNs[i * (MAXSNLEN + 1)]);
2370 g_show_info_text(buf);
2371 g_free(buf);
2372
2373 return 1;
2374 }
2375
2376 int gaim_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2377 va_list ap;
2378 char *address;
2379 char buf[BUF_LONG];
2380
2381 va_start(ap, command);
2382 address = va_arg(ap, char *);
2383 va_end(ap);
2384
2385 g_snprintf(buf, sizeof(buf), "No results found for email address %s", address);
2386 do_error_dialog(buf, _("Error"));
2387
2388 return 1;
2389 }
2390
2391 int gaim_account_confirm(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2392 int status;
2393 va_list ap;
2394 char msg[256];
2395 struct gaim_connection *gc = sess->aux_data;
2396
2397 va_start(ap, command);
2398 status = va_arg(ap, int); /* status code of confirmation request */
2399 va_end(ap);
2400
2401 debug_printf("account confirmation returned status 0x%04x (%s)\n", status,
2402 status ? "email sent" : "unknown");
2403 if (status) {
2404 g_snprintf(msg, sizeof(msg), "You should receive an email asking to confirm %s.",
2405 gc->username);
2406 do_error_dialog(msg, "Confirm");
2407 }
2408
2409 return 1;
2410 }
2411
2412 int gaim_info_change(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2413 unsigned short change = 0;
2414 int perms, type, length, str;
2415 char *val;
2416 va_list ap;
2417 char buf[BUF_LONG];
2418 struct gaim_connection *gc = sess->aux_data;
2419
2420 va_start(ap, command);
2421 perms = va_arg(ap, int);
2422 type = va_arg(ap, int);
2423 length = va_arg(ap, int);
2424 val = va_arg(ap, char *);
2425 str = va_arg(ap, int);
2426 va_end(ap);
2427
2428 if (aimutil_get16(command->data+2) == 0x0005)
2429 change = 1;
2430
2431 debug_printf("info%s: perms = %d, type = %x, length = %d, val = %s\n",
2432 change ? " change" : "", perms, type, length, str ? val : "(not string)");
2433
2434 if ((type == 0x0011) && str) {
2435 g_snprintf(buf, sizeof(buf), "The email address for %s is %s", gc->username, val);
2436 do_error_dialog(buf, "Email");
2437 }
2438
2439 return 1;
2440 }
2441
2442 static void oscar_keepalive(struct gaim_connection *gc) {
2443 struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
2444 aim_flap_nop(odata->sess, odata->conn);
2445 }
2446
2447 static char *oscar_name() {
2448 return "Oscar";
2449 }
2450
2451 static void oscar_send_im(struct gaim_connection *gc, char *name, char *message, int away) {
2452 struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
2453 struct direct_im *dim = find_direct_im(odata, name);
2454 if (dim) {
2455 aim_send_im_direct(odata->sess, dim->conn, message);
2456 } else {
2457 if (away)
2458 aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_AWAY, message);
2459 else {
2460 int flags = AIM_IMFLAGS_ACK;
2461 #if USE_PIXBUF
2462 GSList *h = odata->hasicons;
2463 struct icon_req *ir;
2464 char *who = normalize(name);
2465 while (h) {
2466 ir = h->data;
2467 if (ir->request && !strcmp(who, ir->user))
2468 break;
2469 h = h->next;
2470 }
2471 if (h) {
2472 ir->request = FALSE;
2473 flags |= AIM_IMFLAGS_BUDDYREQ;
2474 debug_printf("sending buddy icon request with message\n");
2475 }
2476 #endif
2477 aim_send_im(odata->sess, odata->conn, name, flags, message);
2478 }
2479 }
2480 }
2481
2482 static void oscar_get_info(struct gaim_connection *g, char *name) {
2483 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2484 aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_GENERALINFO);
2485 }
2486
2487 static void oscar_get_away_msg(struct gaim_connection *g, char *name) {
2488 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2489 aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_AWAYMESSAGE);
2490 }
2491
2492 static void oscar_set_dir(struct gaim_connection *g, char *first, char *middle, char *last,
2493 char *maiden, char *city, char *state, char *country, int web) {
2494 /* FIXME : some of these things are wrong, but i'm lazy */
2495 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2496 aim_setdirectoryinfo(odata->sess, odata->conn, first, middle, last,
2497 maiden, NULL, NULL, city, state, NULL, 0, web);
2498 }
2499
2500
2501 static void oscar_set_idle(struct gaim_connection *g, int time) {
2502 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2503 aim_bos_setidle(odata->sess, odata->conn, time);
2504 }
2505
2506 static void oscar_set_info(struct gaim_connection *g, char *info) {
2507 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2508 char inforeal[1025], away[1025];
2509 g_snprintf(inforeal, sizeof(inforeal), "%s", info);
2510 if (g->away)
2511 g_snprintf(away, sizeof(away), "%s", g->away);
2512 if (strlen(info) > 1024)
2513 do_error_dialog("Maximum info length (1024) exceeded, truncating", "Info Too Long");
2514 aim_bos_setprofile(odata->sess, odata->conn, inforeal, g->away ? NULL : "", gaim_caps);
2515 }
2516
2517 static void oscar_set_away(struct gaim_connection *g, char *state, char *message) {
2518 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2519 char info[1025], away[1025];
2520 g_snprintf(info, sizeof(info), "%s", g->user->user_info);
2521 if (message)
2522 g_snprintf(away, sizeof(away), "%s", message);
2523 aim_bos_setprofile(odata->sess, odata->conn, NULL, message ? away : "", gaim_caps);
2524 if (g->away)
2525 g_free (g->away);
2526 g->away = NULL;
2527 if (message) {
2528 if (strlen(message) > 1024)
2529 do_error_dialog("Maximum away length (1024) exceeded, truncating",
2530 "Info Too Long");
2531 g->away = g_strdup (message);
2532 }
2533 }
2534
2535 static void oscar_warn(struct gaim_connection *g, char *name, int anon) {
2536 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2537 aim_send_warning(odata->sess, odata->conn, name, anon);
2538 }
2539
2540 static void oscar_dir_search(struct gaim_connection *g, char *first, char *middle, char *last,
2541 char *maiden, char *city, char *state, char *country, char *email) {
2542 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2543 if (strlen(email))
2544 aim_usersearch_address(odata->sess, odata->conn, email);
2545 }
2546
2547 static void oscar_add_buddy(struct gaim_connection *g, char *name) {
2548 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2549 aim_add_buddy(odata->sess, odata->conn, name);
2550 }
2551
2552 static void oscar_add_buddies(struct gaim_connection *g, GList *buddies) {
2553 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2554 char buf[MSG_LEN];
2555 int n = 0;
2556 while (buddies) {
2557 if (n > MSG_LEN - 18) {
2558 aim_bos_setbuddylist(odata->sess, odata->conn, buf);
2559 n = 0;
2560 }
2561 n += g_snprintf(buf + n, sizeof(buf) - n, "%s&", (char *)buddies->data);
2562 buddies = buddies->next;
2563 }
2564 aim_bos_setbuddylist(odata->sess, odata->conn, buf);
2565 }
2566
2567 static void oscar_remove_buddy(struct gaim_connection *g, char *name) {
2568 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2569 aim_remove_buddy(odata->sess, odata->conn, name);
2570 }
2571
2572 static void oscar_join_chat(struct gaim_connection *g, int exchange, char *name) {
2573 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2574 struct aim_conn_t *cur = NULL;
2575 if (!name) {
2576 if (!join_chat_entry || !join_chat_spin)
2577 return;
2578 name = gtk_entry_get_text(GTK_ENTRY(join_chat_entry));
2579 exchange = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(join_chat_spin));
2580 if (!name || !strlen(name))
2581 return;
2582 }
2583 debug_printf("Attempting to join chat room %s.\n", name);
2584 if ((cur = aim_getconn_type(odata->sess, AIM_CONN_TYPE_CHATNAV))) {
2585 debug_printf("chatnav exists, creating room\n");
2586 aim_chatnav_createroom(odata->sess, cur, name, exchange);
2587 } else {
2588 /* this gets tricky */
2589 debug_printf("chatnav does not exist, opening chatnav\n");
2590 odata->create_exchange = exchange;
2591 odata->create_name = g_strdup(name);
2592 aim_bos_reqservice(odata->sess, odata->conn, AIM_CONN_TYPE_CHATNAV);
2593 }
2594 }
2595
2596 static void des_jc()
2597 {
2598 join_chat_entry = NULL;
2599 join_chat_spin = NULL;
2600 }
2601
2602 static void oscar_draw_join_chat(struct gaim_connection *gc, GtkWidget *fbox) {
2603 GtkWidget *label;
2604 GtkWidget *rowbox;
2605 GtkObject *adjust;
2606
2607 rowbox = gtk_hbox_new(FALSE, 5);
2608 gtk_box_pack_start(GTK_BOX(fbox), rowbox, TRUE, TRUE, 0);
2609 gtk_widget_show(rowbox);
2610
2611 label = gtk_label_new(_("Join what group:"));
2612 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0);
2613 gtk_signal_connect(GTK_OBJECT(label), "destroy", GTK_SIGNAL_FUNC(des_jc), NULL);
2614 gtk_widget_show(label);
2615
2616 join_chat_entry = gtk_entry_new();
2617 gtk_box_pack_start(GTK_BOX(rowbox), join_chat_entry, TRUE, TRUE, 0);
2618 gtk_widget_grab_focus(join_chat_entry);
2619 gtk_signal_connect(GTK_OBJECT(join_chat_entry), "activate", GTK_SIGNAL_FUNC(do_join_chat), NULL);
2620 gtk_widget_show(join_chat_entry);
2621
2622 rowbox = gtk_hbox_new(FALSE, 5);
2623 gtk_box_pack_start(GTK_BOX(fbox), rowbox, TRUE, TRUE, 0);
2624 gtk_widget_show(rowbox);
2625
2626 label = gtk_label_new(_("Exchange:"));
2627 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0);
2628 gtk_widget_show(label);
2629
2630 adjust = gtk_adjustment_new(4, 4, 20, 1, 10, 10);
2631 join_chat_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
2632 gtk_widget_set_usize(join_chat_spin, 50, -1);
2633 gtk_box_pack_start(GTK_BOX(rowbox), join_chat_spin, FALSE, FALSE, 0);
2634 gtk_widget_show(join_chat_spin);
2635 }
2636
2637 static void oscar_chat_invite(struct gaim_connection *g, int id, char *message, char *name) {
2638 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2639 struct chat_connection *ccon = find_oscar_chat(g, id);
2640
2641 if (!ccon)
2642 return;
2643
2644 aim_chat_invite(odata->sess, odata->conn, name, message ? message : "",
2645 ccon->exchange, ccon->name, 0x0);
2646 }
2647
2648 static void oscar_chat_leave(struct gaim_connection *g, int id) {
2649 struct oscar_data *odata = g ? (struct oscar_data *)g->proto_data : NULL;
2650 GSList *bcs = g->buddy_chats;
2651 struct conversation *b = NULL;
2652 struct chat_connection *c = NULL;
2653 int count = 0;
2654
2655 while (bcs) {
2656 count++;
2657 b = (struct conversation *)bcs->data;
2658 if (id == b->id)
2659 break;
2660 bcs = bcs->next;
2661 b = NULL;
2662 }
2663
2664 if (!b)
2665 return;
2666
2667 debug_printf("Attempting to leave room %s (currently in %d rooms)\n", b->name, count);
2668
2669 c = find_oscar_chat(g, b->id);
2670 if (c != NULL) {
2671 if (odata)
2672 odata->oscar_chats = g_slist_remove(odata->oscar_chats, c);
2673 if (c->inpa > 0)
2674 gdk_input_remove(c->inpa);
2675 if (g && odata->sess)
2676 aim_conn_kill(odata->sess, &c->conn);
2677 g_free(c->name);
2678 g_free(c->show);
2679 g_free(c);
2680 }
2681 /* we do this because with Oscar it doesn't tell us we left */
2682 serv_got_chat_left(g, b->id);
2683 }
2684
2685 static void oscar_chat_send(struct gaim_connection *g, int id, char *message) {
2686 struct oscar_data *odata = (struct oscar_data *)g->proto_data;
2687 GSList *bcs = g->buddy_chats;
2688 struct conversation *b = NULL;
2689 struct chat_connection *c = NULL;
2690 char *buf;
2691 int i, j;
2692
2693 while (bcs) {
2694 b = (struct conversation *)bcs->data;
2695 if (id == b->id)
2696 break;
2697 bcs = bcs->next;
2698 b = NULL;
2699 }
2700 if (!b)
2701 return;
2702
2703 bcs = odata->oscar_chats;
2704 while (bcs) {
2705 c = (struct chat_connection *)bcs->data;
2706 if (b == c->cnv)
2707 break;
2708 bcs = bcs->next;
2709 c = NULL;
2710 }
2711 if (!c)
2712 return;
2713
2714 buf = g_malloc(strlen(message) * 4 + 1);
2715 for (i = 0, j = 0; i < strlen(message); i++) {
2716 if (message[i] == '\n') {
2717 buf[j++] = '<';
2718 buf[j++] = 'B';
2719 buf[j++] = 'R';
2720 buf[j++] = '>';
2721 } else {
2722 buf[j++] = message[i];
2723 }
2724 }
2725 buf[j] = '\0';
2726 aim_chat_send_im(odata->sess, c->conn, 0, buf, strlen(buf));
2727 g_free(buf);
2728 }
2729
2730 static char **oscar_list_icon(int uc) {
2731 if (uc & UC_UNAVAILABLE)
2732 return (char **)away_icon_xpm;
2733 if (uc & UC_AOL)
2734 return (char **)aol_icon_xpm;
2735 if (uc & UC_NORMAL)
2736 return (char **)free_icon_xpm;
2737 if (uc & UC_ADMIN)
2738 return (char **)admin_icon_xpm;
2739 if (uc & UC_UNCONFIRMED)
2740 return (char **)dt_icon_xpm;
2741 return NULL;
2742 }
2743
2744 static void oscar_info(GtkObject *obj, char *who) {
2745 struct gaim_connection *gc = (struct gaim_connection *)gtk_object_get_user_data(obj);
2746 serv_get_info(gc, who);
2747 }
2748
2749 static void oscar_away_msg(GtkObject *obj, char *who) {
2750 struct gaim_connection *gc = (struct gaim_connection *)gtk_object_get_user_data(obj);
2751 serv_get_away_msg(gc, who);
2752 }
2753
2754 static int gaim_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2755 va_list ap;
2756 struct gaim_connection *gc = sess->aux_data;
2757 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
2758 struct aim_directim_priv *priv;
2759 struct aim_conn_t *newconn;
2760 struct direct_im *dim;
2761 char buf[256];
2762
2763 va_start(ap, command);
2764 newconn = va_arg(ap, struct aim_conn_t *);
2765 va_end(ap);
2766
2767 priv = (struct aim_directim_priv *)newconn->priv;
2768
2769 debug_printf("DirectIM: initiate success to %s\n", priv->sn);
2770 dim = find_direct_im(od, priv->sn);
2771
2772 dim->cnv = find_conversation(priv->sn);
2773 if (!dim->cnv) dim->cnv = new_conversation(priv->sn);
2774 gtk_signal_connect(GTK_OBJECT(dim->cnv->window), "destroy",
2775 GTK_SIGNAL_FUNC(delete_direct_im), dim);
2776 gdk_input_remove(dim->watcher);
2777 dim->conn = newconn;
2778 dim->watcher = gdk_input_add(dim->conn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
2779 oscar_callback, dim->conn);
2780 g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), priv->sn);
2781 write_to_conv(dim->cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL));
2782
2783 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING,
2784 gaim_directim_incoming, 0);
2785 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT,
2786 gaim_directim_disconnect, 0);
2787 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING,
2788 gaim_directim_typing, 0);
2789
2790 return 1;
2791 }
2792
2793 static int gaim_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2794 va_list ap;
2795 char *msg = NULL;
2796 struct aim_conn_t *conn;
2797 struct aim_directim_priv *priv;
2798 struct gaim_connection *gc = sess->aux_data;
2799
2800 va_start(ap, command);
2801 conn = va_arg(ap, struct aim_conn_t *);
2802 msg = va_arg(ap, char *);
2803 va_end(ap);
2804
2805 if (!(priv = conn->priv)) {
2806 return -1;
2807 }
2808
2809 debug_printf("Got DirectIM message from %s\n", priv->sn);
2810
2811 serv_got_im(gc, priv->sn, msg, 0, time((time_t)NULL));
2812
2813 return 1;
2814 }
2815
2816 static int gaim_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2817 va_list ap;
2818 struct aim_conn_t *conn;
2819 char *sn;
2820 struct gaim_connection *gc = sess->aux_data;
2821 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
2822 struct direct_im *dim;
2823 char buf[256];
2824
2825 va_start(ap, command);
2826 conn = va_arg(ap, struct aim_conn_t *);
2827 sn = va_arg(ap, char *);
2828 va_end(ap);
2829
2830 debug_printf("%s disconnected Direct IM.\n", sn);
2831
2832 dim = find_direct_im(od, sn);
2833 od->direct_ims = g_slist_remove(od->direct_ims, dim);
2834 gdk_input_remove(dim->watcher);
2835 gtk_signal_disconnect_by_data(GTK_OBJECT(dim->cnv->window), dim);
2836
2837 g_snprintf(buf, sizeof buf, _("Direct IM with %s closed"), sn);
2838 if (dim->cnv)
2839 write_to_conv(dim->cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL));
2840
2841 aim_conn_kill(sess, &conn);
2842
2843 return 1;
2844 }
2845
2846 static int gaim_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
2847 va_list ap;
2848 struct aim_conn_t *conn;
2849 struct aim_directim_priv *priv;
2850
2851 va_start(ap, command);
2852 conn = va_arg(ap, struct aim_conn_t *);
2853 va_end(ap);
2854
2855 if (!(priv = conn->priv)) {
2856 return -1;
2857 }
2858
2859 /* I had to leave this. It's just too funny. It reminds me of my sister. */
2860 debug_printf("ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", priv->sn);
2861
2862 return 1;
2863 }
2864
2865 struct ask_do_dir_im {
2866 char *who;
2867 struct gaim_connection *gc;
2868 };
2869
2870 static void oscar_cancel_direct_im(GtkObject *obj, struct ask_do_dir_im *data) {
2871 g_free(data);
2872 }
2873
2874 static void oscar_direct_im(GtkObject *obj, struct ask_do_dir_im *data) {
2875 struct gaim_connection *gc = data->gc;
2876 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
2877 struct direct_im *dim;
2878
2879 dim = find_direct_im(od, data->who);
2880 if (dim) {
2881 do_error_dialog("Direct IM request already pending.", "Unable");
2882 return;
2883 }
2884 dim = g_new0(struct direct_im, 1);
2885 dim->gc = gc;
2886 g_snprintf(dim->name, sizeof dim->name, "%s", data->who);
2887
2888 dim->conn = aim_directim_initiate(od->sess, od->conn, NULL, data->who);
2889 if (dim->conn != NULL) {
2890 od->direct_ims = g_slist_append(od->direct_ims, dim);
2891 dim->watcher = gdk_input_add(dim->conn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
2892 oscar_callback, dim->conn);
2893 aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE,
2894 gaim_directim_initiate, 0);
2895 } else {
2896 do_error_dialog(_("Unable to open Direct IM"), _("Error"));
2897 g_free(dim);
2898 }
2899 }
2900
2901 static void oscar_ask_direct_im(GtkObject *m, gchar *who) {
2902 char buf[BUF_LONG];
2903 struct ask_do_dir_im *data = g_new0(struct ask_do_dir_im, 1);
2904 data->who = who;
2905 data->gc = gtk_object_get_user_data(m);
2906 g_snprintf(buf, sizeof(buf), _("You have selected to open a Direct IM connection with %s."
2907 " Doing this will let them see your IP address, and may be"
2908 " a security risk. Do you wish to continue?"), who);
2909 do_ask_dialog(buf, data, oscar_direct_im, oscar_cancel_direct_im);
2910 }
2911
2912 static void oscar_buddy_menu(GtkWidget *menu, struct gaim_connection *gc, char *who) {
2913 GtkWidget *button;
2914 char *n = g_strdup(normalize(gc->username));
2915
2916 button = gtk_menu_item_new_with_label(_("Get Info"));
2917 gtk_signal_connect(GTK_OBJECT(button), "activate",
2918 GTK_SIGNAL_FUNC(oscar_info), who);
2919 gtk_object_set_user_data(GTK_OBJECT(button), gc);
2920 gtk_menu_append(GTK_MENU(menu), button);
2921 gtk_widget_show(button);
2922
2923 button = gtk_menu_item_new_with_label(_("Get Away Msg"));
2924 gtk_signal_connect(GTK_OBJECT(button), "activate",
2925 GTK_SIGNAL_FUNC(oscar_away_msg), who);
2926 gtk_object_set_user_data(GTK_OBJECT(button), gc);
2927 gtk_menu_append(GTK_MENU(menu), button);
2928 gtk_widget_show(button);
2929
2930 if (strcmp(n, normalize(who))) {
2931 button = gtk_menu_item_new_with_label(_("Direct IM"));
2932 gtk_signal_connect(GTK_OBJECT(button), "activate",
2933 GTK_SIGNAL_FUNC(oscar_ask_direct_im), who);
2934 gtk_object_set_user_data(GTK_OBJECT(button), gc);
2935 gtk_menu_append(GTK_MENU(menu), button);
2936 gtk_widget_show(button);
2937 }
2938 g_free(n);
2939 }
2940
2941
2942 /* weeee */
2943 static void oscar_print_option(GtkEntry *entry, struct aim_user *user)
2944 {
2945 int entrynum;
2946
2947 entrynum = (int)gtk_object_get_user_data(GTK_OBJECT(entry));
2948
2949 if (entrynum == USEROPT_AUTH) {
2950 g_snprintf(user->proto_opt[USEROPT_AUTH],
2951 sizeof(user->proto_opt[USEROPT_AUTH]), "%s", gtk_entry_get_text(entry));
2952 } else if (entrynum == USEROPT_AUTHPORT) {
2953 g_snprintf(user->proto_opt[USEROPT_AUTHPORT],
2954 sizeof(user->proto_opt[USEROPT_AUTHPORT]), "%s", gtk_entry_get_text(entry));
2955 }
2956 }
2957
2958 static void oscar_user_opts(GtkWidget *book, struct aim_user *user)
2959 {
2960 /* so here, we create the new notebook page */
2961 GtkWidget *vbox;
2962 GtkWidget *hbox;
2963 GtkWidget *label;
2964 GtkWidget *entry;
2965
2966 vbox = gtk_vbox_new(FALSE, 5);
2967 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
2968 gtk_notebook_append_page(GTK_NOTEBOOK(book), vbox, gtk_label_new("Oscar Options"));
2969 gtk_widget_show(vbox);
2970
2971 hbox = gtk_hbox_new(FALSE, 5);
2972 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2973 gtk_widget_show(hbox);
2974
2975 label = gtk_label_new("Auth Host:");
2976 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
2977 gtk_widget_show(label);
2978
2979 entry = gtk_entry_new();
2980 gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
2981 gtk_object_set_user_data(GTK_OBJECT(entry), (void *)USEROPT_AUTH);
2982 gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(oscar_print_option), user);
2983 if (user->proto_opt[USEROPT_AUTH][0]) {
2984 debug_printf("setting text %s\n", user->proto_opt[USEROPT_AUTH]);
2985 gtk_entry_set_text(GTK_ENTRY(entry), user->proto_opt[USEROPT_AUTH]);
2986 } else
2987 gtk_entry_set_text(GTK_ENTRY(entry), "login.oscar.aol.com");
2988 gtk_widget_show(entry);
2989
2990 hbox = gtk_hbox_new(FALSE, 0);
2991 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2992 gtk_widget_show(hbox);
2993
2994 label = gtk_label_new("Auth Port:");
2995 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
2996 gtk_widget_show(label);
2997
2998 entry = gtk_entry_new();
2999 gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
3000 gtk_object_set_user_data(GTK_OBJECT(entry), (void *)USEROPT_AUTHPORT);
3001 gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(oscar_print_option), user);
3002 if (user->proto_opt[USEROPT_AUTHPORT][0]) {
3003 debug_printf("setting text %s\n", user->proto_opt[USEROPT_AUTHPORT]);
3004 gtk_entry_set_text(GTK_ENTRY(entry), user->proto_opt[USEROPT_AUTHPORT]);
3005 } else
3006 gtk_entry_set_text(GTK_ENTRY(entry), "5190");
3007
3008 gtk_widget_show(entry);
3009 }
3010
3011 static void oscar_set_permit_deny(struct gaim_connection *gc) {
3012 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
3013 GSList *list;
3014 char buf[MAXMSGLEN];
3015 int at;
3016
3017 switch(gc->permdeny) {
3018 case 1:
3019 aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_DENYADD, gc->username);
3020 break;
3021 case 2:
3022 aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_PERMITADD, gc->username);
3023 break;
3024 case 3:
3025 list = gc->permit;
3026 at = 0;
3027 while (list) {
3028 at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", (char *)list->data);
3029 list = list->next;
3030 }
3031 aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_PERMITADD, buf);
3032 break;
3033 case 4:
3034 list = gc->deny;
3035 at = 0;
3036 while (list) {
3037 at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", (char *)list->data);
3038 list = list->next;
3039 }
3040 aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_DENYADD, buf);
3041 break;
3042 default:
3043 break;
3044 }
3045 }
3046
3047 static void oscar_add_permit(struct gaim_connection *gc, char *who) {
3048 if (gc->permdeny != 3) return;
3049 oscar_set_permit_deny(gc);
3050 }
3051
3052 static void oscar_add_deny(struct gaim_connection *gc, char *who) {
3053 if (gc->permdeny != 4) return;
3054 oscar_set_permit_deny(gc);
3055 }
3056
3057 static void oscar_rem_permit(struct gaim_connection *gc, char *who) {
3058 if (gc->permdeny != 3) return;
3059 oscar_set_permit_deny(gc);
3060 }
3061
3062 static void oscar_rem_deny(struct gaim_connection *gc, char *who) {
3063 if (gc->permdeny != 4) return;
3064 oscar_set_permit_deny(gc);
3065 }
3066
3067 static void oscar_draw_new_user(GtkWidget *box)
3068 {
3069 GtkWidget *label;
3070
3071 label = gtk_label_new(_("Unfortunately, currently Oscar only allows new user registration by "
3072 "going to http://aim.aol.com/aimnew/Aim/register.adp?promo=106723&pageset=Aim&client=no"
3073 ". Clicking the Register button will open the URL for you."));
3074 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
3075 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5);
3076 gtk_widget_show(label);
3077 }
3078
3079 static void oscar_do_new_user()
3080 {
3081 open_url(NULL, "http://aim.aol.com/aimnew/Aim/register.adp?promo=106723&pageset=Aim&client=no");
3082 }
3083
3084 static GList *oscar_away_states()
3085 {
3086 return g_list_append(NULL, GAIM_AWAY_CUSTOM);
3087 }
3088
3089 static void oscar_do_action(struct gaim_connection *gc, char *act)
3090 {
3091 struct oscar_data *od = gc->proto_data;
3092 struct aim_conn_t *conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH);
3093
3094 if (!strcmp(act, "Set User Info")) {
3095 show_set_info(gc);
3096 } else if (!strcmp(act, "Change Password")) {
3097 show_change_passwd(gc);
3098 } else if (!strcmp(act, "Confirm Account")) {
3099 if (!conn) {
3100 od->conf = TRUE;
3101 aim_bos_reqservice(od->sess, od->conn, AIM_CONN_TYPE_AUTH);
3102 } else
3103 aim_auth_reqconfirm(od->sess, conn);
3104 } else if (!strcmp(act, "Change Email")) {
3105 } else if (!strcmp(act, "Display Current Registered Address")) {
3106 if (!conn) {
3107 od->reqemail = TRUE;
3108 aim_bos_reqservice(od->sess, od->conn, AIM_CONN_TYPE_AUTH);
3109 } else
3110 aim_auth_getinfo(od->sess, conn, 0x11);
3111 } else if (!strcmp(act, "Search for Buddy by Email")) {
3112 show_find_email(gc);
3113 }
3114 }
3115
3116 static GList *oscar_actions()
3117 {
3118 GList *m = NULL;
3119
3120 m = g_list_append(m, "Set User Info");
3121 m = g_list_append(m, NULL);
3122 m = g_list_append(m, "Change Password");
3123 m = g_list_append(m, "Confirm Account");
3124 /*
3125 m = g_list_append(m, "Change Email");
3126 */
3127 m = g_list_append(m, "Display Current Registered Address");
3128 m = g_list_append(m, NULL);
3129 m = g_list_append(m, "Search for Buddy by Email");
3130
3131 return m;
3132 }
3133
3134 static void oscar_change_passwd(struct gaim_connection *gc, char *old, char *new)
3135 {
3136 struct oscar_data *od = gc->proto_data;
3137 if (!aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH)) {
3138 od->chpass = TRUE;
3139 od->oldp = g_strdup(old);
3140 od->newp = g_strdup(new);
3141 aim_bos_reqservice(od->sess, od->conn, AIM_CONN_TYPE_AUTH);
3142 } else {
3143 aim_auth_changepasswd(od->sess, aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH),
3144 new, old);
3145 }
3146 }
3147
3148 static void oscar_insert_convo(struct gaim_connection *gc, struct conversation *c)
3149 {
3150 #if USE_PIXBUF
3151 struct oscar_data *od = gc->proto_data;
3152 GSList *h = od->hasicons;
3153 struct icon_req *ir = NULL;
3154 char *who = normalize(c->name);
3155
3156 GdkPixbufLoader *load;
3157 GList *frames;
3158 GdkPixbuf *buf;
3159 GdkPixmap *pm;
3160 GdkBitmap *bm;
3161
3162 while (h) {
3163 ir = h->data;
3164 if (!strcmp(who, ir->user))
3165 break;
3166 h = h->next;
3167 }
3168 if (!h || !ir->data)
3169 return;
3170
3171 ir->cnv = c;
3172
3173 load = gdk_pixbuf_loader_new();
3174 gdk_pixbuf_loader_write(load, ir->data, ir->length);
3175 ir->anim = gdk_pixbuf_loader_get_animation(load);
3176
3177 if (ir->anim) {
3178 frames = gdk_pixbuf_animation_get_frames(ir->anim);
3179 buf = gdk_pixbuf_frame_get_pixbuf(frames->data);
3180 gdk_pixbuf_render_pixmap_and_mask(buf, &pm, &bm, 0);
3181
3182 if (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1) {
3183 int delay = MAX(gdk_pixbuf_frame_get_delay_time(frames->data), 13);
3184 ir->curframe = 1;
3185 ir->timer = gtk_timeout_add(delay * 10, redraw_anim, ir);
3186 }
3187 } else {
3188 ir->unanim = gdk_pixbuf_loader_get_pixbuf(load);
3189 if (!ir->unanim) {
3190 gdk_pixbuf_loader_close(load);
3191 return;
3192 }
3193 gdk_pixbuf_render_pixmap_and_mask(ir->unanim, &pm, &bm, 0);
3194 }
3195
3196 ir->pix = gtk_pixmap_new(pm, bm);
3197 gtk_box_pack_start(GTK_BOX(c->bbox), ir->pix, FALSE, FALSE, 5);
3198 if (ir->anim && (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1))
3199 gtk_widget_set_usize(ir->pix, gdk_pixbuf_animation_get_width(ir->anim),
3200 gdk_pixbuf_animation_get_height(ir->anim));
3201 gtk_widget_show(ir->pix);
3202 gdk_pixmap_unref(pm);
3203 if (bm)
3204 gdk_bitmap_unref(bm);
3205
3206 gdk_pixbuf_loader_close(load);
3207 #endif
3208 }
3209
3210 static void oscar_remove_convo(struct gaim_connection *gc, struct conversation *c)
3211 {
3212 #if USE_PIXBUF
3213 struct oscar_data *od = gc->proto_data;
3214 GSList *h = od->hasicons;
3215 struct icon_req *ir = NULL;
3216 char *who = normalize(c->name);
3217
3218 while (h) {
3219 ir = h->data;
3220 if (!strcmp(who, ir->user))
3221 break;
3222 h = h->next;
3223 }
3224 if (!h || !ir->data)
3225 return;
3226
3227 if (ir->cnv && ir->pix) {
3228 gtk_container_remove(GTK_CONTAINER(ir->cnv->bbox), ir->pix);
3229 ir->pix = NULL;
3230 ir->cnv = NULL;
3231 }
3232
3233 if (ir->anim) {
3234 gdk_pixbuf_animation_unref(ir->anim);
3235 ir->anim = NULL;
3236 } else if (ir->unanim) {
3237 gdk_pixbuf_unref(ir->unanim);
3238 ir->unanim = NULL;
3239 }
3240
3241 ir->curframe = 0;
3242
3243 if (ir->timer)
3244 gtk_timeout_remove(ir->timer);
3245 ir->timer = 0;
3246 #endif
3247 }
3248
3249 static struct prpl *my_protocol = NULL;
3250
3251 void oscar_init(struct prpl *ret) {
3252 ret->protocol = PROTO_OSCAR;
3253 ret->options = OPT_PROTO_HTML | OPT_PROTO_CORRECT_TIME;
3254 ret->name = oscar_name;
3255 ret->list_icon = oscar_list_icon;
3256 ret->away_states = oscar_away_states;
3257 ret->actions = oscar_actions;
3258 ret->do_action = oscar_do_action;
3259 ret->buddy_menu = oscar_buddy_menu;
3260 ret->user_opts = oscar_user_opts;
3261 ret->draw_new_user = oscar_draw_new_user;
3262 ret->do_new_user = oscar_do_new_user;
3263 ret->insert_convo = oscar_insert_convo;
3264 ret->remove_convo = oscar_remove_convo;
3265 ret->login = oscar_login;
3266 ret->close = oscar_close;
3267 ret->send_im = oscar_send_im;
3268 ret->set_info = oscar_set_info;
3269 ret->get_info = oscar_get_info;
3270 ret->set_away = oscar_set_away;
3271 ret->get_away_msg = oscar_get_away_msg;
3272 ret->set_dir = oscar_set_dir;
3273 ret->get_dir = NULL; /* Oscar really doesn't have this */
3274 ret->dir_search = oscar_dir_search;
3275 ret->set_idle = oscar_set_idle;
3276 ret->change_passwd = oscar_change_passwd;
3277 ret->add_buddy = oscar_add_buddy;
3278 ret->add_buddies = oscar_add_buddies;
3279 ret->remove_buddy = oscar_remove_buddy;
3280 ret->add_permit = oscar_add_permit;
3281 ret->add_deny = oscar_add_deny;
3282 ret->rem_permit = oscar_rem_permit;
3283 ret->rem_deny = oscar_rem_deny;
3284 ret->set_permit_deny = oscar_set_permit_deny;
3285 ret->warn = oscar_warn;
3286 ret->accept_chat = NULL; /* oscar doesn't have accept, it just joins */
3287 ret->join_chat = oscar_join_chat;
3288 ret->draw_join_chat = oscar_draw_join_chat;
3289 ret->chat_invite = oscar_chat_invite;
3290 ret->chat_leave = oscar_chat_leave;
3291 ret->chat_whisper = NULL;
3292 ret->chat_send = oscar_chat_send;
3293 ret->keepalive = oscar_keepalive;
3294
3295 my_protocol = ret;
3296 }
3297
3298 #ifndef STATIC
3299
3300 char *gaim_plugin_init(GModule *handle)
3301 {
3302 load_protocol(oscar_init, sizeof(struct prpl));
3303 return NULL;
3304 }
3305
3306 void gaim_plugin_remove()
3307 {
3308 struct prpl *p = find_prpl(PROTO_OSCAR);
3309 if (p == my_protocol)
3310 unload_protocol(p);
3311 }
3312
3313 char *name()
3314 {
3315 return "Oscar";
3316 }
3317
3318 char *description()
3319 {
3320 return "Allows gaim to use the Oscar protocol.";
3321 }
3322
3323 #endif