1 /*
2 	tools.c
3 	27.3.99 tn
4 */
5 
6 #ifdef HAVE_CONFIG_H
7 # include <config.h>
8 #endif
9 
10 #if HAVE_LOCALE_H
11 #include <locale.h>
12 #else
13 # define setlocale(Category, Locale)
14 #endif
15 #include "gettext.h"
16 
17 #include <stdio.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <strings.h>
22 #include <dirent.h>
23 #include <fcntl.h>
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <pwd.h>
29 
30 #if ENABLE_NLS
31 # define _(String) gettext (String)
32 # define N_(String) gettext_noop (String)
33 #else
34 # define _(String) (String)
35 # define N_(String) (String)
36 #endif
37 
38 #include <gtk/gtk.h>
39 #include <gdk/gdk.h>
40 #include "xcdrdata.h"
41 #include "xcdroast.h"
42 #include "main.h"
43 
44 
45 /* return 1 if path is a directory and 0 if not or invalid path */
46 
is_directory(gchar * path)47 gint is_directory(gchar *path) {
48 struct stat buf;
49 
50 	if (stat(path,&buf) != 0) {
51 		return 0;
52 	}
53 
54 	if (S_ISDIR(buf.st_mode) == 1) {
55 		return 1;
56 	} else {
57 		return 0;
58 	}
59 }
60 
61 /* return 1 if path is not a directory and 0 if or invalid path */
62 
is_not_directory(gchar * path)63 gint is_not_directory(gchar *path) {
64 struct stat buf;
65 
66 	if (stat(path,&buf) != 0) {
67 		return 0;
68 	}
69 
70 	if (S_ISDIR(buf.st_mode) == 0) {
71 		return 1;
72 	} else {
73 		return 0;
74 	}
75 }
76 
77 
78 /* return 1 if path is a file or directory and 0 if not or invalid path */
79 
is_file(gchar * path)80 gint is_file(gchar *path) {
81 struct stat buf;
82 
83 	if (stat(path,&buf) != 0) {
84 		return 0;
85 	}
86 	return 1;
87 }
88 
89 
90 /* return the base directory of a given path, or NULL when invalid */
91 /* warning..overwrites original str */
92 
get_basedir(gchar * dir)93 gchar *get_basedir(gchar *dir) {
94 gchar *p;
95 
96 	/* nothing to do if this is already a directory */
97 	if (is_directory(dir)) {
98 		return dir;
99 	}
100 
101 	/* look for last slash */
102 	p = rindex(dir,'/');
103 	if (p) {
104 		*p = '\0';
105 		if (strcmp(dir,"") == 0) {
106 			strcpy(dir,"/");
107 		}
108 		return dir;
109 	}
110 	return NULL;
111 }
112 
113 
114 /* return the pure filename of a given path */
115 
get_purefile(gchar * dir,gchar * out)116 gchar *get_purefile(gchar *dir, gchar *out) {
117 gchar *p;
118 
119 	/* look for last slash */
120 	p = rindex(dir,'/');
121 	if (p) {
122 		strncpy(out, p+1, MAXLINE);
123 	} else {
124 		strncpy(out, dir, MAXLINE);
125 	}
126 
127 	return out;
128 }
129 
130 
131 /* return 1 when path contains a subdir, else 0 */
132 /* skip . and ..-directories */
133 
is_subdirs(gchar * path)134 gint is_subdirs(gchar *path) {
135 struct dirent *ent;
136 DIR *dir;
137 gchar tmp[MAXLINE];
138 
139 	dir = opendir(path);
140 
141 	/* invalid directory */
142 	if (dir == NULL)
143 		return 0;
144 
145 	while ( (ent = readdir(dir)) ) {
146 		strcpy(tmp,path);
147 		/* add slash when not there */
148 		if (tmp[strlen(tmp)-1] != '/')
149 			strcat(tmp,"/");
150 		strcat(tmp,ent->d_name);
151 
152 		if (strcmp(ent->d_name,".") == 0 ||
153 		    strcmp(ent->d_name,"..") == 0)
154 			continue;
155 
156 		if (is_directory(tmp)) {
157 			closedir(dir);
158 			return 1;
159 		}
160 	}
161 	closedir(dir);
162 	return 0;
163 }
164 
165 
166 /* return 1 when path contains files, else 0 */
167 /* skip . and ..-directories */
168 
is_subfiles(gchar * path)169 gint is_subfiles(gchar *path) {
170 struct dirent *ent;
171 DIR *dir;
172 gchar tmp[MAXLINE];
173 
174 	dir = opendir(path);
175 
176 	/* invalid directory */
177 	if (dir == NULL)
178 		return 0;
179 
180 	while ( (ent = readdir(dir)) ) {
181 		strcpy(tmp,path);
182 		/* add slash when not there */
183 		if (tmp[strlen(tmp)-1] != '/')
184 			strcat(tmp,"/");
185 		strcat(tmp,ent->d_name);
186 
187 		if (strcmp(ent->d_name,".") == 0 ||
188 		    strcmp(ent->d_name,"..") == 0)
189 			continue;
190 
191 		closedir(dir);
192 		return 1;
193 	}
194 	closedir(dir);
195 	return 0;
196 }
197 
198 
199 /* strip a string of leading and trailing whitespace */
200 
strip_string(gchar * str)201 gchar *strip_string(gchar *str) {
202 gint i,j;
203 gint c1;
204 
205         if ( str == NULL) return (NULL);
206 
207         /* count how many leading chars to be whitespace */
208         for(i=0; i<strlen(str); i++) {
209                 if (str[i] != ' ' && str[i] != '\t' && str[i] != '\r')
210                         break;
211         }
212 
213         /* count how many trailing chars to be whitespace */
214         for(j=strlen(str)-1; j >= 0; j--) {
215                 if (str[j] != ' ' && str[j] != '\t' && str[j] != '\n' && str[j] != '\r')
216                         break;
217         }
218 
219 	/* string contains only whitespace? */
220 	if (j<i) {
221 		str[0] = '\0';
222 		return(str);
223 	}
224 
225         /* now move the chars to the front */
226         for(c1=i; c1 <= j; c1++) {
227                 str[c1-i] = str[c1];
228         }
229         str[j+1-i] = '\0';
230 
231         return(str);
232 }
233 
234 
235 /* parse escape-chars in string -> e.g. translate \n to newline */
236 
escape_parse(gchar * str)237 gchar *escape_parse(gchar *str) {
238 gchar tmp[MAXLINE];
239 gchar c;
240 guint i,j;
241 
242         if ( str == NULL) return (NULL);
243 
244 	j = 0;
245         for(i=0; i<strlen(str); i++) {
246 		c = str[i];
247 		if (c == '\\') {
248 			i++;
249 			switch(str[i]) {
250 
251 			case 'n':
252 				c = '\n';
253 				break;
254 
255 			case 't':
256 				c = '\t';
257 				break;
258 
259 			case 'b':
260 				c = '\b';
261 				break;
262 
263 			default:
264 				c = str[i];
265 			}
266 		}
267 
268 		tmp[j]=c;
269 		j++;
270         }
271 
272 	tmp[j] = '\0';
273 
274 	strcpy(str,tmp);
275         return(str);
276 }
277 
278 
279 /* convert escape-chars in string -> e.g. newline to \n */
280 
convert_escape(gchar * str)281 gchar *convert_escape(gchar *str) {
282 gchar tmp[MAXLINE*2];
283 gchar c,d;
284 guint i,j;
285 
286 	if (str == NULL) return (NULL);
287 
288 	j = 0;
289 	for (i = 0; i < strlen(str); i++) {
290 		c = str[i];
291 		d = '\0';
292 
293 		switch (c) {
294 		case '\n':
295 			d = 'n';
296 			break;
297 		case '\t':
298 			d = 't';
299 			break;
300 		case '\b':
301 			d = 'b';
302 			break;
303 		case '\\':
304 			d = '\\';
305 			break;
306 		case '\"':
307 			d = '\"';
308 			break;
309 		case '=':
310 			d = '=';
311 			break;
312 		}
313 		if (d != '\0') {
314 			/* generate escaped char */
315 			tmp[j] = '\\'; j++;
316 			tmp[j] = d; j++;
317 		} else {
318 			tmp[j] = c; j++;
319 		}
320 	}
321 
322 	tmp[j] = '\0';
323 
324 	/* check if new string is not getting to long */
325 	if (strlen(tmp) < MAXLINE) {
326 		strcpy(str,tmp);
327 	} else {
328 		/* over MAXLINE chars - should never happen */
329 		/* cut off string */
330 		strncpy(str,tmp,MAXLINE-1);
331 		str[MAXLINE-1] = '\0';
332 	}
333 
334 	return(str);
335 }
336 
337 
338 /* another variant of escaping. Just required to escape = on the command
339    line of mkisofs directly */
340 
convert_escape3(gchar * str)341 gchar *convert_escape3(gchar *str) {
342 gchar tmp[MAXLINE*2];
343 gchar c,d;
344 guint i,j;
345 
346 	if (str == NULL) return (NULL);
347 
348 	j = 0;
349 	for (i = 0; i < strlen(str); i++) {
350 		c = str[i];
351 		d = '\0';
352 
353 		switch (c) {
354 		case '\n':
355 			d = 'n';
356 			break;
357 		case '\t':
358 			d = 't';
359 			break;
360 		case '\b':
361 			d = 'b';
362 			break;
363 		case '\\':
364 			d = '\\';
365 			break;
366 		case '\"':
367 			d = '\"';
368 			break;
369 		case '=':
370 			d = '=';
371 			break;
372 		}
373 		if (d != '\0') {
374 			/* generate escaped char */
375 			tmp[j] = '\\'; j++;
376 			/* escape the =-sign double! */
377 			if (d == '=') {
378 				tmp[j] = '\\'; j++;
379 			}
380 			tmp[j] = d; j++;
381 		} else {
382 			tmp[j] = c; j++;
383 		}
384 	}
385 
386 	tmp[j] = '\0';
387 
388 	/* check if new string is not getting to long */
389 	if (strlen(tmp) < MAXLINE) {
390 		strcpy(str,tmp);
391 	} else {
392 		/* over MAXLINE chars - should never happen */
393 		/* cut off string */
394 		strncpy(str,tmp,MAXLINE-1);
395 		str[MAXLINE-1] = '\0';
396 	}
397 	return(str);
398 }
399 
400 
401 /* convert escape-chars in string -> e.g. newline to \n */
402 /* this versions will not escape quotes..required for master-path-lists */
403 
convert_escape2(gchar * str)404 gchar *convert_escape2(gchar *str) {
405 gchar tmp[MAXLINE*2];
406 gchar c,d;
407 guint i,j;
408 
409 	if (str == NULL) return (NULL);
410 
411 	j = 0;
412 	for (i = 0; i < strlen(str); i++) {
413 		c = str[i];
414 		d = '\0';
415 
416 		switch (c) {
417 		case '\n':
418 			d = 'n';
419 			break;
420 		case '\t':
421 			d = 't';
422 			break;
423 		case '\b':
424 			d = 'b';
425 			break;
426 		case '\\':
427 			d = '\\';
428 			break;
429 		case '=':
430 			d = '=';
431 			break;
432 		}
433 		if (d != '\0') {
434 			/* generate escaped char */
435 			tmp[j] = '\\'; j++;
436 			tmp[j] = d; j++;
437 		} else {
438 			tmp[j] = c; j++;
439 		}
440 	}
441 
442 	tmp[j] = '\0';
443 
444 	/* check if new string is not getting to long */
445 	if (strlen(tmp) < MAXLINE) {
446 		strcpy(str,tmp);
447 	} else {
448 		/* over MAXLINE chars - should never happen */
449 		/* cut off string */
450 		strncpy(str,tmp,MAXLINE-1);
451 		str[MAXLINE-1] = '\0';
452 	}
453 	return(str);
454 }
455 
456 
457 /* check if there are illegal chars in our string and replace them with _ */
458 /* return 0 if all ok, and 1 if any chars changed/removed */
459 
remove_illegal_chars(gchar * str)460 gint remove_illegal_chars(gchar *str) {
461 guint i,j;
462 
463 	if (str == NULL) return 0;
464 
465 	j = 0;
466 	for (i = 0; i < strlen(str); i++) {
467 		switch (str[i]) {
468 		case '/':
469 		case '\\':
470 		case '\b':
471 		case '\t':
472 			str[i] = '_';
473 			j = 1;
474 			break;
475 		}
476 	}
477 
478 	return(j);
479 }
480 
481 
482 /* get a string of the form "'xxx' from 'xxx'" and extract the strings xxx
483    to artist and title. remove any escape characters.
484    Return 0 if all ok, 1 on problems */
485 
decode_title_artist(gchar * str,gchar * title,gchar * artist)486 gint decode_title_artist(gchar *str, gchar *title, gchar *artist) {
487 gchar tmp[MAXLINE];
488 gchar tmp2[MAXLINE];
489 gchar c, oldc;
490 guint i;
491 
492 	if (str == NULL) {
493 		return 1;
494 	}
495 
496 	oldc = '\0';
497 
498 	/* check first char */
499 	if (str[0] != '\'') {
500 		/* not right - abort */
501 		return 1;
502 	}
503 	strcpy(tmp,str+1);
504 
505 	/* look for next unescaped quote */
506 	for (i = 0; i < strlen(tmp); i++) {
507 		c = tmp[i];
508 
509 		/* if current char ' and previous not \ we are done */
510 		if ((c == '\'') && (oldc != '\\')) {
511 			break;
512 		}
513 		oldc = c;
514 	}
515 
516 	if (i == strlen(tmp)) {
517 		/* no quote found at all */
518 		return 1;
519 	}
520 
521 	/* done extracting the title */
522 	strncpy(title,tmp,i);
523 	title[i] = '\0';
524 	/* now parse all other escaped chars */
525 	escape_parse(title);
526 
527 	/* now the artist-field */
528 	strcpy(tmp2, tmp+i);
529 	if (strncmp(tmp2,"' from '",8) != 0) {
530 		/* look for middle string */
531 		/* not fitting - abort */
532 		return 1;
533 	}
534 	strcpy(tmp,tmp2+8);
535 
536 	/* look for next unescaped quote */
537 	for (i = 0; i < strlen(tmp); i++) {
538 		c = tmp[i];
539 
540 		/* if current char ' and previous not \ we are done */
541 		if ((c == '\'') && (oldc != '\\')) {
542 			break;
543 		}
544 		oldc = c;
545 	}
546 
547 	if (i == strlen(tmp)) {
548 		/* no quote found at all */
549 		return 1;
550 	}
551 
552 	/* done extracting the artist */
553 	strncpy(artist,tmp,i);
554 	artist[i] = '\0';
555 	/* now parse all other escaped chars */
556 	escape_parse(artist);
557 
558 	return 0;
559 }
560 
561 
562 /* read a single char from a file descriptor. If the descriptor
563    says that it is not available, then try again up to 5 times,
564    before giving up.
565    Required for Mac OS 10.3
566 */
567 
read_char(gint fd,gchar * c)568 static gint read_char(gint fd, gchar *c) {
569 gint rc;
570 gint retries;
571 
572         retries = 5;
573 
574         while (retries) {
575                 rc = read(fd, c, 1);
576 
577                 /* all ok, read one char or EOF */
578                 if (rc != -1) {
579                         return rc;
580                 }
581 
582                 /* error code, try again after a little while */
583                 usleep(100);
584                 retries--;
585         }
586         return rc;
587 }
588 
589 /*
590  * Read a line from a descriptor.  Read the line one byte at a time,
591  * looking for the newline. Works fine in nonblocking mode..here
592  * we return when no more data can be read.
593  * We overwrite the newline with a null.
594  * We return the number of characters up to, but not including,
595  * the null (the same as strlen(3)).
596  */
597 
read_line(gint fd,gchar * ptr,gint maxlen)598 gint read_line(gint fd, gchar *ptr, gint maxlen) {
599 gint n, rc;
600 gchar c;
601 gchar *str;
602 
603 	str = ptr;
604 
605         for (n = 1; n < maxlen; n++) {
606                 if ( (rc = read_char(fd, &c)) == 1) {
607                         *ptr++ = c;
608                         if (c == '\n') {
609                                 break;
610                         }
611 
612                 } else if (rc == 0) {
613 			/* EOF */
614                         if (n == 1)
615                                 return(0);      /* EOF, no data read */
616                         else
617                                 break;          /* EOF, some data was read */
618                 } else if (rc == -2) {
619 			/* timeout while reading string */
620 			return(-2);
621 		} else {
622 			/* nonblocking mode an nothing to read? */
623 			if (rc == -1 && errno == EAGAIN) {
624 				if (n == 1)
625 					return(-1);
626 				else
627 					break;
628 			}
629                         return(-1);     /* error */
630 		}
631         }
632 
633 	/* terminate the string */
634 	*ptr = 0;
635 
636         /* strip of some trailing chars - yes..we need both levels */
637         ptr--;
638         if ((*ptr == '\n') || (*ptr == '\r') ) {
639                 *ptr = 0;
640         }
641         ptr--;
642         if ((*ptr == '\n') || (*ptr == '\r') ) {
643                 *ptr = 0;
644         }
645 
646 	if (strlen(str) == 0) {
647 		/* if we read an empty string, but are NOT on EOF return 1 */
648 		return 1;
649 	} else {
650         	return(strlen(str));
651 	}
652 }
653 
654 
655 /*
656  * Use this version to work around some of the critical races
657  * such as bz 127658. This issue should be solved on a case by case basis.
658  * Expected side effects: GUI freezes (e.g. if called from read_write_out() in io.c).
659  */
660 
read_line_wait(gint fd,gchar * ptr,gint maxlen)661 gint read_line_wait(gint fd, gchar *ptr, gint maxlen) {
662 gint n, rc;
663 gchar c;
664 gchar *str;
665 
666 	str = ptr;
667 
668         for (n = 1; n < maxlen; n++) {
669                 if ( (rc = read(fd, &c, 1)) == 1) {
670                         *ptr++ = c;
671                         if (c == '\n') {
672                                 break;
673                         }
674 
675                 } else if (rc == 0) {
676 			/* EOF */
677                         if (n == 1)
678                                 return(0);      /* EOF, no data read */
679                         else
680                                 break;          /* EOF, some data was read */
681                 } else if (rc == -2) {
682 			/* timeout while reading string */
683 			return(-2);
684 		} else {
685 			/* nonblocking mode an nothing to read? */
686 			if (rc == -1 && errno == EAGAIN) {
687 				if (n == 1)
688 					return(-1);
689 				else {
690 					/* Partial line read.  Wait a
691 					 * bit longer in case there's
692 					 * more.  This does not fix
693 					 * all the races in the
694 					 * parsing code, but works
695 					 * around them somewhat. */
696 					struct timeval t;
697 					fd_set set;
698 					FD_ZERO(&set);
699 					FD_SET(fd,&set);
700 					t.tv_sec = 1;
701 					t.tv_usec = 0;
702 					if (select (fd+1, &set, NULL,
703 						    NULL, &t) > 0)
704 						continue;
705 
706 					break;
707 				}
708 			}
709                         return(-1);     /* error */
710 		}
711         }
712 
713 	/* terminate the string */
714 	*ptr = 0;
715 
716         /* strip of some trailing chars - yes..we need both levels */
717         ptr--;
718         if ((*ptr == '\n') || (*ptr == '\r') ) {
719                 *ptr = 0;
720         }
721         ptr--;
722         if ((*ptr == '\n') || (*ptr == '\r') ) {
723                 *ptr = 0;
724         }
725 
726 	if (strlen(str) == 0) {
727 		/* if we read an empty string, but are NOT on EOF return 1 */
728 		return 1;
729 	} else {
730         	return(strlen(str));
731 	}
732 }
733 
734 
735 /* extract quotes-delimted string after first colon */
736 /* e.g.: 03: "bla" -> bla */
737 
extract_quoted(gchar * str)738 gint extract_quoted(gchar *str) {
739 gchar *p, *p2;
740 gchar tmp[MAXLINE];
741 gchar tmp2[MAXLINE];
742 
743 	strcpy(tmp,str);
744 
745 	/* get string after first colon */
746 	p = strtok(tmp,":");
747 	if (p == NULL)
748 		return 1;
749 	p = strtok(NULL,"");
750 	if (p == NULL)
751 		return 1;
752 
753 	strcpy(tmp,p);
754 	strip_string(tmp);
755 
756 	/* now strip quotes */
757 	p = tmp;
758 	if (*p == '\"') {
759 		p2 = p+1;
760 	} else {
761 		p2 = p;
762 	}
763 	if (p[strlen(p)-1] == '\"') {
764 		p[strlen(p)-1] = '\0';
765 	}
766 	strcpy(tmp2,p2);
767 	escape_parse(tmp2);
768 
769 	strcpy(str,tmp2);
770 
771 	return 0;
772 }
773 
774 
775 /* extract single quotes-delimted string */
776 /* e.g.: 'bla' -> bla */
777 
extract_singlequoted(gchar * str)778 gint extract_singlequoted(gchar *str) {
779 gchar *p, *p2;
780 gchar tmp[MAXLINE];
781 
782 	strcpy(tmp,str);
783 	strip_string(tmp);
784 
785 	/* now strip quotes */
786 	p = tmp;
787 	if (*p == '\'') {
788 		p2 = p+1;
789 	} else {
790 		p2 = p;
791 	}
792 	if (p[strlen(p)-1] == '\'') {
793 		p[strlen(p)-1] = '\0';
794 	}
795 	strcpy(str,p2);
796 
797 	return 0;
798 }
799 
800 
801 /* read one char from a file descriptor with timeout */
802 /* return 1 if char read ok, -1 on read error, -2 on timeout */
803 
get_char(gint fd,char * c)804 gint get_char(gint fd, char *c) {
805 gint j;
806 struct timeval t;
807 fd_set set;
808 
809 	FD_ZERO(&set);
810 	FD_SET(fd,&set);
811 	t.tv_sec = NETIOTIMEOUT;
812 	t.tv_usec = 0;
813 
814 	j = select(fd+1, &set, NULL, NULL, &t);
815 	if (j > 0) {
816 		return(read(fd, c, 1));
817 	} else {
818 		/* timeout triggered */
819 		return -2;
820 	}
821 }
822 
823 
824 /*
825  * Read a line from a descriptor.  Read the line one byte at a time,
826  * looking for the newline.
827  * We overwrite the newline with a null.
828  * We return the number of characters up to, but not including,
829  * the null (the same as strlen(3)).
830  */
831 
read_line2(gint fd,gchar * ptr,gint maxlen,gint timeout)832 gint read_line2(gint fd, gchar *ptr, gint maxlen, gint timeout) {
833 gint n, rc;
834 gchar c;
835 
836         for (n = 1; n < maxlen; n++) {
837 		if (timeout) {
838 			/* use timeout */
839 			rc = get_char(fd,&c);
840 		} else {
841 			rc = read(fd, &c, 1);
842 		}
843 		if ( rc == 1) {
844                         *ptr++ = c;
845                         if (c == '\n') {
846                                 break;
847                         }
848                 } else if (rc == 0) {
849                         if (n == 1)
850                                 return(0);      /* EOF, no data read */
851                         else
852                                 break;          /* EOF, some data was read */
853                 } else if (rc == -2) {
854 			/* timeout while reading string */
855 			return(-2);
856 		} else {
857                         return(-1);     /* error */
858 		}
859         }
860 
861         /* strip of some trailing chars - yes..we need all three levels*/
862         if ((*ptr == '\n') || (*ptr == '\r') ) {
863                 *ptr = 0;
864         }
865         ptr--;
866         if ((*ptr == '\n') || (*ptr == '\r') ) {
867                 *ptr = 0;
868         }
869         ptr--;
870         if ((*ptr == '\n') || (*ptr == '\r') ) {
871                 *ptr = 0;
872         }
873 
874         return(n);
875 }
876 
877 
878 /*
879  * Write "n" bytes to a descriptor.
880  * Use in place of write() when fd is a stream socket.
881  */
882 
writen(gint fd,gchar * ptr,gint nbytes,gint newline)883 gint writen(gint fd, gchar *ptr, gint nbytes, gint newline) {
884 gint nleft, nwritten;
885 
886         nleft = nbytes;
887         while (nleft > 0) {
888                 nwritten = write(fd, ptr, nleft);
889                 if (nwritten <= 0)
890                         return(nwritten);               /* error */
891 
892                 nleft -= nwritten;
893                 ptr   += nwritten;
894         }
895 
896         /* add a newline when requested */
897         if (newline) {
898                 write(fd,"\n",1);
899         }
900 
901         return(nbytes - nleft);
902 }
903 
904 
905 /* replace ~/ in an entry field by the home-directory */
906 /* warning - in some cases $HOME is not correct when user root */
907 
check_tilde(gchar * str)908 gchar *check_tilde(gchar *str) {
909 gchar tmp[MAXLINE];
910 
911 	if (str == NULL)
912 		return str;
913 
914 	strip_string(str);
915 
916 	/* to short, do nothing */
917 	if (strlen(str) < 2)
918 		return str;
919 
920 	/* ~/ found? */
921 	if (str[0] == '~' && str[1] == '/') {
922 		tmp[0] = '\0';
923 		if (!isroot()) {
924 			/* we are not root, trust $HOME */
925 			if (g_get_home_dir()) {
926 				strcpy(tmp, g_get_home_dir());
927 			}
928 		} else {
929 			/* as root $HOME is often wrong - override */
930 			if (get_pw_home(0)) {
931 				strcpy(tmp, get_pw_home(0));
932 			}
933 		}
934 		strcat(tmp,"/");
935 		strcat(tmp,str+2);
936 
937 		strcpy(str,tmp);
938 	}
939 
940 	return str;
941 }
942 
943 
944 /* parse config line and return id and value */
945 /* return 0 if ok, 1 on error */
946 
parse_config_line(gchar * iline,gchar * id,gchar * value)947 gint parse_config_line(gchar *iline, gchar *id, gchar *value) {
948 gchar *p,*p2;
949 gchar line[1024];
950 gchar tmp[1024];
951 
952 	strncpy(line,iline, MAXLINE);
953 	strcpy(id,"");
954         p = strtok(line,"=");
955         if (p != NULL) {
956 		/* got id */
957         	strcpy(id,p);
958                 strip_string(id);
959         } else {
960 		return 1;
961 	}
962 
963 	strcpy(tmp,"");
964         p = strtok(NULL,"");
965         if (p != NULL) {
966 		/* string after = */
967         	strcpy(tmp,p);
968                 strip_string(tmp);
969         } else {
970 		return 1;
971 	}
972 
973         /* now strip quotes from string */
974         p = tmp;
975         if (*p == '\"') {
976                 p2 = p+1;
977         } else {
978                 p2 = p;
979         }
980         if (p[strlen(p)-1] == '\"') {
981                 p[strlen(p)-1] = '\0';
982         }
983         strcpy(value,p2);
984 
985         /* now reconvert escape-chars */
986         escape_parse(value);
987 
988 	/* all ok */
989 	return 0;
990 }
991 
992 
993 /* parse config line and return id and value, value2 */
994 /* form is  ID = "val1","val2" */
995 /* return 0 if ok, 1 on error */
996 
parse_config_line2(gchar * iline,gchar * id,gchar * value,gchar * value2)997 gint parse_config_line2(gchar *iline, gchar *id, gchar *value, gchar *value2) {
998 gchar *p,*p2;
999 gchar line[1024];
1000 gchar tmp[1024];
1001 
1002 	strncpy(line,iline,MAXLINE);
1003 	strcpy(id,"");
1004 	strcpy(value,"");
1005 	strcpy(value2,"");
1006         p = strtok(line,"=");
1007         if (p != NULL) {
1008 		/* got id */
1009         	strcpy(id,p);
1010                 strip_string(id);
1011         } else {
1012 		return 1;
1013 	}
1014 
1015 	strcpy(tmp,"");
1016         p = strtok(NULL,"");
1017         if (p != NULL) {
1018 		/* string after = */
1019         	strcpy(tmp,p);
1020                 strip_string(tmp);
1021         } else {
1022 		return 1;
1023 	}
1024 
1025         /* now strip quotes from string */
1026         p = tmp;
1027         if (*p == '\"') {
1028                 p2 = p+1;
1029         } else {
1030                 p2 = p;
1031         }
1032         if (p[strlen(p)-1] == '\"') {
1033                 p[strlen(p)-1] = '\0';
1034         }
1035         strcpy(line,p2);
1036 
1037 	/* now in line is someling like xxx","yyy */
1038 	p = strstr(line,"\",\"");
1039 	if (p) {
1040 		*p = '\0';
1041 		strcpy(value,line);
1042 		strcpy(value2,p+3);
1043 	}
1044 
1045         /* now reconvert escape-chars */
1046         escape_parse(value);
1047         escape_parse(value2);
1048 
1049 	/* all ok */
1050 	return 0;
1051 }
1052 
1053 
1054 /* check if we are root */
1055 
isroot()1056 gint isroot() {
1057 
1058 	if (geteuid() == 0) {
1059 		return 1;
1060 	} else {
1061 		return 0;
1062 	}
1063 }
1064 
1065 
1066 /* check if user exists */
1067 
check_pw_user(gchar * name)1068 gint check_pw_user(gchar *name) {
1069 struct passwd *ent;
1070 
1071 	ent = getpwnam(name);
1072 	if (ent) return 1;
1073 	return 0;
1074 }
1075 
1076 
1077 /* return the homedir (as in /etc/passwd) for a given user */
1078 
get_pw_home(gint uid)1079 gchar *get_pw_home(gint uid) {
1080 struct passwd *ent;
1081 
1082 	ent = getpwuid(uid);
1083 
1084 	if (ent)
1085 		return ent->pw_dir;
1086 	else
1087 		return NULL;
1088 }
1089 
1090 
1091 /* return the owner (uid) of a given file */
1092 
get_file_owner(gchar * path)1093 gint get_file_owner(gchar *path) {
1094 struct stat buf;
1095 
1096 	if (stat(path,&buf) != 0) {
1097 		return -1;
1098 	}
1099 
1100 	return (buf.st_uid);
1101 }
1102 
1103 
1104 /* does move a text file */
1105 
move_textfile(gchar * src,gchar * target)1106 gint move_textfile(gchar *src, gchar *target) {
1107 FILE *fd, *fd2;
1108 gchar line[MAXLINE];
1109 
1110 	fd = fopen(src,"r");
1111 	if (!fd) {
1112 		/* src file failed to open */
1113 		return 1;
1114 	}
1115 
1116 	fd2 = fopen(target,"w");
1117 	if (!fd2) {
1118 		/* target file failed to open */
1119 		fclose(fd);
1120 		return 1;
1121 	}
1122 
1123 	/* copy file line by line */
1124 	for (;;) {
1125 		if (fgets(line,MAXLINE,fd) == NULL)
1126 			break;
1127 
1128 		fputs(line,fd2);
1129 	}
1130 
1131 	fclose(fd2);
1132 	fclose(fd);
1133 
1134 	/* now delete the src file */
1135 	unlink(src);
1136 
1137 	return 0;
1138 }
1139 
1140 
1141 /* checks if a given file is a link. If so return 1 */
1142 /* return the value of the link too, if requested */
1143 
check_islink(gchar * file,gchar * link)1144 gint check_islink(gchar *file, gchar *link) {
1145 struct stat buf;
1146 
1147 	if (lstat(file, &buf) == 0) {
1148 		if (S_ISLNK(buf.st_mode)) {
1149 			if (link) {
1150 				memset(link, 0, MAXLINE);
1151 				if (readlink(file, link, MAXLINE-1) <= 0) {
1152 					strcpy(link, "?");
1153 				}
1154 			}
1155 			return 1;
1156 		}
1157 	}
1158 
1159 	return 0;
1160 }
1161 
1162 
1163 /* extract a readable string from a buffer */
1164 
get_subheader(gchar * buf,gchar * text,gint start,gint end)1165 void get_subheader(gchar *buf, gchar *text, gint start, gint end) {
1166 gchar tmp[MAXLINE];
1167 gchar c;
1168 gint i,count;
1169 
1170         count = 0;
1171         for(i = start; i < end; i++) {
1172                 c = buf[i];
1173                 if (isprint((gint)c) || isspace((gint)c)) {
1174                         tmp[count++] = c;
1175                 }
1176         }
1177         tmp[count] = '\0';
1178 
1179         for(i = strlen(tmp)-1; i >= 0; i--) {
1180                 if(tmp[i] != 0 && tmp[i] != ' ') {
1181                         tmp[i+1] = '\0';
1182                         break;
1183                 }
1184         }
1185 
1186 	strip_string(tmp);
1187         strcpy(text, tmp);
1188 }
1189 
1190 
1191 /* URL decoding - used because drag&drop names are often URL encoded */
1192 /* borrowed from php4 source code (php4/ext/standard/url.c) */
1193 
url_htoi(gchar * s)1194 static gint url_htoi(gchar *s) {
1195 gint value;
1196 gint c;
1197 
1198         c = s[0];
1199         if (isupper(c))
1200                 c = tolower(c);
1201         value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
1202 
1203         c = s[1];
1204         if (isupper(c))
1205                 c = tolower(c);
1206         value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
1207 
1208         return (value);
1209 }
1210 
1211 
url_decode(gchar * str,gint len)1212 gchar *url_decode(gchar *str, gint len) {
1213 gchar *dest = str;
1214 gchar *data = str;
1215 
1216 	while (len--) {
1217                 if (*data == '+')
1218 			*dest = ' ';
1219 		else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) && isxdigit((int) *(data + 2))) {
1220                         *dest = (gchar) url_htoi(data + 1);
1221                         data += 2;
1222                         len -= 2;
1223                 } else
1224                         *dest = *data;
1225                 data++;
1226                 dest++;
1227 	}
1228         *dest = '\0';
1229         return dest;
1230 }
1231 
1232 
1233 /* URL encoding - used because drag&drop names are often URL encoded */
1234 /* borrowed from php4 source code (php4/ext/standard/url.c) */
1235 
1236 static unsigned char hexchars[] = "0123456789ABCDEF";
1237 
1238 /* encode all special chars, but not / - and . */
1239 
url_encode(gchar * s,gint len,gint * new_length)1240 gchar *url_encode(gchar *s, gint len, gint *new_length) {
1241 gint x, y;
1242 guchar *str;
1243 
1244 	str = (guchar *) g_new0(guchar *, 3 * len + 1);
1245         for (x = 0, y = 0; len--; x++, y++) {
1246                 str[y] = (guchar) s[x];
1247                 if (str[y] == ' ') {
1248                         str[y] = '+';
1249                 } else if ((str[y] < '0' && str[y] != '-' && str[y] != '.' && str[y] != '/') ||
1250                                    (str[y] < 'A' && str[y] > '9') ||
1251                                    (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
1252                                    (str[y] > 'z')) {
1253                         str[y++] = '%';
1254                         str[y++] = hexchars[(guchar) s[x] >> 4];
1255                         str[y] = hexchars[(guchar) s[x] & 15];
1256                 }
1257         }
1258         str[y] = '\0';
1259         if (new_length) {
1260                 *new_length = y;
1261         }
1262         return ((gchar *) str);
1263 }
1264 
1265 
1266 /* extract the first filename from a set of data received from a drag
1267    operation - return 1 on success */
1268 
extract_single_drag_filename(gchar * dragtext,gint draglen,gchar * rettext)1269 gint extract_single_drag_filename(gchar *dragtext, gint draglen, gchar *rettext) {
1270 gchar *p;
1271 gchar tmp[MAXLINE];
1272 gint len;
1273 
1274 	/* if we got serveral filenames only use the first */
1275 	if (dragtext) {
1276 		p = index(dragtext,'\r');
1277 		if (p) {
1278 			len = p - dragtext;
1279 			if (len < MAXLINE) {
1280 				strncpy(tmp,dragtext,len);
1281 				tmp[len] = '\0';
1282 			} else {
1283 				return 0;
1284 			}
1285 		} else {
1286 			strncpy(tmp,dragtext, MAXLINE);
1287 		}
1288 
1289 		/* extracted a single item */
1290 		strip_string(tmp);
1291 
1292 
1293 		/* does it begin with file:? */
1294 		if (strncmp(tmp,"file:", 5) == 0) {
1295 			/* two slashes at front? */
1296 			if (strlen(tmp) > 7 && tmp[5] == '/' && tmp[6] == '/') {
1297 				/* three slashes? */
1298 				if (strlen(tmp) > 8 && tmp[7] == '/') {
1299 					strncpy(rettext,tmp+7, MAXLINE);
1300 					/* url_decode only this case */
1301 					url_decode(rettext, strlen(rettext));
1302 				} else {
1303 					strncpy(rettext,tmp+6, MAXLINE);
1304 				}
1305 			} else {
1306 				strncpy(rettext,tmp+5, MAXLINE);
1307 			}
1308 			return 1;
1309 		}
1310 	}
1311 
1312 	return 0;
1313 }
1314 
1315 
1316 /* extract the a list of filename from a set of data received from a drag
1317    operation - return 1 on success */
1318 
extract_glist_drag_filenames(gchar * dragtext,gint draglen,gchar * match,GList ** dst)1319 gint extract_glist_drag_filenames(gchar *dragtext, gint draglen, gchar *match, GList **dst) {
1320 gchar *p, *buf;
1321 gchar tmp[MAXLINE], tmp2[MAXLINE];
1322 gint count;
1323 
1324 	count = 0;
1325 
1326 	/* if we got serveral filenames only use the first */
1327 	if (dragtext) {
1328 		/* allocate a tmp buffer for the drag data */
1329 		buf = g_strdup(dragtext);
1330 
1331 		p = strtok(buf,"\r\n");
1332 		while (p) {
1333 			strncpy(tmp, p, MAXLINE);
1334 			strip_string(tmp);
1335 
1336 			/* does it begin with file:? */
1337 			if (strncmp(tmp,match, 5) == 0) {
1338 				/* two slashes at front? */
1339 				if (strlen(tmp) > 7 && tmp[5] == '/' && tmp[6] == '/') {
1340 					/* three slashes? */
1341 					if (strlen(tmp) > 8 && tmp[7] == '/') {
1342 						strncpy(tmp2,tmp+7, MAXLINE);
1343 						/* url decode this case */
1344 						url_decode(tmp2, strlen(tmp2));
1345 					} else {
1346 						strncpy(tmp2,tmp+6, MAXLINE);
1347 					}
1348 				} else {
1349 					strncpy(tmp2,tmp+5, MAXLINE);
1350 				}
1351 				*dst = g_list_append(*dst, g_strdup(tmp2));					count++;
1352 			}
1353 			p = strtok(NULL,"\r\n");
1354 		}
1355 		g_free(buf);
1356 	}
1357 
1358 	if (count > 0) {
1359 		return 1;
1360 	} else {
1361 		return 0;
1362 	}
1363 }
1364 
1365 
1366 /* return 1 when invalid MCN number */
1367 /* code from cdrtools  auinfo.c */
1368 
verify_mcn(gchar * mcn)1369 gint verify_mcn(gchar *mcn) {
1370 gchar *p;
1371 
1372 	/* wrong length? */
1373 	if (strlen(mcn) != 13) {
1374 		return 1;
1375 	}
1376 
1377 	for (p = mcn; *p; p++) {
1378 		/* illegal chars in string? */
1379 		if (*p < '0' || *p > '9') {
1380 			return 1;
1381 		}
1382 	}
1383 	return 0;
1384 }
1385 
1386 
1387 /* return 1 when invalid ISRC number */
1388 /* code from cdrtools  auinfo.c */
1389 
verify_isrc(gchar * isrc)1390 gint verify_isrc(gchar *isrc) {
1391 gchar upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1392 gchar ibuf[13];
1393 gchar *ip, *p;
1394 gint i, len;
1395 
1396 	if ((len = strlen(isrc)) != 12) {
1397 		for (p = isrc, i = 0; *p; p++) {
1398 			if (*p == '-')
1399 				i++;
1400 		}
1401 		if (((len - i) != 12) || i > 3) {
1402 			/* illegal length */
1403 			return 1;
1404 		}
1405 	}
1406 
1407 	/* check country code */
1408         for (p = isrc, ip = ibuf, i = 0; i < 2; p++, i++) {
1409                 *ip++ = *p;
1410                 if (!strchr(upper, *p)) {
1411 			/* allow numbers even when not expected */
1412                         if (*p >= '0' && *p <= '9')
1413                                 continue;
1414 			return 1;
1415                 }
1416         }
1417         if (*p == '-')
1418                 p++;
1419 
1420         /* owner code */
1421         for (i = 0; i < 3; p++, i++) {
1422                 *ip++ = *p;
1423                 if (strchr(upper, *p))
1424                         continue;
1425                 if (*p >= '0' && *p <= '9')
1426                         continue;
1427 		return 1;
1428         }
1429         if (*p == '-')
1430                 p++;
1431 
1432 	/* year and recording number */
1433         for (i = 0; i < 7; p++, i++) {
1434                 *ip++ = *p;
1435                 if (*p >= '0' && *p <= '9')
1436                         continue;
1437                 if (*p == '-' && i == 2) {
1438                         ip--;
1439                         i--;
1440                         continue;
1441                 }
1442 		return 1;
1443         }
1444 
1445 	return 0;
1446 }
1447 
1448 
1449 /* remove one path level from a given path */
1450 /* if we are already at root level return emtpy string */
1451 
get_reducedpath(gchar * dir,gchar * out)1452 gchar *get_reducedpath(gchar *dir, gchar *out) {
1453 gchar *p;
1454 gchar tmp[MAXLINE];
1455 
1456 	/* trailing slash? remove it first */
1457 	strncpy(tmp, dir, MAXLINE);
1458 	if (tmp[strlen(tmp)-1] == '/') {
1459 		tmp[strlen(tmp)-1] = '\0';
1460 	}
1461 
1462 	/* look for last slash */
1463 	p = rindex(tmp,'/');
1464 	if (p) {
1465 		/* cut it  */
1466 		*p = '\0';
1467 	}
1468 	strncpy(out, tmp, MAXLINE);
1469 
1470 	return out;
1471 }
1472 
1473