source: aim.c @ d559df9

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