1 /*
2 SMS Server Tools 3
3 Copyright (C) 2006- Keijo Kasvi
4 http://smstools3.kekekasvi.com/
5 
6 Based on SMS Server Tools 2, http://stefanfrings.de/smstools/
7 SMS Server Tools version 2 and below are Copyright (C) Stefan Frings.
8 
9 This program is free software unless you got it under another license directly
10 from the author. You can redistribute it and/or modify it under the terms of
11 the GNU General Public License as published by the Free Software Foundation.
12 Either version 2 of the License, or (at your option) any later version.
13 */
14 
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <limits.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <ctype.h>
26 #include <sys/wait.h>
27 #include <time.h>
28 #include <syslog.h>
29 #include <stdarg.h>
30 #include "extras.h"
31 #include "locking.h"
32 #include "smsd_cfg.h"
33 #include "logging.h"
34 #include "alarm.h"
35 
fopen_mkstemp(char * fname)36 FILE *fopen_mkstemp(char *fname)
37 {
38   mode_t mode;
39   int fd;
40   FILE *fp = 0;
41 
42   if ((fd = mkstemp(fname)) == -1)
43   {
44     writelogfile0(LOG_CRIT, 1, tb_sprintf("mkstemp failure: %s - %i, %s", fname, errno, strerror(errno)));
45     alarm_handler0(LOG_CRIT, tb);
46   }
47   else
48   {
49     mode = umask(0);
50     umask(mode);
51     if (fchmod(fd, 0666 & ~mode))
52     {
53       writelogfile0(LOG_CRIT, 1, tb_sprintf("fchmod failure: %s - %i, %s", fname, errno, strerror(errno)));
54       alarm_handler0(LOG_CRIT, tb);
55     }
56 
57     if (!(fp = fdopen(fd, "w")))
58     {
59       writelogfile0(LOG_CRIT, 1, tb_sprintf("fdopen failure: %s - %i, %s", fname, errno, strerror(errno)));
60       alarm_handler0(LOG_CRIT, tb);
61       close(fd);
62       unlink(fname);
63 
64       // This should not be required, but at least on one Cygwin environment fopen() right after
65       // unlink() failed (permission denied) randomly, but rarely, and first retry helped:
66       writelogfile(LOG_CRIT, 1, "Waiting 1 sec before retrying with %s", fname);
67       usleep_until(time_usec() + 1000000);
68       if (!(fp = fopen(fname, "w")))
69       {
70         writelogfile(LOG_CRIT, 1, "2. fopen write failure: %s - %i: %s", fname, errno, strerror(errno));
71         writelogfile(LOG_CRIT, 1, "Waiting 5 sec before retrying with %s", fname);
72         usleep_until(time_usec() + 5000000);
73 
74         if (!(fp = fopen(fname, "w")))
75         {
76           writelogfile(LOG_CRIT, 1, "3. fopen write failure: %s - %i: %s", fname, errno, strerror(errno));
77           writelogfile0(LOG_CRIT, 1, tb_sprintf("Not retrying anymore with %s", fname));
78           alarm_handler0(LOG_CRIT, tb);
79         }
80         else
81         {
82           writelogfile0(LOG_CRIT, 1, tb_sprintf("2. retry helped with %s", fname));
83           alarm_handler0(LOG_CRIT, tb);
84         }
85       }
86       else
87       {
88         writelogfile0(LOG_CRIT, 1, tb_sprintf("1. retry helped with %s", fname));
89         alarm_handler0(LOG_CRIT, tb);
90       }
91     }
92   }
93 
94   return fp;
95 }
96 
yesno(char * value)97 int yesno(char *value)
98 {
99   extern char yes_chars[];
100   extern char no_chars[];
101   char *p, *p2;
102 
103   if (*yes_chars)
104   {
105     p = yes_chars;
106     while (*p)
107     {
108       if (!(p2 = strchr(p, '\'')))
109         break;
110       if (!strncmp(value, p, (int)(p2 -p)))
111         return 1;
112       p = p2 +1;
113     }
114   }
115 
116   if (*no_chars)
117   {
118     p = no_chars;
119     while (*p)
120     {
121       if (!(p2 = strchr(p, '\'')))
122         break;
123       if (!strncmp(value, p, (int)(p2 -p)))
124         return 0;
125       p = p2 +1;
126     }
127   }
128 
129   if ((value[0]=='1') ||
130       (value[0]=='y') ||
131       (value[0]=='Y') ||
132       (value[0]=='t') ||
133       (value[0]=='T') ||
134       ((value[1]=='n') && (
135         (value[0]=='o') ||
136         (value[0]=='O'))
137       ))
138     return 1;
139   else
140     return 0;
141 }
142 
yesno_check(char * value)143 int yesno_check(char*  value)
144 {
145   // This version is used to check config file values.
146   int result = -1;
147 
148   if ((value[0]=='1') ||
149       (value[0]=='y') ||
150       (value[0]=='Y') ||
151       (value[0]=='t') ||
152       (value[0]=='T') ||
153       ((value[1]=='n') && (
154         (value[0]=='o') ||
155         (value[0]=='O'))
156       ))
157     result = 1;
158   else
159   if ((value[0]=='0') ||
160       (value[0]=='n') ||
161       (value[0]=='N') ||
162       (value[0]=='f') ||
163       (value[0]=='F') ||
164       ((value[1]=='f') && (
165         (value[0]=='o') ||
166         (value[0]=='O'))
167       ))
168     result = 0;
169 
170   return result;
171 }
172 
cut_ctrl(char * message)173 char *cut_ctrl(char* message) /* removes all ctrl chars */
174 {
175   // 3.0.9: use dynamic buffer to avoid overflow:
176   //char tmp[500];
177   char *tmp;
178   int posdest=0;
179   int possource;
180   int count;
181 
182   count=strlen(message);
183   if ((tmp = (char *)malloc(count +1)))
184   {
185     for (possource=0; possource<=count; possource++)
186     {
187       // 3.1beta7: added unsigned test:
188       if (((unsigned char)message[possource] >= (unsigned char)' ') || (message[possource]==0))
189         tmp[posdest++]=message[possource];
190     }
191     strcpy(message,tmp);
192     free(tmp);
193   }
194   return message;
195 }
196 
cut_crlf(char * st)197 char *cut_crlf(char *st)
198 {
199 
200   while (*st && strchr("\r\n", st[strlen(st) -1]))
201     st[strlen(st) -1] = 0;
202 
203   return st;
204 }
205 
is_blank(char c)206 int is_blank(char c)
207 {
208   return (c==9) || (c==32);
209 }
210 
line_is_blank(char * line)211 int line_is_blank(char *line)
212 {
213   int i = 0;
214 
215   while (line[i])
216     if (strchr("\t \r\n", line[i]))
217       i++;
218     else
219       break;
220 
221   return(line[i] == 0);
222 }
223 
224 // 3.1.17: Using the same function to copy file.
225 
movefile(char * filename,char * directory)226 int movefile(char *filename, char *directory)
227 {
228   return copymovefile(0, filename, directory);
229 }
230 
copyfile(char * filename,char * directory)231 int copyfile(char *filename, char *directory)
232 {
233   return copymovefile(1, filename, directory);
234 }
235 
copymovefile(int copy,char * filename,char * directory)236 int copymovefile(int copy, char *filename, char *directory)
237 {
238   char newname[PATH_MAX];
239   char storage[1024];
240   int source,dest;
241   int readcount;
242   char* cp;
243   struct stat statbuf;
244 
245   if (stat(filename,&statbuf)<0)
246     statbuf.st_mode=0640;
247   statbuf.st_mode&=07777;
248   cp=strrchr(filename,'/');
249   if (cp)
250     sprintf(newname,"%s%s",directory,cp);
251   else
252     sprintf(newname,"%s/%s",directory,filename);
253   source=open(filename,O_RDONLY);
254   if (source>=0)
255   {
256     dest=open(newname,O_WRONLY|O_CREAT|O_TRUNC,statbuf.st_mode);
257     if (dest>=0)
258     {
259       //while ((readcount=read(source,&storage,sizeof(storage)))>0)
260       //  if (write(dest,&storage,readcount)<readcount)
261       while ((readcount = read(source, storage, sizeof(storage))) > 0)
262         if (write(dest, storage, readcount) < readcount)
263 	{
264 	  close(dest);
265 	  close(source);
266 	  return 0;
267 	}
268       close(dest);
269       close(source);
270 
271       if (!copy)
272         unlink(filename);
273 
274       return 1;
275     }
276     else
277     {
278       close(source);
279       return 0;
280     }
281   }
282   else
283     return 0;
284 }
285 
286 // 3.1beta7: Return values:
287 // 0 = OK.
288 // 1 = lockfile cannot be created. It exists.
289 // 2 = file copying failed.
290 // 3 = lockfile removing failed.
291 
292 // 3.1.17: Using the same function to copy file.
293 
movefilewithdestlock(char * filename,char * directory,int keep_fname,int store_original_fname,char * prefix,char * newfilename)294 int movefilewithdestlock(char *filename, char *directory, int keep_fname, int store_original_fname, char *prefix, char *newfilename)
295 {
296   return copymovefilewithdestlock(0, filename, directory, keep_fname, store_original_fname, prefix, newfilename);
297 }
298 
copyfilewithdestlock(char * filename,char * directory,int keep_fname,int store_original_fname,char * prefix,char * newfilename)299 int copyfilewithdestlock(char *filename, char *directory, int keep_fname, int store_original_fname, char *prefix, char *newfilename)
300 {
301   return copymovefilewithdestlock(1, filename, directory, keep_fname, store_original_fname, prefix, newfilename);
302 }
303 
copymovefilewithdestlock(int copy,char * filename,char * directory,int keep_fname,int store_original_fname,char * prefix,char * newfilename)304 int copymovefilewithdestlock(int copy, char *filename, char *directory, int keep_fname, int store_original_fname, char *prefix, char *newfilename)
305 {
306   if (newfilename)
307     *newfilename = 0;
308 
309   if (keep_fname)
310   {
311     char filename2lock[PATH_MAX];
312     char* cp;
313 
314     //create filename2lock in destination
315     cp=strrchr(filename,'/');
316     if (cp)
317       sprintf(filename2lock,"%s%s",directory,cp);
318     else
319       sprintf(filename2lock,"%s/%s",directory,filename);
320 
321     //create lock and move file
322     if (!lockfile(filename2lock))
323     // 3.1.16beta2: log details in the case of conflict:
324     //  return 1;
325     {
326       char details[128];
327 
328       if (get_file_details(filename2lock, details, sizeof(details)))
329       {
330         writelogfile0(LOG_CRIT, 1, tb_sprintf("File already exists and it was locked: %s %s", filename2lock, details));
331         alarm_handler0(LOG_CRIT, tb);
332       }
333 
334       return 1;
335     }
336 
337     if (!copymovefile(copy, filename, directory))
338     {
339       unlockfile(filename2lock);
340       return 2;
341     }
342     if (!unlockfile(filename2lock))
343       return 3;
344 
345     if (newfilename)
346       strcpy(newfilename, filename2lock);
347 
348     return 0;
349   }
350   else
351   {
352     // A new unique name is created to the destination directory.
353     char newname[PATH_MAX];
354     int result = 0;
355     char line[1024];
356     int in_headers = 1;
357     FILE *fp;
358     FILE *fpnew;
359     size_t n;
360     char *p;
361     extern const char *HDR_OriginalFilename;
362     extern char HDR_OriginalFilename2[];
363 
364     strcpy(line, prefix);
365     if (*line)
366       strcat(line, ".");
367     sprintf(newname,"%s/%sXXXXXX", directory, line);
368     close(mkstemp(newname));
369     if (!lockfile(newname))
370       result = 1;
371 
372     unlink(newname);
373     if (!result)
374     {
375       // 3.1.16beta: Log and retry in case of failures. This is from "VVV-3" special version.
376       if (!(fpnew = fopen(newname, "w")))
377       {
378         writelogfile(LOG_CRIT, 1, "1. fopen write failure: %s - %i: %s", newname, errno, strerror(errno));
379         writelogfile(LOG_CRIT, 1, "Waiting 1 sec before retrying with %s", newname);
380         usleep_until(time_usec() + 1000000);
381 
382         if (!(fpnew = fopen(newname, "w")))
383         {
384           writelogfile(LOG_CRIT, 1, "2. fopen write failure: %s - %i: %s", newname, errno, strerror(errno));
385           writelogfile(LOG_CRIT, 1, "Waiting 5 sec before retrying with %s", newname);
386           usleep_until(time_usec() + 5000000);
387 
388           if (!(fpnew = fopen(newname, "w")))
389           {
390             writelogfile(LOG_CRIT, 1, "3. fopen write failure: %s - %i: %s", newname, errno, strerror(errno));
391             writelogfile(LOG_CRIT, 1, "Not retrying anymore with %s", newname);
392 
393             result = 2;
394           }
395           else
396             writelogfile(LOG_CRIT, 1, "2. retry helped with %s", newname);
397         }
398         else
399           writelogfile(LOG_CRIT, 1, "1. retry helped with %s", newname);
400       }
401 
402       if (!result)
403       {
404         if (!(fp = fopen(filename, "r")))
405         {
406           fclose(fpnew);
407           unlink(newname);
408           result = 2;
409         }
410         else
411         {
412           while (in_headers && fgets(line, sizeof(line), fp))
413           {
414             if (line_is_blank(line))
415             {
416               if (store_original_fname && *HDR_OriginalFilename2 != '-')
417               {
418                 p = strrchr(filename, '/');
419                 fprintf(fpnew, "%s %s\n", (*HDR_OriginalFilename2)? HDR_OriginalFilename2 : HDR_OriginalFilename,
420                         (p)? p +1 : filename);
421               }
422               in_headers = 0;
423             }
424             fwrite(line, 1, strlen(line), fpnew);
425           }
426 
427           while ((n = fread(line, 1, sizeof(line), fp)) > 0)
428             fwrite(line, 1, n, fpnew);
429 
430           fclose(fpnew);
431           fclose(fp);
432         }
433       }
434     }
435 
436     if (!unlockfile(newname))
437     {
438       unlink(newname);
439       if (!result)
440         result = 3;
441     }
442     else
443     {
444       if (!copy)
445         if (!result) // 3.1.16beta2: Do not delete in case of errors.
446           unlink(filename);
447 
448       if (newfilename)
449         strcpy(newfilename, newname);
450     }
451 
452     return result;
453   }
454 }
455 
cutspaces(char * text)456 char *cutspaces(char *text)
457 {
458   int count;
459   int Length;
460   int i;
461   int omitted;
462 
463   /* count ctrl chars and spaces at the beginning */
464   count=0;
465   while ((text[count]!=0) && ((is_blank(text[count])) || (iscntrl((int)text[count]))) )
466     count++;
467   /* remove ctrl chars at the beginning and \r within the text */
468   omitted=0;
469   Length=strlen(text);
470   for (i=0; i<=(Length-count); i++)
471     if (text[i+count]=='\r')
472       omitted++;
473     else
474       text[i-omitted]=text[i+count];
475   Length=strlen(text);
476   while ((Length>0) && ((is_blank(text[Length-1])) || (iscntrl((int)text[Length-1]))))
477   {
478     text[Length-1]=0;
479     Length--;
480   }
481 
482   return text;
483 }
484 
cut_emptylines(char * text)485 char *cut_emptylines(char *text)
486 {
487   char* posi;
488   char* found;
489 
490   posi=text;
491   while (posi[0] && (found=strchr(posi,'\n')))
492   {
493     if ((found[1]=='\n') || (found==text))
494       memmove(found,found+1,strlen(found));
495     else
496       posi++;
497   }
498   return text;
499 }
500 
is_number(char * text)501 int is_number( char*  text)
502 {
503   int i;
504   int Length;
505 
506   Length=strlen(text);
507   for (i=0; i<Length; i++)
508     if (((text[i]>'9') || (text[i]<'0')) && (text[i]!='-'))
509       return 0;
510   return 1;
511 }
512 
is_highpriority(char * filename)513 int is_highpriority(char *filename)
514 {
515   FILE *fp;
516   char line[256];
517   int result = 0;
518   // 3.1beta7: language settings used:
519   extern const char *HDR_Priority;
520   extern char HDR_Priority2[];
521   int hlen;
522   int hlen2 = 0;
523   char *compare;
524   char *compare2 = 0;
525 
526   if (ignore_outgoing_priority || spool_directory_order)
527     return 0;
528 
529   // get_header() and test_header() can be moved to this file,
530   // but this is faster:
531   if (*HDR_Priority2 && strcmp(HDR_Priority2, "-"))
532   {
533     if (*HDR_Priority2 == '-')
534       compare2 = HDR_Priority2 +1;
535     else
536       compare2 = HDR_Priority2;
537     hlen2 = strlen(compare2);
538   }
539 
540   compare = (char *)HDR_Priority;
541   hlen = strlen(compare);
542 
543   if ((fp = fopen(filename, "r")))
544   {
545     while (!result && fgets(line, sizeof(line), fp))
546     {
547       if (line_is_blank(line))
548         break;
549 
550       if ((compare2 && strncmp(line, compare2, hlen2) == 0) ||
551           strncmp(line, compare, hlen) == 0)
552       {
553         cutspaces(strcpyo(line, line + hlen));
554         if (!strcasecmp(line,"HIGH"))
555           result = 1;
556         else if (yesno(line) == 1)
557           result = 1;
558       }
559     }
560     fclose(fp);
561   }
562   return result;
563 }
564 
file_is_writable(char * filename)565 int file_is_writable(char *filename)
566 {
567   int result = 0;
568   FILE *fp;
569   struct stat statbuf;
570 
571   // 3.1.12: First check that the file exists:
572   if (stat(filename, &statbuf) == 0)
573   {
574     if (S_ISDIR(statbuf.st_mode) == 0)
575     {
576       // 3.1.17: Use access() if not under cygwin. If using inotifywait with -e close_write,
577       // testing with append causes extra events. They do not cause errors, but still use access.
578       if (!os_cygwin)
579       {
580         if (access(filename, W_OK) == 0)
581           result = 1;
582       }
583       else
584       {
585         if ((fp = fopen(filename, "a")))
586         {
587           result = 1;
588           fclose(fp);
589         }
590       }
591     }
592   }
593 
594   return result;
595 }
596 
getpdufile(char * filename)597 int getpdufile(char *filename)
598 {
599   int result = 0;
600   struct stat statbuf;
601   DIR* dirdata;
602   struct dirent* ent;
603   char tmpname[PATH_MAX];
604 
605   if (*filename)
606   {
607     if (filename[strlen(filename) -1] != '/')
608     {
609       if (file_is_writable(filename))
610         result = 1;
611     }
612     else if (!strchr(filename, '.'))
613     {
614       if (stat(filename, &statbuf) == 0)
615       {
616         if (S_ISDIR(statbuf.st_mode))
617         {
618           if ((dirdata = opendir(filename)))
619           {
620             while ((ent = readdir(dirdata)))
621             {
622               if (ent->d_name[0] != '.')
623               {
624                 sprintf(tmpname, "%s%s", filename, ent->d_name);
625                 if (file_is_writable(tmpname))
626                 {
627                   strcpy(filename, tmpname);
628                   result = 1;
629                   break;
630                 }
631               }
632             }
633             // 3.1.1:
634             //close the directory. added by Callan Fox to fix open handles problem
635             closedir(dirdata);
636           }
637         }
638       }
639     }
640   }
641 
642   return result;
643 }
644 
getfile(int trust_directory,char * dir,char * filename,int lock)645 int getfile(int trust_directory, char *dir, char *filename, int lock)
646 {
647   DIR* dirdata;
648   struct dirent* ent;
649   struct stat statbuf;
650   int found=0;
651   time_t mtime;
652   char fname[PATH_MAX];
653   char tmpname[PATH_MAX];
654   int found_highpriority;
655   int i;
656   char storage_key[PATH_MAX +3];
657   unsigned long long start_time;
658 
659   // 3.1.12: Collect filenames:
660   typedef struct
661   {
662     char fname[256]; // 3.1.16beta2: was [NAME_MAX + 1]; but some systems do not define NAME_MAX.
663     time_t mtime;
664   } _candidate;
665 
666   _candidate candidates[NUMBER_OF_MODEMS];
667   int lost_count = 0;
668   int files_count;
669   int locked_count;
670 
671 #ifdef DEBUGMSG
672   printf("!! getfile(dir=%s, ...)\n", dir);
673 #endif
674 
675   start_time = time_usec();
676 
677   // 3.1.12: if a file is lost, try a new search immediately.
678   while (1)
679   {
680     if (terminate)
681       break;
682 
683     // Oldest file is searched. With heavy traffic the first file found is not necesssary the oldest one.
684 
685     if (!(dirdata = opendir(dir)))
686     {
687       // Something has happened to dir after startup check was done successfully.
688       writelogfile0(LOG_CRIT, 0, tb_sprintf("Stopping. Cannot open dir %s %s", dir, strerror(errno)));
689       alarm_handler0(LOG_CRIT, tb);
690       abnormal_termination(1);
691     }
692 
693     mtime = 0;
694     files_count = 0;
695     locked_count = 0;
696     found_highpriority = 0;
697     memset(candidates, 0, sizeof(candidates));
698 
699     while ((ent = readdir(dirdata)))
700     {
701 #ifdef DEBUGMSG
702       printf("**readdir(): %s\n", ent->d_name);
703 #endif
704       sprintf(tmpname, "%s/%s", dir, ent->d_name);
705 
706       // 3.1.12:
707       //stat(tmpname, &statbuf);
708       if (stat(tmpname, &statbuf) != 0)
709         continue;
710 
711       if (S_ISDIR(statbuf.st_mode) != 0) /* Is this a directory? */
712         continue;
713 
714       // 3.1.17: should use ent->d_name, tmpname contains full path:
715       i = 1;
716       if (strlen(ent->d_name) >= 5 && !strcmp(ent->d_name + strlen(ent->d_name) - 5, ".LOCK"))
717         i = 0;
718       else if (!strncmp(ent->d_name, "LOCKED", 6))
719         i = 0;
720 
721       if (!i)
722       {
723         locked_count++;
724         continue;
725       }
726 
727       // 3.1.16beta: Skip empty files:
728       if (statbuf.st_size < 8)
729         continue;
730 
731       // 3.1.17: Ignore hidden files starting with a dot:
732       if (ent->d_name[0] == '.')
733         continue;
734 
735       files_count++;
736 
737       // 3.1.12:
738       //if (trust_directory || !islocked(tmpname)) {...
739       if (islocked(tmpname))
740         continue;
741 
742       sprintf(storage_key, "*%s*\n", tmpname);
743 
744       // 3.1beta7, 3.0.10:
745       if (os_cygwin)
746         if (!check_access(tmpname))
747           chmod(tmpname, 0766);
748 
749       if (!trust_directory && !os_cygwin && !file_is_writable(tmpname))
750       {
751         // Try to fix permissions.
752         int result = 1;
753         char tmp_filename[PATH_MAX +7];
754         FILE *fp;
755         FILE *fptmp;
756         char buffer[1024];
757         size_t n;
758 
759         snprintf(tmp_filename, sizeof(tmp_filename), "%s.XXXXXX", tmpname);
760         close(mkstemp(tmp_filename));
761         unlink(tmp_filename);
762 
763         if ((fptmp = fopen(tmp_filename, "w")) == NULL)
764           result = 0;
765         else
766         {
767           if ((fp = fopen(tmpname, "r")) == NULL)
768             result = 0;
769           else
770           {
771             while ((n = fread(buffer, 1, sizeof(buffer), fp)) > 0)
772               fwrite(buffer, 1, n, fptmp);
773 
774             fclose(fp);
775           }
776 
777           fclose(fptmp);
778 
779           if (result)
780           {
781             unlink(tmpname);
782             rename(tmp_filename, tmpname);
783           }
784           else
785             unlink(tmp_filename);
786         }
787       }
788 
789       if (!trust_directory && !file_is_writable(tmpname))
790       {
791         int report = 1;
792         char reason[100];
793 
794         // 3.1.16beta: Retry once after small delay:
795         int access_ok = check_access(tmpname);
796         if (!access_ok)
797         {
798           usleep_until(time_usec() + 250000);
799           access_ok = check_access(tmpname);
800         }
801 
802         if (!access_ok) //!check_access(tmpname))
803         {
804           snprintf(reason, sizeof(reason), "%s", "Access denied. Check the file and directory permissions.");
805           if (getfile_err_store)
806             if (strstr(getfile_err_store, storage_key))
807               report = 0;
808 
809           if (report)
810           {
811             strcat_realloc(&getfile_err_store, storage_key, 0);
812             writelogfile0(LOG_ERR, 0, tb_sprintf("Cannot handle %s: %s", tmpname, reason));
813             alarm_handler0(LOG_ERR, tb);
814           }
815         }
816         else
817         {
818           // 3.1.5: This error is repeated:
819           snprintf(reason, sizeof(reason), "%s", "Dont know why. Check the file and directory permissions.");
820           writelogfile0(LOG_ERR, 0, tb_sprintf("Cannot handle %s: %s", tmpname, reason));
821           alarm_handler0(LOG_ERR, tb);
822         }
823       }
824       else
825       {
826         // Forget previous error with this file:
827         if (getfile_err_store)
828         {
829           char *p;
830           int l = strlen(storage_key);
831 
832           if ((p = strstr(getfile_err_store, storage_key)))
833             memmove(p, p +l, strlen(p) -l +1);
834           if (!(*getfile_err_store))
835           {
836             free(getfile_err_store);
837             getfile_err_store = NULL;
838           }
839         }
840 
841         i = is_highpriority(tmpname);
842         if (found_highpriority && !i)
843         {
844 #ifdef DEBUGMSG
845           printf("**%s %s not highpriority, already have one.\n", dir, ent->d_name);
846 #endif
847           continue;
848         }
849 
850         if (i && !found_highpriority)
851         {
852           // Forget possible previous found normal priority file:
853           mtime = 0;
854           found_highpriority = 1;
855           memset(candidates, 0, sizeof(candidates));
856         }
857 
858 #ifdef DEBUGMSG
859         printf("**%s %s %i ", dir, ent->d_name, (int)(statbuf.st_mtime));
860 #endif
861 
862         // 3.1.6: Files with the same timestamp: compare names:
863         if (found && statbuf.st_mtime == mtime)
864           if (strcmp(fname, tmpname) > 0)
865             mtime = 0;
866 
867         if (mtime == 0 || statbuf.st_mtime < mtime)
868         {
869 #ifdef DEBUGMSG
870           printf("taken\n");
871 #endif
872           strcpy(fname, tmpname);
873           mtime = statbuf.st_mtime;
874           found = 1;
875 
876           if (spool_directory_order)
877             break;
878 
879 #if NUMBER_OF_MODEMS > 1
880           for (i = NUMBER_OF_MODEMS - 1; i > 0; i--)
881           {
882             strcpy(candidates[i].fname, candidates[i - 1].fname);
883             candidates[i].mtime = candidates[i - 1].mtime;
884           }
885           snprintf(candidates[0].fname, sizeof(candidates[0].fname), "%s", ent->d_name);
886           candidates[0].mtime = statbuf.st_mtime;
887 #endif
888         }
889         else
890         {
891 #ifdef DEBUGMSG
892           printf("leaved\n");
893 #endif
894 
895 #if NUMBER_OF_MODEMS > 1
896           for (i = 1; i < NUMBER_OF_MODEMS; i++)
897           {
898             if (candidates[i].fname[0] == 0)
899               break;
900 
901             if (candidates[i].mtime > statbuf.st_mtime)
902               break;
903 
904             if (candidates[i].mtime == statbuf.st_mtime)
905               if (strcmp(candidates[i].fname, tmpname) > 0)
906                 break;
907           }
908 
909           if (i < NUMBER_OF_MODEMS)
910           {
911             int j;
912 
913             for (j = NUMBER_OF_MODEMS - 1; j > i; j--)
914             {
915               strcpy(candidates[j].fname, candidates[j - 1].fname);
916               candidates[j].mtime = candidates[j - 1].mtime;
917             }
918             snprintf(candidates[i].fname, sizeof(candidates[i].fname), "%s", ent->d_name);
919             candidates[i].mtime = statbuf.st_mtime;
920           }
921 #endif
922         }
923       }
924     }
925 
926 #ifdef DEBUGMSG
927     if (getfile_err_store)
928       printf("!! process: %i, getfile_err_store:\n%s", process_id, getfile_err_store);
929 #endif
930 
931     // Each process has it's own error storage.
932     // Mainspooler handles only the outgoing folder.
933     // Modem processes handle all queue directories which are defined to the modem.
934     // If some problematic file is deleted (outside of smsd), it's name remains in the storage.
935     // To avoid missing error messages with the same filename later, storage is checked and cleaned.
936 
937     if (getfile_err_store)
938     {
939       char *p1;
940       char *p2;
941       char tmp[PATH_MAX];
942       struct stat statbuf;
943 
944       p1 = getfile_err_store;
945       while ((p2 = strchr(p1, '\n')))
946       {
947         memcpy(tmp, p1 +1, p2 -p1 -2);
948         tmp[p2 -p1 -2] = 0;
949         //if (access(tmp, F_OK) != 0)
950         if (stat(tmp, &statbuf))
951           memmove(p1, p2 +1, strlen(p2));
952         else
953           p1 = p2 +1;
954       }
955 
956       if (!(*getfile_err_store))
957       {
958         free(getfile_err_store);
959         getfile_err_store = NULL;
960       }
961     }
962 
963 #ifdef DEBUGMSG
964     if (getfile_err_store)
965       printf("!! process: %i, getfile_err_store:\n%s", process_id, getfile_err_store);
966 #endif
967 
968     // 3.1.9: Lock the file before waiting.
969     if (found && lock)
970     {
971       // 3.1.12: check if a file still exists:
972       if (stat(fname, &statbuf) || !lockfile(fname))
973       {
974         found = 0;
975 
976 #if NUMBER_OF_MODEMS > 1
977         // Try to take the next best file:
978         for (i = 1; i < NUMBER_OF_MODEMS && candidates[i].fname[0] && !found; i++)
979         {
980           sprintf(fname, "%s/%s", dir, candidates[i].fname);
981           if (stat(fname, &statbuf) == 0 && lockfile(fname))
982           {
983             mtime = candidates[i].mtime;
984             found = 1;
985             //writelogfile(LOG_DEBUG, 0, "Got the next best file from candidates (%i), %i SMS files and %i LOCK files seen.", i, files_count, locked_count);
986           }
987         }
988 #endif
989 
990         if (found == 0)
991         {
992           lost_count++;
993 
994           // 3.1.12: continue immediately, or do other tasks after trying enough
995           if (max_continuous_sending == 0 || time_usec() < start_time + max_continuous_sending * 1000000)
996           {
997             closedir(dirdata);
998             continue;
999           }
1000           else if (max_continuous_sending > 0)
1001             writelogfile(LOG_DEBUG, 0, "Tried to get a file for %i seconds, will do other tasks and then continue.", (int)(time_usec() - start_time) / 1000000);
1002         }
1003       }
1004     }
1005 
1006     if (!trust_directory && found)
1007     {
1008       /* check if the file grows at the moment (another program writes to it) */
1009       int groesse1;
1010       int groesse2;
1011 
1012       // 3.1.9: check if the file is deleted, or deleted while waiting...
1013       if (stat(fname, &statbuf))
1014         found = 0;
1015       else
1016       {
1017         groesse1 = statbuf.st_size;
1018 
1019         // 3.1.12: sleep less:
1020         //sleep(1);
1021         usleep_until(time_usec() + 500000);
1022 
1023         if (stat(fname, &statbuf))
1024           groesse2 = -1;
1025         else
1026           groesse2 = statbuf.st_size;
1027         if (groesse1 != groesse2)
1028           found = 0;
1029       }
1030 
1031       if (!found && lock)
1032         unlockfile(fname);
1033     }
1034 
1035     closedir(dirdata);
1036 
1037     break;
1038   }
1039 
1040   if (!found)
1041     *filename = 0;
1042   else
1043   {
1044     strcpy(filename, fname);
1045 
1046     // 3.1.12:
1047     i = (int)(time_usec() - start_time) / 100000;
1048     if (i > 10)
1049       writelogfile((i >= 50)? LOG_NOTICE : LOG_DEBUG, 0, "Took %.1f seconds to get a file %s, lost %i times, %i SMS files and %i LOCK files seen.", (double)i / 10, fname, lost_count, files_count, locked_count);
1050   }
1051 
1052 #ifdef DEBUGMSG
1053   printf("## result for dir %s: %s\n\n", dir, filename);
1054 #endif
1055   return found;
1056 }
1057 
my_system(char * command,char * info)1058 int my_system(
1059 	//
1060 	// Executes an external process.
1061 	//
1062 	char *command,
1063 	char *info
1064 )
1065 {
1066 	int pid;
1067 	int status;
1068 	time_t start_time;
1069 	char *p;
1070 	char tmp1[PATH_MAX];
1071 	char tmp2[PATH_MAX];
1072 
1073 	// Cannot contain "(" when passed as an argument
1074 
1075 	// 3.1.16beta: Use tmpdir:
1076 	//snprintf(tmp1, sizeof(tmp1), ">%s/smsd_%s_1.XXXXXX", "/tmp", info);
1077 	snprintf(tmp1, sizeof(tmp1), ">%s/smsd_%s_1.XXXXXX", tmpdir, info);
1078 	while ((p = strchr(tmp1, '(')))
1079 		*p = '.';
1080 	while ((p = strchr(tmp1, ')')))
1081 		*p = '.';
1082 	while ((p = strchr(tmp1, ' ')))
1083 		*p = '-';
1084 
1085 	// 3.1.16beta: Use tmpdir:
1086 	//snprintf(tmp2, sizeof(tmp2), "2>%s/smsd_%s_2.XXXXXX", "/tmp", info);
1087 	snprintf(tmp2, sizeof(tmp2), "2>%s/smsd_%s_2.XXXXXX", tmpdir, info);
1088 	while ((p = strchr(tmp2, '(')))
1089 		*p = '.';
1090 	while ((p = strchr(tmp2, ')')))
1091 		*p = '.';
1092 	while ((p = strchr(tmp2, ' ')))
1093 		*p = '-';
1094 
1095 	if (!ignore_exec_output) // 3.1.7
1096 	{
1097 		close(mkstemp(tmp1 + 1));
1098 		close(mkstemp(tmp2 + 2));
1099 	}
1100 
1101 	start_time = time(0);
1102 #ifdef DEBUGMSG
1103 	printf("!! my_system(%s, %s)\n", command, info);
1104 #endif
1105 	writelogfile0(LOG_DEBUG, 0, tb_sprintf("Running %s: %s", info, command));
1106 
1107 	pid = fork();
1108 	if (pid == -1)
1109 	{
1110 		// 3.1.12:
1111 		//writelogfile0(LOG_CRIT, 0, tb_sprintf("Fatal error: fork failed."));
1112 		writelogfile0(LOG_CRIT, 0, tb_sprintf("Fatal error: fork failed. %i, %s", errno, strerror(errno)));
1113 
1114 		return -1;
1115 	}
1116 
1117 	if (pid == 0)		// only executed in the child
1118 	{
1119 		char *argv[4];
1120 		char *cmd = 0;
1121 
1122 #ifdef DEBUGMSG
1123 		printf("!! pid=%i, child running external command\n", pid);
1124 #endif
1125 
1126 		// TODO: sh still ok?
1127 		argv[0] = "sh";
1128 		if ((p = strrchr(shell, '/')))
1129 			argv[0] = p + 1;
1130 
1131 		argv[1] = "-c";
1132 		argv[2] = command;	//(char*) command;
1133 
1134 		if (!ignore_exec_output)
1135 		{
1136 			if ((cmd = (char *) malloc(strlen(command) + strlen(tmp1) + strlen(tmp2) + 3)))
1137 			{
1138 				sprintf(cmd, "%s %s %s", command, tmp1, tmp2);
1139 				argv[2] = cmd;
1140 			}
1141 		}
1142 
1143 		argv[3] = 0;
1144 
1145 		// 3.1.5:
1146 		//execv("/bin/sh",argv);  // replace child with the external command
1147 		execv(shell, argv);	// replace child with the external command
1148 		writelogfile0(LOG_CRIT, 1, tb_sprintf("Fatal error: execv( %s ) returned: %i, %s", shell, errno, strerror(errno)));
1149 
1150 		free(cmd);
1151 
1152 #ifdef DEBUGMSG
1153 		printf("!! pid=%i, execv() failed, %i, %s\n", pid, errno, strerror(errno));
1154 		printf("!! child exits now\n");
1155 #endif
1156 		exit((errno) ? errno : 1);	// exit with error when the execv call failed
1157 	}
1158 
1159 	errno = 0;
1160 #ifdef DEBUGMSG
1161 	printf("!! father waiting for child %i\n", pid);
1162 #endif
1163 	snprintf(run_info, sizeof(run_info), "%s", info);
1164 
1165 	while (1)
1166 	{
1167 		if (waitpid(pid, &status, 0) == -1)
1168 		{
1169 			if (errno != EINTR)
1170 			{
1171 				*run_info = 0;
1172 				// 3.1.21: Fixed time_t argument to int.
1173 				writelogfile0(LOG_ERR, 0, tb_sprintf("Done: %s, execution time %i sec., errno: %i, %s", info, (int)(time(0) - start_time), errno, strerror(errno)));
1174 				return -1;
1175 			}
1176 		}
1177 		else
1178 		{
1179 			int level = LOG_DEBUG;
1180 			int trouble = 0;
1181 
1182 			*run_info = 0;
1183 
1184 			// 3.1.6: When running checkhandler and it spooled a message, return value 2 SHOULD NOT activate trouble logging:
1185 			//writelogfile0((status == 0) ? LOG_DEBUG : LOG_ERR, (status == 0) ? 0 : 1, tb_sprintf("Done: %s, execution time %i sec., status: %i", info, time(0) - start_time, status));
1186 			if (!strcmp(info, "checkhandler"))
1187 			{
1188 				if (status != 0 && WEXITSTATUS(status) != 2)
1189 				{
1190 					level = LOG_ERR;
1191 					trouble = 1;
1192 				}
1193 			}
1194 			else if (status != 0)
1195 			{
1196 				level = LOG_ERR;
1197 				trouble = 1;
1198 			}
1199 
1200 			// 3.1.21: Fixed time_t argument to int.
1201 			writelogfile0(level, trouble, tb_sprintf("Done: %s, execution time %i sec., status: %i (%i)", info, (int)(time(0) - start_time), status, WEXITSTATUS(status)));
1202 
1203 			if (!ignore_exec_output)
1204 			{
1205 				struct stat statbuf;
1206 				FILE *fp;
1207 				char line[2048];
1208 				int i;
1209 				char *p;
1210 
1211 				for (i = 1; i <= 2; i++)
1212 				{
1213 					p = (i == 1) ? tmp1 + 1 : tmp2 + 2;
1214 
1215 					if (stat(p, &statbuf) == 0)
1216 					{
1217 						if (statbuf.st_size)
1218 						{
1219 							writelogfile0(LOG_ERR, 1, tb_sprintf("Exec: %s %s:", info, (i == 1) ? "said something" : "encountered errors"));
1220 							if ((fp = fopen(p, "r")))
1221 							{
1222 								while (fgets(line, sizeof(line), fp))
1223 								{
1224 									while (strlen(line) > 1 && strchr("\r\n", line[strlen(line) - 1]))
1225 										line[strlen(line) - 1] = 0;
1226 
1227 									writelogfile0(LOG_ERR, 1, tb_sprintf("! %s", line));
1228 								}
1229 								fclose(fp);
1230 							}
1231 						}
1232 
1233 						unlink(p);
1234 					}
1235 				}
1236 			}
1237 
1238 			return WEXITSTATUS(status);
1239 		}
1240 	}
1241 }
1242 
write_pid(char * filename)1243 int write_pid( char* filename)
1244 {
1245   char pid[20];
1246   int pidfile;
1247 
1248   sprintf(pid,"%i\n", (int)getpid());
1249   pidfile = open(filename, O_CREAT|O_WRONLY|O_TRUNC, 0644);
1250   if (pidfile >= 0)
1251   {
1252     write(pidfile, pid, strlen(pid));
1253     close(pidfile);
1254     return 1;
1255   }
1256   return 0;
1257 }
1258 
check_pid(char * filename)1259 int check_pid(char *filename)
1260 {
1261   int result = 0;
1262   char pid[20];
1263   FILE *fp;
1264   char buffer[256];
1265 
1266   sprintf(pid,"%i\n", (int)getpid());
1267   if ((fp = fopen(filename, "r")))
1268   {
1269     if (fgets(buffer, sizeof(buffer), fp))
1270       if (strcmp(pid, buffer))
1271         result = atoi(buffer);
1272 
1273     fclose(fp);
1274   }
1275 
1276   return result;
1277 }
1278 
remove_pid(char * filename)1279 void remove_pid( char* filename)
1280 {
1281   if (*filename)
1282     unlink(filename);
1283 }
1284 
parse_validity(char * value,int defaultvalue)1285 int parse_validity(char *value, int defaultvalue)
1286 {
1287   int result = defaultvalue;
1288   char buffer[100];
1289   int i;
1290   char tmp[100];
1291   int got_numbers = 0;
1292   int got_letters = 0;
1293   int idx;
1294   char *p;
1295 
1296   if (value && *value)
1297   {
1298     // n min, hour, day, week, month, year
1299     // 3.0.9: if only keyword is given, insert number 1.
1300     // Fixed number without keyword handling.
1301     // Convert to lowercase so upcase is also accepted.
1302 
1303     *buffer = 0;
1304     snprintf(tmp, sizeof(tmp), "%s", value);
1305     cutspaces(tmp);
1306     for (idx = 0; tmp[idx]; idx++)
1307     {
1308       tmp[idx] = tolower((int)tmp[idx]);
1309       if (tmp[idx] == '\t')
1310         tmp[idx] = ' ';
1311       if (isdigitc(tmp[idx]))
1312         got_numbers = 1;
1313       else
1314         got_letters = 1;
1315     }
1316 
1317     if (got_numbers && !got_letters)
1318     {
1319       i = atoi(tmp);
1320       if (i >= 0 && i <= 255)
1321         result = i;
1322       return result;
1323     }
1324 
1325     if ((p = strchr(tmp, ' ')))
1326       *p = 0;
1327 
1328     if (strstr("min hour day week month year", tmp))
1329       sprintf(buffer, "1 %.*s", (int)sizeof(buffer) -3, tmp);
1330     else
1331       sprintf(buffer, "%.*s", (int)sizeof(buffer) -1, value);
1332 
1333     while ((i = atoi(buffer)) > 0)
1334     {
1335       // 0 ... 143     (value + 1) * 5 minutes (i.e. 5 minutes intervals up to 12 hours)
1336       if (strstr(buffer, "min"))
1337       {
1338         if (i <= 720)
1339         {
1340           result = (i < 5)? 0 : i /5 -1;
1341           break;
1342         }
1343         sprintf(buffer, "%i hour", i /= 60);
1344       }
1345 
1346       // 144 ... 167   12 hours + ((value - 143) * 30 minutes) (i.e. 30 min intervals up to 24 hours)
1347       if (strstr(buffer, "hour"))
1348       {
1349         if (i <= 12)
1350         {
1351           sprintf(buffer, "%i min", i *60);
1352           continue;
1353         }
1354         if (i <= 24)
1355         {
1356           result = (i -12) *2 +143;
1357           break;
1358         }
1359         sprintf(buffer, "%i day", i /= 24);
1360       }
1361 
1362       // 168 ... 196   (value - 166) * 1 day (i.e. 1 day intervals up to 30 days)
1363       if (strstr(buffer, "day"))
1364       {
1365         if (i < 2)
1366         {
1367           sprintf(buffer, "24 hour");
1368           continue;
1369         }
1370         if (i <= 34)
1371         {
1372           result = (i <= 30)? i +166 : 30 +166;
1373           break;
1374         }
1375         sprintf(buffer, "%i week", i /= 7);
1376       }
1377 
1378       // 197 ... 255   (value - 192) * 1 week (i.e. 1 week intervals up to 63 weeks)
1379       if (strstr(buffer, "week"))
1380       {
1381         if (i < 5)
1382         {
1383           sprintf(buffer, "%i day", i *7);
1384           continue;
1385         }
1386         result = (i <= 63)? i +192 : 255;
1387         break;
1388       }
1389 
1390       if (strstr(buffer, "month"))
1391       {
1392         sprintf(buffer, "%i day", (i == 12)? 365 : i *30);
1393         continue;
1394       }
1395 
1396       if (strstr(buffer, "year"))
1397       {
1398         if (i == 1)
1399         {
1400           sprintf(buffer, "52 week");
1401           continue;
1402         }
1403         result = 255;
1404       }
1405 
1406       break;
1407     }
1408   }
1409 
1410   return result;
1411 }
1412 
1413 // 0=invalid, 1=valid
report_validity(char * buffer,int validity_period)1414 int report_validity(char *buffer, int validity_period)
1415 {
1416   int result = 0;
1417   int n;
1418   char *p;
1419 
1420   if (validity_period < 0 || validity_period > 255)
1421     sprintf(buffer, "invalid (%i)", validity_period);
1422   else
1423   {
1424     if (validity_period <= 143)
1425     {
1426       // 0 ... 143    (value + 1) * 5 minutes (i.e. 5 minutes intervals up to 12 hours)
1427       n = (validity_period +1) *5;
1428       p = "min";
1429     }
1430     else if (validity_period <= 167)
1431     {
1432       // 144 ... 167  12 hours + ((value - 143) * 30 minutes) (i.e. 30 min intervals up to 24 hours)
1433       n =  12 +(validity_period -143) /2;
1434       p = "hour";
1435     }
1436     else if (validity_period <= 196)
1437     {
1438       // 168 ... 196  (value - 166) * 1 day (i.e. 1 day intervals up to 30 days)
1439       n = validity_period -166;
1440       p = "day";
1441     }
1442     else
1443     {
1444       // 197 ... 255  (value - 192) * 1 week (i.e. 1 week intervals up to 63 weeks)
1445       n = validity_period -192;
1446       p = "week";
1447     }
1448 
1449     sprintf(buffer, "%i %s%s (%i)", n, p, (n > 1)? "s" : "", validity_period);
1450     result = 1;
1451   }
1452 
1453   return result;
1454 }
1455 
getrand(int toprange)1456 int getrand(int toprange)
1457 {
1458   srand((int)(time(NULL) * getpid()));
1459   return (rand() % toprange) +1;
1460 }
1461 
is_executable(char * filename)1462 int is_executable(char *filename)
1463 {
1464   // access() migth do this easier, but in Gygwin it returns 0 even when requested permissions are NOT granted.
1465   int executable = 0;
1466   struct stat statbuf;
1467   mode_t mode;
1468   int n, i;
1469   gid_t *g;
1470 
1471   // 3.1.20: Should also check if filename is a directory. It can be executable but it's not a script.
1472   // Return value now: 0 = ok, 1 = not exists, 2 = is a directory, 3 = not executable
1473 
1474   if (stat(filename, &statbuf) < 0)
1475     return 1;
1476 
1477   if (S_ISDIR(statbuf.st_mode))
1478     return 2;
1479 
1480   mode = statbuf.st_mode & 0755;
1481 
1482   if (getuid())
1483   {
1484     if (statbuf.st_uid != getuid())
1485     {
1486       if ((n = getgroups(0, NULL)) > 0)
1487       {
1488         if ((g = (gid_t *)malloc(n * sizeof(gid_t))))
1489         {
1490           if ((n = getgroups(n, g)) > 0)
1491           {
1492             for (i = 0; (i < n) & (!executable); i++)
1493               if (g[i] == statbuf.st_gid)
1494                 executable = 1;
1495           }
1496           free(g);
1497         }
1498       }
1499 
1500       if (executable)
1501       {
1502         if ((mode & 050) != 050)
1503           executable = 0;
1504       }
1505       else if ((mode & 05) == 05)
1506         executable = 1;
1507     }
1508     else if ((mode & 0500) == 0500)
1509       executable = 1;
1510   }
1511   else if ((mode & 0100) || (mode & 010) || (mode & 01))
1512     executable = 1;
1513 
1514   return (executable)? 0 : 3;
1515 }
1516 
check_access(char * filename)1517 int check_access(char *filename)
1518 {
1519   // access() migth do this easier, but in Gygwin it returns 0 even when requested permissions are NOT granted.
1520   int result = 0;
1521   struct stat statbuf;
1522   mode_t mode;
1523   int n, i;
1524   gid_t *g;
1525 
1526   if (stat(filename, &statbuf) >= 0)
1527   {
1528     mode = statbuf.st_mode; // & 0777;
1529 
1530     if (getuid())
1531     {
1532       if (statbuf.st_uid != getuid())
1533       {
1534         if ((n = getgroups(0, NULL)) > 0)
1535         {
1536           if ((g = (gid_t *)malloc(n * sizeof(gid_t))))
1537           {
1538             if ((n = getgroups(n, g)) > 0)
1539             {
1540               for (i = 0; (i < n) & (!result); i++)
1541                 if (g[i] == statbuf.st_gid)
1542                   result = 1;
1543             }
1544             free(g);
1545           }
1546         }
1547 
1548         if (result)
1549         {
1550           if ((mode & 060) != 060)
1551             result = 0;
1552         }
1553         else if ((mode & 06) == 06)
1554           result = 1;
1555       }
1556       else if ((mode & 0600) == 0600)
1557         result = 1;
1558     }
1559     else if ((mode & 0200) || (mode & 020) || (mode & 02))
1560       result = 1;
1561   }
1562 
1563   return result;
1564 }
1565 
value_in(int value,int arg_count,...)1566 int value_in(int value, int arg_count, ...)
1567 {
1568   int result = 0;
1569   va_list ap;
1570 
1571   va_start(ap, arg_count);
1572   for (; arg_count > 0; arg_count--)
1573     if (value == va_arg(ap, int))
1574       result = 1;
1575 
1576   va_end(ap);
1577 
1578   return result;
1579 }
1580 
t_sleep(int seconds)1581 int t_sleep(int seconds)
1582 {
1583   // 3.1.12: When a signal handler is installed, receiving of any singal causes
1584   // that functions sleep() and usleep() will return immediately.
1585   //int i;
1586   time_t t;
1587 
1588   t = time(0);
1589   //for (i = 0; i < seconds; i++)
1590   while (time(0) - t < seconds)
1591   {
1592     if (terminate)
1593       return 1;
1594 
1595     sleep(1);
1596   }
1597 
1598   return 0;
1599 }
1600 
usleep_until(unsigned long long target_time)1601 int usleep_until(unsigned long long target_time)
1602 {
1603   struct timeval tv;
1604   struct timezone tz;
1605   unsigned long long now;
1606 
1607   // 3.1.16beta, 3.1.17: Sleep more and less often to reduce CPU load (100 --> 10000 max).
1608   for (;;)
1609   {
1610     gettimeofday(&tv, &tz);
1611     now = (unsigned long long)tv.tv_sec *1000000 +tv.tv_usec;
1612 
1613     if (terminate == 1)
1614       return 1;
1615 
1616     if (now >= target_time)
1617       break;
1618 
1619     if (now +10000 < target_time)
1620       usleep(10000);
1621     else
1622       usleep(target_time -now);
1623   }
1624 
1625   return 0;
1626 }
1627 
time_usec()1628 unsigned long long time_usec()
1629 {
1630   struct timeval tv;
1631   struct timezone tz;
1632   //struct tm *tm;
1633 
1634   gettimeofday(&tv, &tz);
1635   /*tm =*/ //localtime(&tv.tv_sec);
1636 
1637   return (unsigned long long)tv.tv_sec *1000000 +tv.tv_usec;
1638 }
1639 
make_datetime_string(char * dest,size_t dest_size,char * a_date,char * a_time,char * a_format)1640 int make_datetime_string(char *dest, size_t dest_size, char *a_date, char *a_time, char *a_format)
1641 {
1642   int result = 0;
1643   time_t rawtime;
1644   struct tm *timeinfo;
1645 
1646   //time(&rawtime);
1647 
1648   // 3.1.14:
1649   //if (!a_date && !a_time)
1650   //  return strftime(dest, dest_size, (a_format)? a_format : datetime_format, localtime(&rawtime));
1651   if (!a_date && !a_time)
1652   {
1653     struct timeval tv;
1654     struct timezone tz;
1655     char *p;
1656     char buffer[7];
1657 
1658     gettimeofday(&tv, &tz);
1659     rawtime = tv.tv_sec;
1660     timeinfo = localtime(&rawtime);
1661     result = strftime(dest, dest_size, (a_format)? a_format : datetime_format, timeinfo);
1662 
1663     if ((p = strstr(dest, "timeus")))
1664     {
1665       snprintf(buffer, sizeof(buffer), "%06d", (int)tv.tv_usec);
1666       strncpy(p, buffer, strlen(buffer));
1667     }
1668     else if ((p = strstr(dest, "timems")))
1669     {
1670       snprintf(buffer, sizeof(buffer), "%03d", (int)tv.tv_usec / 1000);
1671       strncpy(p, buffer, strlen(buffer));
1672       memmove(p + 3, p + 6, strlen(p + 6) + 1);
1673     }
1674 
1675     return result;
1676   }
1677 
1678   if (a_date && strlen(a_date) >= 8 && a_time && strlen(a_time) >= 8)
1679   {
1680     time(&rawtime);
1681 
1682     timeinfo = localtime(&rawtime);
1683     timeinfo->tm_year = atoi(a_date) + 100;
1684     timeinfo->tm_mon = atoi(a_date + 3) - 1;
1685     timeinfo->tm_mday = atoi(a_date + 6);
1686     timeinfo->tm_hour = atoi(a_time);
1687     timeinfo->tm_min = atoi(a_time + 3);
1688     timeinfo->tm_sec = atoi(a_time + 6);
1689     // ?? mktime(timeinfo);
1690     result = strftime(dest, dest_size, (a_format)? a_format : datetime_format, timeinfo);
1691   }
1692 
1693   return result;
1694 }
1695 
strcat_realloc(char ** buffer,char * str,char * delimiter)1696 void strcat_realloc(char **buffer, char *str, char *delimiter)
1697 {
1698   int delimiter_length = 0;
1699 
1700   if (delimiter)
1701     delimiter_length = strlen(delimiter);
1702 
1703   if (*buffer == 0)
1704   {
1705     if ((*buffer = (char *) malloc(strlen(str) + delimiter_length + 1)))
1706       **buffer = 0;
1707   }
1708   else
1709     *buffer = (char *) realloc((void *) *buffer, strlen(*buffer) + strlen(str) + delimiter_length + 1);
1710 
1711   if (*buffer)
1712     sprintf(strchr(*buffer, 0), "%s%s", str, (delimiter) ? delimiter : "");
1713 }
1714 
strcpyo(char * dest,const char * src)1715 char *strcpyo(char *dest, const char *src)
1716 {
1717   size_t i;
1718 
1719   for (i = 0; src[i] != '\0'; i++)
1720     dest[i] = src[i];
1721 
1722   dest[i] = '\0';
1723 
1724   return dest;
1725 }
1726 
getfield(char * line,int field,char * result,int size)1727 void getfield(char* line, int field, char* result, int size)
1728 {
1729   char* start;
1730   char* end;
1731   int i;
1732   int length;
1733 
1734 #ifdef DEBUGMSG
1735   printf("!! getfield(line=%s, field=%i, ...)\n",line,field);
1736 #endif
1737   if (size < 1)
1738     return;
1739 
1740   *result=0;
1741   start=strstr(line,":");
1742   if (start==0)
1743     return;
1744   for (i=1; i<field; i++)
1745   {
1746     start=strchr(start+1,',');
1747     if (start==0)
1748       return;
1749   }
1750   start++;
1751   while (start[0]=='\"' || start[0]==' ')
1752     start++;
1753   if (start[0]==0)
1754     return;
1755   end=strstr(start,",");
1756   if (end==0)
1757     end=start+strlen(start)-1;
1758   while ((end[0]=='\"' || end[0]=='\"' || end[0]==',') && (end>=start))
1759     end--;
1760   length=end-start+1;
1761   if (length >= size)
1762     return;
1763   strncpy(result,start,length);
1764   result[length]=0;
1765 #ifdef DEBUGMSG
1766   printf("!! result=%s\n",result);
1767 #endif
1768 }
1769 
1770 // 3.1.16beta:
make_uptime_string(char * dest,size_t dest_size,time_t upt)1771 int make_uptime_string(char *dest, size_t dest_size, time_t upt)
1772 {
1773   int result = 0;
1774   time_t day;
1775   char tmp[16];
1776 
1777   day = 60 * 60 * 24;
1778   if (upt < day)
1779   {
1780     if (upt >= 60 * 60)
1781     {
1782       strftime(tmp, sizeof(tmp), "%H:%M", gmtime(&upt));
1783       snprintf(dest, dest_size, "%s", (*tmp == '0')? tmp + 1 : tmp);
1784     }
1785     else
1786       snprintf(dest, dest_size, "%i min", (int)upt / 60);
1787   }
1788   else
1789   {
1790     int days;
1791 
1792     days = (int)upt / day;
1793     snprintf(dest, dest_size, "%i day%s, ", days, (days > 1)? "s" : "");
1794     upt -= days * day;
1795     if (upt >= 60 * 60)
1796     {
1797       strftime(tmp, sizeof(tmp), "%H:%M", gmtime(&upt));
1798       snprintf(dest + strlen(dest), dest_size - strlen(dest), "%s", (*tmp == '0')? tmp + 1 : tmp);
1799     }
1800     else
1801       snprintf(dest + strlen(dest), dest_size - strlen(dest), "%i min", (int)upt / 60);
1802   }
1803 
1804   return result;
1805 }
1806 
1807 // 3.1.16beta:
is_ok_answer(char * answer)1808 int is_ok_answer(char *answer)
1809 {
1810   if (strstr(answer, "OK"))
1811     return 1;
1812   return 0;
1813 }
1814 
is_error_answer(char * answer)1815 int is_error_answer(char *answer)
1816 {
1817   if (strstr(answer, "ERROR"))
1818     return 1;
1819   return 0;
1820 }
1821 
is_ok_0_answer(char * answer)1822 int is_ok_0_answer(char *answer)
1823 {
1824   if (is_ok_answer(answer) || strstr(answer, "0"))
1825     return 1;
1826   return 0;
1827 }
1828 
is_error_4_answer(char * answer)1829 int is_error_4_answer(char *answer)
1830 {
1831   if (is_error_answer(answer) || strstr(answer, "4"))
1832     return 1;
1833   return 0;
1834 }
1835 
is_ok_error_answer(char * answer)1836 int is_ok_error_answer(char *answer)
1837 {
1838   if (is_ok_answer(answer) || is_error_answer(answer))
1839     return 1;
1840   return 0;
1841 }
1842 
is_ok_error_0_4_answer(char * answer)1843 int is_ok_error_0_4_answer(char *answer)
1844 {
1845   if (is_ok_0_answer(answer) || is_error_4_answer(answer))
1846     return 1;
1847   return 0;
1848 }
1849 
get_file_details(char * filename,char * dest,size_t dest_size)1850 int get_file_details(char *filename, char *dest, size_t dest_size)
1851 {
1852   struct stat statbuf;
1853 
1854   if (dest)
1855     *dest = 0;
1856 
1857   if (stat(filename, &statbuf) == 0)
1858   {
1859     if (dest)
1860     {
1861       time_t t = statbuf.st_mtime;
1862       struct tm *timeinfo;
1863       char timestamp[81];
1864 
1865       timeinfo = localtime(&t);
1866       strftime(timestamp, sizeof(timestamp), datetime_format, timeinfo);
1867 
1868       snprintf(dest, dest_size, "%s 0%o/%c%c%c%c%c%c%c%c%c%c %u %u:%u %u",
1869                timestamp,
1870                0777 & statbuf.st_mode,
1871                (S_ISDIR(statbuf.st_mode))? 'd' : '-',
1872                (statbuf.st_mode & S_IRUSR)? 'r' : '-',
1873                (statbuf.st_mode & S_IWUSR)? 'w' : '-',
1874                (statbuf.st_mode & S_IXUSR)? 'x' : '-',
1875                (statbuf.st_mode & S_IRGRP)? 'r' : '-',
1876                (statbuf.st_mode & S_IWGRP)? 'w' : '-',
1877                (statbuf.st_mode & S_IXGRP)? 'x' : '-',
1878                (statbuf.st_mode & S_IROTH)? 'r' : '-',
1879                (statbuf.st_mode & S_IWOTH)? 'w' : '-',
1880                (statbuf.st_mode & S_IXOTH)? 'x' : '-',
1881                (int)statbuf.st_ino, statbuf.st_uid, statbuf.st_gid, (int)statbuf.st_size);
1882     }
1883 
1884     return 1;
1885   }
1886 
1887   return 0;
1888 }
1889 
1890 // 3.1.16beta2:
calculate_required_parts(char * text,int textlen,int * reserved,int split,int * use_get_part)1891 int calculate_required_parts(char *text, int textlen, int *reserved, int split, int *use_get_part)
1892 {
1893   int result = 0;
1894   int chars = 0;
1895 
1896   // text is in GSM alphabet.
1897   // If more than one part is required, should not split right after esc character.
1898 
1899   if (use_get_part)
1900     *use_get_part = 0;
1901 
1902   if (textlen <= maxsms_pdu - *reserved)
1903     return 1;
1904 
1905   if (split == 3)
1906   {
1907     if (*reserved == 0)
1908       *reserved = 7;
1909     else if (*reserved == 8)
1910       *reserved = 14;
1911     else
1912       *reserved = 11;
1913   }
1914 
1915   while (chars < textlen)
1916   {
1917     chars += maxsms_pdu - *reserved;
1918     if (chars <= textlen && text[chars -1] == 0x1B)
1919       chars--;
1920 
1921     result++;
1922   }
1923 
1924   if (result > 1 && use_get_part)
1925     *use_get_part = 1;
1926 
1927   return result;
1928 }
1929 
get_part(char ** part_start,char * text,int textlen,int reserved,int part)1930 int get_part(char **part_start, char *text, int textlen, int reserved, int part)
1931 {
1932   int length;
1933   char *start = text;
1934 
1935   while (textlen > 0)
1936   {
1937     length = (textlen > maxsms_pdu -reserved)? maxsms_pdu -reserved : textlen;
1938 
1939     if (length > 1 && start[length -1] == 0x1B)
1940       length--;
1941 
1942     textlen -= length;
1943 
1944     if (!part)
1945     {
1946       if (part_start)
1947         *part_start = start;
1948       return length;
1949     }
1950 
1951     part--;
1952     start += length;
1953   }
1954 
1955   return 0;
1956 }
1957 
spend_delay(int delaytime,int (* cb)(time_t *),time_t * cb_last,int cb_interval)1958 int spend_delay(int delaytime, int (*cb)(time_t *), time_t *cb_last, int cb_interval)
1959 {
1960   if (!terminate && !break_workless_delay &&
1961       delaytime > 0)
1962   {
1963     time_t targettime = time(0) + delaytime;
1964     time_t target_cb;
1965     time_t time_to_sleep;
1966 
1967     if (*cb_last > 0 && cb_interval > 0 && *cb_last + cb_interval - time(0) > 0)
1968     {
1969       while (!terminate && !break_workless_delay &&
1970              (target_cb = *cb_last + cb_interval) <= targettime)
1971       {
1972         while (!terminate && !break_workless_delay &&
1973                (time_to_sleep = target_cb - time(0)) > 0)
1974           sleep(time_to_sleep);
1975 
1976         if (!terminate)
1977           if (!cb(cb_last))
1978             return 0;
1979       }
1980     }
1981 
1982     while (!terminate && !break_workless_delay &&
1983            (time_to_sleep = targettime - time(0)) > 0)
1984       sleep(time_to_sleep);
1985 
1986     if (!terminate)
1987       if (!cb(cb_last))
1988         return 0;
1989   }
1990 
1991   return 1;
1992 }
1993