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