source: aim.c @ 836ea3a3

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