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