source: aim.c @ 03ad7b2

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