source: aim.c @ 1db061d

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 1db061d was 1db061d, checked in by James M. Kretchmar <kretch@mit.edu>, 20 years ago
Set aim_ignorelogin_timer to 15 by default Admin message on login/logout of AIM
  • Property mode set to 100644
File size: 75.2 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 *aimbinarypath;
10  char *screenname;
11  char *password;
12  char *server;
13  char *proxy;
14  char *proxyusername;
15  char *proxypass;
16  char *ohcaptainmycaptain;
17  int connected;
18
19  FILE *listingfile;
20  char *listingpath;
21
22  fu8_t *buddyicon;
23  int buddyiconlen;
24  time_t buddyiconstamp;
25  fu16_t buddyiconsum;
26};
27
28static char *msgerrreasons[] = {
29        "Invalid error",
30        "Invalid SNAC",
31        "Rate to host",
32        "Rate to client",
33        "Not logged on",
34        "Service unavailable",
35        "Service not defined",
36        "Obsolete SNAC",
37        "Not supported by host",
38        "Not supported by client",
39        "Refused by client",
40        "Reply too big",
41        "Responses lost",
42        "Request denied",
43        "Busted SNAC payload",
44        "Insufficient rights",
45        "In local permit/deny",
46        "Too evil (sender)",
47        "Too evil (receiver)",
48        "User temporarily unavailable",
49        "No match",
50        "List overflow",
51        "Request ambiguous",
52        "Queue full",
53        "Not while on AOL",
54};
55static int msgerrreasonslen = 25;
56
57static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va);
58static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...);
59static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...);
60int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...);
61int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...);
62void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn);
63static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...);
64int login(aim_session_t *sess, const char *sn, const char *passwd);
65static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...);
66int logout(aim_session_t *sess);
67
68static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...);
69static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...);
70static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...);
71static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...);
72static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...);
73static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...);
74static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...);
75static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...);
76static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...);
77/* static int reportinterval(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs); */
78static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...);
79static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname);
80static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...);
81static void printuserflags(fu16_t flags);
82static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...);
83static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, const char *tmpstr);
84static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args);
85static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
86static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...);
87static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...);
88static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...);
89int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...);
90static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...);
91static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...);
92static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...);
93static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...);
94static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...);
95static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...);
96static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...);
97static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...);
98static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...);
99static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...);
100static int migrate(aim_session_t *sess, aim_frame_t *fr, ...);
101static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...);
102static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...);
103static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...);
104static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...);
105static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...);
106
107void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
108void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
109
110/*****************************************************************/
111
112void owl_aim_init(void)
113{
114  aim_session_init(owl_global_get_aimsess(&g), AIM_SESS_FLAGS_NONBLOCKCONNECT, 0);
115  aim_setdebuggingcb(owl_global_get_aimsess(&g), faimtest_debugcb);
116
117  /* an experiment to expose idle time */
118  aim_ssi_setpresence(owl_global_get_aimsess(&g), 0x00000400);
119}
120
121
122int owl_aim_login(char *screenname, char *password)
123{
124  int ret;
125  struct owlfaim_priv *priv;
126
127  /* this will leak, I know and just don't care right now */
128  priv=owl_malloc(sizeof(struct owlfaim_priv));
129  memset(priv, 0, sizeof(struct owlfaim_priv));
130
131  priv->screenname = owl_strdup(screenname);
132  priv->password = owl_strdup(password);
133  priv->server = "login.oscar.aol.com";
134  owl_global_get_aimsess(&g)->aux_data = priv;
135
136  aim_tx_setenqueue(owl_global_get_aimsess(&g), AIM_TX_IMMEDIATE, NULL);
137 
138  /* login */
139  ret=login(owl_global_get_aimsess(&g), priv->screenname, priv->password);
140  if (ret) {
141    owl_global_set_aimnologgedin(&g);
142    owl_global_set_no_doaimevents(&g);
143    return(-1);
144  }
145  owl_global_set_doaimevents(&g);
146
147  return(0);
148}
149
150#if 0
151static void oscar_login(GaimAccount *account)
152{
153  aim_session_t *sess;
154  aim_conn_t *conn;
155  char buf[256];
156  GaimConnection *gc = gaim_account_get_connection(account);
157  struct oscar_data *od = gc->proto_data = g_new0(struct oscar_data, 1);
158
159  gaim_debug(GAIM_DEBUG_MISC, "oscar", "oscar_login: gc = %p\n", gc);
160
161  if (isdigit(*(gaim_account_get_username(account)))) {
162    od->icq = TRUE;
163  } else {
164    gc->flags |= GAIM_CONNECTION_HTML;
165    gc->flags |= GAIM_CONNECTION_AUTO_RESP;
166  }
167  od->buddyinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, oscar_free_buddyinfo);
168
169  sess = g_new0(aim_session_t, 1);
170
171  aim_session_init(sess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 0);
172  aim_setdebuggingcb(sess, oscar_debug);
173
174  /* we need an immediate queue because we don't use a while-loop to
175   * see if things need to be sent. */
176  aim_tx_setenqueue(sess, AIM_TX_IMMEDIATE, NULL);
177  od->sess = sess;
178  sess->aux_data = gc;
179
180  conn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL);
181  if (conn == NULL) {
182    gaim_debug(GAIM_DEBUG_ERROR, "oscar",
183               "internal connection error\n");
184    gaim_connection_error(gc, _("Unable to login to AIM"));
185    return;
186  }
187
188  g_snprintf(buf, sizeof(buf), _("Signon: %s"), gaim_account_get_username(account));
189  gaim_connection_update_progress(gc, buf, 2, 5);
190
191  aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
192  aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0);
193  aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0);
194
195  conn->status |= AIM_CONN_STATUS_INPROGRESS;
196  if (gaim_proxy_connect(account, gaim_account_get_string(account, "server", FAIM_LOGIN_SERVER),
197                         gaim_account_get_int(account, "port", FAIM_LOGIN_PORT),
198                         oscar_login_connect, gc) < 0) {
199    gaim_connection_error(gc, _("Couldn't connect to host"));
200    return;
201  }
202  aim_request_login(sess, conn, gaim_account_get_username(account));
203}
204#endif
205
206
207/* stuff to run once login has been successful */
208void owl_aim_successful_login(char *screenname)
209{
210  char *buff;
211  owl_function_debugmsg("doing owl_aim_successful_login");
212  owl_global_set_aimloggedin(&g, screenname);
213  owl_global_set_doaimevents(&g); /* this should already be on */
214  owl_function_makemsg("%s logged in", screenname);
215  buff=owl_sprintf("Logged in to AIM as %s", screenname);
216  owl_function_adminmsg("", buff);
217  owl_free(buff);
218
219  owl_function_debugmsg("Successful AIM login for %s", screenname);
220
221  /* start the ingorelogin timer */
222  owl_timer_reset_newstart(owl_global_get_aim_login_timer(&g),
223                           owl_global_get_aim_ignorelogin_timer(&g));
224
225  /* aim_bos_setidle(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), 5000); */
226}
227
228void owl_aim_logout(void)
229{
230  /* need to check if it's connected first, I think */
231  logout(owl_global_get_aimsess(&g));
232
233  owl_function_adminmsg("", "Logged out of AIM");
234
235  owl_global_set_aimnologgedin(&g);
236  owl_global_set_no_doaimevents(&g);
237}
238
239void owl_aim_logged_out()
240{
241  owl_function_adminmsg("", "You have been logged out of AIM");
242  owl_aim_logout();
243}
244
245void owl_aim_login_error(char *message)
246{
247  if (message) {
248    owl_function_error(message);
249  } else {
250    owl_function_error("Authentication error on login");
251  }
252  owl_function_beep();
253  owl_global_set_aimnologgedin(&g);
254  owl_global_set_no_doaimevents(&g);
255}
256
257int owl_aim_send_im(char *to, char *msg)
258{
259  int ret;
260
261  ret=aim_im_sendch1(owl_global_get_aimsess(&g), to, NULL, msg);
262   
263  /* aim_send_im(owl_global_get_aimsess(&g), to, AIM_IMFLAGS_ACK, msg); */
264
265  /* I don't know how to check for an error yet */
266  return(ret);
267}
268
269void owl_aim_addbuddy(char *name)
270{
271  aim_ssi_addbuddy(owl_global_get_aimsess(&g), name, "Buddies", NULL, NULL, NULL, 0);
272}
273
274void owl_aim_delbuddy(char *name)
275{
276  aim_ssi_delbuddy(owl_global_get_aimsess(&g), name, "Buddies");
277  owl_buddylist_offgoing(owl_global_get_buddylist(&g), name);
278}
279
280
281int owl_aim_set_awaymsg(char *msg)
282{
283  /* there is a max away message lentgh we should check against */
284
285  aim_bos_setprofile(owl_global_get_aimsess(&g),
286                     owl_global_get_bosconn(&g),
287                     NULL, NULL, 0, "us-ascii", msg, 
288                     strlen(msg), 0);
289  return(0);
290}
291
292void owl_aim_chat_join(char *chatroom, int exchange)
293{
294  int ret;
295
296  /* ret=aim_chat_join(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), exchange, chatroom, 0x0000); */
297  /*
298  ret=aim_chat_join(owl_global_get_aimsess(&g),
299                    aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV), exchange, chatroom, 0x0000);
300  */
301
302  aim_reqservice(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), AIM_CONN_TYPE_CHATNAV);
303  ret = aim_chatnav_createroom(owl_global_get_aimsess(&g),
304                               aim_getconn_type(owl_global_get_aimsess(&g), AIM_CONN_TYPE_CHATNAV), chatroom, exchange);
305   ret=aim_chat_join(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), exchange, chatroom, 0x0000);
306 
307  owl_function_debugmsg("Attempting to join chatroom %s exchange %i", chatroom, exchange);
308}
309
310void owl_aim_chat_leave(char *chatroom)
311{
312}
313
314int owl_aim_chat_sendmsg(char *chatroom, char *msg)
315{
316  return(0);
317}
318
319/* caller must free the return */
320char *owl_aim_normalize_screenname(char *in)
321{
322  char *out;
323  int i, j, k;
324
325  j=strlen(in);
326  out=owl_malloc(j+30);
327  k=0;
328  for (i=0; i<j; i++) {
329    if (in[i]!=' ') {
330      out[k]=in[i];
331      k++;
332    }
333  }
334  out[k]='\0';
335  return(out);
336}
337
338int owl_aim_process_events()
339{
340  aim_session_t *aimsess;
341  aim_conn_t *waitingconn = NULL;
342  struct timeval tv;
343  int selstat = 0;
344  struct owlfaim_priv *priv;
345
346  aimsess=owl_global_get_aimsess(&g);
347  priv = (struct owlfaim_priv *) &(aimsess->aux_data);
348
349  /* do a select without blocking */
350  tv.tv_sec = 0;
351  tv.tv_usec = 0;
352  waitingconn = aim_select(aimsess, &tv, &selstat);
353
354  if (owl_global_is_aimnop_time(&g)) {
355    aim_flap_nop(aimsess, aim_getconn_type(aimsess, AIM_CONN_TYPE_BOS));
356    owl_global_aimnop_sent(&g);
357  }
358
359  if (selstat == -1) {
360    owl_aim_logged_out();
361  } else if (selstat == 0) { 
362    /* no events pending */
363  } else if (selstat == 1) { /* outgoing data pending */
364    aim_tx_flushqueue(aimsess);
365  } else if (selstat == 2) { /* incoming data pending */
366    /* printf("selstat == 2\n"); */
367   
368    if (aim_get_command(aimsess, waitingconn) >= 0) {
369      aim_rxdispatch(aimsess);
370    } else {
371      /* printf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype); */
372      /* we should have callbacks for all these, else the library will do the conn_kill for us. */
373      if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
374        if (waitingconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
375          /* printf("disconnected from %s\n", aim_directim_getsn(waitingconn)); */
376          aim_conn_kill(aimsess, &waitingconn);
377          owl_aim_logged_out();
378        }
379      } else {
380        aim_conn_kill(aimsess, &waitingconn);
381        owl_aim_logged_out();
382      }
383      if (!aim_getconn_type(aimsess, AIM_CONN_TYPE_BOS)) {
384        /* printf("major connection error\n"); */
385        owl_aim_logged_out();
386        /* break; */
387      }
388    }
389  }
390  /* free(priv->buddyicon); */
391  /* exit(0); */
392  return(0);
393}
394
395static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va)
396{
397  return;
398}
399
400static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...)
401{
402  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
403  struct client_info_s info = CLIENTINFO_AIM_KNOWNGOOD;
404   
405  char *key;
406  va_list ap;
407
408  va_start(ap, fr);
409  key = va_arg(ap, char *);
410  va_end(ap);
411
412  owl_function_debugmsg("doing faimtest_parse_login");
413
414  aim_send_login(sess, fr->conn, priv->screenname, priv->password, &info, key);
415 
416  return(1);
417}
418
419
420static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...)
421{
422  va_list ap;
423  struct aim_authresp_info *info;
424  aim_conn_t *bosconn;
425
426  va_start(ap, fr);
427  info = va_arg(ap, struct aim_authresp_info *);
428  va_end(ap);
429
430  /* printf("Screen name: %s\n", info->sn); */
431  owl_function_debugmsg("doing faimtest_parse_authresp");
432  owl_function_debugmsg("faimtest_parse_authresp: %s", info->sn);
433
434  /*
435   * Check for error.
436   */
437  if (info->errorcode || !info->bosip || !info->cookie) {
438    /*
439    printf("Login Error Code 0x%04x\n", info->errorcode);
440    printf("Error URL: %s\n", info->errorurl);
441    */
442    if (info->errorcode==0x05) {
443      owl_aim_login_error("Incorrect nickname or password.");
444    } else if (info->errorcode==0x11) {
445      owl_aim_login_error("Your account is currently suspended.");
446    } else if (info->errorcode==0x14) {
447      owl_aim_login_error("The AOL Instant Messenger service is temporarily unavailable.");
448    } else if (info->errorcode==0x18) {
449      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.");
450    } else if (info->errorcode==0x1c) {
451      owl_aim_login_error("The client version you are using is too old.");
452    } else {
453      owl_aim_login_error(NULL);
454    }
455    aim_conn_kill(sess, &fr->conn);
456    return(1);
457  }
458
459  /*
460  printf("Reg status: %d\n", info->regstatus);
461  printf("Email: %s\n", info->email);
462  printf("BOS IP: %s\n", info->bosip);
463  */
464
465  /* printf("Closing auth connection...\n"); */
466  aim_conn_kill(sess, &fr->conn);
467  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, info->bosip))) {
468    /* printf("could not connect to BOS: internal error\n"); */
469    return(1);
470  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {
471    /* printf("could not connect to BOS\n"); */
472    aim_conn_kill(sess, &bosconn);
473    return(1);
474  }
475  owl_global_set_bossconn(&g, bosconn);
476  owl_aim_successful_login(info->sn);
477  addcb_bos(sess, bosconn);
478  aim_sendcookie(sess, bosconn, info->cookielen, info->cookie);
479  return(1);
480}
481
482int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...)
483{
484  owl_function_debugmsg("doing faimtest_flapversion");
485
486#if 0
487  /* XXX fix libfaim to support this */
488  printf("using FLAP version 0x%08x\n", /* aimutil_get32(fr->data)*/ 0xffffffff);
489
490  /*
491   * This is an alternate location for starting the login process.
492   */
493  /* XXX should do more checking to make sure its really the right AUTH conn */
494  if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
495    /* do NOT send a flapversion, request_login will send it if needed */
496    aim_request_login(sess, fr->conn, priv->screenname);
497    /* printf("faimtest: login request sent\n"); */
498  }
499#endif
500
501  return 1;
502}
503
504
505int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...)
506{
507  owl_function_debugmsg("doing faimtest_conncomplete");
508  /* owl_aim_successful_login(info->sn); */
509  return 1;
510}
511
512void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
513{
514  owl_function_debugmsg("doing addcb_bos");
515  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
516  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_bos, 0);
517
518  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0003,                        ssirights, 0);
519  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0006,                        ssidata, 0);
520  aim_conn_addhandler(sess, bosconn, 0x0013,         0x000f,                        ssidatanochange, 0);
521  aim_conn_addhandler(sess, bosconn, 0x0008,         0x0002,                        handlepopup, 0);
522  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0003,                        faimtest_bosrights, 0);
523  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT,           faimtest_handleredirect, 0);
524  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL,  faimtest_reportinterval, 0);
525  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO,         faimtest_parse_buddyrights, 0);
526  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD,               faimtest_parse_motd, 0);
527  aim_conn_addhandler(sess, bosconn, 0x0004,         0x0005,                        faimtest_icbmparaminfo, 0);
528  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR,    faimtest_parse_connerr, 0);
529  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO,         faimtest_locrights, 0);
530  aim_conn_addhandler(sess, bosconn, 0x0001,         0x001f,                        faimtest_memrequest, 0);
531  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING,           faimtest_parse_oncoming, 0);
532  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING,           faimtest_parse_offgoing, 0);
533  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING,           faimtest_parse_incoming_im, 0);
534  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR,              faimtest_parse_locerr, 0);
535  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL,         faimtest_parse_misses, 0);
536  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE,         faimtest_parse_ratechange, 0);
537  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL,               faimtest_parse_evilnotify, 0);
538  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0001,                        faimtest_parse_searcherror, 0);
539  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0003,                        faimtest_parse_searchreply, 0);
540  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR,              faimtest_parse_msgerr, 0);
541  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO,           faimtest_parse_userinfo, 0);
542  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK,                faimtest_parse_msgack, 0);
543
544  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0001,                        faimtest_parse_genericerr, 0);
545  aim_conn_addhandler(sess, bosconn, 0x0003,         0x0001,                        faimtest_parse_genericerr, 0);
546  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0001,                        faimtest_parse_genericerr, 0);
547  aim_conn_addhandler(sess, bosconn, 0x0001,         0x000b,                        serverpause, 0);
548  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0012,                        migrate, 0);
549  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG,         offlinemsg, 0);
550  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, offlinemsgdone, 0);
551
552  return;
553}
554
555static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...)
556{
557  owl_function_debugmsg("doing coninitdone_bos");
558  aim_reqpersonalinfo(sess, fr->conn);
559
560  aim_ssi_reqrights(sess);
561  aim_ssi_reqdata(sess);
562
563  aim_bos_reqlocaterights(sess, fr->conn);
564  aim_bos_reqbuddyrights(sess, fr->conn);
565  aim_im_reqparams(sess);
566  aim_bos_reqrights(sess, fr->conn); /* XXX - Don't call this with ssi? */
567
568  /* aim_bos_setprofile(owl_global_get_aimsess(&g), fr->conn, NULL, NULL, 0, NULL, NULL, 0, AIM_CAPS_CHAT); */
569
570#ifdef NOSSI
571  /*
572  aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
573  aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE | AIM_PRIVFLAGS_ALLOWMEMBERSINCE);
574  */
575#endif
576
577  return(1);
578}
579
580int login(aim_session_t *sess, const char *sn, const char *passwd)
581{
582  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
583  aim_conn_t *authconn;
584
585  if (sn) priv->screenname = strdup(sn);
586  if (passwd) priv->password = strdup(passwd);
587  if (priv->proxy) aim_setupproxy(sess, priv->proxy, priv->proxyusername, priv->proxypass);
588
589  if (!priv->screenname || !priv->password) {
590    /* printf("need SN and password\n"); */
591    return(-1);
592  }
593
594  if (!(authconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, priv->server ? priv->server : FAIM_LOGIN_SERVER))) {
595    /* printf("internal connection error during login\n"); */
596    return (-1);
597  } else if (authconn->fd == -1) {
598    if (authconn->status & AIM_CONN_STATUS_RESOLVERR) {
599      /* printf("could not resolve authorizer name\n");*/
600    } else if (authconn->status & AIM_CONN_STATUS_CONNERR) {
601      /* printf("could not connect to authorizer\n"); */
602    }
603    aim_conn_kill(sess, &authconn);
604    return(-1);
605  }
606
607  aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
608  aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
609  aim_conn_addhandler(sess, authconn, 0x0017, 0x0007, faimtest_parse_login, 0);
610  aim_conn_addhandler(sess, authconn, 0x0017, 0x0003, faimtest_parse_authresp, 0);
611
612  /* If the connection is in progress, this will just be queued */
613  aim_request_login(sess, authconn, priv->screenname);
614
615  /* printf("login request sent\n"); */
616  return(0);
617}
618
619
620static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...)
621{
622  aim_clientready(sess, fr->conn);
623  /* printf("initialization done for admin connection\n"); */
624  return(1);
625}
626
627int logout(aim_session_t *sess)
628{
629  aim_session_kill(sess);
630  owl_aim_init();
631 
632  /* kretch
633  if (faimtest_init() == -1)
634    printf("faimtest_init failed\n");
635  */
636
637  return(0);
638}
639
640/**************************************************************************************************/
641
642static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...)
643{
644  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
645  va_list ap;
646  fu16_t code;
647  char *msg;
648 
649  va_start(ap, fr);
650  code = va_arg(ap, int);
651  msg = va_arg(ap, char *);
652  va_end(ap);
653 
654  /* printf("connerr: Code 0x%04x: %s\n", code, msg); */
655  aim_conn_kill(sess, &fr->conn); /* this will break the main loop */
656 
657  priv->connected = 0;
658 
659  return 1;
660}
661
662static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...)
663{
664  int status;
665  va_list ap;
666 
667  va_start(ap, fr);
668  status = va_arg(ap, int); /* status code of confirmation request */
669  va_end(ap);
670 
671  /* printf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown"); */
672 
673  return 1;
674}
675
676static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
677{
678  fu16_t change = 0, perms, type;
679  int length, str;
680  char *val;
681  va_list ap;
682 
683  va_start(ap, fr);
684  change = va_arg(ap, int);
685  perms = (fu16_t)va_arg(ap, unsigned int);
686  type = (fu16_t)va_arg(ap, unsigned int);
687  length = va_arg(ap, int);
688  val = va_arg(ap, char *);
689  str = va_arg(ap, int);
690  va_end(ap);
691 
692  /* printf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)"); */
693 
694  return 1;
695}
696
697
698static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...)
699{
700  va_list ap;
701  struct aim_redirect_data *redir;
702 
703  va_start(ap, fr);
704  redir = va_arg(ap, struct aim_redirect_data *);
705 
706  if (redir->group == 0x0005) {  /* Adverts */
707   
708  } else if (redir->group == 0x0007) {  /* Authorizer */
709    aim_conn_t *tstconn;
710   
711    tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, redir->ip);
712    if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
713      /* printf("unable to reconnect with authorizer\n"); */
714    } else {
715      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
716      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
717      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_admin, 0);
718      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0);
719      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0);
720      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0);
721      /* Send the cookie to the Auth */
722      aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
723      /* printf("sent cookie to authorizer host\n"); */
724    }
725  } else if (redir->group == 0x000d) {  /* ChatNav */
726    chatnav_redirect(sess, redir);
727  } else if (redir->group == 0x000e) { /* Chat */
728    chat_redirect(sess, redir);
729  } else {
730    /* printf("uh oh... got redirect for unknown service 0x%04x!!\n", redir->group); */
731  }
732  va_end(ap);
733  return 1;
734}
735
736static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...)
737{
738  struct aim_icbmparameters *params;
739  va_list ap;
740 
741  va_start(ap, fr);
742  params = va_arg(ap, struct aim_icbmparameters *);
743  va_end(ap);
744 
745  /* printf("ICBM Parameters: maxchannel = %d, default flags = 0x%08lx, max msg len = %d, max sender evil = %f, max reciever evil = %f, min msg interval = %ld\n", params->maxchan, params->flags, params->maxmsglen, ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, params->minmsginterval); */
746     
747  /*
748  * Set these to your taste, or client medium.  Setting minmsginterval
749  * higher is good for keeping yourself from getting flooded (esp
750  * if you're on a slow connection or something where that would be
751  * useful).
752  */
753  params->maxmsglen = 8000;
754  params->minmsginterval = 0; /* in milliseconds */
755  /* aim_seticbmparam(sess, params); */
756  aim_im_setparams(sess, params);
757 
758  return 1;
759}
760
761static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
762{
763  va_list ap;
764  fu16_t maxbuddies, maxwatchers;
765 
766  va_start(ap, fr);
767  maxbuddies = va_arg(ap, int);
768  maxwatchers = va_arg(ap, int);
769  va_end(ap);
770 
771  /* printf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers); */
772 
773  /* aim_ssi_reqrights(sess, fr->conn); */
774  aim_ssi_reqrights(sess);
775 
776  return 1;
777}
778
779static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
780{
781  va_list ap;
782  fu16_t maxpermits, maxdenies;
783 
784  va_start(ap, fr);
785  maxpermits = va_arg(ap, int);
786  maxdenies = va_arg(ap, int);
787  va_end(ap);
788 
789  /* printf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies); */
790  aim_clientready(sess, fr->conn);
791  owl_function_debugmsg("officially connected to BOS.");
792  aim_icq_reqofflinemsgs(sess);
793  return 1;
794}
795
796static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
797{
798  va_list ap;
799  fu16_t maxsiglen;
800 
801  va_start(ap, fr);
802  maxsiglen = va_arg(ap, int);
803  va_end(ap);
804
805  /* printf("locate rights: max signature length = %d\n", maxsiglen); */
806 
807  return(1);
808}
809
810static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
811{
812  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
813  va_list ap;
814  fu16_t interval;
815
816  va_start(ap, fr);
817  interval = va_arg(ap, int);
818  va_end(ap);
819
820  /* printf("minimum report interval: %d (seconds?)\n", interval); */
821
822  if (!priv->connected) {
823    priv->connected++;
824  }
825  /* aim_reqicbmparams(sess); */
826  aim_im_reqparams(sess);
827  /* kretch */
828  return 1;
829}
830
831static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
832{
833  char *msg;
834  fu16_t id;
835  va_list ap;
836  /* static int codeslen = 5;
837  static char *codes[] = {
838    "Unknown",
839    "Mandatory upgrade",
840    "Advisory upgrade",
841    "System bulletin",
842    "Top o' the world!"
843  };
844  */
845
846  return 1;
847 
848  va_start(ap, fr);
849  id = va_arg(ap, int);
850  msg = va_arg(ap, char *);
851  va_end(ap);
852 
853  /* printf("motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown"); */
854 
855  return 1;
856}
857
858/*
859 * This is a little more complicated than it looks.  The module
860 * name (proto, boscore, etc) may or may not be given.  If it is
861 * not given, then use aim.exe.  If it is given, put ".ocm" on the
862 * end of it.
863 *
864 * Now, if the offset or length requested would cause a read past
865 * the end of the file, then the request is considered invalid.  Invalid
866 * requests are processed specially.  The value hashed is the
867 * the request, put into little-endian (eight bytes: offset followed
868 * by length). 
869 *
870 * Additionally, if the request is valid, the length is mod 4096.  It is
871 * important that the length is checked for validity first before doing
872 * the mod.
873 *
874 * Note to Bosco's Brigade: if you'd like to break this, put the
875 * module name on an invalid request.
876 *
877 */
878static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
879{
880  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
881  FILE *f;
882  static const char defaultmod[] = "aim.exe";
883  char *filename = NULL;
884  struct stat st;
885  unsigned char *buf;
886  int invalid = 0;
887 
888  if (!bufret || !buflenret)
889    return -1;
890 
891  if (modname) {
892    if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
893      /* perror("memrequest: malloc"); */
894      return -1;
895    }
896    sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname);
897  } else {
898    if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
899      /* perror("memrequest: malloc"); */
900      return -1;
901    }
902    sprintf(filename, "%s/%s", priv->aimbinarypath, defaultmod);
903  }
904 
905  if (stat(filename, &st) == -1) {
906    if (!modname) {
907      /* perror("memrequest: stat"); */
908      free(filename);
909      return -1;
910    }
911    invalid = 1;
912  }
913 
914  if (!invalid) {
915    if ((offset > st.st_size) || (len > st.st_size))
916      invalid = 1;
917    else if ((st.st_size - offset) < len)
918      len = st.st_size - offset;
919    else if ((st.st_size - len) < len)
920      len = st.st_size - len;
921  }
922 
923  if (!invalid && len) {
924    len %= 4096;
925  }
926 
927  if (invalid) {
928    int i;
929   
930    free(filename); /* not needed */
931    printf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
932    i = 8;
933    if (modname) {
934      i+=strlen(modname);
935    }
936   
937    if (!(buf = malloc(i))) {
938      return -1;
939    }
940   
941    i=0;
942   
943    if (modname) {
944      memcpy(buf, modname, strlen(modname));
945      i+=strlen(modname);
946    }
947   
948    /* Damn endianness. This must be little (LSB first) endian. */
949    buf[i++] = offset & 0xff;
950    buf[i++] = (offset >> 8) & 0xff;
951    buf[i++] = (offset >> 16) & 0xff;
952    buf[i++] = (offset >> 24) & 0xff;
953    buf[i++] = len & 0xff;
954    buf[i++] = (len >> 8) & 0xff;
955    buf[i++] = (len >> 16) & 0xff;
956    buf[i++] = (len >> 24) & 0xff;
957   
958    *bufret = buf;
959    *buflenret = i;
960  } else {
961    if (!(buf = malloc(len))) {
962      free(filename);
963      return -1;
964    }
965    /* printf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename); */
966    if (!(f = fopen(filename, "r"))) {
967      /* perror("memrequest: fopen"); */
968      free(filename);
969      free(buf);
970      return -1;
971    }
972   
973    free(filename);
974   
975    if (fseek(f, offset, SEEK_SET) == -1) {
976      /* perror("memrequest: fseek"); */
977      fclose(f);
978      free(buf);
979      return -1;
980    }
981   
982    if (fread(buf, len, 1, f) != 1) {
983      /* perror("memrequest: fread"); */
984      fclose(f);
985      free(buf);
986      return -1;
987    }
988   
989    fclose(f);
990    *bufret = buf;
991    *buflenret = len;
992  }
993  return 0; /* success! */
994}
995
996/*
997 * This will get an offset and a length.  The client should read this
998 * data out of whatever AIM.EXE binary the user has provided (hopefully
999 * it matches the client information thats sent at login) and pass a
1000 * buffer back to libfaim so it can hash the data and send it to AOL for
1001 * inspection by the client police.
1002 */
1003static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...)
1004{
1005  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
1006  va_list ap;
1007  fu32_t offset, len;
1008  char *modname;
1009  unsigned char *buf;
1010  int buflen;
1011 
1012  va_start(ap, fr);
1013  offset = va_arg(ap, fu32_t);
1014  len = va_arg(ap, fu32_t);
1015  modname = va_arg(ap, char *);
1016  va_end(ap);
1017 
1018  if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
1019    aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
1020    free(buf);
1021  } else {
1022    /* printf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname); */
1023    aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
1024  }
1025  return 1;
1026}
1027
1028static void printuserflags(fu16_t flags)
1029{
1030
1031  if (flags & AIM_FLAG_UNCONFIRMED)
1032    printf("UNCONFIRMED ");
1033  if (flags & AIM_FLAG_ADMINISTRATOR)
1034    printf("ADMINISTRATOR ");
1035  if (flags & AIM_FLAG_AOL)
1036    printf("AOL ");
1037  if (flags & AIM_FLAG_OSCAR_PAY)
1038    printf("OSCAR_PAY ");
1039  if (flags & AIM_FLAG_FREE)
1040    printf("FREE ");
1041  if (flags & AIM_FLAG_AWAY)
1042    printf("AWAY ");
1043  if (flags & AIM_FLAG_ICQ)
1044    printf("ICQ ");
1045  if (flags & AIM_FLAG_WIRELESS)
1046    printf("WIRELESS ");
1047  if (flags & AIM_FLAG_ACTIVEBUDDY)
1048    printf("ACTIVEBUDDY ");
1049 
1050  return;
1051}
1052
1053static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
1054{
1055  aim_userinfo_t *userinfo;
1056  char *prof_encoding = NULL;
1057  char *prof = NULL;
1058  fu16_t inforeq = 0;
1059  owl_buddy *b;
1060  va_list ap;
1061  va_start(ap, fr);
1062  userinfo = va_arg(ap, aim_userinfo_t *);
1063  inforeq = (fu16_t)va_arg(ap, unsigned int);
1064  prof_encoding = va_arg(ap, char *);
1065  prof = va_arg(ap, char *);
1066  va_end(ap);
1067
1068  /* right now the only reason we call this is for idle times */
1069  owl_function_debugmsg("parse_userinfo sn: %s idle: %i", userinfo->sn, userinfo->idletime);
1070  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g),
1071                                userinfo->sn);
1072  if (!b) return(1);
1073  owl_buddy_set_idle_since(b, userinfo->idletime);
1074  return(1);
1075
1076  /*
1077  printf("userinfo: sn: %s\n", userinfo->sn);
1078  printf("userinfo: warnlevel: %f\n", aim_userinfo_warnlevel(userinfo));
1079  printf("userinfo: flags: 0x%04x = ", userinfo->flags);
1080  printuserflags(userinfo->flags);
1081  printf("\n");
1082  */
1083
1084  /*
1085  printf("userinfo: membersince: %lu\n", userinfo->membersince);
1086  printf("userinfo: onlinesince: %lu\n", userinfo->onlinesince);
1087  printf("userinfo: idletime: 0x%04x\n", userinfo->idletime);
1088  printf("userinfo: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
1089  */
1090 
1091  if (inforeq == AIM_GETINFO_GENERALINFO) {
1092    owl_function_debugmsg("userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1093    owl_function_debugmsg("userinfo: prof: %s\n", prof ? prof : "[none]");
1094  } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
1095    owl_function_debugmsg("userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
1096    owl_function_debugmsg("userinfo: awaymsg: %s\n", prof ? prof : "[none]");
1097  } else if (inforeq == AIM_GETINFO_CAPABILITIES) {
1098    owl_function_debugmsg("userinfo: capabilities: see above\n");
1099  } else {
1100    owl_function_debugmsg("userinfo: unknown info request\n");
1101  }
1102 
1103  return(1);
1104}
1105
1106#if 0
1107static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, const char *tmpstr)
1108{
1109  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
1110 
1111  if (!strncmp(tmpstr, "disconnect", 10)) {
1112    logout(sess);
1113  } else if (strstr(tmpstr, "goodday")) {
1114    /* aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too."); */
1115  } else if (strstr(tmpstr, "haveicon") && priv->buddyicon) {
1116    struct aim_sendimext_args args;
1117    /* static const char iconmsg[] = {"I have an icon"}; */
1118    static const char iconmsg[] = {""};
1119   
1120    args.destsn = userinfo->sn;
1121    args.flags = AIM_IMFLAGS_HASICON;
1122    args.msg = iconmsg;
1123    args.msglen = strlen(iconmsg);
1124    args.iconlen = priv->buddyiconlen;
1125    args.iconstamp = priv->buddyiconstamp;
1126    args.iconsum = priv->buddyiconsum;
1127   
1128    /* aim_send_im_ext(sess, &args); */
1129   
1130  } else if (strstr(tmpstr, "sendbin")) {
1131    struct aim_sendimext_args args;
1132    static const unsigned char data[] = {
1133      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1134      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1135      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1136      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1137      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1138      0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1139    };
1140   
1141    /*
1142     * I put this here as a demonstration of how to send
1143     * arbitrary binary data via OSCAR ICBM's without the need
1144     * for escape or baseN encoding of any sort. 
1145     *
1146     * Apparently if you set the charset to something WinAIM
1147     * doesn't recognize, it will completly ignore the message.
1148     * That is, it will not display anything in the conversation
1149     * window for the user that recieved it.
1150     *
1151     * HOWEVER, if they do not have a conversation window open
1152     * for you, a new one will be created, but it will not have
1153     * any messages in it.  Therefore sending these things could
1154     * be a great way to seemingly subliminally convince people
1155     * to talk to you...
1156     *
1157     */
1158    args.destsn = userinfo->sn;
1159    /* args.flags = AIM_IMFLAGS_CUSTOMCHARSET; */
1160    args.charset = args.charsubset = 0x4242;
1161    args.msg = data;
1162    args.msglen = sizeof(data);
1163    /* aim_send_im_ext(sess, &args); */
1164   } else if (strstr(tmpstr, "sendmulti")) {
1165    struct aim_sendimext_args args;
1166    aim_mpmsg_t mpm;
1167    static const fu16_t unidata[] = { /* "UNICODE." */
1168      0x0055, 0x004e, 0x0049, 0x0043,
1169      0x004f, 0x0044, 0x0045, 0x002e,
1170    };
1171    static const int unidatalen = 8;
1172   
1173    /*
1174     * This is how multipart messages should be sent.
1175     *
1176     * This should render as:
1177     *        "Part 1, ASCII.  UNICODE.Part 3, ASCII.  "
1178     */
1179   
1180    aim_mpmsg_init(sess, &mpm);
1181    aim_mpmsg_addascii(sess, &mpm, "Part 1, ASCII.  ");
1182    aim_mpmsg_addunicode(sess, &mpm, unidata, unidatalen);
1183    aim_mpmsg_addascii(sess, &mpm, "Part 3, ASCII.  ");
1184   
1185    args.destsn = userinfo->sn;
1186    args.flags = AIM_IMFLAGS_MULTIPART;
1187    args.mpmsg = &mpm;
1188   
1189    /* aim_send_im_ext(sess, &args); */
1190   
1191    aim_mpmsg_free(sess, &mpm);
1192   
1193  } else if (strstr(tmpstr, "sendprebin")) {
1194    static const unsigned char data[] = {
1195      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1196      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1197      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1198      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1199      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1200      0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1201    };
1202    struct aim_sendimext_args args;
1203    aim_mpmsg_t mpm;
1204   
1205    /*
1206     * This demonstrates sending a human-readable preamble,
1207     * and then arbitrary binary data.
1208     *
1209     * This means that you can very inconspicuously send binary
1210     * attachments to other users.  In WinAIM, this appears as
1211     * though it only had the ASCII portion.
1212     *
1213     */
1214   
1215    aim_mpmsg_init(sess, &mpm);
1216    aim_mpmsg_addascii(sess, &mpm, "This message has binary data.");
1217    aim_mpmsg_addraw(sess, &mpm, 0x4242, 0x4242, data, sizeof(data));
1218   
1219    args.destsn = userinfo->sn;
1220    args.flags = AIM_IMFLAGS_MULTIPART;
1221    args.mpmsg = &mpm;
1222   
1223    /* aim_send_im_ext(sess, &args); */
1224    aim_mpmsg_free(sess, &mpm);
1225   
1226  } else if (strstr(tmpstr, "havefeat")) {
1227    struct aim_sendimext_args args;
1228    static const char featmsg[] = {"I have nifty features."};
1229    fu8_t features[] = {0x01, 0x01, 0x01, 0x02, 0x42, 0x43, 0x44, 0x45};
1230   
1231    args.destsn = userinfo->sn;
1232    args.flags = AIM_IMFLAGS_CUSTOMFEATURES;
1233    args.msg = featmsg;
1234    args.msglen = strlen(featmsg);
1235    args.features = features;
1236    args.featureslen = sizeof(features);
1237   
1238    /* aim_send_im_ext(sess, &args); */
1239  } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) {
1240    /* aim_send_icon(sess, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum); */
1241  } else if (strstr(tmpstr, "warnme")) {
1242    /* printf("icbm: sending non-anon warning\n"); */
1243    /* aim_send_warning(sess, conn, userinfo->sn, 0); */
1244  } else if (strstr(tmpstr, "anonwarn")) {
1245    /* printf("icbm: sending anon warning\n"); */
1246    /* aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON); */
1247  } else if (strstr(tmpstr, "setdirectoryinfo")) {
1248    /* printf("icbm: sending backwards profile data\n"); */
1249    aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
1250  } else if (strstr(tmpstr, "setinterests")) {
1251    /* printf("icbm: setting fun interests\n"); */
1252    aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
1253  } else if (!strncmp(tmpstr, "open chatnav", 12)) {
1254    aim_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV);
1255  } else if (!strncmp(tmpstr, "create", 6)) {
1256    aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
1257  } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1258    aim_conn_t *chatnavconn;
1259    if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)))
1260      aim_conn_kill(sess, &chatnavconn);
1261  } else if (!strncmp(tmpstr, "join", 4)) {
1262    aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000);
1263  } else if (!strncmp(tmpstr, "leave", 5)) {
1264    aim_chat_leaveroom(sess, "worlddomination");
1265  } else if (!strncmp(tmpstr, "getinfo", 7)) {
1266    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO);
1267    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
1268    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_CAPABILITIES);
1269  } else if(strstr(tmpstr, "lookup")) {
1270    /* aim_usersearch_address(sess, conn, "mid@auk.cx"); */
1271  } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1272    /* aim_send_im(sess, priv->ohcaptainmycaptain, 0, "sendmsg 7900"); */
1273  } else if (!strncmp(tmpstr, "reqadmin", 8)) {
1274    aim_reqservice(sess, conn, AIM_CONN_TYPE_AUTH);
1275  } else if (!strncmp(tmpstr, "changenick", 10)) {
1276    aim_admin_setnick(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "diputs8  1");
1277  } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1278    aim_admin_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1279  } else if (!strncmp(tmpstr, "reqemail", 8)) {
1280    aim_admin_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1281  } else if (!strncmp(tmpstr, "changepass", 8)) {
1282    aim_admin_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1283  } else if (!strncmp(tmpstr, "setemail", 8)) {
1284    aim_admin_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1285  } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1286    int i;
1287   
1288    i = atoi(tmpstr+8);
1289    if (i < 10000) {
1290      char *newbuf;
1291      int z;
1292     
1293      newbuf = malloc(i+1);
1294      for (z = 0; z < i; z++)
1295        newbuf[z] = (z % 10)+0x30;
1296      newbuf[i] = '\0';
1297      /* aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK | AIM_IMFLAGS_AWAY, newbuf); */
1298      free(newbuf);
1299    }
1300  } else if (strstr(tmpstr, "seticqstatus")) {
1301    aim_setextstatus(sess, AIM_ICQ_STATE_DND);
1302  } else if (strstr(tmpstr, "rtfmsg")) {
1303    static const char rtfmsg[] = {"{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fswiss\\fcharset0 Arial;}{\\f1\\froman\\fprq2\\fcharset0 Georgia;}{\\f2\\fmodern\\fprq1\\fcharset0 MS Mincho;}{\\f3\\froman\\fprq2\\fcharset2 Symbol;}}\\viewkind4\\uc1\\pard\\f0\\fs20 Test\\f1 test\\f2\fs44 test\\f3\\fs20 test\\f0\\par}"};
1304    struct aim_sendrtfmsg_args rtfargs;
1305   
1306    memset(&rtfargs, 0, sizeof(rtfargs));
1307    rtfargs.destsn = userinfo->sn;
1308    rtfargs.fgcolor = 0xffffffff;
1309    rtfargs.bgcolor = 0x00000000;
1310    rtfargs.rtfmsg = rtfmsg;
1311    /* aim_send_rtfmsg(sess, &rtfargs); */
1312  } else {
1313    /* printf("unknown command.\n"); */
1314    aim_add_buddy(sess, conn, userinfo->sn);
1315  } 
1316 
1317  return 0;
1318}
1319#endif
1320
1321/*
1322 * Channel 1: Standard Message
1323 */
1324static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args)
1325{
1326  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
1327  owl_message *m;
1328  char *stripmsg, *nz_screenname, *wrapmsg;
1329  char realmsg[8192+1] = {""};
1330  /* int clienttype = AIM_CLIENTTYPE_UNKNOWN; */
1331
1332  /* clienttype = aim_fingerprintclient(args->features, args->featureslen); */
1333
1334  /*
1335  printf("icbm: sn = \"%s\"\n", userinfo->sn);
1336  printf("icbm: probable client type: %d\n", clienttype);
1337  printf("icbm: warnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1338  printf("icbm: flags = 0x%04x = ", userinfo->flags);
1339  printuserflags(userinfo->flags);
1340  printf("\n");
1341  */
1342
1343  /*
1344  printf("icbm: membersince = %lu\n", userinfo->membersince);
1345  printf("icbm: onlinesince = %lu\n", userinfo->onlinesince);
1346  printf("icbm: idletime = 0x%04x\n", userinfo->idletime);
1347  printf("icbm: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
1348  */
1349
1350  /*
1351  printf("icbm: icbmflags = ");
1352  if (args->icbmflags & AIM_IMFLAGS_AWAY) printf("away ");
1353  if (args->icbmflags & AIM_IMFLAGS_ACK) printf("ackrequest ");
1354  if (args->icbmflags & AIM_IMFLAGS_OFFLINE) printf("offline ");
1355  if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) printf("buddyreq ");
1356  if (args->icbmflags & AIM_IMFLAGS_HASICON) printf("hasicon ");
1357  printf("\n");
1358  */
1359
1360  /*
1361  if (args->icbmflags & AIM_IMFLAGS_CUSTOMCHARSET) {
1362  printf("icbm: encoding flags = {%04x, %04x}\n", args->charset, args->charsubset);
1363  }
1364  */
1365 
1366  /*
1367   * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1368   * characters with their equivelent HTML entity.
1369   */
1370  if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1371    int i;
1372   
1373    for (i=0; i<args->msglen; i+=2) {
1374      fu16_t uni;
1375
1376      uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1377      if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1378        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
1379      } else { /* something else, do UNICODE entity */
1380        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
1381      }
1382    }
1383  } else {
1384    /*
1385     * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1386     * no need to do anything special here.  Most
1387     * terminals/whatever will be able to display such characters
1388     * unmodified.
1389     *
1390     * Beware that PC-ASCII 128 through 159 are _not_ actually
1391     * defined in ASCII or ISO 8859-1, and you should send them as
1392     * UNICODE.  WinAIM will send these characters in a UNICODE
1393     * message, so you need to do so as well.
1394     *
1395     * You may not think it necessary to handle UNICODE messages. 
1396     * You're probably wrong.  For one thing, Microsoft "Smart
1397     * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1398     * but real UNICODE). If you don't parse UNICODE at all, your
1399     * users will get a blank message instead of the message
1400     * containing Smart Quotes.
1401     *
1402     */
1403    strncpy(realmsg, args->msg, sizeof(realmsg));
1404  }
1405
1406  /* create a message, and put it on the message queue */
1407  stripmsg=owl_text_htmlstrip(realmsg);
1408  wrapmsg=owl_text_wordwrap(stripmsg, 70);
1409  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1410  m=owl_malloc(sizeof(owl_message));
1411  owl_message_create_aim(m,
1412                         nz_screenname,
1413                         owl_global_get_aim_screenname(&g),
1414                         wrapmsg,
1415                         OWL_MESSAGE_DIRECTION_IN,
1416                         0);
1417  owl_global_messagequeue_addmsg(&g, m);
1418  owl_free(stripmsg);
1419  owl_free(wrapmsg);
1420  owl_free(nz_screenname);
1421
1422  return(1);
1423 
1424  /* printf("icbm: message: %s\n", realmsg); */
1425 
1426  if (args->icbmflags & AIM_IMFLAGS_MULTIPART) {
1427    aim_mpmsg_section_t *sec;
1428    int z;
1429
1430    /* printf("icbm: multipart: this message has %d parts\n", args->mpmsg.numparts); */
1431   
1432    for (sec = args->mpmsg.parts, z = 0; sec; sec = sec->next, z++) {
1433      if ((sec->charset == 0x0000) || (sec->charset == 0x0003) || (sec->charset == 0xffff)) {
1434        /* printf("icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, msg = %s\n", z, sec->charset, sec->charsubset, sec->data); */
1435      } else {
1436        /* printf("icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, binary or UNICODE data\n", z, sec->charset, sec->charsubset); */
1437      }
1438    }
1439  }
1440 
1441  if (args->icbmflags & AIM_IMFLAGS_HASICON) {
1442    /* aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon"); */
1443    /* printf("icbm: their icon: iconstamp = %ld, iconlen = 0x%08lx, iconsum = 0x%04x\n", args->iconstamp, args->iconlen, args->iconsum); */
1444  }
1445
1446  /*
1447  if (realmsg) {
1448    int i = 0;
1449    while (realmsg[i] == '<') {
1450      if (realmsg[i] == '<') {
1451        while (realmsg[i] != '>')
1452          i++;
1453        i++;
1454      }
1455    }
1456    tmpstr = realmsg+i;
1457    faimtest_handlecmd(sess, conn, userinfo, tmpstr);
1458  }
1459  */
1460 
1461  if (priv->buddyicon && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)) {
1462    /* aim_send_icon(sess, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum); */
1463  }
1464 
1465  return(1);
1466}
1467
1468/*
1469 * Channel 2: Rendevous Request
1470 */
1471static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
1472{
1473  /*
1474  printf("rendezvous: source sn = %s\n", userinfo->sn);
1475  printf("rendezvous: \twarnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1476  printf("rendezvous: \tclass = 0x%04x = ", userinfo->flags);
1477  printuserflags(userinfo->flags);
1478  printf("\n");
1479 
1480  printf("rendezvous: \tonlinesince = %lu\n", userinfo->onlinesince);
1481  printf("rendezvous: \tidletime = 0x%04x\n", userinfo->idletime);
1482 
1483  printf("rendezvous: message/description = %s\n", args->msg);
1484  printf("rendezvous: encoding = %s\n", args->encoding);
1485  printf("rendezvous: language = %s\n", args->language);
1486  */
1487 
1488  if (args->reqclass == AIM_CAPS_SENDFILE) {
1489    /* printf("send file!\n"); */
1490  } else if (args->reqclass == AIM_CAPS_CHAT) {
1491    owl_function_debugmsg("chat invite: %s, %i, %i", args->info.chat.roominfo.name, args->info.chat.roominfo.exchange, args->info.chat.roominfo.instance);
1492    /*
1493    printf("chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1494    printf("chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1495    printf("chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1496    */
1497    /* Automatically join room... */
1498    /* printf("chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); */
1499
1500    /* aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance); */
1501  } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1502    /* printf("Buddy Icon from %s, length = %lu\n", userinfo->sn, args->info.icon.length); */
1503  } else if (args->reqclass == AIM_CAPS_ICQRTF) {
1504    /* printf("RTF message from %s: (fgcolor = 0x%08lx, bgcolor = 0x%08lx) %s\n", userinfo->sn, args->info.rtfmsg.fgcolor, args->info.rtfmsg.bgcolor, args->info.rtfmsg.rtfmsg); */
1505  } else {
1506    /* printf("icbm: unknown reqclass (%d)\n", args->reqclass); */
1507  }
1508  return 1;
1509}
1510
1511static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1512{
1513  fu16_t channel;
1514  aim_userinfo_t *userinfo;
1515  va_list ap;
1516  int ret = 0;
1517 
1518  va_start(ap, fr);
1519  channel = (fu16_t)va_arg(ap, unsigned int);
1520  userinfo = va_arg(ap, aim_userinfo_t *);
1521 
1522  if (channel == 1) {
1523    struct aim_incomingim_ch1_args *args;
1524    args = va_arg(ap, struct aim_incomingim_ch1_args *);
1525    ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, args);
1526  } else if (channel == 2) {
1527    struct aim_incomingim_ch2_args *args;
1528    args = va_arg(ap, struct aim_incomingim_ch2_args *);
1529    ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, args);
1530  } else {
1531    /* printf("unsupported channel 0x%04x\n", channel); */
1532  }
1533  va_end(ap);
1534  /* printf("icbm: done with ICBM handling (ret = %d)\n", ret); */
1535  return 1;
1536}
1537
1538static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1539{
1540  aim_userinfo_t *userinfo;
1541  char *nz_screenname;
1542  owl_buddy *b;
1543  owl_buddylist *bl;
1544  va_list ap;
1545  va_start(ap, fr);
1546  userinfo = va_arg(ap, aim_userinfo_t *);
1547  va_end(ap);
1548
1549  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1550  bl=owl_global_get_buddylist(&g);
1551 
1552  owl_buddylist_oncoming(owl_global_get_buddylist(&g), nz_screenname);
1553
1554  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1555    /*  */
1556  }
1557
1558  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g), nz_screenname);
1559  if (!b) {
1560    owl_function_debugmsg("Error: parse_oncoming setting idle time with no buddy present.");
1561    return(1);
1562  }
1563  if (userinfo->idletime==0) {
1564    owl_buddy_set_unidle(b);
1565  } else {
1566    owl_buddy_set_idle(b);
1567    owl_buddy_set_idle_since(b, userinfo->idletime);
1568  }
1569
1570  if (userinfo->flags & AIM_FLAG_AWAY) {
1571    owl_function_debugmsg("parse_oncoming sn: %s away flag!", userinfo->sn);
1572  }
1573 
1574  owl_function_debugmsg("parse_oncoming sn: %s idle: %i", userinfo->sn, userinfo->idletime);
1575   
1576  owl_free(nz_screenname);
1577 
1578  /*
1579    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1580    time(NULL),
1581    userinfo->sn, userinfo->flags,
1582    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1583    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1584    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1585    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1586    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1587    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1588    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1589    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1590    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1591    userinfo->capabilities);
1592  */
1593  return(1);
1594}
1595
1596static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1597{
1598  aim_userinfo_t *userinfo;
1599  char *nz_screenname;
1600  va_list ap;
1601 
1602  va_start(ap, fr);
1603  userinfo = va_arg(ap, aim_userinfo_t *);
1604  va_end(ap);
1605
1606  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1607  owl_buddylist_offgoing(owl_global_get_buddylist(&g), nz_screenname);
1608  owl_free(nz_screenname);
1609
1610  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1611    owl_function_debugmsg("parse_offgoing sn: %s idle time %i", userinfo->sn, userinfo->idletime);
1612  }
1613
1614  /*
1615  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1616         time(NULL),
1617         userinfo->sn, userinfo->flags,
1618         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1619         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1620         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1621         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1622         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1623         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1624         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1625         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1626         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1627         userinfo->capabilities);
1628  */
1629 
1630  return 1;
1631}
1632
1633/* Used by chat as well. */
1634int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1635{
1636  va_list ap;
1637  fu16_t reason;
1638 
1639  va_start(ap, fr);
1640  reason = (fu16_t)va_arg(ap, unsigned int);
1641  va_end(ap);
1642 
1643  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1644  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
1645 
1646  return 1;
1647}
1648
1649static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1650{
1651  va_list ap;
1652  char *destsn;
1653  fu16_t reason;
1654 
1655  va_start(ap, fr);
1656  reason = (fu16_t)va_arg(ap, unsigned int);
1657  destsn = va_arg(ap, char *);
1658  va_end(ap);
1659 
1660  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1661  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
1662
1663  if (reason==4) {
1664    owl_function_adminmsg("", "Could not send AIM message, user not logged on");
1665  }
1666 
1667  return 1;
1668}
1669
1670static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1671{
1672  va_list ap;
1673  char *destsn;
1674  fu16_t reason;
1675 
1676  va_start(ap, fr);
1677  reason = (fu16_t)va_arg(ap, unsigned int);
1678  destsn = va_arg(ap, char *);
1679  va_end(ap);
1680 
1681  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1682  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
1683 
1684  return 1;
1685}
1686
1687static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1688{
1689  /*
1690  static char *missedreasons[] = {
1691    "Invalid (0)",
1692    "Message too large",
1693    "Rate exceeded",
1694    "Evil Sender",
1695    "Evil Receiver"
1696  };
1697  static int missedreasonslen = 5; */
1698 
1699  va_list ap;
1700  fu16_t chan, nummissed, reason;
1701  aim_userinfo_t *userinfo;
1702 
1703  va_start(ap, fr);
1704  chan = (fu16_t)va_arg(ap, unsigned int);
1705  userinfo = va_arg(ap, aim_userinfo_t *);
1706  nummissed = (fu16_t)va_arg(ap, unsigned int);
1707  reason = (fu16_t)va_arg(ap, unsigned int);
1708  va_end(ap);
1709 
1710  /* printf("missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown"); */
1711 
1712  return 1;
1713}
1714
1715/*
1716 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1717 */
1718static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1719{
1720  va_list ap;
1721  fu16_t type;
1722  char *sn = NULL;
1723 
1724  va_start(ap, fr);
1725  type = (fu16_t)va_arg(ap, unsigned int);
1726  sn = va_arg(ap, char *);
1727  va_end(ap);
1728 
1729  /* printf("msgack: 0x%04x / %s\n", type, sn); */
1730 
1731  return 1;
1732}
1733
1734static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1735{
1736  /*
1737  static char *codes[5] = {
1738    "invalid",
1739    "change",
1740    "warning",
1741    "limit",
1742    "limit cleared"
1743  };
1744  */
1745  va_list ap;
1746  fu16_t code, rateclass;
1747  fu32_t windowsize, clear, alert, limit, disconnect;
1748  fu32_t currentavg, maxavg;
1749 
1750  va_start(ap, fr); 
1751 
1752  /* See code explanations below */
1753  code = (fu16_t)va_arg(ap, unsigned int);
1754 
1755  /*
1756   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1757   */
1758  rateclass = (fu16_t)va_arg(ap, unsigned int);
1759 
1760  /*
1761   * Not sure what this is exactly.  I think its the temporal
1762   * relation factor (ie, how to make the rest of the numbers
1763   * make sense in the real world).
1764   */
1765  windowsize = va_arg(ap, fu32_t);
1766 
1767  /* Explained below */
1768  clear = va_arg(ap, fu32_t);
1769  alert = va_arg(ap, fu32_t);
1770  limit = va_arg(ap, fu32_t);
1771  disconnect = va_arg(ap, fu32_t);
1772  currentavg = va_arg(ap, fu32_t);
1773  maxavg = va_arg(ap, fu32_t);
1774 
1775  va_end(ap);
1776 
1777  /*
1778  printf("rate %s (rate class 0x%04x): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
1779         (code < 5)?codes[code]:"invalid",
1780         rateclass,
1781         currentavg, maxavg,
1782         alert, clear,
1783         limit, disconnect,
1784         windowsize);
1785  */
1786  return 1;
1787}
1788
1789static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1790{
1791  va_list ap;
1792  fu16_t newevil;
1793  aim_userinfo_t *userinfo;
1794 
1795  va_start(ap, fr);
1796  newevil = (fu16_t)va_arg(ap, unsigned int);
1797  userinfo = va_arg(ap, aim_userinfo_t *);
1798  va_end(ap);
1799 
1800  /*
1801   * Evil Notifications that are lacking userinfo->sn are anon-warns
1802   * if they are an evil increases, but are not warnings at all if its
1803   * a decrease (its the natural backoff happening).
1804   *
1805   * newevil is passed as an int representing the new evil value times
1806   * ten.
1807   */
1808  /* printf("evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous"); */
1809 
1810  return 1;
1811}
1812
1813static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1814{
1815  va_list ap;
1816  char *address, *SNs;
1817  int num;
1818  /* int i; */
1819 
1820  va_start(ap, fr);
1821  address = va_arg(ap, char *);
1822  num = va_arg(ap, int);
1823  SNs = va_arg(ap, char *);
1824  va_end(ap);
1825 
1826  /* printf("E-Mail Search Results for %s: ", address);
1827 
1828  for(i = 0; i < num; i++)
1829    printf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1830  printf("\n");
1831  */
1832 
1833  return 1;
1834}
1835
1836static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1837{
1838  va_list ap;
1839  char *address;
1840 
1841  va_start(ap, fr);
1842  address = va_arg(ap, char *);
1843  va_end(ap);
1844 
1845  /* printf("E-Mail Search Results for %s: No Results or Invalid Email\n", address); */
1846 
1847  return 1;
1848}
1849
1850static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1851{
1852  va_list ap;
1853  char *msg, *url;
1854  fu16_t width, height, delay;
1855 
1856  va_start(ap, fr);
1857  msg = va_arg(ap, char *);
1858  url = va_arg(ap, char *);
1859  width = va_arg(ap, unsigned int);
1860  height = va_arg(ap, unsigned int);
1861  delay = va_arg(ap, unsigned int);
1862  va_end(ap);
1863 
1864  /* printf("popup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url); */
1865 
1866  return 1;
1867}
1868
1869static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1870{
1871  aim_sendpauseack(sess, fr->conn);
1872  return 1;
1873}
1874
1875static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1876{
1877  va_list ap;
1878  aim_conn_t *bosconn;
1879  char *bosip;
1880  fu8_t *cookie;
1881 
1882  va_start(ap, fr);
1883  bosip = va_arg(ap, char *);
1884  cookie = va_arg(ap, fu8_t *);
1885  va_end(ap);
1886 
1887  /* printf("migration in progress -- new BOS is %s -- disconnecting\n", bosip); */
1888  aim_conn_kill(sess, &fr->conn);
1889 
1890  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1891    /* printf("migrate: could not connect to BOS: internal error\n"); */
1892    return 1;
1893  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1894    /* printf("migrate: could not connect to BOS\n"); */
1895    aim_conn_kill(sess, &bosconn);
1896    return 1;
1897  }
1898 
1899  /* Login will happen all over again. */
1900  addcb_bos(sess, bosconn);
1901  /* aim_sendcookie(sess, bosconn, cookie); */
1902  return 1;
1903}
1904
1905static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1906{
1907  /* printf("got SSI rights, requesting data\n"); */
1908  /* aim_ssi_reqdata(sess, fr->conn, 0, 0x0000); */
1909  aim_ssi_reqdata(sess);
1910 
1911  return(1);
1912}
1913
1914static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1915{
1916  va_list ap;
1917  fu8_t fmtver;
1918  fu16_t itemcount;
1919  fu32_t stamp;
1920  struct aim_ssi_item *list;
1921  struct aim_ssi_item *curitem;
1922  /* struct aim_ssi_item *l; */
1923 
1924  va_start(ap, fr);
1925  fmtver = va_arg(ap, unsigned int);
1926  itemcount = va_arg(ap, unsigned int);
1927  stamp = va_arg(ap, fu32_t);
1928  list = va_arg(ap, struct aim_ssi_item *);
1929  va_end(ap);
1930 
1931  /* printf("got SSI data: (0x%02x, %d items, %ld)\n", fmtver, itemcount, stamp); */
1932  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
1933    /* for (l = list; l; l = l->next) { */
1934    /* printf("\t0x%04x (%s) - 0x%04x/0x%04x\n", l->type, l->name, l->gid, l->bid); */
1935    /* printf("I would have printed data here!\n"); */
1936  }
1937 
1938  aim_ssi_enable(sess);
1939 
1940  return 1;
1941}
1942
1943static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1944{
1945  /* printf("server says we have the latest SSI data already\n"); */
1946  /* aim_ssi_enable(sess, fr->conn); */
1947  aim_ssi_enable(sess);
1948  return 1;
1949}
1950
1951static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1952{
1953  va_list ap;
1954  struct aim_icq_offlinemsg *msg;
1955 
1956  va_start(ap, fr);
1957  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1958  va_end(ap);
1959 
1960  if (msg->type == 0x0001) {
1961    /* printf("offline message from %ld at %d/%d/%d %02d:%02d : %s\n", msg->sender, msg->year, msg->month, msg->day, msg->hour, msg->minute, msg->msg); */
1962  } else {
1963    /* printf("unknown offline message type 0x%04x\n", msg->type); */
1964  }
1965  return 1;
1966}
1967
1968static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1969{
1970  /* Tell the server to delete them. */
1971  aim_icq_ackofflinemsgs(sess);
1972  return 1;
1973}
1974
1975
1976/******************** chat.c **************************/
1977
1978
1979static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1980{
1981  va_list ap;
1982  aim_userinfo_t *userinfo;
1983  int count;
1984  /* int i; */
1985 
1986  va_start(ap, fr);
1987  count = va_arg(ap, int);
1988  userinfo = va_arg(ap, aim_userinfo_t *);
1989  va_end(ap);
1990
1991  owl_function_debugmsg("In faimtest_chat_join");
1992  /*
1993  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1994  for (i = 0; i < count; i++)
1995    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1996  */
1997  return 1;
1998}
1999
2000static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
2001{
2002  aim_userinfo_t *userinfo;
2003  va_list ap;
2004  int count;
2005  /* int i; */
2006
2007 
2008  va_start(ap, fr);
2009  count = va_arg(ap, int);
2010  userinfo = va_arg(ap, aim_userinfo_t *);
2011  va_end(ap);
2012 
2013  /*
2014    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
2015   
2016    for (i = 0; i < count; i++)
2017    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
2018  */
2019  return 1;
2020}
2021
2022static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
2023{
2024  va_list ap;
2025  aim_userinfo_t *userinfo;
2026  struct aim_chat_roominfo *roominfo;
2027  char *roomname;
2028  int usercount;
2029  char *roomdesc;
2030  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
2031  fu32_t creationtime;
2032  const char *croomname;
2033  /* int i; */
2034 
2035  croomname = aim_chat_getname(fr->conn);
2036 
2037  va_start(ap, fr);
2038  roominfo = va_arg(ap, struct aim_chat_roominfo *);
2039  roomname = va_arg(ap, char *);
2040  usercount = va_arg(ap, int);
2041  userinfo = va_arg(ap, aim_userinfo_t *);
2042  roomdesc = va_arg(ap, char *);
2043  flags = (fu16_t)va_arg(ap, unsigned int);
2044  creationtime = va_arg(ap, fu32_t);
2045  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
2046  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
2047  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
2048  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
2049  va_end(ap);
2050
2051  owl_function_debugmsg("In faimtest_chat_infoupdate");
2052  /*
2053  printf("chat: %s:  info update:\n", croomname);
2054  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
2055  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
2056  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
2057  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
2058
2059  for (i = 0; i < usercount; i++)
2060    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
2061 
2062  owl_function_debugmsg("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
2063         croomname, flags,
2064         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
2065         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
2066         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
2067         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
2068  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
2069  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
2070  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
2071  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
2072  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
2073  */
2074 
2075  return(1);
2076}
2077
2078static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
2079{
2080  va_list ap;
2081  aim_userinfo_t *userinfo;
2082  char *msg;
2083  char tmpbuf[1152];
2084 
2085  va_start(ap, fr);
2086  userinfo = va_arg(ap, aim_userinfo_t *);     
2087  msg = va_arg(ap, char *);
2088  va_end(ap);
2089
2090  owl_function_debugmsg("in faimtest_chat_incomingmsg");
2091
2092  /*
2093  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
2094  */
2095 
2096  /*
2097   * Do an echo for testing purposes.  But not for ourselves ("oops!")
2098   */
2099  if (strcmp(userinfo->sn, sess->sn) != 0) {
2100    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
2101    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
2102  }
2103 
2104  return 1;
2105}
2106
2107static int faimtest_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...)
2108{
2109  fu16_t type;
2110  va_list ap;
2111 
2112  va_start(ap, fr);
2113  type = (fu16_t)va_arg(ap, unsigned int);
2114
2115  owl_function_debugmsg("in faimtest_chatnav_info");
2116 
2117  if (type == 0x0002) {
2118    int maxrooms;
2119    struct aim_chat_exchangeinfo *exchanges;
2120    int exchangecount;
2121    /* int i; */
2122   
2123    maxrooms = va_arg(ap, int);
2124    exchangecount = va_arg(ap, int);
2125    exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
2126    va_end(ap);
2127
2128    /*
2129    printf("chat info: Chat Rights:\n");
2130    printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
2131    printf("chat info: \tExchange List: (%d total)\n", exchangecount);
2132    for (i = 0; i < exchangecount; i++) {
2133      printf("chat info: \t\t%x: %s (%s/%s) (0x%04x = %s%s%s%s)\n",
2134             exchanges[i].number,
2135             exchanges[i].name,
2136             exchanges[i].charset1,
2137             exchanges[i].lang1,
2138             exchanges[i].flags,
2139             (exchanges[i].flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
2140             (exchanges[i].flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
2141             (exchanges[i].flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
2142             (exchanges[i].flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
2143    }
2144    */
2145  } else if (type == 0x0008) {
2146    char *fqcn, *name, *ck;
2147    fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
2148    fu8_t createperms;
2149    fu32_t createtime;
2150   
2151    fqcn = va_arg(ap, char *);
2152    instance = (fu16_t)va_arg(ap, unsigned int);
2153    exchange = (fu16_t)va_arg(ap, unsigned int);
2154    flags = (fu16_t)va_arg(ap, unsigned int);
2155    createtime = va_arg(ap, fu32_t);
2156    maxmsglen = (fu16_t)va_arg(ap, unsigned int);
2157    maxoccupancy = (fu16_t)va_arg(ap, unsigned int);
2158    createperms = (fu8_t)va_arg(ap, unsigned int);
2159    unknown = (fu16_t)va_arg(ap, unsigned int);
2160    name = va_arg(ap, char *);
2161    ck = va_arg(ap, char *);
2162    va_end(ap);
2163   
2164    /* printf("received room create reply for %s/0x%04x\n", fqcn, exchange); */
2165   
2166  } else {
2167    va_end(ap);
2168    /* printf("chatnav info: unknown type (%04x)\n", type); */
2169  }
2170 
2171  return 1;
2172}
2173
2174static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
2175{
2176
2177  owl_function_debugmsg("in faimtest_conninitdone_chat");
2178 
2179  aim_clientready(sess, fr->conn);
2180 
2181  if (fr->conn->type == AIM_CONN_TYPE_CHATNAV) {
2182    /* printf("chatnav ready\n"); */
2183    aim_conn_addhandler(sess, fr->conn, 0x000d, 0x0001, faimtest_parse_genericerr, 0);
2184    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0);
2185    aim_chatnav_reqrights(sess, fr->conn);
2186  } else if (fr->conn->type == AIM_CONN_TYPE_CHAT) {
2187    /* printf("chat ready\n"); */
2188    owl_function_debugmsg("Chat ready");
2189    aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
2190    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
2191    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
2192    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
2193    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
2194  }
2195  return 1;
2196}
2197
2198void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2199{
2200  aim_conn_t *tstconn;
2201
2202  owl_function_debugmsg("in faimtest_chatnav_redirect");
2203 
2204  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
2205  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2206    /* printf("unable to connect to chat(nav) server\n"); */
2207    if (tstconn)
2208      aim_conn_kill(sess, &tstconn);
2209    return;
2210  }
2211 
2212  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2213  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2214  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2215  /* printf("chatnav: connected\n"); */
2216  return;
2217}
2218
2219/* XXX this needs instance too */
2220void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2221{
2222  aim_conn_t *tstconn;
2223
2224  owl_function_debugmsg("in chat_redirect");
2225 
2226  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
2227  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2228    /* printf("unable to connect to chat server\n"); */
2229    if (tstconn) aim_conn_kill(sess, &tstconn);
2230    return; 
2231  }             
2232  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
2233 
2234  /*
2235   * We must do this to attach the stored name to the connection!
2236   */
2237  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
2238  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2239  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2240  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2241  return;       
2242}
2243
2244
2245/****************************************/
2246
2247/*
2248static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) {
2249        struct gaim_connection *gc = sess->aux_data;
2250        struct oscar_data *od = gc->proto_data;
2251        aim_userinfo_t *info;
2252        time_t time_idle = 0, signon = 0;
2253        int type = 0;
2254        int caps = 0;
2255        char *tmp;
2256
2257        va_list ap;
2258        va_start(ap, fr);
2259        info = va_arg(ap, aim_userinfo_t *);
2260        va_end(ap);
2261
2262        if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
2263                caps = info->capabilities;
2264        if (info->flags & AIM_FLAG_ACTIVEBUDDY)
2265                type |= UC_AB;
2266
2267        if ((!od->icq) && (info->present & AIM_USERINFO_PRESENT_FLAGS)) {
2268                        if (info->flags & AIM_FLAG_UNCONFIRMED)
2269                                type |= UC_UNCONFIRMED;
2270                        if (info->flags & AIM_FLAG_ADMINISTRATOR)
2271                                type |= UC_ADMIN;
2272                        if (info->flags & AIM_FLAG_AOL)
2273                                type |= UC_AOL;
2274                        if (info->flags & AIM_FLAG_FREE)
2275                                type |= UC_NORMAL;
2276                        if (info->flags & AIM_FLAG_AWAY)
2277                                type |= UC_UNAVAILABLE;
2278                        if (info->flags & AIM_FLAG_WIRELESS)
2279                                type |= UC_WIRELESS;
2280        }
2281        if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) {
2282                type = (info->icqinfo.status << 16);
2283                if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) &&
2284                      (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) {
2285                        type |= UC_UNAVAILABLE;
2286                }
2287        }
2288
2289        if (caps & AIM_CAPS_ICQ)
2290                caps ^= AIM_CAPS_ICQ;
2291
2292        if (info->present & AIM_USERINFO_PRESENT_IDLE) {
2293                time(&time_idle);
2294                time_idle -= info->idletime*60;
2295        }
2296
2297        if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
2298                signon = time(NULL) - info->sessionlen;
2299
2300        tmp = g_strdup(normalize(gc->username));
2301        if (!strcmp(tmp, normalize(info->sn)))
2302                g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", info->sn);
2303        g_free(tmp);
2304
2305        serv_got_update(gc, info->sn, 1, info->warnlevel/10, signon,
2306                        time_idle, type, caps);
2307
2308        return 1;
2309}
2310*/
Note: See TracBrowser for help on using the repository browser.