Mercurial > pidgin
annotate src/protocols/oscar/ft.c @ 4617:858979ab3867
[gaim-migrate @ 4908]
Big Changes:
-Rewrote some of the perl stuff so perl scripts can change a few of their
parameters
-Receiving a file with AIM over oscar works pretty well
Now, the "nitty gritty":
Very minor change to prefs.c: In the plugins details tab, I changed "URL"
to "Web Site." I was just going to fix the tabbing, but silvestrij
suggested changing it to "Web site," and I thought that sounded good.
I think it fits better, too. I dunno, maybe that's just me.
"Get Capabilities" has stopped working for some reason. I'm just going to
blame AOL. It's really not important anyway, and some people wanted it
taken off. It is now #ifdef 0'ed out. I'll remove it completely if it
continues to no longer function.
I took out a few plugin_event calls from oscar.c and put them in core code.
"event_error" should be, uh, "evented" when there is an error signing on.
Hopefully no one was using this. It's really pretty useless. The parameter
is now the reason for not being able to connect rather than the archaic
toc error code.
I screwed around with how perl functions are called some. There was way the
hell too much malloc'ing going on here. I think all in all it's an
improvement, though I'm still not a big fan of how changes to parameters
propagate to the actual memory.
I really think it would be nice if the perl stuff was made into a C plugin.
It's just so much cleaner. Especially if someone wanted to write, say, a
python or tcl interpreter. That's how xchat2 does it. I just think that
would be really slick. Like butter. Or ice. Very unlike Velcro.
I added a "Change Password" Protocol Action for ICQ over oscar. This was
really pretty easy. I'd like to thank my housemate Andrew for complaining
a lot that having to use Windows ICQ to change his password was a pain.
I rewrote a lot of the oscar file transfer stuff to use Christian's new
xfer interface. This involved moving a few functions from ft.c to im.c,
where they belong. I also removed all the #if 0'ed getfile functions.
I'll be rewritting them soonish. Receiving a file should work perfectly,
aside from maybe a small memleak when stuff is canceled. Sending a file is
currently disabled. No ETA on when I'll have that working.
I renamed pretty much all of the functions in im.c so they have kind of a
scheme now. They should all be aim_im_bleh, since "im" is the family
name. There comes a time when you must break the crap out of any clients
that might be using libfaim in order to make stuff cleaner. Maybe.
I got rid of the snac destructor stuff for now. I'll probably add it back
later. I wasn't entirely comfortable with how it was done.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Wed, 26 Feb 2003 05:01:37 +0000 |
parents | 9891c1458eb7 |
children | 3c7d4a060d30 |
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 */ | |
116 faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, fu32_t prevcheck) | |
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 | |
2086 | 141 /** |
4617 | 142 * Create a listening socket on a given port. |
143 * | |
144 * XXX - Give the client author the responsibility of setting up a | |
145 * listener, then we no longer have a libfaim problem with broken | |
146 * solaris *innocent smile* -- jbm | |
2086 | 147 * |
4617 | 148 * @param portnum The port number to bind to. |
149 * @return The file descriptor of the listening socket. | |
150 */ | |
151 static int listenestablish(fu16_t portnum) | |
152 { | |
153 #if HAVE_GETADDRINFO | |
154 int listenfd; | |
155 const int on = 1; | |
156 struct addrinfo hints, *res, *ressave; | |
157 char serv[5]; | |
158 | |
159 snprintf(serv, sizeof(serv), "%d", portnum); | |
160 memset(&hints, 0, sizeof(struct addrinfo)); | |
161 hints.ai_flags = AI_PASSIVE; | |
162 hints.ai_family = AF_UNSPEC; | |
163 hints.ai_socktype = SOCK_STREAM; | |
164 if (getaddrinfo(NULL /* any IP */, serv, &hints, &res) != 0) { | |
165 perror("getaddrinfo"); | |
166 return -1; | |
167 } | |
168 ressave = res; | |
169 do { | |
170 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); | |
171 if (listenfd < 0) | |
172 continue; | |
173 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); | |
174 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) | |
175 break; /* success */ | |
176 close(listenfd); | |
177 } while ( (res = res->ai_next) ); | |
178 | |
179 if (!res) | |
180 return -1; | |
181 | |
182 freeaddrinfo(ressave); | |
183 #else | |
184 int listenfd; | |
185 const int on = 1; | |
186 struct sockaddr_in sockin; | |
187 | |
188 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
189 perror("socket"); | |
190 return -1; | |
191 } | |
192 | |
193 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) { | |
194 perror("setsockopt"); | |
195 close(listenfd); | |
196 return -1; | |
197 } | |
198 | |
199 memset(&sockin, 0, sizeof(struct sockaddr_in)); | |
200 sockin.sin_family = AF_INET; | |
201 sockin.sin_port = htons(portnum); | |
202 | |
203 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { | |
204 perror("bind"); | |
205 close(listenfd); | |
206 return -1; | |
207 } | |
208 #endif | |
209 | |
210 if (listen(listenfd, 4) != 0) { | |
211 perror("listen"); | |
212 close(listenfd); | |
213 return -1; | |
214 } | |
215 fcntl(listenfd, F_SETFL, O_NONBLOCK); | |
216 | |
217 return listenfd; | |
218 } | |
219 | |
220 /** | |
221 * After establishing a listening socket, this is called to accept a connection. It | |
222 * clones the conn used by the listener, and passes both of these to a signal handler. | |
223 * The signal handler should close the listener conn and keep track of the new conn, | |
224 * since this is what is used for file transfers and what not. | |
225 * | |
226 * @param sess The session. | |
227 * @param cur The conn the incoming connection is on. | |
228 * @return Return 0 if no errors, otherwise return the error number. | |
2086 | 229 */ |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
230 faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur) |
4617 | 231 { |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
232 int acceptfd = 0; |
4617 | 233 struct sockaddr addr; |
234 socklen_t addrlen = sizeof(addr); | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
235 int ret = 0; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
236 aim_conn_t *newconn; |
4617 | 237 char ip[20]; |
238 int port; | |
2086 | 239 |
4617 | 240 debug_printf("AAA - We got a bite! Dude connected to listener\n"); |
241 if ((acceptfd = accept(cur->fd, &addr, &addrlen)) == -1) | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
242 return 0; /* not an error */ |
2086 | 243 |
4617 | 244 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
|
245 close(acceptfd); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
246 aim_conn_close(cur); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
247 return -1; |
4617 | 248 } |
249 | |
250 strncpy(ip, inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr), sizeof(ip)); | |
251 port = ntohs(((struct sockaddr_in *)&addr)->sin_port); | |
2086 | 252 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
253 if (!(newconn = aim_cloneconn(sess, cur))) { |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
254 close(acceptfd); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
255 aim_conn_close(cur); |
4617 | 256 return -ENOMEM; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
257 } |
2086 | 258 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
259 newconn->type = AIM_CONN_TYPE_RENDEZVOUS; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
260 newconn->fd = acceptfd; |
2086 | 261 |
4617 | 262 if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
263 aim_rxcallback_t userfunc; |
4617 | 264 struct aim_odc_intdata *priv; |
2086 | 265 |
4617 | 266 priv = (struct aim_odc_intdata *)(newconn->internal = cur->internal); |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
267 cur->internal = NULL; |
4617 | 268 snprintf(priv->ip, sizeof(priv->ip), "%s:%u", ip, port); |
2086 | 269 |
4617 | 270 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
|
271 ret = userfunc(sess, NULL, newconn, cur); |
2086 | 272 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
273 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { |
4617 | 274 } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
275 aim_rxcallback_t userfunc; |
2086 | 276 |
4617 | 277 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
|
278 ret = userfunc(sess, NULL, newconn, cur); |
3630 | 279 |
4617 | 280 } else { |
281 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
|
282 aim_conn_close(newconn); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
283 ret = -1; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
284 } |
2086 | 285 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
286 return ret; |
2086 | 287 } |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
288 |
2086 | 289 /** |
4617 | 290 * Send client-to-client typing notification over an established direct connection. |
2086 | 291 * |
4617 | 292 * @param sess The session. |
293 * @param conn The already-connected ODC connection. | |
294 * @param typing If true, notify user has started typing; if false, notify user has stopped. | |
295 * @return Return 0 if no errors, otherwise return the error number. | |
2086 | 296 */ |
4617 | 297 faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing) |
2086 | 298 { |
4617 | 299 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
|
300 aim_frame_t *fr; |
3952 | 301 aim_bstream_t *hdrbs; |
302 fu8_t *hdr; | |
303 int hdrlen = 0x44; | |
2086 | 304 |
3952 | 305 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) |
306 return -EINVAL; | |
2086 | 307 |
2993 | 308 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0))) |
3952 | 309 return -ENOMEM; |
310 memcpy(fr->hdr.rend.magic, "ODC2", 4); | |
311 fr->hdr.rend.hdrlen = hdrlen; | |
2086 | 312 |
3952 | 313 if (!(hdr = calloc(1, hdrlen))) { |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
314 aim_frame_destroy(fr); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
315 return -ENOMEM; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
316 } |
3952 | 317 |
318 hdrbs = &(fr->data); | |
319 aim_bstream_init(hdrbs, hdr, hdrlen); | |
2086 | 320 |
3952 | 321 aimbs_put16(hdrbs, 0x0006); |
322 aimbs_put16(hdrbs, 0x0000); | |
323 aimbs_putraw(hdrbs, intdata->cookie, 8); | |
324 aimbs_put16(hdrbs, 0x0000); | |
325 aimbs_put16(hdrbs, 0x0000); | |
326 aimbs_put16(hdrbs, 0x0000); | |
327 aimbs_put16(hdrbs, 0x0000); | |
328 aimbs_put32(hdrbs, 0x00000000); | |
329 aimbs_put16(hdrbs, 0x0000); | |
330 aimbs_put16(hdrbs, 0x0000); | |
331 aimbs_put16(hdrbs, 0x0000); | |
2086 | 332 |
2993 | 333 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing */ |
3952 | 334 aimbs_put16(hdrbs, ( typing ? 0x000e : 0x0002)); |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
335 |
3952 | 336 aimbs_put16(hdrbs, 0x0000); |
337 aimbs_put16(hdrbs, 0x0000); | |
338 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); | |
4617 | 339 |
3952 | 340 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ |
2086 | 341 |
3952 | 342 aimbs_put8(hdrbs, 0x00); |
343 aimbs_put16(hdrbs, 0x0000); | |
344 aimbs_put16(hdrbs, 0x0000); | |
345 aimbs_put16(hdrbs, 0x0000); | |
346 aimbs_put16(hdrbs, 0x0000); | |
347 aimbs_put16(hdrbs, 0x0000); | |
348 aimbs_put16(hdrbs, 0x0000); | |
349 aimbs_put16(hdrbs, 0x0000); | |
350 aimbs_put8(hdrbs, 0x00); | |
2086 | 351 |
3952 | 352 /* end of hdr */ |
2086 | 353 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
354 aim_tx_enqueue(sess, fr); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
355 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
356 return 0; |
4617 | 357 } |
2086 | 358 |
2993 | 359 /** |
4617 | 360 * Send client-to-client IM over an established direct connection. |
361 * Call this just like you would aim_send_im, to send a directim. | |
2993 | 362 * |
4617 | 363 * @param sess The session. |
364 * @param conn The already-connected ODC connection. | |
365 * @param msg Null-terminated string to send. | |
366 * @param len The length of the message to send, including binary data. | |
367 * @param encoding 0 for ascii, 2 for Unicode, 3 for ISO 8859-1. | |
368 * @return Return 0 if no errors, otherwise return the error number. | |
2993 | 369 */ |
4617 | 370 faim_export int aim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding) |
2993 | 371 { |
372 aim_frame_t *fr; | |
3952 | 373 aim_bstream_t *hdrbs; |
4617 | 374 struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal; |
3952 | 375 int hdrlen = 0x44; |
376 fu8_t *hdr; | |
2993 | 377 |
4617 | 378 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !msg) |
379 return -EINVAL; | |
2993 | 380 |
3033 | 381 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, len))) |
4617 | 382 return -ENOMEM; |
2993 | 383 |
3952 | 384 memcpy(fr->hdr.rend.magic, "ODC2", 4); |
385 fr->hdr.rend.hdrlen = hdrlen; | |
4617 | 386 |
3952 | 387 if (!(hdr = calloc(1, hdrlen + len))) { |
2993 | 388 aim_frame_destroy(fr); |
389 return -ENOMEM; | |
390 } | |
3952 | 391 |
392 hdrbs = &(fr->data); | |
393 aim_bstream_init(hdrbs, hdr, hdrlen + len); | |
394 | |
395 aimbs_put16(hdrbs, 0x0006); | |
396 aimbs_put16(hdrbs, 0x0000); | |
397 aimbs_putraw(hdrbs, intdata->cookie, 8); | |
398 aimbs_put16(hdrbs, 0x0000); | |
399 aimbs_put16(hdrbs, 0x0000); | |
400 aimbs_put16(hdrbs, 0x0000); | |
401 aimbs_put16(hdrbs, 0x0000); | |
402 aimbs_put32(hdrbs, len); | |
403 aimbs_put16(hdrbs, encoding); | |
404 aimbs_put16(hdrbs, 0x0000); | |
405 aimbs_put16(hdrbs, 0x0000); | |
4617 | 406 |
2993 | 407 /* flags -- 0x000e for "started typing", 0x0002 for "stopped typing, 0x0000 for message */ |
3952 | 408 aimbs_put16(hdrbs, 0x0000); |
409 | |
410 aimbs_put16(hdrbs, 0x0000); | |
411 aimbs_put16(hdrbs, 0x0000); | |
412 aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn)); | |
413 | |
414 aim_bstream_setpos(hdrbs, 52); /* bleeehh */ | |
415 | |
416 aimbs_put8(hdrbs, 0x00); | |
417 aimbs_put16(hdrbs, 0x0000); | |
418 aimbs_put16(hdrbs, 0x0000); | |
419 aimbs_put16(hdrbs, 0x0000); | |
420 aimbs_put16(hdrbs, 0x0000); | |
421 aimbs_put16(hdrbs, 0x0000); | |
422 aimbs_put16(hdrbs, 0x0000); | |
423 aimbs_put16(hdrbs, 0x0000); | |
424 aimbs_put8(hdrbs, 0x00); | |
4617 | 425 |
2993 | 426 /* end of hdr2 */ |
4617 | 427 |
428 #if 0 /* XXX - this is how you send buddy icon info... */ | |
429 aimbs_put16(hdrbs, 0x0008); | |
430 aimbs_put16(hdrbs, 0x000c); | |
431 aimbs_put16(hdrbs, 0x0000); | |
432 aimbs_put16(hdrbs, 0x1466); | |
433 aimbs_put16(hdrbs, 0x0001); | |
434 aimbs_put16(hdrbs, 0x2e0f); | |
435 aimbs_put16(hdrbs, 0x393e); | |
436 aimbs_put16(hdrbs, 0xcac8); | |
2993 | 437 #endif |
3952 | 438 aimbs_putraw(hdrbs, msg, len); |
4617 | 439 |
2993 | 440 aim_tx_enqueue(sess, fr); |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
441 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
442 return 0; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
443 } |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
444 |
2086 | 445 /** |
4617 | 446 * Get the screen name of the peer of a direct connection. |
447 * | |
448 * @param conn The ODC connection. | |
449 * @return The screen name of the dude, or NULL if there was an anomaly. | |
2086 | 450 */ |
4617 | 451 faim_export const char *aim_odc_getsn(aim_conn_t *conn) |
452 { | |
453 struct aim_odc_intdata *intdata; | |
3630 | 454 |
4617 | 455 if (!conn || !conn->internal) |
3952 | 456 return NULL; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
457 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
458 if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
459 (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) |
3952 | 460 return NULL; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
461 |
4617 | 462 intdata = (struct aim_odc_intdata *)conn->internal; |
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 intdata->sn; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
465 } |
2086 | 466 |
467 /** | |
4617 | 468 * Find the conn of a direct connection with the given buddy. |
469 * | |
470 * @param sess The session. | |
471 * @param sn The screen name of the buddy whose direct connection you want to find. | |
472 * @return The conn for the direct connection with the given buddy, or NULL if no | |
473 * connection was found. | |
474 */ | |
475 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn) | |
476 { | |
477 aim_conn_t *cur; | |
478 struct aim_odc_intdata *intdata; | |
479 | |
480 if (!sess || !sn || !strlen(sn)) | |
481 return NULL; | |
482 | |
483 for (cur = sess->connlist; cur; cur = cur->next) { | |
484 if ((cur->type == AIM_CONN_TYPE_RENDEZVOUS) && (cur->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) { | |
485 intdata = cur->internal; | |
486 if (!aim_sncmp(intdata->sn, sn)) | |
487 return cur; | |
488 } | |
489 } | |
490 | |
491 return NULL; | |
492 } | |
493 | |
494 /** | |
495 * For those times when we want to open up the direct connection channel ourselves. | |
496 * | |
497 * You'll want to set up some kind of watcher on this socket. | |
498 * When the state changes, call aim_handlerendconnection with | |
499 * the connection returned by this. aim_handlerendconnection | |
500 * will accept the pending connection and stop listening. | |
501 * | |
502 * @param sess The session | |
503 * @param conn The BOS conn. | |
504 * @param priv A dummy priv value (we'll let it get filled in later) | |
505 * (if you pass a %NULL, we alloc one). | |
506 * @param sn The screen name to connect to. | |
507 * @return The new connection. | |
508 */ | |
509 faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn) | |
510 { | |
511 aim_conn_t *newconn; | |
512 aim_msgcookie_t *cookie; | |
513 struct aim_odc_intdata *priv; | |
514 int listenfd; | |
515 fu16_t port = 4443; | |
516 fu8_t localip[4]; | |
517 fu8_t ck[8]; | |
518 | |
519 if (aim_util_getlocalip(localip) == -1) | |
520 return NULL; | |
521 | |
522 if ((listenfd = listenestablish(port)) == -1) | |
523 return NULL; | |
524 | |
525 aim_im_sendch2_odcrequest(sess, ck, sn, localip, port); | |
526 | |
527 cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); | |
528 memcpy(cookie->cookie, ck, 8); | |
529 cookie->type = AIM_COOKIETYPE_OFTIM; | |
530 | |
531 /* this one is for the cookie */ | |
532 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); | |
533 | |
534 memcpy(priv->cookie, ck, 8); | |
535 strncpy(priv->sn, sn, sizeof(priv->sn)); | |
536 cookie->data = priv; | |
537 aim_cachecookie(sess, cookie); | |
538 | |
539 /* XXX - switch to aim_cloneconn()? */ | |
540 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { | |
541 close(listenfd); | |
542 return NULL; | |
543 } | |
544 | |
545 /* this one is for the conn */ | |
546 priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata)); | |
547 | |
548 memcpy(priv->cookie, ck, 8); | |
549 strncpy(priv->sn, sn, sizeof(priv->sn)); | |
550 | |
551 newconn->fd = listenfd; | |
552 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; | |
553 newconn->internal = priv; | |
554 newconn->lastactivity = time(NULL); | |
555 | |
556 return newconn; | |
557 } | |
558 | |
559 /** | |
560 * Connect directly to the given buddy for directim. | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
561 * |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
562 * This is a wrapper for aim_newconn. |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
563 * |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
564 * 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
|
565 * allocated and setup to connect. |
2086 | 566 * |
4617 | 567 * @param sess The Godly session. |
568 * @param sn The screen name we're connecting to. I hope it's a girl... | |
569 * @param addr Address to connect to. | |
570 * @return The new connection. | |
2086 | 571 */ |
4617 | 572 faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie) |
573 { | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
574 aim_conn_t *newconn; |
4617 | 575 struct aim_odc_intdata *intdata; |
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 if (!sess || !sn) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
578 return NULL; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
579 |
4617 | 580 if (!(intdata = malloc(sizeof(struct aim_odc_intdata)))) |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
581 return NULL; |
4617 | 582 memset(intdata, 0, sizeof(struct aim_odc_intdata)); |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
583 memcpy(intdata->cookie, cookie, 8); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
584 strncpy(intdata->sn, sn, sizeof(intdata->sn)); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
585 if (addr) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
586 strncpy(intdata->ip, addr, sizeof(intdata->ip)); |
2086 | 587 |
4617 | 588 /* XXX - verify that non-blocking connects actually work */ |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
589 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) { |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
590 free(intdata); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
591 return NULL; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
592 } |
2086 | 593 |
4617 | 594 newconn->internal = intdata; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
595 newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
596 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
597 return newconn; |
4617 | 598 } |
2086 | 599 |
600 /** | |
4617 | 601 * Creates a listener socket so the other dude can connect to us. |
2086 | 602 * |
4617 | 603 * You'll want to set up some kind of watcher on this socket. |
604 * When the state changes, call aim_handlerendconnection with | |
605 * the connection returned by this. aim_handlerendconnection | |
606 * will accept the pending connection and stop listening. | |
2086 | 607 * |
4617 | 608 * @param sess The session. |
609 * @param cookie This better be Mrs. Fields or I'm going to be pissed. | |
610 * @param ip Should be 4 bytes, each byte is 1 quartet of the IP address. | |
611 * @param port Ye olde port number to listen on. | |
612 * @return Return the new conn if everything went as planned. Otherwise, | |
613 * return NULL. | |
2086 | 614 */ |
4617 | 615 faim_export aim_conn_t *aim_sendfile_listen(aim_session_t *sess, const fu8_t *cookie, const fu8_t *ip, fu16_t port) |
2086 | 616 { |
4617 | 617 aim_conn_t *newconn; |
618 int listenfd; | |
2086 | 619 |
4617 | 620 debug_printf("AAA - listening on port %d\n", port); |
621 if ((listenfd = listenestablish(port)) == -1) | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
622 return NULL; |
2086 | 623 |
4617 | 624 if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) { |
625 close(listenfd); | |
3952 | 626 return NULL; |
627 } | |
3630 | 628 |
4617 | 629 newconn->fd = listenfd; |
630 newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; | |
631 newconn->lastactivity = time(NULL); | |
3952 | 632 |
4617 | 633 return newconn; |
634 } | |
3630 | 635 |
4617 | 636 /** |
637 * Extract an &aim_fileheader_t from the given buffer. | |
638 * | |
639 * @param bs The should be from an incoming rendezvous packet. | |
640 * @return A pointer to new struct on success, or NULL on error. | |
641 */ | |
642 static struct aim_fileheader_t *aim_oft_getheader(aim_bstream_t *bs) | |
643 { | |
644 struct aim_fileheader_t *fh; | |
3630 | 645 |
4617 | 646 if (!(fh = calloc(1, sizeof(struct aim_fileheader_t)))) |
647 return NULL; | |
3630 | 648 |
4617 | 649 /* The bstream should be positioned after the hdrtype. */ |
650 aimbs_getrawbuf(bs, fh->bcookie, 8); | |
651 fh->encrypt = aimbs_get16(bs); | |
652 fh->compress = aimbs_get16(bs); | |
653 fh->totfiles = aimbs_get16(bs); | |
654 fh->filesleft = aimbs_get16(bs); | |
655 fh->totparts = aimbs_get16(bs); | |
656 fh->partsleft = aimbs_get16(bs); | |
657 fh->totsize = aimbs_get32(bs); | |
658 fh->size = aimbs_get32(bs); | |
659 fh->modtime = aimbs_get32(bs); | |
660 fh->checksum = aimbs_get32(bs); | |
661 fh->rfrcsum = aimbs_get32(bs); | |
662 fh->rfsize = aimbs_get32(bs); | |
663 fh->cretime = aimbs_get32(bs); | |
664 fh->rfcsum = aimbs_get32(bs); | |
665 fh->nrecvd = aimbs_get32(bs); | |
666 fh->recvcsum = aimbs_get32(bs); | |
667 aimbs_getrawbuf(bs, fh->idstring, 32); | |
668 fh->flags = aimbs_get8(bs); | |
669 fh->lnameoffset = aimbs_get8(bs); | |
670 fh->lsizeoffset = aimbs_get8(bs); | |
671 aimbs_getrawbuf(bs, fh->dummy, 69); | |
672 aimbs_getrawbuf(bs, fh->macfileinfo, 16); | |
673 fh->nencode = aimbs_get16(bs); | |
674 fh->nlanguage = aimbs_get16(bs); | |
675 aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */ | |
2086 | 676 |
4617 | 677 return fh; |
678 } | |
3630 | 679 |
4617 | 680 /** |
681 * Fills a buffer with network-order fh data | |
682 * | |
683 * @param bs A bstream to fill -- automatically initialized | |
684 * @param fh A struct aim_fileheader_t to get data from. | |
685 * @return Return non-zero on error. | |
686 */ | |
687 static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh) | |
688 { | |
689 fu8_t *hdr; | |
3630 | 690 |
4617 | 691 if (!bs || !fh) |
692 return -EINVAL; | |
3952 | 693 |
4617 | 694 if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) |
695 return -ENOMEM; | |
3630 | 696 |
4617 | 697 aim_bstream_init(bs, hdr, 0x100 - 8); |
698 aimbs_putraw(bs, fh->bcookie, 8); | |
699 aimbs_put16(bs, fh->encrypt); | |
700 aimbs_put16(bs, fh->compress); | |
701 aimbs_put16(bs, fh->totfiles); | |
702 aimbs_put16(bs, fh->filesleft); | |
703 aimbs_put16(bs, fh->totparts); | |
704 aimbs_put16(bs, fh->partsleft); | |
705 aimbs_put32(bs, fh->totsize); | |
706 aimbs_put32(bs, fh->size); | |
707 aimbs_put32(bs, fh->modtime); | |
708 aimbs_put32(bs, fh->checksum); | |
709 aimbs_put32(bs, fh->rfrcsum); | |
710 aimbs_put32(bs, fh->rfsize); | |
711 aimbs_put32(bs, fh->cretime); | |
712 aimbs_put32(bs, fh->rfcsum); | |
713 aimbs_put32(bs, fh->nrecvd); | |
714 aimbs_put32(bs, fh->recvcsum); | |
715 aimbs_putraw(bs, fh->idstring, 32); | |
716 aimbs_put8(bs, fh->flags); | |
717 aimbs_put8(bs, fh->lnameoffset); | |
718 aimbs_put8(bs, fh->lsizeoffset); | |
719 aimbs_putraw(bs, fh->dummy, 69); | |
720 aimbs_putraw(bs, fh->macfileinfo, 16); | |
721 aimbs_put16(bs, fh->nencode); | |
722 aimbs_put16(bs, fh->nlanguage); | |
723 aimbs_putraw(bs, fh->name, 64); /* XXX - filenames longer than 64B */ | |
3952 | 724 |
4617 | 725 return 0; |
726 } | |
2086 | 727 |
4617 | 728 /** |
729 * Create an OFT packet based on the given information, and send it on its merry way. | |
730 * | |
731 * @param sess The session. | |
732 * @param conn The already-connected OFT connection. | |
733 * @param cookie The cookie associated with this file transfer. | |
734 * @param filename The filename. | |
735 * @param filesdone Number of files already transferred. | |
736 * @param numfiles Total number of files. | |
737 * @param size Size in bytes of this file. | |
738 * @param totsize Size in bytes of all files combined. | |
739 * @param checksum Funky checksum of this file. | |
740 * @param flags Any flags you want, baby. Send 0x21 when sending the | |
741 * "AIM_CB_OFT_DONE" message, and "0x02" for everything else. | |
742 * @return Return 0 if no errors, otherwise return the error number. | |
743 */ | |
744 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) | |
745 { | |
746 aim_frame_t *newoft; | |
747 struct aim_fileheader_t *fh; | |
2086 | 748 |
4617 | 749 if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !filename) |
750 return -EINVAL; | |
751 | |
752 if (!(fh = (struct aim_fileheader_t *)calloc(1, sizeof(struct aim_fileheader_t)))) | |
753 return -ENOMEM; | |
754 | |
755 /* | |
756 * If you are receiving a file, the cookie should be null, if you are sending a | |
757 * file, the cookie should be the same as the one used in the ICBM negotiation | |
758 * SNACs. | |
759 */ | |
760 if (cookie) | |
761 memcpy(fh->bcookie, cookie, 8); | |
762 fh->totfiles = numfiles; | |
763 fh->filesleft = numfiles - filesdone; | |
764 fh->totparts = 0x0001; /* set to 0x0002 sending Mac resource forks */ | |
3952 | 765 fh->partsleft = 0x0001; |
4617 | 766 fh->totsize = totsize; |
767 fh->size = size; | |
768 fh->modtime = modtime; | |
769 fh->checksum = checksum; | |
770 | |
3952 | 771 strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); |
772 fh->flags = 0x02; | |
773 fh->lnameoffset = 0x1a; | |
774 fh->lsizeoffset = 0x10; | |
775 memset(fh->dummy, 0, sizeof(fh->dummy)); | |
776 memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo)); | |
2086 | 777 |
4617 | 778 /* apparently 0 is ASCII, 2 is UCS-2 */ |
779 /* it is likely that 3 is ISO 8859-1 */ | |
3952 | 780 fh->nencode = 0x0000; |
781 fh->nlanguage = 0x0000; | |
4617 | 782 |
783 strncpy(fh->name, filename, sizeof(fh->name)); | |
784 aim_oft_dirconvert_tostupid(fh->name); | |
2086 | 785 |
4617 | 786 if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, type, 0))) { |
787 free(fh); | |
788 return -ENOMEM; | |
3952 | 789 } |
2086 | 790 |
4617 | 791 if (aim_oft_buildheader(&newoft->data, fh) == -1) { |
792 aim_frame_destroy(newoft); | |
793 free(fh); | |
794 return -ENOMEM; | |
795 } | |
2086 | 796 |
4617 | 797 memcpy(newoft->hdr.rend.magic, "OFT2", 4); |
798 newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data); | |
3952 | 799 |
800 aim_tx_enqueue(sess, newoft); | |
2086 | 801 |
3952 | 802 free(fh); |
803 | |
804 return 0; | |
2086 | 805 } |
806 | |
807 /** | |
4617 | 808 * Sometimes you just don't know with these kinds of people. |
2086 | 809 * |
4617 | 810 * @param sess The session. |
811 * @param conn The ODC connection of the incoming data. | |
812 * @param frr The frame allocated for the incoming data. | |
813 * @param bs It stands for "bologna sandwich." | |
814 * @return Return 0 if no errors, otherwise return the error number. | |
2086 | 815 */ |
4617 | 816 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
|
817 { |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
818 aim_frame_t fr; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
819 aim_rxcallback_t userfunc; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
820 fu32_t payloadlength; |
3952 | 821 fu16_t flags, encoding; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
822 char *snptr = NULL; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
823 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
824 fr.conn = conn; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
825 |
4617 | 826 /* AAA - ugly */ |
3952 | 827 aim_bstream_setpos(bs, 20); |
828 payloadlength = aimbs_get32(bs); | |
829 | |
830 aim_bstream_setpos(bs, 24); | |
831 encoding = aimbs_get16(bs); | |
832 | |
833 aim_bstream_setpos(bs, 30); | |
834 flags = aimbs_get16(bs); | |
835 | |
836 aim_bstream_setpos(bs, 36); | |
4617 | 837 /* XXX - create an aimbs_getnullstr function? */ |
3952 | 838 snptr = aimbs_getstr(bs, MAXSNLEN); |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
839 |
4617 | 840 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
|
841 |
3952 | 842 if (flags & 0x0002) { |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
843 int ret = 0; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
844 |
4002 | 845 if (flags & 0x000c) { |
3952 | 846 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) |
847 ret = userfunc(sess, &fr, snptr, 1); | |
848 return ret; | |
849 } | |
2993 | 850 |
851 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) | |
852 ret = userfunc(sess, &fr, snptr, 0); | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
853 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
854 return ret; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
855 |
3952 | 856 } else if (((flags & 0x000f) == 0x0000) && payloadlength) { |
2993 | 857 char *msg, *msg2; |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
858 int ret = 0; |
2993 | 859 int recvd = 0; |
860 int i; | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
861 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
862 if (!(msg = calloc(1, payloadlength+1))) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
863 return -1; |
2993 | 864 msg2 = msg; |
865 | |
866 while (payloadlength - recvd) { | |
867 if (payloadlength - recvd >= 1024) | |
868 i = aim_recv(conn->fd, msg2, 1024); | |
869 else | |
870 i = aim_recv(conn->fd, msg2, payloadlength - recvd); | |
3012 | 871 if (i <= 0) { |
2993 | 872 free(msg); |
873 return -1; | |
874 } | |
875 recvd = recvd + i; | |
876 msg2 = msg2 + i; | |
4617 | 877 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER))) |
2993 | 878 userfunc(sess, &fr, snptr, (double)recvd / payloadlength); |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
879 } |
2993 | 880 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
881 if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) ) |
3952 | 882 ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding); |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
883 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
884 free(msg); |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
885 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
886 return ret; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
887 } |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
888 |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
889 return 0; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
890 } |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
891 |
4617 | 892 /** |
893 * Handle incoming data on a rendezvous connection. This is analogous to the | |
894 * consumesnac function in rxhandlers.c, and I really think this should probably | |
895 * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet. | |
896 * | |
897 * @param sess The session. | |
898 * @param fr The frame allocated for the incoming data. | |
899 * @return Return 0 if the packet was handled correctly, otherwise return the | |
900 * error number. | |
3771 | 901 */ |
3952 | 902 faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr) |
2086 | 903 { |
3952 | 904 aim_conn_t *conn = fr->conn; |
4617 | 905 int ret = 1; |
2086 | 906 |
4617 | 907 if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { |
908 if (fr->hdr.rend.type == 0x0001) | |
909 ret = handlehdr_odc(sess, conn, fr, &fr->data); | |
910 else | |
911 faimdprintf(sess, 0, "faim: ODC directim frame unknown, type is %04x\n", fr->hdr.rend.type); | |
2086 | 912 |
4617 | 913 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { |
914 switch (fr->hdr.rend.type) { | |
915 case 0x1108: /* getfile listing.txt incoming tx->rx */ | |
916 break; | |
917 case 0x1209: /* get file listing ack rx->tx */ | |
918 break; | |
919 case 0x120b: /* get file listing rx confirm */ | |
3630 | 920 break; |
4617 | 921 case 0x120c: /* getfile request */ |
922 break; | |
923 case 0x0101: /* getfile sending data */ | |
3630 | 924 break; |
4617 | 925 case 0x0202: /* getfile recv data */ |
3630 | 926 break; |
4617 | 927 case 0x0204: /* getfile finished */ |
3630 | 928 break; |
929 default: | |
4617 | 930 faimdprintf(sess, 2, "faim: OFT getfile frame uknown, type is %04x\n", fr->hdr.rend.type); |
3630 | 931 break; |
932 } | |
933 | |
4617 | 934 } else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { |
935 aim_rxcallback_t userfunc; | |
936 struct aim_fileheader_t *header = aim_oft_getheader(&fr->data); | |
937 aim_oft_dirconvert_fromstupid(header->name); /* XXX - This should be client-side */ | |
3771 | 938 |
4617 | 939 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, fr->hdr.rend.type))) |
940 ret = userfunc(sess, fr, conn, header->bcookie, header); | |
941 | |
942 free(header); | |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
943 } |
4617 | 944 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
945 if (ret == -1) |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
946 aim_conn_close(conn); |
2086 | 947 |
2246
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
948 return ret; |
933346315b9b
[gaim-migrate @ 2256]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
949 } |