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;