source: aim.c @ a836200

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since a836200 was a836200, checked in by James M. Kretchmar <kretch@mit.edu>, 20 years ago
Do an erro and admin message for failed AIM send.
  • Property mode set to 100644
File size: 73.3 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  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
1611 
1612  return 1;
1613}
1614
1615static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1616{
1617  va_list ap;
1618  char *destsn;
1619  fu16_t reason;
1620 
1621  va_start(ap, fr);
1622  reason = (fu16_t)va_arg(ap, unsigned int);
1623  destsn = va_arg(ap, char *);
1624  va_end(ap);
1625 
1626  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1627  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
1628
1629  if (reason==4) {
1630    owl_function_adminmsg("", "Could not send AIM message, user not logged on");
1631  }
1632 
1633  return 1;
1634}
1635
1636static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1637{
1638  va_list ap;
1639  char *destsn;
1640  fu16_t reason;
1641 
1642  va_start(ap, fr);
1643  reason = (fu16_t)va_arg(ap, unsigned int);
1644  destsn = va_arg(ap, char *);
1645  va_end(ap);
1646 
1647  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1648  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
1649 
1650  return 1;
1651}
1652
1653static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1654{
1655  /*
1656  static char *missedreasons[] = {
1657    "Invalid (0)",
1658    "Message too large",
1659    "Rate exceeded",
1660    "Evil Sender",
1661    "Evil Receiver"
1662  };
1663  static int missedreasonslen = 5; */
1664 
1665  va_list ap;
1666  fu16_t chan, nummissed, reason;
1667  aim_userinfo_t *userinfo;
1668 
1669  va_start(ap, fr);
1670  chan = (fu16_t)va_arg(ap, unsigned int);
1671  userinfo = va_arg(ap, aim_userinfo_t *);
1672  nummissed = (fu16_t)va_arg(ap, unsigned int);
1673  reason = (fu16_t)va_arg(ap, unsigned int);
1674  va_end(ap);
1675 
1676  /* printf("missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown"); */
1677 
1678  return 1;
1679}
1680
1681/*
1682 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1683 */
1684static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1685{
1686  va_list ap;
1687  fu16_t type;
1688  char *sn = NULL;
1689 
1690  va_start(ap, fr);
1691  type = (fu16_t)va_arg(ap, unsigned int);
1692  sn = va_arg(ap, char *);
1693  va_end(ap);
1694 
1695  /* printf("msgack: 0x%04x / %s\n", type, sn); */
1696 
1697  return 1;
1698}
1699
1700static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1701{
1702  /*
1703  static char *codes[5] = {
1704    "invalid",
1705    "change",
1706    "warning",
1707    "limit",
1708    "limit cleared"
1709  };
1710  */
1711  va_list ap;
1712  fu16_t code, rateclass;
1713  fu32_t windowsize, clear, alert, limit, disconnect;
1714  fu32_t currentavg, maxavg;
1715 
1716  va_start(ap, fr); 
1717 
1718  /* See code explanations below */
1719  code = (fu16_t)va_arg(ap, unsigned int);
1720 
1721  /*
1722   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1723   */
1724  rateclass = (fu16_t)va_arg(ap, unsigned int);
1725 
1726  /*
1727   * Not sure what this is exactly.  I think its the temporal
1728   * relation factor (ie, how to make the rest of the numbers
1729   * make sense in the real world).
1730   */
1731  windowsize = va_arg(ap, fu32_t);
1732 
1733  /* Explained below */
1734  clear = va_arg(ap, fu32_t);
1735  alert = va_arg(ap, fu32_t);
1736  limit = va_arg(ap, fu32_t);
1737  disconnect = va_arg(ap, fu32_t);
1738  currentavg = va_arg(ap, fu32_t);
1739  maxavg = va_arg(ap, fu32_t);
1740 
1741  va_end(ap);
1742 
1743  /*
1744  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",
1745         (code < 5)?codes[code]:"invalid",
1746         rateclass,
1747         currentavg, maxavg,
1748         alert, clear,
1749         limit, disconnect,
1750         windowsize);
1751  */
1752  return 1;
1753}
1754
1755static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1756{
1757  va_list ap;
1758  fu16_t newevil;
1759  aim_userinfo_t *userinfo;
1760 
1761  va_start(ap, fr);
1762  newevil = (fu16_t)va_arg(ap, unsigned int);
1763  userinfo = va_arg(ap, aim_userinfo_t *);
1764  va_end(ap);
1765 
1766  /*
1767   * Evil Notifications that are lacking userinfo->sn are anon-warns
1768   * if they are an evil increases, but are not warnings at all if its
1769   * a decrease (its the natural backoff happening).
1770   *
1771   * newevil is passed as an int representing the new evil value times
1772   * ten.
1773   */
1774  /* printf("evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous"); */
1775 
1776  return 1;
1777}
1778
1779static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1780{
1781  va_list ap;
1782  char *address, *SNs;
1783  int num;
1784  /* int i; */
1785 
1786  va_start(ap, fr);
1787  address = va_arg(ap, char *);
1788  num = va_arg(ap, int);
1789  SNs = va_arg(ap, char *);
1790  va_end(ap);
1791 
1792  /* printf("E-Mail Search Results for %s: ", address);
1793 
1794  for(i = 0; i < num; i++)
1795    printf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1796  printf("\n");
1797  */
1798 
1799  return 1;
1800}
1801
1802static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1803{
1804  va_list ap;
1805  char *address;
1806 
1807  va_start(ap, fr);
1808  address = va_arg(ap, char *);
1809  va_end(ap);
1810 
1811  /* printf("E-Mail Search Results for %s: No Results or Invalid Email\n", address); */
1812 
1813  return 1;
1814}
1815
1816static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1817{
1818  va_list ap;
1819  char *msg, *url;
1820  fu16_t width, height, delay;
1821 
1822  va_start(ap, fr);
1823  msg = va_arg(ap, char *);
1824  url = va_arg(ap, char *);
1825  width = va_arg(ap, unsigned int);
1826  height = va_arg(ap, unsigned int);
1827  delay = va_arg(ap, unsigned int);
1828  va_end(ap);
1829 
1830  /* printf("popup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url); */
1831 
1832  return 1;
1833}
1834
1835static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1836{
1837  aim_sendpauseack(sess, fr->conn);
1838  return 1;
1839}
1840
1841static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1842{
1843  va_list ap;
1844  aim_conn_t *bosconn;
1845  char *bosip;
1846  fu8_t *cookie;
1847 
1848  va_start(ap, fr);
1849  bosip = va_arg(ap, char *);
1850  cookie = va_arg(ap, fu8_t *);
1851  va_end(ap);
1852 
1853  /* printf("migration in progress -- new BOS is %s -- disconnecting\n", bosip); */
1854  aim_conn_kill(sess, &fr->conn);
1855 
1856  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1857    /* printf("migrate: could not connect to BOS: internal error\n"); */
1858    return 1;
1859  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1860    /* printf("migrate: could not connect to BOS\n"); */
1861    aim_conn_kill(sess, &bosconn);
1862    return 1;
1863  }
1864 
1865  /* Login will happen all over again. */
1866  addcb_bos(sess, bosconn);
1867  /* aim_sendcookie(sess, bosconn, cookie); */
1868  return 1;
1869}
1870
1871static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1872{
1873 
1874  /* printf("got SSI rights, requesting data\n"); */
1875  /* aim_ssi_reqdata(sess, fr->conn, 0, 0x0000); */
1876  aim_ssi_reqdata(sess);
1877 
1878  return 1;
1879}
1880
1881static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1882{
1883  va_list ap;
1884  fu8_t fmtver;
1885  fu16_t itemcount;
1886  fu32_t stamp;
1887  struct aim_ssi_item *list;
1888  struct aim_ssi_item *curitem;
1889  /* struct aim_ssi_item *l; */
1890 
1891  va_start(ap, fr);
1892  fmtver = va_arg(ap, unsigned int);
1893  itemcount = va_arg(ap, unsigned int);
1894  stamp = va_arg(ap, fu32_t);
1895  list = va_arg(ap, struct aim_ssi_item *);
1896  va_end(ap);
1897 
1898  /* printf("got SSI data: (0x%02x, %d items, %ld)\n", fmtver, itemcount, stamp); */
1899  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
1900    /* for (l = list; l; l = l->next) { */
1901    /* printf("\t0x%04x (%s) - 0x%04x/0x%04x\n", l->type, l->name, l->gid, l->bid); */
1902    /* printf("I would have printed data here!\n"); */
1903  }
1904 
1905  aim_ssi_enable(sess);
1906 
1907  return 1;
1908}
1909
1910static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1911{
1912  /* printf("server says we have the latest SSI data already\n"); */
1913  /* aim_ssi_enable(sess, fr->conn); */
1914  aim_ssi_enable(sess);
1915  return 1;
1916}
1917
1918static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1919{
1920  va_list ap;
1921  struct aim_icq_offlinemsg *msg;
1922 
1923  va_start(ap, fr);
1924  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1925  va_end(ap);
1926 
1927  if (msg->type == 0x0001) {
1928    /* 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); */
1929  } else {
1930    /* printf("unknown offline message type 0x%04x\n", msg->type); */
1931  }
1932  return 1;
1933}
1934
1935static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1936{
1937  /* Tell the server to delete them. */
1938  aim_icq_ackofflinemsgs(sess);
1939  return 1;
1940}
1941
1942
1943/******************** chat.c **************************/
1944
1945
1946static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1947{
1948  va_list ap;
1949  aim_userinfo_t *userinfo;
1950  int count;
1951  /* int i; */
1952 
1953  va_start(ap, fr);
1954  count = va_arg(ap, int);
1955  userinfo = va_arg(ap, aim_userinfo_t *);
1956  va_end(ap);
1957
1958  /*
1959  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1960  for (i = 0; i < count; i++)
1961    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1962  */
1963  return 1;
1964}
1965
1966static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1967{
1968  aim_userinfo_t *userinfo;
1969  va_list ap;
1970  int count;
1971  /* int i; */
1972
1973 
1974  va_start(ap, fr);
1975  count = va_arg(ap, int);
1976  userinfo = va_arg(ap, aim_userinfo_t *);
1977  va_end(ap);
1978 
1979  /*
1980    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1981   
1982    for (i = 0; i < count; i++)
1983    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1984  */
1985  return 1;
1986}
1987
1988static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1989{
1990  va_list ap;
1991  aim_userinfo_t *userinfo;
1992  struct aim_chat_roominfo *roominfo;
1993  char *roomname;
1994  int usercount;
1995  char *roomdesc;
1996  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1997  fu32_t creationtime;
1998  const char *croomname;
1999  /* int i; */
2000 
2001  croomname = aim_chat_getname(fr->conn);
2002 
2003  va_start(ap, fr);
2004  roominfo = va_arg(ap, struct aim_chat_roominfo *);
2005  roomname = va_arg(ap, char *);
2006  usercount = va_arg(ap, int);
2007  userinfo = va_arg(ap, aim_userinfo_t *);
2008  roomdesc = va_arg(ap, char *);
2009  flags = (fu16_t)va_arg(ap, unsigned int);
2010  creationtime = va_arg(ap, fu32_t);
2011  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
2012  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
2013  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
2014  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
2015  va_end(ap);
2016
2017  /*
2018  printf("chat: %s:  info update:\n", croomname);
2019  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
2020  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
2021  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
2022  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
2023
2024  for (i = 0; i < usercount; i++)
2025    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
2026 
2027  printf("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
2028         croomname, flags,
2029         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
2030         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
2031         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
2032         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
2033  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
2034  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
2035  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
2036  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
2037  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
2038  */
2039 
2040  return 1;
2041}
2042
2043static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
2044{
2045  va_list ap;
2046  aim_userinfo_t *userinfo;
2047  char *msg;
2048  char tmpbuf[1152];
2049 
2050  va_start(ap, fr);
2051  userinfo = va_arg(ap, aim_userinfo_t *);     
2052  msg = va_arg(ap, char *);
2053  va_end(ap);
2054
2055  /*
2056  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
2057  */
2058 
2059  /*
2060   * Do an echo for testing purposes.  But not for ourselves ("oops!")
2061   */
2062  if (strcmp(userinfo->sn, sess->sn) != 0) {
2063    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
2064    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
2065  }
2066 
2067  return 1;
2068}
2069
2070static int faimtest_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...)
2071{
2072  fu16_t type;
2073  va_list ap;
2074 
2075  va_start(ap, fr);
2076  type = (fu16_t)va_arg(ap, unsigned int);
2077 
2078  if (type == 0x0002) {
2079    int maxrooms;
2080    struct aim_chat_exchangeinfo *exchanges;
2081    int exchangecount;
2082    /* int i; */
2083   
2084    maxrooms = va_arg(ap, int);
2085    exchangecount = va_arg(ap, int);
2086    exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
2087    va_end(ap);
2088
2089    /*
2090    printf("chat info: Chat Rights:\n");
2091    printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
2092    printf("chat info: \tExchange List: (%d total)\n", exchangecount);
2093    for (i = 0; i < exchangecount; i++) {
2094      printf("chat info: \t\t%x: %s (%s/%s) (0x%04x = %s%s%s%s)\n",
2095             exchanges[i].number,
2096             exchanges[i].name,
2097             exchanges[i].charset1,
2098             exchanges[i].lang1,
2099             exchanges[i].flags,
2100             (exchanges[i].flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
2101             (exchanges[i].flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
2102             (exchanges[i].flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
2103             (exchanges[i].flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
2104    }
2105    */
2106  } else if (type == 0x0008) {
2107    char *fqcn, *name, *ck;
2108    fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
2109    fu8_t createperms;
2110    fu32_t createtime;
2111   
2112    fqcn = va_arg(ap, char *);
2113    instance = (fu16_t)va_arg(ap, unsigned int);
2114    exchange = (fu16_t)va_arg(ap, unsigned int);
2115    flags = (fu16_t)va_arg(ap, unsigned int);
2116    createtime = va_arg(ap, fu32_t);
2117    maxmsglen = (fu16_t)va_arg(ap, unsigned int);
2118    maxoccupancy = (fu16_t)va_arg(ap, unsigned int);
2119    createperms = (fu8_t)va_arg(ap, unsigned int);
2120    unknown = (fu16_t)va_arg(ap, unsigned int);
2121    name = va_arg(ap, char *);
2122    ck = va_arg(ap, char *);
2123    va_end(ap);
2124   
2125    /* printf("received room create reply for %s/0x%04x\n", fqcn, exchange); */
2126   
2127  } else {
2128    va_end(ap);
2129    /* printf("chatnav info: unknown type (%04x)\n", type); */
2130  }
2131 
2132  return 1;
2133}
2134
2135static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
2136{
2137
2138  aim_clientready(sess, fr->conn);
2139 
2140  if (fr->conn->type == AIM_CONN_TYPE_CHATNAV) {
2141    /* printf("chatnav ready\n"); */
2142    aim_conn_addhandler(sess, fr->conn, 0x000d, 0x0001, faimtest_parse_genericerr, 0);
2143    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0);
2144    aim_chatnav_reqrights(sess, fr->conn);
2145  } else if (fr->conn->type == AIM_CONN_TYPE_CHAT) {
2146    /* printf("chat ready\n"); */
2147    aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
2148    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
2149    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
2150    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
2151    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
2152  }
2153  return 1;
2154}
2155
2156void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2157{
2158  aim_conn_t *tstconn;
2159 
2160  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
2161  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2162    /* printf("unable to connect to chat(nav) server\n"); */
2163    if (tstconn)
2164      aim_conn_kill(sess, &tstconn);
2165    return;
2166  }
2167 
2168  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2169  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2170  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2171  /* printf("chatnav: connected\n"); */
2172  return;
2173}
2174
2175/* XXX this needs instance too */
2176void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2177{
2178  aim_conn_t *tstconn;
2179 
2180  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
2181  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2182    /* printf("unable to connect to chat server\n"); */
2183    if (tstconn) aim_conn_kill(sess, &tstconn);
2184    return; 
2185  }             
2186  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
2187 
2188  /*
2189   * We must do this to attach the stored name to the connection!
2190   */
2191  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
2192  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2193  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2194  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2195  return;       
2196}
2197
2198
2199/****************************************/
2200
2201/*
2202static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) {
2203        struct gaim_connection *gc = sess->aux_data;
2204        struct oscar_data *od = gc->proto_data;
2205        aim_userinfo_t *info;
2206        time_t time_idle = 0, signon = 0;
2207        int type = 0;
2208        int caps = 0;
2209        char *tmp;
2210
2211        va_list ap;
2212        va_start(ap, fr);
2213        info = va_arg(ap, aim_userinfo_t *);
2214        va_end(ap);
2215
2216        if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
2217                caps = info->capabilities;
2218        if (info->flags & AIM_FLAG_ACTIVEBUDDY)
2219                type |= UC_AB;
2220
2221        if ((!od->icq) && (info->present & AIM_USERINFO_PRESENT_FLAGS)) {
2222                        if (info->flags & AIM_FLAG_UNCONFIRMED)
2223                                type |= UC_UNCONFIRMED;
2224                        if (info->flags & AIM_FLAG_ADMINISTRATOR)
2225                                type |= UC_ADMIN;
2226                        if (info->flags & AIM_FLAG_AOL)
2227                                type |= UC_AOL;
2228                        if (info->flags & AIM_FLAG_FREE)
2229                                type |= UC_NORMAL;
2230                        if (info->flags & AIM_FLAG_AWAY)
2231                                type |= UC_UNAVAILABLE;
2232                        if (info->flags & AIM_FLAG_WIRELESS)
2233                                type |= UC_WIRELESS;
2234        }
2235        if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) {
2236                type = (info->icqinfo.status << 16);
2237                if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) &&
2238                      (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) {
2239                        type |= UC_UNAVAILABLE;
2240                }
2241        }
2242
2243        if (caps & AIM_CAPS_ICQ)
2244                caps ^= AIM_CAPS_ICQ;
2245
2246        if (info->present & AIM_USERINFO_PRESENT_IDLE) {
2247                time(&time_idle);
2248                time_idle -= info->idletime*60;
2249        }
2250
2251        if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
2252                signon = time(NULL) - info->sessionlen;
2253
2254        tmp = g_strdup(normalize(gc->username));
2255        if (!strcmp(tmp, normalize(info->sn)))
2256                g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", info->sn);
2257        g_free(tmp);
2258
2259        serv_got_update(gc, info->sn, 1, info->warnlevel/10, signon,
2260                        time_idle, type, caps);
2261
2262        return 1;
2263}
2264*/
Note: See TracBrowser for help on using the repository browser.