Commit | Line | Data |
---|---|---|
f8beb284 MW |
1 | /*Id: ezmlm-make.c,v 1.31 1997/12/08 23:44:02 lindberg Exp lindberg $*/ |
2 | /*$Name: ezmlm-idx-040 $*/ | |
3 | ||
5b62e993 MW |
4 | #include <sys/types.h> |
5 | #include <sys/time.h> | |
6 | #include "sgetopt.h" | |
7 | #include "stralloc.h" | |
8 | #include "strerr.h" | |
9 | #include "exit.h" | |
10 | #include "readwrite.h" | |
11 | #include "open.h" | |
12 | #include "substdio.h" | |
13 | #include "str.h" | |
14 | #include "auto_bin.h" | |
f8beb284 MW |
15 | #include "getln.h" |
16 | #include "error.h" | |
17 | #include "lock.h" | |
18 | #include "errtxt.h" | |
19 | #include "idx.h" | |
20 | ||
21 | /* defaults. All other flags are false = 0 */ | |
22 | char *defflags="ap"; /* archived list -a */ | |
23 | /* public list -p */ | |
24 | /* no ezmlm-archive -I */ | |
25 | /* no text edit for remote admin -D */ | |
26 | /* not in edit mode -E */ | |
27 | /* no subs list for remote admin -L */ | |
28 | /* no remote admin -R */ | |
29 | /* no message moderation -M */ | |
30 | /* no subscription moderation -S */ | |
31 | /* don't use .ezmlmrc from dot-file dir -C */ | |
32 | /* no prefix -F */ | |
33 | /* no trailer -T */ | |
34 | ||
35 | #define NO_FLAGS ('z' - 'a' + 1) | |
36 | int flags[NO_FLAGS]; /* holds flags */ | |
37 | ||
38 | char *popt[10]; | |
39 | stralloc dotplus = {0}; | |
40 | stralloc dirplus = {0}; | |
41 | stralloc line = {0}; | |
5b62e993 MW |
42 | |
43 | #define FATAL "ezmlm-make: fatal: " | |
f8beb284 | 44 | #define WARNING "ezmlm-make: warning: " |
5b62e993 MW |
45 | |
46 | void die_usage() | |
47 | { | |
f8beb284 MW |
48 | strerr_die1x(100, |
49 | "ezmlm-make: usage: ezmlm-make [-+] [ -a..zA..Z03..9 ] dir dot local host"); | |
5b62e993 MW |
50 | } |
51 | void die_relative() | |
52 | { | |
f8beb284 | 53 | strerr_die2x(100,FATAL,ERR_SLASH); |
5b62e993 MW |
54 | } |
55 | void die_newline() | |
56 | { | |
f8beb284 | 57 | strerr_die2x(100,FATAL,ERR_NEWLINE); |
5b62e993 MW |
58 | } |
59 | void die_quote() | |
60 | { | |
f8beb284 | 61 | strerr_die2x(100,FATAL,ERR_QUOTE); |
5b62e993 MW |
62 | } |
63 | void die_nomem() | |
64 | { | |
f8beb284 MW |
65 | strerr_die2x(111,FATAL,ERR_NOMEM); |
66 | } | |
67 | ||
68 | void die_read() | |
69 | { | |
70 | strerr_die4sys(111,FATAL,ERR_READ,dirplus.s,": "); | |
5b62e993 MW |
71 | } |
72 | ||
f8beb284 MW |
73 | stralloc cmdline = {0}; |
74 | stralloc outline = {0}; | |
75 | substdio sstext; | |
76 | char textbuf[1024]; | |
77 | ||
78 | stralloc fname = {0}; /* file name */ | |
79 | stralloc oldfname = {0}; /* file name from prevoius tag */ | |
80 | stralloc dname = {0}; /* directory name */ | |
81 | stralloc lname = {0}; /* link name */ | |
82 | stralloc template = {0}; /* template file name */ | |
83 | stralloc ext1 = {0}; /* dot = dir/.qmail-ext1-ext2-list */ | |
84 | stralloc ext2 = {0}; | |
85 | stralloc f = {0}; | |
5b62e993 MW |
86 | stralloc key = {0}; |
87 | struct timeval tv; | |
f8beb284 | 88 | char sz[2] = "?"; |
5b62e993 MW |
89 | |
90 | void keyadd(u) | |
91 | unsigned long u; | |
92 | { | |
93 | char ch; | |
f8beb284 MW |
94 | ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; |
95 | ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; | |
96 | ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; | |
97 | ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); | |
5b62e993 MW |
98 | } |
99 | ||
100 | void keyaddtime() | |
101 | { | |
102 | gettimeofday(&tv,(struct timezone *) 0); | |
103 | keyadd(tv.tv_usec); | |
104 | } | |
105 | ||
106 | char *dir; | |
107 | char *dot; | |
f8beb284 MW |
108 | char *local = (char *) 0; |
109 | char *host = (char *) 0; | |
5b62e993 MW |
110 | |
111 | void dirplusmake(slash) | |
112 | char *slash; | |
113 | { | |
114 | if (!stralloc_copys(&dirplus,dir)) die_nomem(); | |
115 | if (!stralloc_cats(&dirplus,slash)) die_nomem(); | |
116 | if (!stralloc_0(&dirplus)) die_nomem(); | |
117 | } | |
118 | ||
119 | void linkdotdir(dash,slash) | |
120 | char *dash; | |
121 | char *slash; | |
122 | { | |
123 | if (!stralloc_copys(&dotplus,dot)) die_nomem(); | |
124 | if (!stralloc_cats(&dotplus,dash)) die_nomem(); | |
125 | if (!stralloc_0(&dotplus)) die_nomem(); | |
126 | dirplusmake(slash); | |
f8beb284 MW |
127 | if (flags['e' - 'a']) |
128 | if (unlink(dotplus.s) == -1) | |
129 | if (errno != error_noent) | |
130 | strerr_die4x(111,FATAL,ERR_DELETE,dotplus.s,": "); | |
5b62e993 | 131 | if (symlink(dirplus.s,dotplus.s) == -1) |
f8beb284 | 132 | strerr_die4sys(111,FATAL,ERR_CREATE,dotplus.s,": "); |
5b62e993 MW |
133 | keyaddtime(); |
134 | } | |
135 | ||
136 | void dcreate(slash) | |
137 | char *slash; | |
138 | { | |
139 | dirplusmake(slash); | |
140 | if (mkdir(dirplus.s,0755) == -1) | |
f8beb284 MW |
141 | if ((errno != error_exist) || !flags['e' - 'a']) |
142 | strerr_die4sys(111,FATAL,ERR_CREATE,dirplus.s,": "); | |
5b62e993 MW |
143 | keyaddtime(); |
144 | } | |
145 | ||
146 | substdio ss; | |
147 | char ssbuf[SUBSTDIO_OUTSIZE]; | |
148 | ||
f8beb284 | 149 | void f_open(slash) |
5b62e993 MW |
150 | char *slash; |
151 | { | |
152 | int fd; | |
153 | ||
154 | dirplusmake(slash); | |
155 | fd = open_trunc(dirplus.s); | |
156 | if (fd == -1) | |
f8beb284 | 157 | strerr_die4sys(111,FATAL,ERR_CREATE,dirplus.s,": "); |
5b62e993 MW |
158 | |
159 | substdio_fdbuf(&ss,write,fd,ssbuf,sizeof(ssbuf)); | |
160 | } | |
161 | ||
f8beb284 | 162 | void f_put(buf,len) |
5b62e993 MW |
163 | char *buf; |
164 | unsigned int len; | |
165 | { | |
166 | if (substdio_bput(&ss,buf,len) == -1) | |
f8beb284 | 167 | strerr_die4sys(111,FATAL,ERR_WRITE,dirplus.s,": "); |
5b62e993 | 168 | } |
f8beb284 | 169 | void f_puts(buf) |
5b62e993 MW |
170 | char *buf; |
171 | { | |
172 | if (substdio_bputs(&ss,buf) == -1) | |
f8beb284 | 173 | strerr_die4sys(111,FATAL,ERR_WRITE,dirplus.s,": "); |
5b62e993 MW |
174 | } |
175 | ||
f8beb284 | 176 | void f_close() |
5b62e993 MW |
177 | { |
178 | if (substdio_flush(&ss) == -1) | |
f8beb284 | 179 | strerr_die4sys(111,FATAL,ERR_FLUSH,dirplus.s,": "); |
5b62e993 | 180 | if (fsync(ss.fd) == -1) |
f8beb284 | 181 | strerr_die4sys(111,FATAL,ERR_SYNC,dirplus.s,": "); |
5b62e993 | 182 | if (close(ss.fd) == -1) /* NFS stupidity */ |
f8beb284 | 183 | strerr_die4sys(111,FATAL,ERR_CLOSE,dirplus.s,": "); |
5b62e993 MW |
184 | keyaddtime(); |
185 | } | |
186 | ||
f8beb284 MW |
187 | void frm(slash) |
188 | char *slash; | |
189 | { | |
190 | dirplusmake(slash); | |
191 | if (unlink(dirplus.s) == -1) | |
192 | if (errno != error_noent) | |
193 | strerr_die4sys(111,FATAL,ERR_DELETE,dirplus.s,": "); | |
194 | } | |
195 | ||
196 | ||
5b62e993 MW |
197 | void main(argc,argv) |
198 | int argc; | |
199 | char **argv; | |
200 | { | |
f8beb284 | 201 | unsigned long euid; |
5b62e993 | 202 | int opt; |
f8beb284 MW |
203 | int flagdo; |
204 | int flagnot; | |
205 | int flagover; | |
206 | int flagnotexist; | |
207 | int flagforce = 0; | |
208 | int flagforce_p = 0; | |
209 | int usecfg = 0; | |
210 | int match; | |
211 | unsigned int next,i,j; | |
212 | int last; | |
213 | unsigned int slpos,hashpos,pos; | |
214 | int fdin,fdlock,fdtmp; | |
215 | char *p; | |
216 | char *oldflags = (char *) 0; | |
217 | char *code = (char *) 0; | |
218 | char *cfname = (char *) 0; /* config file if spec as -C cf_file */ | |
219 | char ch; | |
5b62e993 | 220 | |
f8beb284 MW |
221 | keyadd((unsigned long) getpid()); |
222 | keyadd((unsigned long) getppid()); | |
223 | euid = (unsigned long) geteuid(); | |
224 | keyadd(euid); | |
225 | keyadd((unsigned long) getgid()); | |
5b62e993 MW |
226 | gettimeofday(&tv,(struct timezone *) 0); |
227 | keyadd(tv.tv_sec); | |
228 | ||
f8beb284 MW |
229 | (void) umask(077); |
230 | /* flags with defined use. vV for version. Others free */ | |
5b62e993 | 231 | |
f8beb284 MW |
232 | for (pos = 0; pos < (unsigned int) NO_FLAGS; pos++) { |
233 | flags[pos] = 0; | |
234 | } | |
235 | for (pos = 0; pos < 10; popt[pos++] = (char *) 0); | |
236 | ||
237 | while ((opt = getopt(argc,argv, | |
238 | "+aAbBcC:dDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0:3:4:5:6:7:8:9:")) | |
239 | != opteof) { | |
240 | if (opt == 'v' || opt == 'V') | |
241 | strerr_die2x(0,"ezmlm-make version: ezmlm-0.53+",EZIDX_VERSION); | |
242 | if (opt =='C') /* treat this like nl switch to allow override of -c*/ | |
243 | cfname = optarg; | |
244 | if (opt >= 'a' && opt <= 'z') { | |
245 | flags[opt - 'a'] = 3; /* Dominant "set" */ | |
246 | if (opt == 'e') flagforce++; /* two 'e' => ignore 'E' */ | |
247 | } else if (opt >= 'A' && opt <= 'Z') | |
248 | flags[opt - 'A'] = 2; /* Dominant "unset" */ | |
249 | else if (opt >= '0' && opt <= '9') | |
250 | popt[opt-'0'] = optarg; | |
251 | else if (opt == '+') { | |
252 | flagforce_p++; /* two '+' => ignore 'E' */ | |
253 | flags['e' - 'a'] = 3; /* -+ implies -e */ | |
254 | usecfg = 1; | |
255 | } else | |
256 | die_usage(); | |
257 | } | |
5b62e993 MW |
258 | argv += optind; |
259 | ||
f8beb284 MW |
260 | if (flagforce_p > 1 || flagforce > 1) |
261 | flagforce = 1; | |
262 | else | |
263 | flagforce = 0; | |
5b62e993 | 264 | |
f8beb284 | 265 | if (!(dir = *argv++)) die_usage(); |
5b62e993 MW |
266 | if (dir[0] != '/') die_relative(); |
267 | if (dir[str_chr(dir,'\'')]) die_quote(); | |
268 | if (dir[str_chr(dir,'\n')]) die_newline(); | |
5b62e993 | 269 | |
f8beb284 MW |
270 | if (flags['e' - 'a'] & 1) { /* lock for edit */ |
271 | dirplusmake("/lock"); | |
272 | fdlock = open_append(dirplus.s); | |
273 | if (fdlock == -1) | |
274 | strerr_die4sys(111,FATAL,ERR_OPEN,dirplus.s,": "); | |
275 | if (lock_ex(fdlock) == -1) | |
276 | strerr_die4sys(111,FATAL,ERR_OBTAIN,dirplus.s,": "); | |
277 | ||
278 | /* for edit, try to get args from dir/config */ | |
279 | dirplusmake("/config"); | |
280 | if ((fdin = open_read(dirplus.s)) == -1) { | |
281 | if (errno != error_noent) die_read(); | |
282 | } else { | |
283 | substdio_fdbuf(&sstext,read,fdin,textbuf,sizeof(textbuf)); | |
284 | for (;;) { | |
285 | if (getln(&sstext,&line,&match,'\n') == -1) die_read(); | |
286 | if (!match) break; | |
287 | if (line.s[0] == '#') continue; | |
288 | if (line.len == 1) break; | |
289 | if (line.s[1] != ':') break; | |
290 | line.s[line.len - 1] = '\0'; | |
291 | if (!stralloc_cat(&cmdline,&line)) die_nomem(); | |
292 | } | |
293 | close(fdin); | |
294 | pos = 0; | |
295 | while (pos < cmdline.len) { | |
296 | ch = cmdline.s[pos]; | |
297 | pos += 2; | |
298 | switch (ch) { | |
299 | case 'X': if (euid && !flags['c' - 'a'] && (!cfname)) | |
300 | cfname = cmdline.s + pos; /* cmdline overrides */ | |
301 | break; /* for safety: ignore if root */ | |
302 | case 'T': dot = cmdline.s + pos; break; | |
303 | case 'L': local = cmdline.s + pos; break; | |
304 | case 'H': host = cmdline.s + pos; break; | |
305 | case 'C': code = cmdline.s + pos; break; | |
306 | case 'D': break; /* no reason to check */ | |
307 | case 'F': oldflags = cmdline.s + pos; break; | |
308 | default: | |
309 | if (ch == '0' || (ch >= '3' && ch <= '9')) { | |
310 | if (usecfg && !popt[ch - '0']) | |
311 | popt[ch - '0'] = cmdline.s + pos; | |
312 | } else | |
313 | strerr_die4x(111,FATAL,dirplus.s,ERR_SYNTAX, | |
314 | cmdline.s+pos); | |
315 | break; | |
316 | } | |
317 | pos += str_len(cmdline.s + pos) + 1; | |
318 | } | |
319 | } | |
320 | } | |
5b62e993 | 321 | |
f8beb284 MW |
322 | if (p = *argv++) { |
323 | dot = p; | |
324 | if (p = *argv++) { | |
325 | if (!local || str_diff(local,p)) | |
326 | flagforce = 1; /* must rewrite if list name changed */ | |
327 | local = p; | |
328 | if (p = *argv++) { | |
329 | if (!host || str_diff(host,p)) | |
330 | flagforce = 1; /* must rewrite if list name changed */ | |
331 | host = p; | |
332 | if (p = *argv++) { | |
333 | code = p; | |
334 | } | |
335 | } | |
336 | } | |
337 | } | |
338 | if (!dot || !local || !host) die_usage(); | |
339 | if (dot[0] != '/') die_relative(); /* force absolute dot */ | |
340 | ||
341 | /* use flags from config, overridden with new values */ | |
342 | /* if there are old flags, we're in "edit" and "-+" */ | |
343 | /* Previous versions only wrote _set_ flags to */ | |
344 | /* to DIR/confiag. We need to make sure that we */ | |
345 | /* don't apply the defaults for non-specified ones! */ | |
346 | if (usecfg && oldflags && flags['e' - 'a']) { | |
347 | while ((ch = *(oldflags++))) { | |
348 | if (ch >= 'a' && ch <= 'z') { /* unset flags ignored */ | |
349 | if (ch != 'e') | |
350 | if (!flags[ch - 'a']) /* cmd line overrides */ | |
351 | flags[ch - 'a'] = 1; | |
352 | } | |
353 | } | |
354 | } | |
5b62e993 | 355 | |
f8beb284 MW |
356 | if (!usecfg) { /* apply defaults */ |
357 | while (( ch = *(defflags++))) { /* gets used up! */ | |
358 | if (ch >= 'a' && ch <= 'z') { /* defensive! */ | |
359 | if (!flags[ch - 'a']) /* cmdline still overrides */ | |
360 | flags[ch - 'a'] = 1; | |
361 | } | |
362 | } | |
363 | } | |
5b62e993 | 364 | |
f8beb284 MW |
365 | for (pos = 0; pos < (unsigned int) NO_FLAGS; pos++) { /* set real flags */ |
366 | if (flags[pos] & 2) /* 2 = "dominant" 0 */ | |
367 | flags[pos] = flags[pos] & 1; /* 3 = "dominant" 1 */ | |
5b62e993 | 368 | } |
f8beb284 MW |
369 | |
370 | if (local[str_chr(local,'\n')]) die_newline(); | |
371 | if (host[str_chr(host,'\n')]) die_newline(); | |
372 | ||
373 | /* build 'f' for <#F#> */ | |
374 | if (!stralloc_ready(&f,28)) die_nomem(); | |
375 | if (!stralloc_copys(&f,"-")) die_nomem(); | |
376 | for (ch = 0; ch <= 'z' - 'a'; ch++) { /* build string with flags */ | |
377 | if (flags[ch]) | |
378 | sz[0] = 'a' + ch; | |
379 | else | |
380 | sz[0] = 'A' + ch; | |
381 | if (!stralloc_append(&f,sz)) die_nomem(); | |
382 | } | |
383 | ||
384 | fdin = -1; /* assure failure for .ezmlmrc in case flags['c'-'a'] = 0 */ | |
385 | slpos = str_len(dot); | |
386 | while ((--slpos > 0) && dot[slpos] != '/'); | |
387 | if (dot[slpos] == '/') { | |
388 | if (!stralloc_copyb(&template,dot,slpos+1)) die_nomem(); /* dot dir */ | |
389 | slpos += str_chr(dot+slpos,'-'); | |
390 | if (dot[slpos]) { | |
391 | slpos++; | |
392 | pos = slpos + str_chr(dot+slpos,'-'); | |
393 | if (dot[pos]) { | |
394 | if (!stralloc_copyb(&ext1,dot+slpos,pos-slpos)) die_nomem(); | |
395 | pos++; | |
396 | slpos = pos + str_chr(dot+pos,'-'); | |
397 | if (dot[slpos]) | |
398 | if (!stralloc_copyb(&ext2,dot+pos,slpos-pos)) die_nomem(); | |
399 | } | |
400 | } | |
401 | } | |
402 | if (!stralloc_0(&ext1)) die_nomem(); | |
403 | if (!stralloc_0(&ext2)) die_nomem(); | |
404 | popt[1] = ext1.s; | |
405 | popt[2] = ext2.s; | |
406 | /* if 'c', template already has the dot directory. If 'C', cfname */ | |
407 | /* (if exists and != '') points to the file name to use instead. */ | |
408 | if (flags['c'-'a'] || (cfname && *cfname)) { | |
409 | if (!flags['c'-'a']) { /* i.e. there is a cfname specified */ | |
410 | if (!stralloc_copys(&template,cfname)) die_nomem(); | |
411 | } else | |
412 | if (!stralloc_cats(&template,TXT_DOTEZMLMRC)) die_nomem(); | |
413 | if (!stralloc_0(&template)) die_nomem(); | |
414 | if ((fdin = open_read(template.s)) == -1) | |
415 | if (errno != error_noent) | |
416 | strerr_die4sys(111,FATAL,ERR_OPEN,template.s,": "); | |
417 | else | |
418 | strerr_die3x(100,FATAL,template.s,ERR_NOEXIST); | |
419 | } else { /* /etc/ezmlmrc */ | |
420 | if (!stralloc_copys(&template,TXT_ETC_EZMLMRC)) die_nomem(); | |
421 | if (!stralloc_0(&template)) die_nomem(); | |
422 | if ((fdin = open_read(template.s)) == -1) | |
423 | if (errno != error_noent) | |
424 | strerr_die4sys(111,FATAL,ERR_OPEN,template.s,": "); | |
425 | else { /* ezbin/ezmlmrc */ | |
25a55efe | 426 | if (!stralloc_copys(&template,"/usr/share/ezmlm")) die_nomem(); |
f8beb284 MW |
427 | if (!stralloc_cats(&template,TXT_EZMLMRC)) die_nomem(); |
428 | if (!stralloc_0(&template)) die_nomem(); | |
429 | if ((fdin = open_read(template.s)) == -1) | |
430 | if (errno != error_noent) | |
431 | strerr_die4sys(111,FATAL,ERR_OPEN,template.s,": "); | |
432 | else | |
433 | strerr_die3x(100,FATAL,template.s,ERR_NOEXIST); | |
434 | } | |
5b62e993 | 435 | } |
5b62e993 | 436 | |
f8beb284 MW |
437 | dcreate(""); /* This is all we do, the rest is up to ezmlmrc */ |
438 | /* do it after opening template to avoid aborts */ | |
439 | /* with created DIR. Well we also write DIR/key */ | |
440 | /* at the end except in -e[dit] mode. */ | |
441 | ||
442 | substdio_fdbuf(&sstext,read,fdin,textbuf,sizeof(textbuf)); | |
443 | if (!stralloc_0(&oldfname)) die_nomem(); /* init oldfname */ | |
444 | flagdo = 0; | |
445 | ||
446 | if (getln(&sstext,&line,&match,'\n') == -1) | |
447 | strerr_die4sys(111,FATAL,ERR_READ,template.s,": "); | |
448 | if (!match) | |
449 | strerr_die4sys(111,FATAL,ERR_READ,template.s,": "); | |
450 | i = str_rchr(EZIDX_VERSION,'-'); /* check version */ | |
451 | if (EZIDX_VERSION[i]) i++; | |
452 | j = 0; | |
453 | while (line.s[j] == EZIDX_VERSION[i] && j < line.len && | |
454 | EZIDX_VERSION[i] != '.' && EZIDX_VERSION[i]) { | |
455 | i++; j++; /* major */ | |
456 | } /* first minor */ | |
457 | if (EZIDX_VERSION[i] != '.' || j + 1 >= line.len || | |
458 | EZIDX_VERSION[i+1] != line.s[j+1]) | |
459 | strerr_warn2(WARNING,ERR_VERSION, (struct strerr *) 0); | |
460 | ||
461 | for (;;) { | |
462 | if (getln(&sstext,&line,&match,'\n') == -1) | |
463 | strerr_die4sys(111,FATAL,ERR_READ,template.s,": "); | |
464 | if (!match) | |
465 | break; | |
466 | if (line.s[0] == '#') /* comment */ | |
467 | continue; | |
468 | if (!stralloc_0(&line)) die_nomem(); | |
469 | if (line.s[0] == '<' && line.s[1] == '/') { /* tag */ | |
470 | if (line.s[str_chr(line.s,'.')]) | |
471 | strerr_die3x(100,FATAL,ERR_PERIOD,line.s); | |
472 | flagdo = 1; | |
473 | flagover = 0; | |
474 | hashpos = 0; | |
475 | pos = str_chr(line.s+2,'#')+2; | |
476 | if (line.s[pos]) { | |
477 | hashpos = pos; | |
478 | pos++; | |
479 | flagnot = 0; | |
480 | while ((ch = line.s[pos]) && | |
481 | (line.s[pos] != '/' && line.s[pos+1] != '>')) { | |
482 | if (ch == '^') { | |
483 | flagnot = 1; | |
484 | pos++; | |
485 | continue; | |
486 | } | |
487 | /* E is ignored. For files => create unless exists */ | |
488 | if (ch == 'E' && !flagnot || ch == 'e' && flagnot) { | |
489 | if (flags['e' - 'a'] && !flagforce) | |
490 | flagover = 1; /* ignore #E & #^e, but set flagover */ | |
491 | } else if (ch >= 'a' && ch <= 'z') | |
492 | flagdo &= (flags[ch - 'a'] ^ flagnot); | |
493 | else if (ch >= 'A' && ch <= 'Z') | |
494 | flagdo &= !(flags[ch - 'A'] ^ flagnot); | |
495 | else if (ch >= '0' && ch <= '9') | |
496 | flagdo &= (popt[ch - '0'] && *popt[ch - '0']) ^flagnot; | |
497 | flagnot = 0; | |
498 | pos++; | |
499 | } | |
500 | if (line.s[pos] != '/' || line.s[pos+1] != '>') | |
501 | strerr_die3x(100,FATAL,ERR_ENDTAG,line.s); | |
502 | } else { | |
503 | flagdo = 1; | |
504 | pos = 2; /* name needs to be >= 1 char */ | |
505 | while (line.s[pos = str_chr(line.s+pos,'/')+pos]) { | |
506 | if (line.s[pos+1] == '>') | |
507 | break; | |
508 | pos++; | |
509 | } | |
510 | if (!line.s[pos]) | |
511 | strerr_die3x(100,FATAL,ERR_ENDTAG,line.s); | |
512 | } | |
513 | if (hashpos) | |
514 | pos = hashpos; /* points to after file name */ | |
515 | ||
516 | if (line.s[2] == '+') { /* mkdir */ | |
517 | if (!flagdo) | |
518 | continue; | |
519 | if (!stralloc_copys(&dname,"/")) die_nomem(); | |
520 | if (!stralloc_catb(&dname,line.s+3,pos-3)) die_nomem(); | |
521 | if (!stralloc_0(&dname)) die_nomem(); | |
522 | dcreate(dname.s); | |
523 | flagdo = 0; | |
524 | continue; | |
525 | } else if (line.s[2] == ':') { /* ln -s */ | |
526 | if (!flagdo) | |
527 | continue; | |
528 | slpos = str_chr(line.s + 3,'/') + 3; | |
529 | if (slpos >= pos) | |
530 | strerr_die3x(100,FATAL,ERR_LINKDIR,line.s); | |
531 | if (!stralloc_copyb(&dname,line.s+slpos,pos-slpos)) die_nomem(); | |
532 | if (!stralloc_copyb(&lname,line.s+3,slpos-3)) die_nomem(); | |
533 | if (!stralloc_0(&dname)) die_nomem(); | |
534 | if (!stralloc_0(&lname)) die_nomem(); | |
535 | linkdotdir(lname.s,dname.s); | |
536 | flagdo = 0; | |
537 | continue; | |
538 | } else if (line.s[2] == '-') { /* rm */ | |
539 | if (!flagdo) | |
540 | continue; | |
541 | if (!stralloc_copys(&dname,"/")) die_nomem(); | |
542 | if (!stralloc_catb(&dname,line.s+3,pos-3)) die_nomem(); | |
543 | if (!stralloc_0(&dname)) die_nomem(); | |
544 | frm(dname.s); | |
545 | flagdo = 0; | |
546 | continue; | |
547 | } | |
548 | /* only plain files left */ | |
549 | /* first get file name */ | |
550 | if (pos > 2) { /* </#ai/> => add to open file */ | |
551 | if (!stralloc_copyb(&fname,line.s+1,pos-1)) die_nomem(); | |
552 | if (!stralloc_0(&fname)) die_nomem(); | |
553 | } | |
554 | ||
555 | if (str_diff(fname.s, oldfname.s)) { | |
556 | flagnotexist = 1; | |
557 | /* Treat special case of #E when editing which _should*/ | |
558 | /* write only if the file does not exist. flagover */ | |
559 | /* is set if we need to check */ | |
560 | if (flagover) { /* skip if exists */ | |
561 | dirplusmake(fname.s); /* decided by FIRST tag for file */ | |
562 | fdtmp = open_read(dirplus.s); | |
563 | if (fdtmp == -1) { | |
564 | if (errno != error_noent) | |
565 | strerr_die3sys(111,ERR_OPEN,dirplus.s,": "); | |
566 | } else { | |
567 | flagnotexist = 0; /* already there - don't do it */ | |
568 | close(fdtmp); | |
569 | } | |
570 | } | |
571 | if (oldfname.len > 1) { | |
572 | f_close(); | |
573 | if (!stralloc_copys(&oldfname,"")) die_nomem(); | |
574 | if (!stralloc_0(&oldfname)) die_nomem(); | |
575 | } | |
576 | if (flagdo && flagnotexist) { | |
577 | if (!fname.len) | |
578 | strerr_die3x(100,FATAL,ERR_FILENAME,line.s); | |
579 | f_open(fname.s); | |
580 | if (!stralloc_copy(&oldfname,&fname)) die_nomem(); | |
581 | } | |
582 | } | |
583 | if (flagdo) flagdo = flagnotexist; | |
584 | continue; | |
585 | } else if (!flagdo) | |
586 | continue; /* part not to go out */ | |
587 | last = -1; | |
588 | next = 0; | |
589 | outline.len = 0; | |
590 | for (;;) { | |
591 | pos = next + str_chr(line.s+next,'<'); | |
592 | if (line.s[pos] && | |
593 | line.s[pos+1] == '#' && | |
594 | line.s[pos+2] && | |
595 | line.s[pos+3] == '#' && | |
596 | line.s[pos+4] == '>') { /* host/local */ | |
597 | if (!stralloc_catb(&outline,line.s+last+1,pos-last-1)) | |
598 | die_nomem(); | |
599 | switch (line.s[pos+2]) { | |
600 | case 'B': /* path to ezmlm binaries (no trailing /) */ | |
601 | if (!stralloc_cats(&outline,auto_bin)) die_nomem(); | |
602 | last = pos + 4; next = pos + 5; break; | |
603 | case 'C': /* digestcode */ | |
604 | if (code && *code) | |
605 | if (!stralloc_cats(&outline,code)) die_nomem(); | |
606 | last = pos + 4; next = pos + 5; break; | |
607 | case 'D': /* listdir */ | |
608 | if (!stralloc_cats(&outline,dir)) die_nomem(); | |
609 | last = pos + 4; next = pos + 5; break; | |
610 | case 'F': /* flags */ | |
611 | if (!stralloc_cat(&outline,&f)) die_nomem(); | |
612 | last = pos + 4; next = pos + 5; break; | |
613 | case 'H': /* hostname */ | |
614 | if (!stralloc_cats(&outline,host)) die_nomem(); | |
615 | last = pos + 4; next = pos + 5; break; | |
616 | case 'L': /* local */ | |
617 | if (!stralloc_cats(&outline,local)) die_nomem(); | |
618 | last = pos + 4; next = pos + 5; break; | |
619 | case 'T': /* dot */ | |
620 | if (!stralloc_cats(&outline,dot)) die_nomem(); | |
621 | last = pos + 4; next = pos + 5; break; | |
622 | case 'X': /* config file name */ | |
623 | if (cfname) | |
624 | if (!stralloc_cats(&outline,cfname)) die_nomem(); | |
625 | last = pos + 4; next = pos + 5; break; | |
626 | default: /* copy unknown tag as is for e.g. <#A#> and*/ | |
627 | /* <#R#> to be processed by -manage/store */ | |
628 | /* stuff in args for <#0#> .. <#9#> */ | |
629 | if ((line.s[pos+2] >= '0') && (line.s[pos+2] <= '9')) { | |
630 | if (popt[line.s[pos+2] - '0']) | |
631 | if (!stralloc_cats(&outline,popt[line.s[pos+2]-'0'])) | |
632 | die_nomem(); | |
633 | } else | |
634 | if (!stralloc_catb(&outline,line.s+pos,5)) die_nomem(); | |
635 | last = pos + 4; next = pos + 5; break; | |
636 | } | |
637 | } else { /* not tag */ | |
638 | if (line.s[pos]) { | |
639 | next++; | |
640 | } else { | |
641 | if (!stralloc_catb(&outline,line.s+last+1,line.len-last-1)) | |
642 | die_nomem(); | |
643 | f_puts(outline.s); | |
644 | break; | |
645 | } | |
646 | } | |
647 | } | |
648 | } | |
649 | ||
650 | close(fdin); | |
651 | if (oldfname.len > 1) | |
652 | f_close(); | |
653 | ||
654 | if (!flags['e' - 'a']) { /* don't redo key when editing a list */ | |
655 | f_open("/key"); | |
656 | f_put(key.s,key.len); | |
657 | f_close(); | |
658 | } | |
5b62e993 MW |
659 | _exit(0); |
660 | } | |
f8beb284 | 661 |