source: aim.c @ 1e34e40

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