source: aim.c @ a7ac83a

release-1.10release-1.9
Last change on this file since a7ac83a was f271129, checked in by Jason Gross <jgross@mit.edu>, 13 years ago
Fix up headers The additions to owl.h and some of the removals were done by Alejandro Sedeño <asedeno@mit.edu> in commit 77a0258b3919468fc9d7f7602588ac427ab36e6c. Notes: * I think owl.c lost the need for sys/time.h when we punted select() in favor of glib's main loop. * We don't actually need to include things like stdarg.h, stdio.h, glib/gstdio.h, glib-object.h. I think they get indirectly included via owl.h and/or glib.h. They're left in (or added in to) the files that use functions/types from them. * I'm not entirely sure what sys/socket.h is doing in message.c. It is there from the initial commit. I suspect it might have had something to do with the call to getnameinfo. message.c compiles without it, but http://pubs.opengroup.org/onlinepubs/009695399/functions/getnameinfo.html suggests that we're supposed to include it? *shrugs* I'm leaving it in, for now. (Rather, I'll leave one copy of the #include in.)
  • Property mode set to 100644
File size: 61.9 KB
Line 
1#include "owl.h"
2
3/**********************************************************************/
4
5struct owlfaim_priv {
6  char *screenname;
7  char *password;
8  char *server;
9  int connected;
10};
11
12static const char *msgerrreasons[] = {
13        "Invalid error",
14        "Invalid SNAC",
15        "Rate to host",
16        "Rate to client",
17        "Not logged on",
18        "Service unavailable",
19        "Service not defined",
20        "Obsolete SNAC",
21        "Not supported by host",
22        "Not supported by client",
23        "Refused by client",
24        "Reply too big",
25        "Responses lost",
26        "Request denied",
27        "Busted SNAC payload",
28        "Insufficient rights",
29        "In local permit/deny",
30        "Too evil (sender)",
31        "Too evil (receiver)",
32        "User temporarily unavailable",
33        "No match",
34        "List overflow",
35        "Request ambiguous",
36        "Queue full",
37        "Not while on AOL",
38};
39static int msgerrreasonslen = 25;
40
41static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va);
42static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...);
43static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...);
44int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...);
45int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...);
46void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn);
47static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...);
48static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...);
49static int conninitdone_chat     (aim_session_t *, aim_frame_t *, ...);
50int logout(aim_session_t *sess);
51
52static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...);
53static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...);
54static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...);
55static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...);
56static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...);
57static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...);
58static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...);
59static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...);
60static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...);
61/* static int reportinterval(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs); */
62static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...);
63/* static void printuserflags(fu16_t flags); */
64static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...);
65static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args);
66static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
67static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...);
68static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...);
69static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...);
70int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...);
71static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...);
72static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...);
73static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...);
74static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...);
75static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...);
76static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...);
77static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...);
78static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...);
79static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...);
80static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...);
81static int migrate(aim_session_t *sess, aim_frame_t *fr, ...);
82static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...);
83static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...);
84static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...);
85static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...);
86static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...);
87/*
88static int faimtest_ssi_parseerr     (aim_session_t *, aim_frame_t *, ...);
89static int faimtest_ssi_parserights  (aim_session_t *, aim_frame_t *, ...);
90static int faimtest_ssi_parselist    (aim_session_t *, aim_frame_t *, ...);
91static int faimtest_ssi_parseack     (aim_session_t *, aim_frame_t *, ...);
92static int faimtest_ssi_authgiven    (aim_session_t *, aim_frame_t *, ...);
93static int faimtest_ssi_authrequest  (aim_session_t *, aim_frame_t *, ...);
94static int faimtest_ssi_authreply    (aim_session_t *, aim_frame_t *, ...);
95static int faimtest_ssi_gotadded     (aim_session_t *, aim_frame_t *, ...);
96*/
97
98void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
99void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
100
101/*****************************************************************/
102
103void owl_aim_init(void)
104{
105  /* this has all been moved to owl_aim_login, but we'll leave the
106   * function here, in case there's stuff we want to init in the
107   * future.  It's still called by Owl.
108   */
109     
110}
111
112gboolean owl_aim_send_nop(gpointer data) {
113  owl_global *g = data;
114  if (owl_global_is_doaimevents(g)) {
115    aim_session_t *sess = owl_global_get_aimsess(g);
116    aim_flap_nop(sess, aim_getconn_type(sess, AIM_CONN_TYPE_BOS));
117  }
118  return TRUE;
119}
120
121
122int owl_aim_login(const char *screenname, const char *password)
123{
124  struct owlfaim_priv *priv;
125  aim_conn_t *conn;
126  aim_session_t *sess;
127
128  sess=owl_global_get_aimsess(&g);
129
130  aim_session_init(sess, TRUE, 0);
131  aim_setdebuggingcb(sess, faimtest_debugcb);
132  aim_tx_setenqueue(sess, AIM_TX_IMMEDIATE, NULL);
133 
134  /* this will leak, I know and just don't care right now */
135  priv=g_new0(struct owlfaim_priv, 1);
136
137  priv->screenname = g_strdup(screenname);
138  priv->password = g_strdup(password);
139  priv->server = g_strdup(FAIM_LOGIN_SERVER);
140  sess->aux_data = priv;
141
142  conn=aim_newconn(sess, AIM_CONN_TYPE_AUTH, priv->server ? priv->server : FAIM_LOGIN_SERVER);
143  /*  conn=aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL); */
144  if (!conn) {
145    owl_function_error("owl_aim_login: connection error during AIM login\n");
146    owl_global_set_aimnologgedin(&g);
147    owl_global_set_no_doaimevents(&g);
148    return (-1);
149  }
150
151  /*
152  else if (conn->fd == -1) {
153    if (conn->status & AIM_CONN_STATUS_RESOLVERR) {
154      owl_function_error("owl_aim_login: could not resolve authorize name");
155    } else if (conn->status & AIM_CONN_STATUS_CONNERR) {
156      owl_function_error("owl_aim_login: could not connect to authorizer");
157    } else {
158      owl_function_error("owl_aim_login: unknown connection error");
159    }
160    owl_global_set_aimnologgedin(&g);
161    owl_global_set_no_doaimevents(&g);
162    aim_conn_kill(sess, &conn);
163    return(-1);
164  }
165  */
166
167   
168  aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
169  aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
170
171  aim_conn_addhandler(sess, conn, AIM_CB_FAM_ATH, AIM_CB_ATH_AUTHRESPONSE, faimtest_parse_login, 0);
172  aim_conn_addhandler(sess, conn, AIM_CB_FAM_ATH, AIM_CB_ATH_LOGINRESPONSE, faimtest_parse_authresp, 0);
173  /* aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0); */
174  /* aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0); */
175  /* aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0); */
176   
177  /* start processing AIM events */
178  owl_global_set_doaimevents(&g);
179  /* conn->status |= AIM_CONN_STATUS_INPROGRESS; */
180  owl_function_debugmsg("owl_aim_login: sending login request for %s", screenname);
181  aim_request_login(sess, conn, screenname);
182  owl_function_debugmsg("owl_aim_login: connecting");
183
184  g.aim_nop_timer = g_timeout_add_seconds(30, owl_aim_send_nop, &g);
185
186  return(0);
187}
188
189static gboolean owl_aim_unset_ignorelogin(void *data)
190{
191  owl_global *g = data;
192  owl_global_unset_ignore_aimlogin(g);
193  return FALSE;  /* only run once. */
194}
195
196/* stuff to run once login has been successful */
197void owl_aim_successful_login(const char *screenname)
198{
199  char *buff;
200  owl_function_debugmsg("doing owl_aim_successful_login");
201  owl_global_set_aimloggedin(&g, screenname);
202  owl_global_set_doaimevents(&g); /* this should already be on */
203  owl_function_makemsg("%s logged in", screenname);
204  buff=g_strdup_printf("Logged in to AIM as %s", screenname);
205  owl_function_adminmsg("", buff);
206  g_free(buff);
207
208  owl_function_debugmsg("Successful AIM login for %s", screenname);
209
210  /* start the ingorelogin timer */
211  owl_global_set_ignore_aimlogin(&g);
212  g_timeout_add_seconds(owl_global_get_aim_ignorelogin_timer(&g),
213                        owl_aim_unset_ignorelogin, &g);
214
215  /* aim_ssi_setpresence(owl_global_get_aimsess(&g), 0x00000400); */
216  /* aim_bos_setidle(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), 5000); */
217}
218
219void owl_aim_logout(void)
220{
221  /* need to check if it's connected first, I think */
222  logout(owl_global_get_aimsess(&g));
223
224  if (owl_global_is_aimloggedin(&g)) owl_function_adminmsg("", "Logged out of AIM");
225  owl_global_set_aimnologgedin(&g);
226  owl_global_set_no_doaimevents(&g);
227  if (g.aim_nop_timer) {
228    g_source_remove(g.aim_nop_timer);
229    g.aim_nop_timer = 0;
230  }
231}
232
233void owl_aim_logged_out(void)
234{
235  if (owl_global_is_aimloggedin(&g)) owl_function_adminmsg("", "Logged out of AIM");
236  owl_aim_logout();
237}
238
239void owl_aim_login_error(const char *message)
240{
241  if (message) {
242    owl_function_error("%s", message);
243  } else {
244    owl_function_error("Authentication error on login");
245  }
246  owl_function_beep();
247  owl_global_set_aimnologgedin(&g);
248  owl_global_set_no_doaimevents(&g);
249  if (g.aim_nop_timer) {
250    g_source_remove(g.aim_nop_timer);
251    g.aim_nop_timer = 0;
252  }
253}
254
255/*
256 * I got these constants by skimming libfaim/im.c
257 *
258 * "UNICODE" actually means "UCS-2BE".
259 */
260#define AIM_CHARSET_ISO_8859_1         0x0003
261#define AIM_CHARSET_UNICODE            0x0002
262
263static int owl_aim_do_send(const char *to, const char *msg, int flags)
264{
265  int ret;
266  char *encoded;
267  struct aim_sendimext_args args;
268    gsize len;
269
270  encoded = g_convert(msg, -1, "ISO-8859-1", "UTF-8", NULL, &len, NULL);
271  if (encoded) {
272    owl_function_debugmsg("Encoded outgoing AIM as ISO-8859-1");
273    args.charset = AIM_CHARSET_ISO_8859_1;
274    args.charsubset = 0;
275    args.flags = AIM_IMFLAGS_ISO_8859_1;
276  } else {
277    owl_function_debugmsg("Encoding outgoing IM as UCS-2BE");
278    encoded = g_convert(msg, -1, "UCS-2BE", "UTF-8", NULL, &len, NULL);
279    if (!encoded) {
280      /*
281       * TODO: Strip or HTML-encode characters, or figure out how to
282       * send in a differen charset.
283       */
284      owl_function_error("Unable to encode outgoing AIM message in UCS-2");
285      return 1;
286    }
287
288    args.charset = AIM_CHARSET_UNICODE;
289    args.charsubset = 0;
290    args.flags = AIM_IMFLAGS_UNICODE;
291  }
292
293  args.destsn = to;
294  args.msg = encoded;
295  args.msglen = len;
296  args.flags |= flags;
297
298  ret=aim_im_sendch1_ext(owl_global_get_aimsess(&g), &args);
299
300  g_free(encoded);
301
302  return(ret);
303}
304
305int owl_aim_send_im(const char *to, const char *msg)
306{
307  return owl_aim_do_send(to, msg, 0);
308}
309
310int owl_aim_send_awaymsg(const char *to, const char *msg)
311{
312  return owl_aim_do_send(to, msg, AIM_IMFLAGS_AWAY);
313}
314
315void owl_aim_addbuddy(const char *name)
316{
317
318  aim_ssi_addbuddy(owl_global_get_aimsess(&g), name, "Buddies", NULL, NULL, NULL, 0);
319
320  /*
321  aim_ssi_addbuddy(owl_global_get_aimsess(&g),
322                   name,
323                   "Buddies",
324                   NULL, NULL, NULL,
325                   aim_ssi_waitingforauth(owl_global_get_aimsess(&g)->ssi.local, "Buddies", name));
326  */
327}
328
329void owl_aim_delbuddy(const char *name)
330{
331  aim_ssi_delbuddy(owl_global_get_aimsess(&g), name, "Buddies");
332  owl_buddylist_offgoing(owl_global_get_buddylist(&g), name);
333}
334
335void owl_aim_search(const char *email)
336{
337  int ret;
338
339  owl_function_debugmsg("owl_aim_search: doing search for %s", email);
340  ret=aim_search_address(owl_global_get_aimsess(&g), 
341                         aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_BOS),
342                         email);
343
344  if (ret) owl_function_error("owl_aim_search: aim_search_address returned %i", ret);
345}
346
347
348int owl_aim_set_awaymsg(const char *msg)
349{
350  int len;
351  char *foo;
352  /* there is a max away message lentgh we should check against */
353
354  foo=g_strdup(msg);
355  len=strlen(foo);
356  if (len>500) {
357    foo[500]='\0';
358    len=499;
359  }
360   
361  aim_locate_setprofile(owl_global_get_aimsess(&g),
362                        NULL, NULL, 0,
363                        "us-ascii", foo, len);
364  g_free(foo);
365
366  /*
367  aim_bos_setprofile(owl_global_get_aimsess(&g),
368                     owl_global_get_bosconn(&g),
369                     NULL, NULL, 0, "us-ascii", msg,
370                     strlen(msg), 0);
371  */
372  return(0);
373}
374
375void owl_aim_chat_join(const char *name, int exchange)
376{
377  int ret;
378  aim_conn_t *cur;
379  /*
380  OscarData *od = g->proto_data;
381  const char *name, *exchange;
382  */
383
384  owl_function_debugmsg("Attempting to join chatroom %s exchange %i", name, exchange);
385
386  /*
387  name = g_hash_table_lookup(data, "room");
388  exchange = g_hash_table_lookup(data, "exchange");
389  */
390  if ((cur = aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV))) {
391    owl_function_debugmsg("owl_aim_chat_join: chatnav exists, creating room");
392    aim_chatnav_createroom(owl_global_get_aimsess(&g), cur, name, exchange);
393  } else {
394    /*    struct create_room *cr = g_new0(struct create_room, 1); */
395    owl_function_debugmsg("owl_aim_chat_join: chatnav does not exist, opening chatnav");
396    /*
397    cr->exchange = atoi(exchange);
398    cr->name = g_strdup(name);
399    od->create_rooms = g_slist_append(od->create_rooms, cr);
400    */
401    aim_reqservice(owl_global_get_aimsess(&g),
402                   aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV),
403                   AIM_CONN_TYPE_CHATNAV);
404    aim_reqservice(owl_global_get_aimsess(&g), NULL, AIM_CONN_TYPE_CHATNAV);
405    aim_chatnav_createroom(owl_global_get_aimsess(&g), cur, name, exchange);
406    ret=aim_chat_join(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), exchange, name, 0x0000);
407
408  }
409  return;
410  /******/
411
412
413  /* ret=aim_chat_join(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), exchange, chatroom, 0x0000); */
414  /*
415  ret=aim_chat_join(owl_global_get_aimsess(&g),
416                    aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV), exchange, chatroom, 0x0000);
417  */
418
419  aim_reqservice(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), AIM_CONN_TYPE_CHATNAV);
420  ret = aim_chatnav_createroom(owl_global_get_aimsess(&g),
421                               aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV), name, exchange);
422   ret=aim_chat_join(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), exchange, name, 0x0000);
423 
424}
425
426void owl_aim_chat_leave(const char *chatroom)
427{
428}
429
430int owl_aim_chat_sendmsg(const char *chatroom, const char *msg)
431{
432  return(0);
433}
434
435/* caller must free the return */
436CALLER_OWN char *owl_aim_normalize_screenname(const char *in)
437{
438  char *out;
439  int i, j, k;
440
441  j=strlen(in);
442  out=g_new(char, j+30);
443  k=0;
444  for (i=0; i<j; i++) {
445    if (in[i]!=' ') {
446      out[k]=in[i];
447      k++;
448    }
449  }
450  out[k]='\0';
451  return(out);
452}
453
454int owl_aim_process_events(aim_session_t *aimsess)
455{
456  aim_conn_t *waitingconn = NULL;
457  struct timeval tv;
458  int selstat = 0;
459  struct owlfaim_priv *priv;
460
461  priv = aimsess->aux_data;
462
463  /* do a select without blocking */
464  tv.tv_sec = 0;
465  tv.tv_usec = 0;
466  waitingconn = aim_select(aimsess, &tv, &selstat);
467
468  if (selstat == -1) {
469    owl_aim_logged_out();
470  } else if (selstat == 0) { 
471    /* no events pending */
472  } else if (selstat == 1) { /* outgoing data pending */
473    aim_tx_flushqueue(aimsess);
474  } else if (selstat == 2) { /* incoming data pending */
475    /* printf("selstat == 2\n"); */
476   
477    if (aim_get_command(aimsess, waitingconn) >= 0) {
478      aim_rxdispatch(aimsess);
479    } else {
480      /* printf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype); */
481      /* we should have callbacks for all these, else the library will do the conn_kill for us. */
482      if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
483        if (waitingconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
484          /* printf("disconnected from %s\n", aim_directim_getsn(waitingconn)); */
485          aim_conn_kill(aimsess, &waitingconn);
486          owl_aim_logged_out();
487        }
488      } else {
489        aim_conn_kill(aimsess, &waitingconn);
490        owl_aim_logged_out();
491      }
492      if (!aim_getconn_type(aimsess, AIM_CONN_TYPE_BOS)) {
493        /* printf("major connection error\n"); */
494        owl_aim_logged_out();
495        /* break; */
496      }
497    }
498  }
499  /* exit(0); */
500  return(0);
501}
502
503static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va)
504{
505  return;
506}
507
508static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...)
509{
510  struct owlfaim_priv *priv = sess->aux_data;
511  struct client_info_s info = CLIENTINFO_AIM_KNOWNGOOD;
512   
513  const char *key;
514  va_list ap;
515
516  va_start(ap, fr);
517  key = va_arg(ap, const char *);
518  va_end(ap);
519
520  aim_send_login(sess, fr->conn, priv->screenname, priv->password, &info, key);
521 
522  return(1);
523}
524
525
526static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...)
527{
528  va_list ap;
529  struct aim_authresp_info *info;
530  aim_conn_t *bosconn;
531
532  va_start(ap, fr);
533  info = va_arg(ap, struct aim_authresp_info *);
534  va_end(ap);
535
536  /* printf("Screen name: %s\n", info->sn); */
537  owl_function_debugmsg("doing faimtest_parse_authresp");
538  owl_function_debugmsg("faimtest_parse_authresp: %s", info->sn);
539
540  /*
541   * Check for error.
542   */
543  if (info->errorcode || !info->bosip || !info->cookie) {
544    /*
545    printf("Login Error Code 0x%04x\n", info->errorcode);
546    printf("Error URL: %s\n", info->errorurl);
547    */
548    if (info->errorcode==0x05) {
549      owl_aim_login_error("Incorrect nickname or password.");
550    } else if (info->errorcode==0x11) {
551      owl_aim_login_error("Your account is currently suspended.");
552    } else if (info->errorcode==0x14) {
553      owl_aim_login_error("The AOL Instant Messenger service is temporarily unavailable.");
554    } else if (info->errorcode==0x18) {
555      owl_aim_login_error("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.");
556    } else if (info->errorcode==0x1c) {
557      owl_aim_login_error("The client version you are using is too old.");
558    } else {
559      owl_aim_login_error(NULL);
560    }
561    aim_conn_kill(sess, &fr->conn);
562    return(1);
563  }
564
565  /*
566  printf("Reg status: %d\n", info->regstatus);
567  printf("Email: %s\n", info->email);
568  printf("BOS IP: %s\n", info->bosip);
569  */
570
571  /* printf("Closing auth connection...\n"); */
572  aim_conn_kill(sess, &fr->conn);
573  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, info->bosip))) {
574    /* printf("could not connect to BOS: internal error\n"); */
575    return(1);
576  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {
577    /* printf("could not connect to BOS\n"); */
578    aim_conn_kill(sess, &bosconn);
579    return(1);
580  }
581  owl_global_set_bossconn(&g, bosconn);
582  owl_aim_successful_login(info->sn);
583  addcb_bos(sess, bosconn);
584  aim_sendcookie(sess, bosconn, info->cookielen, info->cookie);
585  return(1);
586}
587
588int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...)
589{
590  owl_function_debugmsg("doing faimtest_flapversion");
591
592#if 0
593  /* XXX fix libfaim to support this */
594  printf("using FLAP version 0x%08x\n", /* aimutil_get32(fr->data)*/ 0xffffffff);
595
596  /*
597   * This is an alternate location for starting the login process.
598   */
599  /* XXX should do more checking to make sure its really the right AUTH conn */
600  if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
601    /* do NOT send a flapversion, request_login will send it if needed */
602    aim_request_login(sess, fr->conn, priv->screenname);
603    /* printf("faimtest: login request sent\n"); */
604  }
605#endif
606
607  return 1;
608}
609
610
611int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...)
612{
613  owl_function_debugmsg("doing faimtest_conncomplete");
614  /* owl_aim_successful_login(info->sn); */
615  return 1;
616}
617
618void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
619{
620  owl_function_debugmsg("doing addcb_bos");
621  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
622  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_bos, 0);
623
624  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0003,                        ssirights, 0);
625  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0006,                        ssidata, 0);
626  aim_conn_addhandler(sess, bosconn, 0x0013,         0x000f,                        ssidatanochange, 0);
627  aim_conn_addhandler(sess, bosconn, 0x0008,         0x0002,                        handlepopup, 0);
628  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0003,                        faimtest_bosrights, 0);
629  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT,           faimtest_handleredirect, 0);
630  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL,  faimtest_reportinterval, 0);
631  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO,         faimtest_parse_buddyrights, 0);
632  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD,               faimtest_parse_motd, 0);
633  aim_conn_addhandler(sess, bosconn, 0x0004,         0x0005,                        faimtest_icbmparaminfo, 0);
634  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR,    faimtest_parse_connerr, 0);
635  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO,         faimtest_locrights, 0);
636  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING,           faimtest_parse_oncoming, 0);
637  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING,           faimtest_parse_offgoing, 0);
638  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING,           faimtest_parse_incoming_im, 0);
639  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR,              faimtest_parse_locerr, 0);
640  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL,         faimtest_parse_misses, 0);
641  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE,         faimtest_parse_ratechange, 0);
642  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL,               faimtest_parse_evilnotify, 0);
643
644  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0001,                        faimtest_parse_searcherror, 0);
645  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0003,                        faimtest_parse_searchreply, 0);
646
647  /*
648  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOK, AIM_CB_LOK_ERROR, faimtest_parse_searcherror, 0);
649  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOK, 0x0003, faimtest_parse_searchreply, 0);
650  */
651 
652  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR,              faimtest_parse_msgerr, 0);
653  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO,           faimtest_parse_userinfo, 0);
654  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK,                faimtest_parse_msgack, 0);
655
656  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0001,                        faimtest_parse_genericerr, 0);
657  aim_conn_addhandler(sess, bosconn, 0x0003,         0x0001,                        faimtest_parse_genericerr, 0);
658  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0001,                        faimtest_parse_genericerr, 0);
659  aim_conn_addhandler(sess, bosconn, 0x0001,         0x000b,                        serverpause, 0);
660  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0012,                        migrate, 0);
661  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG,         offlinemsg, 0);
662  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, offlinemsgdone, 0);
663
664  /*
665  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR,     gaim_connerr, 0);
666  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chatnav, 0);
667  */
668
669  /*
670  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_ERROR,              faimtest_ssi_parseerr, 0);
671  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RIGHTSINFO,         faimtest_ssi_parserights, 0);
672  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_LIST,               faimtest_ssi_parselist, 0);
673  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_NOLIST,             faimtest_ssi_parselist, 0);
674  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_SRVACK,             faimtest_ssi_parseack, 0);
675  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RECVAUTH,           faimtest_ssi_authgiven, 0);
676  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RECVAUTHREQ,        faimtest_ssi_authrequest, 0);
677  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RECVAUTHREP,        faimtest_ssi_authreply, 0);
678  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_ADDED,              faimtest_ssi_gotadded, 0);
679  */
680
681  return;
682}
683
684static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...)
685{
686  owl_function_debugmsg("doing coninitdone_bos");
687
688
689  aim_reqpersonalinfo(sess, fr->conn);
690  aim_ssi_reqrights(sess);
691  aim_ssi_reqdata(sess);
692  aim_locate_reqrights(sess);
693  aim_buddylist_reqrights(sess, fr->conn);
694
695  aim_im_reqparams(sess);
696  /* aim_bos_reqrights(sess, fr->conn); */ /* XXX - Don't call this with ssi */
697
698  owl_function_debugmsg("conninitdone_bos: requesting rights");
699  aim_bos_reqrights(sess, fr->conn); /* XXX - Don't call this with ssi */
700  aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
701  aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE | AIM_PRIVFLAGS_ALLOWMEMBERSINCE);
702
703  return(1);
704}
705
706static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...)
707{
708  aim_clientready(sess, fr->conn);
709  owl_function_debugmsg("conninitdone_admin: initializtion done for admin connection");
710  return(1);
711}
712
713int logout(aim_session_t *sess)
714{
715  aim_session_kill(sess);
716  owl_aim_init();
717
718  owl_function_debugmsg("libfaim logout called");
719  /*
720  if (faimtest_init() == -1)
721    printf("faimtest_init failed\n");
722  */
723
724  return(0);
725}
726
727/**************************************************************************************************/
728
729static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...)
730{
731  struct owlfaim_priv *priv = sess->aux_data;
732  va_list ap;
733  fu16_t code;
734  const char *msg;
735 
736  va_start(ap, fr);
737  code = va_arg(ap, int);
738  msg = va_arg(ap, const char *);
739  va_end(ap);
740 
741  owl_function_error("faimtest_parse_connerr: Code 0x%04x: %s\n", code, msg);
742  aim_conn_kill(sess, &fr->conn); /* this will break the main loop */
743 
744  priv->connected = 0;
745 
746  return 1;
747}
748
749static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...)
750{
751  int status;
752  va_list ap;
753 
754  va_start(ap, fr);
755  status = va_arg(ap, int); /* status code of confirmation request */
756  va_end(ap);
757
758  /* owl_function_debugmsg("faimtest_accountconfirm: Code 0x%04x: %s\n", code, msg); */
759  owl_function_debugmsg("faimtest_accountconfirm: account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown");
760 
761  return 1;
762}
763
764static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
765{
766  fu16_t change = 0, perms, type;
767  int length, str;
768  const char *val;
769  va_list ap;
770 
771  va_start(ap, fr);
772  change = va_arg(ap, int);
773  perms = (fu16_t)va_arg(ap, unsigned int);
774  type = (fu16_t)va_arg(ap, unsigned int);
775  length = va_arg(ap, int);
776  val = va_arg(ap, const char *);
777  str = va_arg(ap, int);
778  va_end(ap);
779 
780  owl_function_debugmsg("faimtest_infochange: info%s: perms = %d, type = %x, length = %d, val = %s", change?" change":"", perms, type, length, str?val:"(not string)");
781 
782  return(1);
783}
784
785
786static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...)
787{
788  va_list ap;
789  struct aim_redirect_data *redir;
790
791  owl_function_debugmsg("faimtest_handledirect:");
792 
793  va_start(ap, fr);
794  redir = va_arg(ap, struct aim_redirect_data *);
795 
796  if (redir->group == 0x0005) {  /* Adverts */
797   
798  } else if (redir->group == 0x0007) {  /* Authorizer */
799    aim_conn_t *tstconn;
800
801    owl_function_debugmsg("faimtest_handledirect: autorizer");
802   
803    tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, redir->ip);
804    if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
805      owl_function_error("faimtest_handleredirect: unable to reconnect with authorizer");
806    } else {
807      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
808      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
809      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_admin, 0);
810      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0);
811      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0);
812      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0);
813      /* Send the cookie to the Auth */
814      aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
815      owl_function_debugmsg("faimtest_handleredirect: sent cookie to authorizer host");
816    }
817  } else if (redir->group == 0x000d) {  /* ChatNav */
818    owl_function_debugmsg("faimtest_handledirect: chatnav");
819    chatnav_redirect(sess, redir);
820  } else if (redir->group == 0x000e) { /* Chat */
821    owl_function_debugmsg("faimtest_handledirect: chat");
822    chat_redirect(sess, redir);
823  } else {
824    owl_function_debugmsg("faimtest_handleredirect: uh oh... got redirect for unknown service 0x%04x!!", redir->group);
825  }
826  va_end(ap);
827  return 1;
828}
829
830static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...)
831{
832  struct aim_icbmparameters *params;
833  va_list ap;
834 
835  va_start(ap, fr);
836  params = va_arg(ap, struct aim_icbmparameters *);
837  va_end(ap);
838 
839  owl_function_debugmsg("faimtest_icbmparaminfo: ICBM Parameters: maxchannel = %d, default flags = 0x%08x, max msg len = %d, max sender evil = %f, max reciever evil = %f, min msg interval = %u",
840                       params->maxchan, params->flags, params->maxmsglen, ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, params->minmsginterval);
841     
842  /*
843  * Set these to your taste, or client medium.  Setting minmsginterval
844  * higher is good for keeping yourself from getting flooded (esp
845  * if you're on a slow connection or something where that would be
846  * useful).
847  */
848  params->maxmsglen = 8000;
849  params->minmsginterval = 0; /* in milliseconds */
850  /* aim_seticbmparam(sess, params); */
851  aim_im_setparams(sess, params);
852 
853  return 1;
854}
855
856static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
857{
858  va_list ap;
859  fu16_t maxbuddies, maxwatchers;
860 
861  va_start(ap, fr);
862  maxbuddies = va_arg(ap, int);
863  maxwatchers = va_arg(ap, int);
864  va_end(ap);
865 
866  owl_function_debugmsg("faimtest_parse_buddyrights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
867 
868  /* aim_ssi_reqrights(sess, fr->conn); */
869  aim_ssi_reqrights(sess);
870 
871  return 1;
872}
873
874static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
875{
876  va_list ap;
877  fu16_t maxpermits, maxdenies;
878 
879  va_start(ap, fr);
880  maxpermits = va_arg(ap, int);
881  maxdenies = va_arg(ap, int);
882  va_end(ap);
883 
884  owl_function_debugmsg("faimtest_bosrights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
885  aim_clientready(sess, fr->conn);
886  owl_function_debugmsg("officially connected to BOS.");
887  aim_icq_reqofflinemsgs(sess);
888  return 1;
889}
890
891static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
892{
893  va_list ap;
894  fu16_t maxsiglen;
895 
896  va_start(ap, fr);
897  maxsiglen = va_arg(ap, int);
898  va_end(ap);
899
900  owl_function_debugmsg("faimtest_locrights: rights: max signature length = %d\n", maxsiglen);
901 
902  return(1);
903}
904
905static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
906{
907  struct owlfaim_priv *priv = sess->aux_data;
908  va_list ap;
909  fu16_t interval;
910
911  va_start(ap, fr);
912  interval = va_arg(ap, int);
913  va_end(ap);
914
915  owl_function_debugmsg("faimtest_reportinterval: %d (seconds?)\n", interval);
916
917  if (!priv->connected) {
918    priv->connected++;
919  }
920  /* aim_reqicbmparams(sess); */
921  aim_im_reqparams(sess);
922  /* kretch */
923  return 1;
924}
925
926static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
927{
928  const char *msg;
929  fu16_t id;
930  va_list ap;
931  static int codeslen = 5;
932  static const char *codes[] = {
933    "Unknown",
934    "Mandatory upgrade",
935    "Advisory upgrade",
936    "System bulletin",
937    "Top o' the world!"
938  };
939
940  va_start(ap, fr);
941  id = va_arg(ap, int);
942  msg = va_arg(ap, const char *);
943  va_end(ap);
944
945  owl_function_debugmsg("faimtest_parse_motd: %s (%d / %s)\n", msg?msg:"nomsg", id, (id < codeslen)?codes[id]:"unknown");
946 
947  return 1;
948}
949
950/*
951static void printuserflags(fu16_t flags)
952{
953  if (flags & AIM_FLAG_UNCONFIRMED) printf("UNCONFIRMED ");
954  if (flags & AIM_FLAG_ADMINISTRATOR) printf("ADMINISTRATOR ");
955  if (flags & AIM_FLAG_AOL) printf("AOL ");
956  if (flags & AIM_FLAG_OSCAR_PAY) printf("OSCAR_PAY ");
957  if (flags & AIM_FLAG_FREE) printf("FREE ");
958  if (flags & AIM_FLAG_AWAY) printf("AWAY ");
959  if (flags & AIM_FLAG_ICQ) printf("ICQ ");
960  if (flags & AIM_FLAG_WIRELESS) printf("WIRELESS ");
961  if (flags & AIM_FLAG_ACTIVEBUDDY) printf("ACTIVEBUDDY ");
962 
963  return;
964}
965*/
966
967static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
968{
969  aim_userinfo_t *userinfo;
970  const char *prof_encoding = NULL;
971  const char *prof = NULL;
972  fu16_t inforeq = 0;
973  owl_buddy *b;
974  va_list ap;
975  va_start(ap, fr);
976  userinfo = va_arg(ap, aim_userinfo_t *);
977  inforeq = (fu16_t)va_arg(ap, unsigned int);
978  prof_encoding = va_arg(ap, const char *);
979  prof = va_arg(ap, const char *);
980  va_end(ap);
981
982  /* right now the only reason we call this is for idle times */
983  owl_function_debugmsg("parse_userinfo sn: %s idle: %i", userinfo->sn, userinfo->idletime);
984  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g),
985                                userinfo->sn);
986  if (!b) return(1);
987  owl_buddy_set_idle_since(b, userinfo->idletime);
988  return(1);
989
990  /*
991  printf("userinfo: sn: %s\n", userinfo->sn);
992  printf("userinfo: warnlevel: %f\n", aim_userinfo_warnlevel(userinfo));
993  printf("userinfo: flags: 0x%04x = ", userinfo->flags);
994  printuserflags(userinfo->flags);
995  printf("\n");
996  */
997
998  /*
999  printf("userinfo: membersince: %lu\n", userinfo->membersince);
1000  printf("userinfo: onlinesince: %lu\n", userinfo->onlinesince);
1001  printf("userinfo: idletime: 0x%04x\n", userinfo->idletime);
1002  printf("userinfo: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
1003  */
1004
1005  /*
1006  if (inforeq == AIM_GETINFO_GENERALINFO) {
1007    owl_function_debugmsg("userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1008    owl_function_debugmsg("userinfo: prof: %s\n", prof ? prof : "[none]");
1009  } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
1010    owl_function_debugmsg("userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1011    owl_function_debugmsg("userinfo: awaymsg: %s\n", prof ? prof : "[none]");
1012  } else if (inforeq == AIM_GETINFO_CAPABILITIES) {
1013    owl_function_debugmsg("userinfo: capabilities: see above\n");
1014  } else {
1015    owl_function_debugmsg("userinfo: unknown info request\n");
1016  }
1017  */
1018  return(1);
1019}
1020
1021/*
1022 * Channel 1: Standard Message
1023 */
1024static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args)
1025{
1026  owl_message *m;
1027  char *stripmsg, *nz_screenname, *wrapmsg;
1028  char *realmsg = NULL;
1029
1030  if (!args->msg) {
1031    realmsg = g_strdup("");
1032  } else if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1033    realmsg = g_convert(args->msg, args->msglen, "UTF-8", "UCS-2BE",
1034                        NULL, NULL, NULL);
1035  } else if(args->icbmflags & AIM_IMFLAGS_ISO_8859_1) {
1036    realmsg = g_convert(args->msg, args->msglen, "UTF-8", "ISO-8859-1",
1037                        NULL, NULL, NULL);
1038  } else {
1039    realmsg = g_strdup(args->msg);
1040  }
1041
1042  if (!realmsg) {
1043    realmsg = g_strdup("[Error decoding incoming IM]");
1044  }
1045
1046  owl_function_debugmsg("faimtest_parse_incoming_im_chan1: message from: %s", userinfo->sn?userinfo->sn:"");
1047  /* create a message, and put it on the message queue */
1048  stripmsg=owl_text_htmlstrip(realmsg);
1049  wrapmsg=owl_text_wordwrap(stripmsg, 70);
1050  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1051  m=g_new(owl_message, 1);
1052  owl_message_create_aim(m,
1053                         nz_screenname,
1054                         owl_global_get_aim_screenname(&g),
1055                         wrapmsg,
1056                         OWL_MESSAGE_DIRECTION_IN,
1057                         0);
1058  if (args->icbmflags & AIM_IMFLAGS_AWAY) owl_message_set_attribute(m, "isauto", "");
1059  owl_global_messagequeue_addmsg(&g, m);
1060  g_free(stripmsg);
1061  g_free(wrapmsg);
1062  g_free(nz_screenname);
1063  g_free(realmsg);
1064
1065  return(1);
1066
1067  /* TODO: Multipart? See history from before 1.8 release. */
1068}
1069
1070/*
1071 * Channel 2: Rendevous Request
1072 */
1073static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
1074{
1075  /*
1076  printf("rendezvous: source sn = %s\n", userinfo->sn);
1077  printf("rendezvous: \twarnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1078  printf("rendezvous: \tclass = 0x%04x = ", userinfo->flags);
1079  printuserflags(userinfo->flags);
1080  printf("\n");
1081 
1082  printf("rendezvous: \tonlinesince = %lu\n", userinfo->onlinesince);
1083  printf("rendezvous: \tidletime = 0x%04x\n", userinfo->idletime);
1084 
1085  printf("rendezvous: message/description = %s\n", args->msg);
1086  printf("rendezvous: encoding = %s\n", args->encoding);
1087  printf("rendezvous: language = %s\n", args->language);
1088  */
1089 
1090  if (args->reqclass == AIM_CAPS_SENDFILE) {
1091    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: send file!");
1092  } else if (args->reqclass == AIM_CAPS_CHAT) {
1093    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: chat invite: %s, %i, %i", args->info.chat.roominfo.name, args->info.chat.roominfo.exchange, args->info.chat.roominfo.instance);
1094    /*
1095    printf("chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1096    printf("chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1097    printf("chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1098    */
1099    /* Automatically join room... */
1100    /* printf("chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); */
1101
1102    /* aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance); */
1103  } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1104    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: Buddy Icon from %s, length = %u\n",
1105                          userinfo->sn, args->info.icon.length);
1106  } else if (args->reqclass == AIM_CAPS_ICQRTF) {
1107    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: RTF message from %s: (fgcolor = 0x%08x, bgcolor = 0x%08x) %s\n",
1108                          userinfo->sn, args->info.rtfmsg.fgcolor, args->info.rtfmsg.bgcolor, args->info.rtfmsg.rtfmsg);
1109  } else {
1110    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: icbm: unknown reqclass (%d)\n", args->reqclass);
1111  }
1112  return 1;
1113}
1114
1115static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1116{
1117  fu16_t channel;
1118  aim_userinfo_t *userinfo;
1119  va_list ap;
1120  int ret = 0;
1121 
1122  va_start(ap, fr);
1123  channel = (fu16_t)va_arg(ap, unsigned int);
1124  userinfo = va_arg(ap, aim_userinfo_t *);
1125 
1126  if (channel == 1) {
1127    struct aim_incomingim_ch1_args *args;
1128    args = va_arg(ap, struct aim_incomingim_ch1_args *);
1129    ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, args);
1130  } else if (channel == 2) {
1131    struct aim_incomingim_ch2_args *args;
1132    args = va_arg(ap, struct aim_incomingim_ch2_args *);
1133    ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, args);
1134  } else {
1135    owl_function_debugmsg("faimtest_parse_incoming_im: unsupported channel 0x%04x\n", channel);
1136  }
1137  va_end(ap);
1138  owl_function_debugmsg("faimtest_parse_incoming_im: done with ICBM handling (ret = %d)\n", ret);
1139  return 1;
1140}
1141
1142static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1143{
1144  aim_userinfo_t *userinfo;
1145  char *nz_screenname;
1146  owl_buddy *b;
1147  va_list ap;
1148  va_start(ap, fr);
1149  userinfo = va_arg(ap, aim_userinfo_t *);
1150  va_end(ap);
1151
1152  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1153 
1154  owl_buddylist_oncoming(owl_global_get_buddylist(&g), nz_screenname);
1155
1156  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1157    owl_function_debugmsg("faimtest_parseoncoming: in empty part of userinfo present and present idle");
1158  }
1159
1160  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g), nz_screenname);
1161  if (!b) {
1162    owl_function_debugmsg("Error: parse_oncoming setting idle time with no buddy present.");
1163    return(1);
1164  }
1165  if (userinfo->idletime==0) {
1166    owl_buddy_set_unidle(b);
1167  } else {
1168    owl_buddy_set_idle(b);
1169    owl_buddy_set_idle_since(b, userinfo->idletime);
1170  }
1171
1172  if (userinfo->flags & AIM_FLAG_AWAY) {
1173    owl_function_debugmsg("parse_oncoming sn: %s away flag!", userinfo->sn);
1174  }
1175 
1176  owl_function_debugmsg("parse_oncoming sn: %s idle: %i", userinfo->sn, userinfo->idletime);
1177   
1178  g_free(nz_screenname);
1179 
1180  /*
1181    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1182    time(NULL),
1183    userinfo->sn, userinfo->flags,
1184    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1185    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1186    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1187    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1188    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1189    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1190    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1191    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1192    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1193    userinfo->capabilities);
1194  */
1195  return(1);
1196}
1197
1198static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1199{
1200  aim_userinfo_t *userinfo;
1201  char *nz_screenname;
1202  va_list ap;
1203 
1204  va_start(ap, fr);
1205  userinfo = va_arg(ap, aim_userinfo_t *);
1206  va_end(ap);
1207
1208  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1209  owl_buddylist_offgoing(owl_global_get_buddylist(&g), nz_screenname);
1210  g_free(nz_screenname);
1211
1212  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1213    owl_function_debugmsg("parse_offgoing sn: %s idle time %i", userinfo->sn, userinfo->idletime);
1214  }
1215
1216  /*
1217  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1218         time(NULL),
1219         userinfo->sn, userinfo->flags,
1220         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1221         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1222         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1223         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1224         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1225         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1226         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1227         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1228         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1229         userinfo->capabilities);
1230  */
1231 
1232  return 1;
1233}
1234
1235/* Used by chat as well. */
1236int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1237{
1238  va_list ap;
1239  fu16_t reason;
1240 
1241  va_start(ap, fr);
1242  reason = (fu16_t)va_arg(ap, unsigned int);
1243  va_end(ap);
1244 
1245  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1246  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1247 
1248  return 1;
1249}
1250
1251static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1252{
1253  va_list ap;
1254  const char *destsn;
1255  fu16_t reason;
1256 
1257  va_start(ap, fr);
1258  reason = (fu16_t)va_arg(ap, unsigned int);
1259  destsn = va_arg(ap, const char *);
1260  va_end(ap);
1261 
1262  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1263  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1264
1265  if (reason==4) {
1266    owl_function_adminmsg("", "Could not send AIM message, user not logged on");
1267  }
1268 
1269  return 1;
1270}
1271
1272static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1273{
1274  va_list ap;
1275  const char *destsn;
1276  fu16_t reason;
1277 
1278  va_start(ap, fr);
1279  reason = (fu16_t)va_arg(ap, unsigned int);
1280  destsn = va_arg(ap, const char *);
1281  va_end(ap);
1282 
1283  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1284  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1285 
1286  return 1;
1287}
1288
1289static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1290{
1291  static const char *missedreasons[] = {
1292    "Invalid (0)",
1293    "Message too large",
1294    "Rate exceeded",
1295    "Evil Sender",
1296    "Evil Receiver"
1297  };
1298  static int missedreasonslen = 5;
1299 
1300  va_list ap;
1301  fu16_t chan, nummissed, reason;
1302  aim_userinfo_t *userinfo;
1303 
1304  va_start(ap, fr);
1305  chan = (fu16_t)va_arg(ap, unsigned int);
1306  userinfo = va_arg(ap, aim_userinfo_t *);
1307  nummissed = (fu16_t)va_arg(ap, unsigned int);
1308  reason = (fu16_t)va_arg(ap, unsigned int);
1309  va_end(ap);
1310 
1311  owl_function_debugmsg("faimtest_parse_misses: missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
1312 
1313  return 1;
1314}
1315
1316/*
1317 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1318 */
1319static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1320{
1321  va_list ap;
1322  fu16_t type;
1323  const char *sn = NULL;
1324 
1325  va_start(ap, fr);
1326  type = (fu16_t)va_arg(ap, unsigned int);
1327  sn = va_arg(ap, const char *);
1328  va_end(ap);
1329 
1330  owl_function_debugmsg("faimtest_parse_msgack: 0x%04x / %s\n", type, sn);
1331 
1332  return 1;
1333}
1334
1335static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1336{
1337  static const char *codes[5] = {
1338    "invalid",
1339    "change",
1340    "warning",
1341    "limit",
1342    "limit cleared"
1343  };
1344  va_list ap;
1345  fu16_t code, rateclass;
1346  fu32_t windowsize, clear, alert, limit, disconnect;
1347  fu32_t currentavg, maxavg;
1348 
1349  va_start(ap, fr); 
1350 
1351  /* See code explanations below */
1352  code = (fu16_t)va_arg(ap, unsigned int);
1353 
1354  /*
1355   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1356   */
1357  rateclass = (fu16_t)va_arg(ap, unsigned int);
1358 
1359  /*
1360   * Not sure what this is exactly.  I think its the temporal
1361   * relation factor (ie, how to make the rest of the numbers
1362   * make sense in the real world).
1363   */
1364  windowsize = va_arg(ap, fu32_t);
1365 
1366  /* Explained below */
1367  clear = va_arg(ap, fu32_t);
1368  alert = va_arg(ap, fu32_t);
1369  limit = va_arg(ap, fu32_t);
1370  disconnect = va_arg(ap, fu32_t);
1371  currentavg = va_arg(ap, fu32_t);
1372  maxavg = va_arg(ap, fu32_t);
1373 
1374  va_end(ap);
1375 
1376  owl_function_debugmsg("faimtest_parse_ratechange: rate %s (rate class 0x%04x): curavg = %u, maxavg = %u, alert at %u, clear warning at %u, limit at %u, disconnect at %u (window size = %u)",
1377                        (code < 5)?codes[code]:"invalid",
1378                        rateclass,
1379                        currentavg, maxavg,
1380                        alert, clear,
1381                        limit, disconnect,
1382                        windowsize);
1383  return 1;
1384}
1385
1386static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1387{
1388  va_list ap;
1389  fu16_t newevil;
1390  aim_userinfo_t *userinfo;
1391 
1392  va_start(ap, fr);
1393  newevil = (fu16_t)va_arg(ap, unsigned int);
1394  userinfo = va_arg(ap, aim_userinfo_t *);
1395  va_end(ap);
1396 
1397  /*
1398   * Evil Notifications that are lacking userinfo->sn are anon-warns
1399   * if they are an evil increases, but are not warnings at all if its
1400   * a decrease (its the natural backoff happening).
1401   *
1402   * newevil is passed as an int representing the new evil value times
1403   * ten.
1404   */
1405  owl_function_debugmsg("faimtest_parse_evilnotify: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1406 
1407  return 1;
1408}
1409
1410static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1411{
1412  va_list ap;
1413  const char *address, *SNs;
1414  int num, i;
1415  GPtrArray *list;
1416 
1417  va_start(ap, fr);
1418  address = va_arg(ap, const char *);
1419  num = va_arg(ap, int);
1420  SNs = va_arg(ap, const char *);
1421  va_end(ap);
1422
1423  list = g_ptr_array_new();
1424 
1425  owl_function_debugmsg("faimtest_parse_searchreply: E-Mail Search Results for %s: ", address);
1426  for (i=0; i<num; i++) {
1427    owl_function_debugmsg("  %s", &SNs[i*(MAXSNLEN+1)]);
1428    g_ptr_array_add(list, (void *)&SNs[i*(MAXSNLEN+1)]);
1429  }
1430  owl_function_aimsearch_results(address, list);
1431  g_ptr_array_free(list, true);
1432  return 1;
1433}
1434
1435static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1436{
1437  va_list ap;
1438  const char *address;
1439 
1440  va_start(ap, fr);
1441  address = va_arg(ap, const char *);
1442  va_end(ap);
1443
1444  owl_function_error("No results searching for %s", address);
1445  owl_function_debugmsg("faimtest_parse_searcherror: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1446 
1447  return(1);
1448}
1449
1450static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1451{
1452  va_list ap;
1453  const char *msg, *url;
1454  fu16_t width, height, delay;
1455 
1456  va_start(ap, fr);
1457  msg = va_arg(ap, const char *);
1458  url = va_arg(ap, const char *);
1459  width = va_arg(ap, unsigned int);
1460  height = va_arg(ap, unsigned int);
1461  delay = va_arg(ap, unsigned int);
1462  va_end(ap);
1463 
1464  owl_function_debugmsg("handlepopup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url);
1465 
1466  return 1;
1467}
1468
1469static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1470{
1471  aim_sendpauseack(sess, fr->conn);
1472  return 1;
1473}
1474
1475static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1476{
1477  va_list ap;
1478  aim_conn_t *bosconn;
1479  const char *bosip;
1480  fu8_t *cookie;
1481 
1482  va_start(ap, fr);
1483  bosip = va_arg(ap, const char *);
1484  cookie = va_arg(ap, fu8_t *);
1485  va_end(ap);
1486 
1487  owl_function_debugmsg("migrate: migration in progress -- new BOS is %s -- disconnecting", bosip);
1488  aim_conn_kill(sess, &fr->conn);
1489 
1490  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1491    owl_function_debugmsg("migrate: could not connect to BOS: internal error");
1492    return 1;
1493  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1494    owl_function_debugmsg("migrate: could not connect to BOS");
1495    aim_conn_kill(sess, &bosconn);
1496    return 1;
1497  }
1498 
1499  /* Login will happen all over again. */
1500  addcb_bos(sess, bosconn);
1501  /* aim_sendcookie(sess, bosconn, cookie); */ /********/
1502  return 1;
1503}
1504
1505static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1506{
1507  owl_function_debugmsg("ssirights: got SSI rights, requesting data\n");
1508  /* aim_ssi_reqdata(sess, fr->conn, 0, 0x0000); */
1509  aim_ssi_reqdata(sess);
1510 
1511  return(1);
1512}
1513
1514static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1515{
1516  va_list ap;
1517  fu8_t fmtver;
1518  fu16_t itemcount;
1519  fu32_t stamp;
1520  struct aim_ssi_item *list;
1521  /*
1522  struct aim_ssi_item *curitem;
1523  struct aim_ssi_item *l;
1524  */
1525 
1526  va_start(ap, fr);
1527  fmtver = va_arg(ap, unsigned int);
1528  itemcount = va_arg(ap, unsigned int);
1529  stamp = va_arg(ap, fu32_t);
1530  list = va_arg(ap, struct aim_ssi_item *);
1531  va_end(ap);
1532 
1533  owl_function_debugmsg("ssiddata: got SSI data (0x%02x, %d items, %u)", fmtver, itemcount, stamp);
1534  /*
1535  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
1536    for (l = list; l; l = l->next) {
1537      owl_function_debugmsg("\t0x%04x (%s) - 0x%04x/0x%04x", l->type, l->name, l->gid, l->bid);
1538    }
1539  }
1540  */
1541  aim_ssi_enable(sess);
1542 
1543  return 1;
1544}
1545
1546static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1547{
1548  owl_function_debugmsg("ssidatanochange: server says we have the latest SSI data already");
1549  /* aim_ssi_enable(sess, fr->conn); */
1550  aim_ssi_enable(sess);
1551  return 1;
1552}
1553
1554static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1555{
1556  va_list ap;
1557  struct aim_icq_offlinemsg *msg;
1558 
1559  va_start(ap, fr);
1560  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1561  va_end(ap);
1562 
1563  if (msg->type == 0x0001) {
1564    owl_function_debugmsg("offlinemsg: from %u at %d/%d/%d %02d:%02d : %s", msg->sender, msg->year, msg->month, msg->day, msg->hour, msg->minute, msg->msg);
1565  } else {
1566    owl_function_debugmsg("unknown offline message type 0x%04x", msg->type);
1567  }
1568  return 1;
1569}
1570
1571static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1572{
1573  /* Tell the server to delete them. */
1574  owl_function_debugmsg("offlinemsg done: ");
1575  aim_icq_ackofflinemsgs(sess);
1576  return 1;
1577}
1578
1579
1580/******************** chat.c **************************/
1581
1582static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1583{
1584  va_list ap;
1585  aim_userinfo_t *userinfo;
1586  int count;
1587  /* int i; */
1588 
1589  va_start(ap, fr);
1590  count = va_arg(ap, int);
1591  userinfo = va_arg(ap, aim_userinfo_t *);
1592  va_end(ap);
1593
1594  owl_function_debugmsg("In faimtest_chat_join");
1595  /*
1596  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1597  for (i = 0; i < count; i++)
1598    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1599  */
1600  return 1;
1601}
1602
1603static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1604{
1605  aim_userinfo_t *userinfo;
1606  va_list ap;
1607  int count;
1608  /* int i; */
1609
1610 
1611  va_start(ap, fr);
1612  count = va_arg(ap, int);
1613  userinfo = va_arg(ap, aim_userinfo_t *);
1614  va_end(ap);
1615 
1616  /*
1617    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1618   
1619    for (i = 0; i < count; i++)
1620    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1621  */
1622  return 1;
1623}
1624
1625static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1626{
1627  va_list ap;
1628  aim_userinfo_t *userinfo;
1629  struct aim_chat_roominfo *roominfo;
1630  const char *roomname;
1631  int usercount;
1632  const char *roomdesc;
1633  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1634  fu32_t creationtime;
1635  const char *croomname;
1636  /* int i; */
1637 
1638  croomname = aim_chat_getname(fr->conn);
1639 
1640  va_start(ap, fr);
1641  roominfo = va_arg(ap, struct aim_chat_roominfo *);
1642  roomname = va_arg(ap, const char *);
1643  usercount = va_arg(ap, int);
1644  userinfo = va_arg(ap, aim_userinfo_t *);
1645  roomdesc = va_arg(ap, const char *);
1646  flags = (fu16_t)va_arg(ap, unsigned int);
1647  creationtime = va_arg(ap, fu32_t);
1648  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1649  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
1650  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
1651  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
1652  va_end(ap);
1653
1654  owl_function_debugmsg("In faimtest_chat_infoupdate");
1655  /*
1656  printf("chat: %s:  info update:\n", croomname);
1657  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
1658  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
1659  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
1660  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
1661
1662  for (i = 0; i < usercount; i++)
1663    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
1664 
1665  owl_function_debugmsg("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
1666         croomname, flags,
1667         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1668         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1669         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1670         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1671  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
1672  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
1673  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
1674  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
1675  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
1676  */
1677 
1678  return(1);
1679}
1680
1681static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
1682{
1683  va_list ap;
1684  aim_userinfo_t *userinfo;
1685  const char *msg;
1686  char tmpbuf[1152];
1687 
1688  va_start(ap, fr);
1689  userinfo = va_arg(ap, aim_userinfo_t *);     
1690  msg = va_arg(ap, const char *);
1691  va_end(ap);
1692
1693  owl_function_debugmsg("in faimtest_chat_incomingmsg");
1694
1695  /*
1696  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
1697  */
1698 
1699  /*
1700   * Do an echo for testing purposes.  But not for ourselves ("oops!")
1701   */
1702  if (strcmp(userinfo->sn, sess->sn) != 0) {
1703    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
1704    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
1705  }
1706 
1707  return 1;
1708}
1709
1710static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
1711{
1712  owl_function_debugmsg("faimtest_conninitdone_chat:");
1713
1714  aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
1715  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
1716  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
1717  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
1718  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
1719 
1720  aim_clientready(sess, fr->conn);
1721 
1722  owl_function_debugmsg("Chat ready");
1723
1724  /*
1725    chatcon = find_oscar_chat_by_conn(gc, fr->conn);
1726    chatcon->id = id;
1727    chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show);
1728  */
1729  return(1);
1730}
1731
1732void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1733{
1734  aim_conn_t *tstconn;
1735
1736  owl_function_debugmsg("in faimtest_chatnav_redirect");
1737 
1738  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
1739  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1740    /* printf("unable to connect to chat(nav) server\n"); */
1741    if (tstconn)
1742      aim_conn_kill(sess, &tstconn);
1743    return;
1744  }
1745 
1746  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1747  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
1748  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
1749  /* printf("chatnav: connected\n"); */
1750  return;
1751}
1752
1753/* XXX this needs instance too */
1754void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1755{
1756  aim_conn_t *tstconn;
1757
1758  owl_function_debugmsg("in chat_redirect");
1759 
1760  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
1761  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1762    /* printf("unable to connect to chat server\n"); */
1763    if (tstconn) aim_conn_kill(sess, &tstconn);
1764    return; 
1765  }             
1766  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
1767 
1768  /*
1769   * We must do this to attach the stored name to the connection!
1770   */
1771  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
1772  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1773  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
1774  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
1775  return;       
1776}
1777
1778typedef struct _owl_aim_event_source { /*noproto*/
1779  GSource source;
1780  aim_session_t *sess;
1781  GPtrArray *fds;
1782} owl_aim_event_source;
1783
1784static void truncate_pollfd_list(owl_aim_event_source *event_source, int len)
1785{
1786  GPollFD *fd;
1787  int i;
1788  if (len < event_source->fds->len) {
1789    owl_function_debugmsg("Truncating AIM PollFDs to %d, was %d", len, event_source->fds->len);
1790    for (i = len; i < event_source->fds->len; i++) {
1791      fd = event_source->fds->pdata[i];
1792      g_source_remove_poll(&event_source->source, fd);
1793      g_free(fd);
1794    }
1795    g_ptr_array_remove_range(event_source->fds, len, event_source->fds->len - len);
1796  }
1797}
1798
1799static gboolean owl_aim_event_source_prepare(GSource *source, int *timeout)
1800{
1801  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
1802  aim_conn_t *cur;
1803  GPollFD *fd;
1804  int i;
1805
1806  /* AIM HACK:
1807   *
1808   *  The problem - I'm not sure where to hook into the owl/faim
1809   *  interface to keep track of when the AIM socket(s) open and
1810   *  close. In particular, the bosconn thing throws me off. So,
1811   *  rather than register particular dispatchers for AIM, I look up
1812   *  the relevant FDs and add them to select's watch lists, then
1813   *  check for them individually before moving on to the other
1814   *  dispatchers. --asedeno
1815   */
1816  i = 0;
1817  for (cur = event_source->sess->connlist; cur; cur = cur->next) {
1818    if (cur->fd != -1) {
1819      /* Add new GPollFDs as necessary. */
1820      if (i == event_source->fds->len) {
1821        fd = g_new0(GPollFD, 1);
1822        g_ptr_array_add(event_source->fds, fd);
1823        g_source_add_poll(source, fd);
1824        owl_function_debugmsg("Allocated new AIM PollFD, len = %d", event_source->fds->len);
1825      }
1826      fd = event_source->fds->pdata[i];
1827      fd->fd = cur->fd;
1828      fd->events = G_IO_IN | G_IO_HUP | G_IO_ERR;
1829      if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
1830        /* AIM login requires checking writable sockets. See aim_select. */
1831        fd->events |= G_IO_OUT;
1832      }
1833      i++;
1834    }
1835  }
1836  /* If the number of GPollFDs went down, clean up. */
1837  truncate_pollfd_list(event_source, i);
1838
1839  *timeout = -1;
1840  return FALSE;
1841}
1842
1843static gboolean owl_aim_event_source_check(GSource *source)
1844{
1845  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
1846  int i;
1847
1848  for (i = 0; i < event_source->fds->len; i++) {
1849    GPollFD *fd = event_source->fds->pdata[i];
1850    if (fd->revents & fd->events)
1851      return TRUE;
1852  }
1853  return FALSE;
1854}
1855
1856static gboolean owl_aim_event_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
1857{
1858  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
1859  owl_aim_process_events(event_source->sess);
1860  return TRUE;
1861}
1862
1863static void owl_aim_event_source_finalize(GSource *source)
1864{
1865  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
1866  /* Don't remove the GPollFDs. We are being finalized, so they'll be removed
1867   * for us. Moreover, glib will fire asserts if g_source_remove_poll is called
1868   * on a source which has been destroyed (which occurs when g_source_remove is
1869   * called on it). */
1870  owl_ptr_array_free(event_source->fds, g_free);
1871}
1872
1873static GSourceFuncs aim_event_funcs = {
1874  owl_aim_event_source_prepare,
1875  owl_aim_event_source_check,
1876  owl_aim_event_source_dispatch,
1877  owl_aim_event_source_finalize,
1878};
1879
1880GSource *owl_aim_event_source_new(aim_session_t *sess)
1881{
1882  GSource *source;
1883  owl_aim_event_source *event_source;
1884
1885  source = g_source_new(&aim_event_funcs, sizeof(owl_aim_event_source));
1886  event_source = (owl_aim_event_source *)source;
1887  event_source->sess = sess;
1888  /* TODO: When we depend on glib 2.22+, use g_ptr_array_new_with_free_func. */
1889  event_source->fds = g_ptr_array_new();
1890  return source;
1891}
Note: See TracBrowser for help on using the repository browser.