source: aim.c @ 0ff8fb57

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 0ff8fb57 was 0ff8fb57, checked in by James M. Kretchmar <kretch@mit.edu>, 18 years ago
More AIM work. The auto-prototype building has been re-enabled as well.
  • Property mode set to 100644
File size: 78.6 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, awaymsg, 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   
955    args.destsn = userinfo->sn;
956    args.flags = AIM_IMFLAGS_HASICON;
957    args.msg = iconmsg;
958    args.msglen = strlen(iconmsg);
959    args.iconlen = priv->buddyiconlen;
960    args.iconstamp = priv->buddyiconstamp;
961    args.iconsum = priv->buddyiconsum;
962   
963    aim_send_im_ext(sess, &args);
964   
965  } else if (strstr(tmpstr, "sendbin")) {
966    struct aim_sendimext_args args;
967    static const unsigned char data[] = {
968      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
969      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
970      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
971      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
972      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
973      0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
974    };
975   
976    /*
977     * I put this here as a demonstration of how to send
978     * arbitrary binary data via OSCAR ICBM's without the need
979     * for escape or baseN encoding of any sort. 
980     *
981     * Apparently if you set the charset to something WinAIM
982     * doesn't recognize, it will completly ignore the message.
983     * That is, it will not display anything in the conversation
984     * window for the user that recieved it.
985     *
986     * HOWEVER, if they do not have a conversation window open
987     * for you, a new one will be created, but it will not have
988     * any messages in it.  Therefore sending these things could
989     * be a great way to seemingly subliminally convince people
990     * to talk to you...
991     *
992     */
993    args.destsn = userinfo->sn;
994    args.flags = AIM_IMFLAGS_CUSTOMCHARSET;
995    args.charset = args.charsubset = 0x4242;
996    args.msg = data;
997    args.msglen = sizeof(data);
998    aim_send_im_ext(sess, &args);
999   } else if (strstr(tmpstr, "sendmulti")) {
1000    struct aim_sendimext_args args;
1001    aim_mpmsg_t mpm;
1002    static const fu16_t unidata[] = { /* "UNICODE." */
1003      0x0055, 0x004e, 0x0049, 0x0043,
1004      0x004f, 0x0044, 0x0045, 0x002e,
1005    };
1006    static const int unidatalen = 8;
1007   
1008    /*
1009     * This is how multipart messages should be sent.
1010     *
1011     * This should render as:
1012     *        "Part 1, ASCII.  UNICODE.Part 3, ASCII.  "
1013     */
1014   
1015    aim_mpmsg_init(sess, &mpm);
1016    aim_mpmsg_addascii(sess, &mpm, "Part 1, ASCII.  ");
1017    aim_mpmsg_addunicode(sess, &mpm, unidata, unidatalen);
1018    aim_mpmsg_addascii(sess, &mpm, "Part 3, ASCII.  ");
1019   
1020    args.destsn = userinfo->sn;
1021    args.flags = AIM_IMFLAGS_MULTIPART;
1022    args.mpmsg = &mpm;
1023   
1024    aim_send_im_ext(sess, &args);
1025   
1026    aim_mpmsg_free(sess, &mpm);
1027   
1028  } else if (strstr(tmpstr, "sendprebin")) {
1029    static const unsigned char data[] = {
1030      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1031      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1032      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1033      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1034      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1035      0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1036    };
1037    struct aim_sendimext_args args;
1038    aim_mpmsg_t mpm;
1039   
1040    /*
1041     * This demonstrates sending a human-readable preamble,
1042     * and then arbitrary binary data.
1043     *
1044     * This means that you can very inconspicuously send binary
1045     * attachments to other users.  In WinAIM, this appears as
1046     * though it only had the ASCII portion.
1047     *
1048     */
1049   
1050    aim_mpmsg_init(sess, &mpm);
1051    aim_mpmsg_addascii(sess, &mpm, "This message has binary data.");
1052    aim_mpmsg_addraw(sess, &mpm, 0x4242, 0x4242, data, sizeof(data));
1053   
1054    args.destsn = userinfo->sn;
1055    args.flags = AIM_IMFLAGS_MULTIPART;
1056    args.mpmsg = &mpm;
1057   
1058    aim_send_im_ext(sess, &args);
1059    aim_mpmsg_free(sess, &mpm);
1060   
1061  } else if (strstr(tmpstr, "havefeat")) {
1062    struct aim_sendimext_args args;
1063    static const char featmsg[] = {"I have nifty features."};
1064    fu8_t features[] = {0x01, 0x01, 0x01, 0x02, 0x42, 0x43, 0x44, 0x45};
1065   
1066    args.destsn = userinfo->sn;
1067    args.flags = AIM_IMFLAGS_CUSTOMFEATURES;
1068    args.msg = featmsg;
1069    args.msglen = strlen(featmsg);
1070    args.features = features;
1071    args.featureslen = sizeof(features);
1072   
1073    aim_send_im_ext(sess, &args);
1074  } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) {
1075    aim_send_icon(sess, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
1076  } else if (strstr(tmpstr, "warnme")) {
1077    /* printf("icbm: sending non-anon warning\n"); */
1078    aim_send_warning(sess, conn, userinfo->sn, 0);
1079  } else if (strstr(tmpstr, "anonwarn")) {
1080    /* printf("icbm: sending anon warning\n"); */
1081    aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON);
1082  } else if (strstr(tmpstr, "setdirectoryinfo")) {
1083    /* printf("icbm: sending backwards profile data\n"); */
1084    aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
1085  } else if (strstr(tmpstr, "setinterests")) {
1086    /* printf("icbm: setting fun interests\n"); */
1087    aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
1088  } else if (!strncmp(tmpstr, "getfile", 7)) {
1089    if (!priv->ohcaptainmycaptain) {
1090      aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
1091    } else {
1092      getfile_start(sess, conn, (strlen(tmpstr) < 8)?priv->ohcaptainmycaptain:tmpstr+8);
1093    }
1094  } else if (!strncmp(tmpstr, "open chatnav", 12)) {
1095    aim_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV);
1096  } else if (!strncmp(tmpstr, "create", 6)) {
1097    aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
1098  } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1099    aim_conn_t *chatnavconn;
1100    if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)))
1101      aim_conn_kill(sess, &chatnavconn);
1102  } else if (!strncmp(tmpstr, "join", 4)) {
1103    aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000);
1104  } else if (!strncmp(tmpstr, "leave", 5)) {
1105    aim_chat_leaveroom(sess, "worlddomination");
1106  } else if (!strncmp(tmpstr, "getinfo", 7)) {
1107    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO);
1108    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
1109    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_CAPABILITIES);
1110  } else if (strstr(tmpstr, "open directim")) {
1111    directim_start(sess, userinfo->sn);
1112  } else if(strstr(tmpstr, "lookup")) {
1113    aim_usersearch_address(sess, conn, "mid@auk.cx");
1114  } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1115    aim_send_im(sess, priv->ohcaptainmycaptain, 0, "sendmsg 7900");
1116  } else if (!strncmp(tmpstr, "reqadmin", 8)) {
1117    aim_reqservice(sess, conn, AIM_CONN_TYPE_AUTH);
1118  } else if (!strncmp(tmpstr, "changenick", 10)) {
1119    aim_admin_setnick(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "diputs8  1");
1120  } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1121    aim_admin_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1122  } else if (!strncmp(tmpstr, "reqemail", 8)) {
1123    aim_admin_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1124  } else if (!strncmp(tmpstr, "changepass", 8)) {
1125    aim_admin_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1126  } else if (!strncmp(tmpstr, "setemail", 8)) {
1127    aim_admin_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1128  } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1129    int i;
1130   
1131    i = atoi(tmpstr+8);
1132    if (i < 10000) {
1133      char *newbuf;
1134      int z;
1135     
1136      newbuf = malloc(i+1);
1137      for (z = 0; z < i; z++)
1138        newbuf[z] = (z % 10)+0x30;
1139      newbuf[i] = '\0';
1140      aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK | AIM_IMFLAGS_AWAY, newbuf);
1141      free(newbuf);
1142    }
1143  } else if (strstr(tmpstr, "seticqstatus")) {
1144    aim_setextstatus(sess, conn, AIM_ICQ_STATE_DND);
1145  } else if (strstr(tmpstr, "rtfmsg")) {
1146    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}"};
1147    struct aim_sendrtfmsg_args rtfargs;
1148   
1149    memset(&rtfargs, 0, sizeof(rtfargs));
1150    rtfargs.destsn = userinfo->sn;
1151    rtfargs.fgcolor = 0xffffffff;
1152    rtfargs.bgcolor = 0x00000000;
1153    rtfargs.rtfmsg = rtfmsg;
1154    aim_send_rtfmsg(sess, &rtfargs);
1155  } else {
1156    /* printf("unknown command.\n"); */
1157    aim_add_buddy(sess, conn, userinfo->sn);
1158  } 
1159 
1160  return 0;
1161}
1162
1163/*
1164 * Channel 1: Standard Message
1165 */
1166static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args)
1167{
1168  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
1169  char *tmpstr;
1170  int clienttype = AIM_CLIENTTYPE_UNKNOWN;
1171  owl_message *m;
1172  char realmsg[8192+1] = {""};
1173  clienttype = aim_fingerprintclient(args->features, args->featureslen);
1174
1175  /*
1176  printf("icbm: sn = \"%s\"\n", userinfo->sn);
1177  printf("icbm: probable client type: %d\n", clienttype);
1178  printf("icbm: warnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1179  printf("icbm: flags = 0x%04x = ", userinfo->flags);
1180  printuserflags(userinfo->flags);
1181  printf("\n");
1182  */
1183
1184  /*
1185  printf("icbm: membersince = %lu\n", userinfo->membersince);
1186  printf("icbm: onlinesince = %lu\n", userinfo->onlinesince);
1187  printf("icbm: idletime = 0x%04x\n", userinfo->idletime);
1188  printf("icbm: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
1189  */
1190
1191  /*
1192  printf("icbm: icbmflags = ");
1193  if (args->icbmflags & AIM_IMFLAGS_AWAY) printf("away ");
1194  if (args->icbmflags & AIM_IMFLAGS_ACK) printf("ackrequest ");
1195  if (args->icbmflags & AIM_IMFLAGS_OFFLINE) printf("offline ");
1196  if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) printf("buddyreq ");
1197  if (args->icbmflags & AIM_IMFLAGS_HASICON) printf("hasicon ");
1198  printf("\n");
1199  */
1200
1201  if (args->icbmflags & AIM_IMFLAGS_CUSTOMCHARSET) {
1202    /* printf("icbm: encoding flags = {%04x, %04x}\n", args->charset, args->charsubset); */
1203  }
1204 
1205  /*
1206   * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1207   * characters with their equivelent HTML entity.
1208   */
1209  if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1210    int i;
1211   
1212    for (i = 0; i < args->msglen; i += 2) {
1213      fu16_t uni;
1214
1215      uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1216      if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1217        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
1218      } else { /* something else, do UNICODE entity */
1219        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
1220      }
1221    }
1222  } else {
1223    /*
1224     * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1225     * no need to do anything special here.  Most
1226     * terminals/whatever will be able to display such characters
1227     * unmodified.
1228     *
1229     * Beware that PC-ASCII 128 through 159 are _not_ actually
1230     * defined in ASCII or ISO 8859-1, and you should send them as
1231     * UNICODE.  WinAIM will send these characters in a UNICODE
1232     * message, so you need to do so as well.
1233     *
1234     * You may not think it necessary to handle UNICODE messages. 
1235     * You're probably wrong.  For one thing, Microsoft "Smart
1236     * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1237     * but real UNICODE). If you don't parse UNICODE at all, your
1238     * users will get a blank message instead of the message
1239     * containing Smart Quotes.
1240     *
1241     */
1242    strncpy(realmsg, args->msg, sizeof(realmsg));
1243  }
1244
1245  /* create a message, and put it on the message queue */
1246  m=owl_malloc(sizeof(owl_message));
1247  owl_message_create_aim(m, userinfo->sn, owl_global_get_aim_screenname(&g), realmsg);
1248  owl_message_set_direction_in(m);
1249  owl_global_messagequeue_addmsg(&g, m);
1250 
1251  /* printf("icbm: message: %s\n", realmsg); */
1252 
1253  if (args->icbmflags & AIM_IMFLAGS_MULTIPART) {
1254    aim_mpmsg_section_t *sec;
1255    int z;
1256
1257    /* printf("icbm: multipart: this message has %d parts\n", args->mpmsg.numparts); */
1258   
1259    for (sec = args->mpmsg.parts, z = 0; sec; sec = sec->next, z++) {
1260      if ((sec->charset == 0x0000) || (sec->charset == 0x0003) || (sec->charset == 0xffff)) {
1261        /* printf("icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, msg = %s\n", z, sec->charset, sec->charsubset, sec->data); */
1262      } else {
1263        /* printf("icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, binary or UNICODE data\n", z, sec->charset, sec->charsubset); */
1264      }
1265    }
1266  }
1267 
1268  if (args->icbmflags & AIM_IMFLAGS_HASICON) {
1269    aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon");
1270    /* printf("icbm: their icon: iconstamp = %ld, iconlen = 0x%08lx, iconsum = 0x%04x\n", args->iconstamp, args->iconlen, args->iconsum); */
1271  }
1272 
1273  if (realmsg) {
1274    int i = 0;
1275    while (realmsg[i] == '<') {
1276      if (realmsg[i] == '<') {
1277        while (realmsg[i] != '>')
1278          i++;
1279        i++;
1280      }
1281    }
1282    tmpstr = realmsg+i;
1283    faimtest_handlecmd(sess, conn, userinfo, tmpstr);
1284  }
1285 
1286  if (priv->buddyicon && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)) {
1287    aim_send_icon(sess, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
1288  }
1289 
1290  return 1;
1291}
1292
1293/*
1294 * Channel 2: Rendevous Request
1295 */
1296static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
1297{
1298  /*
1299  printf("rendezvous: source sn = %s\n", userinfo->sn);
1300  printf("rendezvous: \twarnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1301  printf("rendezvous: \tclass = 0x%04x = ", userinfo->flags);
1302  printuserflags(userinfo->flags);
1303  printf("\n");
1304 
1305  printf("rendezvous: \tonlinesince = %lu\n", userinfo->onlinesince);
1306  printf("rendezvous: \tidletime = 0x%04x\n", userinfo->idletime);
1307 
1308  printf("rendezvous: message/description = %s\n", args->msg);
1309  printf("rendezvous: encoding = %s\n", args->encoding);
1310  printf("rendezvous: language = %s\n", args->language);
1311  */
1312 
1313  if (args->reqclass == AIM_CAPS_GETFILE) {
1314    getfile_requested(sess, conn, userinfo, args);
1315  } else if (args->reqclass == AIM_CAPS_SENDFILE) {
1316    /* printf("send file!\n"); */
1317  } else if (args->reqclass == AIM_CAPS_CHAT) {
1318    /*
1319    printf("chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1320    printf("chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1321    printf("chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1322    */
1323    /* Automatically join room... */
1324    /* printf("chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); */
1325    aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance);
1326  } else if (args->reqclass == AIM_CAPS_IMIMAGE) {
1327    directim_requested(sess, conn, userinfo, args);
1328  } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1329    /* printf("Buddy Icon from %s, length = %lu\n", userinfo->sn, args->info.icon.length); */
1330  } else if (args->reqclass == AIM_CAPS_ICQRTF) {
1331    /* 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); */
1332  } else {
1333    /* printf("icbm: unknown reqclass (%d)\n", args->reqclass); */
1334  }
1335  return 1;
1336}
1337
1338static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1339{
1340  fu16_t channel;
1341  aim_userinfo_t *userinfo;
1342  va_list ap;
1343  int ret = 0;
1344 
1345  va_start(ap, fr);
1346  channel = (fu16_t)va_arg(ap, unsigned int);
1347  userinfo = va_arg(ap, aim_userinfo_t *);
1348 
1349  if (channel == 1) {
1350    struct aim_incomingim_ch1_args *args;
1351    args = va_arg(ap, struct aim_incomingim_ch1_args *);
1352    ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, args);
1353  } else if (channel == 2) {
1354    struct aim_incomingim_ch2_args *args;
1355    args = va_arg(ap, struct aim_incomingim_ch2_args *);
1356    ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, args);
1357  } else {
1358    /* printf("unsupported channel 0x%04x\n", channel); */
1359  }
1360  va_end(ap);
1361  /* printf("icbm: done with ICBM handling (ret = %d)\n", ret); */
1362  return 1;
1363}
1364
1365static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1366{
1367  aim_userinfo_t *userinfo;
1368 
1369  va_list ap;
1370  va_start(ap, fr);
1371  userinfo = va_arg(ap, aim_userinfo_t *);
1372  va_end(ap);
1373  /*
1374    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1375    time(NULL),
1376    userinfo->sn, userinfo->flags,
1377    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1378    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1379    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1380    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1381    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1382    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1383    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1384    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1385    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1386    userinfo->capabilities);
1387  */
1388  return 1;
1389}
1390
1391static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1392{
1393  aim_userinfo_t *userinfo;
1394  va_list ap;
1395 
1396  va_start(ap, fr);
1397  userinfo = va_arg(ap, aim_userinfo_t *);
1398  va_end(ap);
1399
1400  /*
1401  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1402         time(NULL),
1403         userinfo->sn, userinfo->flags,
1404         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1405         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1406         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1407         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1408         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1409         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1410         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1411         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1412         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1413         userinfo->capabilities);
1414  */
1415 
1416  return 1;
1417}
1418
1419/* Used by chat as well. */
1420int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1421{
1422  va_list ap;
1423  fu16_t reason;
1424 
1425  va_start(ap, fr);
1426  reason = (fu16_t)va_arg(ap, unsigned int);
1427  va_end(ap);
1428 
1429  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1430 
1431  return 1;
1432}
1433
1434static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1435{
1436  va_list ap;
1437  char *destsn;
1438  fu16_t reason;
1439 
1440  va_start(ap, fr);
1441  reason = (fu16_t)va_arg(ap, unsigned int);
1442  destsn = va_arg(ap, char *);
1443  va_end(ap);
1444 
1445  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1446 
1447  return 1;
1448}
1449
1450static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1451{
1452  va_list ap;
1453  char *destsn;
1454  fu16_t reason;
1455 
1456  va_start(ap, fr);
1457  reason = (fu16_t)va_arg(ap, unsigned int);
1458  destsn = va_arg(ap, char *);
1459  va_end(ap);
1460 
1461  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1462 
1463  return 1;
1464}
1465
1466static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1467{
1468  /*
1469  static char *missedreasons[] = {
1470    "Invalid (0)",
1471    "Message too large",
1472    "Rate exceeded",
1473    "Evil Sender",
1474    "Evil Receiver"
1475  };
1476  static int missedreasonslen = 5; */
1477 
1478  va_list ap;
1479  fu16_t chan, nummissed, reason;
1480  aim_userinfo_t *userinfo;
1481 
1482  va_start(ap, fr);
1483  chan = (fu16_t)va_arg(ap, unsigned int);
1484  userinfo = va_arg(ap, aim_userinfo_t *);
1485  nummissed = (fu16_t)va_arg(ap, unsigned int);
1486  reason = (fu16_t)va_arg(ap, unsigned int);
1487  va_end(ap);
1488 
1489  /* printf("missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown"); */
1490 
1491  return 1;
1492}
1493
1494/*
1495 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1496 */
1497static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1498{
1499  va_list ap;
1500  fu16_t type;
1501  char *sn = NULL;
1502 
1503  va_start(ap, fr);
1504  type = (fu16_t)va_arg(ap, unsigned int);
1505  sn = va_arg(ap, char *);
1506  va_end(ap);
1507 
1508  /* printf("msgack: 0x%04x / %s\n", type, sn); */
1509 
1510  return 1;
1511}
1512
1513static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1514{
1515  /*
1516  static char *codes[5] = {
1517    "invalid",
1518    "change",
1519    "warning",
1520    "limit",
1521    "limit cleared"
1522  };
1523  */
1524  va_list ap;
1525  fu16_t code, rateclass;
1526  fu32_t windowsize, clear, alert, limit, disconnect;
1527  fu32_t currentavg, maxavg;
1528 
1529  va_start(ap, fr); 
1530 
1531  /* See code explanations below */
1532  code = (fu16_t)va_arg(ap, unsigned int);
1533 
1534  /*
1535   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1536   */
1537  rateclass = (fu16_t)va_arg(ap, unsigned int);
1538 
1539  /*
1540   * Not sure what this is exactly.  I think its the temporal
1541   * relation factor (ie, how to make the rest of the numbers
1542   * make sense in the real world).
1543   */
1544  windowsize = va_arg(ap, fu32_t);
1545 
1546  /* Explained below */
1547  clear = va_arg(ap, fu32_t);
1548  alert = va_arg(ap, fu32_t);
1549  limit = va_arg(ap, fu32_t);
1550  disconnect = va_arg(ap, fu32_t);
1551  currentavg = va_arg(ap, fu32_t);
1552  maxavg = va_arg(ap, fu32_t);
1553 
1554  va_end(ap);
1555 
1556  /*
1557  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",
1558         (code < 5)?codes[code]:"invalid",
1559         rateclass,
1560         currentavg, maxavg,
1561         alert, clear,
1562         limit, disconnect,
1563         windowsize);
1564  */
1565  return 1;
1566}
1567
1568static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1569{
1570  va_list ap;
1571  fu16_t newevil;
1572  aim_userinfo_t *userinfo;
1573 
1574  va_start(ap, fr);
1575  newevil = (fu16_t)va_arg(ap, unsigned int);
1576  userinfo = va_arg(ap, aim_userinfo_t *);
1577  va_end(ap);
1578 
1579  /*
1580   * Evil Notifications that are lacking userinfo->sn are anon-warns
1581   * if they are an evil increases, but are not warnings at all if its
1582   * a decrease (its the natural backoff happening).
1583   *
1584   * newevil is passed as an int representing the new evil value times
1585   * ten.
1586   */
1587  /* printf("evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous"); */
1588 
1589  return 1;
1590}
1591
1592static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1593{
1594  va_list ap;
1595  char *address, *SNs;
1596  int num;
1597  /* int i; */
1598 
1599  va_start(ap, fr);
1600  address = va_arg(ap, char *);
1601  num = va_arg(ap, int);
1602  SNs = va_arg(ap, char *);
1603  va_end(ap);
1604 
1605  /* printf("E-Mail Search Results for %s: ", address);
1606 
1607  for(i = 0; i < num; i++)
1608    printf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1609  printf("\n");
1610  */
1611 
1612  return 1;
1613}
1614
1615static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1616{
1617  va_list ap;
1618  char *address;
1619 
1620  va_start(ap, fr);
1621  address = va_arg(ap, char *);
1622  va_end(ap);
1623 
1624  /* printf("E-Mail Search Results for %s: No Results or Invalid Email\n", address); */
1625 
1626  return 1;
1627}
1628
1629static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1630{
1631  va_list ap;
1632  char *msg, *url;
1633  fu16_t width, height, delay;
1634 
1635  va_start(ap, fr);
1636  msg = va_arg(ap, char *);
1637  url = va_arg(ap, char *);
1638  width = va_arg(ap, unsigned int);
1639  height = va_arg(ap, unsigned int);
1640  delay = va_arg(ap, unsigned int);
1641  va_end(ap);
1642 
1643  /* printf("popup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url); */
1644 
1645  return 1;
1646}
1647
1648static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1649{
1650  aim_sendpauseack(sess, fr->conn);
1651  return 1;
1652}
1653
1654static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1655{
1656  va_list ap;
1657  aim_conn_t *bosconn;
1658  char *bosip;
1659  fu8_t *cookie;
1660 
1661  va_start(ap, fr);
1662  bosip = va_arg(ap, char *);
1663  cookie = va_arg(ap, fu8_t *);
1664  va_end(ap);
1665 
1666  /* printf("migration in progress -- new BOS is %s -- disconnecting\n", bosip); */
1667  aim_conn_kill(sess, &fr->conn);
1668 
1669  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1670    /* printf("migrate: could not connect to BOS: internal error\n"); */
1671    return 1;
1672  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1673    /* printf("migrate: could not connect to BOS\n"); */
1674    aim_conn_kill(sess, &bosconn);
1675    return 1;
1676  }
1677 
1678  /* Login will happen all over again. */
1679  addcb_bos(sess, bosconn);
1680  aim_sendcookie(sess, bosconn, cookie);
1681  return 1;
1682}
1683
1684static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1685{
1686 
1687  /* printf("got SSI rights, requesting data\n"); */
1688  aim_ssi_reqdata(sess, fr->conn, 0, 0x0000);
1689 
1690  return 1;
1691}
1692
1693static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1694{
1695  va_list ap;
1696  fu8_t fmtver;
1697  fu16_t itemcount;
1698  fu32_t stamp;
1699  struct aim_ssi_item *list, *l;
1700 
1701  va_start(ap, fr);
1702  fmtver = va_arg(ap, unsigned int);
1703  itemcount = va_arg(ap, unsigned int);
1704  stamp = va_arg(ap, fu32_t);
1705  list = va_arg(ap, struct aim_ssi_item *);
1706  va_end(ap);
1707 
1708  /* printf("got SSI data: (0x%02x, %d items, %ld)\n", fmtver, itemcount, stamp); */
1709  for (l = list; l; l = l->next) {
1710    /* printf("\t0x%04x (%s) - 0x%04x/0x%04x\n", l->type, l->name, l->gid, l->bid); */
1711    /* printf("I would have printed data here!\n"); */
1712  }
1713 
1714  aim_ssi_enable(sess, fr->conn);
1715 
1716  return 1;
1717}
1718
1719static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1720{
1721  /* printf("server says we have the latest SSI data already\n"); */
1722  aim_ssi_enable(sess, fr->conn);
1723  return 1;
1724}
1725
1726static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1727{
1728  va_list ap;
1729  struct aim_icq_offlinemsg *msg;
1730 
1731  va_start(ap, fr);
1732  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1733  va_end(ap);
1734 
1735  if (msg->type == 0x0001) {
1736    /* 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); */
1737  } else {
1738    /* printf("unknown offline message type 0x%04x\n", msg->type); */
1739  }
1740  return 1;
1741}
1742
1743static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1744{
1745  /* Tell the server to delete them. */
1746  aim_icq_ackofflinemsgs(sess);
1747  return 1;
1748}
1749
1750
1751/******************** chat.c **************************/
1752
1753
1754static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1755{
1756  va_list ap;
1757  aim_userinfo_t *userinfo;
1758  int count;
1759  /* int i; */
1760 
1761  va_start(ap, fr);
1762  count = va_arg(ap, int);
1763  userinfo = va_arg(ap, aim_userinfo_t *);
1764  va_end(ap);
1765
1766  /*
1767  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1768  for (i = 0; i < count; i++)
1769    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1770  */
1771  return 1;
1772}
1773
1774static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1775{
1776  aim_userinfo_t *userinfo;
1777  va_list ap;
1778  int count;
1779  /* int i; */
1780
1781 
1782  va_start(ap, fr);
1783  count = va_arg(ap, int);
1784  userinfo = va_arg(ap, aim_userinfo_t *);
1785  va_end(ap);
1786 
1787  /*
1788    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1789   
1790    for (i = 0; i < count; i++)
1791    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1792  */
1793  return 1;
1794}
1795
1796static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1797{
1798  va_list ap;
1799  aim_userinfo_t *userinfo;
1800  struct aim_chat_roominfo *roominfo;
1801  char *roomname;
1802  int usercount;
1803  char *roomdesc;
1804  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1805  fu32_t creationtime;
1806  const char *croomname;
1807  /* int i; */
1808 
1809  croomname = aim_chat_getname(fr->conn);
1810 
1811  va_start(ap, fr);
1812  roominfo = va_arg(ap, struct aim_chat_roominfo *);
1813  roomname = va_arg(ap, char *);
1814  usercount = va_arg(ap, int);
1815  userinfo = va_arg(ap, aim_userinfo_t *);
1816  roomdesc = va_arg(ap, char *);
1817  flags = (fu16_t)va_arg(ap, unsigned int);
1818  creationtime = va_arg(ap, fu32_t);
1819  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1820  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
1821  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
1822  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
1823  va_end(ap);
1824
1825  /*
1826  printf("chat: %s:  info update:\n", croomname);
1827  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
1828  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
1829  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
1830  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
1831
1832  for (i = 0; i < usercount; i++)
1833    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
1834 
1835  printf("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
1836         croomname, flags,
1837         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1838         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1839         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1840         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1841  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
1842  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
1843  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
1844  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
1845  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
1846  */
1847 
1848  return 1;
1849}
1850
1851static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
1852{
1853  va_list ap;
1854  aim_userinfo_t *userinfo;
1855  char *msg;
1856  char tmpbuf[1152];
1857 
1858  va_start(ap, fr);
1859  userinfo = va_arg(ap, aim_userinfo_t *);     
1860  msg = va_arg(ap, char *);
1861  va_end(ap);
1862
1863  /*
1864  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
1865  */
1866 
1867  /*
1868   * Do an echo for testing purposes.  But not for ourselves ("oops!")
1869   */
1870  if (strcmp(userinfo->sn, sess->sn) != 0) {
1871    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
1872    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
1873  }
1874 
1875  return 1;
1876}
1877
1878static int faimtest_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...)
1879{
1880  fu16_t type;
1881  va_list ap;
1882 
1883  va_start(ap, fr);
1884  type = (fu16_t)va_arg(ap, unsigned int);
1885 
1886  if (type == 0x0002) {
1887    int maxrooms;
1888    struct aim_chat_exchangeinfo *exchanges;
1889    int exchangecount;
1890    /* int i; */
1891   
1892    maxrooms = va_arg(ap, int);
1893    exchangecount = va_arg(ap, int);
1894    exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
1895    va_end(ap);
1896
1897    /*
1898    printf("chat info: Chat Rights:\n");
1899    printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
1900    printf("chat info: \tExchange List: (%d total)\n", exchangecount);
1901    for (i = 0; i < exchangecount; i++) {
1902      printf("chat info: \t\t%x: %s (%s/%s) (0x%04x = %s%s%s%s)\n",
1903             exchanges[i].number,
1904             exchanges[i].name,
1905             exchanges[i].charset1,
1906             exchanges[i].lang1,
1907             exchanges[i].flags,
1908             (exchanges[i].flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1909             (exchanges[i].flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1910             (exchanges[i].flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1911             (exchanges[i].flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1912    }
1913    */
1914  } else if (type == 0x0008) {
1915    char *fqcn, *name, *ck;
1916    fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
1917    fu8_t createperms;
1918    fu32_t createtime;
1919   
1920    fqcn = va_arg(ap, char *);
1921    instance = (fu16_t)va_arg(ap, unsigned int);
1922    exchange = (fu16_t)va_arg(ap, unsigned int);
1923    flags = (fu16_t)va_arg(ap, unsigned int);
1924    createtime = va_arg(ap, fu32_t);
1925    maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1926    maxoccupancy = (fu16_t)va_arg(ap, unsigned int);
1927    createperms = (fu8_t)va_arg(ap, unsigned int);
1928    unknown = (fu16_t)va_arg(ap, unsigned int);
1929    name = va_arg(ap, char *);
1930    ck = va_arg(ap, char *);
1931    va_end(ap);
1932   
1933    /* printf("received room create reply for %s/0x%04x\n", fqcn, exchange); */
1934   
1935  } else {
1936    va_end(ap);
1937    /* printf("chatnav info: unknown type (%04x)\n", type); */
1938  }
1939 
1940  return 1;
1941}
1942
1943static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
1944{
1945
1946  aim_clientready(sess, fr->conn);
1947 
1948  if (fr->conn->type == AIM_CONN_TYPE_CHATNAV) {
1949    /* printf("chatnav ready\n"); */
1950    aim_conn_addhandler(sess, fr->conn, 0x000d, 0x0001, faimtest_parse_genericerr, 0);
1951    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0);
1952    aim_chatnav_reqrights(sess, fr->conn);
1953  } else if (fr->conn->type == AIM_CONN_TYPE_CHAT) {
1954    /* printf("chat ready\n"); */
1955    aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
1956    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
1957    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
1958    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
1959    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
1960  }
1961  return 1;
1962}
1963
1964void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1965{
1966  aim_conn_t *tstconn;
1967 
1968  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
1969  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1970    /* printf("unable to connect to chat(nav) server\n"); */
1971    if (tstconn)
1972      aim_conn_kill(sess, &tstconn);
1973    return;
1974  }
1975 
1976  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
1977  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
1978  aim_sendcookie(sess, tstconn, redir->cookie);
1979  /* printf("chatnav: connected\n"); */
1980  return;
1981}
1982
1983/* XXX this needs instance too */
1984void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
1985{
1986  aim_conn_t *tstconn;
1987 
1988  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
1989  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
1990    /* printf("unable to connect to chat server\n"); */
1991    if (tstconn) aim_conn_kill(sess, &tstconn);
1992    return; 
1993  }             
1994  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
1995 
1996  /*
1997   * We must do this to attach the stored name to the connection!
1998   */
1999  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
2000  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2001  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2002  aim_sendcookie(sess, tstconn, redir->cookie);
2003  return;       
2004}
2005
2006
2007
2008
2009/******************************************* ft.c ******************************************/
2010
2011
2012static int directim_incoming(aim_session_t *sess, aim_frame_t *fr, ...)
2013{
2014  va_list ap;
2015  char *sn, *msg;
2016 
2017  va_start(ap, fr);
2018  sn = va_arg(ap, char *);
2019  msg = va_arg(ap, char *);
2020  va_end(ap);
2021 
2022  /* printf("Directim from %s: %s\n", sn, msg); */
2023  if (strstr(msg, "sendmsg")) {
2024    int i;
2025   
2026    i = atoi(strstr(msg, "sendmsg")+8);
2027    if (i < 10000) {
2028      char *newbuf;
2029      int z;
2030     
2031      newbuf = malloc(i+1);
2032      for (z = 0; z < i; z++)
2033        newbuf[z] = (z % 10)+0x30;
2034      newbuf[i] = '\0';
2035      aim_send_im_direct(sess, fr->conn, newbuf);
2036      free(newbuf);
2037    }
2038  } else if (strstr(msg, "goodday")) {
2039    aim_send_im_direct(sess, fr->conn, "Good day to you, too");
2040  } else {
2041    char newmsg[1024];
2042    snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg);
2043    aim_send_im_direct(sess, fr->conn, newmsg);
2044  }
2045
2046  return 1;
2047}
2048
2049static int directim_typing(aim_session_t *sess, aim_frame_t *fr, ...)
2050{
2051  va_list ap;
2052  char *sn;
2053 
2054  va_start(ap, fr);
2055  sn = va_arg(ap, char *);
2056  va_end(ap);
2057  /* printf("ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn); */
2058  return 1;
2059}
2060
2061static int faimtest_directim_initiate(aim_session_t *sess, aim_frame_t *fr, ...)
2062{
2063  va_list ap;
2064  aim_conn_t *newconn, *listenerconn;
2065 
2066  va_start(ap, fr);
2067  newconn = va_arg(ap, aim_conn_t *);
2068  listenerconn = va_arg(ap, aim_conn_t *);
2069  va_end(ap);
2070 
2071  aim_conn_close(listenerconn);
2072  aim_conn_kill(sess, &listenerconn);
2073 
2074  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, directim_incoming, 0);
2075  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, directim_typing, 0);
2076 
2077  aim_send_im_direct(sess, newconn, "goodday");
2078 
2079  /* printf("OFT: DirectIM: connected to %s\n", aim_directim_getsn(newconn)); */
2080 
2081  return 1;
2082}
2083
2084static int faimtest_getfile_filereq(aim_session_t *ses, aim_frame_t *fr, ...)
2085{
2086  va_list ap;
2087  aim_conn_t *oftconn;
2088  struct aim_fileheader_t *fh;
2089  fu8_t *cookie;
2090 
2091  va_start(ap, fr);
2092  oftconn = va_arg(ap, aim_conn_t *);
2093  fh = va_arg(ap, struct aim_fileheader_t *);
2094  cookie = va_arg(ap, fu8_t *);
2095  va_end(ap);
2096 
2097  /* printf("request for file %s.\n", fh->name); */
2098 
2099  return 1;
2100}
2101
2102static int faimtest_getfile_filesend(aim_session_t *sess, aim_frame_t *fr, ...)
2103{
2104  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
2105  va_list ap;
2106  aim_conn_t *oftconn;
2107  struct aim_fileheader_t *fh;
2108  char *path;
2109  fu8_t *cookie;
2110  int pos, bufpos = 0, bufsize = 2048, i;
2111  char *buf;
2112  FILE *file;
2113 
2114  va_start(ap, fr);
2115  oftconn = va_arg(ap, aim_conn_t *);
2116  fh = va_arg(ap, struct aim_fileheader_t *);
2117  cookie = va_arg(ap, fu8_t *);
2118  va_end(ap);
2119 
2120  /* printf("sending file %s(%ld).\n", fh->name, fh->size); */
2121
2122  if (!(buf = malloc(2048)))
2123    return -1;
2124 
2125  if (!(path = (char *)calloc(1, strlen(priv->listingpath) +strlen(fh->name)+2))) {
2126    /* perror("calloc"); */
2127    /* printf("error in calloc of path\n"); */
2128   
2129    return 0; /* XXX: no idea what winaim expects here =) */
2130  }
2131
2132  snprintf(path, strlen(priv->listingpath)+strlen(fh->name)+2, "%s/%s", priv->listingpath, fh->name);
2133 
2134  if (!(file = fopen(path, "r"))) {
2135    /* printf("getfile_send fopen failed for %s. damn.\n", path); */
2136    return 0;
2137  }
2138 
2139  /*
2140   * This is a mess. Remember that faimtest is demonstration code
2141   * only and for the sake of the gods, don't use this code in any
2142   * of your clients. --mid
2143   */
2144  for(pos = 0; pos < fh->size; pos++) {
2145   
2146    bufpos = pos % bufsize;
2147   
2148    if (bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2149      if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2150        /* perror("faim: getfile_send: write1"); */
2151        /* printf("faim: getfile_send: whoopsy, didn't write it all...\n"); */
2152        free(buf);   
2153        return 0;
2154      }
2155    }
2156   
2157    if( (buf[bufpos] = fgetc(file)) == EOF) {
2158      if(pos != fh->size) {
2159        /* printf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); */
2160        free(buf);   
2161        return 0;
2162      }
2163    }     
2164    /* printf("%c(0x%02x) ", buf[pos], buf[pos]); */
2165  }
2166 
2167  if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2168    /* perror("faim: getfile_send: write2"); */
2169    /* printf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); */
2170    free(buf);   
2171    return 0;
2172  }
2173 
2174  free(buf);
2175  free(fh);
2176 
2177  return 1;
2178}
2179
2180static int faimtest_getfile_complete(aim_session_t *sess, aim_frame_t *fr, ...) 
2181{
2182  va_list ap;
2183  aim_conn_t *conn;
2184  struct aim_fileheader_t *fh;
2185 
2186  va_start(ap, fr);
2187  conn = va_arg(ap, aim_conn_t *);
2188  fh = va_arg(ap, struct aim_fileheader_t *);
2189  va_end(ap);
2190 
2191  /* printf("completed file transfer for %s.\n", fh->name); */
2192 
2193  aim_conn_close(conn);
2194  aim_conn_kill(sess, &conn);
2195 
2196  return 1;
2197}
2198
2199static int faimtest_getfile_disconnect(aim_session_t *sess, aim_frame_t *fr, ...)
2200{
2201  va_list ap;
2202  aim_conn_t *conn;
2203  char *sn;
2204 
2205  va_start(ap, fr);
2206  conn = va_arg(ap, aim_conn_t *);
2207  sn = va_arg(ap, char *);
2208  va_end(ap);
2209 
2210  aim_conn_kill(sess, &conn);
2211 
2212  /* printf("getfile: disconnected from %s\n", sn); */
2213 
2214  return 1;
2215}
2216
2217static int faimtest_getfile_listing(aim_session_t *sess, aim_frame_t *fr, ...)
2218{
2219  va_list ap;
2220  aim_conn_t *conn;
2221  char *listing;
2222  struct aim_filetransfer_priv *ft;
2223  char *filename, *nameend, *sizec;
2224  int filesize, namelen;
2225 
2226  va_start(ap, fr);
2227  conn = va_arg(ap, aim_conn_t *);
2228  ft = va_arg(ap, struct aim_filetransfer_priv *);
2229  listing = va_arg(ap, char *);
2230  va_end(ap);
2231 
2232  /* printf("listing on %d==================\n%s\n===========\n", conn->fd, listing); */
2233 
2234  nameend = strstr(listing+0x1a, "\r");
2235  namelen = nameend - (listing + 0x1a);
2236 
2237  filename = malloc(namelen + 1);
2238  strncpy(filename, listing+0x1a, namelen);
2239  filename[namelen] = 0x00;
2240 
2241  sizec = malloc(8+1);
2242  memcpy(sizec, listing + 0x11, 8);
2243  sizec[8] = 0x00;
2244 
2245  filesize =  strtol(sizec, (char **)NULL, 10);
2246 
2247  /* printf("requesting %d %s(%d long)\n", namelen, filename, filesize); */
2248 
2249  aim_oft_getfile_request(sess, conn, filename, filesize);
2250 
2251  free(filename);
2252  free(sizec);
2253 
2254  return 0;
2255}
2256
2257static int faimtest_getfile_listingreq(aim_session_t *sess, aim_frame_t *fr, ...)
2258{
2259  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
2260  va_list ap;
2261  aim_conn_t *oftconn;
2262  struct aim_fileheader_t *fh;
2263  int pos, bufpos = 0, bufsize = 2048, i;
2264  char *buf;
2265 
2266  va_start(ap, fr);
2267  oftconn = va_arg(ap, aim_conn_t *);
2268  fh = va_arg(ap, struct aim_fileheader_t *);
2269  va_end(ap);
2270 
2271  /* printf("sending listing of size %ld\n", fh->size); */
2272
2273  if(!(buf = malloc(2048))) return -1;
2274 
2275  for(pos = 0; pos < fh->size; pos++) {
2276    bufpos = pos % bufsize;
2277    if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2278      if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2279        /* perror("faim: getfile_send: write1"); */
2280        /* printf("faim: getfile_send: whoopsy, didn't write it all...\n"); */
2281        free(buf);   
2282        return 0;
2283      }
2284    }
2285    if( (buf[bufpos] = fgetc(priv->listingfile)) == EOF) {
2286      if(pos != fh->size) {
2287        /* printf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); */
2288        free(buf);   
2289        return 0;
2290      }
2291    }     
2292  }
2293 
2294  if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2295    /* perror("faim: getfile_send: write2"); */
2296    /* printf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); */
2297    free(buf);   
2298    return 0;
2299  }
2300 
2301  /* printf("sent listing\n"); */
2302  free(buf);
2303 
2304  return 0;
2305}
2306
2307static int faimtest_getfile_receive(aim_session_t *sess, aim_frame_t *fr, ...)
2308{
2309  va_list ap;
2310  aim_conn_t *conn;
2311  struct aim_filetransfer_priv *ft;
2312  unsigned char data;
2313  int pos;
2314 
2315  va_start(ap, fr);
2316  conn = va_arg(ap, aim_conn_t *);
2317  ft = va_arg(ap, struct aim_filetransfer_priv *);
2318  va_end(ap);
2319
2320  /* printf("receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name); */
2321
2322  for(pos = 0; pos < ft->fh.size; pos++) {
2323    read(conn->fd, &data, 1);
2324    /* printf("%c(%02x) ", data, data); */
2325  }
2326
2327  /* printf("\n"); */
2328
2329  aim_oft_getfile_end(sess, conn);
2330  return 0;
2331}
2332
2333static int faimtest_getfile_state4(aim_session_t *sess, aim_frame_t *fr, ...)
2334{
2335  va_list ap;
2336  aim_conn_t *conn;
2337 
2338  va_start(ap, fr);
2339  conn = va_arg(ap, aim_conn_t *);
2340  va_end(ap);
2341 
2342  aim_conn_close(conn);
2343  aim_conn_kill(sess, &conn);
2344 
2345  return 0;
2346}
2347
2348static int faimtest_getfile_initiate(aim_session_t *sess, aim_frame_t *fr, ...)
2349{
2350  va_list ap;
2351  aim_conn_t *conn, *listenerconn;
2352  struct aim_filetransfer_priv *priv;
2353 
2354  va_start(ap, fr);
2355  conn = va_arg(ap, aim_conn_t *);
2356  listenerconn = va_arg(ap, aim_conn_t *);
2357  va_end(ap);
2358 
2359  aim_conn_close(listenerconn);
2360  aim_conn_kill(sess, &listenerconn);
2361 
2362  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
2363  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
2364  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);     
2365  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);     
2366  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0);
2367  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
2368  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0);
2369  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0);
2370 
2371  priv = (struct aim_filetransfer_priv *)conn->priv;
2372 
2373  /* printf("getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd); */
2374 
2375  return 1;
2376}
2377
2378void getfile_start(aim_session_t *sess, aim_conn_t *conn, const char *sn)
2379{
2380  aim_conn_t *newconn;
2381 
2382  newconn = aim_getfile_initiate(sess, conn, sn);
2383  /* printf("getting file listing from %s\n", sn); */
2384  aim_conn_addhandler(sess, newconn,  AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE, faimtest_getfile_initiate,0);
2385 
2386  return;
2387}
2388
2389void getfile_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
2390{
2391  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
2392  aim_conn_t *newconn;
2393  struct aim_fileheader_t *fh;
2394 
2395  printf("get file request from %s (at %s/%s/%s) %x\n", userinfo->sn, args->clientip, args->clientip2, args->verifiedip, args->reqclass);
2396  fh = aim_getlisting(sess, priv->listingfile);
2397  newconn = aim_accepttransfer(sess, conn, userinfo->sn, args->cookie, args->clientip, fh->totfiles, fh->totsize, fh->size, fh->checksum, args->reqclass);
2398  free(fh);
2399
2400  if ( (!newconn) || (newconn->fd == -1) ) {
2401    printf("getfile: requestconn: apparent error in accepttransfer\n");
2402    if (newconn) aim_conn_kill(sess, &newconn);
2403    return;
2404  }
2405 
2406  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
2407  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
2408  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
2409  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);     
2410  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);     
2411 
2412  /* printf("getfile connect succeeded, handlers added.\n"); */
2413 
2414  return;
2415}
2416
2417void directim_start(aim_session_t *sess, const char *sn)
2418{
2419  aim_conn_t *newconn;
2420 
2421  /* printf("opening directim to %s\n", sn); */
2422  newconn = aim_directim_initiate(sess, sn);
2423  if (!newconn || (newconn->fd == -1)) {
2424    /* printf("connection failed!\n"); */
2425    if (newconn) aim_conn_kill(sess, &newconn);
2426  } else {
2427    aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, faimtest_directim_initiate, 0);
2428  }
2429  return;
2430}
2431
2432void directim_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
2433{
2434  aim_conn_t *newconn;
2435 
2436  /* printf("OFT: DirectIM: request from %s (%s/%s/%s)\n", userinfo->sn, args->clientip, args->clientip2, args->verifiedip); */
2437 
2438  newconn = aim_directim_connect(sess, userinfo->sn, args->clientip, args->cookie);
2439  if (!newconn || (newconn->fd == -1)) {
2440    /* printf("icbm: imimage: could not connect\n"); */
2441    if (newconn) aim_conn_kill(sess, &newconn);
2442  } else {
2443    aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, directim_incoming, 0);
2444    aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, directim_typing, 0);
2445    /* printf("OFT: DirectIM: connected to %s\n", userinfo->sn); */
2446    aim_send_im_direct(sess, newconn, "goodday");
2447  }
2448}
Note: See TracBrowser for help on using the repository browser.