source: aim.c @ 75e3879

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