source: aim.c @ 6a87084

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