1 /***************************************************************************/
2 /* This code is part of WWW grabber called pavuk */
3 /* Copyright (c) 1997 - 2001 Stefan Ondrejicka */
4 /* Distributed under GPL 2 or later */
5 /***************************************************************************/
6
7 #include "config.h"
8
9 #include <sys/time.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13 #ifdef HAVE_FLOCK
14 #include <sys/file.h>
15 #endif
16 #include <unistd.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <netdb.h>
22 #include <fcntl.h>
23 #include <limits.h>
24 #include <time.h>
25 #include <utime.h>
26 #include <dirent.h>
27 #include <signal.h>
28
29 #ifdef HAVE_TERMIOS
30 #include <termios.h>
31 #endif
32
33 #ifdef HAVE_FNMATCH
34 #include <fnmatch.h>
35 #else
36 #include "fnmatch.h"
37 #endif
38
39 #ifdef __CYGWIN__
40 #include <sys/cygwin.h>
41 #endif
42
43 #ifdef GTK_FACE
44 #include <glib.h>
45 #endif
46
47 #include "gui_api.h"
48 #include "url.h"
49 #include "doc.h"
50 #include "ftp.h"
51 #include "dinfo.h"
52 #include "log.h"
53
strip_nl(char * str)54 void strip_nl(char *str)
55 {
56 char *p;
57
58 p = strchr(str, '\n');
59 if(p)
60 *p = '\0';
61 p = strchr(str, '\r');
62 if(p)
63 *p = '\0';
64 }
65
omit_chars(char * str,char * chars)66 void omit_chars(char *str, char *chars)
67 {
68 int src, dst;
69
70 for(src = 0, dst = 0; str[src]; src++)
71 {
72 if(strchr(chars, str[src]))
73 continue;
74 str[dst] = str[src];
75 dst++;
76 }
77 str[dst] = '\0';
78 }
79
80 #ifndef HAVE_SETENV
tl_setenv(const char * var,const char * val,int ovr)81 int tl_setenv(const char *var, const char *val, int ovr)
82 {
83 char *pom = _malloc(strlen(var) + strlen(val) + 2);
84
85 sprintf(pom, "%s=%s", var, val);
86 return putenv(pom);
87 }
88 #endif
89
90 #ifndef HAVE_INET6
xstrherror(int enr)91 static char *xstrherror(int enr)
92 {
93 char *p;
94
95 switch (enr)
96 {
97 #ifdef NETDB_INTERNAL
98 case NETDB_INTERNAL:
99 p = strerror(errno);
100 break;
101 #endif
102 #ifdef NETDB_SUCCESS
103 case NETDB_SUCCESS:
104 p = gettext("no error");
105 break;
106 #endif
107 #ifdef HOST_NOT_FOUND
108 case HOST_NOT_FOUND:
109 p = gettext("host not found");
110 break;
111 #endif
112 #ifdef TRY_AGAIN
113 case TRY_AGAIN:
114 p = gettext("temporary error (try again later)");
115 break;
116 #endif
117 #ifdef NO_RECOVERY
118 case NO_RECOVERY:
119 p = gettext("non recoverable error");
120 break;
121 #endif
122 #ifdef NO_ADDRESS
123 case NO_ADDRESS:
124 p = gettext("name is valid, but doesn't have an IP address");
125 break;
126 #endif
127 default:
128 p = gettext("unknown hostname translation error");
129 }
130 return p;
131 }
132 #endif
133
xherror(const char * str)134 void xherror(const char *str)
135 {
136 #ifdef HAVE_INET6
137 xprintf(1, "%s: %s\n", str, gai_strerror(_h_errno_));
138 #else
139 xprintf(1, "%s: %s\n", str, xstrherror(_h_errno_));
140 #endif
141 }
142
xperror(const char * str)143 void xperror(const char *str)
144 {
145 xprintf(1, "%s: %s\n", str, strerror(errno));
146 }
147
148 #ifdef HAVE_MT
st_xvaprintf(int log,const char * strs,va_list * args)149 static void st_xvaprintf(int log, const char *strs, va_list * args)
150 #else
151 void xvaprintf(int log, const char *strs, va_list * args)
152 #endif
153 {
154 #ifdef GTK_FACE
155 char *buf = g_strdup_vprintf(strs, *args);
156 #else
157 char buf[4096];
158 #ifdef HAVE_VSNPRINTF
159 int l = vsnprintf(buf, sizeof(buf), strs, *args);
160 if(TL_BETWEEN(l, 0, sizeof(buf) - 1))
161 buf[l] = '\0';
162 #else
163 vsprintf(buf, strs, *args);
164 #endif
165 #endif
166
167 if(log && cfg.logfile)
168 log_str(buf);
169
170 #ifdef I_FACE
171 if(cfg.xi_face && cfg.done && !cfg.quiet)
172 {
173 gui_xprint(buf);
174 }
175 else
176 #endif
177 {
178 if(!cfg.quiet && !cfg.bgmode)
179 {
180 bool_t wout = TRUE;
181 #ifdef HAVE_TERMIOS
182 if(cfg.tccheck)
183 {
184 static int _istty = -1;
185 static pid_t _pgrp;
186
187 if(_istty == -1)
188 {
189 _istty = isatty(1);
190 #ifdef GETPGRP_NEED_PID
191 _pgrp = getpgrp(getpid());
192 #else
193 _pgrp = getpgrp();
194 #endif
195 }
196
197 if(_istty && tcgetpgrp(1) != _pgrp)
198 wout = FALSE;
199 }
200 #endif
201 if(wout)
202 {
203 fwrite(buf, sizeof(char), strlen(buf), stdout);
204 fflush(stdout);
205 }
206 }
207 }
208 #ifdef GTK_FACE
209 g_free(buf);
210 #endif
211 }
212
213 #ifdef HAVE_MT
xvaprintf(int log,const char * strs,va_list * args)214 void xvaprintf(int log, const char *strs, va_list * args)
215 {
216 doc *cdoc;
217
218 cdoc = (doc *) pthread_getspecific(cfg.currdoc_key);
219
220 if(!cdoc || (cfg.nthr == 1) || cfg.immessages)
221 st_xvaprintf(log, strs, args);
222 else if(cdoc)
223 {
224 doc_msg *dm = _malloc(sizeof(doc_msg));
225 char buf[4096];
226
227 buf[0] = '\0';
228 vsprintf(buf, strs, *args);
229
230 dm->log = log;
231 dm->msg = tl_strdup(buf);
232
233 cdoc->msgbuf = dllist_append(cdoc->msgbuf, dm);
234 }
235 else
236 st_xvaprintf(log, strs, args);
237 }
238 #endif
239
xprintf(int log,const char * strs,...)240 void xprintf(int log, const char *strs, ...)
241 {
242 va_list args;
243
244 va_start(args, strs);
245 xvaprintf(log, strs, &args);
246 va_end(args);
247 }
248
xdebug(int level,const char * strs,...)249 void xdebug(int level, const char *strs, ...)
250 {
251 #ifdef HAVE_MT
252 static pthread_mutex_t unique_lock = PTHREAD_MUTEX_INITIALIZER;
253 static volatile int unique = 0;
254 #endif
255 #ifdef DEBUG
256 if(cfg.debug && (level & cfg.debug_level))
257 {
258 va_list args;
259 va_start(args, strs);
260 #ifdef HAVE_MT
261 pthread_mutex_lock(&unique_lock);
262 printf("%4d ", unique++);
263 st_xvaprintf(1, strs, &args);
264 pthread_mutex_unlock(&unique_lock);
265 #else
266 xvaprintf(1, strs, &args);
267 #endif
268 va_end(args);
269 }
270 #endif /* DEBUG */
271 }
272
xvadebug(int level,const char * strs,va_list * args)273 void xvadebug(int level, const char *strs, va_list * args)
274 {
275 #ifdef DEBUG
276 if(cfg.debug && (level & cfg.debug_level))
277 {
278 xvaprintf(1, strs, args);
279 }
280 #endif
281 }
282
hash_func(const char * str,int num)283 unsigned int hash_func(const char *str, int num)
284 {
285 const char *p = str;
286 unsigned int rv = 0;
287
288 while(*p)
289 {
290 rv = (rv + (unsigned char) *p) % num;
291 p++;
292 }
293 rv = rv % num;
294 return rv;
295 }
296
report_unsup_locking(void)297 static void report_unsup_locking(void)
298 {
299 static int visited = FALSE;
300 if(!visited)
301 {
302 visited = TRUE;
303 xprintf(1,
304 "------------------------------------------------------------------------------\n");
305 xprintf(1,
306 gettext
307 ("Warning: locking not supported ... don't run multiple processes or threads!\n"));
308 xprintf(1,
309 "------------------------------------------------------------------------------\n");
310 }
311 }
312
tl_flock(int * fd,const char * filename,int opt,int b_lock)313 int tl_flock(int *fd, const char *filename, int opt, int b_lock)
314 {
315 int i = 0;
316
317 /* currently it seemds to me that BeOS */
318 /* doesn't support file locking :-( */
319 /* so just without real locking, report */
320 /* successfully acquired lock */
321 #ifdef __BEOS__
322 report_unsup_locking();
323 return 0;
324 #endif
325
326 DEBUG_LOCKS("Locking file - %s\n", filename);
327 if(b_lock)
328 {
329 bool_t ready = FALSE;
330 while(!ready)
331 {
332 #ifdef HAVE_FLOCK
333 if(flock(*fd, LOCK_EX | LOCK_NB))
334 {
335 if(errno == EWOULDBLOCK)
336 {
337 xprintf(1, gettext("waiting to release lock on FD : %d\n"), *fd);
338 i = flock(*fd, LOCK_EX);
339 }
340 else if(errno == ENOSYS ||
341 #ifdef ENOTSUP
342 errno == ENOTSUP ||
343 #endif
344 errno == EOPNOTSUPP)
345 {
346 report_unsup_locking();
347 break;
348 }
349 else
350 perror(filename);
351 }
352 else
353 {
354 i = 0;
355 }
356 #else
357 #ifdef HAVE_FCNTL_LOCK
358 struct flock fl;
359
360 memset(&fl, '\0', sizeof(fl));
361 fl.l_type = F_WRLCK;
362 if(fcntl(*fd, F_SETLK, &fl))
363 {
364 if(errno == EWOULDBLOCK)
365 {
366 xprintf(1, gettext("waiting to release lock on FD : %d\n"), *fd);
367 memset(&fl, '\0', sizeof(fl));
368 fl.l_type = F_WRLCK;
369 i = fcntl(*fd, F_SETLKW, &fl);
370 }
371 else if(errno == ENOSYS ||
372 #ifdef ENOTSUP
373 errno == ENOTSUP ||
374 #endif
375 errno == EOPNOTSUPP)
376 {
377 report_unsup_locking();
378 break;
379 }
380 else
381 perror(filename);
382 }
383 else
384 {
385 i = 0;
386 }
387 #endif
388 #endif
389 if(access(filename, F_OK))
390 {
391 DEBUG_LOCKS("Lock file was removed - creating new one.\n");
392 close(*fd);
393 if(!makealldirs(filename))
394 {
395 *fd = open(filename, opt, 0644);
396 if(*fd < 0)
397 {
398 i = -1;
399 ready = TRUE;
400 }
401 }
402 else
403 {
404 i = -1;
405 ready = TRUE;
406 }
407 }
408 else
409 ready = TRUE;
410 }
411
412 }
413 else
414 {
415 #ifdef HAVE_FLOCK
416 i = flock(*fd, LOCK_EX | LOCK_NB);
417 #else
418 #ifdef HAVE_FCNTL_LOCK
419 struct flock fl;
420
421 memset(&fl, '\0', sizeof(fl));
422 fl.l_type = F_WRLCK;
423 i = fcntl(*fd, b_lock ? F_SETLKW : F_SETLK, &fl);
424 #endif
425 #endif
426 if(i < 0 && (errno == ENOSYS ||
427 #ifdef ENOTSUP
428 errno == ENOTSUP ||
429 #endif
430 errno == EOPNOTSUPP))
431 {
432 report_unsup_locking();
433 i = 0;
434 }
435 else if(i < 0)
436 perror(filename);
437 }
438
439 return i;
440 }
441
442 #ifdef HAVE_FCNTL_LOCK
tl_funlock(int fd)443 int tl_funlock(int fd)
444 {
445 struct flock fl;
446 int i;
447
448 memset(&fl, '\0', sizeof(fl));
449 fl.l_type = F_UNLCK;
450 i = fcntl(fd, F_SETLK, &fl);
451
452 return i;
453 }
454 #endif
455
tl_mkstemp(char * pattern)456 int tl_mkstemp(char *pattern)
457 {
458 #ifdef HAVE_MKSTEMP
459 return mkstemp(pattern);
460 #else
461 tmpnam(pattern);
462
463 return open(pattern, O_CREAT | O_RDWR | O_TRUNC | O_EXCL | O_BINARY, 0600);
464 #endif
465 }
466
_atoi(char * str)467 long int _atoi(char *str)
468 {
469 char *__eptr__;
470 long int rv;
471
472 if(!*str)
473 {
474 errno = ERANGE;
475 rv = 0;
476 }
477 else
478 {
479 errno = 0;
480 rv = strtol(str, (char **) &__eptr__, 10);
481 if(*__eptr__ != '\0')
482 errno = ERANGE;
483 else
484 errno = 0;
485 }
486
487 return rv;
488 }
489
_atof(char * str)490 double _atof(char *str)
491 {
492 char *__eptr__;
493 double rv;
494
495 if(!*str)
496 {
497 errno = ERANGE;
498 rv = 0.0;
499 }
500 else
501 {
502 errno = 0;
503 rv = strtod(str, (char **) &__eptr__);
504 if(*__eptr__ != '\0')
505 errno = ERANGE;
506 else
507 errno = 0;
508 }
509
510 return rv;
511 }
512
513
_strtrchr(char * str,int cfrom,int cto)514 char *_strtrchr(char *str, int cfrom, int cto)
515 {
516 char *p = str;
517
518 while((p = strchr(p, cfrom)))
519 *p = cto;
520
521 return str;
522 }
523
_malloc(int sz)524 void *_malloc(int sz)
525 {
526 void *ret = malloc(sz);
527 if(!ret)
528 {
529 perror("malloc");
530 }
531 return ret;
532 }
533
_realloc(void * from,int sz)534 void *_realloc(void *from, int sz)
535 {
536 void *ret = from ? realloc(from, sz) : malloc(sz);
537 if(!ret)
538 {
539 perror("realloc");
540 }
541 return ret;
542 }
543
get_1qstr(const char * str)544 char *get_1qstr(const char *str)
545 {
546 static const char *p = 0;
547 static char pom[4096];
548 const char *pom1 = NULL, *pom2 = NULL;
549 int found;
550 bool_t wasesc = FALSE;
551
552 if(str)
553 p = str;
554
555 for(; p && *p && (!pom1 || !pom2); p++)
556 {
557 found = FALSE;
558
559 if(!wasesc && *p == '\"')
560 found = TRUE;
561
562 if(!wasesc && *p == '\\')
563 wasesc = TRUE;
564 else
565 wasesc = FALSE;
566
567 if(!pom1 && found)
568 pom1 = p + 1;
569 else if(!pom2 && found)
570 pom2 = p;
571 }
572 if(pom1 && pom2)
573 {
574 char *p2;
575 p2 = pom;
576 while(pom1 < pom2)
577 {
578 if(*pom1 == '\\')
579 {
580 pom1++;
581 *p2 = *pom1;
582 }
583 else
584 {
585 *p2 = *pom1;
586 }
587 p2++;
588 pom1++;
589 }
590 *p2 = '\0';
591 return pom;
592 }
593 else
594 {
595 p = NULL;
596 return NULL;
597 }
598 }
599
escape_str(char * str,char * unsafe)600 char *escape_str(char *str, char *unsafe)
601 {
602 char sbuf[4096];
603 char *p, *r;
604
605 for(p = str, r = sbuf; *p; p++)
606 {
607 if(strchr(unsafe, *p))
608 {
609 *r = '\\';
610 r++;
611 *r = *p;
612 r++;
613 }
614 else
615 {
616 *r = *p;
617 r++;
618 }
619 }
620 *r = '\0';
621 return tl_strdup(sbuf);
622 }
623
624 /**************************************************************/
625 /* implementation of standard function strtok */
626 /* split string at occurence of <chr> by setting \0-character */
627 /* store next element (one behind \0) pointer for next call */
628 /* calling with str equal to zero uses stored pointer */
629 /**************************************************************/
strtokc_r(char * str,int chr,char ** save)630 char *strtokc_r(char *str, int chr, char **save)
631 {
632 char *ret;
633
634 if(str)
635 *save = str;
636
637 if((ret = *save))
638 {
639 char *pom;
640
641 if((pom = strchr(*save, chr)))
642 {
643 *pom = '\0';
644 *save = pom + 1;
645 }
646 else
647 *save = NULL;
648 }
649
650 return ret;
651 }
652
653 /**************************************/
654 /* najdi poziciu n-teho vyskytu znaku */
655 /* FIXME: Translate me! */
656 /**************************************/
strfindnchr(char * str,int chr,int n)657 char *strfindnchr(char *str, int chr, int n)
658 {
659 int cnt;
660 char *p;
661
662 for(p = str, cnt = 0; *p && cnt < n; p++)
663 {
664 if(*p == chr)
665 cnt++;
666 }
667 if(cnt != n)
668 return NULL;
669 else
670 return p;
671 }
672
673 /********************************************/
674 /* search in list for string occurrence */
675 /********************************************/
is_in_list(char * str,char ** list)676 bool_t is_in_list(char *str, char **list)
677 {
678 char **p = list;
679
680 while(*p)
681 {
682 if(!strcasecmp(*p, str))
683 return TRUE;
684 p++;
685 }
686 return FALSE;
687 }
688
is_in_dllist(char * str,dllist * list)689 bool_t is_in_dllist(char *str, dllist * list)
690 {
691 dllist *p;
692
693 for(p = list; p; p = p->next)
694 {
695 if(!strcasecmp((char *) p->data, str))
696 return TRUE;
697 }
698 return FALSE;
699 }
700
701 /****************************************************/
702 /* match string again list of wildcard patterns */
703 /****************************************************/
is_in_pattern_list(char * str,char ** list)704 bool_t is_in_pattern_list(char *str, char **list)
705 {
706 char **p = list;
707
708 while(*p)
709 {
710 if(!fnmatch(*p, str, 0))
711 return TRUE;
712 p++;
713 }
714 return FALSE;
715 }
716
is_in_pattern_dllist(char * str,dllist * list)717 bool_t is_in_pattern_dllist(char *str, dllist * list)
718 {
719 dllist *p;
720
721 for(p = list; p; p = p->next)
722 {
723 if(!fnmatch((char *) p->data, str, 0))
724 return TRUE;
725 }
726 return FALSE;
727 }
728
729 /*******************************************************/
730 /* split string to NULL terminated array of strings */
731 /* separated with some of characters in sep */
732 /*******************************************************/
tl_str_split(const char * liststr,const char * sep)733 char **tl_str_split(const char *liststr, const char *sep)
734 {
735 const char *p;
736 int i = 0;
737 char **ret_val = NULL;
738 int ilen;
739
740 if(!liststr || !*liststr)
741 return NULL;
742
743 ret_val = _malloc(sizeof(char **));
744 ret_val[0] = NULL;
745
746 p = liststr;
747
748 while(*p)
749 {
750 ilen = strcspn(p, sep);
751 ret_val = _realloc(ret_val, sizeof(char **) * (i + 2));
752 ret_val[i] = tl_strndup(p, ilen);
753 ret_val[i + 1] = NULL;
754 p += ilen;
755 if(*p)
756 p++;
757 i++;
758 }
759
760 return ret_val;
761 }
762
tl_numlist_split(char * str,char * sep)763 dllist *tl_numlist_split(char *str, char *sep)
764 {
765 dllist *rv = NULL;
766 char **v;
767 int i;
768
769 v = tl_str_split(str, sep);
770
771 for(i = 0; v && v[i]; i++)
772 {
773 long n = _atoi(v[i]);
774 if(errno == ERANGE)
775 {
776 while(rv)
777 rv = dllist_remove_entry(rv, rv);
778 break;
779 }
780
781 rv = dllist_append(rv, (dllist_t) n);
782 }
783
784 tl_strv_free(v);
785
786 return rv;
787 }
788
789 /* free null terminated string vector */
tl_strv_free(char ** v)790 void tl_strv_free(char **v)
791 {
792 int i;
793
794 for(i = 0; v && v[i]; i++)
795 _free(v[i]);
796
797 _free(v);
798 }
799
800 /* count length of null terminated string vector */
tl_strv_length(char ** v)801 int tl_strv_length(char **v)
802 {
803 int i;
804
805 for(i = 0; v && v[i]; i++);
806
807 return i;
808 }
809
tl_strv_find(char ** v,char * s)810 int tl_strv_find(char **v, char *s)
811 {
812 int i;
813 for(i = 0; v && v[i]; i++)
814 {
815 if(!strcmp(v[i], s))
816 return i;
817 }
818 return -1;
819 }
820
sort_strcmp(const char ** s1,const char ** s2)821 static int sort_strcmp(const char **s1, const char **s2)
822 {
823 return strcmp(*s1, *s2);
824 }
825
tl_strv_sort(char ** v)826 void tl_strv_sort(char **v)
827 {
828 if(v)
829 {
830 qsort((void *) v, tl_strv_length(v), sizeof(char *),
831 (int (*)(const void *, const void *)) sort_strcmp);
832 }
833 }
834
835 /*************************************************/
836 /* change all characters in string to upper case */
837 /*************************************************/
upperstr(char * s)838 char *upperstr(char *s)
839 {
840 char *p;
841
842 for(p = s; *p != '\0'; p++)
843 *p = tl_ascii_toupper(*p);
844
845 return s;
846 }
847
848 /*************************************************/
849 /* change all characters in string to lower case */
850 /*************************************************/
lowerstr(char * s)851 char *lowerstr(char *s)
852 {
853 char *p;
854
855 for(p = s; *p != '\0'; p++)
856 *p = tl_ascii_tolower(*p);
857
858 return s;
859 }
860
861 /**********************/
862 /* duplicate string */
863 /**********************/
tl_strdup(const char * s)864 char *tl_strdup(const char *s)
865 {
866 char *p;
867
868 if(s)
869 {
870 p = (char *) _malloc(strlen(s) + 1);
871 strcpy(p, s);
872 }
873 else
874 p = NULL;
875
876 return p;
877 }
878
879 /****************************************/
880 /* duplicate n characters from string */
881 /****************************************/
tl_strndup(const char * s,int n)882 char *tl_strndup(const char *s, int n)
883 {
884 char *p;
885
886 if(!s)
887 return NULL;
888
889 p = (char *) _malloc(n + 1);
890 if(n)
891 strncpy(p, s, n);
892 *(p + n) = '\0';
893 return p;
894 }
895
896 /***************************************************/
897 /* create all directories in path specification */
898 /***************************************************/
makealldirs(const char * path)899 int makealldirs(const char *path)
900 {
901 char pom[PATH_MAX];
902 const char *p;
903
904 pom[0] = '\0';
905
906 if(path)
907 {
908 p = path;
909 #ifdef __CYGWIN__
910 /* we can't create new drive on WIN32, so the drive */
911 /* specification part of path must be skipped */
912 #ifdef HAVE_NEWSTYLE_CYGWIN
913 if(p[0] == '/' && p[1] == '/')
914 {
915 char *sp;
916
917 if((sp = strchr(p + 2, '/')) && (sp = strchr(sp + 1, '/')))
918 {
919 strncpy(pom, p, sp - p);
920 pom[sp - p] = '\0';
921 p = sp;
922 }
923 }
924 else if(!strncmp(p, "/cygdrive/", 10) &&
925 (strlen(p) > 10) && tl_ascii_isalpha(p[10]))
926 {
927 strncpy(pom, p, 11);
928 pom[11] = '\0';
929 p += 11;
930 }
931 p += strspn(p, "/");
932 #else
933 if(strlen(p) > 2 && p[0] == '/' && p[1] == '/' &&
934 tl_ascii_isalpha(p[2]) && (p[3] == '\0' || p[3] == '/'))
935 {
936 strncpy(pom, p, 3);
937 pom[3] = '\0';
938 p += 3;
939 }
940 p += strspn(p, "/");
941 #endif
942 #endif
943 while(*p)
944 {
945 int ilen = strcspn(p, "/");
946
947 strcat(pom, "/");
948 strncat(pom, p, ilen);
949
950 p += ilen;
951 p += strspn(p, "/");
952
953 if(*p && access(pom, F_OK))
954 {
955 if(mkdir(pom, S_IRWXU | S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH))
956 return -1;
957 }
958 }
959 }
960 return 0;
961 }
962
963 /***********************************************/
964 /* z relativnej cesty urobi absolutnu a vyhodi */
965 /* vsetky "." a ".." adresare */
966 /* FIXME: Translate me! */
967 /***********************************************/
get_abs_file_path_oss(char * path)968 char *get_abs_file_path_oss(char *path)
969 {
970 char *p, pom[PATH_MAX], *tmp, result[PATH_MAX] = "/";
971 int ilen;
972 bool_t last = 1;
973
974 for(p = path; tl_ascii_isspace(*p) && *p; p++);
975
976 if(*p != '/')
977 {
978 tmp = (char *) getcwd(NULL, PATH_MAX);
979 if(priv_cfg.cache_dir)
980 sprintf(pom, "%s/%s", priv_cfg.cache_dir, p);
981 else
982 sprintf(pom, "%s/%s", tmp, p);
983 _free(tmp);
984 }
985 else
986 {
987 sprintf(pom, "%s", p);
988 }
989
990 p = pom;
991
992 #ifdef __CYGWIN__
993 #ifndef HAVE_NEWSTYLE_CYGWIN
994 /* workaround to allow //[drive]/... paths on WIN32 */
995 if(strlen(pom) > 2 && pom[0] == '/' && pom[1] == '/' &&
996 tl_ascii_isalpha(pom[2]) && (pom[3] == '\0' || pom[3] == '/'))
997 {
998 strncpy(result, pom, 3);
999 result[3] = '\0';
1000 p = pom + 3;
1001 }
1002 #else
1003 /* workaround to allow //host/share/... paths on WIN32 */
1004 /* AFAIK this type of paths work with cygwin-1.1 =< */
1005 if(pom[0] == '/' && pom[1] == '/')
1006 {
1007 strcpy(result, "//");
1008 p++;
1009 }
1010 #endif
1011 #endif
1012 if(!*p)
1013 strcpy(result, "/");
1014
1015 while(*p)
1016 {
1017 ilen = strcspn(p, "/");
1018 if(*(p + ilen))
1019 *(p + ilen) = '\0';
1020 else
1021 last = 0;
1022
1023 if(strcmp(p, "."))
1024 {
1025 if(strcmp(p, ".."))
1026 {
1027 if(!tl_is_dirname(result))
1028 strcat(result, "/");
1029 strcat(result, p);
1030 }
1031 else
1032 {
1033 tmp = strrchr(result, '/');
1034 *(tmp + 1 - (tmp != result)) = '\0';
1035 }
1036 }
1037 p += ilen + last;
1038 p += strspn(p, "/");
1039 }
1040
1041 ilen = strlen(path);
1042 p = path + ilen - 1;
1043 if(ilen && *p != '/' && tl_is_dirname(result))
1044 {
1045 result[strlen(result) - 1] = '\0';
1046 }
1047
1048 if((tl_is_dirname(path) && !tl_is_dirname(result)) || (strlen(result) == 0))
1049 {
1050 result[strlen(result) + 1] = '\0';
1051 result[strlen(result)] = '/';
1052 }
1053
1054 return tl_strdup(result);
1055 }
1056
1057 /***********************************************/
1058 /* z relativnej cesty urobi absolutnu a vyhodi */
1059 /* vsetky "." a ".." adresare */
1060 /* FIXME: Translate me! */
1061 /***********************************************/
get_abs_file_path(char * path)1062 char *get_abs_file_path(char *path)
1063 {
1064 char *p, pom[PATH_MAX], *tmp, result[PATH_MAX] = "/";
1065 int ilen;
1066 bool_t last = 1;
1067
1068 for(p = path; tl_ascii_isspace(*p) && *p; p++);
1069
1070 if(*p != '/')
1071 {
1072 tmp = (char *) getcwd(NULL, PATH_MAX);
1073 sprintf(pom, "%s/%s", tmp ? tmp : "", p);
1074 _free(tmp);
1075 }
1076 else
1077 {
1078 sprintf(pom, "%s", p);
1079 }
1080
1081 p = pom;
1082
1083 if(!*p)
1084 strcpy(result, "/");
1085
1086 while(*p)
1087 {
1088 ilen = strcspn(p, "/");
1089 if(*(p + ilen))
1090 *(p + ilen) = '\0';
1091 else
1092 last = 0;
1093
1094 if(strcmp(p, "."))
1095 {
1096 if(strcmp(p, ".."))
1097 {
1098 if(!tl_is_dirname(result))
1099 strcat(result, "/");
1100 strcat(result, p);
1101 }
1102 else
1103 {
1104 tmp = strrchr(result, '/');
1105 *(tmp + 1 - (tmp != result)) = '\0';
1106 }
1107 }
1108 p += ilen + last;
1109 p += strspn(p, "/");
1110 }
1111
1112 ilen = strlen(path);
1113 p = path + ilen - 1;
1114 if(ilen && *p != '/' && tl_is_dirname(result) == '/')
1115 {
1116 result[strlen(result) - 1] = '\0';
1117 }
1118
1119 if((tl_is_dirname(path) && !tl_is_dirname(result)) || (strlen(result) == 0))
1120 {
1121 result[strlen(result) + 1] = '\0';
1122 result[strlen(result)] = '/';
1123 }
1124
1125 return tl_strdup(result);
1126 }
1127
1128 #ifdef __CYGWIN__
cvt_win32_to_unix_path(char * path)1129 char *cvt_win32_to_unix_path(char *path)
1130 {
1131 char pom[PATH_MAX];
1132 char *p = tl_strdup(path);
1133 char *p1;
1134
1135 pom[0] = '\0';
1136 p1 = p;
1137
1138 if(strlen(p) >= 2 && tl_ascii_isalpha(p[0]) && p[1] == ':')
1139 {
1140 #ifdef HAVE_NEWSTYLE_CYGWIN
1141 sprintf(pom, "/cygdrive/%c", p[0]);
1142 p += 2;
1143 #else
1144 sprintf(pom, "//%c", p[0]);
1145 p += 2;
1146 #endif
1147 }
1148
1149 _strtrchr(p, '\\', '/');
1150
1151 strcat(pom, p);
1152 _free(p1);
1153
1154 return get_abs_file_path_oss(pom);
1155 }
1156
cvt_unix_to_win32_path(char * path)1157 char *cvt_unix_to_win32_path(char *path)
1158 {
1159 char res[PATH_MAX];
1160 cygwin32_conv_to_win32_path(path, res);
1161 return tl_strdup(res);
1162 }
1163 #endif
1164
1165 /**********************************/
1166 /* spocita vyskyt znaku v retazci */
1167 /* FIXME: Translate me! */
1168 /**********************************/
str_cnt_chr(char * s,int c)1169 static int str_cnt_chr(char *s, int c)
1170 {
1171 char *p = s;
1172 int ret = 0;
1173
1174 while(*p)
1175 {
1176 if(*p == c)
1177 ret++;
1178
1179 p++;
1180 }
1181
1182 return ret;
1183 }
1184
1185 /********************************************/
1186 /* urci relativnu cestu z adresara v ktorom */
1187 /* sa nachadza prvy subor na druhy subor */
1188 /* FIXME: Translate me! */
1189 /********************************************/
get_relative_path(char * fromabs,char * toabs)1190 char *get_relative_path(char *fromabs, char *toabs)
1191 {
1192 char *p1, *p2, *pom1, *pom2;
1193 int offset = 0, i, plom;
1194 char *rv = NULL;
1195
1196 pom1 = p1 = get_abs_file_path_oss(fromabs);
1197 pom2 = p2 = get_abs_file_path_oss(toabs);
1198
1199 while(*p1 && *p2 && *p1 == *p2)
1200 {
1201 p1++;
1202 p2++;
1203 }
1204
1205 #if 0
1206 /* this is not good behaviour, as lynx and netscape behaves */
1207 /* differently on empty HREFs */
1208 if(!strcmp(p1, p2))
1209 {
1210 free(pom1);
1211 free(pom2);
1212 return tl_strdup("");
1213 }
1214 #endif
1215
1216 if(*p1)
1217 p1--;
1218
1219 while((p1 >= pom1) && *p1 != '/')
1220 p1--;
1221
1222 if(*p1 != '/')
1223 {
1224 free(pom1);
1225 free(pom2);
1226
1227 return NULL;
1228 }
1229 offset = p1 - pom1;
1230
1231 plom = str_cnt_chr(p1 + 1, '/');
1232
1233 for(i = 0; i < plom; i++)
1234 {
1235 rv = tl_str_concat(rv, "../", NULL);
1236 }
1237
1238 rv = tl_str_concat(rv, pom2 + offset + 1, NULL);
1239
1240 free(pom1);
1241 free(pom2);
1242
1243 return rv;
1244 }
1245
1246 /********************************/
1247 /* vrati poziciu pripony suboru */
1248 /* FIXME: Translate me! */
1249 /********************************/
tl_get_extension(char * fname)1250 char *tl_get_extension(char *fname)
1251 {
1252 char *p1, *p2;
1253
1254 p1 = strrchr(fname, '.');
1255 p2 = strrchr(fname, '/');
1256
1257 if(p1 > p2)
1258 {
1259 return (p1 + 1);
1260 }
1261 else
1262 return "";
1263
1264 }
1265
tl_get_basename(char * fname)1266 char *tl_get_basename(char *fname)
1267 {
1268 char *p;
1269
1270 if((p = strrchr(fname, '/')))
1271 p++;
1272 else
1273 p = fname;
1274
1275 return p;
1276 }
1277
1278 static const char *html_tag_tab[] = {
1279 "<HTML",
1280 "<html",
1281 "<HEAD",
1282 "<head",
1283 "<META",
1284 "<meta",
1285 "<TITLE",
1286 "<title",
1287 "<BODY",
1288 "<body",
1289 "<script",
1290 "<SCRIPT",
1291 "<style",
1292 "<STYLE",
1293 "<!DOCTYPE HTML",
1294 "<!doctype html",
1295 "<!--",
1296 };
1297
ext_is_html(char * fn)1298 bool_t ext_is_html(char *fn)
1299 {
1300 char *ext = tl_get_extension(fn);
1301
1302 return str_is_in_list(0, ext, "html", "htm", "shtml", "phtml", "css", NULL);
1303 }
1304
ext_is_nothtml(char * fn)1305 static bool_t ext_is_nothtml(char *fn)
1306 {
1307 char *ext = tl_get_extension(fn);
1308
1309 return str_is_in_list(0, ext, "gif", "jpg", "jpeg", "png", "mpeg",
1310 "mpg", "avi", "pdf", "gz", "tgz", "zip", "arj",
1311 "hqx", "rar", "tar", "Z", "doc", "doc", "xls", "wav", "au", "mp3", NULL);
1312 }
1313
file_is_html(char * fn)1314 bool_t file_is_html(char *fn)
1315 {
1316 int i, j, len;
1317 char pom[256];
1318 bufio *fd;
1319
1320 if(ext_is_html(fn))
1321 return TRUE;
1322
1323 if(ext_is_nothtml(fn))
1324 return FALSE;
1325
1326 if((fd = bufio_open(fn, O_BINARY | O_RDONLY)))
1327 {
1328 for(j = 0; j < 10; j++)
1329 {
1330 if((len = bufio_readln(fd, pom, sizeof(pom))) > 0)
1331 {
1332 for(i = 0; i < NUM_ELEM(html_tag_tab); i++)
1333 if(strstr(pom, html_tag_tab[i]))
1334 {
1335 bufio_close(fd);
1336 return TRUE;
1337 }
1338 }
1339 else
1340 {
1341 if(len < 0)
1342 xperror("file_is_html");
1343 bufio_close(fd);
1344 return FALSE;
1345 }
1346 }
1347 bufio_close(fd);
1348 }
1349 return FALSE;
1350 }
1351
tl_sleep(unsigned int s)1352 void tl_sleep(unsigned int s)
1353 {
1354 /* if we measure timings, we don't sleep */
1355 if(cfg.time_logfile)
1356 {
1357 return;
1358 }
1359
1360 #ifndef HAVE_MT
1361 if(cfg.xi_face)
1362 {
1363 gui_msleep(s * 1000);
1364 }
1365 else
1366 #endif
1367 {
1368 #ifdef HAVE_MT
1369 struct timeval tout;
1370
1371 tout.tv_sec = s;
1372 tout.tv_usec = 0;
1373
1374 select(0, NULL, NULL, NULL, &tout);
1375 #else
1376 sleep(s);
1377 #endif
1378 }
1379 }
1380
tl_msleep(unsigned int ms)1381 void tl_msleep(unsigned int ms)
1382 {
1383 /* if we measure timings, we don't sleep */
1384 if(cfg.time_logfile)
1385 {
1386 return;
1387 }
1388
1389 #ifndef HAVE_MT
1390 if(cfg.xi_face)
1391 {
1392 gui_msleep(ms);
1393 }
1394 else
1395 #endif
1396
1397 #if defined HAVE_USLEEP && !defined HAVE_MT
1398 usleep(ms * 1000);
1399 #else
1400 {
1401 struct timeval tout;
1402
1403 tout.tv_sec = ms / 1000;
1404 tout.tv_usec = (ms % 1000) * 1000;
1405
1406 select(0, NULL, NULL, NULL, &tout);
1407 }
1408 #endif
1409 }
1410
unlink_recursive(char * fn)1411 int unlink_recursive(char *fn)
1412 {
1413 struct stat estat;
1414
1415 if(lstat(fn, &estat))
1416 {
1417 xperror(fn);
1418 return -1;
1419 }
1420
1421 if(!S_ISDIR(estat.st_mode))
1422 {
1423 if(unlink(fn))
1424 {
1425 xperror(fn);
1426 return (-1);
1427 }
1428 }
1429 else
1430 {
1431 DIR *dir;
1432 struct dirent *dent;
1433 char next_dir[PATH_MAX];
1434
1435 if(!(dir = opendir(fn)))
1436 {
1437 xperror(fn);
1438 return -1;
1439 }
1440
1441 while((dent = readdir(dir)))
1442 {
1443 sprintf(next_dir, "%s/%s", fn, dent->d_name);
1444 if(!strcmp(dent->d_name, "."))
1445 continue;
1446 if(!strcmp(dent->d_name, ".."))
1447 continue;
1448
1449 unlink_recursive(next_dir);
1450 }
1451
1452 closedir(dir);
1453
1454 if(rmdir(fn))
1455 {
1456 xperror(next_dir);
1457 return -1;
1458 }
1459 }
1460
1461 return 0;
1462 }
1463
str_is_in_list(int casesensitive,char * str,...)1464 int str_is_in_list(int casesensitive, char *str, ...)
1465 {
1466 char *which;
1467 va_list args;
1468 int found = FALSE;
1469
1470 va_start(args, str);
1471
1472 for(which = va_arg(args, char *); which; which = va_arg(args, char *))
1473 {
1474 if(casesensitive ? !strcmp(str, which) : !strcasecmp(str, which))
1475 {
1476 found = TRUE;
1477 break;
1478 }
1479 }
1480
1481 va_end(args);
1482
1483 return found;
1484 }
1485
copy_fd_to_file(int fd,char * filename)1486 int copy_fd_to_file(int fd, char *filename)
1487 {
1488 char pom[32768];
1489 int len;
1490 int dfd;
1491
1492 if((dfd = open(filename, O_BINARY | O_WRONLY | O_CREAT, 0644)) < 0)
1493 {
1494 xperror(filename);
1495 return -1;
1496 }
1497
1498 lseek(fd, 0, SEEK_SET);
1499 while((len = read(fd, pom, sizeof(pom))) > 0)
1500 {
1501 if(len != write(dfd, pom, len))
1502 return -1;
1503 }
1504
1505 close(dfd);
1506
1507 lseek(fd, 0, SEEK_END);
1508
1509 return len;
1510 }
1511
tl_adjust_filename(char * path)1512 char *tl_adjust_filename(char *path)
1513 {
1514 char *pom;
1515 char *p, *p2;
1516 int l, n;
1517
1518 pom = _malloc(strlen(path) + 1);
1519
1520 p = pom;
1521 #ifdef __CYGWIN__
1522 #ifndef HAVE_NEWSTYLE_CYGWIN
1523 l = strspn(path, "/");
1524 strncpy(p, path, l);
1525 p += l;
1526 *p = '\0';
1527 path += l;
1528 #endif
1529 #endif
1530
1531 while(*path)
1532 {
1533 n = strspn(path, "/");
1534 path += n;
1535 l = strcspn(path, "/");
1536 if(n)
1537 {
1538 *p = '/';
1539 p++;
1540 }
1541
1542 if(!*(path + l) && ((NAME_MAX - 4) < l))
1543 {
1544 strncpy(p, path + l - (NAME_MAX - 4), NAME_MAX - 4);
1545 p += NAME_MAX - 4;
1546 }
1547 else if(l > NAME_MAX)
1548 {
1549 strncpy(p, path, NAME_MAX);
1550 p += NAME_MAX;
1551 }
1552 else
1553 {
1554 strncpy(p, path, l);
1555 p += l;
1556 }
1557 path += l;
1558 }
1559 *p = '\0';
1560
1561 n = strlen(pom);
1562 p = strrchr(pom, '/');
1563
1564 while(p && (n > PATH_MAX))
1565 {
1566 *p = '\0';
1567 p2 = strrchr(pom, '/');
1568
1569 if(p2)
1570 {
1571 strcpy(p2 + 1, p + 1);
1572 n -= p - p2;
1573 }
1574 p = p2;
1575 }
1576 return pom;
1577 }
1578
tl_filename_needs_adjust(char * path)1579 int tl_filename_needs_adjust(char *path)
1580 {
1581 int l;
1582
1583 if(strlen(path) > PATH_MAX)
1584 return TRUE;
1585
1586 while(*path)
1587 {
1588 path += strspn(path, "/");
1589 l = strcspn(path, "/");
1590
1591 if(!*(path + l) && ((NAME_MAX - 4) < l))
1592 return TRUE;
1593 else if(l > NAME_MAX)
1594 return TRUE;
1595 path += l;
1596 }
1597
1598
1599 return FALSE;
1600 }
1601
tl_is_dirname(const char * path)1602 int tl_is_dirname(const char *path)
1603 {
1604 const char *p = strrchr(path, '/');
1605 return (p && (*(p + 1) == '\0'));
1606 }
1607
tl_str_append(char * str1,char * str2)1608 char *tl_str_append(char *str1, char *str2)
1609 {
1610 int l1, l2;
1611 char *rv;
1612
1613 l1 = str1 ? strlen(str1) : 0;
1614 l2 = strlen(str2);
1615 rv = _realloc(str1, l1 + l2 + 1);
1616 strcpy(rv + l1, str2);
1617
1618 return rv;
1619 }
1620
tl_str_nappend(char * str1,const char * str2,int n)1621 char *tl_str_nappend(char *str1, const char *str2, int n)
1622 {
1623 int l1;
1624 char *rv;
1625
1626 l1 = str1 ? strlen(str1) : 0;
1627 rv = _realloc(str1, l1 + n + 1);
1628 strncpy(rv + l1, str2, n);
1629 rv[l1 + n] = '\0';
1630
1631 return rv;
1632 }
1633
1634
tl_str_concat(char * str1,...)1635 char *tl_str_concat(char *str1, ...)
1636 {
1637 char *p;
1638 va_list args;
1639 int len;
1640 char *rv = str1;
1641
1642 len = str1 ? strlen(str1) : 0;
1643
1644 va_start(args, str1);
1645
1646 for(p = va_arg(args, char *); p; p = va_arg(args, char *))
1647 {
1648 int slen = strlen(p);
1649
1650 rv = _realloc(rv, len + slen + 1);
1651 strcpy(rv + len, p);
1652 len += slen;
1653 }
1654
1655 va_end(args);
1656
1657 return rv;
1658 }
1659
tl_data_concat_str(int * len,char * data,...)1660 char *tl_data_concat_str(int *len, char *data, ...)
1661 {
1662 char *p;
1663 va_list args;
1664 char *rv = data;
1665
1666 va_start(args, data);
1667
1668 for(p = va_arg(args, char *); p; p = va_arg(args, char *))
1669 {
1670 int slen = strlen(p);
1671
1672 rv = _realloc(rv, *len + slen + 1);
1673 strcpy(rv + *len, p);
1674 *len += slen;
1675 }
1676
1677 va_end(args);
1678
1679 return rv;
1680 }
1681
tl_data_concat_data(int * tlen,char * tdata,int len,char * data)1682 char *tl_data_concat_data(int *tlen, char *tdata, int len, char *data)
1683 {
1684 tdata = _realloc(tdata, *tlen + len);
1685 memcpy(tdata + *tlen, data, len);
1686 *tlen += len;
1687
1688 return tdata;
1689 }
1690
tl_load_text_file(char * filename)1691 char *tl_load_text_file(char *filename)
1692 {
1693 char pom[1024];
1694 int tlen, len, fd;
1695 char *rv = NULL;
1696
1697 if((fd = open(filename, O_RDONLY | O_BINARY)) < 0)
1698 {
1699 xperror(filename);
1700 return NULL;
1701 }
1702
1703 tlen = 0;
1704
1705 while((len = read(fd, pom, sizeof(pom))) > 0)
1706 {
1707 rv = tl_data_concat_data(&tlen, rv, len, pom);
1708 }
1709
1710 close(fd);
1711
1712 if(rv)
1713 {
1714 rv = _realloc(rv, tlen + 1);
1715 rv[tlen] = '\0';
1716 }
1717
1718 return rv;
1719 }
1720
tl_save_text_file(char * filename,char * content,int length)1721 int tl_save_text_file(char *filename, char *content, int length)
1722 {
1723 int fd;
1724 int rv = 0;
1725
1726 if(length < 0)
1727 length = strlen(content);
1728
1729 if((fd = open(filename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC), 0644) < 0)
1730 {
1731 xperror(filename);
1732 return -1;
1733 }
1734
1735 if(write(fd, content, length) != length)
1736 {
1737 xperror(filename);
1738 rv = -1;
1739 }
1740
1741 close(fd);
1742
1743 return rv;
1744 }
1745