source: aim.c @ f6ab6ee

release-1.8release-1.9
Last change on this file since f6ab6ee was 24b2f18, checked in by David Benjamin <davidben@mit.edu>, 10 years ago
Move actual truncation inside conditional. Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
  • Property mode set to 100644
File size: 62.9 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
1067  return(1);
1068
1069  owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: message: %s\n", realmsg);
1070 
1071  if (args->icbmflags & AIM_IMFLAGS_MULTIPART) {
1072    aim_mpmsg_section_t *sec;
1073    int z;
1074
1075    owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: multipart: this message has %d parts\n", args->mpmsg.numparts);
1076   
1077    for (sec = args->mpmsg.parts, z = 0; sec; sec = sec->next, z++) {
1078      if ((sec->charset == 0x0000) || (sec->charset == 0x0003) || (sec->charset == 0xffff)) {
1079        owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, msg = %s\n", z, sec->charset, sec->charsubset, sec->data);
1080      } else {
1081        owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, binary or UNICODE data\n", z, sec->charset, sec->charsubset);
1082      }
1083    }
1084  }
1085 
1086  if (args->icbmflags & AIM_IMFLAGS_HASICON) {
1087    /* aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon"); */
1088    owl_function_debugmsg("faimtest_parse_incoming_im_chan1: icbm: their icon: iconstamp = %ld, iconlen = 0x%08x, iconsum = 0x%04x\n", args->iconstamp, args->iconlen, args->iconsum);
1089  }
1090
1091  g_free(realmsg);
1092
1093  return(1);
1094}
1095
1096/*
1097 * Channel 2: Rendevous Request
1098 */
1099static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
1100{
1101  /*
1102  printf("rendezvous: source sn = %s\n", userinfo->sn);
1103  printf("rendezvous: \twarnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1104  printf("rendezvous: \tclass = 0x%04x = ", userinfo->flags);
1105  printuserflags(userinfo->flags);
1106  printf("\n");
1107 
1108  printf("rendezvous: \tonlinesince = %lu\n", userinfo->onlinesince);
1109  printf("rendezvous: \tidletime = 0x%04x\n", userinfo->idletime);
1110 
1111  printf("rendezvous: message/description = %s\n", args->msg);
1112  printf("rendezvous: encoding = %s\n", args->encoding);
1113  printf("rendezvous: language = %s\n", args->language);
1114  */
1115 
1116  if (args->reqclass == AIM_CAPS_SENDFILE) {
1117    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: send file!");
1118  } else if (args->reqclass == AIM_CAPS_CHAT) {
1119    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);
1120    /*
1121    printf("chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1122    printf("chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1123    printf("chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1124    */
1125    /* Automatically join room... */
1126    /* printf("chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); */
1127
1128    /* aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance); */
1129  } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1130    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: Buddy Icon from %s, length = %u\n",
1131                          userinfo->sn, args->info.icon.length);
1132  } else if (args->reqclass == AIM_CAPS_ICQRTF) {
1133    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: RTF message from %s: (fgcolor = 0x%08x, bgcolor = 0x%08x) %s\n",
1134                          userinfo->sn, args->info.rtfmsg.fgcolor, args->info.rtfmsg.bgcolor, args->info.rtfmsg.rtfmsg);
1135  } else {
1136    owl_function_debugmsg("faimtest_parse_incoming_im_chan2: icbm: unknown reqclass (%d)\n", args->reqclass);
1137  }
1138  return 1;
1139}
1140
1141static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1142{
1143  fu16_t channel;
1144  aim_userinfo_t *userinfo;
1145  va_list ap;
1146  int ret = 0;
1147 
1148  va_start(ap, fr);
1149  channel = (fu16_t)va_arg(ap, unsigned int);
1150  userinfo = va_arg(ap, aim_userinfo_t *);
1151 
1152  if (channel == 1) {
1153    struct aim_incomingim_ch1_args *args;
1154    args = va_arg(ap, struct aim_incomingim_ch1_args *);
1155    ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, args);
1156  } else if (channel == 2) {
1157    struct aim_incomingim_ch2_args *args;
1158    args = va_arg(ap, struct aim_incomingim_ch2_args *);
1159    ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, args);
1160  } else {
1161    owl_function_debugmsg("faimtest_parse_incoming_im: unsupported channel 0x%04x\n", channel);
1162  }
1163  va_end(ap);
1164  owl_function_debugmsg("faimtest_parse_incoming_im: done with ICBM handling (ret = %d)\n", ret);
1165  return 1;
1166}
1167
1168static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1169{
1170  aim_userinfo_t *userinfo;
1171  char *nz_screenname;
1172  owl_buddy *b;
1173  va_list ap;
1174  va_start(ap, fr);
1175  userinfo = va_arg(ap, aim_userinfo_t *);
1176  va_end(ap);
1177
1178  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1179 
1180  owl_buddylist_oncoming(owl_global_get_buddylist(&g), nz_screenname);
1181
1182  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1183    owl_function_debugmsg("faimtest_parseoncoming: in empty part of userinfo present and present idle");
1184  }
1185
1186  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g), nz_screenname);
1187  if (!b) {
1188    owl_function_debugmsg("Error: parse_oncoming setting idle time with no buddy present.");
1189    return(1);
1190  }
1191  if (userinfo->idletime==0) {
1192    owl_buddy_set_unidle(b);
1193  } else {
1194    owl_buddy_set_idle(b);
1195    owl_buddy_set_idle_since(b, userinfo->idletime);
1196  }
1197
1198  if (userinfo->flags & AIM_FLAG_AWAY) {
1199    owl_function_debugmsg("parse_oncoming sn: %s away flag!", userinfo->sn);
1200  }
1201 
1202  owl_function_debugmsg("parse_oncoming sn: %s idle: %i", userinfo->sn, userinfo->idletime);
1203   
1204  g_free(nz_screenname);
1205 
1206  /*
1207    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1208    time(NULL),
1209    userinfo->sn, userinfo->flags,
1210    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1211    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1212    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1213    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1214    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1215    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1216    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1217    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1218    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1219    userinfo->capabilities);
1220  */
1221  return(1);
1222}
1223
1224static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1225{
1226  aim_userinfo_t *userinfo;
1227  char *nz_screenname;
1228  va_list ap;
1229 
1230  va_start(ap, fr);
1231  userinfo = va_arg(ap, aim_userinfo_t *);
1232  va_end(ap);
1233
1234  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1235  owl_buddylist_offgoing(owl_global_get_buddylist(&g), nz_screenname);
1236  g_free(nz_screenname);
1237
1238  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1239    owl_function_debugmsg("parse_offgoing sn: %s idle time %i", userinfo->sn, userinfo->idletime);
1240  }
1241
1242  /*
1243  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1244         time(NULL),
1245         userinfo->sn, userinfo->flags,
1246         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1247         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1248         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1249         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1250         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1251         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1252         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1253         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1254         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1255         userinfo->capabilities);
1256  */
1257 
1258  return 1;
1259}
1260
1261/* Used by chat as well. */
1262int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1263{
1264  va_list ap;
1265  fu16_t reason;
1266 
1267  va_start(ap, fr);
1268  reason = (fu16_t)va_arg(ap, unsigned int);
1269  va_end(ap);
1270 
1271  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1272  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1273 
1274  return 1;
1275}
1276
1277static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1278{
1279  va_list ap;
1280  const char *destsn;
1281  fu16_t reason;
1282 
1283  va_start(ap, fr);
1284  reason = (fu16_t)va_arg(ap, unsigned int);
1285  destsn = va_arg(ap, const char *);
1286  va_end(ap);
1287 
1288  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1289  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1290
1291  if (reason==4) {
1292    owl_function_adminmsg("", "Could not send AIM message, user not logged on");
1293  }
1294 
1295  return 1;
1296}
1297
1298static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1299{
1300  va_list ap;
1301  const char *destsn;
1302  fu16_t reason;
1303 
1304  va_start(ap, fr);
1305  reason = (fu16_t)va_arg(ap, unsigned int);
1306  destsn = va_arg(ap, const char *);
1307  va_end(ap);
1308 
1309  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1310  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1311 
1312  return 1;
1313}
1314
1315static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1316{
1317  static const char *missedreasons[] = {
1318    "Invalid (0)",
1319    "Message too large",
1320    "Rate exceeded",
1321    "Evil Sender",
1322    "Evil Receiver"
1323  };
1324  static int missedreasonslen = 5;
1325 
1326  va_list ap;
1327  fu16_t chan, nummissed, reason;
1328  aim_userinfo_t *userinfo;
1329 
1330  va_start(ap, fr);
1331  chan = (fu16_t)va_arg(ap, unsigned int);
1332  userinfo = va_arg(ap, aim_userinfo_t *);
1333  nummissed = (fu16_t)va_arg(ap, unsigned int);
1334  reason = (fu16_t)va_arg(ap, unsigned int);
1335  va_end(ap);
1336 
1337  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");
1338 
1339  return 1;
1340}
1341
1342/*
1343 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1344 */
1345static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1346{
1347  va_list ap;
1348  fu16_t type;
1349  const char *sn = NULL;
1350 
1351  va_start(ap, fr);
1352  type = (fu16_t)va_arg(ap, unsigned int);
1353  sn = va_arg(ap, const char *);
1354  va_end(ap);
1355 
1356  owl_function_debugmsg("faimtest_parse_msgack: 0x%04x / %s\n", type, sn);
1357 
1358  return 1;
1359}
1360
1361static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1362{
1363  static const char *codes[5] = {
1364    "invalid",
1365    "change",
1366    "warning",
1367    "limit",
1368    "limit cleared"
1369  };
1370  va_list ap;
1371  fu16_t code, rateclass;
1372  fu32_t windowsize, clear, alert, limit, disconnect;
1373  fu32_t currentavg, maxavg;
1374 
1375  va_start(ap, fr); 
1376 
1377  /* See code explanations below */
1378  code = (fu16_t)va_arg(ap, unsigned int);
1379 
1380  /*
1381   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1382   */
1383  rateclass = (fu16_t)va_arg(ap, unsigned int);
1384 
1385  /*
1386   * Not sure what this is exactly.  I think its the temporal
1387   * relation factor (ie, how to make the rest of the numbers
1388   * make sense in the real world).
1389   */
1390  windowsize = va_arg(ap, fu32_t);
1391 
1392  /* Explained below */
1393  clear = va_arg(ap, fu32_t);
1394  alert = va_arg(ap, fu32_t);
1395  limit = va_arg(ap, fu32_t);
1396  disconnect = va_arg(ap, fu32_t);
1397  currentavg = va_arg(ap, fu32_t);
1398  maxavg = va_arg(ap, fu32_t);
1399 
1400  va_end(ap);
1401 
1402  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)",
1403                        (code < 5)?codes[code]:"invalid",
1404                        rateclass,
1405                        currentavg, maxavg,
1406                        alert, clear,
1407                        limit, disconnect,
1408                        windowsize);
1409  return 1;
1410}
1411
1412static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1413{
1414  va_list ap;
1415  fu16_t newevil;
1416  aim_userinfo_t *userinfo;
1417 
1418  va_start(ap, fr);
1419  newevil = (fu16_t)va_arg(ap, unsigned int);
1420  userinfo = va_arg(ap, aim_userinfo_t *);
1421  va_end(ap);
1422 
1423  /*
1424   * Evil Notifications that are lacking userinfo->sn are anon-warns
1425   * if they are an evil increases, but are not warnings at all if its
1426   * a decrease (its the natural backoff happening).
1427   *
1428   * newevil is passed as an int representing the new evil value times
1429   * ten.
1430   */
1431  owl_function_debugmsg("faimtest_parse_evilnotify: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1432 
1433  return 1;
1434}
1435
1436static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1437{
1438  va_list ap;
1439  const char *address, *SNs;
1440  int num, i;
1441  GPtrArray *list;
1442 
1443  va_start(ap, fr);
1444  address = va_arg(ap, const char *);
1445  num = va_arg(ap, int);
1446  SNs = va_arg(ap, const char *);
1447  va_end(ap);
1448
1449  list = g_ptr_array_new();
1450 
1451  owl_function_debugmsg("faimtest_parse_searchreply: E-Mail Search Results for %s: ", address);
1452  for (i=0; i<num; i++) {
1453    owl_function_debugmsg("  %s", &SNs[i*(MAXSNLEN+1)]);
1454    g_ptr_array_add(list, (void *)&SNs[i*(MAXSNLEN+1)]);
1455  }
1456  owl_function_aimsearch_results(address, list);
1457  g_ptr_array_free(list, true);
1458  return 1;
1459}
1460
1461static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1462{
1463  va_list ap;
1464  const char *address;
1465 
1466  va_start(ap, fr);
1467  address = va_arg(ap, const char *);
1468  va_end(ap);
1469
1470  owl_function_error("No results searching for %s", address);
1471  owl_function_debugmsg("faimtest_parse_searcherror: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1472 
1473  return(1);
1474}
1475
1476static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1477{
1478  va_list ap;
1479  const char *msg, *url;
1480  fu16_t width, height, delay;
1481 
1482  va_start(ap, fr);
1483  msg = va_arg(ap, const char *);
1484  url = va_arg(ap, const char *);
1485  width = va_arg(ap, unsigned int);
1486  height = va_arg(ap, unsigned int);
1487  delay = va_arg(ap, unsigned int);
1488  va_end(ap);
1489 
1490  owl_function_debugmsg("handlepopup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url);
1491 
1492  return 1;
1493}
1494
1495static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1496{
1497  aim_sendpauseack(sess, fr->conn);
1498  return 1;
1499}
1500
1501static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1502{
1503  va_list ap;
1504  aim_conn_t *bosconn;
1505  const char *bosip;
1506  fu8_t *cookie;
1507 
1508  va_start(ap, fr);
1509  bosip = va_arg(ap, const char *);
1510  cookie = va_arg(ap, fu8_t *);
1511  va_end(ap);
1512 
1513  owl_function_debugmsg("migrate: migration in progress -- new BOS is %s -- disconnecting", bosip);
1514  aim_conn_kill(sess, &fr->conn);
1515 
1516  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1517    owl_function_debugmsg("migrate: could not connect to BOS: internal error");
1518    return 1;
1519  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1520    owl_function_debugmsg("migrate: could not connect to BOS");
1521    aim_conn_kill(sess, &bosconn);
1522    return 1;
1523  }
1524 
1525  /* Login will happen all over again. */
1526  addcb_bos(sess, bosconn);
1527  /* aim_sendcookie(sess, bosconn, cookie); */ /********/
1528  return 1;
1529}
1530
1531static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1532{
1533  owl_function_debugmsg("ssirights: got SSI rights, requesting data\n");
1534  /* aim_ssi_reqdata(sess, fr->conn, 0, 0x0000); */
1535  aim_ssi_reqdata(sess);
1536 
1537  return(1);
1538}
1539
1540static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1541{
1542  va_list ap;
1543  fu8_t fmtver;
1544  fu16_t itemcount;
1545  fu32_t stamp;
1546  struct aim_ssi_item *list;
1547  /*
1548  struct aim_ssi_item *curitem;
1549  struct aim_ssi_item *l;
1550  */
1551 
1552  va_start(ap, fr);
1553  fmtver = va_arg(ap, unsigned int);
1554  itemcount = va_arg(ap, unsigned int);
1555  stamp = va_arg(ap, fu32_t);
1556  list = va_arg(ap, struct aim_ssi_item *);
1557  va_end(ap);
1558 
1559  owl_function_debugmsg("ssiddata: got SSI data (0x%02x, %d items, %u)", fmtver, itemcount, stamp);
1560  /*
1561  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
1562    for (l = list; l; l = l->next) {
1563      owl_function_debugmsg("\t0x%04x (%s) - 0x%04x/0x%04x", l->type, l->name, l->gid, l->bid);
1564    }
1565  }
1566  */
1567  aim_ssi_enable(sess);
1568 
1569  return 1;
1570}
1571
1572static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1573{
1574  owl_function_debugmsg("ssidatanochange: server says we have the latest SSI data already");
1575  /* aim_ssi_enable(sess, fr->conn); */
1576  aim_ssi_enable(sess);
1577  return 1;
1578}
1579
1580static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1581{
1582  va_list ap;
1583  struct aim_icq_offlinemsg *msg;
1584 
1585  va_start(ap, fr);
1586  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1587  va_end(ap);
1588 
1589  if (msg->type == 0x0001) {
1590    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);
1591  } else {
1592    owl_function_debugmsg("unknown offline message type 0x%04x", msg->type);
1593  }
1594  return 1;
1595}
1596
1597static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1598{
1599  /* Tell the server to delete them. */
1600  owl_function_debugmsg("offlinemsg done: ");
1601  aim_icq_ackofflinemsgs(sess);
1602  return 1;
1603}
1604
1605
1606/******************** chat.c **************************/
1607
1608static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1609{
1610  va_list ap;
1611  aim_userinfo_t *userinfo;
1612  int count;
1613  /* int i; */
1614 
1615  va_start(ap, fr);
1616  count = va_arg(ap, int);
1617  userinfo = va_arg(ap, aim_userinfo_t *);
1618  va_end(ap);
1619
1620  owl_function_debugmsg("In faimtest_chat_join");
1621  /*
1622  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1623  for (i = 0; i < count; i++)
1624    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1625  */
1626  return 1;
1627}
1628
1629static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1630{
1631  aim_userinfo_t *userinfo;
1632  va_list ap;
1633  int count;
1634  /* int i; */
1635
1636 
1637  va_start(ap, fr);
1638  count = va_arg(ap, int);
1639  userinfo = va_arg(ap, aim_userinfo_t *);
1640  va_end(ap);
1641 
1642  /*
1643    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1644   
1645    for (i = 0; i < count; i++)
1646    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1647  */
1648  return 1;
1649}
1650
1651static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1652{
1653  va_list ap;
1654  aim_userinfo_t *userinfo;
1655  struct aim_chat_roominfo *roominfo;
1656  const char *roomname;
1657  int usercount;
1658  const char *roomdesc;
1659  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1660  fu32_t creationtime;
1661  const char *croomname;
1662  /* int i; */
1663 
1664  croomname = aim_chat_getname(fr->conn);
1665 
1666  va_start(ap, fr);
1667  roominfo = va_arg(ap, struct aim_chat_roominfo *);
1668  roomname = va_arg(ap, const char *);
1669  usercount = va_arg(ap, int);
1670  userinfo = va_arg(ap, aim_userinfo_t *);
1671  roomdesc = va_arg(ap, const char *);
1672  flags = (fu16_t)va_arg(ap, unsigned int);
1673  creationtime = va_arg(ap, fu32_t);
1674  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1675  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
1676  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
1677  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
1678  va_end(ap);
1679
1680  owl_function_debugmsg("In faimtest_chat_infoupdate");
1681  /*
1682  printf("chat: %s:  info update:\n", croomname);
1683  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
1684  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
1685  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
1686  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
1687
1688  for (i = 0; i < usercount; i++)
1689    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
1690 
1691  owl_function_debugmsg("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
1692         croomname, flags,
1693         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1694         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1695         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1696         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1697  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
1698  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
1699  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
1700  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
1701  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
1702  */
1703 
1704  return(1);
1705}
1706
1707static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
1708{
1709  va_list ap;
1710  aim_userinfo_t *userinfo;
1711  const char *msg;
1712  char tmpbuf[1152];
1713 
1714  va_start(ap, fr);
1715  userinfo = va_arg(ap, aim_userinfo_t *);     
1716  msg = va_arg(ap, const char *);
1717  va_end(ap);
1718
1719  owl_function_debugmsg("in faimtest_chat_incomingmsg");
1720
1721  /*
1722  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
1723  */
1724 
1725  /*
1726   * Do an echo for testing purposes.  But not for ourselves ("oops!")
1727   */
1728  if (strcmp(userinfo->sn, sess->sn) != 0) {
1729    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
1730    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
1731  }
1732 
1733  return 1;
1734}
1735
1736static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
1737{
1738  owl_function_debugmsg("faimtest_conninitdone_chat:");
1739
1740  aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
1741  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
1742  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
1743  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
1744  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
1745 
1746  aim_clientready(sess, fr->conn);
1747 
1748  owl_function_debugmsg("Chat ready");
1749
1750  /*
1751    chatcon = find_oscar_chat_by_conn(gc, fr->conn);
1752    chatcon->id = id;
1753    chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show);
1754  */
1755  return(1);
1756}
1757
1758void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1759{
1760  aim_conn_t *tstconn;
1761
1762  owl_function_debugmsg("in faimtest_chatnav_redirect");
1763 
1764  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
1765  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1766    /* printf("unable to connect to chat(nav) server\n"); */
1767    if (tstconn)
1768      aim_conn_kill(sess, &tstconn);
1769    return;
1770  }
1771 
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  /* printf("chatnav: connected\n"); */
1776  return;
1777}
1778
1779/* XXX this needs instance too */
1780void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1781{
1782  aim_conn_t *tstconn;
1783
1784  owl_function_debugmsg("in chat_redirect");
1785 
1786  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
1787  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1788    /* printf("unable to connect to chat server\n"); */
1789    if (tstconn) aim_conn_kill(sess, &tstconn);
1790    return; 
1791  }             
1792  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
1793 
1794  /*
1795   * We must do this to attach the stored name to the connection!
1796   */
1797  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
1798  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1799  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
1800  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
1801  return;       
1802}
1803
1804typedef struct _owl_aim_event_source { /*noproto*/
1805  GSource source;
1806  aim_session_t *sess;
1807  GPtrArray *fds;
1808} owl_aim_event_source;
1809
1810static void truncate_pollfd_list(owl_aim_event_source *event_source, int len)
1811{
1812  GPollFD *fd;
1813  int i;
1814  if (len < event_source->fds->len) {
1815    owl_function_debugmsg("Truncating AIM PollFDs to %d, was %d", len, event_source->fds->len);
1816    for (i = len; i < event_source->fds->len; i++) {
1817      fd = event_source->fds->pdata[i];
1818      g_source_remove_poll(&event_source->source, fd);
1819      g_free(fd);
1820    }
1821    g_ptr_array_remove_range(event_source->fds, len, event_source->fds->len - len);
1822  }
1823}
1824
1825static gboolean owl_aim_event_source_prepare(GSource *source, int *timeout)
1826{
1827  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
1828  aim_conn_t *cur;
1829  GPollFD *fd;
1830  int i;
1831
1832  /* AIM HACK:
1833   *
1834   *  The problem - I'm not sure where to hook into the owl/faim
1835   *  interface to keep track of when the AIM socket(s) open and
1836   *  close. In particular, the bosconn thing throws me off. So,
1837   *  rather than register particular dispatchers for AIM, I look up
1838   *  the relevant FDs and add them to select's watch lists, then
1839   *  check for them individually before moving on to the other
1840   *  dispatchers. --asedeno
1841   */
1842  i = 0;
1843  for (cur = event_source->sess->connlist; cur; cur = cur->next) {
1844    if (cur->fd != -1) {
1845      /* Add new GPollFDs as necessary. */
1846      if (i == event_source->fds->len) {
1847        fd = g_new0(GPollFD, 1);
1848        g_ptr_array_add(event_source->fds, fd);
1849        g_source_add_poll(source, fd);
1850        owl_function_debugmsg("Allocated new AIM PollFD, len = %d", event_source->fds->len);
1851      }
1852      fd = event_source->fds->pdata[i];
1853      fd->fd = cur->fd;
1854      fd->events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
1855      if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
1856        /* Yes, we're checking writable sockets here. Without it, AIM
1857           login is really slow. */
1858        fd->events |= G_IO_OUT;
1859      }
1860      i++;
1861    }
1862  }
1863  /* If the number of GPollFDs went down, clean up. */
1864  truncate_pollfd_list(event_source, i);
1865
1866  *timeout = -1;
1867  return FALSE;
1868}
1869
1870static gboolean owl_aim_event_source_check(GSource *source)
1871{
1872  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
1873  int i;
1874
1875  for (i = 0; i < event_source->fds->len; i++) {
1876    GPollFD *fd = event_source->fds->pdata[i];
1877    if (fd->revents & fd->events)
1878      return TRUE;
1879  }
1880  return FALSE;
1881}
1882
1883static gboolean owl_aim_event_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
1884{
1885  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
1886  owl_aim_process_events(event_source->sess);
1887  return TRUE;
1888}
1889
1890static void owl_aim_event_source_finalize(GSource *source)
1891{
1892  owl_aim_event_source *event_source = (owl_aim_event_source*)source;
1893  truncate_pollfd_list(event_source, 0);
1894  g_ptr_array_free(event_source->fds, TRUE);
1895}
1896
1897static GSourceFuncs aim_event_funcs = {
1898  owl_aim_event_source_prepare,
1899  owl_aim_event_source_check,
1900  owl_aim_event_source_dispatch,
1901  owl_aim_event_source_finalize,
1902};
1903
1904GSource *owl_aim_event_source_new(aim_session_t *sess)
1905{
1906  GSource *source;
1907  owl_aim_event_source *event_source;
1908
1909  source = g_source_new(&aim_event_funcs, sizeof(owl_aim_event_source));
1910  event_source = (owl_aim_event_source *)source;
1911  event_source->sess = sess;
1912  /* TODO: When we depend on glib 2.22+, use g_ptr_array_new_with_free_func. */
1913  event_source->fds = g_ptr_array_new();
1914  return source;
1915}
Note: See TracBrowser for help on using the repository browser.