source: aim.c @ 1077753b

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