source: aim.c @ c15bbfb

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