comparison src/protocols/oscar/ft.c @ 3952:07283934dedd

[gaim-migrate @ 4133] Ok, big commit with little functionality change. Most of it is me shuffling crap around because I'm one of them neat freaks. Lots of general code cleanup too. I'm trying to move to that whole "one-family-per-file" thing. The details... I added libfaim support for aim's new search family, 0x000f. I only tested this briefly, so if anyone uses it for anything, be aware that it could be buggy. I'll add oscar support sometime. Advantages of this family are... when you search for someone, you get the directory info for that person. So like, first name, middle name, last name, maiden name, city, state, country, zip, address, interests, nickname, and maybe some other stuff. Basically all the info that they've set in their directory info thing. Info. Oh, and I'm calling it "new search" because seach was already taken, and cookie monster ate my right brain. The reason I didn't add support to oscar.c... the new search family requires making a connection to another server. While moving stuff around I realized that I didn't really like how new connections are made. It's kind of sloppy. I'm thinking it would be nice to have an outgoing queue for each type of connection, and then let the client queue messages as much as they want. Then, if libfaim sees that there is a message for a certain type of connection, and there is no open connection of that type, it will connect, and then flush the queue when the connection is made. This seems a lot cleaner, but it also seems like a pain in the ass. I should do ssi for icq first, anyway :-) Also, I think it would be neat if there was an ICBM file that handled channels 1 through 4. Then im.c and chat.c could pass the ICBM part to the icbm stuff and it could get parsed there. im.c is really huge right now. I applied a patch from Graham Booker that paves the way for unicode in direct IMs. Thanks Graham. Now we just need Paco-Paco to git a little free time and write a patch for this. http://sourceforge.net/tracker/index.php?func=detail&aid=633589&group_id=235&atid=300235 I applied 2 patches from Will Mahan dealing with file transfer/oft/rendezous/whatever. Here's some info on them, from The Man himself: Patch 1 "Currently the Rendezvous code is rather messy; this patch attempts to bring it up to speed with the rest of the Oscar prpl. Its changes include: * Rewrite several ft.c functions to use bstreams. Apparently the code in question was written before bstreams were implemented. * Handle incoming Rendezvous packets through the rxqueue like FLAP packets, rather than handling them as a special case as soon as they are received. This takes advantage of the bstream cleanup to unify some code and simplify the aim_frame_t struct. * Change some names used to try to clarify the distinction between OFT, which refers specifically to file transfer, and Rendezvous, which encompasses OFT as well as other types of client-to-client connections." Patch 2 "* Add some comments I inadvertently left out of my last patch. * Fix a double-free that occurs when connections time out. * Correct a bug causing filenames to be truncated by 4 characters on some clients. * Preserve directory structure when sending multiple files. * Handle (throw away) resource forks sent by Mac clients." I also changed all indents to tabs in ft.c. And split all the bstream stuff from rxqueue.c and put it in bstream.c. It really is a separate thing. Especially since it can be used for outgoing connections. Also, I was going to look over the whole patch tonight to make sure it's all good, but it's like 6000 lines, so, uh, I'll do it later. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Wed, 13 Nov 2002 07:01:37 +0000
parents 765769211688
children 7ec84d1954fd
comparison
equal deleted inserted replaced
3951:32942c49dced 3952:07283934dedd
16 #include <netinet/in.h> 16 #include <netinet/in.h>
17 #include <sys/utsname.h> /* for aim_directim_initiate */ 17 #include <sys/utsname.h> /* for aim_directim_initiate */
18 #include <arpa/inet.h> /* for inet_ntoa */ 18 #include <arpa/inet.h> /* for inet_ntoa */
19 #endif 19 #endif
20 20
21 /* XXX - I really don't think this should include gaim.h */
21 #include "gaim.h" 22 #include "gaim.h"
22 23
23 #ifdef _WIN32 24 #ifdef _WIN32
24 #include "win32dep.h" 25 #include "win32dep.h"
25 #endif 26 #endif
43 char sn[MAXSNLEN+1]; 44 char sn[MAXSNLEN+1];
44 char ip[22]; 45 char ip[22];
45 }; 46 };
46 47
47 static int listenestablish(fu16_t portnum); 48 static int listenestablish(fu16_t portnum);
48 static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr); 49 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs);
49 static const char *oft_basename(const char *name); 50 static void oft_dirconvert(char *name);
51 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh);
50 52
51 /** 53 /**
52 * aim_handlerendconnect - call this to accept OFT connections and set up the required structures 54 * aim_handlerendconnect - call this to accept OFT connections and set up the required structures
53 * @sess: the session 55 * @sess: the session
54 * @cur: the conn the incoming connection is on 56 * @cur: the conn the incoming connection is on
143 * 145 *
144 * The connection must have been previously established. 146 * The connection must have been previously established.
145 */ 147 */
146 faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing) 148 faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing)
147 { 149 {
148 150 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
149 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
150 aim_frame_t *fr; 151 aim_frame_t *fr;
151 aim_bstream_t hdrbs; /* XXX this should be within aim_frame_t */ 152 aim_bstream_t *hdrbs;
152 153 fu8_t *hdr;
153 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 154 int hdrlen = 0x44;
154 return -EINVAL; 155
156 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
157 return -EINVAL;
155 158
156 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0))) 159 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0)))
157 return -ENOMEM; 160 return -ENOMEM;
158 161 memcpy(fr->hdr.rend.magic, "ODC2", 4);
159 memcpy(fr->hdr.oft.magic, "ODC2", 4); 162 fr->hdr.rend.hdrlen = hdrlen;
160 163
161 fr->hdr.oft.hdr2len = 0x44; 164 if (!(hdr = calloc(1, hdrlen))) {
162
163 if (!(fr->hdr.oft.hdr2 = calloc(1, fr->hdr.oft.hdr2len))) {
164 aim_frame_destroy(fr); 165 aim_frame_destroy(fr);
165 return -ENOMEM; 166 return -ENOMEM;
166 } 167 }
168
169 hdrbs = &(fr->data);
170 aim_bstream_init(hdrbs, hdr, hdrlen);
171
172 aimbs_put16(hdrbs, 0x0006);
173 aimbs_put16(hdrbs, 0x0000);
174 aimbs_putraw(hdrbs, intdata->cookie, 8);
175 aimbs_put16(hdrbs, 0x0000);
176 aimbs_put16(hdrbs, 0x0000);
177 aimbs_put16(hdrbs, 0x0000);
178 aimbs_put16(hdrbs, 0x0000);
179 aimbs_put32(hdrbs, 0x00000000);
180 aimbs_put16(hdrbs, 0x0000);
181 aimbs_put16(hdrbs, 0x0000);
182 aimbs_put16(hdrbs, 0x0000);
183
184 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing */
185 aimbs_put16(hdrbs, ( typing ? 0x000e : 0x0002));
186
187 aimbs_put16(hdrbs, 0x0000);
188 aimbs_put16(hdrbs, 0x0000);
189 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
167 190
168 aim_bstream_init(&hdrbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len); 191 aim_bstream_setpos(hdrbs, 52); /* bleeehh */
169 192
170 aimbs_put16(&hdrbs, 0x0006); 193 aimbs_put8(hdrbs, 0x00);
171 aimbs_put16(&hdrbs, 0x0000); 194 aimbs_put16(hdrbs, 0x0000);
172 aimbs_putraw(&hdrbs, intdata->cookie, 8); 195 aimbs_put16(hdrbs, 0x0000);
173 aimbs_put16(&hdrbs, 0x0000); 196 aimbs_put16(hdrbs, 0x0000);
174 aimbs_put16(&hdrbs, 0x0000); 197 aimbs_put16(hdrbs, 0x0000);
175 aimbs_put16(&hdrbs, 0x0000); 198 aimbs_put16(hdrbs, 0x0000);
176 aimbs_put16(&hdrbs, 0x0000); 199 aimbs_put16(hdrbs, 0x0000);
177 aimbs_put32(&hdrbs, 0x00000000); 200 aimbs_put16(hdrbs, 0x0000);
178 aimbs_put16(&hdrbs, 0x0000); 201 aimbs_put8(hdrbs, 0x00);
179 aimbs_put16(&hdrbs, 0x0000); 202
180 aimbs_put16(&hdrbs, 0x0000); 203 /* end of hdr */
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
200 /* end of hdr2 */
201 204
202 aim_tx_enqueue(sess, fr); 205 aim_tx_enqueue(sess, fr);
203 206
204 return 0; 207 return 0;
205 } 208 }
206 209
207 /** 210 /**
208 * aim_send_im_direct - send IM client-to-client over established connection 211 * aim_send_im_direct - send IM client-to-client over established connection
209 * @sess: session to conn 212 * @sess: session to conn
210 * @conn: directim connection 213 * @conn: directim connection
211 * @msg: null-terminated string to send. 214 * @msg: null-terminated string to send.
212 * len: The length of the message to send, including binary data. 215 * @len: The length of the message to send, including binary data.
216 * @encoding: 0 for ascii, 2 for Unicode, 3 for ISO 8859-1
213 * 217 *
214 * Call this just like you would aim_send_im, to send a directim. You 218 * Call this just like you would aim_send_im, to send a directim. You
215 * _must_ have previously established the directim connection. 219 * _must_ have previously established the directim connection.
216 */ 220 */
217 faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len) 221 faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding)
218 { 222 {
219 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; 223 struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
220 aim_frame_t *fr; 224 aim_frame_t *fr;
221 aim_bstream_t hdrbs; /* XXX this should be within aim_frame_t */ 225 aim_bstream_t *hdrbs;
226 int hdrlen = 0x44;
227 fu8_t *hdr;
222 228
223 if (!sess || !conn || !msg || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 229 if (!sess || !conn || !msg || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
224 return -EINVAL; 230 return -EINVAL;
225 231
226 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, len))) 232 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, len)))
227 return -ENOMEM; 233 return -ENOMEM;
228 234
229 memcpy(fr->hdr.oft.magic, "ODC2", 4); 235 memcpy(fr->hdr.rend.magic, "ODC2", 4);
236 fr->hdr.rend.hdrlen = hdrlen;
230 237
231 fr->hdr.oft.hdr2len = 0x44; 238 if (!(hdr = calloc(1, hdrlen + len))) {
232
233 if (!(fr->hdr.oft.hdr2 = calloc(1, fr->hdr.oft.hdr2len))) {
234 aim_frame_destroy(fr); 239 aim_frame_destroy(fr);
235 return -ENOMEM; 240 return -ENOMEM;
236 } 241 }
237 242
238 aim_bstream_init(&hdrbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len); 243 hdrbs = &(fr->data);
239 244 aim_bstream_init(hdrbs, hdr, hdrlen + len);
240 aimbs_put16(&hdrbs, 0x0006); 245
241 aimbs_put16(&hdrbs, 0x0000); 246 aimbs_put16(hdrbs, 0x0006);
242 aimbs_putraw(&hdrbs, intdata->cookie, 8); 247 aimbs_put16(hdrbs, 0x0000);
243 aimbs_put16(&hdrbs, 0x0000); 248 aimbs_putraw(hdrbs, intdata->cookie, 8);
244 aimbs_put16(&hdrbs, 0x0000); 249 aimbs_put16(hdrbs, 0x0000);
245 aimbs_put16(&hdrbs, 0x0000); 250 aimbs_put16(hdrbs, 0x0000);
246 aimbs_put16(&hdrbs, 0x0000); 251 aimbs_put16(hdrbs, 0x0000);
247 aimbs_put32(&hdrbs, len); 252 aimbs_put16(hdrbs, 0x0000);
248 aimbs_put16(&hdrbs, 0x0000); 253 aimbs_put32(hdrbs, len);
249 aimbs_put16(&hdrbs, 0x0000); 254 aimbs_put16(hdrbs, encoding);
250 aimbs_put16(&hdrbs, 0x0000); 255 aimbs_put16(hdrbs, 0x0000);
256 aimbs_put16(hdrbs, 0x0000);
251 257
252 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing, 0x0000 for message */ 258 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing, 0x0000 for message */
253 aimbs_put16(&hdrbs, 0x0000); 259 aimbs_put16(hdrbs, 0x0000);
254 260
255 aimbs_put16(&hdrbs, 0x0000); 261 aimbs_put16(hdrbs, 0x0000);
256 aimbs_put16(&hdrbs, 0x0000); 262 aimbs_put16(hdrbs, 0x0000);
257 aimbs_putraw(&hdrbs, sess->sn, strlen(sess->sn)); 263 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
258 264
259 aim_bstream_setpos(&hdrbs, 52); /* bleeehh */ 265 aim_bstream_setpos(hdrbs, 52); /* bleeehh */
260 266
261 aimbs_put8(&hdrbs, 0x00); 267 aimbs_put8(hdrbs, 0x00);
262 aimbs_put16(&hdrbs, 0x0000); 268 aimbs_put16(hdrbs, 0x0000);
263 aimbs_put16(&hdrbs, 0x0000); 269 aimbs_put16(hdrbs, 0x0000);
264 aimbs_put16(&hdrbs, 0x0000); 270 aimbs_put16(hdrbs, 0x0000);
265 aimbs_put16(&hdrbs, 0x0000); 271 aimbs_put16(hdrbs, 0x0000);
266 aimbs_put16(&hdrbs, 0x0000); 272 aimbs_put16(hdrbs, 0x0000);
267 aimbs_put16(&hdrbs, 0x0000); 273 aimbs_put16(hdrbs, 0x0000);
268 aimbs_put16(&hdrbs, 0x0000); 274 aimbs_put16(hdrbs, 0x0000);
275 aimbs_put8(hdrbs, 0x00);
269 276
270 /* end of hdr2 */ 277 /* end of hdr2 */
271 278
272 #if 0 /* XXX this is how you send buddy icon info... */ 279 #if 0 /* XXX this is how you send buddy icon info... */
273 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008); 280 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008);
277 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001); 284 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001);
278 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f); 285 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f);
279 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e); 286 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e);
280 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8); 287 i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8);
281 #endif 288 #endif
282 aimbs_putraw(&fr->data, msg, len); 289 aimbs_putraw(hdrbs, msg, len);
283 290
284 aim_tx_enqueue(sess, fr); 291 aim_tx_enqueue(sess, fr);
285 292
286 return 0; 293 return 0;
287 } 294 }
389 return NULL; 396 return NULL;
390 397
391 if ((listenfd = listenestablish(port)) == -1) 398 if ((listenfd = listenestablish(port)) == -1)
392 return NULL; 399 return NULL;
393 400
394 aim_request_sendfile(sess, destsn, oft_basename(filename), 401 aim_request_sendfile(sess, destsn, filename, numfiles, totsize, localip, port, ck);
395 numfiles, totsize, localip, port, ck);
396 402
397 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); 403 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t));
398 memcpy(cookie->cookie, ck, 8); 404 memcpy(cookie->cookie, ck, 8);
399 cookie->type = AIM_COOKIETYPE_OFTSEND; 405 cookie->type = AIM_COOKIETYPE_OFTSEND;
400 memcpy(cookret, ck, 8); 406 memcpy(cookret, ck, 8);
430 436
431 #if 0 437 #if 0
432 /** 438 /**
433 * unsigned int aim_oft_listener_clean - close up old listeners 439 * unsigned int aim_oft_listener_clean - close up old listeners
434 * @sess: session to clean up in 440 * @sess: session to clean up in
435 * @age: maximum age in seconds 441 * @age: maximum age in seconds
436 * 442 *
437 * returns number closed, -1 on error. 443 * returns number closed, -1 on error.
438 */ 444 */
439 faim_export unsigned int aim_oft_listener_clean(aim_session_t *sess, 445 faim_export unsigned int aim_oft_listener_clean(aim_session_t *sess, time_t age)
440 time_t age) 446 {
441 { 447 aim_conn_t *cur;
442 aim_conn_t *cur; 448 time_t now;
443 time_t now; 449 unsigned int hit = 0;
444 unsigned int hit = 0; 450
445 451 if (!sess)
446 if (!sess) 452 return -1;
447 return -1; 453 now = time(NULL);
448 now = time(NULL); 454
449 for(cur = sess->connlist;cur; cur = cur->next) 455 for(cur = sess->connlist;cur; cur = cur->next)
450 if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { 456 if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
451 if (cur->lastactivity < (now - age) ) { 457 if (cur->lastactivity < (now - age) ) {
452 aim_conn_close(cur); 458 aim_conn_close(cur);
453 hit++; 459 hit++;
454 } 460 }
455 } 461 }
456 return hit; 462 return hit;
457 } 463 }
458 #endif 464 #endif
459 465
460 faim_export const char *aim_directim_getsn(aim_conn_t *conn) 466 faim_export const char *aim_directim_getsn(aim_conn_t *conn)
461 { 467 {
462 struct aim_directim_intdata *intdata; 468 struct aim_directim_intdata *intdata;
463 469
464 if (!conn) 470 if (!conn)
465 return NULL; 471 return NULL;
466 472
467 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || 473 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) ||
468 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) 474 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
469 return NULL; 475 return NULL;
470 476
471 if (!conn->internal) 477 if (!conn->internal)
472 return NULL; 478 return NULL;
473 479
474 intdata = (struct aim_directim_intdata *)conn->internal; 480 intdata = (struct aim_directim_intdata *)conn->internal;
523 } 529 }
524 530
525 /** 531 /**
526 * aim_directim_getconn - find a directim conn for buddy name 532 * aim_directim_getconn - find a directim conn for buddy name
527 * @sess: your session, 533 * @sess: your session,
528 * @name: the name to get, 534 * @name: the name to get,
529 * 535 *
530 * returns conn for directim with name, %NULL if none found. 536 * returns conn for directim with name, %NULL if none found.
531 * 537 *
532 */ 538 */
533 faim_export aim_conn_t *aim_directim_getconn(aim_session_t *sess, const char *name) 539 faim_export aim_conn_t *aim_directim_getconn(aim_session_t *sess, const char *name)
558 * @conn: the BOS conn for the CAP reply 564 * @conn: the BOS conn for the CAP reply
559 * @sn: the screenname to send it to, 565 * @sn: the screenname to send it to,
560 * @cookie: the cookie used 566 * @cookie: the cookie used
561 * @ip: the ip to connect to 567 * @ip: the ip to connect to
562 * @port: the port to use 568 * @port: the port to use
563 * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE) 569 * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE)
564 * 570 *
565 * @listingfiles: number of files to share 571 * @listingfiles: number of files to share
566 * @listingtotsize: total size of shared files 572 * @listingtotsize: total size of shared files
567 * @listingsize: length of the listing file(buffer) 573 * @listingsize: length of the listing file(buffer)
568 * @listingchecksum: checksum of the listing 574 * @listingchecksum: checksum of the listing
569 * 575 *
570 * Returns new connection or %NULL on error. 576 * Returns new connection or %NULL on error.
571 * 577 *
572 * XXX this should take a struct. 578 * XXX this should take a struct.
573 */ 579 */
574 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, 580 faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn,
575 aim_conn_t *conn, 581 const fu8_t *cookie, const fu8_t *ip,
576 const char *sn, const fu8_t *cookie, 582 fu16_t port, fu16_t rendid, ...)
577 const fu8_t *ip, 583 {
578 fu16_t port, 584 aim_frame_t *newpacket;
579 fu16_t rendid, 585 aim_conn_t *newconn;
580 ...) 586 struct aim_filetransfer_priv *priv;
581 { 587 int i;
582 aim_frame_t *newpacket; 588 char addr[21];
583 aim_conn_t *newconn; 589
584 struct aim_filetransfer_priv *priv; 590 if (!sess || !conn || !sn || !cookie || !ip) {
585 int i; 591 return NULL;
586 char addr[21]; 592 }
587 593
588 if (!sess || !conn || !sn || !cookie || !ip) { 594 /* OSCAR CAP accept packet */
589 return NULL; 595
590 } 596 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
591 597 return NULL;
592 /* OSCAR CAP accept packet */ 598 }
593 599
594 600 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
595 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { 601
596 return NULL; 602 for (i = 0; i < 8; i++)
597 } 603 aimbs_put8(&newpacket->data, cookie[i]);
598 604
599 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next); 605 aimbs_put16(&newpacket->data, 0x0002);
600 606 aimbs_put8(&newpacket->data, strlen(sn));
601 for (i = 0; i < 8; i++) 607 aimbs_putraw(&newpacket->data, sn, strlen(sn));
602 aimbs_put8(&newpacket->data, cookie[i]); 608 aimbs_put16(&newpacket->data, 0x0005);
603 609 aimbs_put16(&newpacket->data, 0x001a);
604 aimbs_put16(&newpacket->data, 0x0002); 610 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_ACCEPT);
605 aimbs_put8(&newpacket->data, strlen(sn)); 611
606 aimbs_putraw(&newpacket->data, sn, strlen(sn)); 612 for (i = 0; i < 8; i++) /* yes, again... */
607 aimbs_put16(&newpacket->data, 0x0005); 613 aimbs_put8(&newpacket->data, cookie[i]);
608 aimbs_put16(&newpacket->data, 0x001a); 614
609 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_ACCEPT); 615 aim_putcap(&newpacket->data, rendid);
610 616 aim_tx_enqueue(sess, newpacket);
611 for (i = 0; i < 8; i++) /* yes, again... */ 617
612 aimbs_put8(&newpacket->data, cookie[i]); 618 snprintf(addr, sizeof(addr), "%s:%d", ip, port);
613 619 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr);
614 aim_putcap(&newpacket->data, rendid); 620
615 aim_tx_enqueue(sess, newpacket); 621 if (newconn->status & AIM_CONN_STATUS_CONNERR) {
616 622 return NULL;
617 623 }
618 snprintf(addr, sizeof(addr), "%s:%d", ip, port); 624
619 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr); 625 if (!newconn || (newconn->fd == -1)) {
620 626 perror("aim_newconn");
621 if (newconn->status & AIM_CONN_STATUS_CONNERR) { 627 faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0);
622 return NULL; 628 return newconn;
623 } 629 }
624 630
625 if (!newconn || (newconn->fd == -1)) { 631 priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
626 perror("aim_newconn"); 632
627 faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0); 633 memcpy(priv->cookie, cookie, 8);
628 return newconn; 634 priv->state = 0;
629 } 635 strncpy(priv->sn, sn, MAXSNLEN);
630 636 strncpy(priv->ip, ip, sizeof(priv->ip));
631 priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)); 637 newconn->internal = (void *)priv;
632 638
633 memcpy(priv->cookie, cookie, 8); 639 faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd);
634 priv->state = 0; 640
635 strncpy(priv->sn, sn, MAXSNLEN); 641 if (rendid == AIM_CAPS_GETFILE) {
636 strncpy(priv->ip, ip, sizeof(priv->ip)); 642 return NULL; /* This should never happen for now. -- wtm */
637 newconn->internal = (void *)priv; 643
638
639 faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd);
640
641 if (rendid == AIM_CAPS_GETFILE) {
642 return NULL; /* This should never happen for now. -- wtm */
643 #if 0 644 #if 0
644 struct aim_fileheader_t *fh; 645 struct aim_fileheader_t *fh;
645 aim_frame_t *newoft; 646 aim_frame_t *newoft;
646 aim_msgcookie_t *cachedcook; 647 aim_msgcookie_t *cachedcook;
647 /* XXX take the following parameters fu16_t listingfiles, 648 /* XXX take the following parameters fu16_t listingfiles,
648 fu16_t listingtotsize, 649 fu16_t listingtotsize,
649 fu16_t listingsize, 650 fu16_t listingsize,
650 fu32_t listingchecksum, */ 651 fu32_t listingchecksum, */
651 652
652 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE; 653 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
653 654
654 faimdprintf(sess, 2, "faim: getfile request accept\n"); 655 faimdprintf(sess, 2, "faim: getfile request accept\n");
655 656
656 if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) { 657 if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) {
657 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 658 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
658 /* XXX: conn leak here */ 659 /* XXX: conn leak here */
659 return NULL; 660 return NULL;
660 } 661 }
661 662
662 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 663 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
663 newoft->hdr.oft.hdr2len = 0x100 - 8; 664 newoft->hdr.oft.hdr2len = 0x100 - 8;
664 665
665 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) { 666 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) {
666 /* XXX: conn leak here */ 667 /* XXX: conn leak here */
667 perror("calloc"); 668 perror("calloc");
668 return NULL; 669 return NULL;
669 } 670 }
670 671
671 fh->encrypt = 0x0000; 672 fh->encrypt = 0x0000;
672 fh->compress = 0x0000; 673 fh->compress = 0x0000;
673 fh->totfiles = listingfiles; 674 fh->totfiles = listingfiles;
674 fh->filesleft = listingfiles; /* is this right -- total parts and parts left?*/ 675 fh->filesleft = listingfiles; /* is this right -- total parts and parts left?*/
675 fh->totparts = 0x0001; 676 fh->totparts = 0x0001;
676 fh->partsleft = 0x0001; 677 fh->partsleft = 0x0001;
677 fh->totsize = listingtotsize; 678 fh->totsize = listingtotsize;
678 fh->size = listingsize; /* ls -l listing.txt */ 679 fh->size = listingsize; /* ls -l listing.txt */
679 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 680 fh->modtime = (int)time(NULL); /* we'll go with current time for now */
680 fh->checksum = listingchecksum; 681 fh->checksum = listingchecksum;
681 fh->rfcsum = 0x00000000; 682 fh->rfcsum = 0x00000000;
682 fh->rfsize = 0x00000000; 683 fh->rfsize = 0x00000000;
683 fh->cretime = 0x00000000; 684 fh->cretime = 0x00000000;
684 fh->rfcsum = 0x00000000; 685 fh->rfcsum = 0x00000000;
685 fh->nrecvd = 0x00000000; 686 fh->nrecvd = 0x00000000;
686 fh->recvcsum = 0x00000000; 687 fh->recvcsum = 0x00000000;
687 memset(fh->idstring, 0, sizeof(fh->idstring)); 688 memset(fh->idstring, 0, sizeof(fh->idstring));
688 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 689 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
689 fh->flags = 0x02; 690 fh->flags = 0x02;
690 fh->lnameoffset = 0x1a; 691 fh->lnameoffset = 0x1a;
691 fh->lsizeoffset = 0x10; 692 fh->lsizeoffset = 0x10;
692 memset(fh->dummy, 0, sizeof(fh->dummy)); 693 memset(fh->dummy, 0, sizeof(fh->dummy));
693 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); 694 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
694 695
695 /* we need to figure out these encodings for filenames */ 696 /* we need to figure out these encodings for filenames */
696 fh->nencode = 0x0000; 697 fh->nencode = 0x0000;
697 fh->nlanguage = 0x0000; 698 fh->nlanguage = 0x0000;
698 memset(fh->name, 0, sizeof(fh->name)); 699 memset(fh->name, 0, sizeof(fh->name));
699 strncpy(fh->name, "listing.txt", sizeof(fh->name)); 700 strncpy(fh->name, "listing.txt", sizeof(fh->name));
700 701
701 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 702 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
702 aim_frame_destroy(newoft); 703 aim_frame_destroy(newoft);
703 /* XXX: conn leak */ 704 /* XXX: conn leak */
704 perror("calloc (1)"); 705 perror("calloc (1)");
705 return NULL; 706 return NULL;
706 } 707 }
707 708
708 memcpy(fh->bcookie, cookie, 8); 709 memcpy(fh->bcookie, cookie, 8);
709 710
710 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh))) 711 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh)))
711 faimdprintf(sess, 1, "eek, bh fail!\n"); 712 faimdprintf(sess, 1, "eek, bh fail!\n");
712 713
713 aim_tx_enqueue(sess, newoft); 714 aim_tx_enqueue(sess, newoft);
714 715
715 if (!(cachedcook = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)))) { 716 if (!(cachedcook = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)))) {
716 faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n"); 717 faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n");
717 /* XXX: more cleanup, conn leak */ 718 /* XXX: more cleanup, conn leak */
718 perror("calloc (2)"); 719 perror("calloc (2)");
719 return NULL; 720 return NULL;
720 } 721 }
721 722
722 memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t)); 723 memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t));
723 memcpy(cachedcook->cookie, cookie, 8); 724 memcpy(cachedcook->cookie, cookie, 8);
724 725
725 cachedcook->type = AIM_COOKIETYPE_OFTGET; 726 cachedcook->type = AIM_COOKIETYPE_OFTGET;
726 /* XXX doesn't priv need to be copied so we don't 727 /* XXX doesn't priv need to be copied so we don't
727 * double free? -- wtm 728 * double free? -- wtm
728 */ 729 */
729 cachedcook->data = (void *)priv; 730 cachedcook->data = (void *)priv;
730 731
731 if (aim_cachecookie(sess, cachedcook) == -1) 732 if (aim_cachecookie(sess, cachedcook) == -1)
732 faimdprintf(sess, 1, "faim: ERROR caching message cookie\n"); 733 faimdprintf(sess, 1, "faim: ERROR caching message cookie\n");
733 734
734 free(fh); 735 free(fh);
735 #endif 736 #endif
736 737
737 } else if (rendid == AIM_CAPS_SENDFILE) { 738 } else if (rendid == AIM_CAPS_SENDFILE) {
738 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; 739 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
739 priv->fh.recvcsum = 0xffff0000; 740 priv->fh.recvcsum = 0xffff0000;
740 } else { 741 } else {
741 return NULL; 742 return NULL;
742 } 743 }
743 744
744 return newconn; 745 return newconn;
745 } 746 }
746 747
747 /* conn is a BOS connection over which to send the cancel msg */ 748 /* conn is a BOS connection over which to send the cancel msg */
748 faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn, 749 faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn,
749 const char *cookie, const char *sn, int rendid) 750 const char *cookie, const char *sn, int rendid)
750 { 751 {
751 aim_frame_t *newpacket; 752 aim_frame_t *newpacket;
752 int i; 753 int i;
753 754
754 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { 755 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
755 return 1; 756 return 1;
756 } 757 }
757 758
758 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next); 759 aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
759 760
760 for (i = 0; i < 8; i++) 761 for (i = 0; i < 8; i++)
761 aimbs_put8(&newpacket->data, cookie[i]); 762 aimbs_put8(&newpacket->data, cookie[i]);
762 763
763 aimbs_put16(&newpacket->data, 0x0002); 764 aimbs_put16(&newpacket->data, 0x0002);
764 aimbs_put8(&newpacket->data, strlen(sn)); 765 aimbs_put8(&newpacket->data, strlen(sn));
765 aimbs_putraw(&newpacket->data, sn, strlen(sn)); 766 aimbs_putraw(&newpacket->data, sn, strlen(sn));
766 aimbs_put16(&newpacket->data, 0x0005); 767 aimbs_put16(&newpacket->data, 0x0005);
767 aimbs_put16(&newpacket->data, 0x001a); 768 aimbs_put16(&newpacket->data, 0x001a);
768 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_CANCEL); 769 aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_CANCEL);
769 770
770 for (i = 0; i < 8; i++) 771 for (i = 0; i < 8; i++)
771 aimbs_put8(&newpacket->data, cookie[i]); 772 aimbs_put8(&newpacket->data, cookie[i]);
772 773
773 aim_putcap(&newpacket->data, rendid); 774 aim_putcap(&newpacket->data, rendid);
774 aim_tx_enqueue(sess, newpacket); 775 aim_tx_enqueue(sess, newpacket);
775 776
776 return 0; 777 return 0;
777 } 778 }
778 779
779 /** 780 /**
780 * aim_getlisting(FILE *file) -- get an aim_fileheader_t for a given FILE* 781 * aim_getlisting(FILE *file) -- get an aim_fileheader_t for a given FILE*
781 * @file is an opened listing file 782 * @file is an opened listing file
782 * 783 *
783 * returns a pointer to the filled-in fileheader_t 784 * returns a pointer to the filled-in fileheader_t
784 * 785 *
785 * Currently omits checksum. we'll fix this when AOL breaks us, i 786 * Currently omits checksum. we'll fix this when AOL breaks us, i
786 * guess. 787 * guess.
788 */ 789 */
789 faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *file) 790 faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *file)
790 { 791 {
791 return NULL; 792 return NULL;
792 #if 0 793 #if 0
793 struct aim_fileheader_t *fh; 794 struct aim_fileheader_t *fh;
794 u_long totsize = 0, size = 0, checksum = 0xffff0000; 795 u_long totsize = 0, size = 0, checksum = 0xffff0000;
795 short totfiles = 0; 796 short totfiles = 0;
796 char *linebuf, sizebuf[9]; 797 char *linebuf, sizebuf[9];
797 798 int linelength = 1024;
798 int linelength = 1024; 799
799 800 /* XXX: if we have a line longer than 1024chars, God help us. */
800 /* XXX: if we have a line longer than 1024chars, God help us. */ 801 if ((linebuf = (char *)calloc(1, linelength)) == NULL ) {
801 if ( (linebuf = (char *)calloc(1, linelength)) == NULL ) { 802 faimdprintf(sess, 2, "linebuf calloc failed\n");
802 faimdprintf(sess, 2, "linebuf calloc failed\n"); 803 return NULL;
803 return NULL; 804 }
804 } 805
805 806 if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */
806 if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */ 807 perror("getlisting END1 fseek:");
807 perror("getlisting END1 fseek:"); 808 faimdprintf(sess, 2, "getlising fseek END1 error\n");
808 faimdprintf(sess, 2, "getlising fseek END1 error\n"); 809 }
809 } 810
810 811 if ((size = ftell(file)) == -1) {
811 if ((size = ftell(file)) == -1) { 812 perror("getlisting END1 getpos:");
812 perror("getlisting END1 getpos:"); 813 faimdprintf(sess, 2, "getlising getpos END1 error\n");
813 faimdprintf(sess, 2, "getlising getpos END1 error\n"); 814 }
814 } 815
815 816 if (fseek(file, 0, SEEK_SET) != 0) {
816 if (fseek(file, 0, SEEK_SET) != 0) { 817 perror("getlesting fseek(SET):");
817 perror("getlesting fseek(SET):"); 818 faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n");
818 faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n"); 819 }
819 } 820
820 821 memset(linebuf, 0, linelength);
821 memset(linebuf, 0, linelength); 822
822 823 size = 0;
823 size = 0; 824
824 825 while(fgets(linebuf, linelength, file)) {
825 while(fgets(linebuf, linelength, file)) { 826 totfiles++;
826 totfiles++; 827 memset(sizebuf, 0, 9);
827 memset(sizebuf, 0, 9); 828
828 829 size += strlen(linebuf);
829 size += strlen(linebuf); 830
830 831 if (strlen(linebuf) < 23) {
831 if (strlen(linebuf) < 23) { 832 faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf);
832 faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf); 833 continue;
833 continue; 834 }
834 } 835
835 if (linebuf[strlen(linebuf)-1] != '\n') { 836 if (linebuf[strlen(linebuf)-1] != '\n') {
836 faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n"); 837 faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n");
837 } 838 }
838 839
839 memcpy(sizebuf, linebuf+17, 8); 840 memcpy(sizebuf, linebuf+17, 8);
840 841
841 totsize += strtol(sizebuf, NULL, 10); 842 totsize += strtol(sizebuf, NULL, 10);
842 memset(linebuf, 0, linelength); 843 memset(linebuf, 0, linelength);
843 } 844 }
844 845
845 if (fseek(file, 0, SEEK_SET) == -1) { 846 if (fseek(file, 0, SEEK_SET) == -1) {
846 perror("getlisting END2 fseek:"); 847 perror("getlisting END2 fseek:");
847 faimdprintf(sess, 2, "getlising fseek END2 error\n"); 848 faimdprintf(sess, 2, "getlising fseek END2 error\n");
848 } 849 }
849 850
850 free(linebuf); 851 free(linebuf);
851 852
852 /* we're going to ignore checksumming the data for now -- that 853 /* we're going to ignore checksumming the data for now -- that
853 * requires walking the whole listing.txt. it should probably be 854 * requires walking the whole listing.txt. it should probably be
854 * done at register time and cached, but, eh. */ 855 * done at register time and cached, but, eh. */
855 856
856 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) 857 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
857 return NULL; 858 return NULL;
858 859
859 fh->encrypt = 0x0000; 860 fh->encrypt = 0x0000;
860 fh->compress = 0x0000; 861 fh->compress = 0x0000;
861 fh->totfiles = totfiles; 862 fh->totfiles = totfiles;
862 fh->filesleft = totfiles; /* is this right ?*/ 863 fh->filesleft = totfiles; /* is this right? */
863 fh->totparts = 0x0001; 864 fh->totparts = 0x0001;
864 fh->partsleft = 0x0001; 865 fh->partsleft = 0x0001;
865 fh->totsize = totsize; 866 fh->totsize = totsize;
866 fh->size = size; /* ls -l listing.txt */ 867 fh->size = size; /* ls -l listing.txt */
867 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 868 fh->modtime = (int)time(NULL); /* we'll go with current time for now */
868 fh->checksum = checksum; /* XXX: checksum ! */ 869 fh->checksum = checksum; /* XXX: checksum ! */
869 fh->rfcsum = 0x00000000; 870 fh->rfcsum = 0x00000000;
870 fh->rfsize = 0x00000000; 871 fh->rfsize = 0x00000000;
871 fh->cretime = 0x00000000; 872 fh->cretime = 0x00000000;
872 fh->rfcsum = 0x00000000; 873 fh->rfcsum = 0x00000000;
873 fh->nrecvd = 0x00000000; 874 fh->nrecvd = 0x00000000;
874 fh->recvcsum = 0x00000000; 875 fh->recvcsum = 0x00000000;
875 876
876 /* memset(fh->idstring, 0, sizeof(fh->idstring)); */ 877 /* memset(fh->idstring, 0, sizeof(fh->idstring)); */
877 memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 878 memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
878 memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring)); 879 memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring));
879 880
880 fh->flags = 0x02; 881 fh->flags = 0x02;
881 fh->lnameoffset = 0x1a; 882 fh->lnameoffset = 0x1a;
882 fh->lsizeoffset = 0x10; 883 fh->lsizeoffset = 0x10;
883 884
884 /* memset(fh->dummy, 0, sizeof(fh->dummy)); */ 885 /* memset(fh->dummy, 0, sizeof(fh->dummy)); */
885 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); 886 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
886 887
887 fh->nencode = 0x0000; /* we need to figure out these encodings for filenames */ 888 fh->nencode = 0x0000; /* we need to figure out these encodings for filenames */
888 fh->nlanguage = 0x0000; 889 fh->nlanguage = 0x0000;
889 890
890 /* memset(fh->name, 0, sizeof(fh->name)); */ 891 /* memset(fh->name, 0, sizeof(fh->name)); */
891 strncpy(fh->name, "listing.txt", sizeof(fh->name)); 892 strncpy(fh->name, "listing.txt", sizeof(fh->name));
892 memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name)); 893 memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name));
893 894
894 faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name)))); 895 faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));
895 return fh; 896 return fh;
896 #endif 897 #endif
897 } 898 }
898 899
899 /** 900 /**
900 * aim_listenestablish - create a listening socket on a port. 901 * aim_listenestablish - create a listening socket on a port.
901 * @portnum: the port number to bind to. 902 * @portnum: the port number to bind to.
902 * 903 *
903 * you need to call accept() when it's connected. returns your fd 904 * you need to call accept() when it's connected. returns your fd
904 * 905 *
905 * XXX: give the client author the responsibility of setting up a 906 * XXX: give the client author the responsibility of setting up a
906 * listener, then we no longer have a libfaim problem with broken 907 * listener, then we no longer have a libfaim problem with broken
923 perror("getaddrinfo"); 924 perror("getaddrinfo");
924 return -1; 925 return -1;
925 } 926 }
926 ressave = res; 927 ressave = res;
927 do { 928 do {
928 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 929 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
929 if (listenfd < 0) 930 if (listenfd < 0)
930 continue; 931 continue;
931 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 932 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
932 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) 933 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
933 break; 934 break;
1144 connkill_directim(sess, conn); 1145 connkill_directim(sess, conn);
1145 1146
1146 return; 1147 return;
1147 } 1148 }
1148 1149
1149 static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1150 static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
1150 { 1151 {
1151 aim_frame_t fr; 1152 aim_frame_t fr;
1152 aim_rxcallback_t userfunc; 1153 aim_rxcallback_t userfunc;
1153 fu32_t payloadlength; 1154 fu32_t payloadlength;
1154 fu16_t flags; 1155 fu16_t flags, encoding;
1155 char *snptr = NULL; 1156 char *snptr = NULL;
1156 1157
1157 fr.conn = conn; 1158 fr.conn = conn;
1158 1159
1159 payloadlength = aimutil_get32(hdr+22); 1160 /* XXX ugly */
1160 flags = aimutil_get16(hdr+32); 1161 aim_bstream_setpos(bs, 20);
1161 snptr = (char *)hdr+38; 1162 payloadlength = aimbs_get32(bs);
1163
1164 aim_bstream_setpos(bs, 24);
1165 encoding = aimbs_get16(bs);
1166
1167 aim_bstream_setpos(bs, 30);
1168 flags = aimbs_get16(bs);
1169
1170 aim_bstream_setpos(bs, 36);
1171 /* XXX -create an aimbs_getnullstr function? */
1172 snptr = aimbs_getstr(bs, MAXSNLEN);
1162 1173
1163 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_directim: %04x / %04x / %s\n", payloadlength, flags, snptr); 1174 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_directim: %04x / %04x / %s\n", payloadlength, flags, snptr);
1164 1175
1165 if (flags == 0x000e) { 1176 if (flags & 0x0002) {
1166 int ret = 0; 1177 int ret = 0;
1167 1178
1168 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) 1179 if (flags == 0x000c) {
1169 ret = userfunc(sess, &fr, snptr, 1); 1180 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
1170 1181 ret = userfunc(sess, &fr, snptr, 1);
1171 return ret; 1182 return ret;
1172 1183 }
1173 } else if (flags == 0x0002) { 1184
1174 int ret = 0;
1175
1176 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) 1185 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
1177 ret = userfunc(sess, &fr, snptr, 0); 1186 ret = userfunc(sess, &fr, snptr, 0);
1178 1187
1179 return ret; 1188 return ret;
1180 1189
1181 } else if ((flags == 0x0000) && payloadlength) { 1190 } else if (((flags & 0x000f) == 0x0000) && payloadlength) {
1182 char *msg, *msg2; 1191 char *msg, *msg2;
1183 int ret = 0; 1192 int ret = 0;
1184 int recvd = 0; 1193 int recvd = 0;
1185 int i; 1194 int i;
1186 1195
1202 if ((userfunc=aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) 1211 if ((userfunc=aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER)))
1203 userfunc(sess, &fr, snptr, (double)recvd / payloadlength); 1212 userfunc(sess, &fr, snptr, (double)recvd / payloadlength);
1204 } 1213 }
1205 1214
1206 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) ) 1215 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) )
1207 ret = userfunc(sess, &fr, snptr, msg, payloadlength); 1216 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding);
1208 1217
1209 free(msg); 1218 free(msg);
1210 1219
1211 return ret; 1220 return ret;
1212 } 1221 }
1242 free(fh); 1251 free(fh);
1243 1252
1244 if(aim_cachecookie(sess, cook) == -1) { 1253 if(aim_cachecookie(sess, cook) == -1) {
1245 faimdprintf(sess, 1, "error caching cookie\n"); 1254 faimdprintf(sess, 1, "error caching cookie\n");
1246 return -1; 1255 return -1;
1247 } 1256 }
1248 1257
1249 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) { 1258 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) {
1250 aim_conn_close(conn); 1259 aim_conn_close(conn);
1251 return -1; 1260 return -1;
1252 } 1261 }
1282 aim_rxcallback_t userfunc; 1291 aim_rxcallback_t userfunc;
1283 1292
1284 fh = aim_oft_getfh(hdr); 1293 fh = aim_oft_getfh(hdr);
1285 1294
1286 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) 1295 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET)))
1287 faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie); 1296 faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie);
1288 1297
1289 ft = cook->data; 1298 ft = cook->data;
1290 1299
1291 if (ft->fh.size != fh->size) 1300 if (ft->fh.size != fh->size)
1292 faimdprintf(sess, 2, "hrm. ft->fh.size (%ld) != fh->size (%ld). um. using ft->fh.size\n", ft->fh.size, fh->size); 1301 faimdprintf(sess, 2, "hrm. ft->fh.size (%ld) != fh->size (%ld). um. using ft->fh.size\n", ft->fh.size, fh->size);
1451 1460
1452 /* We are receiving a file, and the buddy sent us this header describing 1461 /* We are receiving a file, and the buddy sent us this header describing
1453 * it. We send back a similar header to confirm, then we're ready to 1462 * it. We send back a similar header to confirm, then we're ready to
1454 * start reading the raw data. 1463 * start reading the raw data.
1455 */ 1464 */
1456 static int handlehdr_sendfile_sending(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1465 static int handlehdr_sendfile_sending(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
1457 { 1466 {
1458 struct aim_filetransfer_priv *ft; 1467 struct aim_filetransfer_priv *ft;
1459 struct aim_fileheader_t *fh; 1468 struct aim_fileheader_t *fh;
1460 aim_frame_t *newoft; 1469 aim_frame_t *newoft;
1461 aim_rxcallback_t userfunc; 1470 aim_rxcallback_t userfunc;
1462 1471
1463 fh = aim_oft_getfh(hdr); 1472 fh = aim_oft_getfh(bs);
1464 1473
1465 /* We receive a null cookie for the first file; we must fill 1474 /* We receive a null cookie for the first file; we must fill
1466 * it in to authenticate ourselves. -- wtm 1475 * it in to authenticate ourselves. -- wtm
1467 */ 1476 */
1468 ft = conn->internal; 1477 ft = conn->internal;
1474 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACCEPT, 0))) { 1483 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACCEPT, 0))) {
1475 faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n"); 1484 faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n");
1476 return -1; 1485 return -1;
1477 } 1486 }
1478 1487
1479 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 1488 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
1480 1489 return -1;
1481 newoft->hdr.oft.hdr2len = 0x100 - 8; 1490 }
1482 1491 memcpy(newoft->hdr.rend.magic, "OFT2", 4);
1483 if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) { 1492 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
1484 aim_frame_destroy(newoft);
1485 return -1;
1486 }
1487
1488 if (!aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2,
1489 &(ft->fh))) {
1490 return -1;
1491 }
1492 1493
1493 aim_tx_enqueue(sess, newoft); 1494 aim_tx_enqueue(sess, newoft);
1495
1496 /*
1497 * Throw away the resource fork, in case we are receiving from a Mac.
1498 */
1499 if (ft->fh.rfsize) {
1500 char *buf = malloc(ft->fh.rfsize);
1501 if (!buf)
1502 return -1;
1503 aim_recv(conn->fd, buf, ft->fh.rfsize);
1504 }
1494 1505
1495 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILEREQ)) == NULL) 1506 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILEREQ)) == NULL)
1496 return 1; 1507 return 1;
1497 1508
1498 { 1509 {
1509 1520
1510 1521
1511 /* 1522 /*
1512 * These were originally described by Josh Myer: 1523 * These were originally described by Josh Myer:
1513 * http://www.geocrawler.com/archives/3/896/2000/9/0/4291064/ 1524 * http://www.geocrawler.com/archives/3/896/2000/9/0/4291064/
1525 * XXX this doesn't actualy work yet
1514 * -- wtm 1526 * -- wtm
1515 */ 1527 */
1516 static int handlehdr_sendfile_resume(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) { 1528 static int handlehdr_sendfile_resume(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
1517 aim_frame_t *newoft; 1529 aim_frame_t *newoft;
1518 aim_msgcookie_t *cook; 1530 aim_msgcookie_t *cook;
1519 struct aim_fileheader_t *fh; 1531 struct aim_fileheader_t *fh;
1520 struct aim_filetransfer_priv *ft; 1532 struct aim_filetransfer_priv *ft;
1521 1533
1522 fh = aim_oft_getfh(hdr); 1534 fh = aim_oft_getfh(bs);
1523 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) { 1535 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
1524 free(fh); 1536 free(fh);
1525 return -1; 1537 return -1;
1526 } 1538 }
1527 ft = (struct aim_filetransfer_priv *)cook->data; 1539 ft = (struct aim_filetransfer_priv *)cook->data;
1528 1540
1529 ft->fh.nrecvd = fh->nrecvd; 1541 ft->fh.nrecvd = fh->nrecvd;
1530 ft->fh.recvcsum = fh->recvcsum; 1542 ft->fh.recvcsum = fh->recvcsum;
1531 strncpy(ft->fh.name, fh->name, sizeof(ft->fh.name)); 1543 strncpy(ft->fh.name, fh->name, sizeof(ft->fh.name));
1532 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0106, 0))) { 1544 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0106, 0))) {
1533 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 1545 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
1534 free(fh); 1546 free(fh);
1535 return -1; 1547 return -1;
1536 } 1548 }
1537 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 1549
1538 newoft->hdr.oft.hdr2len = 0x100 - 8; 1550 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
1539 1551 aim_frame_destroy(newoft);
1540 if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) { 1552 free(fh);
1541 aim_frame_destroy(newoft); 1553 return -1;
1542 return -1; 1554 }
1543 } 1555 memcpy(newoft->hdr.rend.magic, "OFT2", 4);
1544 1556 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
1545 if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) { 1557
1546 aim_frame_destroy(newoft); 1558 aim_tx_enqueue(sess, newoft);
1547 free(fh); 1559 free(fh);
1548 return -1; 1560
1549 } 1561 return 0;
1550
1551 aim_tx_enqueue(sess, newoft);
1552 free(fh);
1553
1554 return 0;
1555 } 1562 }
1556 1563
1557 /* We are sending a file, and the buddy sent us this header indicating 1564 /* We are sending a file, and the buddy sent us this header indicating
1558 * that he or she is ready for the raw data. 1565 * that he or she is ready for the raw data.
1559 */ 1566 */
1560 static int handlehdr_sendfile_recv(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) { 1567 static int handlehdr_sendfile_recv(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
1561 struct aim_fileheader_t *fh; 1568 struct aim_fileheader_t *fh;
1562 aim_msgcookie_t *cook; 1569 aim_msgcookie_t *cook;
1563 int ret = 1; 1570 int ret = 1;
1564 struct aim_filetransfer_priv *ft; 1571 struct aim_filetransfer_priv *ft;
1565 aim_rxcallback_t userfunc; 1572 aim_rxcallback_t userfunc;
1566 1573
1567 fh = aim_oft_getfh(hdr); 1574 fh = aim_oft_getfh(bs);
1568 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) { 1575 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
1569 free(fh); 1576 free(fh);
1570 return -1; 1577 return -1;
1571 } 1578 }
1572 ft = (struct aim_filetransfer_priv *)cook->data; 1579 ft = (struct aim_filetransfer_priv *)cook->data;
1611 } 1618 }
1612 1619
1613 /* We just sent the raw data of a file, and the buddy sent us back this 1620 /* We just sent the raw data of a file, and the buddy sent us back this
1614 * header indicating that the transfer is complete. 1621 * header indicating that the transfer is complete.
1615 */ 1622 */
1616 static int handlehdr_sendfile_finish(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) 1623 static int handlehdr_sendfile_finish(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
1617 { 1624 {
1618 struct aim_fileheader_t *fh; 1625 struct aim_fileheader_t *fh;
1619 aim_msgcookie_t *cook; 1626 aim_msgcookie_t *cook;
1620 aim_rxcallback_t userfunc; 1627 aim_rxcallback_t userfunc;
1621 1628
1622 fh = aim_oft_getfh(hdr); 1629 fh = aim_oft_getfh(bs);
1623 1630
1624 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) { 1631 if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
1625 free(fh); 1632 free(fh);
1626 return -1; 1633 return -1;
1627 } 1634 }
1628 1635
1650 #endif 1657 #endif
1651 1658
1652 return -1; 1659 return -1;
1653 } 1660 }
1654 1661
1655 /** 1662 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr)
1656 * aim_get_command_rendezvous - OFT equivalent of aim_get_command 1663 {
1657 * @sess: session to work on 1664 aim_conn_t *conn = fr->conn;
1658 * @conn: conn to pull data from 1665 aim_bstream_t *bs = &fr->data;
1659 *
1660 * this reads and handles data from conn->fd. currently a little rough
1661 * around the edges
1662 */
1663 faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn)
1664 {
1665 fu8_t hdrbuf1[6];
1666 fu8_t *hdr = NULL;
1667 int hdrlen, hdrtype;
1668 int ret = -1; 1666 int ret = -1;
1669
1670 1667
1671 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { 1668 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
1672 /* This should never happen. -- wtm */ 1669 /* This should never happen. -- wtm */
1673 return getcommand_getfile(sess, conn); 1670 return getcommand_getfile(sess, conn);
1674 } 1671
1675 1672 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
1676 memset(hdrbuf1, 0, sizeof(hdrbuf1)); 1673 switch(fr->hdr.rend.type) {
1677
1678 if (aim_recv(conn->fd, hdrbuf1, 6) < 6) {
1679 faimdprintf(sess, 2, "faim: rend: read error (fd: %i)\n", conn->fd);
1680 aim_conn_close(conn);
1681 return -1;
1682 }
1683
1684 hdrlen = aimutil_get16(hdrbuf1+4);
1685 hdrlen -= 6;
1686
1687 hdr = malloc(hdrlen);
1688 if (!hdr) {
1689 aim_conn_close(conn);
1690 return -1;
1691 }
1692
1693 if (aim_recv(conn->fd, hdr, hdrlen) < hdrlen) {
1694 faimdprintf(sess, 2, "faim: rend: read2 error on %d (%d)\n", conn->fd, hdrlen);
1695 free(hdr);
1696 aim_conn_close(conn);
1697 return -1;
1698 }
1699
1700 hdrtype = aimutil_get16(hdr);
1701
1702 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
1703 switch(hdrtype) {
1704 case AIM_OFT_PROTO_OFFER: 1674 case AIM_OFT_PROTO_OFFER:
1705 ret = handlehdr_sendfile_sending(sess, conn, 1675 ret = handlehdr_sendfile_sending(sess, conn, bs);
1706 hdr);
1707 break; 1676 break;
1708 case AIM_OFT_PROTO_RESUME: 1677 case AIM_OFT_PROTO_RESUME:
1709 ret = handlehdr_sendfile_resume(sess, 1678 ret = handlehdr_sendfile_resume(sess, conn, bs);
1710 conn, hdr);
1711 break; 1679 break;
1712 case AIM_OFT_PROTO_RESUMEACCEPT: /* like _ACCEPT */; 1680 case AIM_OFT_PROTO_RESUMEACCEPT: /* like _ACCEPT */;
1713 case AIM_OFT_PROTO_ACCEPT: 1681 case AIM_OFT_PROTO_ACCEPT:
1714 ret = handlehdr_sendfile_recv(sess, conn, hdr); 1682 ret = handlehdr_sendfile_recv(sess, conn, bs);
1715 break; 1683 break;
1716 case AIM_OFT_PROTO_ACK: 1684 case AIM_OFT_PROTO_ACK:
1717 ret = handlehdr_sendfile_finish(sess, conn, hdr); 1685 ret = handlehdr_sendfile_finish(sess, conn, bs);
1718 break; 1686 break;
1719 default: 1687 default:
1720 faimdprintf(sess, 2, "faim: OFT frame: uknown type %04x\n", hdrtype); 1688 faimdprintf(sess, 2, "faim: OFT frame: uknown type %04x\n", fr->hdr.rend.type);
1721 ret = -1; 1689 ret = -1;
1722 break; 1690 break;
1723 } 1691 }
1724 free(hdr); 1692
1725 if (ret == -1) 1693 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
1726 aim_conn_close(conn); 1694 if (fr->hdr.rend.type == 0x0001)
1727 return ret; 1695 ret = handlehdr_directim(sess, conn, bs);
1728 } 1696 else
1729 1697 faimdprintf(sess, 0, "faim: DIM frame: unknown type %04x\n", fr->hdr.rend.type);
1730 if (hdrtype == 0x0001) 1698
1731 ret = handlehdr_directim(sess, conn, hdr); 1699 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
1732 1700 /* This _really_ shouldn't happen. :) -- wtm */
1733 /* This _really_ shouldn't happen. :) -- wtm */ 1701 char *hdr = NULL;
1734 1702 int hdrtype = fr->hdr.rend.type;
1735 else if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */ 1703 if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */
1736 ret = handlehdr_getfile_listing(sess, conn, hdr); 1704 ret = handlehdr_getfile_listing(sess, conn, hdr);
1737 else if (hdrtype == 0x1209) /* get file listing ack rx->tx */ 1705 else if (hdrtype == 0x1209) /* get file listing ack rx->tx */
1738 ret = handlehdr_getfile_listing2(sess, conn, hdr); 1706 ret = handlehdr_getfile_listing2(sess, conn, hdr);
1739 else if (hdrtype == 0x120b) /* get file listing rx confirm */ 1707 else if (hdrtype == 0x120b) /* get file listing rx confirm */
1740 ret = handlehdr_getfile_listing3(sess, conn, hdr); 1708 ret = handlehdr_getfile_listing3(sess, conn, hdr);
1741 else if (hdrtype == 0x120c) /* getfile request */ 1709 else if (hdrtype == 0x120c) /* getfile request */
1742 ret = handlehdr_getfile_request(sess, conn, hdr); 1710 ret = handlehdr_getfile_request(sess, conn, hdr);
1743 else if (hdrtype == 0x0101) /* getfile sending data */ 1711 else if (hdrtype == 0x0101) /* getfile sending data */
1744 ret = handlehdr_getfile_sending(sess, conn, hdr); 1712 ret = handlehdr_getfile_sending(sess, conn, hdr);
1745 else if (hdrtype == 0x0202) /* getfile recv data */ 1713 else if (hdrtype == 0x0202) /* getfile recv data */
1746 ret = handlehdr_getfile_recv(sess, conn, hdr); 1714 ret = handlehdr_getfile_recv(sess, conn, hdr);
1747 else if (hdrtype == 0x0204) /* getfile finished */ 1715 else if (hdrtype == 0x0204) /* getfile finished */
1748 ret = handlehdr_getfile_finish(sess, conn, hdr); 1716 ret = handlehdr_getfile_finish(sess, conn, hdr);
1749 else { 1717 else {
1750 faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype); 1718 faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype);
1751 ret = -1; 1719 ret = -1;
1720 }
1752 } 1721 }
1753 1722
1754 free(hdr);
1755
1756 if (ret == -1) 1723 if (ret == -1)
1757 aim_conn_close(conn); 1724 aim_conn_close(conn);
1758 1725
1759 return ret; 1726 return ret;
1760 } 1727 }
1761 1728
1762 /** 1729 /**
1763 * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr. 1730 * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr.
1764 * @hdr: buffer to extract header from 1731 * @bs: bstream to extract header from
1765 * 1732 *
1766 * returns pointer to new struct on success; %NULL on error. 1733 * returns pointer to new struct on success; %NULL on error.
1767 * 1734 *
1768 */ 1735 */
1769 static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr) 1736 static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs)
1770 { 1737 {
1771 struct aim_fileheader_t *fh; 1738 struct aim_fileheader_t *fh;
1772 int i, j; 1739
1773 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t)))) 1740 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t))))
1774 return NULL; 1741 return NULL;
1775 1742
1776 /* [0] and [1] are the type. we can ignore those here. */ 1743 /* The bstream should be positioned after the hdrtype. */
1777 i = 2; 1744 aimbs_getrawbuf(bs, fh->bcookie, 8);
1778 for(j = 0; j < 8; j++, i++) 1745 fh->encrypt = aimbs_get16(bs);
1779 fh->bcookie[j] = hdr[i]; 1746 fh->compress = aimbs_get16(bs);
1780 fh->encrypt = aimutil_get16(hdr+i); 1747 fh->totfiles = aimbs_get16(bs);
1781 i += 2; 1748 fh->filesleft = aimbs_get16(bs);
1782 fh->compress = aimutil_get16(hdr+i); 1749 fh->totparts = aimbs_get16(bs);
1783 i += 2; 1750 fh->partsleft = aimbs_get16(bs);
1784 fh->totfiles = aimutil_get16(hdr+i); 1751 fh->totsize = aimbs_get32(bs);
1785 i += 2; 1752 fh->size = aimbs_get32(bs);
1786 fh->filesleft = aimutil_get16(hdr+i); 1753 fh->modtime = aimbs_get32(bs);
1787 i += 2; 1754 fh->checksum = aimbs_get32(bs);
1788 fh->totparts = aimutil_get16(hdr+i); 1755 fh->rfrcsum = aimbs_get32(bs);
1789 i += 2; 1756 fh->rfsize = aimbs_get32(bs);
1790 fh->partsleft = aimutil_get16(hdr+i); 1757 fh->cretime = aimbs_get16(bs);
1791 i += 2; 1758 fh->rfcsum = aimbs_get16(bs);
1792 fh->totsize = aimutil_get32(hdr+i); 1759 fh->nrecvd = aimbs_get16(bs);
1793 i += 4; 1760 fh->recvcsum = aimbs_get16(bs);
1794 fh->size = aimutil_get32(hdr+i); 1761 aimbs_getrawbuf(bs, fh->idstring, 32);
1795 i += 4; 1762 fh->flags = aimbs_get8(bs);
1796 fh->modtime = aimutil_get32(hdr+i); 1763 fh->lnameoffset = aimbs_get8(bs);
1797 i += 4; 1764 fh->lsizeoffset = aimbs_get8(bs);
1798 fh->checksum = aimutil_get32(hdr+i); 1765 aimbs_getrawbuf(bs, fh->dummy, 69);
1799 i += 4; 1766 aimbs_getrawbuf(bs, fh->macfileinfo, 16);
1800 fh->rfrcsum = aimutil_get32(hdr+i); 1767 fh->nencode = aimbs_get16(bs);
1801 i += 4; 1768 fh->nlanguage = aimbs_get16(bs);
1802 fh->rfsize = aimutil_get32(hdr+i); 1769 aimbs_getrawbuf(bs, fh->name, 64); /* XXX */
1803 i += 4; 1770
1804 fh->cretime = aimutil_get32(hdr+i); 1771 return fh;
1805 i += 4;
1806 fh->rfcsum = aimutil_get32(hdr+i);
1807 i += 4;
1808 fh->nrecvd = aimutil_get32(hdr+i);
1809 i += 4;
1810 fh->recvcsum = aimutil_get32(hdr+i);
1811 i += 4;
1812 memcpy(fh->idstring, hdr+i, 32);
1813 i += 32;
1814 fh->flags = aimutil_get8(hdr+i);
1815 i += 1;
1816 fh->lnameoffset = aimutil_get8(hdr+i);
1817 i += 1;
1818 fh->lsizeoffset = aimutil_get8(hdr+i);
1819 i += 1;
1820 memcpy(fh->dummy, hdr+i, 69);
1821 i += 69;
1822 memcpy(fh->macfileinfo, hdr+i, 16);
1823 i += 16;
1824 fh->nencode = aimutil_get16(hdr+i);
1825 i += 2;
1826 fh->nlanguage = aimutil_get16(hdr+i);
1827 i += 2;
1828 memcpy(fh->name, hdr+i, 64);
1829 i += 64;
1830 return fh;
1831 } 1772 }
1832 1773
1833 /** 1774 /**
1834 * aim_oft_checksum - calculate oft checksum of buffer 1775 * aim_oft_checksum - calculate oft checksum of buffer
1835 * @buffer: buffer of data to checksum 1776 * @buffer: buffer of data to checksum
1842 * thought we didn't care about you and your pathetic client's meomry 1783 * thought we didn't care about you and your pathetic client's meomry
1843 * footprint ;^) 1784 * footprint ;^)
1844 * 1785 *
1845 * Thanks to Graham Booker for providing this improved checksum 1786 * Thanks to Graham Booker for providing this improved checksum
1846 * routine, which is simpler and should be more accurate than Josh 1787 * routine, which is simpler and should be more accurate than Josh
1847 * Meyer's original code. -- wtm 1788 * Myer's original code. -- wtm
1848 * 1789 *
1849 * This algorithim works every time I have tried it. The other fails 1790 * This algorithim works every time I have tried it. The other fails
1850 * sometimes. So, AOL who thought this up? It has got to be the weirdest 1791 * sometimes. So, AOL who thought this up? It has got to be the weirdest
1851 * checksum I have ever seen. 1792 * checksum I have ever seen.
1852 */ 1793 */
1853 faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, int prevcheck) { 1794 faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, int prevcheck) {
1854 fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck; 1795 fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck;
1855 int i; 1796 int i;
1856 unsigned short val; 1797 unsigned short val;
1857 1798
1858 for(i=0;i<bufferlen;i++){ 1799 for (i=0; i<bufferlen; i++) {
1859 oldcheck = check; 1800 oldcheck = check;
1860 if(i&1){ 1801 if (i&1) {
1861 val = buffer[i]; 1802 val = buffer[i];
1862 } else { 1803 } else {
1863 val = buffer[i] << 8; 1804 val = buffer[i] << 8;
1864 } 1805 }
1865 check -= val; 1806 check -= val;
1866 /* The follownig appears to be necessary.... It happens every once in a while and the checksum doesn't fail. */ 1807 /* The follownig appears to be necessary.... It happens every once in a while and the checksum doesn't fail. */
1867 if(check > oldcheck) { 1808 if (check > oldcheck) {
1868 check--; 1809 check--;
1869 } 1810 }
1870 } 1811 }
1871 check = ((check & 0x0000ffff) + (check >> 16)); 1812 check = ((check & 0x0000ffff) + (check >> 16));
1872 check = ((check & 0x0000ffff) + (check >> 16)); 1813 check = ((check & 0x0000ffff) + (check >> 16));
1873 return check << 16; 1814 return check << 16;
1874 } 1815 }
1875 1816
1876 faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn, 1817 faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn,
1877 const unsigned char *buffer, int len) { 1818 const unsigned char *buffer, int len) {
1878 struct aim_filetransfer_priv *ft = conn->internal; 1819 struct aim_filetransfer_priv *ft = conn->internal;
1883 return 0; 1824 return 0;
1884 } 1825 }
1885 1826
1886 /** 1827 /**
1887 * aim_oft_buildheader - fills a buffer with network-order fh data 1828 * aim_oft_buildheader - fills a buffer with network-order fh data
1888 * @dest: buffer to fill -- pre-alloced 1829 * @bs: bstream to fill -- automatically initialized
1889 * @fh: fh to get data from 1830 * @fh: fh to get data from
1890 * 1831 *
1891 * returns length written; -1 on error. 1832 * returns -1 on error.
1892 * DOES NOT DO BOUNDS CHECKING! 1833 *
1893 * 1834 */
1894 */ 1835 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh)
1895 faim_export int aim_oft_buildheader(unsigned char *dest, struct aim_fileheader_t *fh)
1896 { 1836 {
1897 int i, curbyte; 1837 fu8_t *hdr;
1898 if (!dest || !fh) 1838
1899 return -1; 1839 if (!bs || !fh)
1900 curbyte = 0; 1840 return -1;
1901 for(i = 0; i < 8; i++) 1841
1902 curbyte += aimutil_put8(dest+curbyte, fh->bcookie[i]); 1842
1903 curbyte += aimutil_put16(dest+curbyte, fh->encrypt); 1843
1904 curbyte += aimutil_put16(dest+curbyte, fh->compress); 1844
1905 curbyte += aimutil_put16(dest+curbyte, fh->totfiles); 1845 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) {
1906 curbyte += aimutil_put16(dest+curbyte, fh->filesleft); 1846 return -1;
1907 curbyte += aimutil_put16(dest+curbyte, fh->totparts); 1847 }
1908 curbyte += aimutil_put16(dest+curbyte, fh->partsleft); 1848 aim_bstream_init(bs, hdr, 0x100 - 8);
1909 curbyte += aimutil_put32(dest+curbyte, fh->totsize); 1849
1910 curbyte += aimutil_put32(dest+curbyte, fh->size); 1850 aimbs_putraw(bs, fh->bcookie, 8);
1911 curbyte += aimutil_put32(dest+curbyte, fh->modtime); 1851 aimbs_put16(bs, fh->encrypt);
1912 curbyte += aimutil_put32(dest+curbyte, fh->checksum); 1852 aimbs_put16(bs, fh->compress);
1913 curbyte += aimutil_put32(dest+curbyte, fh->rfrcsum); 1853 aimbs_put16(bs, fh->totfiles);
1914 curbyte += aimutil_put32(dest+curbyte, fh->rfsize); 1854 aimbs_put16(bs, fh->filesleft);
1915 curbyte += aimutil_put32(dest+curbyte, fh->cretime); 1855 aimbs_put16(bs, fh->totparts);
1916 curbyte += aimutil_put32(dest+curbyte, fh->rfcsum); 1856 aimbs_put16(bs, fh->partsleft);
1917 curbyte += aimutil_put32(dest+curbyte, fh->nrecvd); 1857 aimbs_put32(bs, fh->totsize);
1918 curbyte += aimutil_put32(dest+curbyte, fh->recvcsum); 1858 aimbs_put32(bs, fh->size);
1919 memcpy(dest+curbyte, fh->idstring, 32); 1859 aimbs_put32(bs, fh->modtime);
1920 curbyte += 32; 1860 aimbs_put32(bs, fh->checksum);
1921 curbyte += aimutil_put8(dest+curbyte, fh->flags); 1861 aimbs_put32(bs, fh->rfrcsum);
1922 curbyte += aimutil_put8(dest+curbyte, fh->lnameoffset); 1862 aimbs_put32(bs, fh->rfsize);
1923 curbyte += aimutil_put8(dest+curbyte, fh->lsizeoffset); 1863 aimbs_put32(bs, fh->cretime);
1924 memcpy(dest+curbyte, fh->dummy, 69); 1864 aimbs_put32(bs, fh->rfcsum);
1925 curbyte += 69; 1865 aimbs_put32(bs, fh->nrecvd);
1926 memcpy(dest+curbyte, fh->macfileinfo, 16); 1866 aimbs_put32(bs, fh->recvcsum);
1927 curbyte += 16; 1867 aimbs_putraw(bs, fh->idstring, 32);
1928 curbyte += aimutil_put16(dest+curbyte, fh->nencode); 1868 aimbs_put8(bs, fh->flags);
1929 curbyte += aimutil_put16(dest+curbyte, fh->nlanguage); 1869 aimbs_put8(bs, fh->lnameoffset);
1930 memset(dest+curbyte, 0x00, 64); 1870 aimbs_put8(bs, fh->lsizeoffset);
1931 memcpy(dest+curbyte, fh->name, 64); 1871 aimbs_putraw(bs, fh->dummy, 69);
1932 1872 aimbs_putraw(bs, fh->macfileinfo, 16);
1933 /* XXX: Filenames longer than 64B */ 1873 aimbs_put16(bs, fh->nencode);
1934 curbyte += 64; 1874 aimbs_put16(bs, fh->nlanguage);
1935 return curbyte; 1875 aimbs_putraw(bs, fh->name, 64);
1876
1877 /* XXX: Filenames longer than 64B */
1878 return 0;
1936 } 1879 }
1937 1880
1938 /** 1881 /**
1939 * aim_getfile_intitiate - Request an OFT getfile session 1882 * aim_getfile_intitiate - Request an OFT getfile session
1940 * @sess: your session, 1883 * @sess: your session,
1945 */ 1888 */
1946 faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn) 1889 faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn)
1947 { 1890 {
1948 return NULL; 1891 return NULL;
1949 #if 0 1892 #if 0
1950 struct command_tx_struct *newpacket; 1893 struct command_tx_struct *newpacket;
1951 struct aim_conn_t *newconn; 1894 struct aim_conn_t *newconn;
1952 struct aim_filetransfer_priv *priv; 1895 struct aim_filetransfer_priv *priv;
1953 struct aim_msgcookie_t *cookie; 1896 struct aim_msgcookie_t *cookie;
1954 int curbyte, i, listenfd; 1897 int curbyte, i, listenfd;
1955 short port = 4443; 1898 short port = 4443;
1956 struct hostent *hptr; 1899 struct hostent *hptr;
1957 struct utsname myname; 1900 struct utsname myname;
1958 char cap[16]; 1901 char cap[16];
1959 char d[4]; 1902 char d[4];
1903
1904 /* Open our socket */
1905
1906 if ( (listenfd = aim_listenestablish(port)) == -1)
1907 return NULL;
1908
1909 /* get our local IP */
1910
1911 if (uname(&myname) < 0)
1912 return NULL;
1913 if ( (hptr = gethostbyname(myname.nodename)) == NULL)
1914 return NULL;
1915 memcpy(&d, hptr->h_addr_list[0], 4);
1916
1917 aim_putcap(cap, 16, AIM_CAPS_GETFILE);
1918
1919 /* create the OSCAR packet */
1920
1921 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42)))
1922 return NULL;
1923 newpacket->lock = 1;
1924
1925 /* lock struct */
1926 curbyte = 0;
1927 curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
1928
1929 /* XXX: check the cookie before commiting to using it */
1930
1931 /* Generate a random message cookie
1932 * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */
1933 for (i=0; i<7; i++)
1934 curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10));
1935
1936 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1937
1938 /* grab all the data for cookie caching. */
1960 1939
1961 /* Open our socket */ 1940 if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t))))
1962 1941 return NULL;
1963 if ( (listenfd = aim_listenestablish(port)) == -1) 1942 memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
1964 return NULL; 1943 cookie->type = AIM_COOKIETYPE_OFTGET;
1965 1944
1966 /* get our local IP */ 1945 if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv))))
1967 1946 return NULL;
1968 if (uname(&myname) < 0) 1947 memcpy(priv->cookie, cookie, 8);
1969 return NULL; 1948 memcpy(priv->sn, destsn, sizeof(priv->sn));
1970 if ( (hptr = gethostbyname(myname.nodename)) == NULL) 1949 memcpy(priv->fh.name, "listing.txt", strlen("listing.txt"));
1971 return NULL; 1950 priv->state = 1;
1972 memcpy(&d, hptr->h_addr_list[0], 4); 1951
1973 1952 cookie->data = priv;
1974 aim_putcap(cap, 16, AIM_CAPS_GETFILE); 1953
1975 1954 aim_cachecookie(sess, cookie);
1976 /* create the OSCAR packet */ 1955
1977 1956 /* Channel ID */
1978 if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42))) 1957 curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
1979 return NULL; 1958
1980 newpacket->lock = 1; 1959 /* Destination SN (prepended with byte length) */
1981 1960 curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
1982 /* lock struct */ 1961 curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
1983 curbyte = 0; 1962 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1984 curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid); 1963 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
1985 1964
1986 /* XXX: check the cookie before commiting to using it */ 1965 /* enTLV start */
1987 1966 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1988 /* Generate a random message cookie 1967 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042);
1989 * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */ 1968
1990 for (i=0; i<7; i++) 1969 /* Flag data / ICBM Parameters? */
1991 curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10)); 1970 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1992 1971 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
1993 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 1972
1994 1973 /* Cookie */
1995 /* grab all the data for cookie caching. */ 1974 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
1975
1976 /* Capability String */
1977 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
1978
1979 /* 000a/0002 : 0001 */
1980 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
1981 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
1982 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
1983
1984 /* 0003/0004: IP address */
1985 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
1986 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
1987 for (i = 0; i < 4; i++)
1988 curbyte += aimutil_put8(newpacket->data+curbyte, d[i]);
1989
1990 /* already in network byte order */
1996 1991
1997 if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t)))) 1992 /* 0005/0002: Port */
1998 return NULL; 1993 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
1999 memcpy(cookie->cookie, newpacket->data+curbyte-8, 8); 1994 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
2000 cookie->type = AIM_COOKIETYPE_OFTGET; 1995 curbyte += aimutil_put16(newpacket->data+curbyte, port);
2001 1996
2002 if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv)))) 1997 /* 000f/0000: ?? */
2003 return NULL; 1998 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
2004 memcpy(priv->cookie, cookie, 8); 1999 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
2005 memcpy(priv->sn, destsn, sizeof(priv->sn)); 2000
2006 memcpy(priv->fh.name, "listing.txt", strlen("listing.txt")); 2001 /* 2711/000c: ?? */
2007 priv->state = 1; 2002 curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711);
2008 2003 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c);
2009 cookie->data = priv; 2004 curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001);
2010 2005
2011 aim_cachecookie(sess, cookie); 2006 for (i = 0; i < 0x000c - 4; i++)
2012 2007 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
2013 /* Channel ID */ 2008
2014 curbyte += aimutil_put16(newpacket->data+curbyte,0x0002); 2009 newpacket->commandlen = curbyte;
2015 2010 newpacket->lock = 0;
2016 /* Destination SN (prepended with byte length) */ 2011 aim_tx_enqueue(sess, newpacket);
2017 curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn)); 2012
2018 curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn)); 2013 /* allocate and set up our connection */
2019 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); 2014
2020 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); 2015 i = fcntl(listenfd, F_GETFL, 0);
2021 2016 fcntl(listenfd, F_SETFL, i | O_NONBLOCK);
2022 /* enTLV start */ 2017 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
2023 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); 2018
2024 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042); 2019 if (!newconn){
2025 2020 perror("aim_newconn");
2026 /* Flag data / ICBM Parameters? */ 2021 return NULL;
2027 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 2022 }
2028 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); 2023
2029 2024 newconn->fd = listenfd;
2030 /* Cookie */ 2025 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
2031 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8); 2026 newconn->internal = priv;
2032 2027 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
2033 /* Capability String */ 2028
2034 curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10); 2029 return newconn;
2035
2036 /* 000a/0002 : 0001 */
2037 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
2038 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
2039 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
2040
2041 /* 0003/0004: IP address */
2042 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
2043 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
2044 for(i = 0; i < 4; i++)
2045 curbyte += aimutil_put8(newpacket->data+curbyte, d[i]);
2046
2047 /* already in network byte order */
2048
2049 /* 0005/0002: Port */
2050 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
2051 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
2052 curbyte += aimutil_put16(newpacket->data+curbyte, port);
2053
2054 /* 000f/0000: ?? */
2055 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
2056 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
2057
2058 /* 2711/000c: ?? */
2059 curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711);
2060 curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c);
2061 curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001);
2062
2063 for(i = 0; i < 0x000c - 4; i++)
2064 curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
2065
2066 newpacket->commandlen = curbyte;
2067 newpacket->lock = 0;
2068 aim_tx_enqueue(sess, newpacket);
2069
2070 /* allocate and set up our connection */
2071
2072 i = fcntl(listenfd, F_GETFL, 0);
2073 fcntl(listenfd, F_SETFL, i | O_NONBLOCK);
2074 newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
2075
2076 if (!newconn){
2077 perror("aim_newconn");
2078 return NULL;
2079 }
2080
2081 newconn->fd = listenfd;
2082 newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
2083 newconn->internal = priv;
2084 faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
2085
2086 return newconn;
2087 #endif 2030 #endif
2088 } 2031 }
2089 2032
2090 /** 2033 /**
2091 * aim_oft_getfile_request - request a particular file over an established getfile connection 2034 * aim_oft_getfile_request - request a particular file over an established getfile connection
2098 * returns -1 on error, 0 on successful enqueuing 2041 * returns -1 on error, 0 on successful enqueuing
2099 */ 2042 */
2100 #if 0 2043 #if 0
2101 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size) 2044 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size)
2102 { 2045 {
2103 aim_frame_t *newoft; 2046 aim_frame_t *newoft;
2104 struct aim_filetransfer_priv *ft; 2047 struct aim_filetransfer_priv *ft;
2105 if (!sess || !conn || !conn->priv || !name) 2048 if (!sess || !conn || !conn->priv || !name)
2106 return -1; 2049 return -1;
2107 2050
2108 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) { 2051 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) {
2109 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2052 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2110 return -1; 2053 return -1;
2111 } 2054 }
2112 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 2055 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
2113 newoft->hdr.oft.hdr2len = 0x100 - 8; 2056 newoft->hdr.oft.hdr2len = 0x100 - 8;
2114 2057
2115 ft = (struct aim_filetransfer_priv *)conn->priv; 2058 ft = (struct aim_filetransfer_priv *)conn->priv;
2116 ft->fh.filesleft = 1; 2059 ft->fh.filesleft = 1;
2117 ft->fh.totfiles = 1; 2060 ft->fh.totfiles = 1;
2118 ft->fh.totparts = 1; 2061 ft->fh.totparts = 1;
2119 ft->fh.partsleft = 1; 2062 ft->fh.partsleft = 1;
2120 ft->fh.totsize = size; 2063 ft->fh.totsize = size;
2121 ft->fh.size = size; 2064 ft->fh.size = size;
2122 ft->fh.checksum = 0; 2065 ft->fh.checksum = 0;
2123 memcpy(ft->fh.name, name, strlen(name)); 2066 memcpy(ft->fh.name, name, strlen(name));
2124 memset(ft->fh.name+strlen(name), 0, 1); 2067 memset(ft->fh.name+strlen(name), 0, 1);
2125 2068
2126 if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) { 2069 if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) {
2127 aim_frame_destroy(newoft); 2070 aim_frame_destroy(newoft);
2128 return -1; 2071 return -1;
2129 } 2072 }
2130 2073
2131 if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) { 2074 if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) {
2132 aim_frame_destroy(newoft); 2075 aim_frame_destroy(newoft);
2133 return -1; 2076 return -1;
2134 } 2077 }
2135 2078
2136 aim_tx_enqueue(sess, newoft); 2079 aim_tx_enqueue(sess, newoft);
2137 return 0; 2080 return 0;
2138 } 2081 }
2139 #endif 2082 #endif
2140 2083
2141 /* Identify a file that we are about to send by transmitting the 2084 /* Identify a file that we are about to send by transmitting the
2142 * appropriate header. 2085 * appropriate header.
2143 */ 2086 */
2144 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) 2087 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)
2145 { 2088 {
2146 aim_frame_t *newoft; 2089 aim_frame_t *newoft;
2147 aim_msgcookie_t *cook; 2090 aim_msgcookie_t *cook;
2148 struct aim_filetransfer_priv *ft = (struct aim_filetransfer_priv *)conn->internal; 2091 struct aim_filetransfer_priv *ft = (struct aim_filetransfer_priv *)conn->internal;
2149 struct aim_fileheader_t *fh; 2092 struct aim_fileheader_t *fh;
2150 2093
2151 if (!sess || !conn || !filename) 2094 if (!sess || !conn || !filename)
2152 return -1; 2095 return -1;
2153 2096
2154 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) 2097 if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
2155 return -1; 2098 return -1;
2156 2099
2157 #ifdef DUMB_OFT_CHECKSUM 2100 #ifdef DUMB_OFT_CHECKSUM
2158 /* Yes, we are supposed to checksum the whole file before sending, and 2101 /* Yes, we are supposed to checksum the whole file before sending, and
2159 * yes, it's dumb. This is the only way to get some clients (such as 2102 * yes, it's dumb. This is the only way to get some clients (such as
2160 * Mac AIM v4.5.163) to successfully complete the transfer. With 2103 * Mac AIM v4.5.163) to successfully complete the transfer. With
2161 * the WinAIM clients, we seem to be able to get away with just 2104 * the WinAIM clients, we seem to be able to get away with just
2162 * setting the checksum to zero. 2105 * setting the checksum to zero.
2163 * -- wtm 2106 * -- wtm
2164 */ 2107 */
2165 { 2108 {
2166 int fd = open(filename, O_RDONLY); 2109 int fd = open(filename, O_RDONLY);
2167 if (fd >= 0) { 2110 if (fd >= 0) {
2168 int bytes; 2111 int bytes;
2169 char buf[1024]; 2112 char buf[1024];
2170 fh->checksum = 0xffff0000; 2113 fh->checksum = 0xffff0000;
2171 while ((bytes = read(fd, buf, 1024)) > 0) { 2114 while ((bytes = aim_recv(fd, buf, 1024)) > 0) {
2172 fh->checksum = aim_oft_checksum(buf, bytes, fh->checksum); 2115 fh->checksum = aim_oft_checksum(buf, bytes, fh->checksum);
2173 } 2116 }
2174 } 2117 }
2175 close(fd); 2118 close(fd);
2176 } 2119 }
2177 #else 2120 #else
2178 fh->checksum = 0x00000000; 2121 fh->checksum = 0x00000000;
2179 #endif 2122 #endif
2180 2123 fh->encrypt = 0x0000;
2181 fh->encrypt = 0x0000; 2124 fh->compress = 0x0000;
2182 fh->compress = 0x0000; 2125 fh->totfiles = numfiles;
2183 fh->totfiles = numfiles; 2126 fh->filesleft = numfiles - filesdone;
2184 fh->filesleft = numfiles - filesdone; 2127 fh->totparts = 0x0001;
2185 fh->totparts = 0x0001; 2128 fh->partsleft = 0x0001;
2186 fh->partsleft = 0x0001; 2129 fh->totsize = totsize; /* set to 0x0002 sending Mac resource forks */
2187 fh->totsize = totsize; 2130 fh->size = size;
2188 fh->size = size; 2131 fh->modtime = (int)time(NULL); /* we'll go with current time for now */
2189 fh->modtime = (int)time(NULL); /* we'll go with current time for now */ 2132 /* fh->checksum set above */
2190 /* fh->checksum set above */ 2133 fh->rfcsum = 0x00000000;
2191 fh->rfcsum = 0x00000000; 2134 fh->rfsize = 0x00000000;
2192 fh->rfsize = 0x00000000; 2135 fh->cretime = 0x00000000;
2193 fh->cretime = 0x00000000; 2136 fh->rfcsum = 0x00000000;
2194 fh->rfcsum = 0x00000000; 2137 fh->nrecvd = 0x00000000; /* always zero initially */
2195 fh->nrecvd = 0x00000000; /* always zero initially */ 2138 fh->recvcsum= 0x00000000; /* ditto */
2196 fh->recvcsum = 0x00000000; /* ditto */ 2139
2197 2140 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
2198 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); 2141 fh->flags = 0x02;
2199 fh->flags = 0x02; 2142 fh->lnameoffset = 0x1a;
2200 fh->lnameoffset = 0x1a; 2143 fh->lsizeoffset = 0x10;
2201 fh->lsizeoffset = 0x10; 2144 memset(fh->dummy, 0, sizeof(fh->dummy));
2202 memset(fh->dummy, 0, sizeof(fh->dummy)); 2145 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
2203 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); 2146
2204 2147 /* apparently 0 is ASCII, 2 is UCS-2 */
2205 /* we need to figure out these encodings for filenames */ 2148 /* it is likely that 3 is ISO 8859-1 */
2206 fh->nencode = 0x0000; 2149 fh->nencode = 0x0000;
2207 fh->nlanguage = 0x0000; 2150 fh->nlanguage = 0x0000;
2208 2151
2209 /* Don't "show full pathname to buddy", just because it is 2152 /* Convert the directory separator to ^A for portability. */
2210 * non-portable. -- wtm 2153 strncpy(fh->name, filename, sizeof(fh->name));
2211 */ 2154 oft_dirconvert(fh->name);
2212 strncpy(fh->name, oft_basename(filename), sizeof(fh->name)); 2155
2213 2156 /* XXX we should normally send a null cookie here, and make
2214 /* XXX we should normally send a null cookie here, and make 2157 * the receiver fill it in for authentication -- wtm
2215 * the receiver fill it in for authentication -- wtm 2158 */
2216 */ 2159 memcpy(fh->bcookie, ft->cookie, 8);
2217 memcpy(fh->bcookie, ft->cookie, 8); 2160
2218 2161 if (!(cook = aim_checkcookie(sess, ft->cookie, AIM_COOKIETYPE_OFTSEND))) {
2219 if (!(cook = aim_checkcookie(sess, ft->cookie, AIM_COOKIETYPE_OFTSEND))) { 2162 return -1;
2220 return -1; 2163 }
2221 } 2164
2222 2165 /* Update both headers to be safe. */
2223 /* Update both headers to be safe. */ 2166 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
2224 memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); 2167 memcpy(&(((struct aim_filetransfer_priv *)cook->data)->fh), fh, sizeof(struct aim_fileheader_t));
2225 memcpy(&(((struct aim_filetransfer_priv *)cook->data)->fh), fh, 2168
2226 sizeof(struct aim_fileheader_t)); 2169 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_OFFER, 0))) {
2227 2170 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2228 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_OFFER, 0))) { 2171 free(fh);
2229 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2172 return -1;
2230 free(fh); 2173 }
2231 return -1; 2174
2232 } 2175 if (aim_oft_buildheader(&newoft->data, fh) == -1) {
2233 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 2176 aim_frame_destroy(newoft);
2234 newoft->hdr.oft.hdr2len = 0x100 - 8; 2177 free(fh);
2235 2178 return -1;
2236 if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) { 2179 }
2237 aim_frame_destroy(newoft); 2180
2238 free(fh); 2181 memcpy(newoft->hdr.rend.magic, "OFT2", 4);
2239 return -1; 2182 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
2240 } 2183
2241 2184 aim_tx_enqueue(sess, newoft);
2242 if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, fh))) { 2185 free(fh);
2243 aim_frame_destroy(newoft); 2186 return 0;
2244 free(fh);
2245 return -1;
2246 }
2247
2248 aim_tx_enqueue(sess, newoft);
2249 free(fh);
2250 return 0;
2251 } 2187 }
2252 2188
2253 /** 2189 /**
2254 * aim_oft_getfile_ack - acknowledge a getfile download as complete 2190 * aim_oft_getfile_ack - acknowledge a getfile download as complete
2255 * @sess: your session 2191 * @sess: your session
2261 */ 2197 */
2262 faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn) 2198 faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn)
2263 { 2199 {
2264 return -EINVAL; 2200 return -EINVAL;
2265 #if 0 2201 #if 0
2266 struct command_tx_struct *newoft; 2202 struct command_tx_struct *newoft;
2267 struct aim_filetransfer_priv *ft; 2203 struct aim_filetransfer_priv *ft;
2268 2204
2269 if (!sess || !conn || !conn->priv) 2205 if (!sess || !conn || !conn->priv)
2270 return -1; 2206 return -1;
2271 2207
2272 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) { 2208 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) {
2273 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2209 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2274 return -1; 2210 return -1;
2275 } 2211 }
2276 2212
2277 newoft->lock = 1; 2213 newoft->lock = 1;
2278 2214
2279 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 2215 memcpy(newoft->hdr.oft.magic, "OFT2", 4);
2280 newoft->hdr.oft.hdr2len = 0x100-8; 2216 newoft->hdr.oft.hdr2len = 0x100-8;
2281 2217
2282 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 2218 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
2283 newoft->lock = 0; 2219 newoft->lock = 0;
2284 aim_frame_destroy(newoft); 2220 aim_frame_destroy(newoft);
2285 return -1; 2221 return -1;
2286 } 2222 }
2287 2223
2288 ft = (struct aim_filetransfer_priv *)conn->priv; 2224 ft = (struct aim_filetransfer_priv *)conn->priv;
2289 2225
2290 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { 2226 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
2291 newoft->lock = 0; 2227 newoft->lock = 0;
2292 aim_frame_destroy(newoft); 2228 aim_frame_destroy(newoft);
2293 return -1; 2229 return -1;
2294 } 2230 }
2295 2231
2296 newoft->lock = 0; 2232 newoft->lock = 0;
2297 aim_tx_enqueue(sess, newoft); 2233 aim_tx_enqueue(sess, newoft);
2298 return 0; 2234 return 0;
2299 #endif 2235 #endif
2300 } 2236 }
2301 2237
2302 /** 2238 /**
2303 * aim_oft_end - end a getfile/sendfile. 2239 * aim_oft_end - end a getfile/sendfile.
2307 * call this before you close the getfile connection if you're on the 2243 * call this before you close the getfile connection if you're on the
2308 * receiving/requesting end. 2244 * receiving/requesting end.
2309 */ 2245 */
2310 faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn) 2246 faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn)
2311 { 2247 {
2312 aim_frame_t *newoft; 2248 aim_frame_t *newoft;
2313 struct aim_filetransfer_priv *ft; 2249 struct aim_filetransfer_priv *ft;
2314 2250
2315 if (!sess || !conn || !conn->internal) 2251 if (!sess || !conn || !conn->internal)
2316 return -1; 2252 return -1;
2317 2253
2318 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACK, 0))) { 2254 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACK, 0))) {
2319 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); 2255 faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
2320 return -1; 2256 return -1;
2321 } 2257 }
2322 2258
2323 memcpy(newoft->hdr.oft.magic, "OFT2", 4); 2259 ft = (struct aim_filetransfer_priv *)conn->internal;
2324 newoft->hdr.oft.hdr2len = 0x100 - 8; 2260 ft->state = 4; /* no longer wanting data */
2325 2261 ft->fh.flags = 0x21;
2326 if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 2262
2327 aim_frame_destroy(newoft); 2263 if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
2328 return -1; 2264 aim_frame_destroy(newoft);
2329 } 2265 return -1;
2330 2266 }
2331 ft = (struct aim_filetransfer_priv *)conn->internal; 2267 memcpy(newoft->hdr.rend.magic, "OFT2", 4);
2332 ft->state = 4; /* no longer wanting data */ 2268 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
2333 ft->fh.flags = 0x21; 2269
2334 2270 aim_tx_enqueue(sess, newoft);
2335 if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { 2271
2336 aim_frame_destroy(newoft); 2272 return 0;
2337 return -1; 2273 }
2338 } 2274
2339 2275 /*
2340 aim_tx_enqueue(sess, newoft); 2276 * Convert the directory separator to ^A, which seems to be AOL's attempt at portability.
2341 2277 */
2342 return 0; 2278 static void oft_dirconvert(char *name) {
2343 } 2279 char *c = name;
2344 2280 while ((c = strchr(c, G_DIR_SEPARATOR)))
2345 /* Portability. Yuck. */ 2281 *c = 0x01;
2346 static const char *oft_basename(const char *name) { 2282 }
2347 const char *r = strrchr(name, G_DIR_SEPARATOR);
2348 r = r ? r + 1 : name;
2349 return r;
2350 }
2351