source: aim.c @ 8c92848

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