Mercurial > gftp.yaz
annotate lib/rfc2068.c @ 117:518cfe046779
2003-03-06 Vincent van Adrighem <V.vanAdrighem@dirck.mine.nu>
* nl.po: Dutch translation updated.
author | adrighem |
---|---|
date | Thu, 06 Mar 2003 00:00:58 +0000 |
parents | ae13b18c9336 |
children | 76e2b58a9440 |
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 { | |
105 | 25 gftp_getline_buffer * rbuf; |
1 | 26 unsigned long read_bytes, |
27 max_bytes; | |
28 int chunked_transfer : 1; | |
29 } rfc2068_params; | |
30 | |
48 | 31 |
32 static char * | |
33 base64_encode (char *str) | |
1 | 34 { |
48 | 35 |
36 /* The standard to Base64 encoding can be found in RFC2045 */ | |
37 | |
38 char *newstr, *newpos, *fillpos, *pos; | |
39 unsigned char table[64], encode[3]; | |
40 int i, num; | |
41 | |
42 for (i = 0; i < 26; i++) | |
43 { | |
44 table[i] = 'A' + i; | |
45 table[i + 26] = 'a' + i; | |
46 } | |
47 | |
48 for (i = 0; i < 10; i++) | |
49 table[i + 52] = '0' + i; | |
50 | |
51 table[62] = '+'; | |
52 table[63] = '-'; | |
53 | |
54 num = strlen (str) / 3; | |
55 if (strlen (str) % 3 > 0) | |
56 num++; | |
57 newstr = g_malloc (num * 4 + 1); | |
58 newstr[num * 4] = '\0'; | |
59 newpos = newstr; | |
60 | |
61 pos = str; | |
62 while (*pos != '\0') | |
63 { | |
64 memset (encode, 0, sizeof (encode)); | |
65 for (i = 0; i < 3 && *pos != '\0'; i++) | |
66 encode[i] = *pos++; | |
67 | |
68 fillpos = newpos; | |
69 *newpos++ = table[encode[0] >> 2]; | |
70 *newpos++ = table[(encode[0] & 3) << 4 | encode[1] >> 4]; | |
71 *newpos++ = table[(encode[1] & 0xF) << 2 | encode[2] >> 6]; | |
72 *newpos++ = table[encode[2] & 0x3F]; | |
73 while (i < 3) | |
74 fillpos[++i] = '='; | |
75 } | |
76 return (newstr); | |
77 } | |
78 | |
79 | |
58 | 80 static off_t |
48 | 81 rfc2068_read_response (gftp_request * request) |
82 { | |
83 rfc2068_params * params; | |
84 char tempstr[255]; | |
84 | 85 int ret; |
48 | 86 |
87 params = request->protocol_data; | |
105 | 88 params->chunked_transfer = 0; |
89 params->rbuf = NULL; | |
90 *tempstr = '\0'; | |
48 | 91 params->max_bytes = 0; |
105 | 92 if (request->last_ftp_response) |
93 { | |
94 g_free (request->last_ftp_response); | |
95 request->last_ftp_response = NULL; | |
96 } | |
48 | 97 |
105 | 98 do |
99 { | |
100 if ((ret = gftp_get_line (request, ¶ms->rbuf, tempstr, sizeof (tempstr), | |
101 request->sockfd)) < 0) | |
102 return (ret); | |
48 | 103 |
105 | 104 if (request->last_ftp_response == NULL) |
105 request->last_ftp_response = g_strdup (tempstr); | |
106 | |
107 if (*tempstr != '\0') | |
108 { | |
109 request->logging_function (gftp_logging_recv, request->user_data, "%s\n", | |
110 tempstr); | |
48 | 111 |
105 | 112 if (strncmp (tempstr, "Content-Length:", 15) == 0) |
113 params->max_bytes = strtol (tempstr + 16, NULL, 10); | |
114 if (strcmp (tempstr, "Transfer-Encoding: chunked") == 0) | |
115 params->chunked_transfer = 1; | |
116 } | |
48 | 117 } |
105 | 118 while (*tempstr != '\0'); |
48 | 119 |
120 return (params->max_bytes); | |
121 } | |
122 | |
123 | |
58 | 124 static off_t |
48 | 125 rfc2068_send_command (gftp_request * request, const char *command, |
126 const char *extrahdr) | |
127 { | |
128 char *tempstr, *str; | |
58 | 129 ssize_t ret; |
48 | 130 |
84 | 131 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
132 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, GFTP_EFATAL); | |
133 g_return_val_if_fail (command != NULL, GFTP_EFATAL); | |
48 | 134 |
58 | 135 tempstr = g_strdup_printf ("%sUser-Agent: %s\nHost: %s\n", command, |
136 version, request->hostname); | |
48 | 137 |
138 request->logging_function (gftp_logging_send, request->user_data, | |
58 | 139 "%s", tempstr); |
140 | |
141 ret = gftp_write (request, tempstr, strlen (tempstr), request->sockfd); | |
142 g_free (tempstr); | |
143 | |
144 if (ret < 0) | |
84 | 145 return (ret); |
48 | 146 |
147 if (request->use_proxy && request->proxy_username != NULL && | |
148 *request->proxy_username != '\0') | |
149 { | |
150 tempstr = g_strconcat (request->proxy_username, ":", | |
151 request->proxy_password, NULL); | |
152 str = base64_encode (tempstr); | |
153 g_free (tempstr); | |
154 | |
155 request->logging_function (gftp_logging_send, request->user_data, | |
156 "Proxy-authorization: Basic xxxx:xxxx\n"); | |
58 | 157 ret = gftp_writefmt (request, request->sockfd, |
158 "Proxy-authorization: Basic %s\n", str); | |
48 | 159 g_free (str); |
58 | 160 if (ret < 0) |
84 | 161 return (ret); |
48 | 162 } |
163 | |
164 if (request->username != NULL && *request->username != '\0') | |
165 { | |
166 tempstr = g_strconcat (request->username, ":", request->password, NULL); | |
167 str = base64_encode (tempstr); | |
168 g_free (tempstr); | |
169 | |
170 request->logging_function (gftp_logging_send, request->user_data, | |
171 "Authorization: Basic xxxx\n"); | |
58 | 172 ret = gftp_writefmt (request, request->sockfd, |
173 "Authorization: Basic %s\n", str); | |
48 | 174 g_free (str); |
58 | 175 if (ret < 0) |
84 | 176 return (ret); |
48 | 177 } |
178 | |
179 if (extrahdr) | |
180 { | |
181 request->logging_function (gftp_logging_send, request->user_data, "%s", | |
182 extrahdr); | |
84 | 183 if ((ret = gftp_write (request, extrahdr, strlen (extrahdr), |
184 request->sockfd)) < 0) | |
185 return (ret); | |
48 | 186 } |
187 | |
84 | 188 if ((ret = gftp_write (request, "\n", 1, request->sockfd)) < 0) |
189 return (ret); | |
58 | 190 |
48 | 191 return (rfc2068_read_response (request)); |
1 | 192 } |
193 | |
194 | |
195 static int | |
196 rfc2068_connect (gftp_request * request) | |
197 { | |
198 char *service; | |
199 | |
84 | 200 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
201 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, GFTP_EFATAL); | |
202 g_return_val_if_fail (request->hostname != NULL, GFTP_EFATAL); | |
1 | 203 |
58 | 204 if (request->sockfd > 0) |
1 | 205 return (0); |
206 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
207 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
|
208 *request->proxy_config != '\0' ? request->proxy_config : "http"; |
87 | 209 |
210 if (request->url_prefix != NULL) | |
211 g_free (request->url_prefix); | |
212 request->url_prefix = g_strdup (service); | |
213 | |
58 | 214 if ((request->sockfd = gftp_connect_server (request, service)) < 0) |
84 | 215 return (GFTP_ERETRYABLE); |
1 | 216 |
217 if (request->directory && *request->directory == '\0') | |
218 { | |
219 g_free (request->directory); | |
220 request->directory = NULL; | |
221 } | |
222 | |
223 if (!request->directory) | |
105 | 224 request->directory = g_strdup ("/"); |
1 | 225 |
226 return (0); | |
227 } | |
228 | |
229 | |
230 static void | |
231 rfc2068_disconnect (gftp_request * request) | |
232 { | |
233 g_return_if_fail (request != NULL); | |
234 g_return_if_fail (request->protonum == GFTP_HTTP_NUM); | |
235 | |
58 | 236 if (request->sockfd > 0) |
1 | 237 { |
238 request->logging_function (gftp_logging_misc, request->user_data, | |
239 _("Disconnecting from site %s\n"), | |
240 request->hostname); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
241 |
58 | 242 if (close (request->sockfd) < 0) |
243 request->logging_function (gftp_logging_error, request->user_data, | |
244 _("Error closing file descriptor: %s\n"), | |
245 g_strerror (errno)); | |
246 | |
247 request->sockfd = -1; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
248 } |
1 | 249 } |
250 | |
251 | |
58 | 252 static off_t |
253 rfc2068_get_file (gftp_request * request, const char *filename, int fd, | |
1 | 254 off_t startsize) |
255 { | |
256 char *tempstr, *extrahdr, *pos, *proto; | |
84 | 257 int restarted, ret; |
1 | 258 off_t size; |
259 | |
84 | 260 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
261 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, GFTP_EFATAL); | |
262 g_return_val_if_fail (filename != NULL, GFTP_EFATAL); | |
1 | 263 |
58 | 264 if (fd > 0) |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
265 request->sockfd = fd; |
1 | 266 |
84 | 267 if (request->sockfd < 0 && (ret = rfc2068_connect (request)) != 0) |
268 return (ret); | |
1 | 269 |
270 if (request->proxy_config != NULL && *request->proxy_config != '\0') | |
271 proto = request->proxy_config; | |
272 else | |
273 proto = "http"; | |
274 | |
7 | 275 if (request->username == NULL || *request->username == '\0') |
1 | 276 tempstr = g_strconcat ("GET ", proto, "://", |
277 request->hostname, "/", filename, | |
278 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
279 else | |
280 tempstr = g_strconcat ("GET ", proto, "://", | |
281 request->username, "@", request->hostname, "/", filename, | |
282 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
283 | |
284 if ((pos = strstr (tempstr, "://")) != NULL) | |
285 remove_double_slashes (pos + 3); | |
286 else | |
287 remove_double_slashes (tempstr); | |
288 | |
289 if (!use_http11 || startsize == 0) | |
290 extrahdr = NULL; | |
291 else | |
292 { | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
293 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
294 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
|
295 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
|
296 _("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
|
297 startsize); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
298 #else |
1 | 299 extrahdr = g_strdup_printf ("Range: bytes=%ld-\n", startsize); |
300 request->logging_function (gftp_logging_misc, request->user_data, | |
301 _("Starting the file transfer at offset %ld\n"), | |
302 startsize); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
303 #endif |
1 | 304 } |
305 | |
306 size = rfc2068_send_command (request, tempstr, extrahdr); | |
307 g_free (tempstr); | |
308 if (extrahdr) | |
309 g_free (extrahdr); | |
58 | 310 if (size < 0) |
84 | 311 return (size); |
1 | 312 |
313 restarted = 0; | |
314 if (strlen (request->last_ftp_response) > 9 | |
315 && strncmp (request->last_ftp_response + 9, "206", 3) == 0) | |
316 restarted = 1; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
317 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
|
318 strncmp (request->last_ftp_response + 9, "200", 3) != 0) |
1 | 319 { |
58 | 320 request->logging_function (gftp_logging_error, request->user_data, |
1 | 321 _("Cannot retrieve file %s\n"), filename); |
84 | 322 return (GFTP_ERETRYABLE); |
1 | 323 } |
324 | |
325 return (restarted ? size + startsize : size); | |
326 } | |
327 | |
328 | |
58 | 329 static ssize_t |
1 | 330 rfc2068_get_next_file_chunk (gftp_request * request, char *buf, size_t size) |
331 { | |
332 rfc2068_params * params; | |
333 size_t len; | |
334 | |
84 | 335 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
336 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, GFTP_EFATAL); | |
1 | 337 |
338 params = request->protocol_data; | |
58 | 339 if (params->max_bytes == params->read_bytes) |
1 | 340 return (0); |
341 | |
58 | 342 if (params->max_bytes > 0 && |
343 size + params->read_bytes > params->max_bytes) | |
344 size = params->max_bytes - params->read_bytes; | |
1 | 345 |
58 | 346 if ((len = gftp_read (request, buf, size, request->sockfd)) < 0) |
84 | 347 return ((ssize_t) len); |
1 | 348 |
349 return (len); | |
350 } | |
351 | |
352 | |
353 static int | |
354 rfc2068_end_transfer (gftp_request * request) | |
355 { | |
356 rfc2068_params * params; | |
357 | |
84 | 358 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
359 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, GFTP_EFATAL); | |
1 | 360 |
58 | 361 if (request->sockfd < 0) |
84 | 362 return (GFTP_EFATAL); |
1 | 363 |
58 | 364 if (close (request->sockfd) < 0) |
365 request->logging_function (gftp_logging_error, request->user_data, | |
366 _("Error closing file descriptor: %s\n"), | |
367 g_strerror (errno)); | |
368 request->sockfd = -1; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
369 |
1 | 370 params = request->protocol_data; |
371 params->max_bytes = 0; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
372 |
1 | 373 request->logging_function (gftp_logging_misc, request->user_data, |
374 _("Finished retrieving data\n")); | |
375 return (0); | |
376 } | |
377 | |
378 | |
379 static int | |
380 rfc2068_list_files (gftp_request * request) | |
381 { | |
382 char *tempstr, *pos, *proto; | |
383 rfc2068_params *params; | |
58 | 384 off_t ret; |
84 | 385 int r; |
1 | 386 |
84 | 387 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
388 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, GFTP_EFATAL); | |
1 | 389 |
390 params = request->protocol_data; | |
84 | 391 if (request->sockfd < 0 && (r = rfc2068_connect (request)) < 0) |
392 return (r); | |
1 | 393 |
394 if (request->proxy_config != NULL && *request->proxy_config != '\0') | |
395 proto = request->proxy_config; | |
396 else | |
397 proto = "http"; | |
398 | |
7 | 399 if (request->username == NULL || *request->username == '\0') |
1 | 400 tempstr = g_strconcat ("GET ", proto, "://", |
401 request->hostname, "/", request->directory, | |
402 use_http11 ? "/ HTTP/1.1\n" : "/ HTTP/1.0\n", NULL); | |
403 else | |
404 tempstr = g_strconcat ("GET ", proto, "://", request->username, "@", | |
405 request->hostname, "/", request->directory, | |
406 use_http11 ? "/ HTTP/1.1\n" : "/ HTTP/1.0\n", NULL); | |
407 | |
408 if ((pos = strstr (tempstr, "://")) != NULL) | |
409 remove_double_slashes (pos + 3); | |
410 else | |
411 remove_double_slashes (tempstr); | |
412 | |
58 | 413 ret = rfc2068_send_command (request, tempstr, NULL); |
1 | 414 g_free (tempstr); |
58 | 415 if (ret < 0) |
84 | 416 return ((int) ret); |
1 | 417 |
418 params->read_bytes = 0; | |
419 if (strlen (request->last_ftp_response) > 9 && | |
420 strncmp (request->last_ftp_response + 9, "200", 3) == 0) | |
421 { | |
422 request->logging_function (gftp_logging_misc, request->user_data, | |
423 _("Retrieving directory listing...\n")); | |
424 return (0); | |
425 } | |
426 | |
84 | 427 return (GFTP_ERETRYABLE); |
1 | 428 } |
429 | |
430 | |
431 static off_t | |
432 rfc2068_get_file_size (gftp_request * request, const char *filename) | |
433 { | |
434 char *tempstr, *pos, *proto; | |
58 | 435 off_t size; |
84 | 436 int ret; |
1 | 437 |
84 | 438 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
439 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, GFTP_EFATAL); | |
440 g_return_val_if_fail (filename != NULL, GFTP_EFATAL); | |
1 | 441 |
84 | 442 if (request->sockfd < 0 && (ret = rfc2068_connect (request)) != 0) |
443 return (ret); | |
1 | 444 |
445 if (request->proxy_config != NULL && *request->proxy_config != '\0') | |
446 proto = request->proxy_config; | |
447 else | |
448 proto = "http"; | |
449 | |
7 | 450 if (request->username == NULL || *request->username == '\0') |
1 | 451 tempstr = g_strconcat ("HEAD ", proto, request->hostname, "/", filename, |
452 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
453 else | |
454 tempstr = g_strconcat ("HEAD ", proto, request->username, "@", | |
455 request->hostname, "/", filename, | |
456 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
457 | |
458 if ((pos = strstr (tempstr, "://")) != NULL) | |
459 remove_double_slashes (pos + 3); | |
460 else | |
461 remove_double_slashes (tempstr); | |
462 | |
463 size = rfc2068_send_command (request, tempstr, NULL); | |
464 g_free (tempstr); | |
465 return (size); | |
466 } | |
467 | |
468 | |
469 static int | |
470 parse_html_line (char *tempstr, gftp_file * fle) | |
471 { | |
102 | 472 char *stpos, *pos; |
1 | 473 long units; |
474 | |
475 memset (fle, 0, sizeof (*fle)); | |
476 | |
477 if ((pos = strstr (tempstr, "<A HREF=")) == NULL && | |
478 (pos = strstr (tempstr, "<a href=")) == NULL) | |
479 return (0); | |
480 | |
481 /* Find the filename */ | |
482 while (*pos != '"' && *pos != '\0') | |
483 pos++; | |
484 if (*pos == '\0') | |
485 return (0); | |
486 pos++; | |
487 | |
488 for (stpos = pos; *pos != '"' && *pos != '\0'; pos++); | |
489 if (*pos == '\0') | |
490 return (0); | |
491 *pos = '\0'; | |
492 | |
493 /* Copy file attributes. Just about the only thing we can get is whether it | |
494 is a directory or not */ | |
105 | 495 fle->attribs = g_strdup ("----------"); |
1 | 496 if (*(pos - 1) == '/') |
497 { | |
498 *(pos - 1) = '\0'; | |
499 *fle->attribs = 'd'; | |
500 fle->isdir = 1; | |
501 } | |
502 | |
503 /* Copy filename */ | |
504 if (strchr (stpos, '/') != NULL || strncmp (stpos, "mailto:", 7) == 0 || | |
505 *stpos == '\0' || *stpos == '?') | |
506 return (0); | |
507 | |
105 | 508 fle->file = g_strdup (stpos); |
1 | 509 |
510 if (*(pos - 1) == '\0') | |
511 *(pos - 1) = '/'; | |
512 *pos = '"'; | |
513 pos++; | |
514 | |
515 /* Skip whitespace and html tags after file and before date */ | |
516 stpos = pos; | |
517 if ((pos = strstr (stpos, "</A>")) == NULL && | |
518 (pos = strstr (stpos, "</a>")) == NULL) | |
519 return (0); | |
520 | |
521 pos += 4; | |
522 | |
105 | 523 while (*pos == ' ' || *pos == '\t' || *pos == '.' || *pos == '<') |
1 | 524 { |
525 if (*pos == '<') | |
526 { | |
527 if (strncmp (pos, "<A ", 3) == 0 || strncmp (pos, "<a ", 3) == 0) | |
528 { | |
529 stpos = pos; | |
530 if ((pos = strstr (stpos, "</A>")) == NULL | |
531 && (pos = strstr (stpos, "</a>")) == NULL) | |
532 return (0); | |
533 pos += 4; | |
534 } | |
535 else | |
536 { | |
537 while (*pos != '>' && *pos != '\0') | |
538 pos++; | |
539 if (*pos == '\0') | |
540 return (0); | |
541 } | |
542 } | |
543 pos++; | |
544 } | |
545 | |
102 | 546 if (*pos == '[') |
547 pos++; | |
1 | 548 |
102 | 549 fle->datetime = parse_time (pos, &pos); |
1 | 550 |
105 | 551 if (pos == NULL) |
552 return (1); | |
553 | |
1 | 554 while (*pos == ' ' || *pos == ']') |
555 pos++; | |
556 | |
557 /* Get the size */ | |
558 /* This gets confusing on lines like "... 1.1M RedHat RPM package" */ | |
559 /* We need to avoid finding the 'k' in package */ | |
560 | |
561 stpos = strchr (pos, 'k'); | |
562 if (stpos == NULL || !isdigit (*(stpos - 1))) | |
563 stpos = strchr (pos, 'M'); | |
564 if (stpos == NULL || !isdigit (*(stpos - 1))) | |
565 return (1); /* Return successfully | |
566 since we got the file */ | |
567 if (*stpos == 'k') | |
568 units = 1024; | |
569 else | |
570 units = 1048576; | |
571 | |
572 fle->size = 0; | |
573 | |
574 while (*(stpos - 1) != ' ' && *(stpos - 1) != '\t' && stpos > tempstr) | |
575 { | |
576 stpos--; | |
577 if ((*stpos == '.') && isdigit (*(stpos + 1)) ) | |
578 { /* found decimal point */ | |
579 fle->size = units * strtol (stpos + 1, NULL, 10); | |
580 fle->size /= 10; | |
581 } | |
582 } | |
583 | |
584 fle->size += units * strtol (stpos, NULL, 10); | |
585 return (1); | |
586 } | |
587 | |
588 | |
48 | 589 static int |
58 | 590 rfc2068_get_next_file (gftp_request * request, gftp_file * fle, int fd) |
1 | 591 { |
48 | 592 rfc2068_params * params; |
593 char tempstr[255]; | |
594 size_t len; | |
84 | 595 int ret; |
1 | 596 |
84 | 597 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
598 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, GFTP_EFATAL); | |
599 g_return_val_if_fail (fle != NULL, GFTP_EFATAL); | |
48 | 600 |
601 params = request->protocol_data; | |
602 if (request->last_dir_entry) | |
603 { | |
604 g_free (request->last_dir_entry); | |
605 request->last_dir_entry = NULL; | |
606 } | |
607 | |
105 | 608 if (fd < 0) |
609 fd = request->sockfd; | |
610 | |
48 | 611 while (1) |
612 { | |
105 | 613 if ((ret = gftp_get_line (request, ¶ms->rbuf, tempstr, sizeof (tempstr), |
84 | 614 fd)) < 0) |
615 return (ret); | |
1 | 616 |
48 | 617 params->read_bytes += strlen (tempstr); |
618 | |
105 | 619 if (params->chunked_transfer && strcmp (tempstr, "0") == 0) |
48 | 620 { |
105 | 621 while ((len = gftp_get_line (request, ¶ms->rbuf, tempstr, |
60 | 622 sizeof (tempstr), fd)) > 0) |
48 | 623 { |
105 | 624 if (*tempstr == '\0') |
48 | 625 break; |
626 } | |
627 gftp_file_destroy (fle); | |
58 | 628 |
629 if (len < 0) | |
84 | 630 return (len); |
58 | 631 |
48 | 632 return (0); |
633 } | |
1 | 634 |
48 | 635 if (parse_html_line (tempstr, fle) == 0 || fle->file == NULL) |
636 gftp_file_destroy (fle); | |
637 else | |
638 break; | |
639 | |
640 if (params->max_bytes != 0 && params->read_bytes == params->max_bytes) | |
641 break; | |
642 } | |
643 | |
644 if (fle->file == NULL) | |
1 | 645 { |
48 | 646 gftp_file_destroy (fle); |
105 | 647 return (0); |
1 | 648 } |
649 | |
48 | 650 len = strlen (tempstr); |
651 if (!request->cached) | |
652 { | |
60 | 653 request->last_dir_entry = g_strdup_printf ("%s\n", tempstr); |
654 request->last_dir_entry_len = len + 1; | |
48 | 655 } |
58 | 656 return (len); |
48 | 657 } |
1 | 658 |
659 | |
48 | 660 static int |
661 rfc2068_chdir (gftp_request * request, const char *directory) | |
662 { | |
84 | 663 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
664 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, GFTP_EFATAL); | |
665 g_return_val_if_fail (directory != NULL, GFTP_EFATAL); | |
48 | 666 |
667 if (request->directory != directory) | |
668 { | |
669 if (request->directory) | |
670 g_free (request->directory); | |
105 | 671 request->directory = g_strdup (directory); |
48 | 672 } |
673 return (0); | |
674 } | |
675 | |
676 | |
58 | 677 static void |
678 rfc2068_set_config_options (gftp_request * request) | |
679 { | |
680 gftp_set_proxy_hostname (request, http_proxy_host); | |
681 gftp_set_proxy_port (request, http_proxy_port); | |
682 gftp_set_proxy_username (request, http_proxy_username); | |
683 gftp_set_proxy_password (request, http_proxy_password); | |
684 | |
685 | |
686 if (request->proxy_config == NULL) | |
105 | 687 request->proxy_config = g_strdup ("http"); |
58 | 688 } |
689 | |
690 | |
87 | 691 static void |
692 rfc2068_destroy (gftp_request * request) | |
693 { | |
694 if (request->url_prefix) | |
695 { | |
696 g_free (request->url_prefix); | |
697 request->url_prefix = NULL; | |
698 } | |
699 } | |
700 | |
701 | |
48 | 702 void |
703 rfc2068_init (gftp_request * request) | |
704 { | |
705 g_return_if_fail (request != NULL); | |
1 | 706 |
48 | 707 request->protonum = GFTP_HTTP_NUM; |
708 request->init = rfc2068_init; | |
87 | 709 request->destroy = rfc2068_destroy; |
48 | 710 request->connect = rfc2068_connect; |
711 request->disconnect = rfc2068_disconnect; | |
712 request->get_file = rfc2068_get_file; | |
713 request->put_file = NULL; | |
714 request->transfer_file = NULL; | |
715 request->get_next_file_chunk = rfc2068_get_next_file_chunk; | |
716 request->put_next_file_chunk = NULL; | |
717 request->end_transfer = rfc2068_end_transfer; | |
718 request->abort_transfer = rfc2068_end_transfer; /* NOTE: uses end_transfer */ | |
719 request->list_files = rfc2068_list_files; | |
720 request->get_next_file = rfc2068_get_next_file; | |
721 request->set_data_type = NULL; | |
722 request->get_file_size = rfc2068_get_file_size; | |
723 request->chdir = rfc2068_chdir; | |
724 request->rmdir = NULL; | |
725 request->rmfile = NULL; | |
726 request->mkdir = NULL; | |
727 request->rename = NULL; | |
728 request->chmod = NULL; | |
729 request->site = NULL; | |
58 | 730 request->parse_url = NULL; |
63 | 731 request->swap_socks = NULL; |
58 | 732 request->set_config_options = rfc2068_set_config_options; |
87 | 733 request->url_prefix = g_strdup ("http"); |
48 | 734 request->protocol_name = "HTTP"; |
735 request->need_hostport = 1; | |
736 request->need_userpass = 0; | |
737 request->use_cache = 1; | |
738 request->use_threads = 1; | |
105 | 739 request->always_connected = 1; |
48 | 740 request->protocol_data = g_malloc0 (sizeof (rfc2068_params)); |
741 gftp_set_config_options (request); | |
742 } | |
1 | 743 |