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