source: aim.c @ c0b1a40

release-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since c0b1a40 was c0b1a40, checked in by Nelson Elhage <nelhage@mit.edu>, 15 years ago
aim.c: Get rid of some warnings. gcc was giving warnings because there were several static functions that were never used. Just delete them; They'll be in git if we ever need them again.
  • Property mode set to 100644
File size: 66.7 KB
Line 
1#include <stdio.h>
2#include <stdio.h>
3#include <sys/stat.h>
4#include "owl.h"
5
6/**********************************************************************/
7
8struct owlfaim_priv {
9  char *aimbinarypath;
10  char *screenname;
11  char *password;
12  char *server;
13  char *proxy;
14  char *proxyusername;
15  char *proxypass;
16  char *ohcaptainmycaptain;
17  int connected;
18
19  FILE *listingfile;
20  char *listingpath;
21
22  fu8_t *buddyicon;
23  int buddyiconlen;
24  time_t buddyiconstamp;
25  fu16_t buddyiconsum;
26};
27
28static char *msgerrreasons[] = {
29        "Invalid error",
30        "Invalid SNAC",
31        "Rate to host",
32        "Rate to client",
33        "Not logged on",
34        "Service unavailable",
35        "Service not defined",
36        "Obsolete SNAC",
37        "Not supported by host",
38        "Not supported by client",
39        "Refused by client",
40        "Reply too big",
41        "Responses lost",
42        "Request denied",
43        "Busted SNAC payload",
44        "Insufficient rights",
45        "In local permit/deny",
46        "Too evil (sender)",
47        "Too evil (receiver)",
48        "User temporarily unavailable",
49        "No match",
50        "List overflow",
51        "Request ambiguous",
52        "Queue full",
53        "Not while on AOL",
54};
55static int msgerrreasonslen = 25;
56
57static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va);
58static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...);
59static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...);
60int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...);
61int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...);
62void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn);
63static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...);
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(char *screenname, 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(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(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(char *to, 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(char *to, 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(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(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(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(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(char *name, int exchange)
344{
345  int ret;
346  aim_conn_t *cur;
347  /*
348  OscarData *od = (OscarData *)g->proto_data;
349  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(char *chatroom)
395{
396}
397
398int owl_aim_chat_sendmsg(char *chatroom, char *msg)
399{
400  return(0);
401}
402
403/* caller must free the return */
404char *owl_aim_normalize_screenname(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 = (struct owlfaim_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 = (struct owlfaim_priv *)sess->aux_data;
482  struct client_info_s info = CLIENTINFO_AIM_KNOWNGOOD;
483   
484  char *key;
485  va_list ap;
486
487  va_start(ap, fr);
488  key = va_arg(ap, 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 = (struct owlfaim_priv *)sess->aux_data;
706  va_list ap;
707  fu16_t code;
708  char *msg;
709 
710  va_start(ap, fr);
711  code = va_arg(ap, int);
712  msg = va_arg(ap, 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  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, 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 = (struct owlfaim_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  char *msg;
903  fu16_t id;
904  va_list ap;
905  static int codeslen = 5;
906  static 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, 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 = (struct owlfaim_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 = (struct owlfaim_priv *)sess->aux_data;
1072  va_list ap;
1073  fu32_t offset, len;
1074  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, 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  char *prof_encoding = NULL;
1115  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, char *);
1123  prof = va_arg(ap, 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 = (struct owlfaim_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  owl_buddylist *bl;
1393  va_list ap;
1394  va_start(ap, fr);
1395  userinfo = va_arg(ap, aim_userinfo_t *);
1396  va_end(ap);
1397
1398  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1399  bl=owl_global_get_buddylist(&g);
1400 
1401  owl_buddylist_oncoming(owl_global_get_buddylist(&g), nz_screenname);
1402
1403  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1404    owl_function_debugmsg("faimtest_parseoncoming: in empty part of userinfo present and present idle");
1405  }
1406
1407  b=owl_buddylist_get_aim_buddy(owl_global_get_buddylist(&g), nz_screenname);
1408  if (!b) {
1409    owl_function_debugmsg("Error: parse_oncoming setting idle time with no buddy present.");
1410    return(1);
1411  }
1412  if (userinfo->idletime==0) {
1413    owl_buddy_set_unidle(b);
1414  } else {
1415    owl_buddy_set_idle(b);
1416    owl_buddy_set_idle_since(b, userinfo->idletime);
1417  }
1418
1419  if (userinfo->flags & AIM_FLAG_AWAY) {
1420    owl_function_debugmsg("parse_oncoming sn: %s away flag!", userinfo->sn);
1421  }
1422 
1423  owl_function_debugmsg("parse_oncoming sn: %s idle: %i", userinfo->sn, userinfo->idletime);
1424   
1425  owl_free(nz_screenname);
1426 
1427  /*
1428    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1429    time(NULL),
1430    userinfo->sn, userinfo->flags,
1431    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1432    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1433    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1434    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1435    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1436    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1437    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1438    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1439    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1440    userinfo->capabilities);
1441  */
1442  return(1);
1443}
1444
1445static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1446{
1447  aim_userinfo_t *userinfo;
1448  char *nz_screenname;
1449  va_list ap;
1450 
1451  va_start(ap, fr);
1452  userinfo = va_arg(ap, aim_userinfo_t *);
1453  va_end(ap);
1454
1455  nz_screenname=owl_aim_normalize_screenname(userinfo->sn);
1456  owl_buddylist_offgoing(owl_global_get_buddylist(&g), nz_screenname);
1457  owl_free(nz_screenname);
1458
1459  if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) {
1460    owl_function_debugmsg("parse_offgoing sn: %s idle time %i", userinfo->sn, userinfo->idletime);
1461  }
1462
1463  /*
1464  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1465         time(NULL),
1466         userinfo->sn, userinfo->flags,
1467         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1468         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1469         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1470         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1471         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1472         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1473         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1474         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1475         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1476         userinfo->capabilities);
1477  */
1478 
1479  return 1;
1480}
1481
1482/* Used by chat as well. */
1483int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1484{
1485  va_list ap;
1486  fu16_t reason;
1487 
1488  va_start(ap, fr);
1489  reason = (fu16_t)va_arg(ap, unsigned int);
1490  va_end(ap);
1491 
1492  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1493  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1494 
1495  return 1;
1496}
1497
1498static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1499{
1500  va_list ap;
1501  char *destsn;
1502  fu16_t reason;
1503 
1504  va_start(ap, fr);
1505  reason = (fu16_t)va_arg(ap, unsigned int);
1506  destsn = va_arg(ap, char *);
1507  va_end(ap);
1508 
1509  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1510  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1511
1512  if (reason==4) {
1513    owl_function_adminmsg("", "Could not send AIM message, user not logged on");
1514  }
1515 
1516  return 1;
1517}
1518
1519static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1520{
1521  va_list ap;
1522  char *destsn;
1523  fu16_t reason;
1524 
1525  va_start(ap, fr);
1526  reason = (fu16_t)va_arg(ap, unsigned int);
1527  destsn = va_arg(ap, char *);
1528  va_end(ap);
1529 
1530  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1531  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
1532 
1533  return 1;
1534}
1535
1536static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1537{
1538  static char *missedreasons[] = {
1539    "Invalid (0)",
1540    "Message too large",
1541    "Rate exceeded",
1542    "Evil Sender",
1543    "Evil Receiver"
1544  };
1545  static int missedreasonslen = 5;
1546 
1547  va_list ap;
1548  fu16_t chan, nummissed, reason;
1549  aim_userinfo_t *userinfo;
1550 
1551  va_start(ap, fr);
1552  chan = (fu16_t)va_arg(ap, unsigned int);
1553  userinfo = va_arg(ap, aim_userinfo_t *);
1554  nummissed = (fu16_t)va_arg(ap, unsigned int);
1555  reason = (fu16_t)va_arg(ap, unsigned int);
1556  va_end(ap);
1557 
1558  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");
1559 
1560  return 1;
1561}
1562
1563/*
1564 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1565 */
1566static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1567{
1568  va_list ap;
1569  fu16_t type;
1570  char *sn = NULL;
1571 
1572  va_start(ap, fr);
1573  type = (fu16_t)va_arg(ap, unsigned int);
1574  sn = va_arg(ap, char *);
1575  va_end(ap);
1576 
1577  owl_function_debugmsg("faimtest_parse_msgack: 0x%04x / %s\n", type, sn);
1578 
1579  return 1;
1580}
1581
1582static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1583{
1584  static char *codes[5] = {
1585    "invalid",
1586    "change",
1587    "warning",
1588    "limit",
1589    "limit cleared"
1590  };
1591  va_list ap;
1592  fu16_t code, rateclass;
1593  fu32_t windowsize, clear, alert, limit, disconnect;
1594  fu32_t currentavg, maxavg;
1595 
1596  va_start(ap, fr); 
1597 
1598  /* See code explanations below */
1599  code = (fu16_t)va_arg(ap, unsigned int);
1600 
1601  /*
1602   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1603   */
1604  rateclass = (fu16_t)va_arg(ap, unsigned int);
1605 
1606  /*
1607   * Not sure what this is exactly.  I think its the temporal
1608   * relation factor (ie, how to make the rest of the numbers
1609   * make sense in the real world).
1610   */
1611  windowsize = va_arg(ap, fu32_t);
1612 
1613  /* Explained below */
1614  clear = va_arg(ap, fu32_t);
1615  alert = va_arg(ap, fu32_t);
1616  limit = va_arg(ap, fu32_t);
1617  disconnect = va_arg(ap, fu32_t);
1618  currentavg = va_arg(ap, fu32_t);
1619  maxavg = va_arg(ap, fu32_t);
1620 
1621  va_end(ap);
1622 
1623  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)",
1624                        (code < 5)?codes[code]:"invalid",
1625                        rateclass,
1626                        currentavg, maxavg,
1627                        alert, clear,
1628                        limit, disconnect,
1629                        windowsize);
1630  return 1;
1631}
1632
1633static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1634{
1635  va_list ap;
1636  fu16_t newevil;
1637  aim_userinfo_t *userinfo;
1638 
1639  va_start(ap, fr);
1640  newevil = (fu16_t)va_arg(ap, unsigned int);
1641  userinfo = va_arg(ap, aim_userinfo_t *);
1642  va_end(ap);
1643 
1644  /*
1645   * Evil Notifications that are lacking userinfo->sn are anon-warns
1646   * if they are an evil increases, but are not warnings at all if its
1647   * a decrease (its the natural backoff happening).
1648   *
1649   * newevil is passed as an int representing the new evil value times
1650   * ten.
1651   */
1652  owl_function_debugmsg("faimtest_parse_evilnotify: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
1653 
1654  return 1;
1655}
1656
1657static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1658{
1659  va_list ap;
1660  char *address, *SNs;
1661  int num, i;
1662  owl_list list;
1663 
1664  va_start(ap, fr);
1665  address = va_arg(ap, char *);
1666  num = va_arg(ap, int);
1667  SNs = va_arg(ap, char *);
1668  va_end(ap);
1669
1670  owl_list_create(&list);
1671 
1672  owl_function_debugmsg("faimtest_parse_searchreply: E-Mail Search Results for %s: ", address);
1673  for (i=0; i<num; i++) {
1674    owl_function_debugmsg("  %s", &SNs[i*(MAXSNLEN+1)]);
1675    owl_list_append_element(&list, &SNs[i*(MAXSNLEN+1)]);
1676  }
1677  owl_function_aimsearch_results(address, &list);
1678  owl_list_free_simple(&list);
1679  return(1);
1680}
1681
1682static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1683{
1684  va_list ap;
1685  char *address;
1686 
1687  va_start(ap, fr);
1688  address = va_arg(ap, char *);
1689  va_end(ap);
1690
1691  owl_function_error("No results searching for %s", address);
1692  owl_function_debugmsg("faimtest_parse_searcherror: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
1693 
1694  return(1);
1695}
1696
1697static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1698{
1699  va_list ap;
1700  char *msg, *url;
1701  fu16_t width, height, delay;
1702 
1703  va_start(ap, fr);
1704  msg = va_arg(ap, char *);
1705  url = va_arg(ap, char *);
1706  width = va_arg(ap, unsigned int);
1707  height = va_arg(ap, unsigned int);
1708  delay = va_arg(ap, unsigned int);
1709  va_end(ap);
1710 
1711  owl_function_debugmsg("handlepopup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url);
1712 
1713  return 1;
1714}
1715
1716static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1717{
1718  aim_sendpauseack(sess, fr->conn);
1719  return 1;
1720}
1721
1722static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1723{
1724  va_list ap;
1725  aim_conn_t *bosconn;
1726  char *bosip;
1727  fu8_t *cookie;
1728 
1729  va_start(ap, fr);
1730  bosip = va_arg(ap, char *);
1731  cookie = va_arg(ap, fu8_t *);
1732  va_end(ap);
1733 
1734  owl_function_debugmsg("migrate: migration in progress -- new BOS is %s -- disconnecting", bosip);
1735  aim_conn_kill(sess, &fr->conn);
1736 
1737  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1738    owl_function_debugmsg("migrate: could not connect to BOS: internal error");
1739    return 1;
1740  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1741    owl_function_debugmsg("migrate: could not connect to BOS");
1742    aim_conn_kill(sess, &bosconn);
1743    return 1;
1744  }
1745 
1746  /* Login will happen all over again. */
1747  addcb_bos(sess, bosconn);
1748  /* aim_sendcookie(sess, bosconn, cookie); */ /********/
1749  return 1;
1750}
1751
1752static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1753{
1754  owl_function_debugmsg("ssirights: got SSI rights, requesting data\n");
1755  /* aim_ssi_reqdata(sess, fr->conn, 0, 0x0000); */
1756  aim_ssi_reqdata(sess);
1757 
1758  return(1);
1759}
1760
1761static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1762{
1763  va_list ap;
1764  fu8_t fmtver;
1765  fu16_t itemcount;
1766  fu32_t stamp;
1767  struct aim_ssi_item *list;
1768  /*
1769  struct aim_ssi_item *curitem;
1770  struct aim_ssi_item *l;
1771  */
1772 
1773  va_start(ap, fr);
1774  fmtver = va_arg(ap, unsigned int);
1775  itemcount = va_arg(ap, unsigned int);
1776  stamp = va_arg(ap, fu32_t);
1777  list = va_arg(ap, struct aim_ssi_item *);
1778  va_end(ap);
1779 
1780  owl_function_debugmsg("ssiddata: got SSI data (0x%02x, %d items, %ld)", fmtver, itemcount, stamp);
1781  /*
1782  for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
1783    for (l = list; l; l = l->next) {
1784      owl_function_debugmsg("\t0x%04x (%s) - 0x%04x/0x%04x", l->type, l->name, l->gid, l->bid);
1785    }
1786  }
1787  */
1788  aim_ssi_enable(sess);
1789 
1790  return 1;
1791}
1792
1793static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1794{
1795  owl_function_debugmsg("ssidatanochange: server says we have the latest SSI data already");
1796  /* aim_ssi_enable(sess, fr->conn); */
1797  aim_ssi_enable(sess);
1798  return 1;
1799}
1800
1801static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1802{
1803  va_list ap;
1804  struct aim_icq_offlinemsg *msg;
1805 
1806  va_start(ap, fr);
1807  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1808  va_end(ap);
1809 
1810  if (msg->type == 0x0001) {
1811    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);
1812  } else {
1813    owl_function_debugmsg("unknown offline message type 0x%04x", msg->type);
1814  }
1815  return 1;
1816}
1817
1818static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1819{
1820  /* Tell the server to delete them. */
1821  owl_function_debugmsg("offlinemsg done: ");
1822  aim_icq_ackofflinemsgs(sess);
1823  return 1;
1824}
1825
1826
1827/******************** chat.c **************************/
1828
1829static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1830{
1831  va_list ap;
1832  aim_userinfo_t *userinfo;
1833  int count;
1834  /* int i; */
1835 
1836  va_start(ap, fr);
1837  count = va_arg(ap, int);
1838  userinfo = va_arg(ap, aim_userinfo_t *);
1839  va_end(ap);
1840
1841  owl_function_debugmsg("In faimtest_chat_join");
1842  /*
1843  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1844  for (i = 0; i < count; i++)
1845    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1846  */
1847  return 1;
1848}
1849
1850static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1851{
1852  aim_userinfo_t *userinfo;
1853  va_list ap;
1854  int count;
1855  /* int i; */
1856
1857 
1858  va_start(ap, fr);
1859  count = va_arg(ap, int);
1860  userinfo = va_arg(ap, aim_userinfo_t *);
1861  va_end(ap);
1862 
1863  /*
1864    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1865   
1866    for (i = 0; i < count; i++)
1867    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1868  */
1869  return 1;
1870}
1871
1872static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1873{
1874  va_list ap;
1875  aim_userinfo_t *userinfo;
1876  struct aim_chat_roominfo *roominfo;
1877  char *roomname;
1878  int usercount;
1879  char *roomdesc;
1880  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1881  fu32_t creationtime;
1882  const char *croomname;
1883  /* int i; */
1884 
1885  croomname = aim_chat_getname(fr->conn);
1886 
1887  va_start(ap, fr);
1888  roominfo = va_arg(ap, struct aim_chat_roominfo *);
1889  roomname = va_arg(ap, char *);
1890  usercount = va_arg(ap, int);
1891  userinfo = va_arg(ap, aim_userinfo_t *);
1892  roomdesc = va_arg(ap, char *);
1893  flags = (fu16_t)va_arg(ap, unsigned int);
1894  creationtime = va_arg(ap, fu32_t);
1895  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1896  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
1897  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
1898  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
1899  va_end(ap);
1900
1901  owl_function_debugmsg("In faimtest_chat_infoupdate");
1902  /*
1903  printf("chat: %s:  info update:\n", croomname);
1904  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
1905  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
1906  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
1907  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
1908
1909  for (i = 0; i < usercount; i++)
1910    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
1911 
1912  owl_function_debugmsg("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
1913         croomname, flags,
1914         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1915         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1916         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1917         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1918  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
1919  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
1920  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
1921  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
1922  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
1923  */
1924 
1925  return(1);
1926}
1927
1928static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
1929{
1930  va_list ap;
1931  aim_userinfo_t *userinfo;
1932  char *msg;
1933  char tmpbuf[1152];
1934 
1935  va_start(ap, fr);
1936  userinfo = va_arg(ap, aim_userinfo_t *);     
1937  msg = va_arg(ap, char *);
1938  va_end(ap);
1939
1940  owl_function_debugmsg("in faimtest_chat_incomingmsg");
1941
1942  /*
1943  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
1944  */
1945 
1946  /*
1947   * Do an echo for testing purposes.  But not for ourselves ("oops!")
1948   */
1949  if (strcmp(userinfo->sn, sess->sn) != 0) {
1950    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
1951    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
1952  }
1953 
1954  return 1;
1955}
1956
1957static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
1958{
1959  owl_function_debugmsg("faimtest_conninitdone_chat:");
1960
1961  aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
1962  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
1963  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
1964  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
1965  aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
1966 
1967  aim_clientready(sess, fr->conn);
1968 
1969  owl_function_debugmsg("Chat ready");
1970
1971  /*
1972    chatcon = find_oscar_chat_by_conn(gc, fr->conn);
1973    chatcon->id = id;
1974    chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show);
1975  */
1976  return(1);
1977}
1978
1979void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1980{
1981  aim_conn_t *tstconn;
1982
1983  owl_function_debugmsg("in faimtest_chatnav_redirect");
1984 
1985  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
1986  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1987    /* printf("unable to connect to chat(nav) server\n"); */
1988    if (tstconn)
1989      aim_conn_kill(sess, &tstconn);
1990    return;
1991  }
1992 
1993  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1994  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
1995  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
1996  /* printf("chatnav: connected\n"); */
1997  return;
1998}
1999
2000/* XXX this needs instance too */
2001void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2002{
2003  aim_conn_t *tstconn;
2004
2005  owl_function_debugmsg("in chat_redirect");
2006 
2007  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
2008  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2009    /* printf("unable to connect to chat server\n"); */
2010    if (tstconn) aim_conn_kill(sess, &tstconn);
2011    return; 
2012  }             
2013  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
2014 
2015  /*
2016   * We must do this to attach the stored name to the connection!
2017   */
2018  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
2019  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2020  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2021  aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
2022  return;       
2023}
2024
2025void owl_process_aim()
2026{
2027  if (owl_global_is_doaimevents(&g)) {
2028    owl_aim_process_events();
2029  }
2030}
Note: See TracBrowser for help on using the repository browser.