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