source: aim.c @ de03334

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