| 1 | /*Id: ezmlm-make.c,v 1.31 1997/12/08 23:44:02 lindberg Exp lindberg $*/ |
| 2 | /*$Name: ezmlm-idx-040 $*/ |
| 3 | |
| 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" |
| 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}; |
| 42 | |
| 43 | #define FATAL "ezmlm-make: fatal: " |
| 44 | #define WARNING "ezmlm-make: warning: " |
| 45 | |
| 46 | void die_usage() |
| 47 | { |
| 48 | strerr_die1x(100, |
| 49 | "ezmlm-make: usage: ezmlm-make [-+] [ -a..zA..Z03..9 ] dir dot local host"); |
| 50 | } |
| 51 | void die_relative() |
| 52 | { |
| 53 | strerr_die2x(100,FATAL,ERR_SLASH); |
| 54 | } |
| 55 | void die_newline() |
| 56 | { |
| 57 | strerr_die2x(100,FATAL,ERR_NEWLINE); |
| 58 | } |
| 59 | void die_quote() |
| 60 | { |
| 61 | strerr_die2x(100,FATAL,ERR_QUOTE); |
| 62 | } |
| 63 | void die_nomem() |
| 64 | { |
| 65 | strerr_die2x(111,FATAL,ERR_NOMEM); |
| 66 | } |
| 67 | |
| 68 | void die_read() |
| 69 | { |
| 70 | strerr_die4sys(111,FATAL,ERR_READ,dirplus.s,": "); |
| 71 | } |
| 72 | |
| 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}; |
| 86 | stralloc key = {0}; |
| 87 | struct timeval tv; |
| 88 | char sz[2] = "?"; |
| 89 | |
| 90 | void keyadd(u) |
| 91 | unsigned long u; |
| 92 | { |
| 93 | char ch; |
| 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(); |
| 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; |
| 108 | char *local = (char *) 0; |
| 109 | char *host = (char *) 0; |
| 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); |
| 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,": "); |
| 131 | if (symlink(dirplus.s,dotplus.s) == -1) |
| 132 | strerr_die4sys(111,FATAL,ERR_CREATE,dotplus.s,": "); |
| 133 | keyaddtime(); |
| 134 | } |
| 135 | |
| 136 | void dcreate(slash) |
| 137 | char *slash; |
| 138 | { |
| 139 | dirplusmake(slash); |
| 140 | if (mkdir(dirplus.s,0755) == -1) |
| 141 | if ((errno != error_exist) || !flags['e' - 'a']) |
| 142 | strerr_die4sys(111,FATAL,ERR_CREATE,dirplus.s,": "); |
| 143 | keyaddtime(); |
| 144 | } |
| 145 | |
| 146 | substdio ss; |
| 147 | char ssbuf[SUBSTDIO_OUTSIZE]; |
| 148 | |
| 149 | void f_open(slash) |
| 150 | char *slash; |
| 151 | { |
| 152 | int fd; |
| 153 | |
| 154 | dirplusmake(slash); |
| 155 | fd = open_trunc(dirplus.s); |
| 156 | if (fd == -1) |
| 157 | strerr_die4sys(111,FATAL,ERR_CREATE,dirplus.s,": "); |
| 158 | |
| 159 | substdio_fdbuf(&ss,write,fd,ssbuf,sizeof(ssbuf)); |
| 160 | } |
| 161 | |
| 162 | void f_put(buf,len) |
| 163 | char *buf; |
| 164 | unsigned int len; |
| 165 | { |
| 166 | if (substdio_bput(&ss,buf,len) == -1) |
| 167 | strerr_die4sys(111,FATAL,ERR_WRITE,dirplus.s,": "); |
| 168 | } |
| 169 | void f_puts(buf) |
| 170 | char *buf; |
| 171 | { |
| 172 | if (substdio_bputs(&ss,buf) == -1) |
| 173 | strerr_die4sys(111,FATAL,ERR_WRITE,dirplus.s,": "); |
| 174 | } |
| 175 | |
| 176 | void f_close() |
| 177 | { |
| 178 | if (substdio_flush(&ss) == -1) |
| 179 | strerr_die4sys(111,FATAL,ERR_FLUSH,dirplus.s,": "); |
| 180 | if (fsync(ss.fd) == -1) |
| 181 | strerr_die4sys(111,FATAL,ERR_SYNC,dirplus.s,": "); |
| 182 | if (close(ss.fd) == -1) /* NFS stupidity */ |
| 183 | strerr_die4sys(111,FATAL,ERR_CLOSE,dirplus.s,": "); |
| 184 | keyaddtime(); |
| 185 | } |
| 186 | |
| 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 | |
| 197 | void main(argc,argv) |
| 198 | int argc; |
| 199 | char **argv; |
| 200 | { |
| 201 | unsigned long euid; |
| 202 | int opt; |
| 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; |
| 220 | |
| 221 | keyadd((unsigned long) getpid()); |
| 222 | keyadd((unsigned long) getppid()); |
| 223 | euid = (unsigned long) geteuid(); |
| 224 | keyadd(euid); |
| 225 | keyadd((unsigned long) getgid()); |
| 226 | gettimeofday(&tv,(struct timezone *) 0); |
| 227 | keyadd(tv.tv_sec); |
| 228 | |
| 229 | (void) umask(077); |
| 230 | /* flags with defined use. vV for version. Others free */ |
| 231 | |
| 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 | } |
| 258 | argv += optind; |
| 259 | |
| 260 | if (flagforce_p > 1 || flagforce > 1) |
| 261 | flagforce = 1; |
| 262 | else |
| 263 | flagforce = 0; |
| 264 | |
| 265 | if (!(dir = *argv++)) die_usage(); |
| 266 | if (dir[0] != '/') die_relative(); |
| 267 | if (dir[str_chr(dir,'\'')]) die_quote(); |
| 268 | if (dir[str_chr(dir,'\n')]) die_newline(); |
| 269 | |
| 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 | } |
| 321 | |
| 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 | } |
| 355 | |
| 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 | } |
| 364 | |
| 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 */ |
| 368 | } |
| 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 */ |
| 426 | if (!stralloc_copys(&template,auto_bin)) die_nomem(); |
| 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 | } |
| 435 | } |
| 436 | |
| 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 | } |
| 659 | _exit(0); |
| 660 | } |
| 661 | |