comparison src/protocols/oscar/ft.c @ 4617:858979ab3867

[gaim-migrate @ 4908] Big Changes: -Rewrote some of the perl stuff so perl scripts can change a few of their parameters -Receiving a file with AIM over oscar works pretty well Now, the "nitty gritty": Very minor change to prefs.c: In the plugins details tab, I changed "URL" to "Web Site." I was just going to fix the tabbing, but silvestrij suggested changing it to "Web site," and I thought that sounded good. I think it fits better, too. I dunno, maybe that's just me. "Get Capabilities" has stopped working for some reason. I'm just going to blame AOL. It's really not important anyway, and some people wanted it taken off. It is now #ifdef 0'ed out. I'll remove it completely if it continues to no longer function. I took out a few plugin_event calls from oscar.c and put them in core code. "event_error" should be, uh, "evented" when there is an error signing on. Hopefully no one was using this. It's really pretty useless. The parameter is now the reason for not being able to connect rather than the archaic toc error code. I screwed around with how perl functions are called some. There was way the hell too much malloc'ing going on here. I think all in all it's an improvement, though I'm still not a big fan of how changes to parameters propagate to the actual memory. I really think it would be nice if the perl stuff was made into a C plugin. It's just so much cleaner. Especially if someone wanted to write, say, a python or tcl interpreter. That's how xchat2 does it. I just think that would be really slick. Like butter. Or ice. Very unlike Velcro. I added a "Change Password" Protocol Action for ICQ over oscar. This was really pretty easy. I'd like to thank my housemate Andrew for complaining a lot that having to use Windows ICQ to change his password was a pain. I rewrote a lot of the oscar file transfer stuff to use Christian's new xfer interface. This involved moving a few functions from ft.c to im.c, where they belong. I also removed all the #if 0'ed getfile functions. I'll be rewritting them soonish. Receiving a file should work perfectly, aside from maybe a small memleak when stuff is canceled. Sending a file is currently disabled. No ETA on when I'll have that working. I renamed pretty much all of the functions in im.c so they have kind of a scheme now. They should all be aim_im_bleh, since "im" is the family name. There comes a time when you must break the crap out of any clients that might be using libfaim in order to make stuff cleaner. Maybe. I got rid of the snac destructor stuff for now. I'll probably add it back later. I wasn't entirely comfortable with how it was done. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Wed, 26 Feb 2003 05:01:37 +0000
parents 9891c1458eb7
children 3c7d4a060d30
comparison
equal deleted inserted replaced
4616:767093a2ddaf 4617:858979ab3867
1 /* 1 /*
2 * File transfer (OFT) and DirectIM (ODC). 2 * Oscar File transfer (OFT) and Oscar Direct Connect (ODC).
3 * (OSCAR File Transfer, Oscar Direct Connect(ion?) 3 * (ODC is also referred to as DirectIM and IM Image.)
4 *
5 * There are a few static helper functions at the top, then
6 * ODC stuff, then ft stuff.
7 *
8 * I feel like this is a good place to explain OFT, so I'm going to
9 * do just that. Each OFT packet has a header type. I guess this
10 * is pretty similar to the subtype of a SNAC packet. The type
11 * basically tells the other client the meaning of the OFT packet.
12 * There are two distinct types of file transfer, which I usually
13 * call "sendfile" and "getfile." Sendfile is when you send a file
14 * to another AIM user. Getfile is when you share a group of files,
15 * and other users request that you send them the files.
16 *
17 * A typical sendfile file transfer goes like this:
18 * 1) Sender sends a channel 2 ICBM telling the other user that
19 * we want to send them a file. At the same time, we open a
20 * listener socket (this should be done before sending the
21 * ICBM) on some port, and wait for them to connect to us.
22 * The ICBM we sent should contain our IP address and the port
23 * number that we're listening on.
24 * 2) The receiver connects to the sender on the given IP address
25 * and port. After the connection is established, the receiver
26 * sends another ICBM signifying that we are ready and waiting.
27 * 3) The sender sends an OFT PROMPT message over the OFT
28 * connection.
29 * 4) The receiver of the file sends back an exact copy of this
30 * OFT packet, except the cookie is filled in with the cookie
31 * from the ICBM. I think this might be an attempt to verify
32 * that the user that is connected is actually the guy that
33 * we sent the ICBM to. Oh, I've been calling this the ACK.
34 * 5) The sender starts sending raw data across the connection
35 * until the entire file has been sent.
36 * 6) The receiver knows the file is finished because the sender
37 * sent the file size in an earlier OFT packet. So then the
38 * receiver sends the DONE thingy and closes the connection.
4 */ 39 */
5 40
6 #define FAIM_INTERNAL 41 #define FAIM_INTERNAL
7 42
8 #ifdef HAVE_CONFIG_H 43 #ifdef HAVE_CONFIG_H
12 47
13 #ifndef _WIN32 48 #ifndef _WIN32
14 #include <netdb.h> 49 #include <netdb.h>
15 #include <sys/socket.h> 50 #include <sys/socket.h>
16 #include <netinet/in.h> 51 #include <netinet/in.h>
17 #include <sys/utsname.h> /* for aim_directim_initiate */ 52 #include <sys/utsname.h> /* for aim_odc_initiate */
18 #include <arpa/inet.h> /* for inet_ntoa */ 53 #include <arpa/inet.h> /* for inet_ntoa */
19 #define G_DIR_SEPARATOR '/' 54 #define G_DIR_SEPARATOR '/'
20 #endif 55 #endif
21 56
22 #ifdef _WIN32 57 #ifdef _WIN32
23 #include "win32dep.h" 58 #include "win32dep.h"
24 #endif 59 #endif
25 60
26 #define AIM_OFT_PROTO_OFFER 0x0101 61 struct aim_odc_intdata {
27 #define AIM_OFT_PROTO_ACCEPT 0x0202
28 #define AIM_OFT_PROTO_RESUME 0x0205
29 #define AIM_OFT_PROTO_RESUMEACCEPT 0x0207
30 #define AIM_OFT_PROTO_ACK 0x0204
31
32 struct aim_filetransfer_priv {
33 char sn[MAXSNLEN+1];
34 char cookie[8];
35 char ip[30];
36 int state;
37 struct aim_fileheader_t fh;
38 };
39
40 struct aim_directim_intdata {
41 fu8_t cookie[8]; 62 fu8_t cookie[8];
42 char sn[MAXSNLEN+1]; 63 char sn[MAXSNLEN+1];
43 char ip[22]; 64 char ip[22];
44 }; 65 };
45 66
46 static int listenestablish(fu16_t portnum); 67 /**
47 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs); 68 * Convert the directory separator from / (0x2f) to ^A (0x01)
48 static void oft_dirconvert(char *name); 69 *
49 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh); 70 * @param name The filename to convert.
50 71 */
51 /** 72 static void aim_oft_dirconvert_tostupid(char *name)
52 * aim_handlerendconnect - call this to accept OFT connections and set up the required structures 73 {
53 * @sess: the session 74 while (name[0]) {
54 * @cur: the conn the incoming connection is on 75 if (name[0] == 0x01)
55 * 76 name[0] = G_DIR_SEPARATOR;
56 * call this when you get an outstanding read on a conn with subtype 77 name++;
57 * AIM_CONN_SUBTYPE_RENDEZVOUS_OUT, it will clone the current 78 }
58 * &aim_conn_t and tweak things as appropriate. the new conn and the 79 }
59 * listener conn are both returned to the client in the 80
60 * %AIM_CB_FAM_OFT, %AIM_CB_OFT_<CLASS>INITIATE callback. 81 /**
61 */ 82 * Convert the directory separator from ^A (0x01) to / (0x2f)
62 faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur) 83 *
63 { 84 * @param name The filename to convert.
64 int acceptfd = 0; 85 */
65 struct sockaddr cliaddr; 86 static void aim_oft_dirconvert_fromstupid(char *name)
66 int clilen = sizeof(cliaddr); 87 {
67 int ret = 0; 88 while (name[0]) {
68 aim_conn_t *newconn; 89 if (name[0] == G_DIR_SEPARATOR)
69 90 name[0] = 0x01;
70 if ((acceptfd = accept(cur->fd, &cliaddr, &clilen)) == -1) 91 name++;
71 return 0; /* not an error */ 92 }
72 93 }
73 if (cliaddr.sa_family != AF_INET) { /* just in case IPv6 really is happening */ 94
74 close(acceptfd); 95 /**
75 aim_conn_close(cur); 96 * Calculate oft checksum of buffer
76 return -1; 97 *
77 } 98 * Prevcheck should be 0xFFFF0000 when starting a checksum of a file. The
78 99 * checksum is kind of a rolling checksum thing, so each time you get bytes
79 if (!(newconn = aim_cloneconn(sess, cur))) { 100 * of a file you just call this puppy and it updates the checksum. You can
80 close(acceptfd); 101 * calculate the checksum of an entire file by calling this in a while or a
81 aim_conn_close(cur); 102 * for loop, or something.
82 return -1; 103 *
83 } 104 * Thanks to Graham Booker for providing this improved checksum routine,
84 105 * which is simpler and should be more accurate than Josh Myer's original
85 newconn->type = AIM_CONN_TYPE_RENDEZVOUS; 106 * code. -- wtm
86 newconn->fd = acceptfd; 107 *
87 108 * This algorithim works every time I have tried it. The other fails
88 if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { 109 * sometimes. So, AOL who thought this up? It has got to be the weirdest
89 struct aim_directim_intdata *priv; 110 * checksum I have ever seen.
90 aim_rxcallback_t userfunc; 111 *
91 112 * @param buffer Buffer of data to checksum. Man I'd like to buff her...
92 priv = (struct aim_directim_intdata *)(newconn->internal = cur->internal); 113 * @param bufsize Size of buffer.
93 cur->internal = NULL; 114 * @param prevcheck Previous checksum.
94 115 */
95 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", 116 faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, fu32_t prevcheck)
96 inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), 117 {
97 ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); 118 fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck;
98
99 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE)))
100 ret = userfunc(sess, NULL, newconn, cur);
101
102 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
103 #if 0
104 struct aim_filetransfer_priv *priv;
105 aim_rxcallback_t userfunc;
106
107 newconn->priv = cur->priv;
108 cur->priv = NULL;
109 priv = (struct aim_filetransfer_priv *)newconn->priv;
110
111 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
112
113 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE)))
114 ret = userfunc(sess, NULL, newconn, cur);
115 #endif
116 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
117 struct aim_filetransfer_priv *ft;
118 aim_rxcallback_t userfunc;
119
120 /* The new conn automatically inherits the internal value
121 * of cur. */
122 cur->internal = NULL;
123 ft = (struct aim_filetransfer_priv *)newconn->internal;
124
125 snprintf(ft->ip, sizeof(ft->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port));
126
127 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEINITIATE)))
128 ret = userfunc(sess, NULL, newconn, cur);
129 } else {
130 faimdprintf(sess, 1,"Got a Connection on a listener that's not Rendezvous Closing conn.\n");
131 aim_conn_close(newconn);
132 ret = -1;
133 }
134
135 return ret;
136 }
137
138 /**
139 * aim_send_typing - send client-to-client typing notification over established connection
140 * @sess: session to conn
141 * @conn: directim connection
142 * @typing: If true, notify user has started typing; if false, notify user has stopped.
143 *
144 * The connection must have been previously established.
145 */
146 faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing)
147 {
148 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
149 aim_frame_t *fr;
150 aim_bstream_t *hdrbs;
151 fu8_t *hdr;
152 int hdrlen = 0x44;
153
154 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
155 return -EINVAL;
156
157 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0)))
158 return -ENOMEM;
159 memcpy(fr->hdr.rend.magic, "ODC2", 4);
160 fr->hdr.rend.hdrlen = hdrlen;
161
162 if (!(hdr = calloc(1, hdrlen))) {
163 aim_frame_destroy(fr);
164 return -ENOMEM;
165 }
166
167 hdrbs = &(fr->data);
168 aim_bstream_init(hdrbs, hdr, hdrlen);
169
170 aimbs_put16(hdrbs, 0x0006);
171 aimbs_put16(hdrbs, 0x0000);
172 aimbs_putraw(hdrbs, intdata->cookie, 8);
173 aimbs_put16(hdrbs, 0x0000);
174 aimbs_put16(hdrbs, 0x0000);
175 aimbs_put16(hdrbs, 0x0000);
176 aimbs_put16(hdrbs, 0x0000);
177 aimbs_put32(hdrbs, 0x00000000);
178 aimbs_put16(hdrbs, 0x0000);
179 aimbs_put16(hdrbs, 0x0000);
180 aimbs_put16(hdrbs, 0x0000);
181
182 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing */
183 aimbs_put16(hdrbs, ( typing ? 0x000e : 0x0002));
184
185 aimbs_put16(hdrbs, 0x0000);
186 aimbs_put16(hdrbs, 0x0000);
187 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
188
189 aim_bstream_setpos(hdrbs, 52); /* bleeehh */
190
191 aimbs_put8(hdrbs, 0x00);
192 aimbs_put16(hdrbs, 0x0000);
193 aimbs_put16(hdrbs, 0x0000);
194 aimbs_put16(hdrbs, 0x0000);
195 aimbs_put16(hdrbs, 0x0000);
196 aimbs_put16(hdrbs, 0x0000);
197 aimbs_put16(hdrbs, 0x0000);
198 aimbs_put16(hdrbs, 0x0000);
199 aimbs_put8(hdrbs, 0x00);
200
201 /* end of hdr */
202
203 aim_tx_enqueue(sess, fr);
204
205 return 0;
206 }
207
208 /**
209 * aim_send_im_direct - send IM client-to-client over established connection
210 * @sess: session to conn
211 * @conn: directim connection
212 * @msg: null-terminated string to send.
213 * @len: The length of the message to send, including binary data.
214 * @encoding: 0 for ascii, 2 for Unicode, 3 for ISO 8859-1
215 *
216 * Call this just like you would aim_send_im, to send a directim. You
217 * _must_ have previously established the directim connection.
218 */
219 faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding)
220 {
221 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
222 aim_frame_t *fr;
223 aim_bstream_t *hdrbs;
224 int hdrlen = 0x44;
225 fu8_t *hdr;
226
227 if (!sess || !conn || !msg || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
228 return -EINVAL;
229
230 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, len)))
231 return -ENOMEM;
232
233 memcpy(fr->hdr.rend.magic, "ODC2", 4);
234 fr->hdr.rend.hdrlen = hdrlen;
235
236 if (!(hdr = calloc(1, hdrlen + len))) {
237 aim_frame_destroy(fr);
238 return -ENOMEM;
239 }
240
241 hdrbs = &(fr->data);
242 aim_bstream_init(hdrbs, hdr, hdrlen + len);
243
244 aimbs_put16(hdrbs, 0x0006);
245 aimbs_put16(hdrbs, 0x0000);
246 aimbs_putraw(hdrbs, intdata->cookie, 8);
247 aimbs_put16(hdrbs, 0x0000);
248 aimbs_put16(hdrbs, 0x0000);
249 aimbs_put16(hdrbs, 0x0000);
250 aimbs_put16(hdrbs, 0x0000);
251 aimbs_put32(hdrbs, len);
252 aimbs_put16(hdrbs, encoding);
253 aimbs_put16(hdrbs, 0x0000);
254 aimbs_put16(hdrbs, 0x0000);
255
256 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing, 0x0000 for message */
257 aimbs_put16(hdrbs, 0x0000);
258
259 aimbs_put16(hdrbs, 0x0000);
260 aimbs_put16(hdrbs, 0x0000);
261 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
262
263 aim_bstream_setpos(hdrbs, 52); /* bleeehh */
264
265 aimbs_put8(hdrbs, 0x00);
266 aimbs_put16(hdrbs, 0x0000);
267 aimbs_put16(hdrbs, 0x0000);
268 aimbs_put16(hdrbs, 0x0000);
269 aimbs_put16(hdrbs, 0x0000);
270 aimbs_put16(hdrbs, 0x0000);
271 aimbs_put16(hdrbs, 0x0000);
272 aimbs_put16(hdrbs, 0x0000);
273 aimbs_put8(hdrbs, 0x00);
274
275 /* end of hdr2 */
276
277 #if 0 /* XXX this is how you send buddy icon info... */
278 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008);
279 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c);
280 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
281 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466);
282 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001);
283 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f);
284 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e);
285 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8);
286 #endif
287 aimbs_putraw(hdrbs, msg, len);
288
289 aim_tx_enqueue(sess, fr);
290
291 return 0;
292 }
293
294 static int getlocalip(fu8_t *ip)
295 {
296 struct hostent *hptr;
297 char localhost[129];
298
299 /* XXX if available, use getaddrinfo() */
300 /* XXX allow client to specify which IP to use for multihomed boxes */
301
302 if (gethostname(localhost, 128) < 0)
303 return -1;
304
305 if (!(hptr = gethostbyname(localhost)))
306 return -1;
307
308 memcpy(ip, hptr->h_addr_list[0], 4);
309
310 return 0;
311 }
312
313 /**
314 * aim_directim_intitiate - For those times when we want to open up the directim channel ourselves.
315 * @sess: your session,
316 * @conn: the BOS conn,
317 * @priv: a dummy priv value (we'll let it get filled in later) (if you pass a %NULL, we alloc one)
318 * @destsn: the SN to connect to.
319 *
320 */
321 faim_export aim_conn_t *aim_directim_initiate(aim_session_t *sess, const char *destsn)
322 {
323 aim_conn_t *newconn;
324 aim_msgcookie_t *cookie;
325 struct aim_directim_intdata *priv;
326 int listenfd;
327 fu16_t port = 4443;
328 fu8_t localip[4];
329 fu8_t ck[8];
330
331 if (getlocalip(localip) == -1)
332 return NULL;
333
334 if ((listenfd = listenestablish(port)) == -1)
335 return NULL;
336
337 aim_request_directim(sess, destsn, localip, port, ck);
338
339 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t));
340 memcpy(cookie->cookie, ck, 8);
341 cookie->type = AIM_COOKIETYPE_OFTIM;
342
343 /* this one is for the cookie */
344 priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata));
345
346 memcpy(priv->cookie, ck, 8);
347 strncpy(priv->sn, destsn, sizeof(priv->sn));
348 cookie->data = priv;
349 aim_cachecookie(sess, cookie);
350
351 /* XXX switch to aim_cloneconn()? */
352 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) {
353 close(listenfd);
354 return NULL;
355 }
356
357 /* this one is for the conn */
358 priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata));
359
360 memcpy(priv->cookie, ck, 8);
361 strncpy(priv->sn, destsn, sizeof(priv->sn));
362
363 newconn->fd = listenfd;
364 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
365 newconn->internal = priv;
366 newconn->lastactivity = time(NULL);
367
368 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
369
370 return newconn;
371 }
372
373 /**
374 * aim_sendfile_intitiate - For those times when we want to send the file ourselves.
375 * @sess: your session,
376 * @conn: the BOS conn,
377 * @destsn: the SN to connect to.
378 * @filename: the name of the files you want to send
379 *
380 */
381 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *sess, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize, char *cookret)
382 {
383 aim_conn_t *newconn;
384 aim_msgcookie_t *cookie;
385 struct aim_filetransfer_priv *ft;
386 int listenfd;
387
388 /* XXX allow different ports */
389 fu16_t port = 4443;
390 fu8_t localip[4];
391 fu8_t ck[8];
392
393 if (getlocalip(localip) == -1)
394 return NULL;
395
396 if ((listenfd = listenestablish(port)) == -1)
397 return NULL;
398
399 aim_request_sendfile(sess, destsn, filename, numfiles, totsize, localip, port, ck);
400
401 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t));
402 memcpy(cookie->cookie, ck, 8);
403 cookie->type = AIM_COOKIETYPE_OFTSEND;
404 memcpy(cookret, ck, 8);
405
406 /* this one is for the cookie */
407 ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
408
409 memcpy(ft->cookie, ck, 8);
410 strncpy(ft->sn, destsn, sizeof(ft->sn));
411 cookie->data = ft;
412 aim_cachecookie(sess, cookie);
413
414 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) {
415 close(listenfd);
416 return NULL;
417 }
418
419 /* this one is for the conn */
420 ft = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
421
422 memcpy(ft->cookie, ck, 8);
423 strncpy(ft->sn, destsn, sizeof(ft->sn));
424
425 newconn->fd = listenfd;
426 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
427 newconn->internal = ft;
428 newconn->lastactivity = time(NULL);
429
430 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
431
432 return newconn;
433 }
434
435 #if 0
436 /**
437 * unsigned int aim_oft_listener_clean - close up old listeners
438 * @sess: session to clean up in
439 * @age: maximum age in seconds
440 *
441 * returns number closed, -1 on error.
442 */
443 faim_export unsigned int aim_oft_listener_clean(aim_session_t *sess, time_t age)
444 {
445 aim_conn_t *cur;
446 time_t now;
447 unsigned int hit = 0;
448
449 if (!sess)
450 return -1;
451 now = time(NULL);
452
453 for(cur = sess->connlist;cur; cur = cur->next)
454 if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
455 if (cur->lastactivity < (now - age) ) {
456 aim_conn_close(cur);
457 hit++;
458 }
459 }
460 return hit;
461 }
462 #endif
463
464 faim_export const char *aim_directim_getsn(aim_conn_t *conn)
465 {
466 struct aim_directim_intdata *intdata;
467
468 if (!conn)
469 return NULL;
470
471 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) ||
472 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
473 return NULL;
474
475 if (!conn->internal)
476 return NULL;
477
478 intdata = (struct aim_directim_intdata *)conn->internal;
479
480 return intdata->sn;
481 }
482
483 /**
484 * aim_directim_connect - connect to buddy for directim
485 * @sess: the session to append the conn to,
486 * @sn: the SN we're connecting to
487 * @addr: address to connect to
488 *
489 * This is a wrapper for aim_newconn.
490 *
491 * If addr is NULL, the socket is not created, but the connection is
492 * allocated and setup to connect.
493 *
494 */
495 faim_export aim_conn_t *aim_directim_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie)
496 {
497 aim_conn_t *newconn;
498 struct aim_directim_intdata *intdata;
499
500 if (!sess || !sn)
501 return NULL;
502
503 if (!(intdata = malloc(sizeof(struct aim_directim_intdata))))
504 return NULL;
505 memset(intdata, 0, sizeof(struct aim_directim_intdata));
506
507 memcpy(intdata->cookie, cookie, 8);
508 strncpy(intdata->sn, sn, sizeof(intdata->sn));
509 if (addr)
510 strncpy(intdata->ip, addr, sizeof(intdata->ip));
511
512 /* XXX verify that non-blocking connects actually work */
513 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) {
514 free(intdata);
515 return NULL;
516 }
517
518 if (!newconn) {
519 free(intdata);
520 return newconn;
521 }
522
523 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
524 newconn->internal = intdata;
525
526 return newconn;
527 }
528
529 /**
530 * aim_directim_getconn - find a directim conn for buddy name
531 * @sess: your session,
532 * @name: the name to get,
533 *
534 * returns conn for directim with name, %NULL if none found.
535 *
536 */
537 faim_export aim_conn_t *aim_directim_getconn(aim_session_t *sess, const char *name)
538 {
539 aim_conn_t *cur;
540
541 if (!sess || !name || !strlen(name))
542 return NULL;
543
544 for (cur = sess->connlist; cur; cur = cur->next) {
545 struct aim_directim_intdata *intdata;
546
547 if ((cur->type != AIM_CONN_TYPE_RENDEZVOUS) || (cur->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
548 continue;
549
550 intdata = cur->internal;
551
552 if (aim_sncmp(intdata->sn, name) == 0)
553 break;
554 }
555
556 return cur;
557 }
558
559 /**
560 * aim_accepttransfer - accept a file transfer request
561 * @sess: the session,
562 * @conn: the BOS conn for the CAP reply
563 * @sn: the screenname to send it to,
564 * @cookie: the cookie used
565 * @ip: the ip to connect to
566 * @port: the port to use
567 * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE)
568 *
569 * @listingfiles: number of files to share
570 * @listingtotsize: total size of shared files
571 * @listingsize: length of the listing file(buffer)
572 * @listingchecksum: checksum of the listing
573 *
574 * Returns new connection or %NULL on error.
575 *
576 * XXX this should take a struct.
577 */
578 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn,
579 const fu8_t *cookie, const fu8_t *ip,
580 fu16_t port, fu16_t rendid, ...)
581 {
582 aim_frame_t *newpacket;
583 aim_conn_t *newconn;
584 struct aim_filetransfer_priv *priv;
585 int i; 119 int i;
586 char addr[21]; 120 unsigned short val;
587 121
588 if (!sess || !conn || !sn || !cookie || !ip) { 122 for (i=0; i<bufferlen; i++) {
589 return NULL; 123 oldcheck = check;
590 } 124 if (i&1)
591 125 val = buffer[i];
592 /* OSCAR CAP accept packet */ 126 else
593 127 val = buffer[i] << 8;
594 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { 128 check -= val;
595 return NULL; 129 /*
596 } 130 * The following appears to be necessary.... It happens
597 131 * every once in a while and the checksum doesn't fail.
598 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next); 132 */
599 133 if (check > oldcheck)
600 for (i = 0; i < 8; i++) 134 check--;
601 aimbs_put8(&newpacket->data, cookie[i]); 135 }
602 136 check = ((check & 0x0000ffff) + (check >> 16));
603 aimbs_put16(&newpacket->data, 0x0002); 137 check = ((check & 0x0000ffff) + (check >> 16));
604 aimbs_put8(&newpacket->data, strlen(sn)); 138 return check << 16;
605 aimbs_putraw(&newpacket->data, sn, strlen(sn)); 139 }
606 aimbs_put16(&newpacket->data, 0x0005); 140
607 aimbs_put16(&newpacket->data, 0x001a); 141 /**
608 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_ACCEPT); 142 * Create a listening socket on a given port.
609 143 *
610 for (i = 0; i < 8; i++) /* yes, again... */ 144 * XXX - Give the client author the responsibility of setting up a
611 aimbs_put8(&newpacket->data, cookie[i]); 145 * listener, then we no longer have a libfaim problem with broken
612 146 * solaris *innocent smile* -- jbm
613 aim_putcap(&newpacket->data, rendid); 147 *
614 aim_tx_enqueue(sess, newpacket); 148 * @param portnum The port number to bind to.
615 149 * @return The file descriptor of the listening socket.
616 snprintf(addr, sizeof(addr), "%s:%d", ip, port);
617 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr);
618
619 if (newconn->status & AIM_CONN_STATUS_CONNERR) {
620 return NULL;
621 }
622
623 if (!newconn || (newconn->fd == -1)) {
624 perror("aim_newconn");
625 faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0);
626 return newconn;
627 }
628
629 priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
630
631 memcpy(priv->cookie, cookie, 8);
632 priv->state = 0;
633 strncpy(priv->sn, sn, MAXSNLEN);
634 strncpy(priv->ip, ip, sizeof(priv->ip));
635 newconn->internal = (void *)priv;
636
637 faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd);
638
639 if (rendid == AIM_CAPS_GETFILE) {
640 return NULL; /* This should never happen for now. -- wtm */
641
642 #if 0
643 struct aim_fileheader_t *fh;
644 aim_frame_t *newoft;
645 aim_msgcookie_t *cachedcook;
646 /* XXX take the following parameters fu16_t listingfiles,
647 fu16_t listingtotsize,
648 fu16_t listingsize,
649 fu32_t listingchecksum, */
650
651 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
652
653 faimdprintf(sess, 2, "faim: getfile request accept\n");
654
655 if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) {
656 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
657 /* XXX: conn leak here */
658 return NULL;
659 }
660
661 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
662 newoft->hdr.oft.hdr2len = 0x100 - 8;
663
664 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) {
665 /* XXX: conn leak here */
666 perror("calloc");
667 return NULL;
668 }
669
670 fh->encrypt = 0x0000;
671 fh->compress = 0x0000;
672 fh->totfiles = listingfiles;
673 fh->filesleft = listingfiles; /* is this right -- total parts and parts left?*/
674 fh->totparts = 0x0001;
675 fh->partsleft = 0x0001;
676 fh->totsize = listingtotsize;
677 fh->size = listingsize; /* ls -l listing.txt */
678 fh->modtime = (int)time(NULL); /* we'll go with current time for now */
679 fh->checksum = listingchecksum;
680 fh->rfcsum = 0x00000000;
681 fh->rfsize = 0x00000000;
682 fh->cretime = 0x00000000;
683 fh->rfcsum = 0x00000000;
684 fh->nrecvd = 0x00000000;
685 fh->recvcsum = 0x00000000;
686 memset(fh->idstring, 0, sizeof(fh->idstring));
687 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
688 fh->flags = 0x02;
689 fh->lnameoffset = 0x1a;
690 fh->lsizeoffset = 0x10;
691 memset(fh->dummy, 0, sizeof(fh->dummy));
692 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
693
694 /* we need to figure out these encodings for filenames */
695 fh->nencode = 0x0000;
696 fh->nlanguage = 0x0000;
697 memset(fh->name, 0, sizeof(fh->name));
698 strncpy(fh->name, "listing.txt", sizeof(fh->name));
699
700 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
701 aim_frame_destroy(newoft);
702 /* XXX: conn leak */
703 perror("calloc (1)");
704 return NULL;
705 }
706
707 memcpy(fh->bcookie, cookie, 8);
708
709 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh)))
710 faimdprintf(sess, 1, "eek, bh fail!\n");
711
712 aim_tx_enqueue(sess, newoft);
713
714 if (!(cachedcook = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)))) {
715 faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n");
716 /* XXX: more cleanup, conn leak */
717 perror("calloc (2)");
718 return NULL;
719 }
720
721 memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t));
722 memcpy(cachedcook->cookie, cookie, 8);
723
724 cachedcook->type = AIM_COOKIETYPE_OFTGET;
725 /* XXX doesn't priv need to be copied so we don't
726 * double free? -- wtm
727 */
728 cachedcook->data = (void *)priv;
729
730 if (aim_cachecookie(sess, cachedcook) == -1)
731 faimdprintf(sess, 1, "faim: ERROR caching message cookie\n");
732
733 free(fh);
734 #endif
735
736 } else if (rendid == AIM_CAPS_SENDFILE) {
737 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
738 priv->fh.recvcsum = 0xffff0000;
739 } else {
740 return NULL;
741 }
742
743 return newconn;
744 }
745
746 /* conn is a BOS connection over which to send the cancel msg */
747 faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn,
748 const char *cookie, const char *sn, int rendid)
749 {
750 aim_frame_t *newpacket;
751 int i;
752
753 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
754 return 1;
755 }
756
757 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
758
759 for (i = 0; i < 8; i++)
760 aimbs_put8(&newpacket->data, cookie[i]);
761
762 aimbs_put16(&newpacket->data, 0x0002);
763 aimbs_put8(&newpacket->data, strlen(sn));
764 aimbs_putraw(&newpacket->data, sn, strlen(sn));
765 aimbs_put16(&newpacket->data, 0x0005);
766 aimbs_put16(&newpacket->data, 0x001a);
767 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_CANCEL);
768
769 for (i = 0; i < 8; i++)
770 aimbs_put8(&newpacket->data, cookie[i]);
771
772 aim_putcap(&newpacket->data, rendid);
773 aim_tx_enqueue(sess, newpacket);
774
775 return 0;
776 }
777
778 /**
779 * aim_getlisting(FILE *file) -- get an aim_fileheader_t for a given FILE*
780 * @file is an opened listing file
781 *
782 * returns a pointer to the filled-in fileheader_t
783 *
784 * Currently omits checksum. we'll fix this when AOL breaks us, i
785 * guess.
786 *
787 */
788 faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *file)
789 {
790 return NULL;
791 #if 0
792 struct aim_fileheader_t *fh;
793 u_long totsize = 0, size = 0, checksum = 0xffff0000;
794 short totfiles = 0;
795 char *linebuf, sizebuf[9];
796 int linelength = 1024;
797
798 /* XXX: if we have a line longer than 1024chars, God help us. */
799 if ((linebuf = (char *)calloc(1, linelength)) == NULL ) {
800 faimdprintf(sess, 2, "linebuf calloc failed\n");
801 return NULL;
802 }
803
804 if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */
805 perror("getlisting END1 fseek:");
806 faimdprintf(sess, 2, "getlising fseek END1 error\n");
807 }
808
809 if ((size = ftell(file)) == -1) {
810 perror("getlisting END1 getpos:");
811 faimdprintf(sess, 2, "getlising getpos END1 error\n");
812 }
813
814 if (fseek(file, 0, SEEK_SET) != 0) {
815 perror("getlesting fseek(SET):");
816 faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n");
817 }
818
819 memset(linebuf, 0, linelength);
820
821 size = 0;
822
823 while(fgets(linebuf, linelength, file)) {
824 totfiles++;
825 memset(sizebuf, 0, 9);
826
827 size += strlen(linebuf);
828
829 if (strlen(linebuf) < 23) {
830 faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf);
831 continue;
832 }
833
834 if (linebuf[strlen(linebuf)-1] != '\n') {
835 faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n");
836 }
837
838 memcpy(sizebuf, linebuf+17, 8);
839
840 totsize += strtol(sizebuf, NULL, 10);
841 memset(linebuf, 0, linelength);
842 }
843
844 if (fseek(file, 0, SEEK_SET) == -1) {
845 perror("getlisting END2 fseek:");
846 faimdprintf(sess, 2, "getlising fseek END2 error\n");
847 }
848
849 free(linebuf);
850
851 /* we're going to ignore checksumming the data for now -- that
852 * requires walking the whole listing.txt. it should probably be
853 * done at register time and cached, but, eh. */
854
855 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
856 return NULL;
857
858 fh->encrypt = 0x0000;
859 fh->compress = 0x0000;
860 fh->totfiles = totfiles;
861 fh->filesleft = totfiles; /* is this right? */
862 fh->totparts = 0x0001;
863 fh->partsleft = 0x0001;
864 fh->totsize = totsize;
865 fh->size = size; /* ls -l listing.txt */
866 fh->modtime = (int)time(NULL); /* we'll go with current time for now */
867 fh->checksum = checksum; /* XXX: checksum ! */
868 fh->rfcsum = 0x00000000;
869 fh->rfsize = 0x00000000;
870 fh->cretime = 0x00000000;
871 fh->rfcsum = 0x00000000;
872 fh->nrecvd = 0x00000000;
873 fh->recvcsum = 0x00000000;
874
875 /* memset(fh->idstring, 0, sizeof(fh->idstring)); */
876 memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
877 memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring));
878
879 fh->flags = 0x02;
880 fh->lnameoffset = 0x1a;
881 fh->lsizeoffset = 0x10;
882
883 /* memset(fh->dummy, 0, sizeof(fh->dummy)); */
884 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
885
886 fh->nencode = 0x0000; /* we need to figure out these encodings for filenames */
887 fh->nlanguage = 0x0000;
888
889 /* memset(fh->name, 0, sizeof(fh->name)); */
890 strncpy(fh->name, "listing.txt", sizeof(fh->name));
891 memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name));
892
893 faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));
894 return fh;
895 #endif
896 }
897
898 /**
899 * aim_listenestablish - create a listening socket on a port.
900 * @portnum: the port number to bind to.
901 *
902 * you need to call accept() when it's connected. returns your fd
903 *
904 * XXX: give the client author the responsibility of setting up a
905 * listener, then we no longer have a libfaim problem with broken
906 * solaris *innocent smile* -jbm
907 */ 150 */
908 static int listenestablish(fu16_t portnum) 151 static int listenestablish(fu16_t portnum)
909 { 152 {
910 #if HAVE_GETADDRINFO 153 #if HAVE_GETADDRINFO
911 int listenfd; 154 int listenfd;
916 snprintf(serv, sizeof(serv), "%d", portnum); 159 snprintf(serv, sizeof(serv), "%d", portnum);
917 memset(&hints, 0, sizeof(struct addrinfo)); 160 memset(&hints, 0, sizeof(struct addrinfo));
918 hints.ai_flags = AI_PASSIVE; 161 hints.ai_flags = AI_PASSIVE;
919 hints.ai_family = AF_UNSPEC; 162 hints.ai_family = AF_UNSPEC;
920 hints.ai_socktype = SOCK_STREAM; 163 hints.ai_socktype = SOCK_STREAM;
921 if (getaddrinfo(NULL /*any IP*/, serv, &hints, &res) != 0) { 164 if (getaddrinfo(NULL /* any IP */, serv, &hints, &res) != 0) {
922 perror("getaddrinfo"); 165 perror("getaddrinfo");
923 return -1; 166 return -1;
924 } 167 }
925 ressave = res; 168 ressave = res;
926 do { 169 do {
927 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 170 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
928 if (listenfd < 0) 171 if (listenfd < 0)
929 continue; 172 continue;
930 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 173 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
931 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) 174 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
932 break; 175 break; /* success */
933 /* success */
934 close(listenfd); 176 close(listenfd);
935 } while ( (res = res->ai_next) ); 177 } while ( (res = res->ai_next) );
936 178
937 if (!res) 179 if (!res)
938 return -1; 180 return -1;
939 181
940 if (listen(listenfd, 1024)!=0) {
941 perror("listen");
942 return -1;
943 }
944
945 fcntl(listenfd, F_SETFL, O_NONBLOCK);
946
947 freeaddrinfo(ressave); 182 freeaddrinfo(ressave);
948 return listenfd;
949 #else 183 #else
950 int listenfd; 184 int listenfd;
951 const int on = 1; 185 const int on = 1;
952 struct sockaddr_in sockin; 186 struct sockaddr_in sockin;
953 187
954 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 188 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
955 perror("socket(listenfd)"); 189 perror("socket");
956 return -1; 190 return -1;
957 } 191 }
958 192
959 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) { 193 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) {
960 perror("setsockopt(listenfd)"); 194 perror("setsockopt");
961 close(listenfd); 195 close(listenfd);
962 return -1; 196 return -1;
963 } 197 }
964 198
965 memset(&sockin, 0, sizeof(struct sockaddr_in)); 199 memset(&sockin, 0, sizeof(struct sockaddr_in));
966 sockin.sin_family = AF_INET; 200 sockin.sin_family = AF_INET;
967 sockin.sin_port = htons(portnum); 201 sockin.sin_port = htons(portnum);
968 202
969 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { 203 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) {
970 perror("bind(listenfd)"); 204 perror("bind");
971 close(listenfd); 205 close(listenfd);
972 return -1; 206 return -1;
973 } 207 }
208 #endif
209
974 if (listen(listenfd, 4) != 0) { 210 if (listen(listenfd, 4) != 0) {
975 perror("listen(listenfd)"); 211 perror("listen");
976 close(listenfd); 212 close(listenfd);
977 return -1; 213 return -1;
978 } 214 }
979 fcntl(listenfd, F_SETFL, O_NONBLOCK); 215 fcntl(listenfd, F_SETFL, O_NONBLOCK);
216
980 return listenfd; 217 return listenfd;
218 }
219
220 /**
221 * After establishing a listening socket, this is called to accept a connection. It
222 * clones the conn used by the listener, and passes both of these to a signal handler.
223 * The signal handler should close the listener conn and keep track of the new conn,
224 * since this is what is used for file transfers and what not.
225 *
226 * @param sess The session.
227 * @param cur The conn the incoming connection is on.
228 * @return Return 0 if no errors, otherwise return the error number.
229 */
230 faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur)
231 {
232 int acceptfd = 0;
233 struct sockaddr addr;
234 socklen_t addrlen = sizeof(addr);
235 int ret = 0;
236 aim_conn_t *newconn;
237 char ip[20];
238 int port;
239
240 debug_printf("AAA - We got a bite! Dude connected to listener\n");
241 if ((acceptfd = accept(cur->fd, &addr, &addrlen)) == -1)
242 return 0; /* not an error */
243
244 if (addr.sa_family != AF_INET) { /* just in case IPv6 really is happening */
245 close(acceptfd);
246 aim_conn_close(cur);
247 return -1;
248 }
249
250 strncpy(ip, inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr), sizeof(ip));
251 port = ntohs(((struct sockaddr_in *)&addr)->sin_port);
252
253 if (!(newconn = aim_cloneconn(sess, cur))) {
254 close(acceptfd);
255 aim_conn_close(cur);
256 return -ENOMEM;
257 }
258
259 newconn->type = AIM_CONN_TYPE_RENDEZVOUS;
260 newconn->fd = acceptfd;
261
262 if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
263 aim_rxcallback_t userfunc;
264 struct aim_odc_intdata *priv;
265
266 priv = (struct aim_odc_intdata *)(newconn->internal = cur->internal);
267 cur->internal = NULL;
268 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", ip, port);
269
270 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIM_ESTABLISHED)))
271 ret = userfunc(sess, NULL, newconn, cur);
272
273 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
274 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
275 aim_rxcallback_t userfunc;
276
277 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED)))
278 ret = userfunc(sess, NULL, newconn, cur);
279
280 } else {
281 faimdprintf(sess, 1,"Got a connection on a listener that's not rendezvous. Closing connection.\n");
282 aim_conn_close(newconn);
283 ret = -1;
284 }
285
286 return ret;
287 }
288
289 /**
290 * Send client-to-client typing notification over an established direct connection.
291 *
292 * @param sess The session.
293 * @param conn The already-connected ODC connection.
294 * @param typing If true, notify user has started typing; if false, notify user has stopped.
295 * @return Return 0 if no errors, otherwise return the error number.
296 */
297 faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing)
298 {
299 struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal;
300 aim_frame_t *fr;
301 aim_bstream_t *hdrbs;
302 fu8_t *hdr;
303 int hdrlen = 0x44;
304
305 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
306 return -EINVAL;
307
308 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0)))
309 return -ENOMEM;
310 memcpy(fr->hdr.rend.magic, "ODC2", 4);
311 fr->hdr.rend.hdrlen = hdrlen;
312
313 if (!(hdr = calloc(1, hdrlen))) {
314 aim_frame_destroy(fr);
315 return -ENOMEM;
316 }
317
318 hdrbs = &(fr->data);
319 aim_bstream_init(hdrbs, hdr, hdrlen);
320
321 aimbs_put16(hdrbs, 0x0006);
322 aimbs_put16(hdrbs, 0x0000);
323 aimbs_putraw(hdrbs, intdata->cookie, 8);
324 aimbs_put16(hdrbs, 0x0000);
325 aimbs_put16(hdrbs, 0x0000);
326 aimbs_put16(hdrbs, 0x0000);
327 aimbs_put16(hdrbs, 0x0000);
328 aimbs_put32(hdrbs, 0x00000000);
329 aimbs_put16(hdrbs, 0x0000);
330 aimbs_put16(hdrbs, 0x0000);
331 aimbs_put16(hdrbs, 0x0000);
332
333 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing */
334 aimbs_put16(hdrbs, ( typing ? 0x000e : 0x0002));
335
336 aimbs_put16(hdrbs, 0x0000);
337 aimbs_put16(hdrbs, 0x0000);
338 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
339
340 aim_bstream_setpos(hdrbs, 52); /* bleeehh */
341
342 aimbs_put8(hdrbs, 0x00);
343 aimbs_put16(hdrbs, 0x0000);
344 aimbs_put16(hdrbs, 0x0000);
345 aimbs_put16(hdrbs, 0x0000);
346 aimbs_put16(hdrbs, 0x0000);
347 aimbs_put16(hdrbs, 0x0000);
348 aimbs_put16(hdrbs, 0x0000);
349 aimbs_put16(hdrbs, 0x0000);
350 aimbs_put8(hdrbs, 0x00);
351
352 /* end of hdr */
353
354 aim_tx_enqueue(sess, fr);
355
356 return 0;
357 }
358
359 /**
360 * Send client-to-client IM over an established direct connection.
361 * Call this just like you would aim_send_im, to send a directim.
362 *
363 * @param sess The session.
364 * @param conn The already-connected ODC connection.
365 * @param msg Null-terminated string to send.
366 * @param len The length of the message to send, including binary data.
367 * @param encoding 0 for ascii, 2 for Unicode, 3 for ISO 8859-1.
368 * @return Return 0 if no errors, otherwise return the error number.
369 */
370 faim_export int aim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding)
371 {
372 aim_frame_t *fr;
373 aim_bstream_t *hdrbs;
374 struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal;
375 int hdrlen = 0x44;
376 fu8_t *hdr;
377
378 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !msg)
379 return -EINVAL;
380
381 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, len)))
382 return -ENOMEM;
383
384 memcpy(fr->hdr.rend.magic, "ODC2", 4);
385 fr->hdr.rend.hdrlen = hdrlen;
386
387 if (!(hdr = calloc(1, hdrlen + len))) {
388 aim_frame_destroy(fr);
389 return -ENOMEM;
390 }
391
392 hdrbs = &(fr->data);
393 aim_bstream_init(hdrbs, hdr, hdrlen + len);
394
395 aimbs_put16(hdrbs, 0x0006);
396 aimbs_put16(hdrbs, 0x0000);
397 aimbs_putraw(hdrbs, intdata->cookie, 8);
398 aimbs_put16(hdrbs, 0x0000);
399 aimbs_put16(hdrbs, 0x0000);
400 aimbs_put16(hdrbs, 0x0000);
401 aimbs_put16(hdrbs, 0x0000);
402 aimbs_put32(hdrbs, len);
403 aimbs_put16(hdrbs, encoding);
404 aimbs_put16(hdrbs, 0x0000);
405 aimbs_put16(hdrbs, 0x0000);
406
407 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing, 0x0000 for message */
408 aimbs_put16(hdrbs, 0x0000);
409
410 aimbs_put16(hdrbs, 0x0000);
411 aimbs_put16(hdrbs, 0x0000);
412 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
413
414 aim_bstream_setpos(hdrbs, 52); /* bleeehh */
415
416 aimbs_put8(hdrbs, 0x00);
417 aimbs_put16(hdrbs, 0x0000);
418 aimbs_put16(hdrbs, 0x0000);
419 aimbs_put16(hdrbs, 0x0000);
420 aimbs_put16(hdrbs, 0x0000);
421 aimbs_put16(hdrbs, 0x0000);
422 aimbs_put16(hdrbs, 0x0000);
423 aimbs_put16(hdrbs, 0x0000);
424 aimbs_put8(hdrbs, 0x00);
425
426 /* end of hdr2 */
427
428 #if 0 /* XXX - this is how you send buddy icon info... */
429 aimbs_put16(hdrbs, 0x0008);
430 aimbs_put16(hdrbs, 0x000c);
431 aimbs_put16(hdrbs, 0x0000);
432 aimbs_put16(hdrbs, 0x1466);
433 aimbs_put16(hdrbs, 0x0001);
434 aimbs_put16(hdrbs, 0x2e0f);
435 aimbs_put16(hdrbs, 0x393e);
436 aimbs_put16(hdrbs, 0xcac8);
981 #endif 437 #endif
982 } 438 aimbs_putraw(hdrbs, msg, len);
983 439
984 static int getcommand_getfile(aim_session_t *sess, aim_conn_t *conn) 440 aim_tx_enqueue(sess, fr);
985 { 441
986 #if 0 442 return 0;
987 struct aim_filetransfer_priv *ft; 443 }
988 aim_rxcallback_t userfunc; 444
989 445 /**
990 ft = conn->priv; 446 * Get the screen name of the peer of a direct connection.
991 if (ft->state == 2) { 447 *
992 /* waiting on listing data */ 448 * @param conn The ODC connection.
993 int ret = 0; 449 * @return The screen name of the dude, or NULL if there was an anomaly.
994 char *listing; 450 */
995 aim_frame_t *newoft; 451 faim_export const char *aim_odc_getsn(aim_conn_t *conn)
996 452 {
997 if (!(listing = malloc(ft->fh.size))) 453 struct aim_odc_intdata *intdata;
998 return -1; 454
999 455 if (!conn || !conn->internal)
1000 ft->state = 0; 456 return NULL;
1001 if (aim_recv(conn->fd, listing, ft->fh.size) != ft->fh.size) 457
1002 faimdprintf(sess, 2, "OFT get: file %s was short. (0x%lx)\n", ft->fh.name, ft->fh.size); 458 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) ||
1003 459 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
1004 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120b, 0))) { 460 return NULL;
1005 faimdprintf(sess, 2, "faim: aim_get_command_rendezvous: getfile listing: tx_new OFT failed\n"); 461
1006 free(listing); 462 intdata = (struct aim_odc_intdata *)conn->internal;
1007 aim_conn_close(conn); 463
1008 return -1; 464 return intdata->sn;
465 }
466
467 /**
468 * Find the conn of a direct connection with the given buddy.
469 *
470 * @param sess The session.
471 * @param sn The screen name of the buddy whose direct connection you want to find.
472 * @return The conn for the direct connection with the given buddy, or NULL if no
473 * connection was found.
474 */
475 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn)
476 {
477 aim_conn_t *cur;
478 struct aim_odc_intdata *intdata;
479
480 if (!sess || !sn || !strlen(sn))
481 return NULL;
482
483 for (cur = sess->connlist; cur; cur = cur->next) {
484 if ((cur->type == AIM_CONN_TYPE_RENDEZVOUS) && (cur->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) {
485 intdata = cur->internal;
486 if (!aim_sncmp(intdata->sn, sn))
487 return cur;
1009 } 488 }
1010 489 }
1011 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 490
1012 newoft->hdr.oft.hdr2len = 0x100 - 8; 491 return NULL;
1013 492 }
1014 /* Protocol BS - set nrecvd to size of listing, recvcsum to listing checksum, flags to 0 */ 493
1015 494 /**
1016 ft->fh.nrecvd = ft->fh.size; 495 * For those times when we want to open up the direct connection channel ourselves.
1017 ft->fh.recvcsum = ft->fh.checksum; 496 *
1018 ft->fh.flags = 0; 497 * You'll want to set up some kind of watcher on this socket.
1019 498 * When the state changes, call aim_handlerendconnection with
1020 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 499 * the connection returned by this. aim_handlerendconnection
1021 aim_frame_destroy(newoft); 500 * will accept the pending connection and stop listening.
1022 free(listing); 501 *
1023 return -1; 502 * @param sess The session
1024 } 503 * @param conn The BOS conn.
1025 504 * @param priv A dummy priv value (we'll let it get filled in later)
1026 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) 505 * (if you pass a %NULL, we alloc one).
1027 faimdprintf(sess, 2, "eek! bh fail listing\n"); 506 * @param sn The screen name to connect to.
1028 507 * @return The new connection.
1029 /* send the 120b */ 508 */
1030 aim_tx_enqueue(sess, newoft); 509 faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn)
1031 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING)) ) 510 {
1032 ret = userfunc(sess, NULL, conn, ft, listing); 511 aim_conn_t *newconn;
1033 512 aim_msgcookie_t *cookie;
1034 free(listing); 513 struct aim_odc_intdata *priv;
1035 return ret; 514 int listenfd;
1036 } 515 fu16_t port = 4443;
1037 516 fu8_t localip[4];
1038 if (ft->state == 3) { 517 fu8_t ck[8];
1039 /* waiting on file data */ 518
1040 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE)) ) 519 if (aim_util_getlocalip(localip) == -1)
1041 return userfunc(sess, NULL, conn, ft->fh.name, 520 return NULL;
1042 ft->fh.size); 521
1043 return 0; 522 if ((listenfd = listenestablish(port)) == -1)
1044 } 523 return NULL;
1045 524
1046 if (ft->state == 4) { 525 aim_im_sendch2_odcrequest(sess, ck, sn, localip, port);
1047 if( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4)) ) 526
1048 return userfunc(sess, NULL, conn); 527 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t));
1049 aim_conn_close(conn); 528 memcpy(cookie->cookie, ck, 8);
1050 return 0; 529 cookie->type = AIM_COOKIETYPE_OFTIM;
1051 } 530
1052 531 /* this one is for the cookie */
1053 return 0; 532 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata));
1054 #else 533
1055 return -1; 534 memcpy(priv->cookie, ck, 8);
1056 #endif 535 strncpy(priv->sn, sn, sizeof(priv->sn));
1057 } 536 cookie->data = priv;
1058 537 aim_cachecookie(sess, cookie);
1059 static void connclose_sendfile(aim_session_t *sess, aim_conn_t *conn) 538
1060 { 539 /* XXX - switch to aim_cloneconn()? */
1061 aim_msgcookie_t *cook; 540 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) {
1062 struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->internal; 541 close(listenfd);
1063 542 return NULL;
1064 cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND); 543 }
1065 aim_cookie_free(sess, cook); 544
1066 545 /* this one is for the conn */
1067 return; 546 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata));
1068 } 547
1069 548 memcpy(priv->cookie, ck, 8);
1070 static void connkill_sendfile(aim_session_t *sess, aim_conn_t *conn) 549 strncpy(priv->sn, sn, sizeof(priv->sn));
1071 { 550
1072 free(conn->internal); 551 newconn->fd = listenfd;
1073 552 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
1074 return; 553 newconn->internal = priv;
1075 } 554 newconn->lastactivity = time(NULL);
1076 555
1077 static void connclose_getfile(aim_session_t *sess, aim_conn_t *conn) 556 return newconn;
1078 { 557 }
1079 #if 0 558
1080 aim_msgcookie_t *cook; 559 /**
1081 struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->priv; 560 * Connect directly to the given buddy for directim.
1082 561 *
1083 cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTGET); 562 * This is a wrapper for aim_newconn.
1084 aim_cookie_free(sess, cook); 563 *
1085 #endif 564 * If addr is NULL, the socket is not created, but the connection is
1086 return; 565 * allocated and setup to connect.
1087 } 566 *
1088 567 * @param sess The Godly session.
1089 static void connkill_getfile(aim_session_t *sess, aim_conn_t *conn) 568 * @param sn The screen name we're connecting to. I hope it's a girl...
1090 { 569 * @param addr Address to connect to.
1091 570 * @return The new connection.
1092 free(conn->internal); 571 */
1093 572 faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie)
1094 return; 573 {
1095 } 574 aim_conn_t *newconn;
1096 575 struct aim_odc_intdata *intdata;
1097 static void connclose_directim(aim_session_t *sess, aim_conn_t *conn) 576
1098 { 577 if (!sess || !sn)
1099 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; 578 return NULL;
1100 aim_msgcookie_t *cook; 579
1101 580 if (!(intdata = malloc(sizeof(struct aim_odc_intdata))))
1102 cook = aim_uncachecookie(sess, intdata->cookie, AIM_COOKIETYPE_OFTIM); 581 return NULL;
1103 aim_cookie_free(sess, cook); 582 memset(intdata, 0, sizeof(struct aim_odc_intdata));
1104 583 memcpy(intdata->cookie, cookie, 8);
1105 return; 584 strncpy(intdata->sn, sn, sizeof(intdata->sn));
1106 } 585 if (addr)
1107 586 strncpy(intdata->ip, addr, sizeof(intdata->ip));
1108 static void connkill_directim(aim_session_t *sess, aim_conn_t *conn) 587
1109 { 588 /* XXX - verify that non-blocking connects actually work */
1110 589 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) {
1111 free(conn->internal); 590 free(intdata);
1112 591 return NULL;
1113 return; 592 }
1114 } 593
1115 594 newconn->internal = intdata;
1116 faim_internal void aim_conn_close_rend(aim_session_t *sess, aim_conn_t *conn) 595 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
1117 { 596
1118 597 return newconn;
1119 if (conn->type != AIM_CONN_TYPE_RENDEZVOUS) 598 }
1120 return; 599
1121 600 /**
1122 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) 601 * Creates a listener socket so the other dude can connect to us.
1123 connclose_sendfile(sess, conn); 602 *
1124 else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) 603 * You'll want to set up some kind of watcher on this socket.
1125 connclose_getfile(sess, conn); 604 * When the state changes, call aim_handlerendconnection with
1126 else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) 605 * the connection returned by this. aim_handlerendconnection
1127 connclose_directim(sess, conn); 606 * will accept the pending connection and stop listening.
1128 607 *
1129 return; 608 * @param sess The session.
1130 } 609 * @param cookie This better be Mrs. Fields or I'm going to be pissed.
1131 610 * @param ip Should be 4 bytes, each byte is 1 quartet of the IP address.
1132 faim_internal void aim_conn_kill_rend(aim_session_t *sess, aim_conn_t *conn) 611 * @param port Ye olde port number to listen on.
1133 { 612 * @return Return the new conn if everything went as planned. Otherwise,
1134 613 * return NULL.
1135 if (conn->type != AIM_CONN_TYPE_RENDEZVOUS) 614 */
1136 return; 615 faim_export aim_conn_t *aim_sendfile_listen(aim_session_t *sess, const fu8_t *cookie, const fu8_t *ip, fu16_t port)
1137 616 {
1138 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) 617 aim_conn_t *newconn;
1139 connkill_sendfile(sess, conn); 618 int listenfd;
1140 else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) 619
1141 connkill_getfile(sess, conn); 620 debug_printf("AAA - listening on port %d\n", port);
1142 else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) 621 if ((listenfd = listenestablish(port)) == -1)
1143 connkill_directim(sess, conn); 622 return NULL;
1144 623
1145 return; 624 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) {
1146 } 625 close(listenfd);
1147 626 return NULL;
1148 static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) 627 }
1149 { 628
1150 aim_frame_t fr; 629 newconn->fd = listenfd;
1151 aim_rxcallback_t userfunc; 630 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
1152 fu32_t payloadlength; 631 newconn->lastactivity = time(NULL);
1153 fu16_t flags, encoding; 632
1154 char *snptr = NULL; 633 return newconn;
1155 634 }
1156 fr.conn = conn; 635
1157 636 /**
1158 /* XXX ugly */ 637 * Extract an &aim_fileheader_t from the given buffer.
1159 aim_bstream_setpos(bs, 20); 638 *
1160 payloadlength = aimbs_get32(bs); 639 * @param bs The should be from an incoming rendezvous packet.
1161 640 * @return A pointer to new struct on success, or NULL on error.
1162 aim_bstream_setpos(bs, 24); 641 */
1163 encoding = aimbs_get16(bs); 642 static struct aim_fileheader_t *aim_oft_getheader(aim_bstream_t *bs)
1164
1165 aim_bstream_setpos(bs, 30);
1166 flags = aimbs_get16(bs);
1167
1168 aim_bstream_setpos(bs, 36);
1169 /* XXX -create an aimbs_getnullstr function? */
1170 snptr = aimbs_getstr(bs, MAXSNLEN);
1171
1172 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_directim: %04x / %04x / %s\n", payloadlength, flags, snptr);
1173
1174 if (flags & 0x0002) {
1175 int ret = 0;
1176
1177 if (flags & 0x000c) {
1178 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
1179 ret = userfunc(sess, &fr, snptr, 1);
1180 return ret;
1181 }
1182
1183 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
1184 ret = userfunc(sess, &fr, snptr, 0);
1185
1186 return ret;
1187
1188 } else if (((flags & 0x000f) == 0x0000) && payloadlength) {
1189 char *msg, *msg2;
1190 int ret = 0;
1191 int recvd = 0;
1192 int i;
1193
1194 if (!(msg = calloc(1, payloadlength+1)))
1195 return -1;
1196 msg2 = msg;
1197
1198 while (payloadlength - recvd) {
1199 if (payloadlength - recvd >= 1024)
1200 i = aim_recv(conn->fd, msg2, 1024);
1201 else
1202 i = aim_recv(conn->fd, msg2, payloadlength - recvd);
1203 if (i <= 0) {
1204 free(msg);
1205 return -1;
1206 }
1207 recvd = recvd + i;
1208 msg2 = msg2 + i;
1209 if ((userfunc=aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER)))
1210 userfunc(sess, &fr, snptr, (double)recvd / payloadlength);
1211 }
1212
1213 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) )
1214 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding);
1215
1216 free(msg);
1217
1218 return ret;
1219 }
1220
1221 return 0;
1222 }
1223
1224 static int handlehdr_getfile_listing(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1225 {
1226 #if 0
1227 struct aim_filetransfer_priv *ft;
1228 struct aim_fileheader_t *fh;
1229 struct aim_msgcookie_t *cook;
1230 aim_frame_t *newoft;
1231 aim_rxcallback_t userfunc;
1232
1233 faimdprintf(sess, 2,"faim: rend: fileget 0x1108\n");
1234 fh = aim_oft_getfh(hdr);
1235
1236 faim_mutex_unlock(&conn->active);
1237
1238 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1239 free(fh);
1240 return -1;
1241 }
1242
1243 ft = cook->data;
1244
1245 /* we're waaaaiiiting.. for listing.txt */
1246 ft->state = 2;
1247
1248 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1249 free(fh);
1250
1251 if(aim_cachecookie(sess, cook) == -1) {
1252 faimdprintf(sess, 1, "error caching cookie\n");
1253 return -1;
1254 }
1255
1256 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) {
1257 aim_conn_close(conn);
1258 return -1;
1259 }
1260
1261 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1262 newoft->hdr.oft.hdr2len = 0x100 - 8;
1263
1264 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
1265 newoft->lock = 0;
1266 aim_frame_destroy(newoft);
1267 return -1;
1268 }
1269
1270 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
1271 newoft->lock = 0;
1272 aim_frame_destroy(newoft);
1273 return -1;
1274 }
1275
1276 newoft->lock = 0;
1277 aim_tx_enqueue(sess, newoft);
1278 #endif
1279 return -1;
1280 }
1281
1282 static int handlehdr_getfile_listing2(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1283 {
1284 #if 0
1285 struct aim_filetransfer_priv *ft;
1286 struct aim_fileheader_t *fh;
1287 struct aim_msgcookie_t *cook;
1288 int ret = 0;
1289 aim_rxcallback_t userfunc;
1290
1291 fh = aim_oft_getfh(hdr);
1292
1293 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET)))
1294 faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie);
1295
1296 ft = cook->data;
1297
1298 if (ft->fh.size != fh->size)
1299 faimdprintf(sess, 2, "hrm. ft->fh.size (%ld) != fh->size (%ld). um. using ft->fh.size\n", ft->fh.size, fh->size);
1300
1301 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ)))
1302 ret = userfunc(sess, NULL, conn, fh);
1303
1304 faimdprintf(sess, 2, "faim: get_command_rendezvous: hit end of 1209\n");
1305
1306 free(fh);
1307
1308 return ret;
1309 #else
1310 return -1;
1311 #endif
1312 }
1313
1314 static int handlehdr_getfile_listing3(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1315 {
1316 #if 0
1317 struct aim_filetransfer_priv *ft;
1318 struct aim_msgcookie_t *cook;
1319 struct aim_fileheader_t *fh;
1320 aim_rxcallback_t userfunc;
1321
1322 fh = aim_oft_getfh(hdr);
1323
1324 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1325 free(fh);
1326 return -1;
1327 }
1328
1329 free(fh);
1330
1331 ft = cook->data;
1332
1333 if (aim_cachecookie(sess, cook) == -1)
1334 return -1;
1335
1336 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGRXCONFIRM)))
1337 return userfunc(sess, NULL, conn);
1338 #endif
1339 return -1;
1340 }
1341
1342 static int handlehdr_getfile_request(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1343 {
1344 #if 0
1345 struct aim_filetransfer_priv *ft;
1346 aim_msgcookie_t *cook;
1347 struct aim_fileheader_t *fh;
1348 aim_frame_t *newoft;
1349 int i = 0;
1350 aim_rxcallback_t userfunc;
1351
1352 fh = aim_oft_getfh(hdr);
1353
1354 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1355 free(fh);
1356 return -1;
1357 }
1358
1359 ft = cook->data;
1360 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1361 free(fh);
1362
1363 aim_cachecookie(sess, cook);
1364
1365 faimdprintf(sess, 2, "faim: fileget: %s seems to want %s\n", ft->sn, ft->fh.name);
1366
1367 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) )
1368 i = userfunc(sess, NULL, conn, &(ft->fh), cook->cookie);
1369
1370 if (i < 0)
1371 return i;
1372
1373 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0101, 0))) {
1374 faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n");
1375 return -1;
1376 }
1377
1378 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1379 newoft->hdr.oft.hdr2len = 0x100 - 8;
1380
1381 if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
1382 aim_frame_destroy(newoft);
1383 return -1;
1384 }
1385
1386 /* protocol BS: nrecvd, recvcsum to 0, flags to 0x20. */
1387 ft->fh.nrecvd = 0;
1388 ft->fh.recvcsum = 0;
1389 ft->fh.flags = 0x20;
1390
1391 aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh));
1392
1393 aim_tx_enqueue(sess, newoft);
1394
1395 faimdprintf(sess, 2, "faim: OFT: OFT file header enqueued.\n");
1396
1397 return i;
1398 #else
1399 return -1;
1400 #endif
1401 }
1402
1403 static int handlehdr_getfile_sending(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1404 {
1405 #if 0
1406 struct aim_fileheader_t *fh;
1407 struct aim_filetransfer_priv *ft;
1408 struct aim_msgcookie_t *cook;
1409 struct command_tx_struct *newoft;
1410 aim_rxcallback_t userfunc;
1411
1412 fh = aim_oft_getfh(hdr);
1413
1414 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1415 free(fh);
1416 return -1;
1417 }
1418
1419 free(fh);
1420
1421 ft = cook->data;
1422
1423 ft->state = 3;
1424
1425 if (aim_cachecookie(sess, cook) == -1)
1426 return -1;
1427
1428 faimdprintf(sess, 2, "faim: fileget: %s seems to want to send %s\n", ft->sn, ft->fh.name);
1429
1430 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) {
1431 faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n");
1432 return -1;
1433 }
1434
1435 newoft->lock = 1;
1436 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
1437
1438 newoft->hdr.oft.hdr2len = 0x100 - 8;
1439
1440 if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
1441 aim_frame_destroy(newoft);
1442 return -1;
1443 }
1444
1445 aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh));
1446
1447 newoft->lock = 0;
1448 aim_tx_enqueue(sess, newoft);
1449
1450 faimdprintf(sess, 2, "faim: OFT: OFT 0x0202 enqueued.\n");
1451
1452 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) == NULL)
1453 return 1;
1454 #else
1455 return -1;
1456 #endif
1457 }
1458
1459 /* We are receiving a file, and the buddy sent us this header describing
1460 * it. We send back a similar header to confirm, then we're ready to
1461 * start reading the raw data.
1462 */
1463 static int handlehdr_sendfile_sending(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
1464 {
1465 struct aim_filetransfer_priv *ft;
1466 struct aim_fileheader_t *fh;
1467 aim_frame_t *newoft;
1468 aim_rxcallback_t userfunc;
1469
1470 fh = aim_oft_getfh(bs);
1471
1472 /* We receive a null cookie for the first file; we must fill
1473 * it in to authenticate ourselves. -- wtm
1474 */
1475 ft = conn->internal;
1476 memcpy(&(fh->bcookie), ft->cookie, 8);
1477
1478 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
1479 free(fh);
1480
1481 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACCEPT, 0))) {
1482 faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n");
1483 return -1;
1484 }
1485
1486 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
1487 return -1;
1488 }
1489 memcpy(newoft->hdr.rend.magic, "OFT2", 4);
1490 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
1491
1492 aim_tx_enqueue(sess, newoft);
1493
1494 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILEREQ)) == NULL)
1495 return 1;
1496
1497 {
1498 char *cur;
1499 /* Convert the directory separator: it is sent
1500 * as ^A (0x01).
1501 */
1502 while ((cur = strchr(ft->fh.name, 0x01))) {
1503 *cur = G_DIR_SEPARATOR;
1504 }
1505 }
1506 return userfunc(sess, NULL, conn, &(ft->fh));
1507 }
1508
1509
1510 /*
1511 * These were originally described by Josh Myer:
1512 * http://www.geocrawler.com/archives/3/896/2000/9/0/4291064/
1513 * XXX this doesn't actually work yet
1514 * -- wtm
1515 */
1516 static int handlehdr_sendfile_resume(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
1517 aim_frame_t *newoft;
1518 aim_msgcookie_t *cook;
1519 struct aim_fileheader_t *fh;
1520 struct aim_filetransfer_priv *ft;
1521
1522 fh = aim_oft_getfh(bs);
1523 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
1524 free(fh);
1525 return -1;
1526 }
1527 ft = (struct aim_filetransfer_priv *)cook->data;
1528
1529 ft->fh.nrecvd = fh->nrecvd;
1530 ft->fh.recvcsum = fh->recvcsum;
1531 strncpy(ft->fh.name, fh->name, sizeof(ft->fh.name));
1532 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0106, 0))) {
1533 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
1534 free(fh);
1535 return -1;
1536 }
1537
1538 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
1539 aim_frame_destroy(newoft);
1540 free(fh);
1541 return -1;
1542 }
1543 memcpy(newoft->hdr.rend.magic, "OFT2", 4);
1544 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
1545
1546 aim_tx_enqueue(sess, newoft);
1547 free(fh);
1548
1549 return 0;
1550 }
1551
1552 /* We are sending a file, and the buddy sent us this header indicating
1553 * that he or she is ready for the raw data.
1554 */
1555 static int handlehdr_sendfile_recv(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
1556 struct aim_fileheader_t *fh;
1557 aim_msgcookie_t *cook;
1558 int ret = 1;
1559 struct aim_filetransfer_priv *ft;
1560 aim_rxcallback_t userfunc;
1561
1562 fh = aim_oft_getfh(bs);
1563 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
1564 free(fh);
1565 return -1;
1566 }
1567 ft = (struct aim_filetransfer_priv *)cook->data;
1568
1569 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILESEND)) )
1570 ret = userfunc(sess, NULL, conn, &(ft->fh));
1571
1572 free(fh);
1573
1574 return ret;
1575 }
1576
1577 static int handlehdr_getfile_recv(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1578 {
1579 #if 0
1580 struct aim_fileheader_t *fh;
1581 struct aim_msgcookie_t *cook;
1582 int ret = 1;
1583 aim_rxcallback_t userfunc;
1584 struct aim_filetransfer_priv *ft;
1585
1586 fh = aim_oft_getfh(hdr);
1587
1588 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) {
1589 free(fh);
1590 return -1;
1591 }
1592
1593 ft = cook->data;
1594
1595 faimdprintf(sess, 2, "faim: get_rend: looks like we're ready to send data.(oft 0x0202)\n");
1596
1597 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND)) )
1598 ret = userfunc(sess, NULL, conn, fh);
1599
1600 free(fh);
1601
1602 return ret;
1603 #else
1604 return -1;
1605 #endif
1606 }
1607
1608 /* We just sent the raw data of a file, and the buddy sent us back this
1609 * header indicating that the transfer is complete.
1610 */
1611 static int handlehdr_sendfile_finish(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
1612 {
1613 struct aim_fileheader_t *fh;
1614 aim_msgcookie_t *cook;
1615 aim_rxcallback_t userfunc;
1616
1617 fh = aim_oft_getfh(bs);
1618
1619 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
1620 free(fh);
1621 return -1;
1622 }
1623
1624 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILECOMPLETE)) )
1625 userfunc(sess, NULL, conn, fh->bcookie);
1626
1627 free(fh);
1628 return 0;
1629 }
1630
1631 static int handlehdr_getfile_finish(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
1632 {
1633 #if 0
1634 struct aim_fileheader_t *fh;
1635 aim_rxcallback_t userfunc;
1636
1637 fh = aim_oft_getfh(hdr);
1638
1639 faimdprintf(sess, 2, "faim: get_rend: looks like we're done with a transfer (oft 0x0204)\n");
1640
1641 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE)) )
1642 userfunc(sess, NULL, conn, fh);
1643
1644 free(fh);
1645 #endif
1646
1647 return -1;
1648 }
1649
1650 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr)
1651 {
1652 aim_conn_t *conn = fr->conn;
1653 aim_bstream_t *bs = &fr->data;
1654 int ret = -1;
1655
1656 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
1657 /* This should never happen. -- wtm */
1658 return getcommand_getfile(sess, conn);
1659
1660 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
1661 switch(fr->hdr.rend.type) {
1662 case AIM_OFT_PROTO_OFFER:
1663 ret = handlehdr_sendfile_sending(sess, conn, bs);
1664 break;
1665 case AIM_OFT_PROTO_RESUME:
1666 ret = handlehdr_sendfile_resume(sess, conn, bs);
1667 break;
1668 case AIM_OFT_PROTO_RESUMEACCEPT: /* like _ACCEPT */;
1669 case AIM_OFT_PROTO_ACCEPT:
1670 ret = handlehdr_sendfile_recv(sess, conn, bs);
1671 break;
1672 case AIM_OFT_PROTO_ACK:
1673 ret = handlehdr_sendfile_finish(sess, conn, bs);
1674 break;
1675 default:
1676 faimdprintf(sess, 2, "faim: OFT frame: uknown type %04x\n", fr->hdr.rend.type);
1677 ret = -1;
1678 break;
1679 }
1680
1681 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
1682 if (fr->hdr.rend.type == 0x0001)
1683 ret = handlehdr_directim(sess, conn, bs);
1684 else
1685 faimdprintf(sess, 0, "faim: DIM frame: unknown type %04x\n", fr->hdr.rend.type);
1686
1687 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
1688 /* This _really_ shouldn't happen. :) -- wtm */
1689 char *hdr = NULL;
1690 int hdrtype = fr->hdr.rend.type;
1691 if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */
1692 ret = handlehdr_getfile_listing(sess, conn, hdr);
1693 else if (hdrtype == 0x1209) /* get file listing ack rx->tx */
1694 ret = handlehdr_getfile_listing2(sess, conn, hdr);
1695 else if (hdrtype == 0x120b) /* get file listing rx confirm */
1696 ret = handlehdr_getfile_listing3(sess, conn, hdr);
1697 else if (hdrtype == 0x120c) /* getfile request */
1698 ret = handlehdr_getfile_request(sess, conn, hdr);
1699 else if (hdrtype == 0x0101) /* getfile sending data */
1700 ret = handlehdr_getfile_sending(sess, conn, hdr);
1701 else if (hdrtype == 0x0202) /* getfile recv data */
1702 ret = handlehdr_getfile_recv(sess, conn, hdr);
1703 else if (hdrtype == 0x0204) /* getfile finished */
1704 ret = handlehdr_getfile_finish(sess, conn, hdr);
1705 else {
1706 faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype);
1707 ret = -1;
1708 }
1709 }
1710
1711 if (ret == -1)
1712 aim_conn_close(conn);
1713
1714 return ret;
1715 }
1716
1717 /**
1718 * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr.
1719 * @bs: bstream to extract header from
1720 *
1721 * returns pointer to new struct on success; %NULL on error.
1722 *
1723 */
1724 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs)
1725 { 643 {
1726 struct aim_fileheader_t *fh; 644 struct aim_fileheader_t *fh;
1727 645
1728 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t)))) 646 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t))))
1729 return NULL; 647 return NULL;
1752 fh->lsizeoffset = aimbs_get8(bs); 670 fh->lsizeoffset = aimbs_get8(bs);
1753 aimbs_getrawbuf(bs, fh->dummy, 69); 671 aimbs_getrawbuf(bs, fh->dummy, 69);
1754 aimbs_getrawbuf(bs, fh->macfileinfo, 16); 672 aimbs_getrawbuf(bs, fh->macfileinfo, 16);
1755 fh->nencode = aimbs_get16(bs); 673 fh->nencode = aimbs_get16(bs);
1756 fh->nlanguage = aimbs_get16(bs); 674 fh->nlanguage = aimbs_get16(bs);
1757 aimbs_getrawbuf(bs, fh->name, 64); /* XXX */ 675 aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */
1758 676
1759 return fh; 677 return fh;
1760 } 678 }
1761 679
1762 /** 680 /**
1763 * aim_oft_checksum - calculate oft checksum of buffer 681 * Fills a buffer with network-order fh data
1764 * @buffer: buffer of data to checksum 682 *
1765 * @bufsize: size of buffer 683 * @param bs A bstream to fill -- automatically initialized
1766 * @prevcheck: previous checksum 684 * @param fh A struct aim_fileheader_t to get data from.
1767 * 685 * @return Return non-zero on error.
1768 * Prevcheck should be 0xFFFF0000 for each new file; you can have this
1769 * checksum chunks of files in series if you just call it repeatedly in a
1770 * for(; ; ) loop and don't reset the checksum between each call. And you
1771 * thought we didn't care about you and your pathetic client's meomry
1772 * footprint ;^)
1773 *
1774 * Thanks to Graham Booker for providing this improved checksum
1775 * routine, which is simpler and should be more accurate than Josh
1776 * Myer's original code. -- wtm
1777 *
1778 * This algorithim works every time I have tried it. The other fails
1779 * sometimes. So, AOL who thought this up? It has got to be the weirdest
1780 * checksum I have ever seen.
1781 */
1782 faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, int prevcheck) {
1783 fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck;
1784 int i;
1785 unsigned short val;
1786
1787 for (i=0; i<bufferlen; i++) {
1788 oldcheck = check;
1789 if (i&1) {
1790 val = buffer[i];
1791 } else {
1792 val = buffer[i] << 8;
1793 }
1794 check -= val;
1795 /* The follownig appears to be necessary.... It happens every once in a while and the checksum doesn't fail. */
1796 if (check > oldcheck) {
1797 check--;
1798 }
1799 }
1800 check = ((check & 0x0000ffff) + (check >> 16));
1801 check = ((check & 0x0000ffff) + (check >> 16));
1802 return check << 16;
1803 }
1804
1805 faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn,
1806 const unsigned char *buffer, int len) {
1807 struct aim_filetransfer_priv *ft = conn->internal;
1808
1809 ft->fh.nrecvd += len;
1810 ft->fh.recvcsum = aim_oft_checksum(buffer, len, ft->fh.recvcsum);
1811
1812 return 0;
1813 }
1814
1815 /**
1816 * aim_oft_buildheader - fills a buffer with network-order fh data
1817 * @bs: bstream to fill -- automatically initialized
1818 * @fh: fh to get data from
1819 *
1820 * returns -1 on error.
1821 *
1822 */ 686 */
1823 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) 687 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh)
1824 { 688 {
1825 fu8_t *hdr; 689 fu8_t *hdr;
1826 690
1827 if (!bs || !fh) 691 if (!bs || !fh)
1828 return -1; 692 return -EINVAL;
1829 693
1830 694 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8)))
1831 695 return -ENOMEM;
1832 696
1833 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) {
1834 return -1;
1835 }
1836 aim_bstream_init(bs, hdr, 0x100 - 8); 697 aim_bstream_init(bs, hdr, 0x100 - 8);
1837
1838 aimbs_putraw(bs, fh->bcookie, 8); 698 aimbs_putraw(bs, fh->bcookie, 8);
1839 aimbs_put16(bs, fh->encrypt); 699 aimbs_put16(bs, fh->encrypt);
1840 aimbs_put16(bs, fh->compress); 700 aimbs_put16(bs, fh->compress);
1841 aimbs_put16(bs, fh->totfiles); 701 aimbs_put16(bs, fh->totfiles);
1842 aimbs_put16(bs, fh->filesleft); 702 aimbs_put16(bs, fh->filesleft);
1858 aimbs_put8(bs, fh->lsizeoffset); 718 aimbs_put8(bs, fh->lsizeoffset);
1859 aimbs_putraw(bs, fh->dummy, 69); 719 aimbs_putraw(bs, fh->dummy, 69);
1860 aimbs_putraw(bs, fh->macfileinfo, 16); 720 aimbs_putraw(bs, fh->macfileinfo, 16);
1861 aimbs_put16(bs, fh->nencode); 721 aimbs_put16(bs, fh->nencode);
1862 aimbs_put16(bs, fh->nlanguage); 722 aimbs_put16(bs, fh->nlanguage);
1863 aimbs_putraw(bs, fh->name, 64); 723 aimbs_putraw(bs, fh->name, 64); /* XXX - filenames longer than 64B */
1864 724
1865 /* XXX: Filenames longer than 64B */
1866 return 0; 725 return 0;
1867 } 726 }
1868 727
1869 /** 728 /**
1870 * aim_getfile_intitiate - Request an OFT getfile session 729 * Create an OFT packet based on the given information, and send it on its merry way.
1871 * @sess: your session, 730 *
1872 * @conn: the BOS conn, 731 * @param sess The session.
1873 * @destsn is the SN to connect to. 732 * @param conn The already-connected OFT connection.
1874 * 733 * @param cookie The cookie associated with this file transfer.
1875 * returns a new &aim_conn_t on success, %NULL on error 734 * @param filename The filename.
1876 */ 735 * @param filesdone Number of files already transferred.
1877 faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn) 736 * @param numfiles Total number of files.
1878 { 737 * @param size Size in bytes of this file.
1879 return NULL; 738 * @param totsize Size in bytes of all files combined.
1880 #if 0 739 * @param checksum Funky checksum of this file.
1881 struct command_tx_struct *newpacket; 740 * @param flags Any flags you want, baby. Send 0x21 when sending the
1882 struct aim_conn_t *newconn; 741 * "AIM_CB_OFT_DONE" message, and "0x02" for everything else.
1883 struct aim_filetransfer_priv *priv; 742 * @return Return 0 if no errors, otherwise return the error number.
1884 struct aim_msgcookie_t *cookie; 743 */
1885 int curbyte, i, listenfd; 744 faim_export int aim_oft_sendheader(aim_session_t *sess, aim_conn_t *conn, fu16_t type, const fu8_t *cookie, const char *filename, fu16_t filesdone, fu16_t numfiles, fu32_t size, fu32_t totsize, fu32_t modtime, fu32_t checksum, fu8_t flags)
1886 short port = 4443;
1887 struct hostent *hptr;
1888 struct utsname myname;
1889 char cap[16];
1890 char d[4];
1891
1892 /* Open our socket */
1893
1894 if ( (listenfd = aim_listenestablish(port)) == -1)
1895 return NULL;
1896
1897 /* get our local IP */
1898
1899 if (uname(&myname) < 0)
1900 return NULL;
1901 if ( (hptr = gethostbyname(myname.nodename)) == NULL)
1902 return NULL;
1903 memcpy(&d, hptr->h_addr_list[0], 4);
1904
1905 aim_putcap(cap, 16, AIM_CAPS_GETFILE);
1906
1907 /* create the OSCAR packet */
1908
1909 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42)))
1910 return NULL;
1911 newpacket->lock = 1;
1912
1913 /* lock struct */
1914 curbyte = 0;
1915 curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
1916
1917 /* XXX: check the cookie before commiting to using it */
1918
1919 /* Generate a random message cookie
1920 * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */
1921 for (i=0; i<7; i++)
1922 curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10));
1923
1924 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1925
1926 /* grab all the data for cookie caching. */
1927
1928 if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t))))
1929 return NULL;
1930 memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
1931 cookie->type = AIM_COOKIETYPE_OFTGET;
1932
1933 if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv))))
1934 return NULL;
1935 memcpy(priv->cookie, cookie, 8);
1936 memcpy(priv->sn, destsn, sizeof(priv->sn));
1937 memcpy(priv->fh.name, "listing.txt", strlen("listing.txt"));
1938 priv->state = 1;
1939
1940 cookie->data = priv;
1941
1942 aim_cachecookie(sess, cookie);
1943
1944 /* Channel ID */
1945 curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
1946
1947 /* Destination SN (prepended with byte length) */
1948 curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
1949 curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
1950 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1951 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
1952
1953 /* enTLV start */
1954 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1955 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042);
1956
1957 /* Flag data / ICBM Parameters? */
1958 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1959 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1960
1961 /* Cookie */
1962 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
1963
1964 /* Capability String */
1965 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
1966
1967 /* 000a/0002 : 0001 */
1968 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
1969 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
1970 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
1971
1972 /* 0003/0004: IP address */
1973 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1974 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
1975 for (i = 0; i < 4; i++)
1976 curbyte += aimutil_put8(newpacket->data+curbyte, d[i]);
1977
1978 /* already in network byte order */
1979
1980 /* 0005/0002: Port */
1981 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1982 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
1983 curbyte += aimutil_put16(newpacket->data+curbyte, port);
1984
1985 /* 000f/0000: ?? */
1986 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
1987 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
1988
1989 /* 2711/000c: ?? */
1990 curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711);
1991 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c);
1992 curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001);
1993
1994 for (i = 0; i < 0x000c - 4; i++)
1995 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1996
1997 newpacket->commandlen = curbyte;
1998 newpacket->lock = 0;
1999 aim_tx_enqueue(sess, newpacket);
2000
2001 /* allocate and set up our connection */
2002
2003 i = fcntl(listenfd, F_GETFL, 0);
2004 fcntl(listenfd, F_SETFL, i | O_NONBLOCK);
2005 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
2006
2007 if (!newconn){
2008 perror("aim_newconn");
2009 return NULL;
2010 }
2011
2012 newconn->fd = listenfd;
2013 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
2014 newconn->internal = priv;
2015 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
2016
2017 return newconn;
2018 #endif
2019 }
2020
2021 /**
2022 * aim_oft_getfile_request - request a particular file over an established getfile connection
2023 * @sess: your session
2024 * @conn: the established OFT getfile connection
2025 * @name: filename to request
2026 * @size: size of the file
2027 *
2028 *
2029 * returns -1 on error, 0 on successful enqueuing
2030 */
2031 #if 0
2032 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size)
2033 { 745 {
2034 aim_frame_t *newoft; 746 aim_frame_t *newoft;
2035 struct aim_filetransfer_priv *ft;
2036 if (!sess || !conn || !conn->priv || !name)
2037 return -1;
2038
2039 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) {
2040 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2041 return -1;
2042 }
2043 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
2044 newoft->hdr.oft.hdr2len = 0x100 - 8;
2045
2046 ft = (struct aim_filetransfer_priv *)conn->priv;
2047 ft->fh.filesleft = 1;
2048 ft->fh.totfiles = 1;
2049 ft->fh.totparts = 1;
2050 ft->fh.partsleft = 1;
2051 ft->fh.totsize = size;
2052 ft->fh.size = size;
2053 ft->fh.checksum = 0;
2054 memcpy(ft->fh.name, name, strlen(name));
2055 memset(ft->fh.name+strlen(name), 0, 1);
2056
2057 if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) {
2058 aim_frame_destroy(newoft);
2059 return -1;
2060 }
2061
2062 if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) {
2063 aim_frame_destroy(newoft);
2064 return -1;
2065 }
2066
2067 aim_tx_enqueue(sess, newoft);
2068 return 0;
2069 }
2070 #endif
2071
2072 /* Identify a file that we are about to send by transmitting the
2073 * appropriate header.
2074 */
2075 faim_export int aim_oft_sendfile_request(aim_session_t *sess, aim_conn_t *conn, const char *filename, int filesdone, int numfiles, int size, int totsize)
2076 {
2077 aim_frame_t *newoft;
2078 aim_msgcookie_t *cook;
2079 struct aim_filetransfer_priv *ft = (struct aim_filetransfer_priv *)conn->internal;
2080 struct aim_fileheader_t *fh; 747 struct aim_fileheader_t *fh;
2081 748
2082 if (!sess || !conn || !filename) 749 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !filename)
2083 return -1; 750 return -EINVAL;
2084 751
2085 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) 752 if (!(fh = (struct aim_fileheader_t *)calloc(1, sizeof(struct aim_fileheader_t))))
2086 return -1; 753 return -ENOMEM;
2087 754
2088 #ifdef DUMB_OFT_CHECKSUM 755 /*
2089 /* Yes, we are supposed to checksum the whole file before sending, and 756 * If you are receiving a file, the cookie should be null, if you are sending a
2090 * yes, it's dumb. This is the only way to get some clients (such as 757 * file, the cookie should be the same as the one used in the ICBM negotiation
2091 * Mac AIM v4.5.163) to successfully complete the transfer. With 758 * SNACs.
2092 * the WinAIM clients, we seem to be able to get away with just
2093 * setting the checksum to zero.
2094 * -- wtm
2095 */ 759 */
2096 { 760 if (cookie)
2097 int fd = open(filename, O_RDONLY); 761 memcpy(fh->bcookie, cookie, 8);
2098 if (fd >= 0) {
2099 int bytes;
2100 char buf[1024];
2101 fh->checksum = 0xffff0000;
2102 while ((bytes = aim_recv(fd, buf, 1024)) > 0) {
2103 fh->checksum = aim_oft_checksum(buf, bytes, fh->checksum);
2104 }
2105 }
2106 close(fd);
2107 }
2108 #else
2109 fh->checksum = 0x00000000;
2110 #endif
2111 fh->encrypt = 0x0000;
2112 fh->compress = 0x0000;
2113 fh->totfiles = numfiles; 762 fh->totfiles = numfiles;
2114 fh->filesleft = numfiles - filesdone; 763 fh->filesleft = numfiles - filesdone;
2115 fh->totparts = 0x0001; /* set to 0x0002 sending Mac resource forks */ 764 fh->totparts = 0x0001; /* set to 0x0002 sending Mac resource forks */
2116 fh->partsleft = 0x0001; 765 fh->partsleft = 0x0001;
2117 fh->totsize = totsize; 766 fh->totsize = totsize;
2118 fh->size = size; 767 fh->size = size;
2119 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 768 fh->modtime = modtime;
2120 /* fh->checksum set above */ 769 fh->checksum = checksum;
2121 fh->rfcsum = 0x00000000;
2122 fh->rfsize = 0x00000000;
2123 fh->cretime = 0x00000000;
2124 fh->rfcsum = 0x00000000;
2125 fh->nrecvd = 0x00000000; /* always zero initially */
2126 fh->recvcsum= 0x00000000; /* ditto */
2127 770
2128 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 771 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
2129 fh->flags = 0x02; 772 fh->flags = 0x02;
2130 fh->lnameoffset = 0x1a; 773 fh->lnameoffset = 0x1a;
2131 fh->lsizeoffset = 0x10; 774 fh->lsizeoffset = 0x10;
2135 /* apparently 0 is ASCII, 2 is UCS-2 */ 778 /* apparently 0 is ASCII, 2 is UCS-2 */
2136 /* it is likely that 3 is ISO 8859-1 */ 779 /* it is likely that 3 is ISO 8859-1 */
2137 fh->nencode = 0x0000; 780 fh->nencode = 0x0000;
2138 fh->nlanguage = 0x0000; 781 fh->nlanguage = 0x0000;
2139 782
2140 /* Convert the directory separator to ^A for portability. */
2141 strncpy(fh->name, filename, sizeof(fh->name)); 783 strncpy(fh->name, filename, sizeof(fh->name));
2142 oft_dirconvert(fh->name); 784 aim_oft_dirconvert_tostupid(fh->name);
2143 785
2144 /* XXX we should normally send a null cookie here, and make 786 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, type, 0))) {
2145 * the receiver fill it in for authentication -- wtm
2146 */
2147 memcpy(fh->bcookie, ft->cookie, 8);
2148
2149 if (!(cook = aim_checkcookie(sess, ft->cookie, AIM_COOKIETYPE_OFTSEND))) {
2150 return -1;
2151 }
2152
2153 /* Update both headers to be safe. */
2154 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
2155 memcpy(&(((struct aim_filetransfer_priv *)cook->data)->fh), fh, sizeof(struct aim_fileheader_t));
2156
2157 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_OFFER, 0))) {
2158 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2159 free(fh); 787 free(fh);
2160 return -1; 788 return -ENOMEM;
2161 } 789 }
2162 790
2163 if (aim_oft_buildheader(&newoft->data, fh) == -1) { 791 if (aim_oft_buildheader(&newoft->data, fh) == -1) {
2164 aim_frame_destroy(newoft); 792 aim_frame_destroy(newoft);
2165 free(fh); 793 free(fh);
2166 return -1; 794 return -ENOMEM;
2167 } 795 }
2168 796
2169 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 797 memcpy(newoft->hdr.rend.magic, "OFT2", 4);
2170 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 798 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
2171 799
2172 aim_tx_enqueue(sess, newoft); 800 aim_tx_enqueue(sess, newoft);
801
2173 free(fh); 802 free(fh);
803
2174 return 0; 804 return 0;
2175 } 805 }
2176 806
2177 /** 807 /**
2178 * aim_oft_getfile_ack - acknowledge a getfile download as complete 808 * Sometimes you just don't know with these kinds of people.
2179 * @sess: your session 809 *
2180 * @conn: the getfile conn to send the ack over 810 * @param sess The session.
2181 * 811 * @param conn The ODC connection of the incoming data.
2182 * Call this function after you have read all the data in a particular 812 * @param frr The frame allocated for the incoming data.
2183 * filetransfer. Returns -1 on error, 0 on apparent success 813 * @param bs It stands for "bologna sandwich."
2184 * 814 * @return Return 0 if no errors, otherwise return the error number.
2185 */ 815 */
2186 faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn) 816 static int handlehdr_odc(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *frr, aim_bstream_t *bs)
2187 { 817 {
2188 return -EINVAL; 818 aim_frame_t fr;
2189 #if 0 819 aim_rxcallback_t userfunc;
2190 struct command_tx_struct *newoft; 820 fu32_t payloadlength;
2191 struct aim_filetransfer_priv *ft; 821 fu16_t flags, encoding;
2192 822 char *snptr = NULL;
2193 if (!sess || !conn || !conn->priv) 823
2194 return -1; 824 fr.conn = conn;
2195 825
2196 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) { 826 /* AAA - ugly */
2197 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 827 aim_bstream_setpos(bs, 20);
2198 return -1; 828 payloadlength = aimbs_get32(bs);
2199 } 829
2200 830 aim_bstream_setpos(bs, 24);
2201 newoft->lock = 1; 831 encoding = aimbs_get16(bs);
2202 832
2203 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 833 aim_bstream_setpos(bs, 30);
2204 newoft->hdr.oft.hdr2len = 0x100-8; 834 flags = aimbs_get16(bs);
2205 835
2206 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 836 aim_bstream_setpos(bs, 36);
2207 newoft->lock = 0; 837 /* XXX - create an aimbs_getnullstr function? */
2208 aim_frame_destroy(newoft); 838 snptr = aimbs_getstr(bs, MAXSNLEN);
2209 return -1; 839
2210 } 840 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_odc: %04x / %04x / %s\n", payloadlength, flags, snptr);
2211 841
2212 ft = (struct aim_filetransfer_priv *)conn->priv; 842 if (flags & 0x0002) {
2213 843 int ret = 0;
2214 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { 844
2215 newoft->lock = 0; 845 if (flags & 0x000c) {
2216 aim_frame_destroy(newoft); 846 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
2217 return -1; 847 ret = userfunc(sess, &fr, snptr, 1);
2218 } 848 return ret;
2219 849 }
2220 newoft->lock = 0; 850
2221 aim_tx_enqueue(sess, newoft); 851 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
852 ret = userfunc(sess, &fr, snptr, 0);
853
854 return ret;
855
856 } else if (((flags & 0x000f) == 0x0000) && payloadlength) {
857 char *msg, *msg2;
858 int ret = 0;
859 int recvd = 0;
860 int i;
861
862 if (!(msg = calloc(1, payloadlength+1)))
863 return -1;
864 msg2 = msg;
865
866 while (payloadlength - recvd) {
867 if (payloadlength - recvd >= 1024)
868 i = aim_recv(conn->fd, msg2, 1024);
869 else
870 i = aim_recv(conn->fd, msg2, payloadlength - recvd);
871 if (i <= 0) {
872 free(msg);
873 return -1;
874 }
875 recvd = recvd + i;
876 msg2 = msg2 + i;
877 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER)))
878 userfunc(sess, &fr, snptr, (double)recvd / payloadlength);
879 }
880
881 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) )
882 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding);
883
884 free(msg);
885
886 return ret;
887 }
888
2222 return 0; 889 return 0;
2223 #endif 890 }
2224 } 891
2225 892 /**
2226 /** 893 * Handle incoming data on a rendezvous connection. This is analogous to the
2227 * aim_oft_end - end a getfile/sendfile. 894 * consumesnac function in rxhandlers.c, and I really think this should probably
2228 * @sess: your session 895 * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet.
2229 * @conn: the getfile connection 896 *
2230 * 897 * @param sess The session.
2231 * call this before you close the getfile connection if you're on the 898 * @param fr The frame allocated for the incoming data.
2232 * receiving/requesting end. 899 * @return Return 0 if the packet was handled correctly, otherwise return the
2233 */ 900 * error number.
2234 faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn) 901 */
2235 { 902 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr)
2236 aim_frame_t *newoft; 903 {
2237 struct aim_filetransfer_priv *ft; 904 aim_conn_t *conn = fr->conn;
2238 905 int ret = 1;
2239 if (!sess || !conn || !conn->internal) 906
2240 return -1; 907 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
2241 908 if (fr->hdr.rend.type == 0x0001)
2242 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACK, 0))) { 909 ret = handlehdr_odc(sess, conn, fr, &fr->data);
2243 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 910 else
2244 return -1; 911 faimdprintf(sess, 0, "faim: ODC directim frame unknown, type is %04x\n", fr->hdr.rend.type);
2245 } 912
2246 913 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
2247 ft = (struct aim_filetransfer_priv *)conn->internal; 914 switch (fr->hdr.rend.type) {
2248 ft->state = 4; /* no longer wanting data */ 915 case 0x1108: /* getfile listing.txt incoming tx->rx */
2249 ft->fh.flags = 0x21; 916 break;
2250 917 case 0x1209: /* get file listing ack rx->tx */
2251 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) { 918 break;
2252 aim_frame_destroy(newoft); 919 case 0x120b: /* get file listing rx confirm */
2253 return -1; 920 break;
2254 } 921 case 0x120c: /* getfile request */
2255 memcpy(newoft->hdr.rend.magic, "OFT2", 4); 922 break;
2256 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); 923 case 0x0101: /* getfile sending data */
2257 924 break;
2258 aim_tx_enqueue(sess, newoft); 925 case 0x0202: /* getfile recv data */
2259 926 break;
2260 return 0; 927 case 0x0204: /* getfile finished */
2261 } 928 break;
2262 929 default:
2263 /* 930 faimdprintf(sess, 2, "faim: OFT getfile frame uknown, type is %04x\n", fr->hdr.rend.type);
2264 * Convert the directory separator to ^A, which seems to be AOL's attempt at portability. 931 break;
2265 */ 932 }
2266 static void oft_dirconvert(char *name) { 933
2267 char *c = name; 934 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
2268 while ((c = strchr(c, G_DIR_SEPARATOR))) 935 aim_rxcallback_t userfunc;
2269 *c = 0x01; 936 struct aim_fileheader_t *header = aim_oft_getheader(&fr->data);
2270 } 937 aim_oft_dirconvert_fromstupid(header->name); /* XXX - This should be client-side */
938
939 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, fr->hdr.rend.type)))
940 ret = userfunc(sess, fr, conn, header->bcookie, header);
941
942 free(header);
943 }
944
945 if (ret == -1)
946 aim_conn_close(conn);
947
948 return ret;
949 }