source: aim.c @ bff8f9f

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