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