Mercurial > pidgin
annotate src/protocols/oscar/ft.c @ 4891:cfa045006bec
[gaim-migrate @ 5221]
this saves the blist.xml file to an alternate name, and then moves it, that
way we don't lose your precious buddies if gaim crashes.
Of course, if gaim were to crash, it wouldn't be gaim's fault, it would be
the fault of some external force. This is because gaim is perfect, and
Sean is perfect. Yeah.
This should be done for .gaimrc too, but i'm too tired to do that right now.
committer: Tailor Script <tailor@pidgin.im>
| author | Nathan Walp <nwalp@pidgin.im> |
|---|---|
| date | Tue, 25 Mar 2003 06:35:45 +0000 |
| parents | 26837f462a66 |
| children | 9e50494f63a1 |
| rev | line source |
|---|---|
| 2086 | 1 /* |
| 4617 | 2 * Oscar File transfer (OFT) and Oscar Direct Connect (ODC). |
| 3 * (ODC is also referred to as DirectIM and IM Image.) | |
| 4 * | |
| 5 * There are a few static helper functions at the top, then | |
| 6 * ODC stuff, then ft stuff. | |
| 7 * | |
| 8 * I feel like this is a good place to explain OFT, so I'm going to | |
| 9 * do just that. Each OFT packet has a header type. I guess this | |
| 10 * is pretty similar to the subtype of a SNAC packet. The type | |
| 11 * basically tells the other client the meaning of the OFT packet. | |
| 12 * There are two distinct types of file transfer, which I usually | |
| 13 * call "sendfile" and "getfile." Sendfile is when you send a file | |
| 14 * to another AIM user. Getfile is when you share a group of files, | |
| 15 * and other users request that you send them the files. | |
| 16 * | |
| 17 * A typical sendfile file transfer goes like this: | |
| 18 * 1) Sender sends a channel 2 ICBM telling the other user that | |
| 19 * we want to send them a file. At the same time, we open a | |
| 20 * listener socket (this should be done before sending the | |
| 21 * ICBM) on some port, and wait for them to connect to us. | |
| 22 * The ICBM we sent should contain our IP address and the port | |
| 23 * number that we're listening on. | |
| 24 * 2) The receiver connects to the sender on the given IP address | |
| 25 * and port. After the connection is established, the receiver | |
| 26 * sends another ICBM signifying that we are ready and waiting. | |
| 27 * 3) The sender sends an OFT PROMPT message over the OFT | |
| 28 * connection. | |
| 29 * 4) The receiver of the file sends back an exact copy of this | |
| 30 * OFT packet, except the cookie is filled in with the cookie | |
| 31 * from the ICBM. I think this might be an attempt to verify | |
| 32 * that the user that is connected is actually the guy that | |
| 33 * we sent the ICBM to. Oh, I've been calling this the ACK. | |
| 34 * 5) The sender starts sending raw data across the connection | |
| 35 * until the entire file has been sent. | |
| 36 * 6) The receiver knows the file is finished because the sender | |
| 37 * sent the file size in an earlier OFT packet. So then the | |
| 38 * receiver sends the DONE thingy and closes the connection. | |
| 2086 | 39 */ |
| 40 | |
| 41 #define FAIM_INTERNAL | |
| 2931 | 42 |
|
2711
b7455c506979
[gaim-migrate @ 2724]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2675
diff
changeset
|
43 #ifdef HAVE_CONFIG_H |
|
b7455c506979
[gaim-migrate @ 2724]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2675
diff
changeset
|
44 #include <config.h> |
|
b7455c506979
[gaim-migrate @ 2724]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2675
diff
changeset
|
45 #endif |
| 2086 | 46 #include <aim.h> |
| 47 | |
| 48 #ifndef _WIN32 | |
| 49 #include <netdb.h> | |
| 50 #include <sys/socket.h> | |
| 51 #include <netinet/in.h> | |
| 4617 | 52 #include <sys/utsname.h> /* for aim_odc_initiate */ |
| 3630 | 53 #include <arpa/inet.h> /* for inet_ntoa */ |
| 3960 | 54 #define G_DIR_SEPARATOR '/' |
|
3646
bfd8df165f32
[gaim-migrate @ 3770]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
3630
diff
changeset
|
55 #endif |
|
bfd8df165f32
[gaim-migrate @ 3770]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
3630
diff
changeset
|
56 |
|
bfd8df165f32
[gaim-migrate @ 3770]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
3630
diff
changeset
|
57 #ifdef _WIN32 |
| 3630 | 58 #include "win32dep.h" |
| 59 #endif | |
| 2086 | 60 |
| 4617 | 61 struct aim_odc_intdata { |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
62 fu8_t cookie[8]; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
63 char sn[MAXSNLEN+1]; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
64 char ip[22]; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
65 }; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
66 |
| 4617 | 67 /** |
| 68 * Convert the directory separator from / (0x2f) to ^A (0x01) | |
| 69 * | |
| 70 * @param name The filename to convert. | |
| 71 */ | |
| 72 static void aim_oft_dirconvert_tostupid(char *name) | |
| 73 { | |
| 74 while (name[0]) { | |
| 75 if (name[0] == 0x01) | |
| 76 name[0] = G_DIR_SEPARATOR; | |
| 77 name++; | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 /** | |
| 82 * Convert the directory separator from ^A (0x01) to / (0x2f) | |
| 83 * | |
| 84 * @param name The filename to convert. | |
| 85 */ | |
| 86 static void aim_oft_dirconvert_fromstupid(char *name) | |
| 87 { | |
| 88 while (name[0]) { | |
| 89 if (name[0] == G_DIR_SEPARATOR) | |
| 90 name[0] = 0x01; | |
| 91 name++; | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 /** | |
| 96 * Calculate oft checksum of buffer | |
| 97 * | |
| 98 * Prevcheck should be 0xFFFF0000 when starting a checksum of a file. The | |
| 99 * checksum is kind of a rolling checksum thing, so each time you get bytes | |
| 100 * of a file you just call this puppy and it updates the checksum. You can | |
| 101 * calculate the checksum of an entire file by calling this in a while or a | |
| 102 * for loop, or something. | |
| 103 * | |
| 104 * Thanks to Graham Booker for providing this improved checksum routine, | |
| 105 * which is simpler and should be more accurate than Josh Myer's original | |
| 106 * code. -- wtm | |
| 107 * | |
| 108 * This algorithim works every time I have tried it. The other fails | |
| 109 * sometimes. So, AOL who thought this up? It has got to be the weirdest | |
| 110 * checksum I have ever seen. | |
| 111 * | |
| 112 * @param buffer Buffer of data to checksum. Man I'd like to buff her... | |
| 113 * @param bufsize Size of buffer. | |
| 114 * @param prevcheck Previous checksum. | |
| 115 */ | |
| 4763 | 116 faim_export fu32_t aim_oft_checksum_chunk(const fu8_t *buffer, int bufferlen, fu32_t prevcheck) |
| 4617 | 117 { |
| 118 fu32_t check = (prevcheck >> 16) & 0xffff, oldcheck; | |
| 119 int i; | |
| 120 unsigned short val; | |
| 121 | |
| 122 for (i=0; i<bufferlen; i++) { | |
| 123 oldcheck = check; | |
| 124 if (i&1) | |
| 125 val = buffer[i]; | |
| 126 else | |
| 127 val = buffer[i] << 8; | |
| 128 check -= val; | |
| 129 /* | |
| 130 * The following appears to be necessary.... It happens | |
| 131 * every once in a while and the checksum doesn't fail. | |
| 132 */ | |
| 133 if (check > oldcheck) | |
| 134 check--; | |
| 135 } | |
| 136 check = ((check & 0x0000ffff) + (check >> 16)); | |
| 137 check = ((check & 0x0000ffff) + (check >> 16)); | |
| 138 return check << 16; | |
| 139 } | |
| 140 | |
| 4650 | 141 faim_export fu32_t aim_oft_checksum_file(char *filename) { |
| 142 FILE *fd; | |
| 143 fu32_t checksum = 0xffff0000; | |
| 144 | |
| 145 if ((fd = fopen(filename, "rb"))) { | |
| 146 int bytes; | |
| 4763 | 147 fu8_t buffer[1024]; |
| 4650 | 148 |
| 149 while ((bytes = fread(buffer, 1, 1024, fd))) | |
| 150 checksum = aim_oft_checksum_chunk(buffer, bytes, checksum); | |
| 151 fclose(fd); | |
| 152 } | |
| 153 | |
| 154 return checksum; | |
| 155 } | |
| 156 | |
| 2086 | 157 /** |
| 4617 | 158 * Create a listening socket on a given port. |
| 159 * | |
| 160 * XXX - Give the client author the responsibility of setting up a | |
| 161 * listener, then we no longer have a libfaim problem with broken | |
| 162 * solaris *innocent smile* -- jbm | |
| 2086 | 163 * |
| 4617 | 164 * @param portnum The port number to bind to. |
| 165 * @return The file descriptor of the listening socket. | |
| 166 */ | |
| 167 static int listenestablish(fu16_t portnum) | |
| 168 { | |
| 169 #if HAVE_GETADDRINFO | |
| 170 int listenfd; | |
| 171 const int on = 1; | |
| 172 struct addrinfo hints, *res, *ressave; | |
| 173 char serv[5]; | |
| 174 | |
| 175 snprintf(serv, sizeof(serv), "%d", portnum); | |
| 176 memset(&hints, 0, sizeof(struct addrinfo)); | |
| 177 hints.ai_flags = AI_PASSIVE; | |
| 178 hints.ai_family = AF_UNSPEC; | |
| 179 hints.ai_socktype = SOCK_STREAM; | |
| 180 if (getaddrinfo(NULL /* any IP */, serv, &hints, &res) != 0) { | |
| 181 perror("getaddrinfo"); | |
| 182 return -1; | |
| 183 } | |
| 184 ressave = res; | |
| 185 do { | |
| 186 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); | |
| 187 if (listenfd < 0) | |
| 188 continue; | |
| 189 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); | |
| 190 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) | |
| 191 break; /* success */ | |
| 192 close(listenfd); | |
| 193 } while ( (res = res->ai_next) ); | |
| 194 | |
| 195 if (!res) | |
| 196 return -1; | |
| 197 | |
| 198 freeaddrinfo(ressave); | |
| 199 #else | |
| 200 int listenfd; | |
| 201 const int on = 1; | |
| 202 struct sockaddr_in sockin; | |
| 203 | |
| 204 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
| 205 perror("socket"); | |
| 206 return -1; | |
| 207 } | |
| 208 | |
| 209 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) { | |
| 210 perror("setsockopt"); | |
| 211 close(listenfd); | |
| 212 return -1; | |
| 213 } | |
| 214 | |
| 215 memset(&sockin, 0, sizeof(struct sockaddr_in)); | |
| 216 sockin.sin_family = AF_INET; | |
| 217 sockin.sin_port = htons(portnum); | |
| 218 | |
| 219 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { | |
| 220 perror("bind"); | |
| 221 close(listenfd); | |
| 222 return -1; | |
| 223 } | |
| 224 #endif | |
| 225 | |
| 226 if (listen(listenfd, 4) != 0) { | |
| 227 perror("listen"); | |
| 228 close(listenfd); | |
| 229 return -1; | |
| 230 } | |
| 231 fcntl(listenfd, F_SETFL, O_NONBLOCK); | |
| 232 | |
| 233 return listenfd; | |
| 234 } | |
| 235 | |
| 236 /** | |
| 237 * After establishing a listening socket, this is called to accept a connection. It | |
| 238 * clones the conn used by the listener, and passes both of these to a signal handler. | |
| 239 * The signal handler should close the listener conn and keep track of the new conn, | |
| 240 * since this is what is used for file transfers and what not. | |
| 241 * | |
| 242 * @param sess The session. | |
| 243 * @param cur The conn the incoming connection is on. | |
| 244 * @return Return 0 if no errors, otherwise return the error number. | |
| 2086 | 245 */ |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
246 faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur) |
| 4617 | 247 { |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
248 int acceptfd = 0; |
| 4617 | 249 struct sockaddr addr; |
| 250 socklen_t addrlen = sizeof(addr); | |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
251 int ret = 0; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
252 aim_conn_t *newconn; |
| 4617 | 253 char ip[20]; |
| 254 int port; | |
| 2086 | 255 |
| 4617 | 256 if ((acceptfd = accept(cur->fd, &addr, &addrlen)) == -1) |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
257 return 0; /* not an error */ |
| 2086 | 258 |
| 4617 | 259 if (addr.sa_family != AF_INET) { /* just in case IPv6 really is happening */ |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
260 close(acceptfd); |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
261 aim_conn_close(cur); |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
262 return -1; |
| 4617 | 263 } |
| 264 | |
| 265 strncpy(ip, inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr), sizeof(ip)); | |
| 266 port = ntohs(((struct sockaddr_in *)&addr)->sin_port); | |
| 2086 | 267 |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
268 if (!(newconn = aim_cloneconn(sess, cur))) { |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
269 close(acceptfd); |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
270 aim_conn_close(cur); |
| 4617 | 271 return -ENOMEM; |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
272 } |
| 2086 | 273 |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
274 newconn->type = AIM_CONN_TYPE_RENDEZVOUS; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
275 newconn->fd = acceptfd; |
| 2086 | 276 |
| 4617 | 277 if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
278 aim_rxcallback_t userfunc; |
| 4617 | 279 struct aim_odc_intdata *priv; |
| 2086 | 280 |
| 4617 | 281 priv = (struct aim_odc_intdata *)(newconn->internal = cur->internal); |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
282 cur->internal = NULL; |
| 4617 | 283 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", ip, port); |
| 2086 | 284 |
| 4617 | 285 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIM_ESTABLISHED))) |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
286 ret = userfunc(sess, NULL, newconn, cur); |
| 2086 | 287 |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
288 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { |
| 4617 | 289 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
290 aim_rxcallback_t userfunc; |
| 2086 | 291 |
| 4617 | 292 if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED))) |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
293 ret = userfunc(sess, NULL, newconn, cur); |
| 3630 | 294 |
| 4617 | 295 } else { |
| 296 faimdprintf(sess, 1,"Got a connection on a listener that's not rendezvous. Closing connection.\n"); | |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
297 aim_conn_close(newconn); |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
298 ret = -1; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
299 } |
| 2086 | 300 |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
301 return ret; |
| 2086 | 302 } |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
303 |
| 2086 | 304 /** |
| 4617 | 305 * Send client-to-client typing notification over an established direct connection. |
| 2086 | 306 * |
| 4617 | 307 * @param sess The session. |
| 308 * @param conn The already-connected ODC connection. | |
| 4870 | 309 * @param typing If 0x0002, sends a "typing" message, 0x0001 sends "typed," and |
| 310 * 0x0000 sends "stopped." | |
| 4617 | 311 * @return Return 0 if no errors, otherwise return the error number. |
| 2086 | 312 */ |
| 4617 | 313 faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing) |
| 2086 | 314 { |
| 4617 | 315 struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal; |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
316 aim_frame_t *fr; |
| 3952 | 317 aim_bstream_t *hdrbs; |
| 318 fu8_t *hdr; | |
| 319 int hdrlen = 0x44; | |
| 2086 | 320 |
| 3952 | 321 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) |
| 322 return -EINVAL; | |
| 2086 | 323 |
| 4870 | 324 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0001, 0))) |
| 3952 | 325 return -ENOMEM; |
| 326 memcpy(fr->hdr.rend.magic, "ODC2", 4); | |
| 327 fr->hdr.rend.hdrlen = hdrlen; | |
| 2086 | 328 |
| 3952 | 329 if (!(hdr = calloc(1, hdrlen))) { |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
330 aim_frame_destroy(fr); |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
331 return -ENOMEM; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
332 } |
| 3952 | 333 |
| 334 hdrbs = &(fr->data); | |
| 335 aim_bstream_init(hdrbs, hdr, hdrlen); | |
| 2086 | 336 |
| 3952 | 337 aimbs_put16(hdrbs, 0x0006); |
| 338 aimbs_put16(hdrbs, 0x0000); | |
| 339 aimbs_putraw(hdrbs, intdata->cookie, 8); | |
| 340 aimbs_put16(hdrbs, 0x0000); | |
| 341 aimbs_put16(hdrbs, 0x0000); | |
| 342 aimbs_put16(hdrbs, 0x0000); | |
| 343 aimbs_put16(hdrbs, 0x0000); | |
| 344 aimbs_put32(hdrbs, 0x00000000); | |
| 345 aimbs_put16(hdrbs, 0x0000); | |
| 346 aimbs_put16(hdrbs, 0x0000); | |
| 347 aimbs_put16(hdrbs, 0x0000); | |
| 2086 | 348 |
| 4870 | 349 if (typing == 0x0002) |
| 350 aimbs_put16(hdrbs, 0x0002 | 0x0008); | |
| 351 else if (typing == 0x0001) | |
| 352 aimbs_put16(hdrbs, 0x0002 | 0x0004); | |
| 353 else | |
| 354 aimbs_put16(hdrbs, 0x0002); | |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
355 |
| 3952 | 356 aimbs_put16(hdrbs, 0x0000); |
| 357 aimbs_put16(hdrbs, 0x0000); | |
| 358 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); | |
| 4617 | 359 |
| 3952 | 360 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ |
| 2086 | 361 |
| 3952 | 362 aimbs_put8(hdrbs, 0x00); |
| 363 aimbs_put16(hdrbs, 0x0000); | |
| 364 aimbs_put16(hdrbs, 0x0000); | |
| 365 aimbs_put16(hdrbs, 0x0000); | |
| 366 aimbs_put16(hdrbs, 0x0000); | |
| 367 aimbs_put16(hdrbs, 0x0000); | |
| 368 aimbs_put16(hdrbs, 0x0000); | |
| 369 aimbs_put16(hdrbs, 0x0000); | |
| 370 aimbs_put8(hdrbs, 0x00); | |
| 2086 | 371 |
| 3952 | 372 /* end of hdr */ |
| 2086 | 373 |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
374 aim_tx_enqueue(sess, fr); |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
375 |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
376 return 0; |
| 4617 | 377 } |
| 2086 | 378 |
| 2993 | 379 /** |
| 4617 | 380 * Send client-to-client IM over an established direct connection. |
| 381 * Call this just like you would aim_send_im, to send a directim. | |
| 2993 | 382 * |
| 4617 | 383 * @param sess The session. |
| 384 * @param conn The already-connected ODC connection. | |
| 385 * @param msg Null-terminated string to send. | |
| 386 * @param len The length of the message to send, including binary data. | |
| 387 * @param encoding 0 for ascii, 2 for Unicode, 3 for ISO 8859-1. | |
| 4870 | 388 * @param isawaymsg 0 if this is not an auto-response, 1 if it is. |
| 4617 | 389 * @return Return 0 if no errors, otherwise return the error number. |
| 2993 | 390 */ |
| 4870 | 391 faim_export int aim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding, int isawaymsg) |
| 2993 | 392 { |
| 393 aim_frame_t *fr; | |
| 3952 | 394 aim_bstream_t *hdrbs; |
| 4617 | 395 struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal; |
| 3952 | 396 int hdrlen = 0x44; |
| 397 fu8_t *hdr; | |
| 2993 | 398 |
| 4617 | 399 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !msg) |
| 400 return -EINVAL; | |
| 2993 | 401 |
| 4875 | 402 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0))) |
| 4617 | 403 return -ENOMEM; |
| 2993 | 404 |
| 3952 | 405 memcpy(fr->hdr.rend.magic, "ODC2", 4); |
| 406 fr->hdr.rend.hdrlen = hdrlen; | |
| 4617 | 407 |
| 3952 | 408 if (!(hdr = calloc(1, hdrlen + len))) { |
| 2993 | 409 aim_frame_destroy(fr); |
| 410 return -ENOMEM; | |
| 411 } | |
| 3952 | 412 |
| 413 hdrbs = &(fr->data); | |
| 414 aim_bstream_init(hdrbs, hdr, hdrlen + len); | |
| 415 | |
| 416 aimbs_put16(hdrbs, 0x0006); | |
| 417 aimbs_put16(hdrbs, 0x0000); | |
| 418 aimbs_putraw(hdrbs, intdata->cookie, 8); | |
| 419 aimbs_put16(hdrbs, 0x0000); | |
| 420 aimbs_put16(hdrbs, 0x0000); | |
| 421 aimbs_put16(hdrbs, 0x0000); | |
| 422 aimbs_put16(hdrbs, 0x0000); | |
| 423 aimbs_put32(hdrbs, len); | |
| 424 aimbs_put16(hdrbs, encoding); | |
| 425 aimbs_put16(hdrbs, 0x0000); | |
| 426 aimbs_put16(hdrbs, 0x0000); | |
| 4617 | 427 |
| 4870 | 428 /* flags - used for typing notification and to mark if this is an away message */ |
| 429 aimbs_put16(hdrbs, 0x0000 | isawaymsg); | |
| 3952 | 430 |
| 431 aimbs_put16(hdrbs, 0x0000); | |
| 432 aimbs_put16(hdrbs, 0x0000); | |
| 433 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); | |
| 434 | |
| 435 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ | |
| 436 | |
| 437 aimbs_put8(hdrbs, 0x00); | |
| 438 aimbs_put16(hdrbs, 0x0000); | |
| 439 aimbs_put16(hdrbs, 0x0000); | |
| 440 aimbs_put16(hdrbs, 0x0000); | |
| 441 aimbs_put16(hdrbs, 0x0000); | |
| 442 aimbs_put16(hdrbs, 0x0000); | |
| 443 aimbs_put16(hdrbs, 0x0000); | |
| 444 aimbs_put16(hdrbs, 0x0000); | |
| 445 aimbs_put8(hdrbs, 0x00); | |
| 4617 | 446 |
| 2993 | 447 /* end of hdr2 */ |
| 4617 | 448 |
| 449 #if 0 /* XXX - this is how you send buddy icon info... */ | |
| 450 aimbs_put16(hdrbs, 0x0008); | |
| 451 aimbs_put16(hdrbs, 0x000c); | |
| 452 aimbs_put16(hdrbs, 0x0000); | |
| 453 aimbs_put16(hdrbs, 0x1466); | |
| 454 aimbs_put16(hdrbs, 0x0001); | |
| 455 aimbs_put16(hdrbs, 0x2e0f); | |
| 456 aimbs_put16(hdrbs, 0x393e); | |
| 457 aimbs_put16(hdrbs, 0xcac8); | |
| 2993 | 458 #endif |
| 3952 | 459 aimbs_putraw(hdrbs, msg, len); |
| 4617 | 460 |
| 2993 | 461 aim_tx_enqueue(sess, fr); |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
462 |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
463 return 0; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
464 } |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
465 |
| 2086 | 466 /** |
| 4617 | 467 * Get the screen name of the peer of a direct connection. |
| 468 * | |
| 469 * @param conn The ODC connection. | |
| 470 * @return The screen name of the dude, or NULL if there was an anomaly. | |
| 2086 | 471 */ |
| 4617 | 472 faim_export const char *aim_odc_getsn(aim_conn_t *conn) |
| 473 { | |
| 474 struct aim_odc_intdata *intdata; | |
| 3630 | 475 |
| 4617 | 476 if (!conn || !conn->internal) |
| 3952 | 477 return NULL; |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
478 |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
479 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
480 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) |
| 3952 | 481 return NULL; |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
482 |
| 4617 | 483 intdata = (struct aim_odc_intdata *)conn->internal; |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
484 |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
485 return intdata->sn; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
486 } |
| 2086 | 487 |
| 488 /** | |
| 4617 | 489 * Find the conn of a direct connection with the given buddy. |
| 490 * | |
| 491 * @param sess The session. | |
| 492 * @param sn The screen name of the buddy whose direct connection you want to find. | |
| 493 * @return The conn for the direct connection with the given buddy, or NULL if no | |
| 494 * connection was found. | |
| 495 */ | |
| 496 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn) | |
| 497 { | |
| 498 aim_conn_t *cur; | |
| 499 struct aim_odc_intdata *intdata; | |
| 500 | |
| 501 if (!sess || !sn || !strlen(sn)) | |
| 502 return NULL; | |
| 503 | |
| 504 for (cur = sess->connlist; cur; cur = cur->next) { | |
| 505 if ((cur->type == AIM_CONN_TYPE_RENDEZVOUS) && (cur->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) { | |
| 506 intdata = cur->internal; | |
| 507 if (!aim_sncmp(intdata->sn, sn)) | |
| 508 return cur; | |
| 509 } | |
| 510 } | |
| 511 | |
| 512 return NULL; | |
| 513 } | |
| 514 | |
| 515 /** | |
| 516 * For those times when we want to open up the direct connection channel ourselves. | |
| 517 * | |
| 518 * You'll want to set up some kind of watcher on this socket. | |
| 519 * When the state changes, call aim_handlerendconnection with | |
| 520 * the connection returned by this. aim_handlerendconnection | |
| 521 * will accept the pending connection and stop listening. | |
| 522 * | |
| 523 * @param sess The session | |
| 524 * @param conn The BOS conn. | |
| 525 * @param priv A dummy priv value (we'll let it get filled in later) | |
| 526 * (if you pass a %NULL, we alloc one). | |
| 527 * @param sn The screen name to connect to. | |
| 528 * @return The new connection. | |
| 529 */ | |
| 530 faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn) | |
| 531 { | |
| 532 aim_conn_t *newconn; | |
| 533 aim_msgcookie_t *cookie; | |
| 534 struct aim_odc_intdata *priv; | |
| 535 int listenfd; | |
| 536 fu16_t port = 4443; | |
| 537 fu8_t localip[4]; | |
| 538 fu8_t ck[8]; | |
| 539 | |
| 540 if (aim_util_getlocalip(localip) == -1) | |
| 541 return NULL; | |
| 542 | |
| 543 if ((listenfd = listenestablish(port)) == -1) | |
| 544 return NULL; | |
| 545 | |
| 546 aim_im_sendch2_odcrequest(sess, ck, sn, localip, port); | |
| 547 | |
| 548 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); | |
| 549 memcpy(cookie->cookie, ck, 8); | |
| 550 cookie->type = AIM_COOKIETYPE_OFTIM; | |
| 551 | |
| 552 /* this one is for the cookie */ | |
| 553 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); | |
| 554 | |
| 555 memcpy(priv->cookie, ck, 8); | |
| 556 strncpy(priv->sn, sn, sizeof(priv->sn)); | |
| 557 cookie->data = priv; | |
| 558 aim_cachecookie(sess, cookie); | |
| 559 | |
| 560 /* XXX - switch to aim_cloneconn()? */ | |
| 561 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { | |
| 562 close(listenfd); | |
| 563 return NULL; | |
| 564 } | |
| 565 | |
| 566 /* this one is for the conn */ | |
| 567 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); | |
| 568 | |
| 569 memcpy(priv->cookie, ck, 8); | |
| 570 strncpy(priv->sn, sn, sizeof(priv->sn)); | |
| 571 | |
| 572 newconn->fd = listenfd; | |
| 573 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; | |
| 574 newconn->internal = priv; | |
| 575 newconn->lastactivity = time(NULL); | |
| 576 | |
| 577 return newconn; | |
| 578 } | |
| 579 | |
| 580 /** | |
| 581 * Connect directly to the given buddy for directim. | |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
582 * |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
583 * This is a wrapper for aim_newconn. |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
584 * |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
585 * If addr is NULL, the socket is not created, but the connection is |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
586 * allocated and setup to connect. |
| 2086 | 587 * |
| 4617 | 588 * @param sess The Godly session. |
| 589 * @param sn The screen name we're connecting to. I hope it's a girl... | |
| 590 * @param addr Address to connect to. | |
| 591 * @return The new connection. | |
| 2086 | 592 */ |
| 4617 | 593 faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie) |
| 594 { | |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
595 aim_conn_t *newconn; |
| 4617 | 596 struct aim_odc_intdata *intdata; |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
597 |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
598 if (!sess || !sn) |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
599 return NULL; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
600 |
| 4617 | 601 if (!(intdata = malloc(sizeof(struct aim_odc_intdata)))) |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
602 return NULL; |
| 4617 | 603 memset(intdata, 0, sizeof(struct aim_odc_intdata)); |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
604 memcpy(intdata->cookie, cookie, 8); |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
605 strncpy(intdata->sn, sn, sizeof(intdata->sn)); |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
606 if (addr) |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
607 strncpy(intdata->ip, addr, sizeof(intdata->ip)); |
| 2086 | 608 |
| 4617 | 609 /* XXX - verify that non-blocking connects actually work */ |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
610 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) { |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
611 free(intdata); |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
612 return NULL; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
613 } |
| 2086 | 614 |
| 4617 | 615 newconn->internal = intdata; |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
616 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
617 |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
618 return newconn; |
| 4617 | 619 } |
| 2086 | 620 |
| 621 /** | |
| 4826 | 622 * Sometimes you just don't know with these kinds of people. |
| 623 * | |
| 624 * @param sess The session. | |
| 625 * @param conn The ODC connection of the incoming data. | |
| 626 * @param frr The frame allocated for the incoming data. | |
| 627 * @param bs It stands for "bologna sandwich." | |
| 628 * @return Return 0 if no errors, otherwise return the error number. | |
| 629 */ | |
| 630 static int handlehdr_odc(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *frr, aim_bstream_t *bs) | |
| 631 { | |
| 632 aim_frame_t fr; | |
| 4870 | 633 int ret = 0; |
| 4826 | 634 aim_rxcallback_t userfunc; |
| 635 fu32_t payloadlength; | |
| 636 fu16_t flags, encoding; | |
| 637 char *snptr = NULL; | |
| 638 | |
| 639 fr.conn = conn; | |
| 640 | |
| 641 /* AAA - ugly */ | |
| 642 aim_bstream_setpos(bs, 20); | |
| 643 payloadlength = aimbs_get32(bs); | |
| 644 | |
| 645 aim_bstream_setpos(bs, 24); | |
| 646 encoding = aimbs_get16(bs); | |
| 647 | |
| 648 aim_bstream_setpos(bs, 30); | |
| 649 flags = aimbs_get16(bs); | |
| 650 | |
| 651 aim_bstream_setpos(bs, 36); | |
| 652 /* XXX - create an aimbs_getnullstr function? */ | |
| 653 snptr = aimbs_getstr(bs, MAXSNLEN); | |
| 654 | |
| 655 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_odc: %04x / %04x / %s\n", payloadlength, flags, snptr); | |
| 656 | |
| 4870 | 657 if (flags & 0x0008) { |
| 658 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) | |
| 659 ret = userfunc(sess, &fr, snptr, 2); | |
| 660 } else if (flags & 0x0004) { | |
| 661 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) | |
| 662 ret = userfunc(sess, &fr, snptr, 1); | |
| 663 } else { | |
| 4826 | 664 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) |
| 665 ret = userfunc(sess, &fr, snptr, 0); | |
| 4870 | 666 } |
| 4826 | 667 |
| 4870 | 668 if (payloadlength) { |
| 669 char *msg; | |
| 4826 | 670 int recvd = 0; |
| 4870 | 671 int i, isawaymsg; |
| 672 | |
| 673 isawaymsg = flags & 0x0001; | |
| 4826 | 674 |
| 675 if (!(msg = calloc(1, payloadlength+1))) | |
| 4870 | 676 return -ENOMEM; |
| 677 | |
| 4826 | 678 while (payloadlength - recvd) { |
| 679 if (payloadlength - recvd >= 1024) | |
| 4870 | 680 i = aim_recv(conn->fd, &msg[recvd], 1024); |
| 4826 | 681 else |
| 4870 | 682 i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd); |
| 4826 | 683 if (i <= 0) { |
| 684 free(msg); | |
| 685 return -1; | |
| 686 } | |
| 687 recvd = recvd + i; | |
| 688 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) | |
| 4870 | 689 ret = userfunc(sess, &fr, snptr, (double)recvd / payloadlength); |
| 4826 | 690 } |
| 691 | |
| 4870 | 692 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING))) |
| 693 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding, isawaymsg); | |
| 4826 | 694 |
| 695 free(msg); | |
| 696 } | |
| 697 | |
| 4870 | 698 return ret; |
| 4826 | 699 } |
| 700 | |
| 701 /** | |
| 4617 | 702 * Creates a listener socket so the other dude can connect to us. |
| 2086 | 703 * |
| 4617 | 704 * You'll want to set up some kind of watcher on this socket. |
| 705 * When the state changes, call aim_handlerendconnection with | |
| 706 * the connection returned by this. aim_handlerendconnection | |
| 707 * will accept the pending connection and stop listening. | |
| 2086 | 708 * |
| 4617 | 709 * @param sess The session. |
| 710 * @param cookie This better be Mrs. Fields or I'm going to be pissed. | |
| 711 * @param ip Should be 4 bytes, each byte is 1 quartet of the IP address. | |
| 712 * @param port Ye olde port number to listen on. | |
| 713 * @return Return the new conn if everything went as planned. Otherwise, | |
| 714 * return NULL. | |
| 2086 | 715 */ |
| 4617 | 716 faim_export aim_conn_t *aim_sendfile_listen(aim_session_t *sess, const fu8_t *cookie, const fu8_t *ip, fu16_t port) |
| 2086 | 717 { |
| 4617 | 718 aim_conn_t *newconn; |
| 719 int listenfd; | |
| 2086 | 720 |
| 4617 | 721 if ((listenfd = listenestablish(port)) == -1) |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
722 return NULL; |
| 2086 | 723 |
| 4617 | 724 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { |
| 725 close(listenfd); | |
| 3952 | 726 return NULL; |
| 727 } | |
| 3630 | 728 |
| 4617 | 729 newconn->fd = listenfd; |
| 730 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; | |
| 731 newconn->lastactivity = time(NULL); | |
| 3952 | 732 |
| 4617 | 733 return newconn; |
| 734 } | |
| 3630 | 735 |
| 4617 | 736 /** |
| 737 * Extract an &aim_fileheader_t from the given buffer. | |
| 738 * | |
| 739 * @param bs The should be from an incoming rendezvous packet. | |
| 740 * @return A pointer to new struct on success, or NULL on error. | |
| 741 */ | |
| 742 static struct aim_fileheader_t *aim_oft_getheader(aim_bstream_t *bs) | |
| 743 { | |
| 744 struct aim_fileheader_t *fh; | |
| 3630 | 745 |
| 4617 | 746 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t)))) |
| 747 return NULL; | |
| 3630 | 748 |
| 4617 | 749 /* The bstream should be positioned after the hdrtype. */ |
| 750 aimbs_getrawbuf(bs, fh->bcookie, 8); | |
| 751 fh->encrypt = aimbs_get16(bs); | |
| 752 fh->compress = aimbs_get16(bs); | |
| 753 fh->totfiles = aimbs_get16(bs); | |
| 754 fh->filesleft = aimbs_get16(bs); | |
| 755 fh->totparts = aimbs_get16(bs); | |
| 756 fh->partsleft = aimbs_get16(bs); | |
| 757 fh->totsize = aimbs_get32(bs); | |
| 758 fh->size = aimbs_get32(bs); | |
| 759 fh->modtime = aimbs_get32(bs); | |
| 760 fh->checksum = aimbs_get32(bs); | |
| 761 fh->rfrcsum = aimbs_get32(bs); | |
| 762 fh->rfsize = aimbs_get32(bs); | |
| 763 fh->cretime = aimbs_get32(bs); | |
| 764 fh->rfcsum = aimbs_get32(bs); | |
| 765 fh->nrecvd = aimbs_get32(bs); | |
| 766 fh->recvcsum = aimbs_get32(bs); | |
| 767 aimbs_getrawbuf(bs, fh->idstring, 32); | |
| 768 fh->flags = aimbs_get8(bs); | |
| 769 fh->lnameoffset = aimbs_get8(bs); | |
| 770 fh->lsizeoffset = aimbs_get8(bs); | |
| 771 aimbs_getrawbuf(bs, fh->dummy, 69); | |
| 772 aimbs_getrawbuf(bs, fh->macfileinfo, 16); | |
| 773 fh->nencode = aimbs_get16(bs); | |
| 774 fh->nlanguage = aimbs_get16(bs); | |
| 775 aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */ | |
| 2086 | 776 |
| 4617 | 777 return fh; |
| 778 } | |
| 3630 | 779 |
| 4617 | 780 /** |
| 781 * Fills a buffer with network-order fh data | |
| 782 * | |
| 783 * @param bs A bstream to fill -- automatically initialized | |
| 784 * @param fh A struct aim_fileheader_t to get data from. | |
| 785 * @return Return non-zero on error. | |
| 786 */ | |
| 787 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) | |
| 788 { | |
| 789 fu8_t *hdr; | |
| 3630 | 790 |
| 4617 | 791 if (!bs || !fh) |
| 792 return -EINVAL; | |
| 3952 | 793 |
| 4617 | 794 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) |
| 795 return -ENOMEM; | |
| 3630 | 796 |
| 4617 | 797 aim_bstream_init(bs, hdr, 0x100 - 8); |
| 798 aimbs_putraw(bs, fh->bcookie, 8); | |
| 799 aimbs_put16(bs, fh->encrypt); | |
| 800 aimbs_put16(bs, fh->compress); | |
| 801 aimbs_put16(bs, fh->totfiles); | |
| 802 aimbs_put16(bs, fh->filesleft); | |
| 803 aimbs_put16(bs, fh->totparts); | |
| 804 aimbs_put16(bs, fh->partsleft); | |
| 805 aimbs_put32(bs, fh->totsize); | |
| 806 aimbs_put32(bs, fh->size); | |
| 807 aimbs_put32(bs, fh->modtime); | |
| 808 aimbs_put32(bs, fh->checksum); | |
| 809 aimbs_put32(bs, fh->rfrcsum); | |
| 810 aimbs_put32(bs, fh->rfsize); | |
| 811 aimbs_put32(bs, fh->cretime); | |
| 812 aimbs_put32(bs, fh->rfcsum); | |
| 813 aimbs_put32(bs, fh->nrecvd); | |
| 814 aimbs_put32(bs, fh->recvcsum); | |
| 815 aimbs_putraw(bs, fh->idstring, 32); | |
| 816 aimbs_put8(bs, fh->flags); | |
| 817 aimbs_put8(bs, fh->lnameoffset); | |
| 818 aimbs_put8(bs, fh->lsizeoffset); | |
| 819 aimbs_putraw(bs, fh->dummy, 69); | |
| 820 aimbs_putraw(bs, fh->macfileinfo, 16); | |
| 821 aimbs_put16(bs, fh->nencode); | |
| 822 aimbs_put16(bs, fh->nlanguage); | |
| 823 aimbs_putraw(bs, fh->name, 64); /* XXX - filenames longer than 64B */ | |
| 3952 | 824 |
| 4617 | 825 return 0; |
| 826 } | |
| 2086 | 827 |
| 4832 | 828 faim_export struct aim_oft_info *aim_oft_createnewheader(fu8_t *cookie, char *ip, fu32_t size, fu32_t modtime, char *filename) |
| 829 { | |
| 830 struct aim_oft_info *new; | |
| 831 | |
| 832 if (!(new = (struct aim_oft_info *)calloc(1, sizeof(struct aim_oft_info)))) | |
| 833 return NULL; | |
| 834 | |
| 835 if (cookie && (sizeof(cookie) == 8)) { | |
| 836 memcpy(new->cookie, cookie, 8); | |
| 837 memcpy(new->fh.bcookie, cookie, 8); | |
| 838 } | |
| 839 if (ip) | |
| 840 strncpy(new->ip, ip, 30); | |
| 841 new->fh.filesleft = 0; | |
| 842 new->fh.totparts = 1; | |
| 843 new->fh.partsleft = 1; | |
| 844 new->fh.totsize = size; | |
| 845 new->fh.size = size; | |
| 846 new->fh.modtime = modtime; | |
| 847 strcpy(new->fh.idstring, "OFT_Windows ICBMFT V1.1 32"); | |
| 848 if (filename) | |
| 849 strncpy(new->fh.name, filename, 64); | |
| 850 | |
| 851 return new; | |
| 852 } | |
| 853 | |
| 4617 | 854 /** |
| 855 * Create an OFT packet based on the given information, and send it on its merry way. | |
| 856 * | |
| 857 * @param sess The session. | |
| 858 * @param conn The already-connected OFT connection. | |
| 859 * @param cookie The cookie associated with this file transfer. | |
| 860 * @param filename The filename. | |
| 861 * @param filesdone Number of files already transferred. | |
| 862 * @param numfiles Total number of files. | |
| 863 * @param size Size in bytes of this file. | |
| 864 * @param totsize Size in bytes of all files combined. | |
| 865 * @param checksum Funky checksum of this file. | |
| 866 * @param flags Any flags you want, baby. Send 0x21 when sending the | |
| 867 * "AIM_CB_OFT_DONE" message, and "0x02" for everything else. | |
| 868 * @return Return 0 if no errors, otherwise return the error number. | |
| 869 */ | |
| 4646 | 870 faim_export int aim_oft_sendheader(aim_session_t *sess, aim_conn_t *conn, fu16_t type, const fu8_t *cookie, const char *filename, fu16_t filesdone, fu16_t numfiles, fu32_t size, fu32_t totsize, fu32_t modtime, fu32_t checksum, fu8_t flags, fu32_t bytesreceived, fu32_t recvcsum) |
| 4617 | 871 { |
| 872 aim_frame_t *newoft; | |
| 873 struct aim_fileheader_t *fh; | |
| 2086 | 874 |
| 4617 | 875 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !filename) |
| 876 return -EINVAL; | |
| 877 | |
| 878 if (!(fh = (struct aim_fileheader_t *)calloc(1, sizeof(struct aim_fileheader_t)))) | |
| 879 return -ENOMEM; | |
| 880 | |
| 881 /* | |
| 882 * If you are receiving a file, the cookie should be null, if you are sending a | |
| 883 * file, the cookie should be the same as the one used in the ICBM negotiation | |
| 884 * SNACs. | |
| 885 */ | |
| 886 if (cookie) | |
| 887 memcpy(fh->bcookie, cookie, 8); | |
| 888 fh->totfiles = numfiles; | |
| 889 fh->filesleft = numfiles - filesdone; | |
| 890 fh->totparts = 0x0001; /* set to 0x0002 sending Mac resource forks */ | |
| 3952 | 891 fh->partsleft = 0x0001; |
| 4617 | 892 fh->totsize = totsize; |
| 893 fh->size = size; | |
| 894 fh->modtime = modtime; | |
| 895 fh->checksum = checksum; | |
| 4646 | 896 fh->nrecvd = bytesreceived; |
| 897 fh->recvcsum = recvcsum; | |
| 4617 | 898 |
| 3952 | 899 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); |
| 4646 | 900 fh->flags = flags; |
| 3952 | 901 fh->lnameoffset = 0x1a; |
| 902 fh->lsizeoffset = 0x10; | |
| 903 memset(fh->dummy, 0, sizeof(fh->dummy)); | |
| 904 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); | |
| 2086 | 905 |
| 4617 | 906 /* apparently 0 is ASCII, 2 is UCS-2 */ |
| 907 /* it is likely that 3 is ISO 8859-1 */ | |
| 4826 | 908 /* I think "nlanguage" might be the same thing as "subenc" in im.c */ |
| 3952 | 909 fh->nencode = 0x0000; |
| 910 fh->nlanguage = 0x0000; | |
| 4617 | 911 |
| 912 strncpy(fh->name, filename, sizeof(fh->name)); | |
| 913 aim_oft_dirconvert_tostupid(fh->name); | |
| 2086 | 914 |
| 4617 | 915 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, type, 0))) { |
| 916 free(fh); | |
| 917 return -ENOMEM; | |
| 3952 | 918 } |
| 2086 | 919 |
| 4617 | 920 if (aim_oft_buildheader(&newoft->data, fh) == -1) { |
| 921 aim_frame_destroy(newoft); | |
| 922 free(fh); | |
| 923 return -ENOMEM; | |
| 924 } | |
| 2086 | 925 |
| 4617 | 926 memcpy(newoft->hdr.rend.magic, "OFT2", 4); |
| 927 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); | |
| 3952 | 928 |
| 929 aim_tx_enqueue(sess, newoft); | |
| 2086 | 930 |
| 3952 | 931 free(fh); |
| 932 | |
| 933 return 0; | |
| 2086 | 934 } |
| 935 | |
| 936 /** | |
| 4617 | 937 * Handle incoming data on a rendezvous connection. This is analogous to the |
| 938 * consumesnac function in rxhandlers.c, and I really think this should probably | |
| 939 * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet. | |
| 940 * | |
| 941 * @param sess The session. | |
| 942 * @param fr The frame allocated for the incoming data. | |
| 943 * @return Return 0 if the packet was handled correctly, otherwise return the | |
| 944 * error number. | |
| 3771 | 945 */ |
| 3952 | 946 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) |
| 2086 | 947 { |
| 3952 | 948 aim_conn_t *conn = fr->conn; |
| 4617 | 949 int ret = 1; |
| 2086 | 950 |
| 4617 | 951 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { |
| 952 if (fr->hdr.rend.type == 0x0001) | |
| 953 ret = handlehdr_odc(sess, conn, fr, &fr->data); | |
| 954 else | |
| 955 faimdprintf(sess, 0, "faim: ODC directim frame unknown, type is %04x\n", fr->hdr.rend.type); | |
| 2086 | 956 |
| 4826 | 957 } else { |
| 4617 | 958 aim_rxcallback_t userfunc; |
| 959 struct aim_fileheader_t *header = aim_oft_getheader(&fr->data); | |
| 960 aim_oft_dirconvert_fromstupid(header->name); /* XXX - This should be client-side */ | |
| 3771 | 961 |
| 4617 | 962 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, fr->hdr.rend.type))) |
| 963 ret = userfunc(sess, fr, conn, header->bcookie, header); | |
| 964 | |
| 965 free(header); | |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
966 } |
| 4617 | 967 |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
968 if (ret == -1) |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
969 aim_conn_close(conn); |
| 2086 | 970 |
|
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
971 return ret; |
|
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
972 } |
