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