Mercurial > pidgin.yaz
annotate src/protocols/oscar/ft.c @ 9070:f13172eed3ad
[gaim-migrate @ 9846]
This fixes what is hopefully the last common direct connect segfault.
Basicly, we were memcpying cookies, and one was null. This was because
our get the cookie function was returning null, because it checked if the
conn was a direct im conn and it wasn't. It was a listening conn instead.
So this adds NULL checks, and makes the get cookie function do less sanity
checking, since it was failing some valid cases.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Wed, 26 May 2004 04:55:10 +0000 |
parents | 460d02fe03df |
children | 30a812571a6b |
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. |
8983 | 393 * |
4617 | 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 |
8983 | 404 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || |
2246
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 /** | |
8983 | 414 * Get the cookie of a direct connection. |
415 * | |
416 * @param conn The ODC connection. | |
417 * @return The cookie, an 8 byte unterminated string, or NULL if there was an anomaly. | |
418 */ | |
419 faim_export const char *aim_odc_getcookie(aim_conn_t *conn) | |
420 { | |
421 struct aim_odc_intdata *intdata; | |
422 | |
423 if (!conn || !conn->internal) | |
424 return NULL; | |
425 | |
426 intdata = (struct aim_odc_intdata *)conn->internal; | |
427 | |
428 return intdata->cookie; | |
429 } | |
430 | |
431 /** | |
4617 | 432 * Find the conn of a direct connection with the given buddy. |
433 * | |
434 * @param sess The session. | |
435 * @param sn The screen name of the buddy whose direct connection you want to find. | |
436 * @return The conn for the direct connection with the given buddy, or NULL if no | |
437 * connection was found. | |
438 */ | |
439 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn) | |
440 { | |
441 aim_conn_t *cur; | |
442 struct aim_odc_intdata *intdata; | |
443 | |
444 if (!sess || !sn || !strlen(sn)) | |
445 return NULL; | |
446 | |
447 for (cur = sess->connlist; cur; cur = cur->next) { | |
448 if ((cur->type == AIM_CONN_TYPE_RENDEZVOUS) && (cur->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) { | |
449 intdata = cur->internal; | |
450 if (!aim_sncmp(intdata->sn, sn)) | |
451 return cur; | |
452 } | |
453 } | |
454 | |
455 return NULL; | |
456 } | |
457 | |
458 /** | |
459 * For those times when we want to open up the direct connection channel ourselves. | |
460 * | |
8982 | 461 * You'll want to set up some kind of watcher on this socket. |
462 * When the state changes, call aim_handlerendconnection with | |
463 * the connection returned by this. aim_handlerendconnection | |
4617 | 464 * will accept the pending connection and stop listening. |
465 * | |
466 * @param sess The session | |
467 * @param sn The screen name to connect to. | |
468 * @return The new connection. | |
469 */ | |
8982 | 470 faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn, int listenfd, |
471 const fu8_t *localip, fu16_t port, const fu8_t *mycookie) | |
4617 | 472 { |
473 aim_conn_t *newconn; | |
474 aim_msgcookie_t *cookie; | |
475 struct aim_odc_intdata *priv; | |
476 fu8_t ck[8]; | |
477 | |
8982 | 478 if (!localip) |
4617 | 479 return NULL; |
480 | |
8982 | 481 if (mycookie) { |
482 memcpy(ck, mycookie, 8); | |
483 aim_im_sendch2_odcrequest(sess, ck, TRUE, sn, localip, port); | |
484 } else | |
485 aim_im_sendch2_odcrequest(sess, ck, FALSE, sn, localip, port); | |
4617 | 486 |
487 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); | |
488 memcpy(cookie->cookie, ck, 8); | |
489 cookie->type = AIM_COOKIETYPE_OFTIM; | |
490 | |
491 /* this one is for the cookie */ | |
492 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); | |
493 | |
494 memcpy(priv->cookie, ck, 8); | |
495 strncpy(priv->sn, sn, sizeof(priv->sn)); | |
496 cookie->data = priv; | |
497 aim_cachecookie(sess, cookie); | |
498 | |
499 /* XXX - switch to aim_cloneconn()? */ | |
500 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { | |
501 close(listenfd); | |
502 return NULL; | |
503 } | |
504 | |
505 /* this one is for the conn */ | |
506 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); | |
507 | |
508 memcpy(priv->cookie, ck, 8); | |
509 strncpy(priv->sn, sn, sizeof(priv->sn)); | |
510 | |
511 newconn->fd = listenfd; | |
512 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; | |
513 newconn->internal = priv; | |
514 newconn->lastactivity = time(NULL); | |
515 | |
516 return newconn; | |
517 } | |
518 | |
519 /** | |
520 * Connect directly to the given buddy for directim. | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
521 * |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
522 * This is a wrapper for aim_newconn. |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
523 * |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
524 * 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
|
525 * allocated and setup to connect. |
2086 | 526 * |
4617 | 527 * @param sess The Godly session. |
528 * @param sn The screen name we're connecting to. I hope it's a girl... | |
529 * @param addr Address to connect to. | |
530 * @return The new connection. | |
2086 | 531 */ |
4617 | 532 faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie) |
533 { | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
534 aim_conn_t *newconn; |
4617 | 535 struct aim_odc_intdata *intdata; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
536 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
537 if (!sess || !sn) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
538 return NULL; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
539 |
5146 | 540 if (!(intdata = calloc(1, sizeof(struct aim_odc_intdata)))) |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
541 return NULL; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
542 memcpy(intdata->cookie, cookie, 8); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
543 strncpy(intdata->sn, sn, sizeof(intdata->sn)); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
544 if (addr) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
545 strncpy(intdata->ip, addr, sizeof(intdata->ip)); |
2086 | 546 |
4617 | 547 /* XXX - verify that non-blocking connects actually work */ |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
548 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) { |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
549 free(intdata); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
550 return NULL; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
551 } |
2086 | 552 |
4617 | 553 newconn->internal = intdata; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
554 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
555 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
556 return newconn; |
4617 | 557 } |
2086 | 558 |
559 /** | |
4826 | 560 * Sometimes you just don't know with these kinds of people. |
561 * | |
562 * @param sess The session. | |
563 * @param conn The ODC connection of the incoming data. | |
564 * @param frr The frame allocated for the incoming data. | |
565 * @param bs It stands for "bologna sandwich." | |
566 * @return Return 0 if no errors, otherwise return the error number. | |
567 */ | |
568 static int handlehdr_odc(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *frr, aim_bstream_t *bs) | |
569 { | |
570 aim_frame_t fr; | |
4870 | 571 int ret = 0; |
4826 | 572 aim_rxcallback_t userfunc; |
573 fu32_t payloadlength; | |
574 fu16_t flags, encoding; | |
575 char *snptr = NULL; | |
576 | |
577 fr.conn = conn; | |
578 | |
579 /* AAA - ugly */ | |
580 aim_bstream_setpos(bs, 20); | |
581 payloadlength = aimbs_get32(bs); | |
582 | |
583 aim_bstream_setpos(bs, 24); | |
584 encoding = aimbs_get16(bs); | |
585 | |
586 aim_bstream_setpos(bs, 30); | |
587 flags = aimbs_get16(bs); | |
588 | |
589 aim_bstream_setpos(bs, 36); | |
590 /* XXX - create an aimbs_getnullstr function? */ | |
4913 | 591 snptr = aimbs_getstr(bs, 32); /* Next 32 bytes contain the sn, padded with null chars */ |
4826 | 592 |
593 faimdprintf(sess, 2, "faim: OFT frame: handlehdr_odc: %04x / %04x / %s\n", payloadlength, flags, snptr); | |
594 | |
4870 | 595 if (flags & 0x0008) { |
596 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) | |
597 ret = userfunc(sess, &fr, snptr, 2); | |
598 } else if (flags & 0x0004) { | |
599 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) | |
600 ret = userfunc(sess, &fr, snptr, 1); | |
601 } else { | |
4826 | 602 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) |
603 ret = userfunc(sess, &fr, snptr, 0); | |
4870 | 604 } |
4826 | 605 |
8000 | 606 if ((payloadlength != 0) && (payloadlength != UINT_MAX)) { |
4870 | 607 char *msg; |
4826 | 608 int recvd = 0; |
4870 | 609 int i, isawaymsg; |
610 | |
611 isawaymsg = flags & 0x0001; | |
4826 | 612 |
4895 | 613 if (!(msg = calloc(1, payloadlength+1))) { |
614 free(snptr); | |
4870 | 615 return -ENOMEM; |
4895 | 616 } |
4870 | 617 |
4826 | 618 while (payloadlength - recvd) { |
619 if (payloadlength - recvd >= 1024) | |
4870 | 620 i = aim_recv(conn->fd, &msg[recvd], 1024); |
4826 | 621 else |
4870 | 622 i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd); |
4826 | 623 if (i <= 0) { |
624 free(msg); | |
4895 | 625 free(snptr); |
4826 | 626 return -1; |
627 } | |
628 recvd = recvd + i; | |
629 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) | |
4870 | 630 ret = userfunc(sess, &fr, snptr, (double)recvd / payloadlength); |
4826 | 631 } |
632 | |
4870 | 633 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING))) |
634 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding, isawaymsg); | |
4826 | 635 |
636 free(msg); | |
637 } | |
638 | |
4895 | 639 free(snptr); |
640 | |
4870 | 641 return ret; |
4826 | 642 } |
643 | |
5146 | 644 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) |
645 { | |
646 struct aim_oft_info *new; | |
647 | |
648 if (!sess) | |
649 return NULL; | |
650 | |
651 if (!(new = (struct aim_oft_info *)calloc(1, sizeof(struct aim_oft_info)))) | |
652 return NULL; | |
653 | |
654 new->sess = sess; | |
655 if (cookie) | |
656 memcpy(new->cookie, cookie, 8); | |
657 if (ip) | |
658 new->clientip = strdup(ip); | |
659 if (sn) | |
660 new->sn = strdup(sn); | |
661 new->port = port; | |
662 new->fh.totfiles = 1; | |
663 new->fh.filesleft = 1; | |
664 new->fh.totparts = 1; | |
665 new->fh.partsleft = 1; | |
666 new->fh.totsize = size; | |
667 new->fh.size = size; | |
668 new->fh.modtime = modtime; | |
669 new->fh.checksum = 0xffff0000; | |
670 new->fh.rfrcsum = 0xffff0000; | |
671 new->fh.rfcsum = 0xffff0000; | |
672 new->fh.recvcsum = 0xffff0000; | |
673 strncpy(new->fh.idstring, "OFT_Windows ICBMFT V1.1 32", 31); | |
8446 | 674 if (filename) { |
5146 | 675 strncpy(new->fh.name, filename, 63); |
8446 | 676 new->fh.name[63] = '\0'; |
677 } | |
5146 | 678 |
679 new->next = sess->oft_info; | |
680 sess->oft_info = new; | |
681 | |
682 return new; | |
683 } | |
684 | |
685 /** | |
686 * Remove the given oft_info struct from the oft_info linked list, and | |
687 * then free its memory. | |
688 * | |
689 * @param sess The session. | |
690 * @param oft_info The aim_oft_info struct that we're destroying. | |
691 * @return Return 0 if no errors, otherwise return the error number. | |
692 */ | |
693 faim_export int aim_oft_destroyinfo(struct aim_oft_info *oft_info) | |
694 { | |
695 aim_session_t *sess; | |
696 | |
697 if (!oft_info || !(sess = oft_info->sess)) | |
698 return -EINVAL; | |
699 | |
700 if (sess->oft_info && (sess->oft_info == oft_info)) { | |
701 sess->oft_info = sess->oft_info->next; | |
702 } else { | |
703 struct aim_oft_info *cur; | |
704 for (cur=sess->oft_info; (cur->next && (cur->next!=oft_info)); cur=cur->next); | |
705 if (cur->next) | |
706 cur->next = cur->next->next; | |
707 } | |
708 | |
709 free(oft_info->sn); | |
710 free(oft_info->proxyip); | |
711 free(oft_info->clientip); | |
712 free(oft_info->verifiedip); | |
713 free(oft_info); | |
714 | |
715 return 0; | |
716 } | |
717 | |
4826 | 718 /** |
4617 | 719 * Creates a listener socket so the other dude can connect to us. |
2086 | 720 * |
4617 | 721 * You'll want to set up some kind of watcher on this socket. |
722 * When the state changes, call aim_handlerendconnection with | |
723 * the connection returned by this. aim_handlerendconnection | |
724 * will accept the pending connection and stop listening. | |
2086 | 725 * |
4617 | 726 * @param sess The session. |
5146 | 727 * @param oft_info File transfer information associated with this |
728 * connection. | |
729 * @return Return 0 if no errors, otherwise return the error number. | |
2086 | 730 */ |
8240 | 731 faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info, int listenfd) |
2086 | 732 { |
5146 | 733 if (!oft_info) |
734 return -EINVAL; | |
2086 | 735 |
5146 | 736 if (!(oft_info->conn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { |
4617 | 737 close(listenfd); |
5146 | 738 return -ENOMEM; |
3952 | 739 } |
3630 | 740 |
5146 | 741 oft_info->conn->fd = listenfd; |
742 oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; | |
743 oft_info->conn->lastactivity = time(NULL); | |
3952 | 744 |
5146 | 745 return 0; |
4617 | 746 } |
3630 | 747 |
4617 | 748 /** |
749 * Extract an &aim_fileheader_t from the given buffer. | |
750 * | |
751 * @param bs The should be from an incoming rendezvous packet. | |
752 * @return A pointer to new struct on success, or NULL on error. | |
753 */ | |
754 static struct aim_fileheader_t *aim_oft_getheader(aim_bstream_t *bs) | |
755 { | |
756 struct aim_fileheader_t *fh; | |
3630 | 757 |
4617 | 758 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t)))) |
759 return NULL; | |
3630 | 760 |
4617 | 761 /* The bstream should be positioned after the hdrtype. */ |
762 aimbs_getrawbuf(bs, fh->bcookie, 8); | |
763 fh->encrypt = aimbs_get16(bs); | |
764 fh->compress = aimbs_get16(bs); | |
765 fh->totfiles = aimbs_get16(bs); | |
766 fh->filesleft = aimbs_get16(bs); | |
767 fh->totparts = aimbs_get16(bs); | |
768 fh->partsleft = aimbs_get16(bs); | |
769 fh->totsize = aimbs_get32(bs); | |
770 fh->size = aimbs_get32(bs); | |
771 fh->modtime = aimbs_get32(bs); | |
772 fh->checksum = aimbs_get32(bs); | |
773 fh->rfrcsum = aimbs_get32(bs); | |
774 fh->rfsize = aimbs_get32(bs); | |
775 fh->cretime = aimbs_get32(bs); | |
776 fh->rfcsum = aimbs_get32(bs); | |
777 fh->nrecvd = aimbs_get32(bs); | |
778 fh->recvcsum = aimbs_get32(bs); | |
779 aimbs_getrawbuf(bs, fh->idstring, 32); | |
780 fh->flags = aimbs_get8(bs); | |
781 fh->lnameoffset = aimbs_get8(bs); | |
782 fh->lsizeoffset = aimbs_get8(bs); | |
783 aimbs_getrawbuf(bs, fh->dummy, 69); | |
784 aimbs_getrawbuf(bs, fh->macfileinfo, 16); | |
785 fh->nencode = aimbs_get16(bs); | |
786 fh->nlanguage = aimbs_get16(bs); | |
787 aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */ | |
8446 | 788 fh->name[63] = '\0'; |
2086 | 789 |
4617 | 790 return fh; |
791 } | |
3630 | 792 |
4617 | 793 /** |
794 * Fills a buffer with network-order fh data | |
795 * | |
796 * @param bs A bstream to fill -- automatically initialized | |
797 * @param fh A struct aim_fileheader_t to get data from. | |
798 * @return Return non-zero on error. | |
799 */ | |
800 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) | |
801 { | |
802 fu8_t *hdr; | |
3630 | 803 |
4617 | 804 if (!bs || !fh) |
805 return -EINVAL; | |
3952 | 806 |
4617 | 807 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) |
808 return -ENOMEM; | |
3630 | 809 |
4617 | 810 aim_bstream_init(bs, hdr, 0x100 - 8); |
811 aimbs_putraw(bs, fh->bcookie, 8); | |
812 aimbs_put16(bs, fh->encrypt); | |
813 aimbs_put16(bs, fh->compress); | |
814 aimbs_put16(bs, fh->totfiles); | |
815 aimbs_put16(bs, fh->filesleft); | |
816 aimbs_put16(bs, fh->totparts); | |
817 aimbs_put16(bs, fh->partsleft); | |
818 aimbs_put32(bs, fh->totsize); | |
819 aimbs_put32(bs, fh->size); | |
820 aimbs_put32(bs, fh->modtime); | |
821 aimbs_put32(bs, fh->checksum); | |
822 aimbs_put32(bs, fh->rfrcsum); | |
823 aimbs_put32(bs, fh->rfsize); | |
824 aimbs_put32(bs, fh->cretime); | |
825 aimbs_put32(bs, fh->rfcsum); | |
826 aimbs_put32(bs, fh->nrecvd); | |
827 aimbs_put32(bs, fh->recvcsum); | |
828 aimbs_putraw(bs, fh->idstring, 32); | |
829 aimbs_put8(bs, fh->flags); | |
830 aimbs_put8(bs, fh->lnameoffset); | |
831 aimbs_put8(bs, fh->lsizeoffset); | |
832 aimbs_putraw(bs, fh->dummy, 69); | |
833 aimbs_putraw(bs, fh->macfileinfo, 16); | |
834 aimbs_put16(bs, fh->nencode); | |
835 aimbs_put16(bs, fh->nlanguage); | |
836 aimbs_putraw(bs, fh->name, 64); /* XXX - filenames longer than 64B */ | |
3952 | 837 |
4617 | 838 return 0; |
839 } | |
2086 | 840 |
4617 | 841 /** |
842 * Create an OFT packet based on the given information, and send it on its merry way. | |
843 * | |
844 * @param sess The session. | |
5146 | 845 * @param type The subtype of the OFT packet we're sending. |
846 * @param oft_info The aim_oft_info struct with the connection and OFT | |
847 * info we're sending. | |
4617 | 848 * @return Return 0 if no errors, otherwise return the error number. |
849 */ | |
5146 | 850 faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info) |
4617 | 851 { |
5146 | 852 aim_frame_t *fr; |
2086 | 853 |
5146 | 854 if (!sess || !oft_info || !oft_info->conn || (oft_info->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) |
4617 | 855 return -EINVAL; |
856 | |
5146 | 857 #if 0 |
4617 | 858 /* |
859 * If you are receiving a file, the cookie should be null, if you are sending a | |
860 * file, the cookie should be the same as the one used in the ICBM negotiation | |
861 * SNACs. | |
862 */ | |
3952 | 863 fh->lnameoffset = 0x1a; |
864 fh->lsizeoffset = 0x10; | |
2086 | 865 |
4617 | 866 /* apparently 0 is ASCII, 2 is UCS-2 */ |
867 /* it is likely that 3 is ISO 8859-1 */ | |
4826 | 868 /* I think "nlanguage" might be the same thing as "subenc" in im.c */ |
3952 | 869 fh->nencode = 0x0000; |
870 fh->nlanguage = 0x0000; | |
5146 | 871 #endif |
4617 | 872 |
5146 | 873 aim_oft_dirconvert_tostupid(oft_info->fh.name); |
2086 | 874 |
5146 | 875 if (!(fr = aim_tx_new(sess, oft_info->conn, AIM_FRAMETYPE_OFT, type, 0))) |
876 return -ENOMEM; | |
877 | |
878 if (aim_oft_buildheader(&fr->data, &oft_info->fh) == -1) { | |
879 aim_frame_destroy(fr); | |
4617 | 880 return -ENOMEM; |
3952 | 881 } |
2086 | 882 |
5146 | 883 memcpy(fr->hdr.rend.magic, "OFT2", 4); |
8426 | 884 fr->hdr.rend.hdrlen = aim_bstream_curpos(&fr->data) + 8; |
2086 | 885 |
5146 | 886 aim_tx_enqueue(sess, fr); |
3952 | 887 |
888 return 0; | |
2086 | 889 } |
890 | |
891 /** | |
4617 | 892 * Handle incoming data on a rendezvous connection. This is analogous to the |
893 * consumesnac function in rxhandlers.c, and I really think this should probably | |
894 * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet. | |
895 * | |
896 * @param sess The session. | |
897 * @param fr The frame allocated for the incoming data. | |
898 * @return Return 0 if the packet was handled correctly, otherwise return the | |
899 * error number. | |
3771 | 900 */ |
3952 | 901 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) |
2086 | 902 { |
3952 | 903 aim_conn_t *conn = fr->conn; |
4617 | 904 int ret = 1; |
2086 | 905 |
4617 | 906 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { |
907 if (fr->hdr.rend.type == 0x0001) | |
908 ret = handlehdr_odc(sess, conn, fr, &fr->data); | |
909 else | |
910 faimdprintf(sess, 0, "faim: ODC directim frame unknown, type is %04x\n", fr->hdr.rend.type); | |
2086 | 911 |
4826 | 912 } else { |
4617 | 913 aim_rxcallback_t userfunc; |
914 struct aim_fileheader_t *header = aim_oft_getheader(&fr->data); | |
915 aim_oft_dirconvert_fromstupid(header->name); /* XXX - This should be client-side */ | |
3771 | 916 |
4617 | 917 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, fr->hdr.rend.type))) |
918 ret = userfunc(sess, fr, conn, header->bcookie, header); | |
919 | |
920 free(header); | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
921 } |
4617 | 922 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
923 if (ret == -1) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
924 aim_conn_close(conn); |
2086 | 925 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
926 return ret; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
927 } |