Mercurial > pidgin.yaz
comparison src/protocols/oscar/ft.c @ 11126:2a3568cbd8a6
[gaim-migrate @ 13182]
Whitespace
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 19 Jul 2005 03:51:54 +0000 |
parents | 8d74ae785a46 |
children | bd8ac1d4b2f2 |
comparison
equal
deleted
inserted
replaced
11125:072d80ba330d | 11126:2a3568cbd8a6 |
---|---|
1 /* | 1 /* |
2 * Oscar File transfer (OFT) and Oscar Direct Connect (ODC). | 2 * Oscar File transfer (OFT) and Oscar Direct Connect (ODC). |
3 * (ODC is also referred to as DirectIM and IM Image.) | 3 * (ODC is also referred to as DirectIM and IM Image.) |
4 * | 4 * |
5 * There are a few static helper functions at the top, then | 5 * There are a few static helper functions at the top, then |
6 * ODC stuff, then ft stuff. | 6 * ODC stuff, then ft stuff. |
7 * | 7 * |
8 * I feel like this is a good place to explain OFT, so I'm going to | 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 | 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 | 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. | 11 * basically tells the other client the meaning of the OFT packet. |
12 * There are two distinct types of file transfer, which I usually | 12 * There are two distinct types of file transfer, which I usually |
13 * call "sendfile" and "getfile." Sendfile is when you send a file | 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, | 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. | 15 * and other users request that you send them the files. |
16 * | 16 * |
17 * A typical sendfile file transfer goes like this: | 17 * A typical sendfile file transfer goes like this: |
18 * 1) Sender sends a channel 2 ICBM telling the other user that | 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 | 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 | 20 * listener socket (this should be done before sending the |
21 * ICBM) on some port, and wait for them to connect to us. | 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 | 22 * The ICBM we sent should contain our IP address and the port |
23 * number that we're listening on. | 23 * number that we're listening on. |
24 * 2) The receiver connects to the sender on the given IP address | 24 * 2) The receiver connects to the sender on the given IP address |
25 * and port. After the connection is established, the receiver | 25 * and port. After the connection is established, the receiver |
26 * sends an ICBM signifying that we are ready and waiting. | 26 * sends an ICBM signifying that we are ready and waiting. |
27 * 3) The sender sends an OFT PROMPT message over the OFT | 27 * 3) The sender sends an OFT PROMPT message over the OFT |
28 * connection. | 28 * connection. |
29 * 4) The receiver of the file sends back an exact copy of this | 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 | 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 | 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 | 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. | 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 | 34 * 5) The sender starts sending raw data across the connection |
35 * until the entire file has been sent. | 35 * until the entire file has been sent. |
36 * 6) The receiver knows the file is finished because the sender | 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 | 37 * sent the file size in an earlier OFT packet. So then the |
38 * receiver sends the DONE thingy (after filling in the | 38 * receiver sends the DONE thingy (after filling in the |
39 * "received" checksum and size) and closes the connection. | 39 * "received" checksum and size) and closes the connection. |
40 */ | 40 */ |
41 | 41 |
42 #define FAIM_INTERNAL | 42 #define FAIM_INTERNAL |
43 #ifdef HAVE_CONFIG_H | 43 #ifdef HAVE_CONFIG_H |
110 } | 110 } |
111 | 111 |
112 /** | 112 /** |
113 * Calculate oft checksum of buffer | 113 * Calculate oft checksum of buffer |
114 * | 114 * |
115 * Prevcheck should be 0xFFFF0000 when starting a checksum of a file. The | 115 * Prevcheck should be 0xFFFF0000 when starting a checksum of a file. The |
116 * checksum is kind of a rolling checksum thing, so each time you get bytes | 116 * checksum is kind of a rolling checksum thing, so each time you get bytes |
117 * of a file you just call this puppy and it updates the checksum. You can | 117 * of a file you just call this puppy and it updates the checksum. You can |
118 * calculate the checksum of an entire file by calling this in a while or a | 118 * calculate the checksum of an entire file by calling this in a while or a |
119 * for loop, or something. | 119 * for loop, or something. |
120 * | 120 * |
121 * Thanks to Graham Booker for providing this improved checksum routine, | 121 * Thanks to Graham Booker for providing this improved checksum routine, |
122 * which is simpler and should be more accurate than Josh Myer's original | 122 * which is simpler and should be more accurate than Josh Myer's original |
123 * code. -- wtm | 123 * code. -- wtm |
124 * | 124 * |
125 * This algorithm works every time I have tried it. The other fails | 125 * This algorithm works every time I have tried it. The other fails |
126 * sometimes. So, AOL who thought this up? It has got to be the weirdest | 126 * sometimes. So, AOL who thought this up? It has got to be the weirdest |
127 * checksum I have ever seen. | 127 * checksum I have ever seen. |
128 * | 128 * |
129 * @param buffer Buffer of data to checksum. Man I'd like to buff her... | 129 * @param buffer Buffer of data to checksum. Man I'd like to buff her... |
130 * @param bufsize Size of buffer. | 130 * @param bufsize Size of buffer. |
131 * @param prevcheck Previous checksum. | 131 * @param prevcheck Previous checksum. |
142 val = buffer[i]; | 142 val = buffer[i]; |
143 else | 143 else |
144 val = buffer[i] << 8; | 144 val = buffer[i] << 8; |
145 check -= val; | 145 check -= val; |
146 /* | 146 /* |
147 * The following appears to be necessary.... It happens | 147 * The following appears to be necessary.... It happens |
148 * every once in a while and the checksum doesn't fail. | 148 * every once in a while and the checksum doesn't fail. |
149 */ | 149 */ |
150 if (check > oldcheck) | 150 if (check > oldcheck) |
151 check--; | 151 check--; |
152 } | 152 } |
242 /** | 242 /** |
243 * Send client-to-client typing notification over an established direct connection. | 243 * Send client-to-client typing notification over an established direct connection. |
244 * | 244 * |
245 * @param sess The session. | 245 * @param sess The session. |
246 * @param conn The already-connected ODC connection. | 246 * @param conn The already-connected ODC connection. |
247 * @param typing If 0x0002, sends a "typing" message, 0x0001 sends "typed," and | 247 * @param typing If 0x0002, sends a "typing" message, 0x0001 sends "typed," and |
248 * 0x0000 sends "stopped." | 248 * 0x0000 sends "stopped." |
249 * @return Return 0 if no errors, otherwise return the error number. | 249 * @return Return 0 if no errors, otherwise return the error number. |
250 */ | 250 */ |
251 faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing) | 251 faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing) |
252 { | 252 { |
315 } | 315 } |
316 | 316 |
317 /** | 317 /** |
318 * Send client-to-client IM over an established direct connection. | 318 * Send client-to-client IM over an established direct connection. |
319 * Call this just like you would aim_send_im, to send a directim. | 319 * Call this just like you would aim_send_im, to send a directim. |
320 * | 320 * |
321 * @param sess The session. | 321 * @param sess The session. |
322 * @param conn The already-connected ODC connection. | 322 * @param conn The already-connected ODC connection. |
323 * @param msg Null-terminated string to send. | 323 * @param msg Null-terminated string to send. |
324 * @param len The length of the message to send, including binary data. | 324 * @param len The length of the message to send, including binary data. |
325 * @param encoding See the AIM_CHARSET_* defines in aim.h | 325 * @param encoding See the AIM_CHARSET_* defines in aim.h |
444 /** | 444 /** |
445 * Find the conn of a direct connection with the given buddy. | 445 * Find the conn of a direct connection with the given buddy. |
446 * | 446 * |
447 * @param sess The session. | 447 * @param sess The session. |
448 * @param sn The screen name of the buddy whose direct connection you want to find. | 448 * @param sn The screen name of the buddy whose direct connection you want to find. |
449 * @return The conn for the direct connection with the given buddy, or NULL if no | 449 * @return The conn for the direct connection with the given buddy, or NULL if no |
450 * connection was found. | 450 * connection was found. |
451 */ | 451 */ |
452 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn) | 452 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn) |
453 { | 453 { |
454 aim_conn_t *cur; | 454 aim_conn_t *cur; |
532 /** | 532 /** |
533 * Connect directly to the given buddy for directim. | 533 * Connect directly to the given buddy for directim. |
534 * | 534 * |
535 * This is a wrapper for aim_newconn. | 535 * This is a wrapper for aim_newconn. |
536 * | 536 * |
537 * If addr is NULL, the socket is not created, but the connection is | 537 * If addr is NULL, the socket is not created, but the connection is |
538 * allocated and setup to connect. | 538 * allocated and setup to connect. |
539 * | 539 * |
540 * @param sess The Godly session. | 540 * @param sess The Godly session. |
541 * @param sn The screen name we're connecting to. I hope it's a girl... | 541 * @param sn The screen name we're connecting to. I hope it's a girl... |
542 * @param addr Address to connect to. | 542 * @param addr Address to connect to. |
629 } | 629 } |
630 | 630 |
631 while (payloadlength - recvd) { | 631 while (payloadlength - recvd) { |
632 if (payloadlength - recvd >= 1024) | 632 if (payloadlength - recvd >= 1024) |
633 i = aim_recv(conn->fd, &msg[recvd], 1024); | 633 i = aim_recv(conn->fd, &msg[recvd], 1024); |
634 else | 634 else |
635 i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd); | 635 i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd); |
636 if (i <= 0) { | 636 if (i <= 0) { |
637 free(msg); | 637 free(msg); |
638 free(snptr); | 638 free(snptr); |
639 return -1; | 639 return -1; |
640 } | 640 } |
641 recvd = recvd + i; | 641 recvd = recvd + i; |
642 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) | 642 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) |
643 ret = userfunc(sess, &fr, snptr, (double)recvd / payloadlength); | 643 ret = userfunc(sess, &fr, snptr, (double)recvd / payloadlength); |
644 } | 644 } |
645 | 645 |
646 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING))) | 646 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING))) |
647 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding, isawaymsg); | 647 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding, isawaymsg); |
648 | 648 |
649 free(msg); | 649 free(msg); |
650 } | 650 } |
694 | 694 |
695 return new; | 695 return new; |
696 } | 696 } |
697 | 697 |
698 /** | 698 /** |
699 * Remove the given oft_info struct from the oft_info linked list, and | 699 * Remove the given oft_info struct from the oft_info linked list, and |
700 * then free its memory. | 700 * then free its memory. |
701 * | 701 * |
702 * @param sess The session. | 702 * @param sess The session. |
703 * @param oft_info The aim_oft_info struct that we're destroying. | 703 * @param oft_info The aim_oft_info struct that we're destroying. |
704 * @return Return 0 if no errors, otherwise return the error number. | 704 * @return Return 0 if no errors, otherwise return the error number. |
729 } | 729 } |
730 | 730 |
731 /** | 731 /** |
732 * Creates a listener socket so the other dude can connect to us. | 732 * Creates a listener socket so the other dude can connect to us. |
733 * | 733 * |
734 * You'll want to set up some kind of watcher on this socket. | 734 * You'll want to set up some kind of watcher on this socket. |
735 * When the state changes, call aim_handlerendconnection with | 735 * When the state changes, call aim_handlerendconnection with |
736 * the connection returned by this. aim_handlerendconnection | 736 * the connection returned by this. aim_handlerendconnection |
737 * will accept the pending connection and stop listening. | 737 * will accept the pending connection and stop listening. |
738 * | 738 * |
739 * @param sess The session. | 739 * @param sess The session. |
740 * @param oft_info File transfer information associated with this | 740 * @param oft_info File transfer information associated with this |
741 * connection. | 741 * connection. |
742 * @return Return 0 if no errors, otherwise return the error number. | 742 * @return Return 0 if no errors, otherwise return the error number. |
743 */ | 743 */ |
744 faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info, int listenfd) | 744 faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info, int listenfd) |
745 { | 745 { |
799 fh->nlanguage = aimbs_get16(bs); | 799 fh->nlanguage = aimbs_get16(bs); |
800 aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */ | 800 aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */ |
801 fh->name[63] = '\0'; | 801 fh->name[63] = '\0'; |
802 | 802 |
803 return fh; | 803 return fh; |
804 } | 804 } |
805 | 805 |
806 /** | 806 /** |
807 * Fills a buffer with network-order fh data | 807 * Fills a buffer with network-order fh data |
808 * | 808 * |
809 * @param bs A bstream to fill -- automatically initialized | 809 * @param bs A bstream to fill -- automatically initialized |
810 * @param fh A struct aim_fileheader_t to get data from. | 810 * @param fh A struct aim_fileheader_t to get data from. |
811 * @return Return non-zero on error. | 811 * @return Return non-zero on error. |
812 */ | 812 */ |
813 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) | 813 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) |
814 { | 814 { |
815 fu8_t *hdr; | 815 fu8_t *hdr; |
816 | 816 |
817 if (!bs || !fh) | 817 if (!bs || !fh) |
818 return -EINVAL; | 818 return -EINVAL; |
819 | 819 |
854 /** | 854 /** |
855 * Create an OFT packet based on the given information, and send it on its merry way. | 855 * Create an OFT packet based on the given information, and send it on its merry way. |
856 * | 856 * |
857 * @param sess The session. | 857 * @param sess The session. |
858 * @param type The subtype of the OFT packet we're sending. | 858 * @param type The subtype of the OFT packet we're sending. |
859 * @param oft_info The aim_oft_info struct with the connection and OFT | 859 * @param oft_info The aim_oft_info struct with the connection and OFT |
860 * info we're sending. | 860 * info we're sending. |
861 * @return Return 0 if no errors, otherwise return the error number. | 861 * @return Return 0 if no errors, otherwise return the error number. |
862 */ | 862 */ |
863 faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info) | 863 faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info) |
864 { | 864 { |
867 if (!sess || !oft_info || !oft_info->conn || (oft_info->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) | 867 if (!sess || !oft_info || !oft_info->conn || (oft_info->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) |
868 return -EINVAL; | 868 return -EINVAL; |
869 | 869 |
870 #if 0 | 870 #if 0 |
871 /* | 871 /* |
872 * If you are receiving a file, the cookie should be null, if you are sending a | 872 * If you are receiving a file, the cookie should be null, if you are sending a |
873 * file, the cookie should be the same as the one used in the ICBM negotiation | 873 * file, the cookie should be the same as the one used in the ICBM negotiation |
874 * SNACs. | 874 * SNACs. |
875 */ | 875 */ |
876 fh->lnameoffset = 0x1a; | 876 fh->lnameoffset = 0x1a; |
877 fh->lsizeoffset = 0x10; | 877 fh->lsizeoffset = 0x10; |
878 | 878 |
898 | 898 |
899 return 0; | 899 return 0; |
900 } | 900 } |
901 | 901 |
902 /** | 902 /** |
903 * Handle incoming data on a rendezvous connection. This is analogous to the | 903 * Handle incoming data on a rendezvous connection. This is analogous to the |
904 * consumesnac function in rxhandlers.c, and I really think this should probably | 904 * consumesnac function in rxhandlers.c, and I really think this should probably |
905 * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet. | 905 * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet. |
906 * | 906 * |
907 * @param sess The session. | 907 * @param sess The session. |
908 * @param fr The frame allocated for the incoming data. | 908 * @param fr The frame allocated for the incoming data. |
909 * @return Return 0 if the packet was handled correctly, otherwise return the | 909 * @return Return 0 if the packet was handled correctly, otherwise return the |
910 * error number. | 910 * error number. |
911 */ | 911 */ |
912 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) | 912 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) |
913 { | 913 { |
914 aim_conn_t *conn = fr->conn; | 914 aim_conn_t *conn = fr->conn; |