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