📄 oft.c
字号:
peer_oft_copy_xfer_data(conn, frame); peer_oft_send_ack(conn); /* Remove our watchers and use the file transfer watchers in the core */ purple_input_remove(conn->watcher_incoming); conn->watcher_incoming = 0; conn->sending_data_timer = purple_timeout_add(100, start_transfer_when_done_sending_data, conn);}/** * We are sending a file to someone else. They have just acknowledged our * prompt, so we want to start sending data like there's no tomorrow. */static voidpeer_oft_recv_frame_ack(PeerConnection *conn, OftFrame *frame){ if (memcmp(conn->cookie, frame->cookie, 8) != 0) { purple_debug_info("oscar", "Received an incorrect cookie. " "Closing connection.\n"); peer_connection_destroy(conn, OSCAR_DISCONNECT_INVALID_DATA, NULL); return; } /* Remove our watchers and use the file transfer watchers in the core */ purple_input_remove(conn->watcher_incoming); conn->watcher_incoming = 0; conn->sending_data_timer = purple_timeout_add(100, start_transfer_when_done_sending_data, conn);}static gbooleanpeer_oft_recv_frame_resume_checksum_calculated_cb(gpointer data){ ChecksumData *checksum_data; PeerConnection *conn; checksum_data = data; conn = checksum_data->conn; /* Check the checksums here. If not match, don't allow resume */ if (checksum_data->checksum != conn->xferdata.recvcsum || checksum_data->total != conn->xferdata.nrecvd) { /* Reset internal structure */ conn->xferdata.recvcsum = 0xffff0000; conn->xferdata.rfrcsum = 0xffff0000; conn->xferdata.nrecvd = 0; } else /* Accept the change */ purple_xfer_set_bytes_sent(checksum_data->xfer, conn->xferdata.nrecvd); peer_oft_send_resume_accept(conn); return FALSE;}/** * We are sending a file to someone else. They have just acknowledged our * prompt and are asking to resume, so we accept their resume and await * a resume ack. */static voidpeer_oft_recv_frame_resume(PeerConnection *conn, OftFrame *frame){ if (memcmp(conn->cookie, frame->cookie, 8) != 0) { purple_debug_info("oscar", "Received an incorrect cookie. " "Closing connection.\n"); peer_connection_destroy(conn, OSCAR_DISCONNECT_INVALID_DATA, NULL); return; } /* Copy resume data into internal structure */ conn->xferdata.recvcsum = frame->recvcsum; conn->xferdata.rfrcsum = frame->rfrcsum; conn->xferdata.nrecvd = frame->nrecvd; peer_oft_checksum_file(conn, conn->xfer, peer_oft_recv_frame_resume_checksum_calculated_cb, frame->nrecvd);}/* * We just sent a file to someone. They said they got it and everything, * so we can close our direct connection and what not. */static voidpeer_oft_recv_frame_done(PeerConnection *conn, OftFrame *frame){ purple_input_remove(conn->watcher_incoming); conn->watcher_incoming = 0; conn->xfer->fd = conn->fd; conn->fd = -1; conn->disconnect_reason = OSCAR_DISCONNECT_DONE; peer_connection_schedule_destroy(conn, conn->disconnect_reason, NULL);}/** * Handle an incoming OftFrame. If there is a payload associated * with this frame, then we remove the old watcher and add the * OFT watcher to read in the payload. */voidpeer_oft_recv_frame(PeerConnection *conn, ByteStream *bs){ OftFrame frame; frame.type = byte_stream_get16(bs); byte_stream_getrawbuf(bs, frame.cookie, 8); frame.encrypt = byte_stream_get16(bs); frame.compress = byte_stream_get16(bs); frame.totfiles = byte_stream_get16(bs); frame.filesleft = byte_stream_get16(bs); frame.totparts = byte_stream_get16(bs); frame.partsleft = byte_stream_get16(bs); frame.totsize = byte_stream_get32(bs); frame.size = byte_stream_get32(bs); frame.modtime = byte_stream_get32(bs); frame.checksum = byte_stream_get32(bs); frame.rfrcsum = byte_stream_get32(bs); frame.rfsize = byte_stream_get32(bs); frame.cretime = byte_stream_get32(bs); frame.rfcsum = byte_stream_get32(bs); frame.nrecvd = byte_stream_get32(bs); frame.recvcsum = byte_stream_get32(bs); byte_stream_getrawbuf(bs, frame.idstring, 32); frame.flags = byte_stream_get8(bs); frame.lnameoffset = byte_stream_get8(bs); frame.lsizeoffset = byte_stream_get8(bs); byte_stream_getrawbuf(bs, frame.dummy, 69); byte_stream_getrawbuf(bs, frame.macfileinfo, 16); frame.nencode = byte_stream_get16(bs); frame.nlanguage = byte_stream_get16(bs); frame.name_length = bs->len - 186; frame.name = byte_stream_getraw(bs, frame.name_length); purple_debug_info("oscar", "Incoming OFT frame from %s with " "type=0x%04x\n", conn->sn, frame.type); /* TODOFT: peer_oft_dirconvert_fromstupid(frame->name); */ switch(frame.type) { case PEER_TYPE_PROMPT: peer_oft_recv_frame_prompt(conn, &frame); break; case PEER_TYPE_ACK: case PEER_TYPE_RESUMEACK: peer_oft_recv_frame_ack(conn, &frame); break; case PEER_TYPE_RESUME: peer_oft_recv_frame_resume(conn, &frame); break; case PEER_TYPE_DONE: peer_oft_recv_frame_done(conn, &frame); break; default: break; } g_free(frame.name);}/*******************************************************************//* Begin PurpleXfer callbacks for use when receiving a file *//*******************************************************************/voidpeer_oft_recvcb_init(PurpleXfer *xfer){ PeerConnection *conn; conn = xfer->data; conn->flags |= PEER_CONNECTION_FLAG_APPROVED; peer_connection_trynext(conn);}voidpeer_oft_recvcb_end(PurpleXfer *xfer){ PeerConnection *conn; conn = xfer->data; /* Tell the other person that we've received everything */ conn->fd = conn->xfer->fd; conn->xfer->fd = -1; peer_oft_send_done(conn); conn->disconnect_reason = OSCAR_DISCONNECT_DONE; conn->sending_data_timer = purple_timeout_add(100, destroy_connection_when_done_sending_data, conn);}voidpeer_oft_recvcb_ack_recv(PurpleXfer *xfer, const guchar *buffer, size_t size){ PeerConnection *conn; /* Update our rolling checksum. Like Walmart, yo. */ conn = xfer->data; conn->xferdata.recvcsum = peer_oft_checksum_chunk(buffer, size, conn->xferdata.recvcsum, purple_xfer_get_bytes_sent(xfer) & 1);}/*******************************************************************//* End PurpleXfer callbacks for use when receiving a file *//*******************************************************************//*******************************************************************//* Begin PurpleXfer callbacks for use when sending a file *//*******************************************************************/static gbooleanpeer_oft_checksum_calculated_cb(gpointer data){ ChecksumData *checksum_data; PeerConnection *conn; checksum_data = data; conn = checksum_data->conn; conn->xferdata.checksum = checksum_data->checksum; /* Start the connection process */ peer_connection_trynext(checksum_data->conn); return FALSE;}voidpeer_oft_sendcb_init(PurpleXfer *xfer){ PeerConnection *conn; size_t size; conn = xfer->data; conn->flags |= PEER_CONNECTION_FLAG_APPROVED; /* Make sure the file size can be represented in 32 bits */ size = purple_xfer_get_size(xfer); if (size > G_MAXUINT32) { gchar *tmp, *size1, *size2; size1 = purple_str_size_to_units(size); size2 = purple_str_size_to_units(G_MAXUINT32); tmp = g_strdup_printf(_("File %s is %s, which is larger than " "the maximum size of %s."), xfer->local_filename, size1, size2); purple_xfer_error(purple_xfer_get_type(xfer), purple_xfer_get_account(xfer), xfer->who, tmp); g_free(size1); g_free(size2); g_free(tmp); peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL); return; } /* Keep track of file transfer info */ conn->xferdata.totfiles = 1; conn->xferdata.filesleft = 1; conn->xferdata.totparts = 1; conn->xferdata.partsleft = 1; conn->xferdata.totsize = size; conn->xferdata.size = size; conn->xferdata.checksum = 0xffff0000; conn->xferdata.rfrcsum = 0xffff0000; conn->xferdata.rfcsum = 0xffff0000; conn->xferdata.recvcsum = 0xffff0000; strncpy((gchar *)conn->xferdata.idstring, "OFT_Windows ICBMFT V1.1 32", 31); conn->xferdata.modtime = 0; conn->xferdata.cretime = 0; xfer->filename = g_path_get_basename(xfer->local_filename); conn->xferdata.name = (guchar *)g_strdup(xfer->filename); conn->xferdata.name_length = strlen(xfer->filename); peer_oft_checksum_file(conn, xfer, peer_oft_checksum_calculated_cb, G_MAXUINT32);}/* * AIM file transfers aren't really meant to be thought * of as a transferring just a single file. The rendezvous * establishes a connection between two computers, and then * those computers can use the same connection for transferring * multiple files. So we don't want the Purple core up and closing * the socket all willy-nilly. We want to do that in the oscar * prpl, whenever one side or the other says they're finished * using the connection. There might be a better way to intercept * the socket from the core... */voidpeer_oft_sendcb_ack(PurpleXfer *xfer, const guchar *buffer, size_t size){ PeerConnection *conn; conn = xfer->data; /* * If we're done sending, intercept the socket from the core ft code * and wait for the other guy to send the "done" OFT packet. */ if (purple_xfer_get_bytes_remaining(xfer) <= 0) { purple_input_remove(xfer->watcher); conn->fd = xfer->fd; xfer->fd = -1; conn->watcher_incoming = purple_input_add(conn->fd, PURPLE_INPUT_READ, peer_connection_recv_cb, conn); }}/*******************************************************************//* End PurpleXfer callbacks for use when sending a file *//*******************************************************************//*******************************************************************//* Begin PurpleXfer callbacks for use when sending and receiving *//*******************************************************************/voidpeer_oft_cb_generic_cancel(PurpleXfer *xfer){ PeerConnection *conn; conn = xfer->data; if (conn == NULL) return; peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);}/*******************************************************************//* End PurpleXfer callbacks for use when sending and receiving *//*******************************************************************/#ifdef TODOFT/* * This little area in oscar.c is the nexus of file transfer code, * so I wrote a little explanation of what happens. I am such a * ninja. * * The series of events for a file send is: * -Create xfer and call purple_xfer_request (this happens in oscar_ask_sendfile) * -User chooses a file and oscar_xfer_init is called. It establishes a * listening socket, then asks the remote user to connect to us (and * gives them the file name, port, IP, etc.) * -They connect to us and we send them an PEER_TYPE_PROMPT (this happens * in peer_oft_recv_frame_established) * -They send us an PEER_TYPE_ACK and then we start sending data * -When we finish, they send us an PEER_TYPE_DONE and they close the * connection. * -We get drunk because file transfer kicks ass. * * The series of events for a file receive is: * -Create xfer and call purple_xfer request (this happens in incomingim_chan2) * -Purple user selects file to name and location to save file to and * oscar_xfer_init is called * -It connects to the remote user using the IP they gave us earlier * -After connecting, they send us an PEER_TYPE_PROMPT. In reply, we send * them an PEER_TYPE_ACK. * -They begin to send us lots of raw data. * -When they finish sending data we send an PEER_TYPE_DONE and then close * the connection. * * Update August 2005: * The series of events for transfers has been seriously complicated by the addition * of transfer redirects and proxied connections. I could throw a whole lot of words * at trying to explain things here, but it probably wouldn't do much good. To get * a better idea of what happens, take a look at the diagrams and documentation * from my Summer of Code project. -- Jonathan Clark *//** * Convert the directory separator from / (0x2f) to ^A (0x01) * * @param name The filename to convert. */static voidpeer_oft_dirconvert_tostupid(char *name){ while (name[0]) { if (name[0] == 0x01) name[0] = G_DIR_SEPARATOR; name++; }}/** * Convert the directory separator from ^A (0x01) to / (0x2f) * * @param name The filename to convert. */static voidpeer_oft_dirconvert_fromstupid(char *name){ while (name[0]) { if (name[0] == G_DIR_SEPARATOR) name[0] = 0x01; name++; }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -