source: aim.c @ ec6ff52

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