source: aim.c @ 3234121

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