Mercurial > pidgin.yaz
annotate src/protocols/oscar/ft.c @ 8982:a4fd6666bb83
[gaim-migrate @ 9757]
Some Direct IM fixes.
1. Let's send our correct ip. We were usually sending localhost, so the
other side would try to connect to localhost and immediately fail and so
say, hey! I can't connect to you! Connect to me instead!
2. Add some gaim_conversation_writes to keep the user more informed as
to what's going on.
This changes the libfaim API. libfaim users take note.
I removed the util get local ip function, and made the function
that used to use it take an ip as an argument instead, so that oscar.c
could just call gaim's function, which works better.
I also made it possible to specify a cookie to use, because I think I'll
need that later. Probably.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Thu, 20 May 2004 00:14:14 +0000 |
parents | 535449a13b07 |
children | 460d02fe03df |
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 * | |
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8610
diff
changeset
|
111 * This algorithm works every time I have tried it. The other fails |
4617 | 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]; |
8880 | 178 unsigned short 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 |
8880 | 183 /* Also accept inet6? */ |
8610 | 184 if (addr.sa_family != AF_INET) { |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
185 close(acceptfd); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
186 aim_conn_close(cur); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
187 return -1; |
4617 | 188 } |
189 | |
190 strncpy(ip, inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr), sizeof(ip)); | |
191 port = ntohs(((struct sockaddr_in *)&addr)->sin_port); | |
2086 | 192 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
193 if (!(newconn = aim_cloneconn(sess, cur))) { |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
194 close(acceptfd); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
195 aim_conn_close(cur); |
4617 | 196 return -ENOMEM; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
197 } |
2086 | 198 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
199 newconn->type = AIM_CONN_TYPE_RENDEZVOUS; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
200 newconn->fd = acceptfd; |
2086 | 201 |
4617 | 202 if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
203 aim_rxcallback_t userfunc; |
4617 | 204 struct aim_odc_intdata *priv; |
2086 | 205 |
4617 | 206 priv = (struct aim_odc_intdata *)(newconn->internal = cur->internal); |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
207 cur->internal = NULL; |
8446 | 208 snprintf(priv->ip, sizeof(priv->ip), "%s:%hu", ip, port); |
2086 | 209 |
4617 | 210 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
|
211 ret = userfunc(sess, NULL, newconn, cur); |
2086 | 212 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
213 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { |
4617 | 214 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
215 aim_rxcallback_t userfunc; |
2086 | 216 |
4617 | 217 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
|
218 ret = userfunc(sess, NULL, newconn, cur); |
3630 | 219 |
4617 | 220 } else { |
221 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
|
222 aim_conn_close(newconn); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
223 ret = -1; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
224 } |
2086 | 225 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
226 return ret; |
2086 | 227 } |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
228 |
2086 | 229 /** |
4617 | 230 * Send client-to-client typing notification over an established direct connection. |
2086 | 231 * |
4617 | 232 * @param sess The session. |
233 * @param conn The already-connected ODC connection. | |
4870 | 234 * @param typing If 0x0002, sends a "typing" message, 0x0001 sends "typed," and |
235 * 0x0000 sends "stopped." | |
4617 | 236 * @return Return 0 if no errors, otherwise return the error number. |
2086 | 237 */ |
4617 | 238 faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing) |
2086 | 239 { |
4617 | 240 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
|
241 aim_frame_t *fr; |
3952 | 242 aim_bstream_t *hdrbs; |
243 fu8_t *hdr; | |
244 int hdrlen = 0x44; | |
2086 | 245 |
3952 | 246 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) |
247 return -EINVAL; | |
2086 | 248 |
4870 | 249 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0001, 0))) |
3952 | 250 return -ENOMEM; |
251 memcpy(fr->hdr.rend.magic, "ODC2", 4); | |
8934 | 252 fr->hdr.rend.hdrlen = hdrlen + 8; |
2086 | 253 |
3952 | 254 if (!(hdr = calloc(1, hdrlen))) { |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
255 aim_frame_destroy(fr); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
256 return -ENOMEM; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
257 } |
3952 | 258 |
259 hdrbs = &(fr->data); | |
260 aim_bstream_init(hdrbs, hdr, hdrlen); | |
2086 | 261 |
3952 | 262 aimbs_put16(hdrbs, 0x0006); |
263 aimbs_put16(hdrbs, 0x0000); | |
264 aimbs_putraw(hdrbs, intdata->cookie, 8); | |
265 aimbs_put16(hdrbs, 0x0000); | |
266 aimbs_put16(hdrbs, 0x0000); | |
267 aimbs_put16(hdrbs, 0x0000); | |
268 aimbs_put16(hdrbs, 0x0000); | |
269 aimbs_put32(hdrbs, 0x00000000); | |
270 aimbs_put16(hdrbs, 0x0000); | |
271 aimbs_put16(hdrbs, 0x0000); | |
272 aimbs_put16(hdrbs, 0x0000); | |
2086 | 273 |
4870 | 274 if (typing == 0x0002) |
275 aimbs_put16(hdrbs, 0x0002 | 0x0008); | |
276 else if (typing == 0x0001) | |
277 aimbs_put16(hdrbs, 0x0002 | 0x0004); | |
278 else | |
279 aimbs_put16(hdrbs, 0x0002); | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
280 |
3952 | 281 aimbs_put16(hdrbs, 0x0000); |
282 aimbs_put16(hdrbs, 0x0000); | |
283 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); | |
4617 | 284 |
3952 | 285 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ |
2086 | 286 |
3952 | 287 aimbs_put8(hdrbs, 0x00); |
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_put16(hdrbs, 0x0000); | |
295 aimbs_put8(hdrbs, 0x00); | |
2086 | 296 |
3952 | 297 /* end of hdr */ |
2086 | 298 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
299 aim_tx_enqueue(sess, fr); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
300 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
301 return 0; |
4617 | 302 } |
2086 | 303 |
2993 | 304 /** |
4617 | 305 * Send client-to-client IM over an established direct connection. |
306 * Call this just like you would aim_send_im, to send a directim. | |
2993 | 307 * |
4617 | 308 * @param sess The session. |
309 * @param conn The already-connected ODC connection. | |
310 * @param msg Null-terminated string to send. | |
311 * @param len The length of the message to send, including binary data. | |
312 * @param encoding 0 for ascii, 2 for Unicode, 3 for ISO 8859-1. | |
4870 | 313 * @param isawaymsg 0 if this is not an auto-response, 1 if it is. |
4617 | 314 * @return Return 0 if no errors, otherwise return the error number. |
2993 | 315 */ |
4870 | 316 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 | 317 { |
318 aim_frame_t *fr; | |
3952 | 319 aim_bstream_t *hdrbs; |
4617 | 320 struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal; |
3952 | 321 int hdrlen = 0x44; |
322 fu8_t *hdr; | |
2993 | 323 |
4617 | 324 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !msg) |
325 return -EINVAL; | |
2993 | 326 |
4875 | 327 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0))) |
4617 | 328 return -ENOMEM; |
2993 | 329 |
3952 | 330 memcpy(fr->hdr.rend.magic, "ODC2", 4); |
8934 | 331 fr->hdr.rend.hdrlen = hdrlen + 8; |
4617 | 332 |
3952 | 333 if (!(hdr = calloc(1, hdrlen + len))) { |
2993 | 334 aim_frame_destroy(fr); |
335 return -ENOMEM; | |
336 } | |
3952 | 337 |
338 hdrbs = &(fr->data); | |
339 aim_bstream_init(hdrbs, hdr, hdrlen + len); | |
340 | |
341 aimbs_put16(hdrbs, 0x0006); | |
342 aimbs_put16(hdrbs, 0x0000); | |
343 aimbs_putraw(hdrbs, intdata->cookie, 8); | |
344 aimbs_put16(hdrbs, 0x0000); | |
345 aimbs_put16(hdrbs, 0x0000); | |
346 aimbs_put16(hdrbs, 0x0000); | |
347 aimbs_put16(hdrbs, 0x0000); | |
348 aimbs_put32(hdrbs, len); | |
349 aimbs_put16(hdrbs, encoding); | |
350 aimbs_put16(hdrbs, 0x0000); | |
351 aimbs_put16(hdrbs, 0x0000); | |
4617 | 352 |
4870 | 353 /* flags - used for typing notification and to mark if this is an away message */ |
354 aimbs_put16(hdrbs, 0x0000 | isawaymsg); | |
3952 | 355 |
356 aimbs_put16(hdrbs, 0x0000); | |
357 aimbs_put16(hdrbs, 0x0000); | |
358 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); | |
359 | |
360 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ | |
361 | |
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); | |
4617 | 371 |
2993 | 372 /* end of hdr2 */ |
4617 | 373 |
374 #if 0 /* XXX - this is how you send buddy icon info... */ | |
375 aimbs_put16(hdrbs, 0x0008); | |
376 aimbs_put16(hdrbs, 0x000c); | |
377 aimbs_put16(hdrbs, 0x0000); | |
378 aimbs_put16(hdrbs, 0x1466); | |
379 aimbs_put16(hdrbs, 0x0001); | |
380 aimbs_put16(hdrbs, 0x2e0f); | |
381 aimbs_put16(hdrbs, 0x393e); | |
382 aimbs_put16(hdrbs, 0xcac8); | |
2993 | 383 #endif |
3952 | 384 aimbs_putraw(hdrbs, msg, len); |
4617 | 385 |
2993 | 386 aim_tx_enqueue(sess, fr); |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
387 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
388 return 0; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
389 } |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
390 |
2086 | 391 /** |
4617 | 392 * Get the screen name of the peer of a direct connection. |
393 * | |
394 * @param conn The ODC connection. | |
395 * @return The screen name of the dude, or NULL if there was an anomaly. | |
2086 | 396 */ |
4617 | 397 faim_export const char *aim_odc_getsn(aim_conn_t *conn) |
398 { | |
399 struct aim_odc_intdata *intdata; | |
3630 | 400 |
4617 | 401 if (!conn || !conn->internal) |
3952 | 402 return NULL; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
403 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
404 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
405 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) |
3952 | 406 return NULL; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
407 |
4617 | 408 intdata = (struct aim_odc_intdata *)conn->internal; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
409 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
410 return intdata->sn; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
411 } |
2086 | 412 |
413 /** | |
4617 | 414 * Find the conn of a direct connection with the given buddy. |
415 * | |
416 * @param sess The session. | |
417 * @param sn The screen name of the buddy whose direct connection you want to find. | |
418 * @return The conn for the direct connection with the given buddy, or NULL if no | |
419 * connection was found. | |
420 */ | |
421 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn) | |
422 { | |
423 aim_conn_t *cur; | |
424 struct aim_odc_intdata *intdata; | |
425 | |
426 if (!sess || !sn || !strlen(sn)) | |
427 return NULL; | |
428 | |
429 for (cur = sess->connlist; cur; cur = cur->next) { | |
430 if ((cur->type == AIM_CONN_TYPE_RENDEZVOUS) && (cur->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) { | |
431 intdata = cur->internal; | |
432 if (!aim_sncmp(intdata->sn, sn)) | |
433 return cur; | |
434 } | |
435 } | |
436 | |
437 return NULL; | |
438 } | |
439 | |
440 /** | |
441 * For those times when we want to open up the direct connection channel ourselves. | |
442 * | |
8982 | 443 * You'll want to set up some kind of watcher on this socket. |
444 * When the state changes, call aim_handlerendconnection with | |
445 * the connection returned by this. aim_handlerendconnection | |
4617 | 446 * will accept the pending connection and stop listening. |
447 * | |
448 * @param sess The session | |
449 * @param sn The screen name to connect to. | |
450 * @return The new connection. | |
451 */ | |
8982 | 452 faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn, int listenfd, |
453 const fu8_t *localip, fu16_t port, const fu8_t *mycookie) | |
4617 | 454 { |
455 aim_conn_t *newconn; | |
456 aim_msgcookie_t *cookie; | |
457 struct aim_odc_intdata *priv; | |
458 fu8_t ck[8]; | |
459 | |
8982 | 460 if (!localip) |
4617 | 461 return NULL; |
462 | |
8982 | 463 if (mycookie) { |
464 memcpy(ck, mycookie, 8); | |
465 aim_im_sendch2_odcrequest(sess, ck, TRUE, sn, localip, port); | |
466 } else | |
467 aim_im_sendch2_odcrequest(sess, ck, FALSE, sn, localip, port); | |
4617 | 468 |
469 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); | |
470 memcpy(cookie->cookie, ck, 8); | |
471 cookie->type = AIM_COOKIETYPE_OFTIM; | |
472 | |
473 /* this one is for the cookie */ | |
474 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); | |
475 | |
476 memcpy(priv->cookie, ck, 8); | |
477 strncpy(priv->sn, sn, sizeof(priv->sn)); | |
478 cookie->data = priv; | |
479 aim_cachecookie(sess, cookie); | |
480 | |
481 /* XXX - switch to aim_cloneconn()? */ | |
482 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { | |
483 close(listenfd); | |
484 return NULL; | |
485 } | |
486 | |
487 /* this one is for the conn */ | |
488 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); | |
489 | |
490 memcpy(priv->cookie, ck, 8); | |
491 strncpy(priv->sn, sn, sizeof(priv->sn)); | |
492 | |
493 newconn->fd = listenfd; | |
494 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; | |
495 newconn->internal = priv; | |
496 newconn->lastactivity = time(NULL); | |
497 | |
498 return newconn; | |
499 } | |
500 | |
501 /** | |
502 * Connect directly to the given buddy for directim. | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
503 * |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
504 * This is a wrapper for aim_newconn. |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
505 * |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
506 * 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
|
507 * allocated and setup to connect. |
2086 | 508 * |
4617 | 509 * @param sess The Godly session. |
510 * @param sn The screen name we're connecting to. I hope it's a girl... | |
511 * @param addr Address to connect to. | |
512 * @return The new connection. | |
2086 | 513 */ |
4617 | 514 faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie) |
515 { | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
516 aim_conn_t *newconn; |
4617 | 517 struct aim_odc_intdata *intdata; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
518 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
519 if (!sess || !sn) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
520 return NULL; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
521 |
5146 | 522 if (!(intdata = calloc(1, sizeof(struct aim_odc_intdata)))) |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
523 return NULL; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
524 memcpy(intdata->cookie, cookie, 8); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
525 strncpy(intdata->sn, sn, sizeof(intdata->sn)); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
526 if (addr) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
527 strncpy(intdata->ip, addr, sizeof(intdata->ip)); |
2086 | 528 |
4617 | 529 /* XXX - verify that non-blocking connects actually work */ |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
530 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) { |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
531 free(intdata); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
532 return NULL; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
533 } |
2086 | 534 |
4617 | 535 newconn->internal = intdata; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
536 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
537 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
538 return newconn; |
4617 | 539 } |
2086 | 540 |
541 /** | |
4826 | 542 * Sometimes you just don't know with these kinds of people. |
543 * | |
544 * @param sess The session. | |
545 * @param conn The ODC connection of the incoming data. | |
546 * @param frr The frame allocated for the incoming data. | |
547 * @param bs It stands for "bologna sandwich." | |
548 * @return Return 0 if no errors, otherwise return the error number. | |
549 */ | |
550 static int handlehdr_odc(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *frr, aim_bstream_t *bs) | |
551 { | |
552 aim_frame_t fr; | |
4870 | 553 int ret = 0; |
4826 | 554 aim_rxcallback_t userfunc; |
555 fu32_t payloadlength; | |
556 fu16_t flags, encoding; | |
557 char *snptr = NULL; | |
558 | |
559 fr.conn = conn; | |
560 | |
561 /* AAA - ugly */ | |
562 aim_bstream_setpos(bs, 20); | |
563 payloadlength = aimbs_get32(bs); | |
564 | |
565 aim_bstream_setpos(bs, 24); | |
566 encoding = aimbs_get16(bs); | |
567 | |
568 aim_bstream_setpos(bs, 30); | |
569 flags = aimbs_get16(bs); | |
570 | |
571 aim_bstream_setpos(bs, 36); | |
572 /* XXX - create an aimbs_getnullstr function? */ | |
4913 | 573 snptr = aimbs_getstr(bs, 32); /* Next 32 bytes contain the sn, padded with null chars */ |
4826 | 574 |
575 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_odc: %04x / %04x / %s\n", payloadlength, flags, snptr); | |
576 | |
4870 | 577 if (flags & 0x0008) { |
578 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) | |
579 ret = userfunc(sess, &fr, snptr, 2); | |
580 } else if (flags & 0x0004) { | |
581 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) | |
582 ret = userfunc(sess, &fr, snptr, 1); | |
583 } else { | |
4826 | 584 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) |
585 ret = userfunc(sess, &fr, snptr, 0); | |
4870 | 586 } |
4826 | 587 |
8000 | 588 if ((payloadlength != 0) && (payloadlength != UINT_MAX)) { |
4870 | 589 char *msg; |
4826 | 590 int recvd = 0; |
4870 | 591 int i, isawaymsg; |
592 | |
593 isawaymsg = flags & 0x0001; | |
4826 | 594 |
4895 | 595 if (!(msg = calloc(1, payloadlength+1))) { |
596 free(snptr); | |
4870 | 597 return -ENOMEM; |
4895 | 598 } |
4870 | 599 |
4826 | 600 while (payloadlength - recvd) { |
601 if (payloadlength - recvd >= 1024) | |
4870 | 602 i = aim_recv(conn->fd, &msg[recvd], 1024); |
4826 | 603 else |
4870 | 604 i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd); |
4826 | 605 if (i <= 0) { |
606 free(msg); | |
4895 | 607 free(snptr); |
4826 | 608 return -1; |
609 } | |
610 recvd = recvd + i; | |
611 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) | |
4870 | 612 ret = userfunc(sess, &fr, snptr, (double)recvd / payloadlength); |
4826 | 613 } |
614 | |
4870 | 615 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING))) |
616 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding, isawaymsg); | |
4826 | 617 |
618 free(msg); | |
619 } | |
620 | |
4895 | 621 free(snptr); |
622 | |
4870 | 623 return ret; |
4826 | 624 } |
625 | |
5146 | 626 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) |
627 { | |
628 struct aim_oft_info *new; | |
629 | |
630 if (!sess) | |
631 return NULL; | |
632 | |
633 if (!(new = (struct aim_oft_info *)calloc(1, sizeof(struct aim_oft_info)))) | |
634 return NULL; | |
635 | |
636 new->sess = sess; | |
637 if (cookie) | |
638 memcpy(new->cookie, cookie, 8); | |
639 if (ip) | |
640 new->clientip = strdup(ip); | |
641 if (sn) | |
642 new->sn = strdup(sn); | |
643 new->port = port; | |
644 new->fh.totfiles = 1; | |
645 new->fh.filesleft = 1; | |
646 new->fh.totparts = 1; | |
647 new->fh.partsleft = 1; | |
648 new->fh.totsize = size; | |
649 new->fh.size = size; | |
650 new->fh.modtime = modtime; | |
651 new->fh.checksum = 0xffff0000; | |
652 new->fh.rfrcsum = 0xffff0000; | |
653 new->fh.rfcsum = 0xffff0000; | |
654 new->fh.recvcsum = 0xffff0000; | |
655 strncpy(new->fh.idstring, "OFT_Windows ICBMFT V1.1 32", 31); | |
8446 | 656 if (filename) { |
5146 | 657 strncpy(new->fh.name, filename, 63); |
8446 | 658 new->fh.name[63] = '\0'; |
659 } | |
5146 | 660 |
661 new->next = sess->oft_info; | |
662 sess->oft_info = new; | |
663 | |
664 return new; | |
665 } | |
666 | |
667 /** | |
668 * Remove the given oft_info struct from the oft_info linked list, and | |
669 * then free its memory. | |
670 * | |
671 * @param sess The session. | |
672 * @param oft_info The aim_oft_info struct that we're destroying. | |
673 * @return Return 0 if no errors, otherwise return the error number. | |
674 */ | |
675 faim_export int aim_oft_destroyinfo(struct aim_oft_info *oft_info) | |
676 { | |
677 aim_session_t *sess; | |
678 | |
679 if (!oft_info || !(sess = oft_info->sess)) | |
680 return -EINVAL; | |
681 | |
682 if (sess->oft_info && (sess->oft_info == oft_info)) { | |
683 sess->oft_info = sess->oft_info->next; | |
684 } else { | |
685 struct aim_oft_info *cur; | |
686 for (cur=sess->oft_info; (cur->next && (cur->next!=oft_info)); cur=cur->next); | |
687 if (cur->next) | |
688 cur->next = cur->next->next; | |
689 } | |
690 | |
691 free(oft_info->sn); | |
692 free(oft_info->proxyip); | |
693 free(oft_info->clientip); | |
694 free(oft_info->verifiedip); | |
695 free(oft_info); | |
696 | |
697 return 0; | |
698 } | |
699 | |
4826 | 700 /** |
4617 | 701 * Creates a listener socket so the other dude can connect to us. |
2086 | 702 * |
4617 | 703 * You'll want to set up some kind of watcher on this socket. |
704 * When the state changes, call aim_handlerendconnection with | |
705 * the connection returned by this. aim_handlerendconnection | |
706 * will accept the pending connection and stop listening. | |
2086 | 707 * |
4617 | 708 * @param sess The session. |
5146 | 709 * @param oft_info File transfer information associated with this |
710 * connection. | |
711 * @return Return 0 if no errors, otherwise return the error number. | |
2086 | 712 */ |
8240 | 713 faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info, int listenfd) |
2086 | 714 { |
5146 | 715 if (!oft_info) |
716 return -EINVAL; | |
2086 | 717 |
5146 | 718 if (!(oft_info->conn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { |
4617 | 719 close(listenfd); |
5146 | 720 return -ENOMEM; |
3952 | 721 } |
3630 | 722 |
5146 | 723 oft_info->conn->fd = listenfd; |
724 oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; | |
725 oft_info->conn->lastactivity = time(NULL); | |
3952 | 726 |
5146 | 727 return 0; |
4617 | 728 } |
3630 | 729 |
4617 | 730 /** |
731 * Extract an &aim_fileheader_t from the given buffer. | |
732 * | |
733 * @param bs The should be from an incoming rendezvous packet. | |
734 * @return A pointer to new struct on success, or NULL on error. | |
735 */ | |
736 static struct aim_fileheader_t *aim_oft_getheader(aim_bstream_t *bs) | |
737 { | |
738 struct aim_fileheader_t *fh; | |
3630 | 739 |
4617 | 740 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t)))) |
741 return NULL; | |
3630 | 742 |
4617 | 743 /* The bstream should be positioned after the hdrtype. */ |
744 aimbs_getrawbuf(bs, fh->bcookie, 8); | |
745 fh->encrypt = aimbs_get16(bs); | |
746 fh->compress = aimbs_get16(bs); | |
747 fh->totfiles = aimbs_get16(bs); | |
748 fh->filesleft = aimbs_get16(bs); | |
749 fh->totparts = aimbs_get16(bs); | |
750 fh->partsleft = aimbs_get16(bs); | |
751 fh->totsize = aimbs_get32(bs); | |
752 fh->size = aimbs_get32(bs); | |
753 fh->modtime = aimbs_get32(bs); | |
754 fh->checksum = aimbs_get32(bs); | |
755 fh->rfrcsum = aimbs_get32(bs); | |
756 fh->rfsize = aimbs_get32(bs); | |
757 fh->cretime = aimbs_get32(bs); | |
758 fh->rfcsum = aimbs_get32(bs); | |
759 fh->nrecvd = aimbs_get32(bs); | |
760 fh->recvcsum = aimbs_get32(bs); | |
761 aimbs_getrawbuf(bs, fh->idstring, 32); | |
762 fh->flags = aimbs_get8(bs); | |
763 fh->lnameoffset = aimbs_get8(bs); | |
764 fh->lsizeoffset = aimbs_get8(bs); | |
765 aimbs_getrawbuf(bs, fh->dummy, 69); | |
766 aimbs_getrawbuf(bs, fh->macfileinfo, 16); | |
767 fh->nencode = aimbs_get16(bs); | |
768 fh->nlanguage = aimbs_get16(bs); | |
769 aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */ | |
8446 | 770 fh->name[63] = '\0'; |
2086 | 771 |
4617 | 772 return fh; |
773 } | |
3630 | 774 |
4617 | 775 /** |
776 * Fills a buffer with network-order fh data | |
777 * | |
778 * @param bs A bstream to fill -- automatically initialized | |
779 * @param fh A struct aim_fileheader_t to get data from. | |
780 * @return Return non-zero on error. | |
781 */ | |
782 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) | |
783 { | |
784 fu8_t *hdr; | |
3630 | 785 |
4617 | 786 if (!bs || !fh) |
787 return -EINVAL; | |
3952 | 788 |
4617 | 789 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) |
790 return -ENOMEM; | |
3630 | 791 |
4617 | 792 aim_bstream_init(bs, hdr, 0x100 - 8); |
793 aimbs_putraw(bs, fh->bcookie, 8); | |
794 aimbs_put16(bs, fh->encrypt); | |
795 aimbs_put16(bs, fh->compress); | |
796 aimbs_put16(bs, fh->totfiles); | |
797 aimbs_put16(bs, fh->filesleft); | |
798 aimbs_put16(bs, fh->totparts); | |
799 aimbs_put16(bs, fh->partsleft); | |
800 aimbs_put32(bs, fh->totsize); | |
801 aimbs_put32(bs, fh->size); | |
802 aimbs_put32(bs, fh->modtime); | |
803 aimbs_put32(bs, fh->checksum); | |
804 aimbs_put32(bs, fh->rfrcsum); | |
805 aimbs_put32(bs, fh->rfsize); | |
806 aimbs_put32(bs, fh->cretime); | |
807 aimbs_put32(bs, fh->rfcsum); | |
808 aimbs_put32(bs, fh->nrecvd); | |
809 aimbs_put32(bs, fh->recvcsum); | |
810 aimbs_putraw(bs, fh->idstring, 32); | |
811 aimbs_put8(bs, fh->flags); | |
812 aimbs_put8(bs, fh->lnameoffset); | |
813 aimbs_put8(bs, fh->lsizeoffset); | |
814 aimbs_putraw(bs, fh->dummy, 69); | |
815 aimbs_putraw(bs, fh->macfileinfo, 16); | |
816 aimbs_put16(bs, fh->nencode); | |
817 aimbs_put16(bs, fh->nlanguage); | |
818 aimbs_putraw(bs, fh->name, 64); /* XXX - filenames longer than 64B */ | |
3952 | 819 |
4617 | 820 return 0; |
821 } | |
2086 | 822 |
4617 | 823 /** |
824 * Create an OFT packet based on the given information, and send it on its merry way. | |
825 * | |
826 * @param sess The session. | |
5146 | 827 * @param type The subtype of the OFT packet we're sending. |
828 * @param oft_info The aim_oft_info struct with the connection and OFT | |
829 * info we're sending. | |
4617 | 830 * @return Return 0 if no errors, otherwise return the error number. |
831 */ | |
5146 | 832 faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info) |
4617 | 833 { |
5146 | 834 aim_frame_t *fr; |
2086 | 835 |
5146 | 836 if (!sess || !oft_info || !oft_info->conn || (oft_info->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) |
4617 | 837 return -EINVAL; |
838 | |
5146 | 839 #if 0 |
4617 | 840 /* |
841 * If you are receiving a file, the cookie should be null, if you are sending a | |
842 * file, the cookie should be the same as the one used in the ICBM negotiation | |
843 * SNACs. | |
844 */ | |
3952 | 845 fh->lnameoffset = 0x1a; |
846 fh->lsizeoffset = 0x10; | |
2086 | 847 |
4617 | 848 /* apparently 0 is ASCII, 2 is UCS-2 */ |
849 /* it is likely that 3 is ISO 8859-1 */ | |
4826 | 850 /* I think "nlanguage" might be the same thing as "subenc" in im.c */ |
3952 | 851 fh->nencode = 0x0000; |
852 fh->nlanguage = 0x0000; | |
5146 | 853 #endif |
4617 | 854 |
5146 | 855 aim_oft_dirconvert_tostupid(oft_info->fh.name); |
2086 | 856 |
5146 | 857 if (!(fr = aim_tx_new(sess, oft_info->conn, AIM_FRAMETYPE_OFT, type, 0))) |
858 return -ENOMEM; | |
859 | |
860 if (aim_oft_buildheader(&fr->data, &oft_info->fh) == -1) { | |
861 aim_frame_destroy(fr); | |
4617 | 862 return -ENOMEM; |
3952 | 863 } |
2086 | 864 |
5146 | 865 memcpy(fr->hdr.rend.magic, "OFT2", 4); |
8426 | 866 fr->hdr.rend.hdrlen = aim_bstream_curpos(&fr->data) + 8; |
2086 | 867 |
5146 | 868 aim_tx_enqueue(sess, fr); |
3952 | 869 |
870 return 0; | |
2086 | 871 } |
872 | |
873 /** | |
4617 | 874 * Handle incoming data on a rendezvous connection. This is analogous to the |
875 * consumesnac function in rxhandlers.c, and I really think this should probably | |
876 * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet. | |
877 * | |
878 * @param sess The session. | |
879 * @param fr The frame allocated for the incoming data. | |
880 * @return Return 0 if the packet was handled correctly, otherwise return the | |
881 * error number. | |
3771 | 882 */ |
3952 | 883 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) |
2086 | 884 { |
3952 | 885 aim_conn_t *conn = fr->conn; |
4617 | 886 int ret = 1; |
2086 | 887 |
4617 | 888 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { |
889 if (fr->hdr.rend.type == 0x0001) | |
890 ret = handlehdr_odc(sess, conn, fr, &fr->data); | |
891 else | |
892 faimdprintf(sess, 0, "faim: ODC directim frame unknown, type is %04x\n", fr->hdr.rend.type); | |
2086 | 893 |
4826 | 894 } else { |
4617 | 895 aim_rxcallback_t userfunc; |
896 struct aim_fileheader_t *header = aim_oft_getheader(&fr->data); | |
897 aim_oft_dirconvert_fromstupid(header->name); /* XXX - This should be client-side */ | |
3771 | 898 |
4617 | 899 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, fr->hdr.rend.type))) |
900 ret = userfunc(sess, fr, conn, header->bcookie, header); | |
901 | |
902 free(header); | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
903 } |
4617 | 904 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
905 if (ret == -1) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
906 aim_conn_close(conn); |
2086 | 907 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
908 return ret; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
909 } |