From: ArdentlyGnarly <ard...@us...> - 2005-08-30 05:22:12
|
Update of /cvsroot/gaim/gaim/src/protocols/oscar In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6475/src/protocols/oscar Modified Files: aim.h ft.c im.c oscar.c txqueue.c Log Message: Bring all the changes to OSCAR file transfers from oldstatus to HEAD. Add documentation resulting from my Summer of Code project to CVS including the original editable files (in OpenOffice.org 2.0 format). Index: aim.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/aim.h,v retrieving revision 1.170 retrieving revision 1.171 diff -u -d -p -r1.170 -r1.171 --- aim.h 25 Aug 2005 02:33:44 -0000 1.170 +++ aim.h 30 Aug 2005 05:21:57 -0000 1.171 @@ -55,7 +55,7 @@ typedef guint16 flap_seqnum_t; */ #ifdef WIN32_INDLL #define faim_export __declspec(dllexport) -#else +#else #define faim_export __declspec(dllimport) #endif /* WIN32_INDLL */ #define faim_internal @@ -293,9 +293,54 @@ struct client_info_s { #define AIM_CONN_TYPE_EMAIL 0x0018 /* they start getting arbitrary for rendezvous stuff =) */ +#define AIM_CONN_TYPE_RENDEZVOUS_PROXY 0xfffd /* these speak a strange language */ #define AIM_CONN_TYPE_RENDEZVOUS 0xfffe /* these do not speak FLAP! */ #define AIM_CONN_TYPE_LISTENER 0xffff /* socket waiting for accept() */ +/* Command types for doing a rendezvous proxy login + * Thanks to Keith Lea and the Joust project for documenting these commands well */ +#define AIM_RV_PROXY_PACKETVER_DFLT 0x044a +#define AIM_RV_PROXY_ERROR 0x0001 +#define AIM_RV_PROXY_INIT_SEND 0x0002 /* First command sent when creating a connection */ +#define AIM_RV_PROXY_INIT_RECV 0x0004 /* First command sent when receiving existing connection */ +#define AIM_RV_PROXY_ACK 0x0003 +#define AIM_RV_PROXY_READY 0x0005 + +/* Number of bytes expected in each of the above packets, including the 2 bytes specifying length */ +#define AIM_RV_PROXY_ERROR_LEN 14 +#define AIM_RV_PROXY_INIT_SEND_LEN 55 +#define AIM_RV_PROXY_INIT_RECV_LEN 57 +#define AIM_RV_PROXY_ACK_LEN 18 +#define AIM_RV_PROXY_READY_LEN 12 +#define AIM_RV_PROXY_HDR_LEN 12 /* Bytes in just the header alone */ + +/* Default values for unknown/unused values in rendezvous proxy negotiation packets */ +#define AIM_RV_PROXY_SERVER_FLAGS 0x0220 /* Default flags sent by proxy server */ +#define AIM_RV_PROXY_CLIENT_FLAGS 0x0000 /* Default flags sent by client */ +#define AIM_RV_PROXY_UNKNOWNA_DFLT 0x00000000 /* Default value for an unknown block */ +#define AIM_RV_PROXY_SERVER_URL "ars.oscar.aol.com" +#define AIM_RV_PROXY_CONNECT_PORT 5190 /* The port we should always connect to */ + +/* What is the purpose of this transfer? (Who will end up with a new file?) + * These values are used in oft_info->send_or_recv */ +#define AIM_XFER_SEND 0x0001 +#define AIM_XFER_RECV 0x0002 + +/* Via what method is the data getting routed? + * These values are used in oft_info->method */ +#define AIM_XFER_DIRECT 0x0001 /* Direct connection; receiver connects to sender */ +#define AIM_XFER_REDIR 0x0002 /* Redirected connection; sender connects to receiver */ +#define AIM_XFER_PROXY 0x0003 /* Proxied connection */ + +/* Who requested the proxy? + * The difference between a stage 2 and stage 3 proxied transfer is that the receiver does the + * initial login for a stage 2, but the sender must do it for a stage 3. + * These values are used in oft_info->stage */ +#define AIM_XFER_PROXY_NONE 0x0001 +#define AIM_XFER_PROXY_STG1 0x0002 /* Sender requested a proxy be used (stage1) */ +#define AIM_XFER_PROXY_STG2 0x0003 /* Receiver requested a proxy be used (stage2) */ +#define AIM_XFER_PROXY_STG3 0x0004 /* Receiver requested a proxy be used (stage3) */ + /* * Subtypes, we need these for OFT stuff. */ @@ -303,7 +348,7 @@ struct client_info_s { #define AIM_CONN_SUBTYPE_OFT_GETFILE 0x0002 #define AIM_CONN_SUBTYPE_OFT_SENDFILE 0x0003 #define AIM_CONN_SUBTYPE_OFT_BUDDYICON 0x0004 -#define AIM_CONN_SUBTYPE_OFT_VOICE 0x0005 +#define AIM_CONN_SUBTYPE_OFT_VOICE 0x0005 /* * Status values returned from aim_conn_new(). ORed together. @@ -326,7 +371,7 @@ typedef struct aim_conn_s { void *priv; /* misc data the client may want to store */ void *internal; /* internal conn-specific libfaim data */ time_t lastactivity; /* time of last transmit */ - int forcedlatency; + int forcedlatency; void *handlerlist; void *sessv; /* pointer to parent session */ void *inside; /* only accessible from inside libfaim */ @@ -356,7 +401,7 @@ typedef struct aim_bstream_s { typedef struct aim_frame_s { fu8_t hdrtype; /* defines which piece of the union to use */ union { - struct { + struct { fu8_t channel; flap_seqnum_t seqnum; } flap; @@ -412,7 +457,7 @@ typedef struct aim_session_s { * These are only used when you don't use your own lowlevel * I/O. I don't suggest that you use libfaim's internal I/O. * Its really bad and the API/event model is quirky at best. - * + * */ aim_frame_t *queue_outgoing; aim_frame_t *queue_incoming; @@ -471,23 +516,21 @@ typedef struct aim_session_s { } aim_session_t; /* Valid for calling aim_icq_setstatus() and for aim_userinfo_t->icqinfo.status */ -#define AIM_ICQ_STATE_NORMAL 0x00000000 -#define AIM_ICQ_STATE_AWAY 0x00000001 -#define AIM_ICQ_STATE_DND 0x00000002 -#define AIM_ICQ_STATE_OUT 0x00000004 -#define AIM_ICQ_STATE_BUSY 0x00000010 -#define AIM_ICQ_STATE_CHAT 0x00000020 -#define AIM_ICQ_STATE_INVISIBLE 0x00000100 -#define AIM_ICQ_STATE_WEBAWARE 0x00010000 -#define AIM_ICQ_STATE_HIDEIP 0x00020000 -#define AIM_ICQ_STATE_BIRTHDAY 0x00080000 +#define AIM_ICQ_STATE_NORMAL 0x00000000 +#define AIM_ICQ_STATE_AWAY 0x00000001 +#define AIM_ICQ_STATE_DND 0x00000002 +#define AIM_ICQ_STATE_OUT 0x00000004 +#define AIM_ICQ_STATE_BUSY 0x00000010 +#define AIM_ICQ_STATE_CHAT 0x00000020 +#define AIM_ICQ_STATE_INVISIBLE 0x00000100 +#define AIM_ICQ_STATE_WEBAWARE 0x00010000 +#define AIM_ICQ_STATE_HIDEIP 0x00020000 +#define AIM_ICQ_STATE_BIRTHDAY 0x00080000 #define AIM_ICQ_STATE_DIRECTDISABLED 0x00100000 -#define AIM_ICQ_STATE_ICQHOMEPAGE 0x00200000 +#define AIM_ICQ_STATE_ICQHOMEPAGE 0x00200000 #define AIM_ICQ_STATE_DIRECTREQUIREAUTH 0x10000000 #define AIM_ICQ_STATE_DIRECTCONTACTLIST 0x20000000 - - /* * Get command from connections * @@ -587,14 +630,10 @@ faim_export aim_conn_t *aim_getconn_type faim_export aim_conn_t *aim_getconn_type_all(aim_session_t *, int type); faim_export aim_conn_t *aim_getconn_fd(aim_session_t *, int fd); - - /* 0x0001 - service.c */ faim_export int aim_srv_setavailmsg(aim_session_t *sess, const char *msg); faim_export int aim_srv_setidle(aim_session_t *sess, fu32_t idletime); - - /* misc.c */ #define AIM_VISIBILITYCHANGE_PERMITADD 0x05 @@ -684,7 +723,7 @@ struct aim_chat_roominfo { #define AIM_IMFLAGS_BUDDYREQ 0x0010 /* buddy icon requested */ #define AIM_IMFLAGS_HASICON 0x0020 /* already has icon */ #define AIM_IMFLAGS_SUBENC_MACINTOSH 0x0040 /* damn that Steve Jobs! */ -#define AIM_IMFLAGS_CUSTOMFEATURES 0x0080 /* features field present */ +#define AIM_IMFLAGS_CUSTOMFEATURES 0x0080 /* features field present */ #define AIM_IMFLAGS_EXTDATA 0x0100 #define AIM_IMFLAGS_X 0x0200 #define AIM_IMFLAGS_MULTIPART 0x0400 /* ->mpmsg section valid */ @@ -778,7 +817,7 @@ struct aim_incomingim_ch1_args { /* Always provided */ aim_mpmsg_t mpmsg; fu32_t icbmflags; /* some flags apply only to ->msg, not all mpmsg */ - + /* Only provided if message has a human-readable section */ gchar *msg; int msglen; @@ -840,6 +879,9 @@ struct aim_incomingim_ch2_args { fu16_t totfiles; fu32_t totsize; char *filename; + /* reqnum: 0x0001 usually; 0x0002 = reply request for stage 2 proxy transfer */ + fu16_t reqnum; + fu8_t use_proxy; /* Did the user request that we use a rv proxy? */ } sendfile; } info; void *destructor; /* used internally only */ @@ -875,43 +917,56 @@ struct aim_incomingim_ch4_args { /* 0x0008 */ faim_export int aim_im_warn(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags); /* 0x000b */ faim_export int aim_im_denytransfer(aim_session_t *sess, const char *sender, const fu8_t *cookie, fu16_t code); /* 0x0014 */ faim_export int aim_im_sendmtn(aim_session_t *sess, fu16_t type1, const char *sn, fu16_t type2); - +faim_export void aim_im_makecookie(char* cookie); /* ft.c */ struct aim_fileheader_t { #if 0 - char magic[4]; /* 0 */ - fu16_t hdrlen; /* 4 */ - fu16_t hdrtype; /* 6 */ + char magic[4]; /* 0 */ + fu16_t hdrlen; /* 4 */ + fu16_t hdrtype; /* 6 */ #endif - guchar bcookie[8]; /* 8 */ - fu16_t encrypt; /* 16 */ - fu16_t compress; /* 18 */ - fu16_t totfiles; /* 20 */ - fu16_t filesleft; /* 22 */ - fu16_t totparts; /* 24 */ - fu16_t partsleft; /* 26 */ - fu32_t totsize; /* 28 */ - fu32_t size; /* 32 */ - fu32_t modtime; /* 36 */ - fu32_t checksum; /* 40 */ - fu32_t rfrcsum; /* 44 */ - fu32_t rfsize; /* 48 */ - fu32_t cretime; /* 52 */ - fu32_t rfcsum; /* 56 */ - fu32_t nrecvd; /* 60 */ - fu32_t recvcsum; /* 64 */ - char idstring[32]; /* 68 */ - fu8_t flags; /* 100 */ - fu8_t lnameoffset; /* 101 */ - fu8_t lsizeoffset; /* 102 */ - guchar dummy[69]; /* 103 */ - guchar macfileinfo[16]; /* 172 */ - fu16_t nencode; /* 188 */ - fu16_t nlanguage; /* 190 */ - char name[64]; /* 192 */ - /* 256 */ + char bcookie[8]; /* 8 */ + fu16_t encrypt; /* 16 */ + fu16_t compress; /* 18 */ + fu16_t totfiles; /* 20 */ + fu16_t filesleft; /* 22 */ + fu16_t totparts; /* 24 */ + fu16_t partsleft; /* 26 */ + fu32_t totsize; /* 28 */ + fu32_t size; /* 32 */ + fu32_t modtime; /* 36 */ + fu32_t checksum; /* 40 */ + fu32_t rfrcsum; /* 44 */ + fu32_t rfsize; /* 48 */ + fu32_t cretime; /* 52 */ + fu32_t rfcsum; /* 56 */ + fu32_t nrecvd; /* 60 */ + fu32_t recvcsum; /* 64 */ + fu8_t idstring[32]; /* 68 */ + fu8_t flags; /* 100 */ + fu8_t lnameoffset; /* 101 */ + fu8_t lsizeoffset; /* 102 */ + char dummy[69]; /* 103 */ + char macfileinfo[16]; /* 172 */ + fu16_t nencode; /* 188 */ + fu16_t nlanguage; /* 190 */ + char name[64]; /* 192 */ + /* 256 */ +}; + +struct aim_rv_proxy_info { + fu16_t packet_ver; + fu16_t cmd_type; + fu16_t flags; + char* ip; /* IP address sent along with this packet */ + fu16_t port; /* This is NOT the port we should use to connect. Always connect to 5190 */ + fu8_t cookie[8]; + fu32_t unknownA; + fu16_t err_code; /* Valid only for cmd_type of AIM_RV_PROXY_ERROR */ + aim_conn_t *conn; + aim_session_t *sess; }; struct aim_oft_info { @@ -921,11 +976,19 @@ struct aim_oft_info { char *clientip; char *verifiedip; fu16_t port; + + int send_or_recv; /* Send or receive */ + int method; /* What method is being used to transfer this file? DIRECT, REDIR, or PROXY */ + int stage; /* At what stage was a proxy requested? NONE, STG1, STG2*/ + int xfer_reffed; /* There are many timers, but we should only ref the xfer once */ + fu32_t res_bytes; /* The bytes already received for resuming a transfer */ + aim_conn_t *conn; aim_session_t *sess; int success; /* Was the connection successful? Used for timing out the transfer. */ struct aim_fileheader_t fh; struct aim_oft_info *next; + struct aim_rv_proxy_info *proxy_info; }; faim_export fu32_t aim_oft_checksum_chunk(const fu8_t *buffer, int bufferlen, fu32_t prevcheck); @@ -940,12 +1003,21 @@ faim_export aim_conn_t *aim_odc_initiate const fu8_t *localip, fu16_t port, const fu8_t *mycookie); faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie); -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); +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, int send_or_recv, + int method, int stage); faim_export int aim_oft_destroyinfo(struct aim_oft_info *oft_info); +faim_export struct aim_rv_proxy_info *aim_rv_proxy_createinfo(aim_session_t *sess, const fu8_t *cookie, fu16_t port); faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info, int listenfd); faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info); +faim_export int aim_rv_proxy_init_recv(struct aim_rv_proxy_info *proxy_info); +faim_export int aim_rv_proxy_init_send(struct aim_rv_proxy_info *proxy_info); +faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info, int listenfd); +faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info); +int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count); +faim_internal struct aim_rv_proxy_info *aim_rv_proxy_read(aim_session_t *sess, aim_conn_t *conn); /* 0x0002 - locate.c */ /* @@ -1081,8 +1153,8 @@ faim_export aim_userinfo_t *aim_locate_f faim_export void aim_locate_dorequest(aim_session_t *sess); /* 0x0002 */ faim_export int aim_locate_reqrights(aim_session_t *sess); -/* 0x0004 */ faim_export int aim_locate_setprofile(aim_session_t *sess, const char *profile_encoding, const gchar *profile, const int profile_len, const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len); /* 0x0004 */ faim_export int aim_locate_setcaps(aim_session_t *sess, fu32_t caps); +/* 0x0004 */ faim_export int aim_locate_setprofile(aim_session_t *sess, const char *profile_encoding, const gchar *profile, const int profile_len, const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len); /* 0x0005 */ faim_export int aim_locate_getinfo(aim_session_t *sess, const char *, fu16_t); /* 0x0009 */ faim_export int aim_locate_setdirinfo(aim_session_t *sess, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy); /* 0x000b */ faim_export int aim_locate_000b(aim_session_t *sess, const char *sn); Index: ft.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/ft.c,v retrieving revision 1.69 retrieving revision 1.70 diff -u -d -p -r1.69 -r1.70 --- ft.c 13 Aug 2005 06:43:45 -0000 1.69 +++ ft.c 30 Aug 2005 05:21:58 -0000 1.70 @@ -2,40 +2,40 @@ * Oscar File transfer (OFT) and Oscar Direct Connect (ODC). * (ODC is also referred to as DirectIM and IM Image.) * - * There are a few static helper functions at the top, then + * There are a few static helper functions at the top, then * ODC stuff, then ft stuff. * - * I feel like this is a good place to explain OFT, so I'm going to - * do just that. Each OFT packet has a header type. I guess this - * is pretty similar to the subtype of a SNAC packet. The type - * basically tells the other client the meaning of the OFT packet. - * There are two distinct types of file transfer, which I usually - * call "sendfile" and "getfile." Sendfile is when you send a file - * to another AIM user. Getfile is when you share a group of files, + * I feel like this is a good place to explain OFT, so I'm going to + * do just that. Each OFT packet has a header type. I guess this + * is pretty similar to the subtype of a SNAC packet. The type + * basically tells the other client the meaning of the OFT packet. + * There are two distinct types of file transfer, which I usually + * call "sendfile" and "getfile." Sendfile is when you send a file + * to another AIM user. Getfile is when you share a group of files, * and other users request that you send them the files. * * A typical sendfile file transfer goes like this: - * 1) Sender sends a channel 2 ICBM telling the other user that - * we want to send them a file. At the same time, we open a - * listener socket (this should be done before sending the - * ICBM) on some port, and wait for them to connect to us. - * The ICBM we sent should contain our IP address and the port + * 1) Sender sends a channel 2 ICBM telling the other user that + * we want to send them a file. At the same time, we open a + * listener socket (this should be done before sending the + * ICBM) on some port, and wait for them to connect to us. + * The ICBM we sent should contain our IP address and the port * number that we're listening on. - * 2) The receiver connects to the sender on the given IP address - * and port. After the connection is established, the receiver + * 2) The receiver connects to the sender on the given IP address + * and port. After the connection is established, the receiver * sends an ICBM signifying that we are ready and waiting. - * 3) The sender sends an OFT PROMPT message over the OFT + * 3) The sender sends an OFT PROMPT message over the OFT * connection. - * 4) The receiver of the file sends back an exact copy of this - * OFT packet, except the cookie is filled in with the cookie - * from the ICBM. I think this might be an attempt to verify - * that the user that is connected is actually the guy that + * 4) The receiver of the file sends back an exact copy of this + * OFT packet, except the cookie is filled in with the cookie + * from the ICBM. I think this might be an attempt to verify + * that the user that is connected is actually the guy that * we sent the ICBM to. Oh, I've been calling this the ACK. - * 5) The sender starts sending raw data across the connection + * 5) The sender starts sending raw data across the connection * until the entire file has been sent. - * 6) The receiver knows the file is finished because the sender - * sent the file size in an earlier OFT packet. So then the - * receiver sends the DONE thingy (after filling in the + * 6) The receiver knows the file is finished because the sender + * sent the file size in an earlier OFT packet. So then the + * receiver sends the DONE thingy (after filling in the * "received" checksum and size) and closes the connection. */ @@ -112,18 +112,18 @@ static void aim_oft_dirconvert_fromstupi /** * Calculate oft checksum of buffer * - * Prevcheck should be 0xFFFF0000 when starting a checksum of a file. The - * checksum is kind of a rolling checksum thing, so each time you get bytes - * of a file you just call this puppy and it updates the checksum. You can - * calculate the checksum of an entire file by calling this in a while or a + * Prevcheck should be 0xFFFF0000 when starting a checksum of a file. The + * checksum is kind of a rolling checksum thing, so each time you get bytes + * of a file you just call this puppy and it updates the checksum. You can + * calculate the checksum of an entire file by calling this in a while or a * for loop, or something. * - * Thanks to Graham Booker for providing this improved checksum routine, - * which is simpler and should be more accurate than Josh Myer's original + * Thanks to Graham Booker for providing this improved checksum routine, + * which is simpler and should be more accurate than Josh Myer's original * code. -- wtm * - * This algorithm works every time I have tried it. The other fails - * sometimes. So, AOL who thought this up? It has got to be the weirdest + * This algorithm works every time I have tried it. The other fails + * sometimes. So, AOL who thought this up? It has got to be the weirdest * checksum I have ever seen. * * @param buffer Buffer of data to checksum. Man I'd like to buff her... @@ -144,7 +144,7 @@ faim_export fu32_t aim_oft_checksum_chun val = buffer[i] << 8; check -= val; /* - * The following appears to be necessary.... It happens + * The following appears to be necessary.... It happens * every once in a while and the checksum doesn't fail. */ if (check > oldcheck) @@ -244,7 +244,7 @@ faim_export int aim_handlerendconnect(ai * * @param sess The session. * @param conn The already-connected ODC connection. - * @param typing If 0x0002, sends a "typing" message, 0x0001 sends "typed," and + * @param typing If 0x0002, sends a "typing" message, 0x0001 sends "typed," and * 0x0000 sends "stopped." * @return Return 0 if no errors, otherwise return the error number. */ @@ -317,7 +317,7 @@ faim_export int aim_odc_send_typing(aim_ /** * Send client-to-client IM over an established direct connection. * Call this just like you would aim_send_im, to send a directim. - * + * * @param sess The session. * @param conn The already-connected ODC connection. * @param msg Null-terminated string to send. @@ -384,7 +384,7 @@ faim_export int aim_odc_send_im(aim_sess /* end of hdr2 */ -#if 0 /* XXX - this is how you send buddy icon info... */ +#if 0 /* XXX - this is how you send buddy icon info... */ aimbs_put16(hdrbs, 0x0008); aimbs_put16(hdrbs, 0x000c); aimbs_put16(hdrbs, 0x0000); @@ -446,7 +446,7 @@ faim_export const guchar *aim_odc_getcoo * * @param sess The session. * @param sn The screen name of the buddy whose direct connection you want to find. - * @return The conn for the direct connection with the given buddy, or NULL if no + * @return The conn for the direct connection with the given buddy, or NULL if no * connection was found. */ faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn) @@ -534,7 +534,7 @@ faim_export aim_conn_t *aim_odc_initiate * * This is a wrapper for aim_newconn. * - * If addr is NULL, the socket is not created, but the connection is + * If addr is NULL, the socket is not created, but the connection is * allocated and setup to connect. * * @param sess The Godly session. @@ -631,7 +631,7 @@ static int handlehdr_odc(aim_session_t * while (payloadlength - recvd) { if (payloadlength - recvd >= 1024) i = aim_recv(conn->fd, &msg[recvd], 1024); - else + else i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd); if (i <= 0) { free(msg); @@ -642,7 +642,7 @@ static int handlehdr_odc(aim_session_t * if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) ret = userfunc(sess, &fr, snptr, (double)recvd / payloadlength); } - + if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING))) ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding, isawaymsg); @@ -654,7 +654,7 @@ static int handlehdr_odc(aim_session_t * return ret; } -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) +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, int send_or_recv, int method, int stage) { struct aim_oft_info *new; @@ -667,11 +667,21 @@ faim_export struct aim_oft_info *aim_oft new->sess = sess; if (cookie) memcpy(new->cookie, cookie, 8); + else + aim_im_makecookie(new->cookie); if (ip) new->clientip = strdup(ip); + else + new->clientip = NULL; if (sn) new->sn = strdup(sn); + else + new->sn = NULL; + new->method = method; + new->send_or_recv = send_or_recv; + new->stage = stage; new->port = port; + new->xfer_reffed = FALSE; new->success = FALSE; new->fh.totfiles = 1; new->fh.filesleft = 1; @@ -696,8 +706,27 @@ faim_export struct aim_oft_info *aim_oft return new; } +faim_export struct aim_rv_proxy_info *aim_rv_proxy_createinfo(aim_session_t *sess, const fu8_t *cookie, + fu16_t port) +{ + struct aim_rv_proxy_info *proxy_info; + + if (!(proxy_info = (struct aim_rv_proxy_info*)calloc(1, sizeof(struct aim_rv_proxy_info)))) + return NULL; + + proxy_info->sess = sess; + proxy_info->port = port; + proxy_info->packet_ver = AIM_RV_PROXY_PACKETVER_DFLT; + proxy_info->unknownA = AIM_RV_PROXY_UNKNOWNA_DFLT; + + if (cookie) + memcpy(proxy_info->cookie, cookie, 8); + + return proxy_info; +} + /** - * Remove the given oft_info struct from the oft_info linked list, and + * Remove the given oft_info struct from the oft_info linked list, and * then free its memory. * * @param sess The session. @@ -732,13 +761,13 @@ faim_export int aim_oft_destroyinfo(stru /** * Creates a listener socket so the other dude can connect to us. * - * You'll want to set up some kind of watcher on this socket. - * When the state changes, call aim_handlerendconnection with - * the connection returned by this. aim_handlerendconnection + * You'll want to set up some kind of watcher on this socket. + * When the state changes, call aim_handlerendconnection with + * the connection returned by this. aim_handlerendconnection * will accept the pending connection and stop listening. * * @param sess The session. - * @param oft_info File transfer information associated with this + * @param oft_info File transfer information associated with this * connection. * @return Return 0 if no errors, otherwise return the error number. */ @@ -802,7 +831,7 @@ static struct aim_fileheader_t *aim_oft_ fh->name[63] = '\0'; return fh; -} +} /** * Fills a buffer with network-order fh data @@ -812,7 +841,7 @@ static struct aim_fileheader_t *aim_oft_ * @return Return non-zero on error. */ static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) -{ +{ fu8_t *hdr; if (!bs || !fh) @@ -857,7 +886,7 @@ static int aim_oft_buildheader(aim_bstre * * @param sess The session. * @param type The subtype of the OFT packet we're sending. - * @param oft_info The aim_oft_info struct with the connection and OFT + * @param oft_info The aim_oft_info struct with the connection and OFT * info we're sending. * @return Return 0 if no errors, otherwise return the error number. */ @@ -870,8 +899,8 @@ faim_export int aim_oft_sendheader(aim_s #if 0 /* - * If you are receiving a file, the cookie should be null, if you are sending a - * file, the cookie should be the same as the one used in the ICBM negotiation + * If you are receiving a file, the cookie should be null, if you are sending a + * file, the cookie should be the same as the one used in the ICBM negotiation * SNACs. */ fh->lnameoffset = 0x1a; @@ -901,13 +930,142 @@ faim_export int aim_oft_sendheader(aim_s } /** - * Handle incoming data on a rendezvous connection. This is analogous to the - * consumesnac function in rxhandlers.c, and I really think this should probably + * Create a rendezvous "init recv" packet and send it on its merry way. + * This is the first packet sent to the proxy server by the second client + * involved in this rendezvous proxy session. + * + * @param sess The session. + * @param proxy_info Changable pieces of data for this packet + * @return Return 0 if no errors, otherwise return the error number. + */ +faim_export int aim_rv_proxy_init_recv(struct aim_rv_proxy_info *proxy_info) +{ + //aim_tlvlist_t *tlvlist_sendfile; + aim_bstream_t bs; + fu8_t *bs_raw; + fu16_t packet_len; + fu8_t sn_len; + int err; + + err = 0; + + if (!proxy_info) + return -EINVAL; + + sn_len = strlen(proxy_info->sess->sn); + packet_len = 2 + 2 /* packet_len, packet_ver */ + + 2 + 4 /* cmd_type, unknownA */ + + 2 /* flags */ + + 1 + sn_len /* Length/value pair for screenname */ + + 8 /* ICBM Cookie */ + + 2 /* port */ + + 2 + 2 + 16; /* TLV for Filesend capability block */ + + if (!(bs_raw = malloc(packet_len))) + return -ENOMEM; + + aim_bstream_init(&bs, bs_raw, packet_len); + aimbs_put16(&bs, packet_len - 2); /* Length includes only packets after length marker */ + aimbs_put16(&bs, proxy_info->packet_ver); + aimbs_put16(&bs, AIM_RV_PROXY_INIT_RECV); + aimbs_put32(&bs, proxy_info->unknownA); + aimbs_put16(&bs, proxy_info->flags); + aimbs_put8(&bs, sn_len); + aimbs_putraw(&bs, proxy_info->sess->sn, sn_len); + aimbs_put16(&bs, proxy_info->port); + aimbs_putraw(&bs, proxy_info->cookie, 8); + + aimbs_put16(&bs, 0x0001); /* Type */ + aimbs_put16(&bs, 16); /* Length */ + aimbs_putcaps(&bs, AIM_CAPS_SENDFILE); /* Value */ + + // TODO: Use built-in TLV + //aim_tlvlist_add_caps(&tlvlist_sendfile, 0x0001, AIM_CAPS_SENDFILE); + //aim_tlvlist_write(&bs, &tlvlist_sendfile); + + aim_bstream_rewind(&bs); + if (aim_bstream_send(&bs, proxy_info->conn, packet_len) != packet_len) + err = errno; + proxy_info->conn->lastactivity = time(NULL); + + //aim_tlvlist_free(tlvlist_sendfile); + free(bs_raw); + + return err; +} + + +/** + * Create a rendezvous "init send" packet and send it on its merry way. + * This is the first packet sent to the proxy server by the client + * first indicating that this will be a proxied connection + * + * @param sess The session. + * @param proxy_info Changable pieces of data for this packet + * @return Return 0 if no errors, otherwise return the error number. + */ +faim_export int aim_rv_proxy_init_send(struct aim_rv_proxy_info *proxy_info) +{ + //aim_tlvlist_t *tlvlist_sendfile; + aim_bstream_t bs; + fu8_t *bs_raw; + fu16_t packet_len; + fu8_t sn_len; + int err; + + err = 0; + + if (!proxy_info) + return -EINVAL; + + sn_len = strlen(proxy_info->sess->sn); + packet_len = 2 + 2 /* packet_len, packet_ver */ + + 2 + 4 /* cmd_type, unknownA */ + + 2 /* flags */ + + 1 + sn_len /* Length/value pair for screenname */ + + 8 /* ICBM Cookie */ + + 2 + 2 + 16; /* TLV for Filesend capability block */ + + if (!(bs_raw = malloc(packet_len))) + return -ENOMEM; + + aim_bstream_init(&bs, bs_raw, packet_len); + aimbs_put16(&bs, packet_len - 2); /* Length includes only packets after length marker */ + aimbs_put16(&bs, proxy_info->packet_ver); + aimbs_put16(&bs, AIM_RV_PROXY_INIT_SEND); + aimbs_put32(&bs, proxy_info->unknownA); + aimbs_put16(&bs, proxy_info->flags); + aimbs_put8(&bs, sn_len); + aimbs_putraw(&bs, proxy_info->sess->sn, sn_len); + aimbs_putraw(&bs, proxy_info->cookie, 8); + + aimbs_put16(&bs, 0x0001); /* Type */ + aimbs_put16(&bs, 16); /* Length */ + aimbs_putcaps(&bs, AIM_CAPS_SENDFILE); /* Value */ + + // TODO: Use built-in TLV + //aim_tlvlist_add_caps(&tlvlist_sendfile, 0x0001, AIM_CAPS_SENDFILE); + //aim_tlvlist_write(&bs, &tlvlist_sendfile); + + aim_bstream_rewind(&bs); + if (aim_bstream_send(&bs, proxy_info->conn, packet_len) != packet_len) + err = errno; + proxy_info->conn->lastactivity = time(NULL); + + //aim_tlvlist_free(tlvlist_sendfile); + free(bs_raw); + + return err; +} + +/** + * Handle incoming data on a rendezvous connection. This is analogous to the + * consumesnac function in rxhandlers.c, and I really think this should probably * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet. * * @param sess The session. * @param fr The frame allocated for the incoming data. - * @return Return 0 if the packet was handled correctly, otherwise return the + * @return Return 0 if the packet was handled correctly, otherwise return the * error number. */ faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) @@ -937,3 +1095,101 @@ faim_internal int aim_rxdispatch_rendezv return ret; } + +/** + * Handle incoming data on a rendezvous proxy connection. This is similar to + * aim_rxdispatch_rendezvous above and should probably be kept with that function. + * + * @param sess The session. + * @param fr The frame allocated for the incoming data. + * @return Return 0 if the packet was handled correctly, otherwise return the + * error number. + */ +faim_internal struct aim_rv_proxy_info *aim_rv_proxy_read(aim_session_t *sess, aim_conn_t *conn) +{ + aim_bstream_t bs_hdr; + fu8_t hdr_buf[AIM_RV_PROXY_HDR_LEN]; + aim_bstream_t bs_body; /* The body (everything but the header) of the packet */ + fu8_t *body_buf = NULL; + fu8_t body_len; + + char str_ip[30] = {""}; + fu8_t ip_temp[4]; + + fu16_t len; + struct aim_rv_proxy_info *proxy_info; + + if(!(proxy_info = malloc(sizeof(struct aim_rv_proxy_info)))) + return NULL; + + aim_bstream_init(&bs_hdr, hdr_buf, AIM_RV_PROXY_HDR_LEN); + if (aim_bstream_recv(&bs_hdr, conn->fd, AIM_RV_PROXY_HDR_LEN) == AIM_RV_PROXY_HDR_LEN) { + aim_bstream_rewind(&bs_hdr); + len = aimbs_get16(&bs_hdr); + proxy_info->packet_ver = aimbs_get16(&bs_hdr); + proxy_info->cmd_type = aimbs_get16(&bs_hdr); + proxy_info->unknownA = aimbs_get32(&bs_hdr); + proxy_info->flags = aimbs_get16(&bs_hdr); + if(proxy_info->cmd_type == AIM_RV_PROXY_READY) { + /* Do a little victory dance + * A ready packet contains no additional information */ + } else if(proxy_info->cmd_type == AIM_RV_PROXY_ERROR) { + if(len == AIM_RV_PROXY_ERROR_LEN - 2) { + body_len = AIM_RV_PROXY_ERROR_LEN - AIM_RV_PROXY_HDR_LEN; + body_buf = malloc(body_len); + aim_bstream_init(&bs_body, body_buf, body_len); + if (aim_bstream_recv(&bs_body, conn->fd, body_len) == body_len) { + aim_bstream_rewind(&bs_body); + proxy_info->err_code = aimbs_get16(&bs_body); + } else { + gaim_debug_warning("oscar","error reading rv proxy error packet\n"); + aim_conn_close(conn); + free(proxy_info); + proxy_info = NULL; + } + } else { + gaim_debug_warning("oscar","invalid length for proxy error packet\n"); + free(proxy_info); + proxy_info = NULL; + } + } else if(proxy_info->cmd_type == AIM_RV_PROXY_ACK) { + if(len == AIM_RV_PROXY_ACK_LEN - 2) { + body_len = AIM_RV_PROXY_ACK_LEN - AIM_RV_PROXY_HDR_LEN; + body_buf = malloc(body_len); + aim_bstream_init(&bs_body, body_buf, body_len); + if (aim_bstream_recv(&bs_body, conn->fd, body_len) == body_len) { + aim_bstream_rewind(&bs_body); + proxy_info->port = aimbs_get16(&bs_body); + int i; + for(i=0; i<4; i++) + ip_temp[i] = aimbs_get8(&bs_body); + snprintf(str_ip, sizeof(str_ip), "%hhu.%hhu.%hhu.%hhu", + ip_temp[0], ip_temp[1], + ip_temp[2], ip_temp[3]); + proxy_info->ip = strdup(str_ip); + } else { + gaim_debug_warning("oscar","error reading rv proxy error packet\n"); + aim_conn_close(conn); + free(proxy_info); + proxy_info = NULL; + } + } else { + gaim_debug_warning("oscar","invalid length for proxy error packet\n"); + free(proxy_info); + proxy_info = NULL; + } + } else { + gaim_debug_warning("oscar","unknown type for aim rendezvous proxy packet\n"); + } + } else { + gaim_debug_warning("oscar","error reading header of rv proxy packet\n"); + aim_conn_close(conn); + free(proxy_info); + proxy_info = NULL; + } + if(body_buf) { + free(body_buf); + body_buf = NULL; + } + return proxy_info; +} Index: im.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/im.c,v retrieving revision 1.77 retrieving revision 1.78 diff -u -d -p -r1.77 -r1.78 --- im.c 17 Aug 2005 02:37:14 -0000 1.77 +++ im.c 30 Aug 2005 05:21:58 -0000 1.78 @@ -83,11 +83,11 @@ faim_export fu16_t aim_im_fingerprint(co fu8_t data[10]; } fingerprints[] = { /* AOL Mobile Communicator, WinAIM 1.0.414 */ - { AIM_CLIENTTYPE_MC, + { AIM_CLIENTTYPE_MC, 3, {0x01, 0x01, 0x01}}, /* WinAIM 2.0.847, 2.1.1187, 3.0.1464, 4.3.2229, 4.4.2286 */ - { AIM_CLIENTTYPE_WINAIM, + { AIM_CLIENTTYPE_WINAIM, 3, {0x01, 0x01, 0x02}}, /* WinAIM 4.1.2010, libfaim */ @@ -144,10 +144,10 @@ faim_export int aim_im_setparams(aim_ses aimbs_put16(&fr->data, 0x0000); /* These are all read-write */ - aimbs_put32(&fr->data, params->flags); + aimbs_put32(&fr->data, params->flags); aimbs_put16(&fr->data, params->maxmsglen); - aimbs_put16(&fr->data, params->maxsenderwarn); - aimbs_put16(&fr->data, params->maxrecverwarn); + aimbs_put16(&fr->data, params->maxsenderwarn); + aimbs_put16(&fr->data, params->maxrecverwarn); aimbs_put32(&fr->data, params->minmsginterval); aim_tx_enqueue(sess, fr); @@ -184,7 +184,7 @@ static int aim_im_paraminfo(aim_session_ params.maxsenderwarn = aimbs_get16(bs); params.maxrecverwarn = aimbs_get16(bs); params.minmsginterval = aimbs_get32(bs); - + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) return userfunc(sess, rx, ¶ms); @@ -282,7 +282,7 @@ faim_export int aim_im_sendch1_ext(aim_s if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128))) return -ENOMEM; - /* XXX - should be optional */ + /* XXX - should be optional */ snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); @@ -432,7 +432,7 @@ faim_export int aim_im_sendch2_chatinvit fu8_t *hdr; int hdrlen; aim_bstream_t hdrbs; - + if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) return -EINVAL; @@ -490,7 +490,7 @@ faim_export int aim_im_sendch2_chatinvit aim_tlvlist_add_str(&itl, 0x000c, msg); aim_tlvlist_add_chatroom(&itl, 0x2711, exchange, roomname, instance); aim_tlvlist_write(&hdrbs, &itl); - + aim_tlvlist_add_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); aim_tlvlist_write(&fr->data, &otl); @@ -498,7 +498,7 @@ faim_export int aim_im_sendch2_chatinvit free(hdr); aim_tlvlist_free(&itl); aim_tlvlist_free(&otl); - + aim_tx_enqueue(sess, fr); return 0; @@ -731,7 +731,7 @@ faim_export int aim_im_sendch2_odcreques aim_tlvlist_add_raw(&itl, 0x0003, 4, ip); aim_tlvlist_add_16(&itl, 0x0005, port); aim_tlvlist_add_noval(&itl, 0x000f); - + aim_tlvlist_write(&hdrbs, &itl); aim_tlvlist_add_raw(&tl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); @@ -747,6 +747,22 @@ faim_export int aim_im_sendch2_odcreques return 0; } +/* + * Extracted from aim_im_sendch2_sendfile_ask + * Generates a random ICBM cookie in a character array of length 8 + * and copies it into the variable passed as cookie + */ +faim_export void aim_im_makecookie(char* cookie) { + int i; + char gen_cookie[8]; + + /* XXX - Should be like "21CBF95" and null terminated */ + for (i = 0; i < 7; i++) + gen_cookie[i] = 0x30 + ((fu8_t)rand() % 10); + gen_cookie[7] = '\0'; + memcpy(cookie, gen_cookie, 8); +} + /** * Subtype 0x0006 - Send an "I want to send you this file" message * @@ -757,55 +773,112 @@ faim_export int aim_im_sendch2_sendfile_ aim_frame_t *fr; aim_snacid_t snacid; aim_tlvlist_t *tl=NULL, *subtl=NULL; - int i; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info) return -EINVAL; - /* XXX - Should be like "21CBF95" and null terminated */ - for (i = 0; i < 7; i++) - oft_info->cookie[i] = 0x30 + ((fu8_t)rand() % 10); - oft_info->cookie[7] = '\0'; + /* The cookie must already have been generated by this point */ { /* Create the subTLV chain */ fu8_t *buf; int buflen; aim_bstream_t bs; + fu8_t ip[4]; + fu8_t ip_comp[4]; /* The bitwise complement of the ip */ + char *nexttoken; + int i; - aim_tlvlist_add_16(&subtl, 0x000a, 0x0001); - aim_tlvlist_add_noval(&subtl, 0x000f); + /* In a stage 2 proxied transfer & a transfer redirect, we send a second "reply request" + * Being the second request for this transfer, its request number is 2 + * You can fill in the blank for a stage 3's request number... */ + if( (oft_info->send_or_recv == AIM_XFER_RECV && oft_info->stage == AIM_XFER_PROXY_STG2) + || (oft_info->send_or_recv == AIM_XFER_RECV + && oft_info->stage == AIM_XFER_PROXY_STG3) + || oft_info->method == AIM_XFER_REDIR) + aim_tlvlist_add_16(&subtl, 0x000a, 0x0002); + else if(oft_info->send_or_recv == AIM_XFER_SEND && oft_info->stage == AIM_XFER_PROXY_STG3) + aim_tlvlist_add_16(&subtl, 0x000a, 0x0003); + else + aim_tlvlist_add_16(&subtl, 0x000a, 0x0001); + + /* This is usually necessary, but ruins a redirect and a stg3 proxy request */ + if(!(oft_info->send_or_recv == AIM_XFER_RECV + && (oft_info->method == AIM_XFER_REDIR || oft_info->stage == AIM_XFER_PROXY_STG3))) { + aim_tlvlist_add_noval(&subtl, 0x000f); + } + + /* If the following is ever enabled, ensure that it is not sent with a receive redirect + * or stage 3 proxy redirect for a file receive (same conditions for sending 0x000f above) */ /* aim_tlvlist_add_raw(&subtl, 0x000e, 2, "en"); aim_tlvlist_add_raw(&subtl, 0x000d, 8, "us-ascii"); aim_tlvlist_add_raw(&subtl, 0x000c, 24, "Please accept this file."); */ /* XXX - Change oft_info->clientip to an array of 4 bytes */ if (oft_info->clientip) { - fu8_t ip[4]; - char *nexttoken; - int i = 0; + i = 0; nexttoken = strtok(oft_info->clientip, "."); while (nexttoken && i<4) { ip[i] = atoi(nexttoken); + ip_comp[i] = ~ip[i]; nexttoken = strtok(NULL, "."); i++; } + + /* If there is no proxyip, we must fill it in with the clientip */ + if(!oft_info->proxyip) { + aim_tlvlist_add_raw(&subtl, 0x0002, 4, ip); + aim_tlvlist_add_raw(&subtl, 0x0016, 4, ip_comp); /* check? value */ + } + aim_tlvlist_add_raw(&subtl, 0x0003, 4, ip); } - aim_tlvlist_add_16(&subtl, 0x0005, oft_info->port); - - /* TLV t(2711) */ - buflen = 2+2+4+strlen(oft_info->fh.name)+1; - buf = malloc(buflen); - aim_bstream_init(&bs, buf, buflen); - aimbs_put16(&bs, (oft_info->fh.totfiles > 1) ? 0x0002 : 0x0001); - aimbs_put16(&bs, oft_info->fh.totfiles); - aimbs_put32(&bs, oft_info->fh.totsize); - - /* Filename - NULL terminated, for some odd reason */ - aimbs_putstr(&bs, oft_info->fh.name); - aimbs_put8(&bs, 0x00); + + /* Don't send the proxyip & accompanying info during a receive redirect or stg3 proxy request */ + if(!(oft_info->send_or_recv == AIM_XFER_RECV + && (oft_info->method == AIM_XFER_REDIR || oft_info->stage == AIM_XFER_PROXY_STG3))) { + if (oft_info->proxyip) { /* Generate the proxyip */ + i = 0; + nexttoken = strtok(oft_info->proxyip, "."); + while (nexttoken && i<4) { + ip[i] = atoi(nexttoken); + ip_comp[i] = ~ip[i]; + nexttoken = strtok(NULL, "."); + i++; + } + aim_tlvlist_add_raw(&subtl, 0x0002, 4, ip); + /* This zero-length TLV specifies a proxy will be used */ + aim_tlvlist_add_noval(&subtl, 0x0010); + + /* Proxied transfers fail without this next (check?) value */ + aim_tlvlist_add_raw(&subtl, 0x0016, 4, ip_comp); + } + } + + /* Don't send the port & its check during a stage 3 proxy request */ + if(!(oft_info->send_or_recv == AIM_XFER_RECV && oft_info->stage == AIM_XFER_PROXY_STG3)) { + aim_tlvlist_add_16(&subtl, 0x0005, oft_info->port); + + /* Check value? Bitwise complement of the port */ + aim_tlvlist_add_16(&subtl, 0x0017, ~(oft_info->port)); + } - aim_tlvlist_add_raw(&subtl, 0x2711, bs.len, bs.data); - free(buf); + /* winAIM gets mad at us if we send too much info during a send redirect or stg3 proxy request */ + if(!(oft_info->send_or_recv == AIM_XFER_RECV + && (oft_info->method == AIM_XFER_REDIR || oft_info->stage == AIM_XFER_PROXY_STG3))) { + /* TLV t(2711) */ + buflen = 2+2+4+strlen(oft_info->fh.name)+1; + buf = malloc(buflen); + aim_bstream_init(&bs, buf, buflen); + aimbs_put16(&bs, (oft_info->fh.totfiles > 1) ? 0x0002 : 0x0001); + aimbs_put16(&bs, oft_info->fh.totfiles); + aimbs_put32(&bs, oft_info->fh.totsize); + + /* Filename - NULL terminated, for some odd reason */ + aimbs_putstr(&bs, oft_info->fh.name); + aimbs_put8(&bs, 0x00); + + aim_tlvlist_add_raw(&subtl, 0x2711, bs.len, bs.data); + free(buf); + } } { /* Create the main TLV chain */ @@ -1143,7 +1216,7 @@ static int outgoingim(aim_session_t *ses flag1 = aimbs_get16(&mbs); flag2 = aimbs_get16(&mbs); - msg = aimbs_getraw(&mbs, msglen); + msg = aimbs_getstr(&mbs, msglen); } if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) @@ -1202,8 +1275,8 @@ faim_export int aim_mpmsg_init(aim_sessi static int mpmsg_addsection(aim_session_t *sess, aim_mpmsg_t *mpm, fu16_t charset, fu16_t charsubset, gchar *data, fu16_t datalen) { - aim_mpmsg_section_t *sec; - + aim_mpmsg_section_t *sec; + if (!(sec = malloc(sizeof(aim_mpmsg_section_t)))) return -1; @@ -1249,7 +1322,7 @@ faim_export int aim_mpmsg_addascii(aim_s { gchar *dup; - if (!(dup = strdup(ascii))) + if (!(dup = strdup(ascii))) return -1; if (mpmsg_addsection(sess, mpm, 0x0000, 0x0000, dup, strlen(ascii)) == -1) { @@ -1279,7 +1352,7 @@ faim_export int aim_mpmsg_addunicode(aim free(buf); return -1; } - + return 0; } @@ -1289,13 +1362,13 @@ faim_export void aim_mpmsg_free(aim_sess for (cur = mpm->parts; cur; ) { aim_mpmsg_section_t *tmp; - + tmp = cur->next; free(cur->data); free(cur); cur = tmp; } - + mpm->numparts = 0; mpm->parts = NULL; @@ -1733,6 +1806,9 @@ static void incomingim_ch2_sendfile(aim_ /* There is sometimes more after the null-terminated filename, * but I'm unsure of its format. */ /* I don't believe him. */ + /* There is sometimes a null byte inside a unicode filename, + * but as far as I can tell the filename is the last + * piece of data that will be in this message. --Jonathan */ } return; @@ -1847,8 +1923,15 @@ static int incomingim_ch2(aim_session_t * 0x0002 - "I will accept this file from you" * 0x0002 - Also used in ICQ Lite Beta 4.0 URLs */ + /* + * This is what I call the request number of the file transfer + * 0x0001 - Initial file transfer request for no proxy or stage 1 proxy + * 0x0002 - "Reply request" for a stage 2 proxy (receiver wants to use proxy) + * 0x0003 - A third request has been sent; applies only to stage 3 proxied transfers + * -- Jonathan + */ if (aim_tlv_gettlv(list2, 0x000a, 1)) - ; + args.info.sendfile.reqnum = aim_tlv_get16(list2, 0x000a, 1); /* * Error code. @@ -1869,7 +1952,7 @@ static int incomingim_ch2(aim_session_t */ if (aim_tlv_gettlv(list2, 0x000d, 1)) args.encoding = aim_tlv_getstr(list2, 0x000d, 1); - + /* * Language. */ @@ -1882,16 +1965,18 @@ static int incomingim_ch2(aim_session_t * Maybe means we should connect directly to transfer the file? * Also used in ICQ Lite Beta 4.0 URLs. Also empty. */ + /* I don't think this indicates a direct transfer; this flag is + * also present in a stage 1 proxied file send request -- Jonathan */ if (aim_tlv_gettlv(list2, 0x000f, 1)) ; /* - * Unknown -- no value - * - * Maybe means we should proxy the file transfer through an AIM server? + * Flag meaning we should proxy the file transfer through an AIM server */ if (aim_tlv_gettlv(list2, 0x0010, 1)) - ; + args.info.sendfile.use_proxy = TRUE; + else + args.info.sendfile.use_proxy = FALSE; if (strlen(proxyip)) args.proxyip = (char *)proxyip; @@ -2100,7 +2185,7 @@ faim_export int aim_im_warn(aim_session_ snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1); aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid); - aimbs_put16(&fr->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000); + aimbs_put16(&fr->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000); aimbs_put8(&fr->data, strlen(sn)); aimbs_putstr(&fr->data, sn); @@ -2117,7 +2202,7 @@ static int missedcall(aim_session_t *ses fu16_t channel, nummissed, reason; aim_userinfo_t userinfo; - while (aim_bstream_empty(bs)) { + while (aim_bstream_empty(bs)) { channel = aimbs_get16(bs); aim_info_extract(sess, bs, &userinfo); @@ -2140,7 +2225,7 @@ static int missedcall(aim_session_t *ses * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support" * AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer" * AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers" - * + * */ faim_export int aim_im_denytransfer(aim_session_t *sess, const char *sender, const fu8_t *cookie, fu16_t code) { @@ -2148,7 +2233,7 @@ faim_export int aim_im_denytransfer(aim_ aim_frame_t *fr; aim_snacid_t snacid; aim_tlvlist_t *tl = NULL; - + if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) return -EINVAL; @@ -2157,7 +2242,7 @@ faim_export int aim_im_denytransfer(aim_ snacid = aim_cachesnac(sess, 0x0004, 0x000b, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0004, 0x000b, 0x0000, snacid); - + aimbs_putraw(&fr->data, cookie, 8); aimbs_put16(&fr->data, 0x0002); /* channel */ Index: oscar.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/oscar.c,v retrieving revision 1.777 retrieving revision 1.778 diff -u -d -p -r1.777 -r1.778 --- oscar.c 28 Aug 2005 22:21:24 -0000 1.777 +++ oscar.c 30 Aug 2005 05:21:58 -0000 1.778 @@ -68,8 +68,11 @@ #define OSCAR_DEFAULT_HIDE_IP TRUE #define OSCAR_DEFAULT_WEB_AWARE FALSE -/* Seconds each file transfer ip address will be given to make a connection */ -#define FT_IP_TIMEOUT 15 +/* Milliseconds each file transfer ip address will be given to make a connection. */ +#define FT_CLIENTIP_TIMEOUT 1000 /* 5000 */ +#define FT_VERIFIEDIP_TIMEOUT 5000 /* 15000 */ +#define FT_REDIR_TIMEOUT 10000 /* 20000 */ /* Time to wait for redirected transfer */ +#define FT_PROXYIP_TIMEOUT 300000 /* 120000 */ /* Time to create a checksum for VERY large files */ [...1520 lines suppressed...] - NULL, /**< prefs_info */ -#else - NULL, /**< prefs_info */ -#endif + &prefs_info, oscar_actions }; @@ -7870,9 +8491,11 @@ init_plugin(GaimPlugin *plugin) option = gaim_account_option_string_new(_("Encoding"), "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + /* Preferences */ gaim_prefs_add_none("/plugins/prpl/oscar"); gaim_prefs_add_bool("/plugins/prpl/oscar/recent_buddies", FALSE); gaim_prefs_add_bool("/plugins/prpl/oscar/show_idle", FALSE); + gaim_prefs_add_bool("/plugins/prpl/oscar/use_rv_proxy", FALSE); } GAIM_INIT_PLUGIN(oscar, init_plugin, info); Index: txqueue.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/txqueue.c,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -p -r1.16 -r1.17 --- txqueue.c 13 Aug 2005 06:43:45 -0000 1.16 +++ txqueue.c 30 Aug 2005 05:21:58 -0000 1.17 @@ -213,7 +213,7 @@ static int aim_send(int fd, const void * return cur; } -static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count) +int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count) { int wrote = 0; |