Import ezmlm-idx 0.40
[ezmlm] / ezmlm-tstdig.c
1 /*$Id: ezmlm-tstdig.c,v 1.17 1999/03/20 16:43:42 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
3
4 #include <sys/types.h>
5 #include "stralloc.h"
6 #include "substdio.h"
7 #include "readwrite.h"
8 #include "strerr.h"
9 #include "sig.h"
10 #include "getconf.h"
11 #include "env.h"
12 #include "fmt.h"
13 #include "now.h"
14 #include "lock.h"
15 #include "sgetopt.h"
16 #include "errtxt.h"
17 #include "idx.h"
18
19 #define FATAL "ezmlm-tstdig: fatal: "
20
21 void die_usage()
22 {
23 strerr_die1x(100,"ezmlm-tstdig: usage: ezmlm-tstdig [-k kbytes] [-m messages] [-t hours] dir");
24 }
25
26 void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
27
28 stralloc line = {0};
29
30 substdio ssnum;
31 char numbuf[16];
32
33 char strnum[FMT_ULONG];
34
35 int flaglocal = 0;
36
37 void main(argc,argv)
38 int argc;
39 char **argv;
40 {
41 char *dir;
42 char *local;
43 char *def;
44 int opt;
45 unsigned int pos;
46 unsigned long num, digsize, dignum;
47 unsigned long cumsize = 0L;
48 unsigned long deltanum = 0L;
49 unsigned long deltawhen = 0L;
50 unsigned long deltasize = 0L;
51 unsigned long when, tsttime, digwhen;
52 int fd,fdlock;
53
54 (void) umask(022);
55 sig_pipeignore();
56 when = (unsigned long) now();
57
58 while ((opt = getopt(argc,argv,"k:t:m:vV")) != opteof)
59 switch(opt) {
60 case 'k':
61 if (optarg)
62 scan_ulong(optarg,&deltasize);
63 break;
64 case 't':
65 if (optarg) /* hours */
66 scan_ulong(optarg,&deltawhen);
67 break;
68 case 'm':
69 if (optarg)
70 scan_ulong(optarg,&deltanum);
71 break;
72 case 'v':
73 case 'V': strerr_die2x(0,"ezmlm-tstdig version: ",EZIDX_VERSION);
74 default:
75 die_usage();
76 }
77
78
79 dir = argv[optind++];
80 if (!dir) die_usage();
81
82 if (chdir(dir) == -1)
83 strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
84
85 if (argv[optind])
86 die_usage(); /* avoid common error of putting options after dir */
87 if (!getconf_line(&line,"num",0,FATAL,dir))
88 _exit(99); /* no msgs no shirt -> no digest */
89 if(!stralloc_0(&line)) die_nomem();
90 pos = scan_ulong(line.s,&num);
91 if (line.s[pos] == ':')
92 scan_ulong(line.s+pos+1,&cumsize);
93
94 if (getconf_line(&line,"dignum",0,FATAL,dir)) {
95 if(!stralloc_0(&line)) die_nomem();
96 pos = scan_ulong(line.s,&dignum);
97 if (line.s[pos] == ':')
98 pos += 1 + scan_ulong(line.s+pos+1,&digsize);
99 if (line.s[pos] == ':')
100 scan_ulong(line.s+pos+1,&digwhen);
101 } else {
102 dignum = 0L; /* no file, not done any digest */
103 digsize = 0L; /* nothing digested */
104 digwhen = 0L; /* will force a digest, but the last one was eons */
105 /* ago. ezmlm-get sends it out only if there are */
106 /* messages. This is as it should for new lists. */
107 }
108 local = env_get("LOCAL");
109 if (local && *local) { /* in editor or manager */
110 def = env_get("DEFAULT");
111 if (def && *def) { /* qmail>=1.02 and manager */
112 if (!case_starts(def,"dig") || case_starts(def,"digest-"))
113 _exit(0);
114 } else { /* older qmail versions or editor */
115 if (!getconf_line(&line,"inlocal",0,FATAL,dir)) {
116 flaglocal = 1;
117 } else {
118 pos = str_len(local);
119 if (pos <= line.len) { /* maybe qmail>=1.02 and editor */
120 flaglocal = 1; /* editor and qmail>=1.02. No harm */
121 /* if we're wrong */
122 } else { /* older qmail */
123 if (case_diffb(local,line.len,line.s)) /* local */
124 flaglocal = 1; /* minimal harm */
125 else if (pos < line.len +4 || /* in manager and non-digest */
126 !case_starts(local+line.len,"-dig"))
127 _exit(0);
128 else if (case_starts(local+line.len,"-digest-"))
129 _exit(0);
130 }
131 }
132 }
133 }
134
135 if (!deltawhen && !deltasize && !deltanum) _exit(0);
136 if ((deltawhen && ((digwhen + deltawhen * 3600L) <= when)) ||
137 (deltasize && ((digsize + (deltasize << 2)) <= cumsize)) ||
138 (deltanum && ((dignum + deltanum) <= num))) { /* digest! */
139 if (flaglocal) { /* avoid multiple digests. Of course, ezmlm-tstdig*/
140 /* belongs in ezmlm-digest, but it's too late ....*/
141 fdlock = open_append("lock");
142 if (fdlock == -1)
143 strerr_die2sys(111,FATAL,ERR_OPEN_LOCK);
144 if (lock_ex(fdlock) == -1) {
145 close(fdlock);
146 strerr_die2sys(111,FATAL,ERR_OBTAIN_LOCK);
147 }
148 getconf_line(&line,"tstdig",0,dir,FATAL);
149 if (!stralloc_0(&line)) die_nomem();
150 scan_ulong(line.s,&tsttime); /* give digest 1 h to complete */
151 /* nobody does digests more often */
152 if ((tsttime + 3600L < when) || (tsttime <= digwhen)) {
153 fd = open_trunc("tstdign");
154 if (fd == -1)
155 strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/","tstdign",": ");
156 substdio_fdbuf(&ssnum,write,fd,numbuf,sizeof(numbuf));
157 if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,when)) == -1)
158 strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/","tstdign",": ");
159 if (substdio_puts(&ssnum,"\n") == -1)
160 strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/","tstdign",": ");
161 if (substdio_flush(&ssnum) == -1)
162 strerr_die6sys(111,FATAL,ERR_FLUSH,dir,"/","tstdign",": ");
163 if (fsync(fd) == -1)
164 strerr_die6sys(111,FATAL,ERR_SYNC,dir,"/","tstdign",": ");
165 if (close(fd) == -1)
166 strerr_die6sys(111,FATAL,ERR_CLOSE,dir,"/","tstdign",": ");
167 if (rename("tstdign","tstdig") == -1)
168 strerr_die4sys(111,FATAL,ERR_MOVE,"tstdign",": ");
169 _exit(0);
170 }
171 } else
172 _exit(0);
173 }
174 _exit(99);
175 }
176