Mercurial > gftp.yaz
annotate lib/rfc2068.c @ 58:c01d91c10f6c
2002-11-20 Brian Masney <masneyb@gftp.org>
* lib/protocols.c lib/gftp.h - added gftp_get_line(), gftp_read(),
gftp_write(), gftp_writefmt(), and gftp_set_sockblocking() functions.
Added struct_gftp_getline_buffer for gftp_get_line function()
* lib/cache.c lib/gftp.h lib/local.c lib/misc.c lib/protocols.c
lib/rfc2068.c lib/rfc959.c lib/ssh.c lib/sshv2.c - *_get_file() returns
off_t instead of long. *_{get,put}_next_file_chunk returns ssize_t
instead of size_t. Added *_set_config_options function to gftp_request
structure and protocol files. Use the new network functions
documented above. Convert usage of ANSI C IO (FILE *) to standard BSD
sockets so that I can use timeouts properly with select
* lib/misc.c (ssh_start_login_sequence) - use gftp_set_sockblock(),
gftp_read() and gftp_write() functions
* lib/protocols.c - move some protocol specific code to the protocol
specific files
* lib/local.c - log succesful messages to gftp_logging_misc instead
of gftp_logging_error
* lib/cache.c - log some more error conditions to the user
* lib/rfc959.c - added rfc959_getcwd(). In,
rfc959_accept_active_connection(), set set socket to blocking mode
before calling accept()
* src/text/gftk-text.c - If we get no files in gftp_text_ls(),
return instead of segfaulting
* src/gtk/gftp-gtk.c - expand the port field in the toolbar to be 45
pixels wide
* src/text/gftp-text.c src/gtk/misc-gtk.c src/gtk/transfer.c
src/gtk/view_dialog.c - changes for conversion of request->{sock,data}
from ANSI C IO (FILE *) to standard BSD sockets
author | masneyb |
---|---|
date | Thu, 21 Nov 2002 00:33:51 +0000 |
parents | e5f6054590b5 |
children | 8a9324fb63a4 |
rev | line source |
---|---|
1 | 1 /*****************************************************************************/ |
2 /* rfc2068.c - General purpose routines for the HTTP protocol */ | |
3 /* Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org> */ | |
4 /* */ | |
5 /* This program is free software; you can redistribute it and/or modify */ | |
6 /* it under the terms of the GNU General Public License as published by */ | |
7 /* the Free Software Foundation; either version 2 of the License, or */ | |
8 /* (at your option) any later version. */ | |
9 /* */ | |
10 /* This program is distributed in the hope that it will be useful, */ | |
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ | |
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ | |
13 /* GNU General Public License for more details. */ | |
14 /* */ | |
15 /* You should have received a copy of the GNU General Public License */ | |
16 /* along with this program; if not, write to the Free Software */ | |
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ | |
18 /*****************************************************************************/ | |
19 | |
20 #include "gftp.h" | |
33 | 21 static const char cvsid[] = "$Id$"; |
1 | 22 |
23 typedef struct rfc2068_params_tag | |
24 { | |
25 unsigned long read_bytes, | |
26 max_bytes; | |
27 int chunked_transfer : 1; | |
28 } rfc2068_params; | |
29 | |
48 | 30 |
31 static char * | |
32 base64_encode (char *str) | |
1 | 33 { |
48 | 34 |
35 /* The standard to Base64 encoding can be found in RFC2045 */ | |
36 | |
37 char *newstr, *newpos, *fillpos, *pos; | |
38 unsigned char table[64], encode[3]; | |
39 int i, num; | |
40 | |
41 for (i = 0; i < 26; i++) | |
42 { | |
43 table[i] = 'A' + i; | |
44 table[i + 26] = 'a' + i; | |
45 } | |
46 | |
47 for (i = 0; i < 10; i++) | |
48 table[i + 52] = '0' + i; | |
49 | |
50 table[62] = '+'; | |
51 table[63] = '-'; | |
52 | |
53 num = strlen (str) / 3; | |
54 if (strlen (str) % 3 > 0) | |
55 num++; | |
56 newstr = g_malloc (num * 4 + 1); | |
57 newstr[num * 4] = '\0'; | |
58 newpos = newstr; | |
59 | |
60 pos = str; | |
61 while (*pos != '\0') | |
62 { | |
63 memset (encode, 0, sizeof (encode)); | |
64 for (i = 0; i < 3 && *pos != '\0'; i++) | |
65 encode[i] = *pos++; | |
66 | |
67 fillpos = newpos; | |
68 *newpos++ = table[encode[0] >> 2]; | |
69 *newpos++ = table[(encode[0] & 3) << 4 | encode[1] >> 4]; | |
70 *newpos++ = table[(encode[1] & 0xF) << 2 | encode[2] >> 6]; | |
71 *newpos++ = table[encode[2] & 0x3F]; | |
72 while (i < 3) | |
73 fillpos[++i] = '='; | |
74 } | |
75 return (newstr); | |
76 } | |
77 | |
78 | |
58 | 79 static off_t |
48 | 80 rfc2068_read_response (gftp_request * request) |
81 { | |
58 | 82 gftp_getline_buffer * rbuf; |
48 | 83 rfc2068_params * params; |
84 char tempstr[255]; | |
85 | |
86 params = request->protocol_data; | |
87 params->max_bytes = 0; | |
88 | |
58 | 89 rbuf = NULL; |
90 if (gftp_get_line (request, &rbuf, tempstr, sizeof (tempstr) - 1, | |
91 request->sockfd) < 0) | |
92 return (-1); | |
48 | 93 |
94 if (request->last_ftp_response) | |
95 g_free (request->last_ftp_response); | |
96 request->last_ftp_response = g_malloc (strlen (tempstr) + 1); | |
97 strcpy (request->last_ftp_response, tempstr); | |
98 | |
99 request->logging_function (gftp_logging_recv, request->user_data, "%s", | |
100 tempstr); | |
101 | |
102 params->chunked_transfer = 0; | |
103 while (1) | |
104 { | |
105 /* Read rest of proxy header */ | |
58 | 106 if (gftp_get_line (request, &rbuf, tempstr, sizeof (tempstr) - 1, |
107 request->sockfd) < 0) | |
108 return (-1); | |
48 | 109 |
110 if (*tempstr == '\r' || *tempstr == '\n') | |
111 break; | |
112 | |
113 request->logging_function (gftp_logging_recv, request->user_data, "%s", | |
114 tempstr); | |
1 | 115 |
48 | 116 if (strncmp (tempstr, "Content-Length:", 15) == 0) |
117 params->max_bytes = strtol (tempstr + 16, NULL, 10); | |
118 if (strncmp (tempstr, "Transfer-Encoding: chunked", 26) == 0) | |
119 params->chunked_transfer = 1; | |
120 } | |
121 | |
122 return (params->max_bytes); | |
123 } | |
124 | |
125 | |
58 | 126 static off_t |
48 | 127 rfc2068_send_command (gftp_request * request, const char *command, |
128 const char *extrahdr) | |
129 { | |
130 char *tempstr, *str; | |
58 | 131 ssize_t ret; |
48 | 132 |
133 g_return_val_if_fail (request != NULL, -2); | |
134 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
135 g_return_val_if_fail (command != NULL, -2); | |
136 | |
58 | 137 tempstr = g_strdup_printf ("%sUser-Agent: %s\nHost: %s\n", command, |
138 version, request->hostname); | |
48 | 139 |
140 request->logging_function (gftp_logging_send, request->user_data, | |
58 | 141 "%s", tempstr); |
142 | |
143 ret = gftp_write (request, tempstr, strlen (tempstr), request->sockfd); | |
144 g_free (tempstr); | |
145 | |
146 if (ret < 0) | |
147 return (-1); | |
48 | 148 |
149 if (request->use_proxy && request->proxy_username != NULL && | |
150 *request->proxy_username != '\0') | |
151 { | |
152 tempstr = g_strconcat (request->proxy_username, ":", | |
153 request->proxy_password, NULL); | |
154 str = base64_encode (tempstr); | |
155 g_free (tempstr); | |
156 | |
157 request->logging_function (gftp_logging_send, request->user_data, | |
158 "Proxy-authorization: Basic xxxx:xxxx\n"); | |
58 | 159 ret = gftp_writefmt (request, request->sockfd, |
160 "Proxy-authorization: Basic %s\n", str); | |
48 | 161 g_free (str); |
58 | 162 if (ret < 0) |
163 return (-2); | |
48 | 164 } |
165 | |
166 if (request->username != NULL && *request->username != '\0') | |
167 { | |
168 tempstr = g_strconcat (request->username, ":", request->password, NULL); | |
169 str = base64_encode (tempstr); | |
170 g_free (tempstr); | |
171 | |
172 request->logging_function (gftp_logging_send, request->user_data, | |
173 "Authorization: Basic xxxx\n"); | |
58 | 174 ret = gftp_writefmt (request, request->sockfd, |
175 "Authorization: Basic %s\n", str); | |
48 | 176 g_free (str); |
58 | 177 if (ret < 0) |
178 return (-2); | |
48 | 179 } |
180 | |
181 if (extrahdr) | |
182 { | |
183 request->logging_function (gftp_logging_send, request->user_data, "%s", | |
184 extrahdr); | |
58 | 185 if (gftp_write (request, extrahdr, strlen (extrahdr), request->sockfd) < 0) |
186 return (-1); | |
48 | 187 } |
188 | |
58 | 189 if (gftp_write (request, "\n", 1, request->sockfd) < 0) |
190 return (-1); | |
191 | |
48 | 192 return (rfc2068_read_response (request)); |
1 | 193 } |
194 | |
195 | |
196 static int | |
197 rfc2068_connect (gftp_request * request) | |
198 { | |
199 char *service; | |
200 | |
201 g_return_val_if_fail (request != NULL, -2); | |
202 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
203 g_return_val_if_fail (request->hostname != NULL, -2); | |
204 | |
58 | 205 if (request->sockfd > 0) |
1 | 206 return (0); |
207 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
208 service = request->use_proxy && request->proxy_config != NULL && |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
209 *request->proxy_config != '\0' ? request->proxy_config : "http"; |
58 | 210 if ((request->sockfd = gftp_connect_server (request, service)) < 0) |
1 | 211 return (-1); |
212 | |
213 if (request->directory && *request->directory == '\0') | |
214 { | |
215 g_free (request->directory); | |
216 request->directory = NULL; | |
217 } | |
218 | |
219 if (!request->directory) | |
220 { | |
221 request->directory = g_malloc (2); | |
222 strcpy (request->directory, "/"); | |
223 } | |
224 | |
225 return (0); | |
226 } | |
227 | |
228 | |
229 static void | |
230 rfc2068_disconnect (gftp_request * request) | |
231 { | |
232 g_return_if_fail (request != NULL); | |
233 g_return_if_fail (request->protonum == GFTP_HTTP_NUM); | |
234 | |
58 | 235 if (request->sockfd > 0) |
1 | 236 { |
237 request->logging_function (gftp_logging_misc, request->user_data, | |
238 _("Disconnecting from site %s\n"), | |
239 request->hostname); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
240 |
58 | 241 if (close (request->sockfd) < 0) |
242 request->logging_function (gftp_logging_error, request->user_data, | |
243 _("Error closing file descriptor: %s\n"), | |
244 g_strerror (errno)); | |
245 | |
246 request->sockfd = -1; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
247 } |
1 | 248 } |
249 | |
250 | |
58 | 251 static off_t |
252 rfc2068_get_file (gftp_request * request, const char *filename, int fd, | |
1 | 253 off_t startsize) |
254 { | |
255 char *tempstr, *extrahdr, *pos, *proto; | |
256 int restarted; | |
257 off_t size; | |
258 | |
259 g_return_val_if_fail (request != NULL, -2); | |
260 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
261 g_return_val_if_fail (filename != NULL, -2); | |
262 | |
58 | 263 if (fd > 0) |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
264 request->sockfd = fd; |
1 | 265 |
58 | 266 if (request->sockfd < 0 && rfc2068_connect (request) != 0) |
1 | 267 return (-2); |
268 | |
269 if (request->proxy_config != NULL && *request->proxy_config != '\0') | |
270 proto = request->proxy_config; | |
271 else | |
272 proto = "http"; | |
273 | |
7 | 274 if (request->username == NULL || *request->username == '\0') |
1 | 275 tempstr = g_strconcat ("GET ", proto, "://", |
276 request->hostname, "/", filename, | |
277 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
278 else | |
279 tempstr = g_strconcat ("GET ", proto, "://", | |
280 request->username, "@", request->hostname, "/", filename, | |
281 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
282 | |
283 if ((pos = strstr (tempstr, "://")) != NULL) | |
284 remove_double_slashes (pos + 3); | |
285 else | |
286 remove_double_slashes (tempstr); | |
287 | |
288 if (!use_http11 || startsize == 0) | |
289 extrahdr = NULL; | |
290 else | |
291 { | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
292 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
293 extrahdr = g_strdup_printf ("Range: bytes=%lld-\n", startsize); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
294 request->logging_function (gftp_logging_misc, request->user_data, |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
295 _("Starting the file transfer at offset %lld\n"), |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
296 startsize); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
297 #else |
1 | 298 extrahdr = g_strdup_printf ("Range: bytes=%ld-\n", startsize); |
299 request->logging_function (gftp_logging_misc, request->user_data, | |
300 _("Starting the file transfer at offset %ld\n"), | |
301 startsize); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
302 #endif |
1 | 303 } |
304 | |
305 size = rfc2068_send_command (request, tempstr, extrahdr); | |
306 g_free (tempstr); | |
307 if (extrahdr) | |
308 g_free (extrahdr); | |
58 | 309 if (size < 0) |
310 return (-1); | |
1 | 311 |
312 restarted = 0; | |
313 if (strlen (request->last_ftp_response) > 9 | |
314 && strncmp (request->last_ftp_response + 9, "206", 3) == 0) | |
315 restarted = 1; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
316 else if (strlen (request->last_ftp_response) < 9 || |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
317 strncmp (request->last_ftp_response + 9, "200", 3) != 0) |
1 | 318 { |
58 | 319 request->logging_function (gftp_logging_error, request->user_data, |
1 | 320 _("Cannot retrieve file %s\n"), filename); |
321 return (-2); | |
322 } | |
323 | |
324 return (restarted ? size + startsize : size); | |
325 } | |
326 | |
327 | |
58 | 328 static ssize_t |
1 | 329 rfc2068_get_next_file_chunk (gftp_request * request, char *buf, size_t size) |
330 { | |
331 rfc2068_params * params; | |
332 size_t len; | |
333 | |
334 g_return_val_if_fail (request != NULL, -2); | |
335 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
336 | |
337 params = request->protocol_data; | |
58 | 338 if (params->max_bytes == params->read_bytes) |
1 | 339 return (0); |
340 | |
58 | 341 if (params->max_bytes > 0 && |
342 size + params->read_bytes > params->max_bytes) | |
343 size = params->max_bytes - params->read_bytes; | |
1 | 344 |
58 | 345 if ((len = gftp_read (request, buf, size, request->sockfd)) < 0) |
346 return (-2); | |
1 | 347 |
348 return (len); | |
349 } | |
350 | |
351 | |
352 static int | |
353 rfc2068_end_transfer (gftp_request * request) | |
354 { | |
355 rfc2068_params * params; | |
356 | |
357 g_return_val_if_fail (request != NULL, -2); | |
358 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
359 | |
58 | 360 if (request->sockfd < 0) |
1 | 361 return (-2); |
362 | |
58 | 363 if (close (request->sockfd) < 0) |
364 request->logging_function (gftp_logging_error, request->user_data, | |
365 _("Error closing file descriptor: %s\n"), | |
366 g_strerror (errno)); | |
367 request->sockfd = -1; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
368 |
1 | 369 params = request->protocol_data; |
370 params->max_bytes = 0; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
371 |
1 | 372 request->logging_function (gftp_logging_misc, request->user_data, |
373 _("Finished retrieving data\n")); | |
374 return (0); | |
375 } | |
376 | |
377 | |
378 static int | |
379 rfc2068_list_files (gftp_request * request) | |
380 { | |
381 char *tempstr, *pos, *proto; | |
382 rfc2068_params *params; | |
58 | 383 off_t ret; |
1 | 384 |
385 g_return_val_if_fail (request != NULL, -2); | |
386 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
387 | |
388 params = request->protocol_data; | |
58 | 389 if (request->sockfd < 0 && rfc2068_connect (request) != 0) |
1 | 390 return (-2); |
391 | |
392 if (request->proxy_config != NULL && *request->proxy_config != '\0') | |
393 proto = request->proxy_config; | |
394 else | |
395 proto = "http"; | |
396 | |
7 | 397 if (request->username == NULL || *request->username == '\0') |
1 | 398 tempstr = g_strconcat ("GET ", proto, "://", |
399 request->hostname, "/", request->directory, | |
400 use_http11 ? "/ HTTP/1.1\n" : "/ HTTP/1.0\n", NULL); | |
401 else | |
402 tempstr = g_strconcat ("GET ", proto, "://", request->username, "@", | |
403 request->hostname, "/", request->directory, | |
404 use_http11 ? "/ HTTP/1.1\n" : "/ HTTP/1.0\n", NULL); | |
405 | |
406 if ((pos = strstr (tempstr, "://")) != NULL) | |
407 remove_double_slashes (pos + 3); | |
408 else | |
409 remove_double_slashes (tempstr); | |
410 | |
58 | 411 ret = rfc2068_send_command (request, tempstr, NULL); |
1 | 412 g_free (tempstr); |
58 | 413 if (ret < 0) |
414 return (-1); | |
1 | 415 |
416 params->read_bytes = 0; | |
417 if (strlen (request->last_ftp_response) > 9 && | |
418 strncmp (request->last_ftp_response + 9, "200", 3) == 0) | |
419 { | |
420 request->logging_function (gftp_logging_misc, request->user_data, | |
421 _("Retrieving directory listing...\n")); | |
422 return (0); | |
423 } | |
424 | |
425 return (-2); | |
426 } | |
427 | |
428 | |
429 static off_t | |
430 rfc2068_get_file_size (gftp_request * request, const char *filename) | |
431 { | |
432 char *tempstr, *pos, *proto; | |
58 | 433 off_t size; |
1 | 434 |
435 g_return_val_if_fail (request != NULL, -2); | |
436 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
437 g_return_val_if_fail (filename != NULL, -2); | |
438 | |
58 | 439 if (request->sockfd < 0 && rfc2068_connect (request) != 0) |
1 | 440 return (-2); |
441 | |
442 if (request->proxy_config != NULL && *request->proxy_config != '\0') | |
443 proto = request->proxy_config; | |
444 else | |
445 proto = "http"; | |
446 | |
7 | 447 if (request->username == NULL || *request->username == '\0') |
1 | 448 tempstr = g_strconcat ("HEAD ", proto, request->hostname, "/", filename, |
449 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
450 else | |
451 tempstr = g_strconcat ("HEAD ", proto, request->username, "@", | |
452 request->hostname, "/", filename, | |
453 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
454 | |
455 if ((pos = strstr (tempstr, "://")) != NULL) | |
456 remove_double_slashes (pos + 3); | |
457 else | |
458 remove_double_slashes (tempstr); | |
459 | |
460 size = rfc2068_send_command (request, tempstr, NULL); | |
461 g_free (tempstr); | |
58 | 462 if (size < 0) |
1 | 463 return (-2); |
464 | |
465 return (size); | |
466 } | |
467 | |
468 | |
469 static int | |
470 parse_html_line (char *tempstr, gftp_file * fle) | |
471 { | |
472 char months[13][3] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", | |
473 "Sep", "Oct", "Nov", "Dec"}; | |
474 char *stpos, *pos, month[4]; | |
475 struct tm t; | |
476 long units; | |
477 int i; | |
478 | |
479 memset (fle, 0, sizeof (*fle)); | |
480 | |
481 if ((pos = strstr (tempstr, "<A HREF=")) == NULL && | |
482 (pos = strstr (tempstr, "<a href=")) == NULL) | |
483 return (0); | |
484 | |
485 /* Find the filename */ | |
486 while (*pos != '"' && *pos != '\0') | |
487 pos++; | |
488 if (*pos == '\0') | |
489 return (0); | |
490 pos++; | |
491 | |
492 for (stpos = pos; *pos != '"' && *pos != '\0'; pos++); | |
493 if (*pos == '\0') | |
494 return (0); | |
495 *pos = '\0'; | |
496 | |
497 /* Copy file attributes. Just about the only thing we can get is whether it | |
498 is a directory or not */ | |
499 fle->attribs = g_malloc (11); | |
500 strcpy (fle->attribs, "----------"); | |
501 if (*(pos - 1) == '/') | |
502 { | |
503 *(pos - 1) = '\0'; | |
504 *fle->attribs = 'd'; | |
505 fle->isdir = 1; | |
506 } | |
507 | |
508 /* Copy filename */ | |
509 if (strchr (stpos, '/') != NULL || strncmp (stpos, "mailto:", 7) == 0 || | |
510 *stpos == '\0' || *stpos == '?') | |
511 return (0); | |
512 | |
513 fle->file = g_malloc (strlen (stpos) + 1); | |
514 strcpy (fle->file, stpos); | |
515 | |
516 if (*(pos - 1) == '\0') | |
517 *(pos - 1) = '/'; | |
518 *pos = '"'; | |
519 pos++; | |
520 | |
521 /* Skip whitespace and html tags after file and before date */ | |
522 stpos = pos; | |
523 if ((pos = strstr (stpos, "</A>")) == NULL && | |
524 (pos = strstr (stpos, "</a>")) == NULL) | |
525 return (0); | |
526 | |
527 pos += 4; | |
528 | |
529 while (*pos == ' ' || *pos == '.' || *pos == '<') | |
530 { | |
531 if (*pos == '<') | |
532 { | |
533 if (strncmp (pos, "<A ", 3) == 0 || strncmp (pos, "<a ", 3) == 0) | |
534 { | |
535 stpos = pos; | |
536 if ((pos = strstr (stpos, "</A>")) == NULL | |
537 && (pos = strstr (stpos, "</a>")) == NULL) | |
538 return (0); | |
539 pos += 4; | |
540 } | |
541 else | |
542 { | |
543 while (*pos != '>' && *pos != '\0') | |
544 pos++; | |
545 if (*pos == '\0') | |
546 return (0); | |
547 } | |
548 } | |
549 pos++; | |
550 } | |
551 | |
552 /* Now get the date */ | |
553 memset (&t, 0, sizeof (t)); | |
554 memset (month, 0, sizeof (month)); | |
555 if (strchr (pos, ':') != NULL) | |
556 { | |
557 if (*pos == '[') | |
558 pos++; | |
559 sscanf (pos, "%02d-%3s-%04d %02d:%02d", &t.tm_mday, month, &t.tm_year, | |
560 &t.tm_hour, &t.tm_min); | |
561 while (*pos != ' ' && *pos != '\0') | |
562 pos++; | |
563 if (*pos == '\0') | |
564 return (1); | |
565 | |
566 while (*pos == ' ') | |
567 pos++; | |
568 | |
569 while (*pos != ' ' && *pos != '\0') | |
570 pos++; | |
571 if (*pos == '\0') | |
572 return (1); | |
573 | |
574 t.tm_year -= 1900; | |
575 } | |
576 else | |
577 { | |
578 pos++; | |
579 strncpy (month, pos, 3); | |
580 for (i=0; i<3 && *pos != '\0'; i++) | |
581 pos++; | |
582 if (*pos == '\0') | |
583 return (1); | |
584 | |
585 while (*pos == ' ') | |
586 pos++; | |
587 | |
588 t.tm_mday = strtol (pos, NULL, 10); | |
589 while (*pos != ' ' && *pos != '\0') | |
590 pos++; | |
591 if (*pos == '\0') | |
592 return (1); | |
593 | |
594 while (*pos == ' ') | |
595 pos++; | |
596 | |
597 t.tm_year = strtol (pos, NULL, 10) - 1900; | |
598 while (*pos != ' ' && *pos != '\0') | |
599 pos++; | |
600 if (*pos == '\0') | |
601 return (1); | |
602 } | |
603 | |
604 for (i=0; i<12; i++) | |
605 { | |
606 if (strncmp (month, months[i], 3) == 0) | |
607 { | |
608 t.tm_mon = i; | |
609 break; | |
610 } | |
611 } | |
612 | |
613 fle->datetime = mktime (&t); | |
614 | |
615 while (*pos == ' ' || *pos == ']') | |
616 pos++; | |
617 | |
618 /* Get the size */ | |
619 /* This gets confusing on lines like "... 1.1M RedHat RPM package" */ | |
620 /* We need to avoid finding the 'k' in package */ | |
621 | |
622 stpos = strchr (pos, 'k'); | |
623 if (stpos == NULL || !isdigit (*(stpos - 1))) | |
624 stpos = strchr (pos, 'M'); | |
625 if (stpos == NULL || !isdigit (*(stpos - 1))) | |
626 return (1); /* Return successfully | |
627 since we got the file */ | |
628 if (*stpos == 'k') | |
629 units = 1024; | |
630 else | |
631 units = 1048576; | |
632 | |
633 fle->size = 0; | |
634 | |
635 while (*(stpos - 1) != ' ' && *(stpos - 1) != '\t' && stpos > tempstr) | |
636 { | |
637 stpos--; | |
638 if ((*stpos == '.') && isdigit (*(stpos + 1)) ) | |
639 { /* found decimal point */ | |
640 fle->size = units * strtol (stpos + 1, NULL, 10); | |
641 fle->size /= 10; | |
642 } | |
643 } | |
644 | |
645 fle->size += units * strtol (stpos, NULL, 10); | |
646 return (1); | |
647 } | |
648 | |
649 | |
48 | 650 static int |
58 | 651 rfc2068_get_next_file (gftp_request * request, gftp_file * fle, int fd) |
1 | 652 { |
58 | 653 gftp_getline_buffer * rbuf; |
48 | 654 rfc2068_params * params; |
655 char tempstr[255]; | |
656 size_t len; | |
1 | 657 |
48 | 658 g_return_val_if_fail (request != NULL, -2); |
659 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
660 g_return_val_if_fail (fle != NULL, -2); | |
661 | |
662 params = request->protocol_data; | |
663 if (request->last_dir_entry) | |
664 { | |
665 g_free (request->last_dir_entry); | |
666 request->last_dir_entry = NULL; | |
667 } | |
668 | |
58 | 669 rbuf = NULL; |
48 | 670 while (1) |
671 { | |
58 | 672 if (gftp_get_line (request, &rbuf, tempstr, sizeof (tempstr) - 1, fd) < 0) |
673 return (-2); | |
1 | 674 |
48 | 675 tempstr[sizeof (tempstr) - 1] = '\0'; |
676 params->read_bytes += strlen (tempstr); | |
677 | |
678 if (params->chunked_transfer && strcmp (tempstr, "0\r\n") == 0) | |
679 { | |
58 | 680 while ((len = gftp_get_line (request, &rbuf, tempstr, |
681 sizeof (tempstr) - 1, fd)) > 0) | |
48 | 682 { |
683 if (strcmp (tempstr, "\r\n") == 0) | |
684 break; | |
685 } | |
686 gftp_file_destroy (fle); | |
58 | 687 |
688 if (len < 0) | |
689 return (-1); | |
690 | |
48 | 691 return (0); |
692 } | |
1 | 693 |
48 | 694 if (parse_html_line (tempstr, fle) == 0 || fle->file == NULL) |
695 gftp_file_destroy (fle); | |
696 else | |
697 break; | |
698 | |
699 if (params->max_bytes != 0 && params->read_bytes == params->max_bytes) | |
700 break; | |
701 } | |
702 | |
703 if (fle->file == NULL) | |
1 | 704 { |
48 | 705 gftp_file_destroy (fle); |
706 return (-2); | |
1 | 707 } |
708 | |
48 | 709 len = strlen (tempstr); |
710 if (!request->cached) | |
711 { | |
712 request->last_dir_entry = g_malloc (len + 1); | |
713 strcpy (request->last_dir_entry, tempstr); | |
714 request->last_dir_entry_len = len; | |
715 } | |
58 | 716 return (len); |
48 | 717 } |
1 | 718 |
719 | |
48 | 720 static int |
721 rfc2068_chdir (gftp_request * request, const char *directory) | |
722 { | |
723 g_return_val_if_fail (request != NULL, -2); | |
724 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
725 g_return_val_if_fail (directory != NULL, -2); | |
726 | |
727 if (request->directory != directory) | |
728 { | |
729 if (request->directory) | |
730 g_free (request->directory); | |
731 request->directory = g_malloc (strlen (directory) + 1); | |
732 strcpy (request->directory, directory); | |
733 } | |
734 return (0); | |
735 } | |
736 | |
737 | |
58 | 738 static void |
739 rfc2068_set_config_options (gftp_request * request) | |
740 { | |
741 gftp_set_proxy_hostname (request, http_proxy_host); | |
742 gftp_set_proxy_port (request, http_proxy_port); | |
743 gftp_set_proxy_username (request, http_proxy_username); | |
744 gftp_set_proxy_password (request, http_proxy_password); | |
745 | |
746 | |
747 if (request->proxy_config == NULL) | |
748 { | |
749 request->proxy_config = g_malloc (5); | |
750 strcpy (request->proxy_config, "http"); | |
751 } | |
752 } | |
753 | |
754 | |
48 | 755 void |
756 rfc2068_init (gftp_request * request) | |
757 { | |
758 g_return_if_fail (request != NULL); | |
1 | 759 |
48 | 760 request->protonum = GFTP_HTTP_NUM; |
761 request->init = rfc2068_init; | |
762 request->destroy = NULL; | |
763 request->connect = rfc2068_connect; | |
764 request->disconnect = rfc2068_disconnect; | |
765 request->get_file = rfc2068_get_file; | |
766 request->put_file = NULL; | |
767 request->transfer_file = NULL; | |
768 request->get_next_file_chunk = rfc2068_get_next_file_chunk; | |
769 request->put_next_file_chunk = NULL; | |
770 request->end_transfer = rfc2068_end_transfer; | |
771 request->abort_transfer = rfc2068_end_transfer; /* NOTE: uses end_transfer */ | |
772 request->list_files = rfc2068_list_files; | |
773 request->get_next_file = rfc2068_get_next_file; | |
774 request->set_data_type = NULL; | |
775 request->get_file_size = rfc2068_get_file_size; | |
776 request->chdir = rfc2068_chdir; | |
777 request->rmdir = NULL; | |
778 request->rmfile = NULL; | |
779 request->mkdir = NULL; | |
780 request->rename = NULL; | |
781 request->chmod = NULL; | |
782 request->site = NULL; | |
58 | 783 request->parse_url = NULL; |
784 request->set_config_options = rfc2068_set_config_options; | |
48 | 785 request->url_prefix = "http"; |
786 request->protocol_name = "HTTP"; | |
787 request->need_hostport = 1; | |
788 request->need_userpass = 0; | |
789 request->use_cache = 1; | |
790 request->use_threads = 1; | |
791 request->always_connected = 0; | |
792 request->protocol_data = g_malloc0 (sizeof (rfc2068_params)); | |
793 gftp_set_config_options (request); | |
794 } | |
1 | 795 |