1 /*
2 Copyright (C) 2000 Masanao Izumo <mo@goice.co.jp>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #ifndef NO_STRING_H
24 #include <string.h>
25 #else
26 #include <strings.h>
27 #endif
28
29 #include "libarc/url.h"
30
31 #ifdef HAVE_SAFE_MALLOC
32 extern void *safe_malloc(size_t count);
33 extern void *safe_realloc(void *old_ptr, size_t new_size);
34 #endif /* HAVE_SAFE_MALLOC */
35
36 /* #define DEBUG */
37
38 int url_errno;
39 static struct URL_module *url_mod_list = NULL;
40 char *user_mailaddr = NULL;
41 char *url_user_agent = NULL;
42 int url_newline_code = '\n';
43 char *url_lib_version = URL_LIB_VERSION;
44 int uudecode_unquote_html = 0;
45
url_add_module(struct URL_module * m)46 void url_add_module(struct URL_module *m)
47 {
48 m->chain = url_mod_list;
49 url_mod_list = m;
50 }
51
url_add_modules(struct URL_module * m,...)52 void url_add_modules(struct URL_module *m, ...)
53 {
54 va_list ap;
55 struct URL_module *mod;
56
57 if(m == NULL)
58 return;
59 url_add_module(m);
60 va_start(ap, m);
61 while((mod = va_arg(ap, struct URL_module *)) != NULL)
62 url_add_module(mod);
63 }
64
url_init_nop(void)65 static int url_init_nop(void)
66 {
67 /* Do nothing any more */
68 return 1;
69 }
70
url_check_type(char * s)71 int url_check_type(char *s)
72 {
73 struct URL_module *m;
74
75 for(m = url_mod_list; m; m = m->chain)
76 if(m->type != URL_none_t && m->name_check && m->name_check(s))
77 return m->type;
78 return -1;
79 }
80
url_open(char * s)81 URL url_open(char *s)
82 {
83 struct URL_module *m;
84
85 for(m = url_mod_list; m; m = m->chain)
86 {
87 #ifdef DEBUG
88 printf("Check URL type=%d\n", m->type);
89 #endif /* DEBUG */
90 if(m->type != URL_none_t && m->name_check && m->name_check(s))
91 {
92 #ifdef DEBUG
93 printf("open url (type=%d, name=%s)\n", m->type, s);
94 #endif /* DEBUG */
95 if(m->url_init != url_init_nop)
96 {
97 if(m->url_init && m->url_init() < 0)
98 return NULL;
99 m->url_init = url_init_nop;
100 }
101
102 url_errno = URLERR_NONE;
103 errno = 0;
104 return m->url_open(s);
105 }
106 }
107
108 url_errno = URLERR_NOURL;
109 errno = ENOENT;
110 return NULL;
111 }
112
url_read(URL url,void * buff,long n)113 long url_read(URL url, void *buff, long n)
114 {
115 if(n <= 0)
116 return 0;
117 url_errno = URLERR_NONE;
118 errno = 0;
119 if(url->nread >= url->readlimit) {
120 url->eof = 1;
121 return 0;
122 }
123 if(url->nread + n > url->readlimit)
124 n = (long)(url->readlimit - url->nread);
125 n = url->url_read(url, buff, n);
126 if(n > 0)
127 url->nread += n;
128 return n;
129 }
130
url_safe_read(URL url,void * buff,long n)131 long url_safe_read(URL url, void *buff, long n)
132 {
133 long i;
134 if(n <= 0)
135 return 0;
136
137 do /* Ignore signal intruption */
138 {
139 errno = 0;
140 i = url_read(url, buff, n);
141 } while(i == -1 && errno == EINTR);
142 #if 0
143 /* Already done in url_read!! */
144 if(i > 0)
145 url->nread += i;
146 #endif
147 return i;
148 }
149
url_nread(URL url,void * buff,long n)150 long url_nread(URL url, void *buff, long n)
151 {
152 long insize = 0;
153 char *s = (char *)buff;
154
155 do
156 {
157 long i;
158 i = url_safe_read(url, s + insize, n - insize);
159 if(i <= 0)
160 {
161 if(insize == 0)
162 return i;
163 break;
164 }
165 insize += i;
166 } while(insize < n);
167
168 return insize;
169 }
170
url_gets(URL url,char * buff,int n)171 char *url_gets(URL url, char *buff, int n)
172 {
173 if(url->nread >= url->readlimit)
174 return NULL;
175
176 if(url->url_gets == NULL)
177 {
178 int maxlen, i, c;
179 int newline = url_newline_code;
180
181 maxlen = n - 1;
182 if(maxlen == 0)
183 *buff = '\0';
184 if(maxlen <= 0)
185 return buff;
186 i = 0;
187
188 do
189 {
190 if((c = url_getc(url)) == EOF)
191 break;
192 buff[i++] = c;
193 } while(c != newline && i < maxlen);
194
195 if(i == 0)
196 return NULL; /* EOF */
197 buff[i] = '\0';
198 return buff;
199 }
200
201 url_errno = URLERR_NONE;
202 errno = 0;
203
204 if(url->nread + n > url->readlimit)
205 n = (long)(url->readlimit - url->nread) + 1;
206
207 buff = url->url_gets(url, buff, n);
208 if(buff != NULL)
209 url->nread += strlen(buff);
210 return buff;
211 }
212
url_readline(URL url,char * buff,int n)213 int url_readline(URL url, char *buff, int n)
214 {
215 int maxlen, i, c;
216
217 maxlen = n - 1;
218 if(maxlen == 0)
219 *buff = '\0';
220 if(maxlen <= 0)
221 return 0;
222 do
223 {
224 i = 0;
225 do
226 {
227 if((c = url_getc(url)) == EOF)
228 break;
229 buff[i++] = c;
230 } while(c != '\r' && c != '\n' && i < maxlen);
231 if(i == 0)
232 return 0; /* EOF */
233 } while(i == 1 && (c == '\r' || c == '\n'));
234
235 if(c == '\r' || c == '\n')
236 i--;
237 buff[i] = '\0';
238 return i;
239 }
240
url_fgetc(URL url)241 int url_fgetc(URL url)
242 {
243 if(url->nread >= url->readlimit)
244 return EOF;
245
246 url->nread++;
247 if(url->url_fgetc == NULL)
248 {
249 unsigned char c;
250 if(url_read(url, &c, 1) <= 0)
251 return EOF;
252 return (int)c;
253 }
254 url_errno = URLERR_NONE;
255 errno = 0;
256 return url->url_fgetc(url);
257 }
258
url_seek(URL url,long offset,int whence)259 long url_seek(URL url, long offset, int whence)
260 {
261 long pos, savelimit;
262
263 if(url->url_seek == NULL)
264 {
265 if(whence == SEEK_CUR && offset >= 0)
266 {
267 pos = url_tell(url);
268 if(offset == 0)
269 return pos;
270 savelimit = (long)url->readlimit;
271 url->readlimit = URL_MAX_READLIMIT;
272 url_skip(url, offset);
273 url->readlimit = savelimit;
274 url->nread = 0;
275 return pos;
276 }
277
278 if(whence == SEEK_SET)
279 {
280 pos = url_tell(url);
281 if(pos != -1 && pos <= offset)
282 {
283 if(pos == offset)
284 return pos;
285 savelimit = (long)url->readlimit;
286 url->readlimit = URL_MAX_READLIMIT;
287 url_skip(url, offset - pos);
288 url->readlimit = savelimit;
289 url->nread = 0;
290 return pos;
291 }
292 }
293
294 url_errno = errno = EPERM;
295 return -1;
296 }
297 url_errno = URLERR_NONE;
298 errno = 0;
299 url->nread = 0;
300 return url->url_seek(url, offset, whence);
301 }
302
url_tell(URL url)303 long url_tell(URL url)
304 {
305 url_errno = URLERR_NONE;
306 errno = 0;
307 if(url->url_tell == NULL)
308 return (long)url->nread;
309 return url->url_tell(url);
310 }
311
url_skip(URL url,long n)312 void url_skip(URL url, long n)
313 {
314 char tmp[BUFSIZ];
315
316 if(url->url_seek != NULL)
317 {
318 long savenread;
319
320 savenread = (long)url->nread;
321 if(savenread >= url->readlimit)
322 return;
323 if(savenread + n > url->readlimit)
324 n = (long)(url->readlimit - savenread);
325 if(url->url_seek(url, n, SEEK_CUR) != -1)
326 {
327 url->nread = savenread + n;
328 return;
329 }
330 url->nread = savenread;
331 }
332
333 while(n > 0)
334 {
335 long c;
336
337 c = n;
338 if(c > sizeof(tmp))
339 c = sizeof(tmp);
340 c = url_read(url, tmp, c);
341 if(c <= 0)
342 break;
343 n -= c;
344 }
345 }
346
url_rewind(URL url)347 void url_rewind(URL url)
348 {
349 if(url->url_seek != NULL)
350 url->url_seek(url, 0, SEEK_SET);
351 url->nread = 0;
352 }
353
url_set_readlimit(URL url,long readlimit)354 void url_set_readlimit(URL url, long readlimit)
355 {
356 if(readlimit < 0)
357 url->readlimit = URL_MAX_READLIMIT;
358 else
359 url->readlimit = (unsigned long)readlimit;
360 url->nread = 0;
361 }
362
alloc_url(int size)363 URL alloc_url(int size)
364 {
365 URL url;
366 #ifdef HAVE_SAFE_MALLOC
367 url = (URL)safe_malloc(size);
368 memset(url, 0, size);
369 #else
370 url = (URL)malloc(size);
371 if(url != NULL)
372 memset(url, 0, size);
373 else
374 url_errno = errno;
375 #endif /* HAVE_SAFE_MALLOC */
376
377 url->nread = 0;
378 url->readlimit = URL_MAX_READLIMIT;
379 url->eof = 0;
380 return url;
381 }
382
url_close(URL url)383 void url_close(URL url)
384 {
385 int save_errno = errno;
386
387 if(url == NULL)
388 {
389 fprintf(stderr, "URL stream structure is NULL?\n");
390 #ifdef ABORT_AT_FATAL
391 abort();
392 #endif /* ABORT_AT_FATAL */
393 }
394 else if(url->url_close == NULL)
395 {
396 fprintf(stderr, "URL Error: Already URL is closed (type=%d)\n",
397 url->type);
398 #ifdef ABORT_AT_FATAL
399 abort();
400 #endif /* ABORT_AT_FATAL */
401 }
402 else
403 {
404 url->url_close(url);
405 #if 0
406 url->url_close = NULL;
407 #endif /* unix */
408 }
409 errno = save_errno;
410 }
411
412 #if defined(TILD_SCHEME_ENABLE)
413 #include <pwd.h>
url_expand_home_dir(char * fname)414 char *url_expand_home_dir(char *fname)
415 {
416 static char path[BUFSIZ];
417 char *dir;
418 int dirlen;
419
420 if(fname[0] != '~')
421 return fname;
422
423 if(IS_PATH_SEP(fname[1])) /* ~/... */
424 {
425 fname++;
426 if((dir = getenv("HOME")) == NULL)
427 if((dir = getenv("home")) == NULL)
428 return fname;
429 }
430 else /* ~user/... */
431 {
432 struct passwd *pw;
433 int i;
434
435 fname++;
436 for(i = 0; i < sizeof(path) - 1 && fname[i] && !IS_PATH_SEP(fname[i]); i++)
437 path[i] = fname[i];
438 path[i] = '\0';
439 if((pw = getpwnam(path)) == NULL)
440 return fname - 1;
441 fname += i;
442 dir = pw->pw_dir;
443 }
444 dirlen = strlen(dir);
445 strncpy(path, dir, sizeof(path) - 1);
446 if(sizeof(path) > dirlen)
447 strncat(path, fname, sizeof(path) - dirlen - 1);
448 path[sizeof(path) - 1] = '\0';
449 return path;
450 }
url_unexpand_home_dir(char * fname)451 char *url_unexpand_home_dir(char *fname)
452 {
453 static char path[BUFSIZ];
454 char *dir, *p;
455 int dirlen;
456
457 if(!IS_PATH_SEP(fname[0]))
458 return fname;
459
460 if((dir = getenv("HOME")) == NULL)
461 if((dir = getenv("home")) == NULL)
462 return fname;
463 dirlen = strlen(dir);
464 if(dirlen == 0 || dirlen >= sizeof(path) - 2)
465 return fname;
466 memcpy(path, dir, dirlen);
467 if(!IS_PATH_SEP(path[dirlen - 1]))
468 path[dirlen++] = PATH_SEP;
469
470 #ifndef __W32__
471 if(strncmp(path, fname, dirlen) != 0)
472 #else
473 if(strncasecmp(path, fname, dirlen) != 0)
474 #endif /* __W32__ */
475 return fname;
476
477 path[0] = '~';
478 path[1] = '/';
479 p = fname + dirlen;
480 if(strlen(p) >= sizeof(path) - 3)
481 return fname;
482 path[2] = '\0';
483 strcat(path, p);
484 return path;
485 }
486 #else
url_expand_home_dir(char * fname)487 char *url_expand_home_dir(char *fname)
488 {
489 return fname;
490 }
url_unexpand_home_dir(char * fname)491 char *url_unexpand_home_dir(char *fname)
492 {
493 return fname;
494 }
495 #endif
496
497 static char *url_strerror_txt[] =
498 {
499 "", /* URLERR_NONE */
500 "Unknown URL", /* URLERR_NOURL */
501 "Operation not permitted", /* URLERR_OPERM */
502 "Can't open a URL", /* URLERR_CANTOPEN */
503 "Invalid URL form", /* URLERR_IURLF */
504 "URL too long", /* URLERR_URLTOOLONG */
505 "No mail address", /* URLERR_NOMAILADDR */
506 ""
507 };
508
url_strerror(int no)509 char *url_strerror(int no)
510 {
511 if(no <= URLERR_NONE)
512 return strerror(no);
513 if(no >= URLERR_MAXNO)
514 return "Internal error";
515 return url_strerror_txt[no - URLERR_NONE];
516 }
517
url_dump(URL url,long nbytes,long * read_size)518 void *url_dump(URL url, long nbytes, long *read_size)
519 {
520 long allocated, offset, read_len;
521 char *buff;
522
523 if(read_size != NULL)
524 *read_size = 0;
525 if(nbytes == 0)
526 return NULL;
527 if(nbytes >= 0)
528 {
529 #ifdef HAVE_SAFE_MALLOC
530 buff = (char *)safe_malloc(nbytes);
531 #else
532 if((buff = (char *)malloc(nbytes)) == NULL)
533 return NULL;
534 #endif
535 if(nbytes == 0)
536 return buff;
537 read_len = url_nread(url, buff, nbytes);
538 if(read_size != NULL)
539 *read_size = read_len;
540 if(read_len <= 0)
541 {
542 free(buff);
543 return NULL;
544 }
545 return buff;
546 }
547
548 allocated = 1024;
549 #ifdef HAVE_SAFE_MALLOC
550 buff = (char *)safe_malloc(allocated);
551 #else
552 if((buff = (char *)malloc(nbytes)) == NULL)
553 return NULL;
554 #endif
555 offset = 0;
556 read_len = allocated;
557 while((nbytes = url_read(url, buff + offset, read_len)) > 0)
558 {
559 offset += nbytes;
560 read_len -= nbytes;
561 if(offset == allocated)
562 {
563 read_len = allocated;
564 allocated *= 2;
565 #ifdef HAVE_SAFE_MALLOC
566 buff = (char *)safe_realloc(buff, allocated);
567 #else
568 if((buff = (char *)realloc(buff, allocated)) == NULL)
569 return NULL;
570 #endif
571 }
572 }
573 if(offset == 0)
574 {
575 free(buff);
576 return NULL;
577 }
578 if(read_size != NULL)
579 *read_size = offset;
580 return buff;
581 }
582