source: aim.c @ dc1edbd

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