source: aim.c @ b2b0773

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