Mercurial > gftp.yaz
annotate lib/rfc2068.c @ 28:b3e16d1f19c9
2002-09-24 Brian Masney <masneyb@gftp.org>
* configure.in - take [external] off of AM_GNU_GETTEXT
* de.po, ja.po, nl.po, no.po, pl.po, sv.po, zh_CN.po - fixed
several format modifiers on some strings
author | masneyb |
---|---|
date | Tue, 24 Sep 2002 13:00:16 +0000 |
parents | 83090328581e |
children | c8ec7877432e |
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" | |
21 | |
22 static int rfc2068_connect ( gftp_request * request ); | |
23 static void rfc2068_disconnect ( gftp_request * request ); | |
24 static long rfc2068_get_file ( gftp_request * request, | |
25 const char *filename, | |
26 FILE * fd, | |
27 off_t startsize ); | |
28 static size_t rfc2068_get_next_file_chunk ( gftp_request * request, | |
29 char *buf, | |
30 size_t size ); | |
31 static int rfc2068_end_transfer ( gftp_request * request ); | |
32 static int rfc2068_list_files ( gftp_request * request ); | |
33 static off_t rfc2068_get_file_size ( gftp_request * request, | |
34 const char *filename ); | |
35 static int rfc2068_get_next_file ( gftp_request * request, | |
36 gftp_file * fle, | |
37 FILE * fd ); | |
38 static int rfc2068_chdir ( gftp_request * request, | |
39 const char *directory ); | |
40 static unsigned long rfc2068_send_command ( gftp_request * request, | |
41 const char *command, | |
42 const char *extrahdr ); | |
43 static unsigned long rfc2068_read_response ( gftp_request * request ); | |
44 static int parse_html_line ( char *tempstr, | |
45 gftp_file * fle ); | |
46 static char *base64_encode ( char *str ); | |
47 | |
48 typedef struct rfc2068_params_tag | |
49 { | |
50 unsigned long read_bytes, | |
51 max_bytes; | |
52 int chunked_transfer : 1; | |
53 } rfc2068_params; | |
54 | |
55 void | |
56 rfc2068_init (gftp_request * request) | |
57 { | |
58 g_return_if_fail (request != NULL); | |
59 | |
60 request->protonum = GFTP_HTTP_NUM; | |
61 request->init = rfc2068_init; | |
62 request->destroy = NULL; | |
63 request->connect = rfc2068_connect; | |
64 request->disconnect = rfc2068_disconnect; | |
65 request->get_file = rfc2068_get_file; | |
66 request->put_file = NULL; | |
67 request->transfer_file = NULL; | |
68 request->get_next_file_chunk = rfc2068_get_next_file_chunk; | |
69 request->put_next_file_chunk = NULL; | |
70 request->end_transfer = rfc2068_end_transfer; | |
71 request->list_files = rfc2068_list_files; | |
72 request->get_next_file = rfc2068_get_next_file; | |
73 request->set_data_type = NULL; | |
74 request->get_file_size = rfc2068_get_file_size; | |
75 request->chdir = rfc2068_chdir; | |
76 request->rmdir = NULL; | |
77 request->rmfile = NULL; | |
78 request->mkdir = NULL; | |
79 request->rename = NULL; | |
80 request->chmod = NULL; | |
81 request->site = NULL; | |
82 request->url_prefix = "http"; | |
83 request->protocol_name = "HTTP"; | |
84 request->need_hostport = 1; | |
85 request->need_userpass = 0; | |
86 request->use_cache = 1; | |
87 request->use_threads = 1; | |
88 request->always_connected = 0; | |
89 request->protocol_data = g_malloc0 (sizeof (rfc2068_params)); | |
90 gftp_set_config_options (request); | |
91 } | |
92 | |
93 | |
94 static int | |
95 rfc2068_connect (gftp_request * request) | |
96 { | |
97 char *service; | |
98 int sock; | |
99 | |
100 g_return_val_if_fail (request != NULL, -2); | |
101 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
102 g_return_val_if_fail (request->hostname != NULL, -2); | |
103 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
104 if (request->sockfd != NULL) |
1 | 105 return (0); |
106 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
107 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
|
108 *request->proxy_config != '\0' ? request->proxy_config : "http"; |
1 | 109 if ((sock = gftp_connect_server (request, service)) < 0) |
110 return (-1); | |
111 | |
112 if (request->directory && *request->directory == '\0') | |
113 { | |
114 g_free (request->directory); | |
115 request->directory = NULL; | |
116 } | |
117 | |
118 if (!request->directory) | |
119 { | |
120 request->directory = g_malloc (2); | |
121 strcpy (request->directory, "/"); | |
122 } | |
123 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
124 if ((request->sockfd = fdopen (sock, "rb+")) == NULL) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
125 { |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
126 request->logging_function (gftp_logging_error, request->user_data, |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
127 _("Cannot fdopen() socket: %s\n"), |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
128 g_strerror (errno)); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
129 close (sock); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
130 return (-2); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
131 } |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
132 |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
133 if ((request->sockfd_write = fdopen (sock, "wb+")) == NULL) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
134 { |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
135 request->logging_function (gftp_logging_error, request->user_data, |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
136 _("Cannot fdopen() socket: %s\n"), |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
137 g_strerror (errno)); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
138 gftp_disconnect (request); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
139 return (-2); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
140 } |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
141 |
1 | 142 return (0); |
143 } | |
144 | |
145 | |
146 static void | |
147 rfc2068_disconnect (gftp_request * request) | |
148 { | |
149 g_return_if_fail (request != NULL); | |
150 g_return_if_fail (request->protonum == GFTP_HTTP_NUM); | |
151 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
152 if (request->sockfd != NULL) |
1 | 153 { |
154 request->logging_function (gftp_logging_misc, request->user_data, | |
155 _("Disconnecting from site %s\n"), | |
156 request->hostname); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
157 fclose (request->sockfd); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
158 request->sockfd = NULL; |
1 | 159 } |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
160 |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
161 if (request->sockfd_write != NULL) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
162 { |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
163 fclose (request->sockfd_write); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
164 request->sockfd_write = NULL; |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
165 } |
1 | 166 } |
167 | |
168 | |
169 static long | |
170 rfc2068_get_file (gftp_request * request, const char *filename, FILE * fd, | |
171 off_t startsize) | |
172 { | |
173 char *tempstr, *extrahdr, *pos, *proto; | |
174 int restarted; | |
175 off_t size; | |
176 | |
177 g_return_val_if_fail (request != NULL, -2); | |
178 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
179 g_return_val_if_fail (filename != NULL, -2); | |
180 | |
181 if (fd != NULL) | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
182 request->sockfd = fd; |
1 | 183 |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
184 if (request->sockfd == NULL && rfc2068_connect (request) != 0) |
1 | 185 return (-2); |
186 | |
187 if (request->proxy_config != NULL && *request->proxy_config != '\0') | |
188 proto = request->proxy_config; | |
189 else | |
190 proto = "http"; | |
191 | |
7 | 192 if (request->username == NULL || *request->username == '\0') |
1 | 193 tempstr = g_strconcat ("GET ", proto, "://", |
194 request->hostname, "/", filename, | |
195 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
196 else | |
197 tempstr = g_strconcat ("GET ", proto, "://", | |
198 request->username, "@", request->hostname, "/", filename, | |
199 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
200 | |
201 if ((pos = strstr (tempstr, "://")) != NULL) | |
202 remove_double_slashes (pos + 3); | |
203 else | |
204 remove_double_slashes (tempstr); | |
205 | |
206 if (!use_http11 || startsize == 0) | |
207 extrahdr = NULL; | |
208 else | |
209 { | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
210 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
211 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
|
212 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
|
213 _("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
|
214 startsize); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
215 #else |
1 | 216 extrahdr = g_strdup_printf ("Range: bytes=%ld-\n", startsize); |
217 request->logging_function (gftp_logging_misc, request->user_data, | |
218 _("Starting the file transfer at offset %ld\n"), | |
219 startsize); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
220 #endif |
1 | 221 } |
222 | |
223 size = rfc2068_send_command (request, tempstr, extrahdr); | |
224 g_free (tempstr); | |
225 if (extrahdr) | |
226 g_free (extrahdr); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
227 if (request->sockfd == NULL) |
1 | 228 return (-2); |
229 | |
230 restarted = 0; | |
231 if (strlen (request->last_ftp_response) > 9 | |
232 && strncmp (request->last_ftp_response + 9, "206", 3) == 0) | |
233 restarted = 1; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
234 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
|
235 strncmp (request->last_ftp_response + 9, "200", 3) != 0) |
1 | 236 { |
237 request->logging_function (gftp_logging_misc, request->user_data, | |
238 _("Cannot retrieve file %s\n"), filename); | |
239 return (-2); | |
240 } | |
241 | |
242 return (restarted ? size + startsize : size); | |
243 } | |
244 | |
245 | |
246 static size_t | |
247 rfc2068_get_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
248 { | |
249 rfc2068_params * params; | |
250 struct timeval tv; | |
251 fd_set fset; | |
252 size_t len; | |
253 | |
254 g_return_val_if_fail (request != NULL, -2); | |
255 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
256 | |
257 params = request->protocol_data; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
258 if (params->max_bytes == params->read_bytes || feof (request->sockfd)) |
1 | 259 return (0); |
260 | |
261 FD_ZERO (&fset); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
262 FD_SET (fileno (request->sockfd), &fset); |
1 | 263 tv.tv_sec = request->network_timeout; |
264 tv.tv_usec = 0; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
265 if (select (fileno (request->sockfd) + 1, &fset, NULL, NULL, &tv) <= 0) |
1 | 266 { |
267 request->logging_function (gftp_logging_error, request->user_data, | |
268 _("Connection to %s timed out\n"), | |
269 request->hostname); | |
270 gftp_disconnect (request); | |
271 return (-1); | |
272 } | |
273 | |
274 if (params->max_bytes > 0 && size + params->read_bytes > params->max_bytes) | |
275 size = params->max_bytes - params->read_bytes; | |
276 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
277 len = fread (buf, 1, size, request->sockfd); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
278 if (ferror (request->sockfd)) |
1 | 279 { |
280 request->logging_function (gftp_logging_error, request->user_data, | |
281 _("Error reading from host %s: %s\n"), | |
282 request->hostname, | |
283 g_strerror (errno)); | |
284 gftp_disconnect (request); | |
285 return (-1); | |
286 } | |
287 | |
288 params->read_bytes += len; | |
289 return (len); | |
290 } | |
291 | |
292 | |
293 static int | |
294 rfc2068_end_transfer (gftp_request * request) | |
295 { | |
296 rfc2068_params * params; | |
297 | |
298 g_return_val_if_fail (request != NULL, -2); | |
299 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
300 g_return_val_if_fail (request->sockfd != NULL, -2); |
1 | 301 |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
302 if (request->sockfd == NULL) |
1 | 303 return (-2); |
304 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
305 fclose (request->sockfd); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
306 request->sockfd = NULL; |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
307 fclose (request->sockfd_write); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
308 request->sockfd_write = NULL; |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
309 |
1 | 310 params = request->protocol_data; |
311 params->max_bytes = 0; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
312 |
1 | 313 request->logging_function (gftp_logging_misc, request->user_data, |
314 _("Finished retrieving data\n")); | |
315 return (0); | |
316 } | |
317 | |
318 | |
319 static int | |
320 rfc2068_list_files (gftp_request * request) | |
321 { | |
322 char *tempstr, *pos, *proto; | |
323 rfc2068_params *params; | |
324 | |
325 g_return_val_if_fail (request != NULL, -2); | |
326 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
327 | |
328 params = request->protocol_data; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
329 if (request->sockfd == NULL && rfc2068_connect (request) != 0) |
1 | 330 return (-2); |
331 | |
332 if (request->proxy_config != NULL && *request->proxy_config != '\0') | |
333 proto = request->proxy_config; | |
334 else | |
335 proto = "http"; | |
336 | |
7 | 337 if (request->username == NULL || *request->username == '\0') |
1 | 338 tempstr = g_strconcat ("GET ", proto, "://", |
339 request->hostname, "/", request->directory, | |
340 use_http11 ? "/ HTTP/1.1\n" : "/ HTTP/1.0\n", NULL); | |
341 else | |
342 tempstr = g_strconcat ("GET ", proto, "://", request->username, "@", | |
343 request->hostname, "/", request->directory, | |
344 use_http11 ? "/ HTTP/1.1\n" : "/ HTTP/1.0\n", NULL); | |
345 | |
346 if ((pos = strstr (tempstr, "://")) != NULL) | |
347 remove_double_slashes (pos + 3); | |
348 else | |
349 remove_double_slashes (tempstr); | |
350 | |
351 rfc2068_send_command (request, tempstr, NULL); | |
352 g_free (tempstr); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
353 if (request->sockfd == NULL) |
1 | 354 return (-2); |
355 | |
356 params->read_bytes = 0; | |
357 if (strlen (request->last_ftp_response) > 9 && | |
358 strncmp (request->last_ftp_response + 9, "200", 3) == 0) | |
359 { | |
360 request->logging_function (gftp_logging_misc, request->user_data, | |
361 _("Retrieving directory listing...\n")); | |
362 return (0); | |
363 } | |
364 | |
365 return (-2); | |
366 } | |
367 | |
368 | |
369 static off_t | |
370 rfc2068_get_file_size (gftp_request * request, const char *filename) | |
371 { | |
372 char *tempstr, *pos, *proto; | |
373 unsigned long size; | |
374 | |
375 g_return_val_if_fail (request != NULL, -2); | |
376 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
377 g_return_val_if_fail (filename != NULL, -2); | |
378 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
379 if (request->sockfd == NULL && rfc2068_connect (request) != 0) |
1 | 380 return (-2); |
381 | |
382 if (request->proxy_config != NULL && *request->proxy_config != '\0') | |
383 proto = request->proxy_config; | |
384 else | |
385 proto = "http"; | |
386 | |
7 | 387 if (request->username == NULL || *request->username == '\0') |
1 | 388 tempstr = g_strconcat ("HEAD ", proto, request->hostname, "/", filename, |
389 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
390 else | |
391 tempstr = g_strconcat ("HEAD ", proto, request->username, "@", | |
392 request->hostname, "/", filename, | |
393 use_http11 ? " HTTP/1.1\n" : " HTTP/1.0\n", NULL); | |
394 | |
395 if ((pos = strstr (tempstr, "://")) != NULL) | |
396 remove_double_slashes (pos + 3); | |
397 else | |
398 remove_double_slashes (tempstr); | |
399 | |
400 size = rfc2068_send_command (request, tempstr, NULL); | |
401 g_free (tempstr); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
402 if (request->sockfd == NULL) |
1 | 403 return (-2); |
404 | |
405 return (size); | |
406 } | |
407 | |
408 | |
409 static int | |
410 rfc2068_get_next_file (gftp_request * request, gftp_file * fle, FILE * fd) | |
411 { | |
412 rfc2068_params * params; | |
413 char tempstr[255]; | |
414 size_t len; | |
415 | |
416 g_return_val_if_fail (request != NULL, -2); | |
417 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
418 g_return_val_if_fail (fle != NULL, -2); | |
419 | |
420 params = request->protocol_data; | |
421 if (request->last_dir_entry) | |
422 { | |
423 g_free (request->last_dir_entry); | |
424 request->last_dir_entry = NULL; | |
425 } | |
426 | |
427 while (1) | |
428 { | |
429 /* I don't run select() here because select could return | |
430 successfully saying there is data, but the fgets call could block if | |
431 there is no carriage return */ | |
432 if (!fgets (tempstr, sizeof (tempstr), fd)) | |
433 { | |
434 gftp_file_destroy (fle); | |
435 return (-2); | |
436 } | |
437 tempstr[sizeof (tempstr) - 1] = '\0'; | |
438 params->read_bytes += strlen (tempstr); | |
439 | |
440 if (params->chunked_transfer && strcmp (tempstr, "0\r\n") == 0) | |
441 { | |
442 /* I don't run select() here because select could return | |
443 successfully saying there is data, but the fgets call could block | |
444 if there is no carriage return */ | |
445 while (fgets (tempstr, sizeof (tempstr), fd)) | |
446 { | |
447 if (strcmp (tempstr, "\r\n") == 0) | |
448 break; | |
449 } | |
450 gftp_file_destroy (fle); | |
451 return (0); | |
452 } | |
453 | |
454 if (parse_html_line (tempstr, fle) == 0 || fle->file == NULL) | |
455 gftp_file_destroy (fle); | |
456 else | |
457 break; | |
458 | |
459 if (params->max_bytes != 0 && params->read_bytes == params->max_bytes) | |
460 break; | |
461 } | |
462 | |
463 if (fle->file == NULL) | |
464 { | |
465 gftp_file_destroy (fle); | |
466 return (-2); | |
467 } | |
468 | |
469 len = strlen (tempstr); | |
470 if (!request->cached) | |
471 { | |
472 request->last_dir_entry = g_malloc (len + 1); | |
473 strcpy (request->last_dir_entry, tempstr); | |
474 request->last_dir_entry_len = len; | |
475 } | |
476 return (feof (fd) ? 0 : len); | |
477 } | |
478 | |
479 | |
480 static int | |
481 rfc2068_chdir (gftp_request * request, const char *directory) | |
482 { | |
483 g_return_val_if_fail (request != NULL, -2); | |
484 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
485 g_return_val_if_fail (directory != NULL, -2); | |
486 | |
487 if (request->directory != directory) | |
488 { | |
489 if (request->directory) | |
490 g_free (request->directory); | |
491 request->directory = g_malloc (strlen (directory) + 1); | |
492 strcpy (request->directory, directory); | |
493 } | |
494 return (0); | |
495 } | |
496 | |
497 | |
498 static unsigned long | |
499 rfc2068_send_command (gftp_request * request, const char *command, | |
500 const char *extrahdr) | |
501 { | |
502 char *tempstr, *str; | |
503 | |
504 g_return_val_if_fail (request != NULL, -2); | |
505 g_return_val_if_fail (request->protonum == GFTP_HTTP_NUM, -2); | |
506 g_return_val_if_fail (command != NULL, -2); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
507 g_return_val_if_fail (request->sockfd_write != NULL, -2); |
1 | 508 |
509 request->logging_function (gftp_logging_send, request->user_data, "%s", | |
510 command); | |
511 | |
512 request->logging_function (gftp_logging_send, request->user_data, | |
513 "User-Agent: %s\n", version); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
514 fprintf (request->sockfd_write, "%sUser-Agent: %s\nHost: %s\n", command, |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
515 version, request->hostname); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
516 if (ferror (request->sockfd_write) != 0) |
1 | 517 { |
518 gftp_disconnect (request); | |
519 return (-2); | |
520 } | |
521 | |
522 if (request->use_proxy && request->proxy_username != NULL && | |
523 *request->proxy_username != '\0') | |
524 { | |
525 tempstr = g_strconcat (request->proxy_username, ":", | |
526 request->proxy_password, NULL); | |
527 str = base64_encode (tempstr); | |
528 g_free (tempstr); | |
529 | |
530 request->logging_function (gftp_logging_send, request->user_data, | |
531 "Proxy-authorization: Basic xxxx:xxxx\n"); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
532 fprintf (request->sockfd_write, "Proxy-authorization: Basic %s\n", str); |
1 | 533 g_free (str); |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
534 if (ferror (request->sockfd_write) != 0) |
1 | 535 { |
536 gftp_disconnect (request); | |
537 return (-2); | |
538 } | |
539 } | |
540 | |
7 | 541 if (request->username != NULL && *request->username != '\0') |
1 | 542 { |
543 tempstr = g_strconcat (request->username, ":", request->password, NULL); | |
544 str = base64_encode (tempstr); | |
545 g_free (tempstr); | |
546 | |
547 request->logging_function (gftp_logging_send, request->user_data, | |
548 "Authorization: Basic xxxx\n"); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
549 fprintf (request->sockfd_write, "Authorization: Basic %s\n", str); |
1 | 550 g_free (str); |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
551 if (ferror (request->sockfd_write) != 0) |
1 | 552 { |
553 gftp_disconnect (request); | |
554 return (-2); | |
555 } | |
556 } | |
557 | |
558 if (extrahdr) | |
559 { | |
560 request->logging_function (gftp_logging_send, request->user_data, | |
561 "%s", extrahdr); | |
562 request->logging_function (gftp_logging_send, request->user_data, "%s", | |
563 extrahdr); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
564 fprintf (request->sockfd_write, "%s", extrahdr); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
565 if (ferror (request->sockfd_write) != 0) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
566 { |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
567 gftp_disconnect (request); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
568 return (-2); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
569 } |
1 | 570 } |
571 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
572 fprintf (request->sockfd_write, "\n"); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
573 if (ferror (request->sockfd_write) != 0) |
1 | 574 { |
575 gftp_disconnect (request); | |
576 return (-2); | |
577 } | |
578 return (rfc2068_read_response (request)); | |
579 } | |
580 | |
581 | |
582 static unsigned long | |
583 rfc2068_read_response (gftp_request * request) | |
584 { | |
585 rfc2068_params * params; | |
586 char tempstr[255]; | |
587 | |
588 params = request->protocol_data; | |
589 params->max_bytes = 0; | |
590 /* I don't run select() here because select could return | |
591 successfully saying there is data, but the fgets call could block if | |
592 there is no carriage return */ | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
593 if (!fgets (tempstr, sizeof (tempstr), request->sockfd)) |
1 | 594 { |
595 gftp_disconnect (request); | |
596 return (0); | |
597 } | |
598 if (request->last_ftp_response) | |
599 g_free (request->last_ftp_response); | |
600 request->last_ftp_response = g_malloc (strlen (tempstr) + 1); | |
601 strcpy (request->last_ftp_response, tempstr); | |
602 | |
603 request->logging_function (gftp_logging_recv, request->user_data, "%s", | |
604 tempstr); | |
605 | |
606 params->chunked_transfer = 0; | |
607 while (1) | |
608 { | |
609 /* I don't run select() here because select could return | |
610 successfully saying there is data, but the fgets call could block if | |
611 there is no carriage return */ | |
612 /* Read rest of proxy header */ | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
613 if (!fgets (tempstr, sizeof (tempstr), request->sockfd)) |
1 | 614 { |
615 gftp_disconnect (request); | |
616 return (0); | |
617 } | |
618 | |
619 if (*tempstr == '\r' || *tempstr == '\n') | |
620 break; | |
621 | |
622 request->logging_function (gftp_logging_recv, request->user_data, "%s", | |
623 tempstr); | |
624 | |
625 if (strncmp (tempstr, "Content-Length:", 15) == 0) | |
626 params->max_bytes = strtol (tempstr + 16, NULL, 10); | |
627 if (strncmp (tempstr, "Transfer-Encoding: chunked", 26) == 0) | |
628 params->chunked_transfer = 1; | |
629 } | |
630 | |
631 return (params->max_bytes); | |
632 } | |
633 | |
634 | |
635 static int | |
636 parse_html_line (char *tempstr, gftp_file * fle) | |
637 { | |
638 char months[13][3] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", | |
639 "Sep", "Oct", "Nov", "Dec"}; | |
640 char *stpos, *pos, month[4]; | |
641 struct tm t; | |
642 long units; | |
643 int i; | |
644 | |
645 memset (fle, 0, sizeof (*fle)); | |
646 | |
647 if ((pos = strstr (tempstr, "<A HREF=")) == NULL && | |
648 (pos = strstr (tempstr, "<a href=")) == NULL) | |
649 return (0); | |
650 | |
651 /* Find the filename */ | |
652 while (*pos != '"' && *pos != '\0') | |
653 pos++; | |
654 if (*pos == '\0') | |
655 return (0); | |
656 pos++; | |
657 | |
658 for (stpos = pos; *pos != '"' && *pos != '\0'; pos++); | |
659 if (*pos == '\0') | |
660 return (0); | |
661 *pos = '\0'; | |
662 | |
663 /* Copy file attributes. Just about the only thing we can get is whether it | |
664 is a directory or not */ | |
665 fle->attribs = g_malloc (11); | |
666 strcpy (fle->attribs, "----------"); | |
667 if (*(pos - 1) == '/') | |
668 { | |
669 *(pos - 1) = '\0'; | |
670 *fle->attribs = 'd'; | |
671 fle->isdir = 1; | |
672 } | |
673 | |
674 /* Copy filename */ | |
675 if (strchr (stpos, '/') != NULL || strncmp (stpos, "mailto:", 7) == 0 || | |
676 *stpos == '\0' || *stpos == '?') | |
677 return (0); | |
678 | |
679 fle->file = g_malloc (strlen (stpos) + 1); | |
680 strcpy (fle->file, stpos); | |
681 | |
682 if (*(pos - 1) == '\0') | |
683 *(pos - 1) = '/'; | |
684 *pos = '"'; | |
685 pos++; | |
686 | |
687 /* Skip whitespace and html tags after file and before date */ | |
688 stpos = pos; | |
689 if ((pos = strstr (stpos, "</A>")) == NULL && | |
690 (pos = strstr (stpos, "</a>")) == NULL) | |
691 return (0); | |
692 | |
693 pos += 4; | |
694 | |
695 while (*pos == ' ' || *pos == '.' || *pos == '<') | |
696 { | |
697 if (*pos == '<') | |
698 { | |
699 if (strncmp (pos, "<A ", 3) == 0 || strncmp (pos, "<a ", 3) == 0) | |
700 { | |
701 stpos = pos; | |
702 if ((pos = strstr (stpos, "</A>")) == NULL | |
703 && (pos = strstr (stpos, "</a>")) == NULL) | |
704 return (0); | |
705 pos += 4; | |
706 } | |
707 else | |
708 { | |
709 while (*pos != '>' && *pos != '\0') | |
710 pos++; | |
711 if (*pos == '\0') | |
712 return (0); | |
713 } | |
714 } | |
715 pos++; | |
716 } | |
717 | |
718 /* Now get the date */ | |
719 memset (&t, 0, sizeof (t)); | |
720 memset (month, 0, sizeof (month)); | |
721 if (strchr (pos, ':') != NULL) | |
722 { | |
723 if (*pos == '[') | |
724 pos++; | |
725 sscanf (pos, "%02d-%3s-%04d %02d:%02d", &t.tm_mday, month, &t.tm_year, | |
726 &t.tm_hour, &t.tm_min); | |
727 while (*pos != ' ' && *pos != '\0') | |
728 pos++; | |
729 if (*pos == '\0') | |
730 return (1); | |
731 | |
732 while (*pos == ' ') | |
733 pos++; | |
734 | |
735 while (*pos != ' ' && *pos != '\0') | |
736 pos++; | |
737 if (*pos == '\0') | |
738 return (1); | |
739 | |
740 t.tm_year -= 1900; | |
741 } | |
742 else | |
743 { | |
744 pos++; | |
745 strncpy (month, pos, 3); | |
746 for (i=0; i<3 && *pos != '\0'; i++) | |
747 pos++; | |
748 if (*pos == '\0') | |
749 return (1); | |
750 | |
751 while (*pos == ' ') | |
752 pos++; | |
753 | |
754 t.tm_mday = strtol (pos, NULL, 10); | |
755 while (*pos != ' ' && *pos != '\0') | |
756 pos++; | |
757 if (*pos == '\0') | |
758 return (1); | |
759 | |
760 while (*pos == ' ') | |
761 pos++; | |
762 | |
763 t.tm_year = strtol (pos, NULL, 10) - 1900; | |
764 while (*pos != ' ' && *pos != '\0') | |
765 pos++; | |
766 if (*pos == '\0') | |
767 return (1); | |
768 } | |
769 | |
770 for (i=0; i<12; i++) | |
771 { | |
772 if (strncmp (month, months[i], 3) == 0) | |
773 { | |
774 t.tm_mon = i; | |
775 break; | |
776 } | |
777 } | |
778 | |
779 fle->datetime = mktime (&t); | |
780 | |
781 while (*pos == ' ' || *pos == ']') | |
782 pos++; | |
783 | |
784 /* Get the size */ | |
785 /* This gets confusing on lines like "... 1.1M RedHat RPM package" */ | |
786 /* We need to avoid finding the 'k' in package */ | |
787 | |
788 stpos = strchr (pos, 'k'); | |
789 if (stpos == NULL || !isdigit (*(stpos - 1))) | |
790 stpos = strchr (pos, 'M'); | |
791 if (stpos == NULL || !isdigit (*(stpos - 1))) | |
792 return (1); /* Return successfully | |
793 since we got the file */ | |
794 if (*stpos == 'k') | |
795 units = 1024; | |
796 else | |
797 units = 1048576; | |
798 | |
799 fle->size = 0; | |
800 | |
801 while (*(stpos - 1) != ' ' && *(stpos - 1) != '\t' && stpos > tempstr) | |
802 { | |
803 stpos--; | |
804 if ((*stpos == '.') && isdigit (*(stpos + 1)) ) | |
805 { /* found decimal point */ | |
806 fle->size = units * strtol (stpos + 1, NULL, 10); | |
807 fle->size /= 10; | |
808 } | |
809 } | |
810 | |
811 fle->size += units * strtol (stpos, NULL, 10); | |
812 return (1); | |
813 } | |
814 | |
815 | |
816 static char * | |
817 base64_encode (char *str) | |
818 { | |
819 | |
820 /* The standard to Base64 encoding can be found in RFC2045 */ | |
821 | |
822 char *newstr, *newpos, *fillpos, *pos; | |
823 unsigned char table[64], encode[3]; | |
824 int i, num; | |
825 | |
826 for (i = 0; i < 26; i++) | |
827 { | |
828 table[i] = 'A' + i; | |
829 table[i + 26] = 'a' + i; | |
830 } | |
831 | |
832 for (i = 0; i < 10; i++) | |
833 table[i + 52] = '0' + i; | |
834 | |
835 table[62] = '+'; | |
836 table[63] = '-'; | |
837 | |
838 num = strlen (str) / 3; | |
839 if (strlen (str) % 3 > 0) | |
840 num++; | |
841 newstr = g_malloc (num * 4 + 1); | |
842 newstr[num * 4] = '\0'; | |
843 newpos = newstr; | |
844 | |
845 pos = str; | |
846 while (*pos != '\0') | |
847 { | |
848 memset (encode, 0, sizeof (encode)); | |
849 for (i = 0; i < 3 && *pos != '\0'; i++) | |
850 encode[i] = *pos++; | |
851 | |
852 fillpos = newpos; | |
853 *newpos++ = table[encode[0] >> 2]; | |
854 *newpos++ = table[(encode[0] & 3) << 4 | encode[1] >> 4]; | |
855 *newpos++ = table[(encode[1] & 0xF) << 2 | encode[2] >> 6]; | |
856 *newpos++ = table[encode[2] & 0x3F]; | |
857 while (i < 3) | |
858 fillpos[++i] = '='; | |
859 } | |
860 return (newstr); | |
861 } |