comparison plugins/oscar.c @ 981:7e231bc0018a

[gaim-migrate @ 991] I think I need a Pepsi. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Fri, 13 Oct 2000 07:24:40 +0000
parents
children 0b5db8cdd30f
comparison
equal deleted inserted replaced
980:82c5865f7cfe 981:7e231bc0018a
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 "gnome_applet_mgr.h"
45
46 #include "pixmaps/cancel.xpm"
47 #include "pixmaps/ok.xpm"
48
49 int gaim_caps = AIM_CAPS_CHAT | AIM_CAPS_SENDFILE | AIM_CAPS_GETFILE |
50 AIM_CAPS_VOICE | AIM_CAPS_IMIMAGE | AIM_CAPS_BUDDYICON;
51 int keepalv = -1;
52
53 struct chat_connection *find_oscar_chat(struct gaim_connection *gc, char *name) {
54 GSList *g = gc->oscar_chats;
55 struct chat_connection *c = NULL;
56 if (gc->protocol != PROTO_OSCAR) return NULL;
57
58 while (g) {
59 c = (struct chat_connection *)g->data;
60 if (!strcmp(name, c->name))
61 break;
62 g = g->next;
63 c = NULL;
64 }
65
66 return c;
67 }
68
69 static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc,
70 struct aim_conn_t *conn) {
71 GSList *g = gc->oscar_chats;
72 struct chat_connection *c = NULL;
73
74 while (g) {
75 c = (struct chat_connection *)g->data;
76 if (c->conn == conn)
77 break;
78 g = g->next;
79 c = NULL;
80 }
81
82 return c;
83 }
84
85 static struct gaim_connection *find_gaim_conn_by_aim_sess(struct aim_session_t *sess) {
86 GSList *g = connections;
87 struct gaim_connection *gc = NULL;
88
89 while (g) {
90 gc = (struct gaim_connection *)g->data;
91 if (sess == gc->oscar_sess)
92 break;
93 g = g->next;
94 gc = NULL;
95 }
96
97 return gc;
98 }
99
100 static struct gaim_connection *find_gaim_conn_by_oscar_conn(struct aim_conn_t *conn) {
101 GSList *g = connections;
102 struct gaim_connection *c = NULL;
103 struct aim_conn_t *s;
104 while (g) {
105 c = (struct gaim_connection *)g->data;
106 if (c->protocol != PROTO_OSCAR) {
107 c = NULL;
108 g = g->next;
109 continue;
110 }
111 s = c->oscar_sess->connlist;
112 while (s) {
113 if (conn == s)
114 break;
115 s = s->next;
116 }
117 if (s) break;
118 g = g->next;
119 c = NULL;
120 }
121
122 return c;
123 }
124
125 static int gaim_parse_auth_resp (struct aim_session_t *, struct command_rx_struct *, ...);
126 static int gaim_parse_login (struct aim_session_t *, struct command_rx_struct *, ...);
127 static int gaim_server_ready (struct aim_session_t *, struct command_rx_struct *, ...);
128 static int gaim_handle_redirect (struct aim_session_t *, struct command_rx_struct *, ...);
129 static int gaim_parse_oncoming (struct aim_session_t *, struct command_rx_struct *, ...);
130 static int gaim_parse_offgoing (struct aim_session_t *, struct command_rx_struct *, ...);
131 static int gaim_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *, ...);
132 static int gaim_parse_misses (struct aim_session_t *, struct command_rx_struct *, ...);
133 static int gaim_parse_user_info (struct aim_session_t *, struct command_rx_struct *, ...);
134 static int gaim_parse_motd (struct aim_session_t *, struct command_rx_struct *, ...);
135 static int gaim_chatnav_info (struct aim_session_t *, struct command_rx_struct *, ...);
136 static int gaim_chat_join (struct aim_session_t *, struct command_rx_struct *, ...);
137 static int gaim_chat_leave (struct aim_session_t *, struct command_rx_struct *, ...);
138 static int gaim_chat_info_update (struct aim_session_t *, struct command_rx_struct *, ...);
139 static int gaim_chat_incoming_msg(struct aim_session_t *, struct command_rx_struct *, ...);
140 static int gaim_parse_msgack (struct aim_session_t *, struct command_rx_struct *, ...);
141 static int gaim_parse_ratechange (struct aim_session_t *, struct command_rx_struct *, ...);
142 static int gaim_parse_evilnotify (struct aim_session_t *, struct command_rx_struct *, ...);
143 static int gaim_bosrights (struct aim_session_t *, struct command_rx_struct *, ...);
144 static int gaim_rateresp (struct aim_session_t *, struct command_rx_struct *, ...);
145 static int gaim_reportinterval (struct aim_session_t *, struct command_rx_struct *, ...);
146 static int gaim_parse_msgerr (struct aim_session_t *, struct command_rx_struct *, ...);
147 static int gaim_parse_buddyrights(struct aim_session_t *, struct command_rx_struct *, ...);
148 static int gaim_parse_locerr (struct aim_session_t *, struct command_rx_struct *, ...);
149
150 static int gaim_directim_incoming(struct aim_session_t *, struct command_rx_struct *, ...);
151 static int gaim_directim_typing (struct aim_session_t *, struct command_rx_struct *, ...);
152 static int gaim_directim_initiate(struct aim_session_t *, struct command_rx_struct *, ...);
153
154 static char *msgerrreason[] = {
155 "Invalid error",
156 "Invalid SNAC",
157 "Rate to host",
158 "Rate to client",
159 "Not logged in",
160 "Service unavailable",
161 "Service not defined",
162 "Obsolete SNAC",
163 "Not supported by host",
164 "Not supported by client",
165 "Refused by client",
166 "Reply too big",
167 "Responses lost",
168 "Request denied",
169 "Busted SNAC payload",
170 "Insufficient rights",
171 "In local permit/deny",
172 "Too evil (sender)",
173 "Too evil (receiver)",
174 "User temporarily unavailable",
175 "No match",
176 "List overflow",
177 "Request ambiguous",
178 "Queue full",
179 "Not while on AOL"
180 };
181 static int msgerrreasonlen = 25;
182
183 static void oscar_callback(gpointer data, gint source,
184 GdkInputCondition condition) {
185 struct aim_conn_t *conn = (struct aim_conn_t *)data;
186 struct gaim_connection *gc = find_gaim_conn_by_oscar_conn(conn);
187 if (!gc) {
188 /* oh boy. this is probably bad. i guess the only thing we can really do
189 * is return? */
190 debug_print("oscar callback for closed connection.\n");
191 return;
192 }
193
194 if (condition & GDK_INPUT_EXCEPTION) {
195 hide_login_progress(gc->username, _("Disconnected."));
196 signoff(gc);
197 return;
198 }
199 if (condition & GDK_INPUT_READ) {
200 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
201 debug_print("got information on rendezvous\n");
202 if (aim_handlerendconnect(gc->oscar_sess, conn) < 0) {
203 debug_print(_("connection error (rend)\n"));
204 }
205 } else {
206 if (aim_get_command(gc->oscar_sess, conn) >= 0) {
207 aim_rxdispatch(gc->oscar_sess);
208 } else {
209 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS &&
210 conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
211 struct conversation *cnv =
212 find_conversation(((struct aim_directim_priv *)conn->priv)->sn);
213 debug_print("connection error for directim\n");
214 if (cnv) {
215 make_direct(cnv, FALSE, NULL, 0);
216 }
217 aim_conn_kill(gc->oscar_sess, &conn);
218 } else if ((conn->type == AIM_CONN_TYPE_BOS) ||
219 !(aim_getconn_type(gc->oscar_sess, AIM_CONN_TYPE_BOS))) {
220 debug_print(_("major connection error\n"));
221 hide_login_progress(gc->username, _("Disconnected."));
222 signoff(gc);
223 } else if (conn->type == AIM_CONN_TYPE_CHAT) {
224 struct chat_connection *c = find_oscar_chat_by_conn(gc, conn);
225 char buf[BUF_LONG];
226 sprintf(debug_buff, "disconnected from chat room %s\n", c->name);
227 debug_print(debug_buff);
228 c->conn = NULL;
229 if (c->inpa > -1)
230 gdk_input_remove(c->inpa);
231 c->inpa = -1;
232 c->fd = -1;
233 aim_conn_kill(gc->oscar_sess, &conn);
234 sprintf(buf, _("You have been disconnected from chat room %s."), c->name);
235 do_error_dialog(buf, _("Chat Error!"));
236 } else if (conn->type == AIM_CONN_TYPE_CHATNAV) {
237 if (gc->cnpa > -1)
238 gdk_input_remove(gc->cnpa);
239 gc->cnpa = -1;
240 debug_print("removing chatnav input watcher\n");
241 aim_conn_kill(gc->oscar_sess, &conn);
242 } else {
243 sprintf(debug_buff, "holy crap! generic connection error! %d\n",
244 conn->type);
245 debug_print(debug_buff);
246 aim_conn_kill(gc->oscar_sess, &conn);
247 }
248 }
249 }
250 }
251 }
252
253 void oscar_login(struct aim_user *user) {
254 struct aim_session_t *sess;
255 struct aim_conn_t *conn;
256 char buf[256];
257 struct gaim_connection *gc;
258
259 sprintf(debug_buff, _("Logging in %s\n"), user->username);
260 debug_print(debug_buff);
261
262 gc = new_gaim_conn(PROTO_OSCAR, user->username, user->password);
263 sess = g_new0(struct aim_session_t, 1);
264 aim_session_init(sess);
265 /* we need an immediate queue because we don't use a while-loop to
266 * see if things need to be sent. */
267 sess->tx_enqueue = &aim_tx_enqueue__immediate;
268 gc->oscar_sess = sess;
269
270 sprintf(buf, _("Looking up %s"), FAIM_LOGIN_SERVER);
271 conn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, FAIM_LOGIN_SERVER);
272
273 if (conn == NULL) {
274 debug_print(_("internal connection error\n"));
275 hide_login_progress(gc->username, _("Unable to login to AIM"));
276 destroy_gaim_conn(gc);
277 return;
278 } else if (conn->fd == -1) {
279 if (conn->status & AIM_CONN_STATUS_RESOLVERR) {
280 sprintf(debug_buff, _("couldn't resolve host"));
281 debug_print(debug_buff); debug_print("\n");
282 hide_login_progress(gc->username, debug_buff);
283 } else if (conn->status & AIM_CONN_STATUS_CONNERR) {
284 sprintf(debug_buff, _("couldn't connect to host"));
285 debug_print(debug_buff); debug_print("\n");
286 hide_login_progress(gc->username, debug_buff);
287 }
288 destroy_gaim_conn(gc);
289 return;
290 }
291 g_snprintf(buf, sizeof(buf), _("Signon: %s"), gc->username);
292
293 aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0);
294 aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0);
295 aim_sendconnack(sess, conn);
296 aim_request_login(sess, conn, gc->username);
297
298 gc->inpa = gdk_input_add(conn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
299 oscar_callback, conn);
300
301 sprintf(gc->user_info, "%s", user->user_info);
302 gc->options = user->options;
303 save_prefs(); /* is this necessary anymore? */
304
305 debug_print(_("Password sent, waiting for response\n"));
306 }
307
308 void oscar_close(struct gaim_connection *gc) {
309 if (gc->protocol != PROTO_OSCAR) return;
310 if (gc->inpa > 0)
311 gdk_input_remove(gc->inpa);
312 gc->inpa = -1;
313 if (gc->cnpa > 0)
314 gdk_input_remove(gc->cnpa);
315 gc->cnpa = -1;
316 if (gc->paspa > 0)
317 gdk_input_remove(gc->paspa);
318 gc->paspa = -1;
319 aim_logoff(gc->oscar_sess);
320 g_free(gc->oscar_sess);
321 debug_print(_("Signed off.\n"));
322 }
323
324 int gaim_parse_auth_resp(struct aim_session_t *sess,
325 struct command_rx_struct *command, ...) {
326 struct aim_conn_t *bosconn = NULL;
327 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
328 sprintf(debug_buff, "inside auth_resp (Screen name: %s)\n",
329 sess->logininfo.screen_name);
330 debug_print(debug_buff);
331
332 if (sess->logininfo.errorcode) {
333 switch (sess->logininfo.errorcode) {
334 case 0x18:
335 /* connecting too frequently */
336 do_error_dialog(_("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."), _("Gaim - Error"));
337 plugin_event(event_error, (void *)983, 0, 0);
338 break;
339 case 0x05:
340 /* Incorrect nick/password */
341 do_error_dialog(_("Incorrect nickname or password."), _("Gaim - Error"));
342 plugin_event(event_error, (void *)980, 0, 0);
343 break;
344 case 0x1c:
345 /* client too old */
346 do_error_dialog(_("The client version you are using is too old. Please upgrade at http://www.marko.net/gaim/"), _("Gaim - Error"));
347 plugin_event(event_error, (void *)989, 0, 0);
348 break;
349 }
350 sprintf(debug_buff, "Login Error Code 0x%04x\n",
351 sess->logininfo.errorcode);
352 debug_print(debug_buff);
353 sprintf(debug_buff, "Error URL: %s\n",
354 sess->logininfo.errorurl);
355 debug_print(debug_buff);
356 #ifdef USE_APPLET
357 set_user_state(offline);
358 #endif
359 gdk_input_remove(gc->inpa);
360 hide_login_progress(gc->username, _("Authentication Failed"));
361 signoff(gc);
362 return 0;
363 }
364
365
366 if (sess->logininfo.email) {
367 sprintf(debug_buff, "Email: %s\n", sess->logininfo.email);
368 debug_print(debug_buff);
369 } else {
370 debug_print("Email is NULL\n");
371 }
372 sprintf(debug_buff, "Closing auth connection...\n");
373 debug_print(debug_buff);
374 gdk_input_remove(gc->inpa);
375 aim_conn_kill(sess, &command->conn);
376
377 bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, sess->logininfo.BOSIP);
378 if (bosconn == NULL) {
379 #ifdef USE_APPLET
380 set_user_state(offline);
381 #endif
382 hide_login_progress(gc->username, _("Internal Error"));
383 destroy_gaim_conn(gc);
384 return -1;
385 } else if (bosconn->status != 0) {
386 #ifdef USE_APPLET
387 set_user_state(offline);
388 #endif
389 hide_login_progress(gc->username, _("Could Not Connect"));
390 destroy_gaim_conn(gc);
391 return -1;
392 }
393
394 aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, gaim_bosrights, 0);
395 aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, gaim_rateresp, 0); /* rate info */
396 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0);
397 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, gaim_server_ready, 0);
398 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
399 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, gaim_handle_redirect, 0);
400 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, gaim_reportinterval, 0);
401 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, gaim_parse_buddyrights, 0);
402 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, gaim_parse_oncoming, 0);
403 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, gaim_parse_offgoing, 0);
404 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, gaim_parse_incoming_im, 0);
405 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, gaim_parse_locerr, 0);
406 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, gaim_parse_misses, 0);
407 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, gaim_parse_ratechange, 0);
408 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, gaim_parse_evilnotify, 0);
409 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, gaim_parse_msgerr, 0);
410 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parse_user_info, 0);
411 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, gaim_parse_msgack, 0);
412 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_CTN, AIM_CB_CTN_DEFAULT, aim_parse_unknown, 0);
413 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0);
414 aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, gaim_parse_motd, 0);
415
416 aim_auth_sendcookie(sess, bosconn, sess->logininfo.cookie);
417 gc->oscar_conn = bosconn;
418 gc->inpa = gdk_input_add(bosconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
419 oscar_callback, bosconn);
420 return 1;
421 }
422
423 int gaim_parse_login(struct aim_session_t *sess,
424 struct command_rx_struct *command, ...) {
425 struct client_info_s info = {"AOL Instant Messenger (SM), version 4.1.2010/WIN32", 4, 30, 3141, "us", "en", 0x0004, 0x0001, 0x055};
426 char *key;
427 va_list ap;
428 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
429
430 va_start(ap, command);
431 key = va_arg(ap, char *);
432 va_end(ap);
433
434 aim_send_login(sess, command->conn, gc->username, gc->password, &info, key);
435 return 1;
436 }
437
438 int gaim_server_ready(struct aim_session_t *sess,
439 struct command_rx_struct *command, ...) {
440 static int id = 1;
441 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
442 switch (command->conn->type) {
443 case AIM_CONN_TYPE_BOS:
444 aim_setversions(sess, command->conn);
445 aim_bos_reqrate(sess, command->conn); /* request rate info */
446 debug_print("done with BOS ServerReady\n");
447 break;
448 case AIM_CONN_TYPE_CHATNAV:
449 debug_print("chatnav: got server ready\n");
450 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, gaim_chatnav_info, 0);
451 aim_bos_reqrate(sess, command->conn);
452 aim_bos_ackrateresp(sess, command->conn);
453 aim_chatnav_clientready(sess, command->conn);
454 aim_chatnav_reqrights(sess, command->conn);
455 break;
456 case AIM_CONN_TYPE_CHAT:
457 debug_print("chat: got server ready\n");
458 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, gaim_chat_join, 0);
459 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, gaim_chat_leave, 0);
460 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, gaim_chat_info_update, 0);
461 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, gaim_chat_incoming_msg, 0);
462 aim_bos_reqrate(sess, command->conn);
463 aim_bos_ackrateresp(sess, command->conn);
464 aim_chat_clientready(sess, command->conn);
465 serv_got_joined_chat(gc, id++, aim_chat_getname(command->conn));
466 break;
467 case AIM_CONN_TYPE_RENDEZVOUS:
468 aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0);
469 break;
470 default: /* huh? */
471 sprintf(debug_buff, "server ready: got unexpected connection type %04x\n", command->conn->type);
472 debug_print(debug_buff);
473 break;
474 }
475 return 1;
476 }
477
478 int gaim_handle_redirect(struct aim_session_t *sess,
479 struct command_rx_struct *command, ...) {
480 va_list ap;
481 int serviceid;
482 char *ip;
483 unsigned char *cookie;
484 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
485
486 va_start(ap, command);
487 serviceid = va_arg(ap, int);
488 ip = va_arg(ap, char *);
489 cookie = va_arg(ap, unsigned char *);
490
491 switch(serviceid) {
492 case 0x7: /* Authorizer */
493 debug_print("Reconnecting with authorizor...\n");
494 {
495 struct aim_conn_t *tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip);
496 if (tstconn == NULL || tstconn->status >= AIM_CONN_STATUS_RESOLVERR)
497 debug_print("unable to reconnect with authorizer\n");
498 else {
499 gc->paspa = gdk_input_add(tstconn->fd,
500 GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
501 oscar_callback, tstconn);
502 aim_auth_sendcookie(sess, tstconn, cookie);
503 }
504 }
505 break;
506 case 0xd: /* ChatNav */
507 {
508 struct aim_conn_t *tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, ip);
509 if (tstconn == NULL || tstconn->status >= AIM_CONN_STATUS_RESOLVERR) {
510 debug_print("unable to connect to chatnav server\n");
511 return 1;
512 }
513 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
514 aim_auth_sendcookie(sess, tstconn, cookie);
515 gc->cnpa = gdk_input_add(tstconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
516 oscar_callback, tstconn);
517 }
518 debug_print("chatnav: connected\n");
519 break;
520 case 0xe: /* Chat */
521 {
522 struct aim_conn_t *tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, ip);
523 char *roomname = va_arg(ap, char *);
524 struct chat_connection *ccon;
525 if (tstconn == NULL || tstconn->status >= AIM_CONN_STATUS_RESOLVERR) {
526 debug_print("unable to connect to chat server\n");
527 return 1;
528 }
529 sprintf(debug_buff, "Connected to chat room %s\n", roomname);
530 debug_print(debug_buff);
531
532 ccon = g_new0(struct chat_connection, 1);
533 ccon->conn = tstconn;
534 ccon->fd = tstconn->fd;
535 ccon->name = g_strdup(roomname);
536
537 ccon->inpa = gdk_input_add(tstconn->fd,
538 GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
539 oscar_callback, tstconn);
540
541 gc->oscar_chats = g_slist_append(gc->oscar_chats, ccon);
542
543 aim_chat_attachname(tstconn, roomname);
544 aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
545 aim_auth_sendcookie(sess, tstconn, cookie);
546 }
547 break;
548 default: /* huh? */
549 sprintf(debug_buff, "got redirect for unknown service 0x%04x\n",
550 serviceid);
551 debug_print(debug_buff);
552 break;
553 }
554
555 va_end(ap);
556
557 return 1;
558 }
559
560 int gaim_parse_oncoming(struct aim_session_t *sess,
561 struct command_rx_struct *command, ...) {
562 struct aim_userinfo_s *info;
563 time_t time_idle;
564 int type = 0;
565
566 va_list ap;
567 va_start(ap, command);
568 info = va_arg(ap, struct aim_userinfo_s *);
569 va_end(ap);
570
571 if (info->flags & AIM_FLAG_UNCONFIRMED)
572 type |= UC_UNCONFIRMED;
573 else if (info->flags & AIM_FLAG_ADMINISTRATOR)
574 type |= UC_ADMIN;
575 else if (info->flags & AIM_FLAG_AOL)
576 type |= UC_AOL;
577 else if (info->flags & AIM_FLAG_FREE)
578 type |= UC_NORMAL;
579 if (info->flags & AIM_FLAG_AWAY)
580 type |= UC_UNAVAILABLE;
581
582 if (info->idletime) {
583 time(&time_idle);
584 time_idle -= info->idletime*60;
585 } else
586 time_idle = 0;
587
588 serv_got_update(info->sn, 1, info->warnlevel/10, info->onlinesince,
589 time_idle, type, info->capabilities);
590
591 return 1;
592 }
593
594 int gaim_parse_offgoing(struct aim_session_t *sess,
595 struct command_rx_struct *command, ...) {
596 char *sn;
597 va_list ap;
598
599 va_start(ap, command);
600 sn = va_arg(ap, char *);
601 va_end(ap);
602
603 serv_got_update(sn, 0, 0, 0, 0, 0, 0);
604
605 return 1;
606 }
607
608 static void accept_directim(GtkWidget *w, GtkWidget *m)
609 {
610 struct aim_conn_t *newconn;
611 struct aim_directim_priv *priv;
612 struct gaim_connection *gc;
613 int watcher;
614
615 priv = (struct aim_directim_priv *)gtk_object_get_user_data(GTK_OBJECT(m));
616 gc = (struct gaim_connection *)gtk_object_get_user_data(GTK_OBJECT(w));
617 gtk_widget_destroy(m);
618
619 if (!(newconn = aim_directim_connect(gc->oscar_sess, gc->oscar_conn, priv))) {
620 debug_print("imimage: could not connect\n");
621 return;
622 }
623
624 aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0);
625 aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_directim_typing, 0);
626
627 watcher = gdk_input_add(newconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
628 oscar_callback, newconn);
629
630 sprintf(debug_buff, "DirectIM: connected to %s\n", priv->sn);
631 debug_print(debug_buff);
632
633 serv_got_imimage(gc, priv->sn, priv->cookie, priv->ip, newconn, watcher);
634
635 g_free(priv);
636 }
637
638 static void cancel_directim(GtkWidget *w, GtkWidget *m)
639 {
640 gtk_widget_destroy(m);
641 }
642
643 static void directim_dialog(struct gaim_connection *gc, struct aim_directim_priv *priv)
644 {
645 GtkWidget *window;
646 GtkWidget *vbox;
647 GtkWidget *hbox;
648 GtkWidget *label;
649 GtkWidget *yes;
650 GtkWidget *no;
651 char buf[BUF_LONG];
652
653 window = gtk_window_new(GTK_WINDOW_DIALOG);
654 gtk_window_set_title(GTK_WINDOW(window), _("Accept Direct IM?"));
655 gtk_window_set_wmclass(GTK_WINDOW(window), "directim", "Gaim");
656 gtk_widget_realize(window);
657 aol_icon(window->window);
658 gtk_object_set_user_data(GTK_OBJECT(window), (void *)priv);
659
660 vbox = gtk_vbox_new(TRUE, 5);
661 gtk_container_add(GTK_CONTAINER(window), vbox);
662 gtk_widget_show(vbox);
663
664 sprintf(buf, _("%s has requested to directly connect to your computer. "
665 "Do you accept?"), priv->sn);
666 label = gtk_label_new(buf);
667 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 5);
668 gtk_widget_show(label);
669
670 hbox = gtk_hbox_new(TRUE, 10);
671 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
672 gtk_widget_show(hbox);
673
674 yes = picture_button(window, _("Accept"), ok_xpm);
675 gtk_box_pack_start(GTK_BOX(hbox), yes, FALSE, FALSE, 5);
676 gtk_object_set_user_data(GTK_OBJECT(yes), gc);
677
678 no = picture_button(window, _("Cancel"), cancel_xpm);
679 gtk_box_pack_end(GTK_BOX(hbox), no, FALSE, FALSE, 5);
680
681 gtk_signal_connect(GTK_OBJECT(yes), "clicked",
682 GTK_SIGNAL_FUNC(accept_directim), window);
683 gtk_signal_connect(GTK_OBJECT(no), "clicked",
684 GTK_SIGNAL_FUNC(cancel_directim), window);
685
686 gtk_widget_show(window);
687 }
688
689 int gaim_parse_incoming_im(struct aim_session_t *sess,
690 struct command_rx_struct *command, ...) {
691 int channel;
692 va_list ap;
693 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
694
695 va_start(ap, command);
696 channel = va_arg(ap, int);
697
698 /* channel 1: standard message */
699 if (channel == 1) {
700 struct aim_userinfo_s *userinfo;
701 char *msg = NULL;
702 char *tmp = g_malloc(BUF_LONG);
703 u_int icbmflags = 0;
704 u_short flag1, flag2;
705
706 userinfo = va_arg(ap, struct aim_userinfo_s *);
707 msg = va_arg(ap, char *);
708 icbmflags = va_arg(ap, u_int);
709 flag1 = (u_short)va_arg(ap, u_int);
710 flag2 = (u_short)va_arg(ap, u_int);
711 va_end(ap);
712
713 g_snprintf(tmp, BUF_LONG, "%s", msg);
714 serv_got_im(gc, userinfo->sn, tmp, icbmflags & AIM_IMFLAGS_AWAY);
715 g_free(tmp);
716 } else if (channel == 2) {
717 struct aim_userinfo_s *userinfo;
718 int rendtype = va_arg(ap, int);
719 if (rendtype & AIM_CAPS_CHAT) {
720 char *msg, *encoding, *lang;
721 struct aim_chat_roominfo *roominfo;
722
723 userinfo = va_arg(ap, struct aim_userinfo_s *);
724 roominfo = va_arg(ap, struct aim_chat_roominfo *);
725 msg = va_arg(ap, char *);
726 encoding = va_arg(ap, char *);
727 lang = va_arg(ap, char *);
728 va_end(ap);
729
730 serv_got_chat_invite(gc,
731 roominfo->name,
732 roominfo->exchange,
733 userinfo->sn,
734 msg);
735 } else if (rendtype & AIM_CAPS_SENDFILE) {
736 /* libfaim won't tell us that we got this just yet */
737 } else if (rendtype & AIM_CAPS_GETFILE) {
738 /* nor will it tell us this. but it's still there */
739 } else if (rendtype & AIM_CAPS_VOICE) {
740 /* this one libfaim tells us unuseful info about */
741 } else if (rendtype & AIM_CAPS_BUDDYICON) {
742 /* bah */
743 } else if (rendtype & AIM_CAPS_IMIMAGE) {
744 /* DirectIM stuff */
745 struct aim_directim_priv *priv, *priv2;
746
747 userinfo = va_arg(ap, struct aim_userinfo_s *);
748 priv = va_arg(ap, struct aim_directim_priv *);
749 va_end(ap);
750
751 sprintf(debug_buff, "DirectIM request from %s (%s)\n", userinfo->sn, priv->ip);
752 debug_print(debug_buff);
753
754 priv2 = g_new0(struct aim_directim_priv, 1);
755 strcpy(priv2->cookie, priv->cookie);
756 strcpy(priv2->sn, priv->sn);
757 strcpy(priv2->ip, priv->ip);
758 directim_dialog(gc, priv2);
759 } else {
760 sprintf(debug_buff, "Unknown rendtype %d\n", rendtype);
761 debug_print(debug_buff);
762 }
763 }
764
765 return 1;
766 }
767
768 int gaim_parse_misses(struct aim_session_t *sess,
769 struct command_rx_struct *command, ...) {
770 va_list ap;
771 u_short chan, nummissed, reason;
772 struct aim_userinfo_s *userinfo;
773 char buf[1024];
774
775 va_start(ap, command);
776 chan = (u_short)va_arg(ap, u_int);
777 userinfo = va_arg(ap, struct aim_userinfo_s *);
778 nummissed = (u_short)va_arg(ap, u_int);
779 reason = (u_short)va_arg(ap, u_int);
780 va_end(ap);
781
782 switch(reason) {
783 case 1:
784 /* message too large */
785 sprintf(buf, _("You missed a message from %s because it was too large."), userinfo->sn);
786 do_error_dialog(buf, _("Gaim - Error"));
787 plugin_event(event_error, (void *)961, 0, 0);
788 break;
789 default:
790 sprintf(buf, _("You missed a message from %s for unknown reasons."), userinfo->sn);
791 do_error_dialog(buf, _("Gaim - Error"));
792 plugin_event(event_error, (void *)970, 0, 0);
793 break;
794 }
795
796 return 1;
797 }
798
799 int gaim_parse_msgerr(struct aim_session_t *sess,
800 struct command_rx_struct *command, ...) {
801 va_list ap;
802 char *destn;
803 u_short reason;
804 char buf[1024];
805
806 va_start(ap, command);
807 destn = va_arg(ap, char *);
808 reason = (u_short)va_arg(ap, u_int);
809 va_end(ap);
810
811 sprintf(buf, _("Your message to %s did not get sent: %s"), destn,
812 (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown"));
813 do_error_dialog(buf, _("Gaim - Error"));
814
815 return 1;
816 }
817
818 int gaim_parse_locerr(struct aim_session_t *sess,
819 struct command_rx_struct *command, ...) {
820 va_list ap;
821 char *destn;
822 u_short reason;
823 char buf[1024];
824
825 va_start(ap, command);
826 destn = va_arg(ap, char *);
827 reason = (u_short)va_arg(ap, u_int);
828 va_end(ap);
829
830 sprintf(buf, _("User information for %s unavailable: %s"), destn,
831 (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown"));
832 do_error_dialog(buf, _("Gaim - Error"));
833
834 return 1;
835 }
836
837 int gaim_parse_user_info(struct aim_session_t *sess,
838 struct command_rx_struct *command, ...) {
839 struct aim_userinfo_s *info;
840 char *prof_enc = NULL, *prof = NULL;
841 u_short infotype;
842 char buf[BUF_LONG];
843 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
844 va_list ap;
845
846 va_start(ap, command);
847 info = va_arg(ap, struct aim_userinfo_s *);
848 prof_enc = va_arg(ap, char *);
849 prof = va_arg(ap, char *);
850 infotype = (u_short)va_arg(ap, u_int);
851 va_end(ap);
852
853 if (prof == NULL || !strlen(prof)) {
854 /* no info/away message */
855 char buf[1024];
856 sprintf(buf, _("%s has no info/away message."), info->sn);
857 do_error_dialog(buf, _("Gaim - Error"));
858 plugin_event(event_error, (void *)977, 0, 0);
859 return 1;
860 }
861
862 snprintf(buf, sizeof buf, _("Username : <B>%s</B>\n<BR>"
863 "Warning Level : <B>%d %%</B>\n<BR>"
864 "Online Since : <B>%s</B><BR>"
865 "Idle Minutes : <B>%d</B>\n<BR><HR><BR>"
866 "%s\n"),
867 info->sn,
868 info->warnlevel/10,
869 asctime(localtime(&info->onlinesince)),
870 info->idletime,
871 infotype == AIM_GETINFO_GENERALINFO ? prof :
872 away_subs(prof, gc->username));
873 g_show_info_text(away_subs(buf, gc->username));
874
875 return 1;
876 }
877
878 int gaim_parse_motd(struct aim_session_t *sess,
879 struct command_rx_struct *command, ...) {
880 char *msg;
881 u_short id;
882 va_list ap;
883 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
884
885 va_start(ap, command);
886 id = (u_short)va_arg(ap, u_int);
887 msg = va_arg(ap, char *);
888 va_end(ap);
889
890 sprintf(debug_buff, "MOTD: %s (%d)\n", msg, id);
891 debug_print(debug_buff);
892 sprintf(debug_buff, "Gaim %s / Libfaim %s\n",
893 VERSION, aim_getbuildstring());
894 debug_print(debug_buff);
895 if (id != 4)
896 do_error_dialog(_("Your connection may be lost."),
897 _("AOL error"));
898
899 if (gc->keepalive < 0)
900 update_keepalive(gc, gc->keepalive);
901
902 return 1;
903 }
904
905 int gaim_chatnav_info(struct aim_session_t *sess,
906 struct command_rx_struct *command, ...) {
907 va_list ap;
908 u_short type;
909 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
910
911 va_start(ap, command);
912 type = (u_short)va_arg(ap, u_int);
913
914 switch(type) {
915 case 0x0002: {
916 int maxrooms;
917 struct aim_chat_exchangeinfo *exchanges;
918 int exchangecount, i = 0;
919
920 maxrooms = (u_char)va_arg(ap, u_int);
921 exchangecount = va_arg(ap, int);
922 exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
923 va_end(ap);
924
925 debug_print("chat info: Chat Rights:\n");
926 sprintf(debug_buff, "chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
927 debug_print(debug_buff);
928 sprintf(debug_buff, "chat info: \tExchange List: (%d total)\n", exchangecount);
929 debug_print(debug_buff);
930 while (i < exchangecount) {
931 sprintf(debug_buff, "chat info: \t\t%x: %s (%s/%s)\n",
932 exchanges[i].number,
933 exchanges[i].name,
934 exchanges[i].charset1,
935 exchanges[i].lang1);
936 debug_print(debug_buff);
937 i++;
938 }
939 if (gc->create_exchange) {
940 sprintf(debug_buff, "creating room %s\n",
941 gc->create_name);
942 debug_print(debug_buff);
943 aim_chatnav_createroom(sess, command->conn, gc->create_name, gc->create_exchange);
944 gc->create_exchange = 0;
945 g_free(gc->create_name);
946 gc->create_name = NULL;
947 }
948 }
949 break;
950 case 0x0008: {
951 char *fqcn, *name, *ck;
952 u_short instance, flags, maxmsglen, maxoccupancy, unknown;
953 unsigned char createperms;
954 unsigned long createtime;
955
956 fqcn = va_arg(ap, char *);
957 instance = (u_short)va_arg(ap, u_int);
958 flags = (u_short)va_arg(ap, u_int);
959 createtime = va_arg(ap, unsigned long);
960 maxmsglen = (u_short)va_arg(ap, u_int);
961 maxoccupancy = (u_short)va_arg(ap, u_int);
962 createperms = (unsigned char)va_arg(ap, int);
963 unknown = (u_short)va_arg(ap, u_int);
964 name = va_arg(ap, char *);
965 ck = va_arg(ap, char *);
966 va_end(ap);
967
968 sprintf(debug_buff, "created room: %s %d %d %lu %d %d %d %d %s %s\n", fqcn, instance, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck);
969 debug_print(debug_buff);
970 if (flags & 0x4) {
971 sprintf(debug_buff, "joining %s on exchange 5\n", name);
972 debug_print(debug_buff);
973 aim_chat_join(gc->oscar_sess, gc->oscar_conn, 5, ck);
974 } else
975 sprintf(debug_buff, "joining %s on exchange 4\n", name);{
976 debug_print(debug_buff);
977 aim_chat_join(gc->oscar_sess, gc->oscar_conn, 4, ck);
978 }
979 }
980 break;
981 default:
982 va_end(ap);
983 sprintf(debug_buff, "chatnav info: unknown type (%04x)\n", type);
984 debug_print(debug_buff);
985 break;
986 }
987 return 1;
988 }
989
990 int gaim_chat_join(struct aim_session_t *sess,
991 struct command_rx_struct *command, ...) {
992 va_list ap;
993 int count, i = 0;
994 struct aim_userinfo_s *info;
995 struct gaim_connection *g = find_gaim_conn_by_aim_sess(sess);
996
997 GSList *bcs = g->buddy_chats;
998 struct conversation *b = NULL;
999
1000 va_start(ap, command);
1001 count = va_arg(ap, int);
1002 info = va_arg(ap, struct aim_userinfo_s *);
1003 va_end(ap);
1004
1005 while(bcs) {
1006 b = (struct conversation *)bcs->data;
1007 if (!strcasecmp(b->name, (char *)command->conn->priv))
1008 break;
1009 bcs = bcs->next;
1010 b = NULL;
1011 }
1012 if (!b)
1013 return 1;
1014
1015 while (i < count)
1016 add_chat_buddy(b, info[i++].sn);
1017
1018 return 1;
1019 }
1020
1021 int gaim_chat_leave(struct aim_session_t *sess,
1022 struct command_rx_struct *command, ...) {
1023 va_list ap;
1024 int count, i = 0;
1025 struct aim_userinfo_s *info;
1026 struct gaim_connection *g = find_gaim_conn_by_aim_sess(sess);
1027
1028 GSList *bcs = g->buddy_chats;
1029 struct conversation *b = NULL;
1030
1031 va_start(ap, command);
1032 count = va_arg(ap, int);
1033 info = va_arg(ap, struct aim_userinfo_s *);
1034 va_end(ap);
1035
1036 while(bcs) {
1037 b = (struct conversation *)bcs->data;
1038 if (!strcasecmp(b->name, (char *)command->conn->priv))
1039 break;
1040 bcs = bcs->next;
1041 b = NULL;
1042 }
1043 if (!b)
1044 return 1;
1045
1046 while (i < count)
1047 remove_chat_buddy(b, info[i++].sn);
1048
1049 return 1;
1050 }
1051
1052 int gaim_chat_info_update(struct aim_session_t *sess,
1053 struct command_rx_struct *command, ...) {
1054 debug_print("inside chat_info_update\n");
1055 return 1;
1056 }
1057
1058 int gaim_chat_incoming_msg(struct aim_session_t *sess,
1059 struct command_rx_struct *command, ...) {
1060 va_list ap;
1061 struct aim_userinfo_s *info;
1062 char *msg;
1063 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
1064
1065 GSList *bcs = gc->buddy_chats;
1066 struct conversation *b = NULL;
1067
1068 va_start(ap, command);
1069 info = va_arg(ap, struct aim_userinfo_s *);
1070 msg = va_arg(ap, char *);
1071
1072 while(bcs) {
1073 b = (struct conversation *)bcs->data;
1074 if (!strcasecmp(b->name, (char *)command->conn->priv))
1075 break;
1076 bcs = bcs->next;
1077 b = NULL;
1078 }
1079 if (!b)
1080 return 0;
1081
1082 serv_got_chat_in(gc, b->id, info->sn, 0, msg);
1083
1084 return 1;
1085 }
1086
1087 /*
1088 * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option.
1089 */
1090 int gaim_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1091 va_list ap;
1092 u_short type;
1093 char *sn = NULL;
1094
1095 va_start(ap, command);
1096 type = (u_short)va_arg(ap, u_int);
1097 sn = va_arg(ap, char *);
1098 va_end(ap);
1099
1100 sprintf(debug_buff, "Sent message to %s.\n", sn);
1101 debug_print(debug_buff);
1102
1103 return 1;
1104 }
1105
1106 int gaim_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1107 va_list ap;
1108 unsigned long newrate;
1109
1110 va_start(ap, command);
1111 newrate = va_arg(ap, unsigned long);
1112 va_end(ap);
1113
1114 sprintf(debug_buff, "ratechange: %lu\n", newrate);
1115 debug_print(debug_buff);
1116
1117 return 1;
1118 }
1119
1120 int gaim_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1121 va_list ap;
1122 char *sn;
1123
1124 va_start(ap, command);
1125 sn = va_arg(ap, char *);
1126 va_end(ap);
1127
1128 serv_got_eviled(sn, 0);
1129
1130 return 1;
1131 }
1132
1133 int gaim_rateresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1134 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
1135 switch (command->conn->type) {
1136 case AIM_CONN_TYPE_BOS:
1137 aim_bos_ackrateresp(sess, command->conn);
1138 aim_bos_reqpersonalinfo(sess, command->conn);
1139 aim_bos_reqlocaterights(sess, command->conn);
1140 aim_bos_setprofile(sess, command->conn, gc->user_info, NULL, gaim_caps);
1141 aim_bos_reqbuddyrights(sess, command->conn);
1142
1143 if (mainwindow)
1144 gtk_widget_hide(mainwindow);
1145 show_buddy_list();
1146
1147 #ifdef USE_APPLET
1148 if (general_options & OPT_GEN_APP_BUDDY_SHOW) {
1149 refresh_buddy_window();
1150 createOnlinePopup();
1151 applet_buddy_show = TRUE;
1152 } else {
1153 gtk_widget_hide(blist);
1154 applet_buddy_show = FALSE;
1155 }
1156 set_user_state(online);
1157 #else
1158 refresh_buddy_window();
1159 #endif
1160
1161 serv_finish_login(gc);
1162 gaim_setup(gc);
1163
1164 if (bud_list_cache_exists(gc))
1165 do_import(NULL, gc);
1166
1167 debug_print("buddy list loaded\n");
1168
1169 setup_buddy_chats();
1170
1171 aim_addicbmparam(sess, command->conn);
1172 aim_bos_reqicbmparaminfo(sess, command->conn);
1173
1174 aim_bos_reqrights(sess, command->conn);
1175 aim_bos_setgroupperm(sess, command->conn, AIM_FLAG_ALLUSERS);
1176 aim_bos_setprivacyflags(sess, command->conn, AIM_PRIVFLAGS_ALLOWIDLE |
1177 AIM_PRIVFLAGS_ALLOWMEMBERSINCE);
1178
1179 break;
1180 default:
1181 sprintf(debug_buff, "got rate response for unhandled connection type %04x\n",
1182 command->conn->type);
1183 debug_print(debug_buff);
1184 break;
1185 }
1186
1187 return 1;
1188 }
1189
1190 int gaim_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1191 if (command->data) {
1192 sprintf(debug_buff, "minimum report interval: %d (seconds?)\n", aimutil_get16(command->data+10));
1193 debug_print(debug_buff);
1194 } else
1195 debug_print("NULL minimum report interval!\n");
1196 return 1;
1197 }
1198
1199 int gaim_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1200 va_list ap;
1201 u_short maxbuddies, maxwatchers;
1202
1203 va_start(ap, command);
1204 maxbuddies = (u_short)va_arg(ap, u_int);
1205 maxwatchers = (u_short)va_arg(ap, u_int);
1206 va_end(ap);
1207
1208 sprintf(debug_buff, "buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
1209 debug_print(debug_buff);
1210
1211 return 1;
1212 }
1213
1214 int gaim_bosrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1215 u_short maxpermits, maxdenies;
1216 va_list ap;
1217
1218 va_start(ap, command);
1219 maxpermits = (u_short)va_arg(ap, u_int);
1220 maxdenies = (u_short)va_arg(ap, u_int);
1221 va_end(ap);
1222
1223 sprintf(debug_buff, "BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
1224 debug_print(debug_buff);
1225
1226 aim_bos_clientready(sess, command->conn);
1227
1228 aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV);
1229
1230 return 1;
1231 }
1232
1233 int gaim_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1234 va_list ap;
1235 char *sn = NULL, *msg = NULL;
1236 struct aim_conn_t *conn;
1237 struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
1238
1239 va_start(ap, command);
1240 conn = va_arg(ap, struct aim_conn_t *);
1241 sn = va_arg(ap, char *);
1242 msg = va_arg(ap, char *);
1243 va_end(ap);
1244
1245 sprintf(debug_buff, "Got DirectIM message from %s\n", sn);
1246 debug_print(debug_buff);
1247
1248 serv_got_im(gc, sn, msg, 0);
1249
1250 return 1;
1251 }
1252
1253 /* this is such a f*cked up function */
1254 int gaim_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1255 va_list ap;
1256 struct aim_directim_priv *priv;
1257 struct aim_conn_t *newconn;
1258 struct conversation *cnv;
1259 int watcher;
1260
1261 va_start(ap, command);
1262 newconn = va_arg(ap, struct aim_conn_t *);
1263 va_end(ap);
1264
1265 priv = (struct aim_directim_priv *)newconn->priv;
1266
1267 sprintf(debug_buff, "DirectIM: initiate success to %s\n", priv->sn);
1268 debug_print(debug_buff);
1269
1270 cnv = find_conversation(priv->sn);
1271 gdk_input_remove(cnv->watcher);
1272 watcher = gdk_input_add(newconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
1273 oscar_callback, newconn);
1274 make_direct(cnv, TRUE, newconn, watcher);
1275
1276 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0);
1277 aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_directim_typing, 0);
1278
1279 return 1;
1280 }
1281
1282 int gaim_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
1283 va_list ap;
1284 char *sn;
1285
1286 va_start(ap, command);
1287 sn = va_arg(ap, char *);
1288 va_end(ap);
1289
1290 /* I had to leave this. It's just too funny. It reminds me of my sister. */
1291 sprintf(debug_buff, "ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn);
1292 debug_print(debug_buff);
1293
1294 return 1;
1295 }
1296
1297 void oscar_do_directim(struct gaim_connection *gc, char *name) {
1298 struct aim_conn_t *newconn = aim_directim_initiate(gc->oscar_sess, gc->oscar_conn, NULL, name);
1299 struct conversation *cnv = find_conversation(name); /* this will never be null because it just got set up */
1300 cnv->conn = newconn;
1301 cnv->watcher = gdk_input_add(newconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, oscar_callback, newconn);
1302 aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, gaim_directim_initiate, 0);
1303 }
1304
1305 static void oscar_keepalive(struct gaim_connection *gc) {
1306 aim_flap_nop(gc->oscar_sess, gc->oscar_conn);
1307 }
1308
1309 static char *oscar_name() {
1310 return "Oscar";
1311 }
1312
1313 char *name() {
1314 return "Oscar";
1315 }
1316
1317 char *description() {
1318 return "Allows gaim to use the Oscar protocol";
1319 }
1320
1321 static void oscar_send_im(struct gaim_connection *gc, char *name, char *message, int away) {
1322 struct conversation *cnv = find_conversation(name);
1323 if (cnv && cnv->is_direct) {
1324 debug_printf("Sending DirectIM to %s\n", name);
1325 aim_send_im_direct(gc->oscar_sess, cnv->conn, message);
1326 } else {
1327 if (away)
1328 aim_send_im(gc->oscar_sess, gc->oscar_conn, name, AIM_IMFLAGS_AWAY, message);
1329 else
1330 aim_send_im(gc->oscar_sess, gc->oscar_conn, name, AIM_IMFLAGS_ACK, message);
1331 }
1332 }
1333
1334 static void oscar_get_info(struct gaim_connection *g, char *name) {
1335 aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_GENERALINFO);
1336 }
1337
1338 static void oscar_get_away_msg(struct gaim_connection *g, char *name) {
1339 aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_AWAYMESSAGE);
1340 }
1341
1342 static void oscar_set_dir(struct gaim_connection *g, char *first, char *middle, char *last,
1343 char *maiden, char *city, char *state, char *country, int web) {
1344 /* FIXME : some of these things are wrong, but i'm lazy */
1345 aim_setdirectoryinfo(g->oscar_sess, g->oscar_conn, first, middle, last,
1346 maiden, NULL, NULL, city, state, NULL, 0, web);
1347 }
1348
1349
1350 static void oscar_set_idle(struct gaim_connection *g, int time) {
1351 aim_bos_setidle(g->oscar_sess, g->oscar_conn, time);
1352 }
1353
1354 static void oscar_set_info(struct gaim_connection *g, char *info) {
1355 if (awaymessage)
1356 aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info,
1357 awaymessage->message, gaim_caps);
1358 else
1359 aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info,
1360 NULL, gaim_caps);
1361 }
1362
1363 static void oscar_set_away(struct gaim_connection *g, char *message) {
1364 aim_bos_setprofile(g->oscar_sess, g->oscar_conn, g->user_info, message, gaim_caps);
1365 }
1366
1367 static void oscar_warn(struct gaim_connection *g, char *name, int anon) {
1368 aim_send_warning(g->oscar_sess, g->oscar_conn, name, anon);
1369 }
1370
1371 static void oscar_dir_search(struct gaim_connection *g, char *first, char *middle, char *last,
1372 char *maiden, char *city, char *state, char *country, char *email) {
1373 if (strlen(email))
1374 aim_usersearch_address(g->oscar_sess, g->oscar_conn, email);
1375 }
1376
1377 static void oscar_add_buddy(struct gaim_connection *g, char *name) {
1378 aim_add_buddy(g->oscar_sess, g->oscar_conn, name);
1379 }
1380
1381 static void oscar_add_buddies(struct gaim_connection *g, GList *buddies) {
1382 char buf[MSG_LEN];
1383 int n = 0;
1384 while (buddies) {
1385 if (n > MSG_LEN - 18) {
1386 aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf);
1387 n = 0;
1388 }
1389 n += g_snprintf(buf + n, sizeof(buf) - n, "%s&", (char *)buddies->data);
1390 buddies = buddies->next;
1391 }
1392 aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf);
1393 }
1394
1395 static void oscar_remove_buddy(struct gaim_connection *g, char *name) {
1396 aim_remove_buddy(g->oscar_sess, g->oscar_conn, name);
1397 }
1398
1399 static void oscar_join_chat(struct gaim_connection *g, int exchange, char *name) {
1400 struct aim_conn_t *cur = NULL;
1401 sprintf(debug_buff, "Attempting to join chat room %s.\n", name);
1402 debug_print(debug_buff);
1403 if ((cur = aim_getconn_type(g->oscar_sess, AIM_CONN_TYPE_CHATNAV))) {
1404 debug_print("chatnav exists, creating room\n");
1405 aim_chatnav_createroom(g->oscar_sess, cur, name, exchange);
1406 } else {
1407 /* this gets tricky */
1408 debug_print("chatnav does not exist, opening chatnav\n");
1409 g->create_exchange = exchange;
1410 g->create_name = g_strdup(name);
1411 aim_bos_reqservice(g->oscar_sess, g->oscar_conn, AIM_CONN_TYPE_CHATNAV);
1412 }
1413 }
1414
1415 static void oscar_chat_invite(struct gaim_connection *g, int id, char *message, char *name) {
1416 GSList *bcs = g->buddy_chats;
1417 struct conversation *b = NULL;
1418
1419 while (bcs) {
1420 b = (struct conversation *)bcs->data;
1421 if (id == b->id)
1422 break;
1423 bcs = bcs->next;
1424 b = NULL;
1425 }
1426
1427 if (!b)
1428 return;
1429
1430 aim_chat_invite(g->oscar_sess, g->oscar_conn, name,
1431 message ? message : "", 0x4, b->name, 0x0);
1432 }
1433
1434 static void oscar_chat_leave(struct gaim_connection *g, int id) {
1435 GSList *bcs = g->buddy_chats;
1436 struct conversation *b = NULL;
1437 struct chat_connection *c = NULL;
1438 int count = 0;
1439
1440 while (bcs) {
1441 count++;
1442 b = (struct conversation *)bcs->data;
1443 if (id == b->id)
1444 break;
1445 bcs = bcs->next;
1446 b = NULL;
1447 }
1448
1449 if (!b)
1450 return;
1451
1452 sprintf(debug_buff, "Attempting to leave room %s (currently in %d rooms)\n",
1453 b->name, count);
1454 debug_print(debug_buff);
1455
1456 c = find_oscar_chat(g, b->name);
1457 if (c != NULL) {
1458 g->oscar_chats = g_slist_remove(g->oscar_chats, c);
1459 gdk_input_remove(c->inpa);
1460 if (g && g->oscar_sess)
1461 aim_conn_kill(g->oscar_sess, &c->conn);
1462 g_free(c->name);
1463 g_free(c);
1464 }
1465 /* we do this because with Oscar it doesn't tell us we left */
1466 serv_got_chat_left(g, b->id);
1467 }
1468
1469 static void oscar_chat_whisper(struct gaim_connection *g, int id, char *who, char *message) {
1470 do_error_dialog("Sorry, Oscar doesn't whisper. Send an IM. (The last message was not received.)",
1471 "Gaim - Chat");
1472 }
1473
1474 static void oscar_chat_send(struct gaim_connection *g, int id, char *message) {
1475 struct aim_conn_t *cn;
1476 GSList *bcs = g->buddy_chats;
1477 struct conversation *b = NULL;
1478
1479 while (bcs) {
1480 b = (struct conversation *)bcs->data;
1481 if (id == b->id)
1482 break;
1483 bcs = bcs->next;
1484 b = NULL;
1485 }
1486 if (!b)
1487 return;
1488
1489 cn = aim_chat_getconn(g->oscar_sess, b->name);
1490 aim_chat_send_im(g->oscar_sess, cn, message);
1491 }
1492
1493 struct prpl *oscar_init() {
1494 struct prpl *ret = g_new0(struct prpl, 1);
1495
1496 ret->protocol = PROTO_OSCAR;
1497 ret->name = oscar_name;
1498 ret->login = oscar_login;
1499 ret->close = oscar_close;
1500 ret->send_im = oscar_send_im;
1501 ret->set_info = oscar_set_info;
1502 ret->get_info = oscar_get_info;
1503 ret->set_away = oscar_set_away;
1504 ret->get_away_msg = oscar_get_away_msg;
1505 ret->set_dir = oscar_set_dir;
1506 ret->get_dir = NULL; /* Oscar really doesn't have this */
1507 ret->dir_search = oscar_dir_search;
1508 ret->set_idle = oscar_set_idle;
1509 ret->change_passwd = NULL; /* Oscar doesn't have this either */
1510 ret->add_buddy = oscar_add_buddy;
1511 ret->add_buddies = oscar_add_buddies;
1512 ret->remove_buddy = oscar_remove_buddy;
1513 ret->add_permit = NULL; /* Oscar's permit/deny stuff is messed up */
1514 ret->add_deny = NULL; /* at least, i can't figure it out :-P */
1515 ret->warn = oscar_warn;
1516 ret->accept_chat = NULL; /* oscar doesn't have accept, it just joins */
1517 ret->join_chat = oscar_join_chat;
1518 ret->chat_invite = oscar_chat_invite;
1519 ret->chat_leave = oscar_chat_leave;
1520 ret->chat_whisper = oscar_chat_whisper;
1521 ret->chat_send = oscar_chat_send;
1522 ret->keepalive = oscar_keepalive;
1523
1524 return ret;
1525 }
1526
1527 int gaim_plugin_init(void *handle) {
1528 protocols = g_slist_append(protocols, oscar_init());
1529 return 0;
1530 }