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