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