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