+/*Id: ezmlm-make.c,v 1.31 1997/12/08 23:44:02 lindberg Exp lindberg $*/
+/*$Name: ezmlm-idx-040 $*/
+
#include <sys/types.h>
#include <sys/time.h>
#include "sgetopt.h"
#include "substdio.h"
#include "str.h"
#include "auto_bin.h"
+#include "getln.h"
+#include "error.h"
+#include "lock.h"
+#include "errtxt.h"
+#include "idx.h"
+
+ /* defaults. All other flags are false = 0 */
+char *defflags="ap"; /* archived list -a */
+ /* public list -p */
+ /* no ezmlm-archive -I */
+ /* no text edit for remote admin -D */
+ /* not in edit mode -E */
+ /* no subs list for remote admin -L */
+ /* no remote admin -R */
+ /* no message moderation -M */
+ /* no subscription moderation -S */
+ /* don't use .ezmlmrc from dot-file dir -C */
+ /* no prefix -F */
+ /* no trailer -T */
+
+#define NO_FLAGS ('z' - 'a' + 1)
+int flags[NO_FLAGS]; /* holds flags */
+
+char *popt[10];
+stralloc dotplus = {0};
+stralloc dirplus = {0};
+stralloc line = {0};
#define FATAL "ezmlm-make: fatal: "
+#define WARNING "ezmlm-make: warning: "
void die_usage()
{
- strerr_die1x(100,"ezmlm-make: usage: ezmlm-make [ -aApP ] dir dot local host");
+ strerr_die1x(100,
+ "ezmlm-make: usage: ezmlm-make [-+] [ -a..zA..Z03..9 ] dir dot local host");
}
void die_relative()
{
- strerr_die2x(100,FATAL,"dir must start with slash");
+ strerr_die2x(100,FATAL,ERR_SLASH);
}
void die_newline()
{
- strerr_die2x(100,FATAL,"newlines not allowed");
+ strerr_die2x(100,FATAL,ERR_NEWLINE);
}
void die_quote()
{
- strerr_die2x(100,FATAL,"quotes not allowed");
+ strerr_die2x(100,FATAL,ERR_QUOTE);
}
void die_nomem()
{
- strerr_die2x(111,FATAL,"out of memory");
+ strerr_die2x(111,FATAL,ERR_NOMEM);
+}
+
+void die_read()
+{
+ strerr_die4sys(111,FATAL,ERR_READ,dirplus.s,": ");
}
+stralloc cmdline = {0};
+stralloc outline = {0};
+substdio sstext;
+char textbuf[1024];
+
+stralloc fname = {0}; /* file name */
+stralloc oldfname = {0}; /* file name from prevoius tag */
+stralloc dname = {0}; /* directory name */
+stralloc lname = {0}; /* link name */
+stralloc template = {0}; /* template file name */
+stralloc ext1 = {0}; /* dot = dir/.qmail-ext1-ext2-list */
+stralloc ext2 = {0};
+stralloc f = {0};
stralloc key = {0};
struct timeval tv;
+char sz[2] = "?";
void keyadd(u)
unsigned long u;
{
char ch;
- ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
- ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
- ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
- ch = u; if (!stralloc_append(&key,&ch)) die_nomem();
+ ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
+ ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
+ ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
+ ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem();
}
void keyaddtime()
char *dir;
char *dot;
-char *local;
-char *host;
-
-stralloc dotplus = {0};
-stralloc dirplus = {0};
+char *local = (char *) 0;
+char *host = (char *) 0;
void dirplusmake(slash)
char *slash;
if (!stralloc_cats(&dotplus,dash)) die_nomem();
if (!stralloc_0(&dotplus)) die_nomem();
dirplusmake(slash);
+ if (flags['e' - 'a'])
+ if (unlink(dotplus.s) == -1)
+ if (errno != error_noent)
+ strerr_die4x(111,FATAL,ERR_DELETE,dotplus.s,": ");
if (symlink(dirplus.s,dotplus.s) == -1)
- strerr_die4sys(111,FATAL,"unable to create ",dotplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_CREATE,dotplus.s,": ");
keyaddtime();
}
{
dirplusmake(slash);
if (mkdir(dirplus.s,0755) == -1)
- strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": ");
+ if ((errno != error_exist) || !flags['e' - 'a'])
+ strerr_die4sys(111,FATAL,ERR_CREATE,dirplus.s,": ");
keyaddtime();
}
substdio ss;
char ssbuf[SUBSTDIO_OUTSIZE];
-void fopen(slash)
+void f_open(slash)
char *slash;
{
int fd;
dirplusmake(slash);
fd = open_trunc(dirplus.s);
if (fd == -1)
- strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_CREATE,dirplus.s,": ");
substdio_fdbuf(&ss,write,fd,ssbuf,sizeof(ssbuf));
}
-void fput(buf,len)
+void f_put(buf,len)
char *buf;
unsigned int len;
{
if (substdio_bput(&ss,buf,len) == -1)
- strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_WRITE,dirplus.s,": ");
}
-void fputs(buf)
+void f_puts(buf)
char *buf;
{
if (substdio_bputs(&ss,buf) == -1)
- strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_WRITE,dirplus.s,": ");
}
-void fclose()
+void f_close()
{
if (substdio_flush(&ss) == -1)
- strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_FLUSH,dirplus.s,": ");
if (fsync(ss.fd) == -1)
- strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_SYNC,dirplus.s,": ");
if (close(ss.fd) == -1) /* NFS stupidity */
- strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_CLOSE,dirplus.s,": ");
keyaddtime();
}
+void frm(slash)
+char *slash;
+{
+ dirplusmake(slash);
+ if (unlink(dirplus.s) == -1)
+ if (errno != error_noent)
+ strerr_die4sys(111,FATAL,ERR_DELETE,dirplus.s,": ");
+}
+
+
void main(argc,argv)
int argc;
char **argv;
{
+ unsigned long euid;
int opt;
- int flagarchived;
- int flagpublic;
+ int flagdo;
+ int flagnot;
+ int flagover;
+ int flagnotexist;
+ int flagforce = 0;
+ int flagforce_p = 0;
+ int usecfg = 0;
+ int match;
+ unsigned int next,i,j;
+ int last;
+ unsigned int slpos,hashpos,pos;
+ int fdin,fdlock,fdtmp;
+ char *p;
+ char *oldflags = (char *) 0;
+ char *code = (char *) 0;
+ char *cfname = (char *) 0; /* config file if spec as -C cf_file */
+ char ch;
- keyadd(getpid());
- keyadd(getppid());
- keyadd(getuid());
- keyadd(getgid());
+ keyadd((unsigned long) getpid());
+ keyadd((unsigned long) getppid());
+ euid = (unsigned long) geteuid();
+ keyadd(euid);
+ keyadd((unsigned long) getgid());
gettimeofday(&tv,(struct timezone *) 0);
keyadd(tv.tv_sec);
- umask(077);
-
- flagarchived = 1;
- flagpublic = 1;
+ (void) umask(077);
+ /* flags with defined use. vV for version. Others free */
- while ((opt = getopt(argc,argv,"aApP")) != opteof)
- switch(opt) {
- case 'a': flagarchived = 1; break;
- case 'A': flagarchived = 0; break;
- case 'p': flagpublic = 1; break;
- case 'P': flagpublic = 0; break;
- default:
- die_usage();
- }
+ for (pos = 0; pos < (unsigned int) NO_FLAGS; pos++) {
+ flags[pos] = 0;
+ }
+ for (pos = 0; pos < 10; popt[pos++] = (char *) 0);
+
+ while ((opt = getopt(argc,argv,
+ "+aAbBcC:dDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0:3:4:5:6:7:8:9:"))
+ != opteof) {
+ if (opt == 'v' || opt == 'V')
+ strerr_die2x(0,"ezmlm-make version: ezmlm-0.53+",EZIDX_VERSION);
+ if (opt =='C') /* treat this like nl switch to allow override of -c*/
+ cfname = optarg;
+ if (opt >= 'a' && opt <= 'z') {
+ flags[opt - 'a'] = 3; /* Dominant "set" */
+ if (opt == 'e') flagforce++; /* two 'e' => ignore 'E' */
+ } else if (opt >= 'A' && opt <= 'Z')
+ flags[opt - 'A'] = 2; /* Dominant "unset" */
+ else if (opt >= '0' && opt <= '9')
+ popt[opt-'0'] = optarg;
+ else if (opt == '+') {
+ flagforce_p++; /* two '+' => ignore 'E' */
+ flags['e' - 'a'] = 3; /* -+ implies -e */
+ usecfg = 1;
+ } else
+ die_usage();
+ }
argv += optind;
- if (!(dir = *argv++)) die_usage();
- if (!(dot = *argv++)) die_usage();
- if (!(local = *argv++)) die_usage();
- if (!(host = *argv++)) die_usage();
+ if (flagforce_p > 1 || flagforce > 1)
+ flagforce = 1;
+ else
+ flagforce = 0;
+ if (!(dir = *argv++)) die_usage();
if (dir[0] != '/') die_relative();
if (dir[str_chr(dir,'\'')]) die_quote();
if (dir[str_chr(dir,'\n')]) die_newline();
- if (local[str_chr(local,'\n')]) die_newline();
- if (host[str_chr(host,'\n')]) die_newline();
- dcreate("");
- dcreate("/archive");
- dcreate("/subscribers");
- dcreate("/bounce");
- dcreate("/text");
+ if (flags['e' - 'a'] & 1) { /* lock for edit */
+ dirplusmake("/lock");
+ fdlock = open_append(dirplus.s);
+ if (fdlock == -1)
+ strerr_die4sys(111,FATAL,ERR_OPEN,dirplus.s,": ");
+ if (lock_ex(fdlock) == -1)
+ strerr_die4sys(111,FATAL,ERR_OBTAIN,dirplus.s,": ");
+
+ /* for edit, try to get args from dir/config */
+ dirplusmake("/config");
+ if ((fdin = open_read(dirplus.s)) == -1) {
+ if (errno != error_noent) die_read();
+ } else {
+ substdio_fdbuf(&sstext,read,fdin,textbuf,sizeof(textbuf));
+ for (;;) {
+ if (getln(&sstext,&line,&match,'\n') == -1) die_read();
+ if (!match) break;
+ if (line.s[0] == '#') continue;
+ if (line.len == 1) break;
+ if (line.s[1] != ':') break;
+ line.s[line.len - 1] = '\0';
+ if (!stralloc_cat(&cmdline,&line)) die_nomem();
+ }
+ close(fdin);
+ pos = 0;
+ while (pos < cmdline.len) {
+ ch = cmdline.s[pos];
+ pos += 2;
+ switch (ch) {
+ case 'X': if (euid && !flags['c' - 'a'] && (!cfname))
+ cfname = cmdline.s + pos; /* cmdline overrides */
+ break; /* for safety: ignore if root */
+ case 'T': dot = cmdline.s + pos; break;
+ case 'L': local = cmdline.s + pos; break;
+ case 'H': host = cmdline.s + pos; break;
+ case 'C': code = cmdline.s + pos; break;
+ case 'D': break; /* no reason to check */
+ case 'F': oldflags = cmdline.s + pos; break;
+ default:
+ if (ch == '0' || (ch >= '3' && ch <= '9')) {
+ if (usecfg && !popt[ch - '0'])
+ popt[ch - '0'] = cmdline.s + pos;
+ } else
+ strerr_die4x(111,FATAL,dirplus.s,ERR_SYNTAX,
+ cmdline.s+pos);
+ break;
+ }
+ pos += str_len(cmdline.s + pos) + 1;
+ }
+ }
+ }
+ if (p = *argv++) {
+ dot = p;
+ if (p = *argv++) {
+ if (!local || str_diff(local,p))
+ flagforce = 1; /* must rewrite if list name changed */
+ local = p;
+ if (p = *argv++) {
+ if (!host || str_diff(host,p))
+ flagforce = 1; /* must rewrite if list name changed */
+ host = p;
+ if (p = *argv++) {
+ code = p;
+ }
+ }
+ }
+ }
+ if (!dot || !local || !host) die_usage();
+ if (dot[0] != '/') die_relative(); /* force absolute dot */
+
+ /* use flags from config, overridden with new values */
+ /* if there are old flags, we're in "edit" and "-+" */
+ /* Previous versions only wrote _set_ flags to */
+ /* to DIR/confiag. We need to make sure that we */
+ /* don't apply the defaults for non-specified ones! */
+ if (usecfg && oldflags && flags['e' - 'a']) {
+ while ((ch = *(oldflags++))) {
+ if (ch >= 'a' && ch <= 'z') { /* unset flags ignored */
+ if (ch != 'e')
+ if (!flags[ch - 'a']) /* cmd line overrides */
+ flags[ch - 'a'] = 1;
+ }
+ }
+ }
- linkdotdir("-owner","/owner");
- linkdotdir("-default","/manager");
- linkdotdir("-return-default","/bouncer");
- linkdotdir("","/editor");
+ if (!usecfg) { /* apply defaults */
+ while (( ch = *(defflags++))) { /* gets used up! */
+ if (ch >= 'a' && ch <= 'z') { /* defensive! */
+ if (!flags[ch - 'a']) /* cmdline still overrides */
+ flags[ch - 'a'] = 1;
+ }
+ }
+ }
- fopen("/lock"); fclose();
- fopen("/lockbounce"); fclose();
- if (flagpublic) {
- fopen("/public"); fclose();
+ for (pos = 0; pos < (unsigned int) NO_FLAGS; pos++) { /* set real flags */
+ if (flags[pos] & 2) /* 2 = "dominant" 0 */
+ flags[pos] = flags[pos] & 1; /* 3 = "dominant" 1 */
}
- if (flagarchived) {
- fopen("/archived"); fclose();
+
+ if (local[str_chr(local,'\n')]) die_newline();
+ if (host[str_chr(host,'\n')]) die_newline();
+
+ /* build 'f' for <#F#> */
+ if (!stralloc_ready(&f,28)) die_nomem();
+ if (!stralloc_copys(&f,"-")) die_nomem();
+ for (ch = 0; ch <= 'z' - 'a'; ch++) { /* build string with flags */
+ if (flags[ch])
+ sz[0] = 'a' + ch;
+ else
+ sz[0] = 'A' + ch;
+ if (!stralloc_append(&f,sz)) die_nomem();
+ }
+
+ fdin = -1; /* assure failure for .ezmlmrc in case flags['c'-'a'] = 0 */
+ slpos = str_len(dot);
+ while ((--slpos > 0) && dot[slpos] != '/');
+ if (dot[slpos] == '/') {
+ if (!stralloc_copyb(&template,dot,slpos+1)) die_nomem(); /* dot dir */
+ slpos += str_chr(dot+slpos,'-');
+ if (dot[slpos]) {
+ slpos++;
+ pos = slpos + str_chr(dot+slpos,'-');
+ if (dot[pos]) {
+ if (!stralloc_copyb(&ext1,dot+slpos,pos-slpos)) die_nomem();
+ pos++;
+ slpos = pos + str_chr(dot+pos,'-');
+ if (dot[slpos])
+ if (!stralloc_copyb(&ext2,dot+pos,slpos-pos)) die_nomem();
+ }
+ }
+ }
+ if (!stralloc_0(&ext1)) die_nomem();
+ if (!stralloc_0(&ext2)) die_nomem();
+ popt[1] = ext1.s;
+ popt[2] = ext2.s;
+ /* if 'c', template already has the dot directory. If 'C', cfname */
+ /* (if exists and != '') points to the file name to use instead. */
+ if (flags['c'-'a'] || (cfname && *cfname)) {
+ if (!flags['c'-'a']) { /* i.e. there is a cfname specified */
+ if (!stralloc_copys(&template,cfname)) die_nomem();
+ } else
+ if (!stralloc_cats(&template,TXT_DOTEZMLMRC)) die_nomem();
+ if (!stralloc_0(&template)) die_nomem();
+ if ((fdin = open_read(template.s)) == -1)
+ if (errno != error_noent)
+ strerr_die4sys(111,FATAL,ERR_OPEN,template.s,": ");
+ else
+ strerr_die3x(100,FATAL,template.s,ERR_NOEXIST);
+ } else { /* /etc/ezmlmrc */
+ if (!stralloc_copys(&template,TXT_ETC_EZMLMRC)) die_nomem();
+ if (!stralloc_0(&template)) die_nomem();
+ if ((fdin = open_read(template.s)) == -1)
+ if (errno != error_noent)
+ strerr_die4sys(111,FATAL,ERR_OPEN,template.s,": ");
+ else { /* ezbin/ezmlmrc */
+ if (!stralloc_copys(&template,auto_bin)) die_nomem();
+ if (!stralloc_cats(&template,TXT_EZMLMRC)) die_nomem();
+ if (!stralloc_0(&template)) die_nomem();
+ if ((fdin = open_read(template.s)) == -1)
+ if (errno != error_noent)
+ strerr_die4sys(111,FATAL,ERR_OPEN,template.s,": ");
+ else
+ strerr_die3x(100,FATAL,template.s,ERR_NOEXIST);
+ }
}
- fopen("/num"); fputs("0\n"); fclose();
- fopen("/inhost"); fputs(host); fputs("\n"); fclose();
- fopen("/outhost"); fputs(host); fputs("\n"); fclose();
- fopen("/inlocal"); fputs(local); fputs("\n"); fclose();
- fopen("/outlocal"); fputs(local); fputs("\n"); fclose();
-
- fopen("/mailinglist");
- fputs("contact ");
- fputs(local); fputs("-help@"); fputs(host); fputs("; run by ezmlm\n");
- fclose();
-
- fopen("/owner");
- fputs(dir); fputs("/Mailbox\n");
- fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir);
- fputs("' || exit 0\n");
- fclose();
-
- fopen("/manager");
- fputs("|"); fputs(auto_bin); fputs("/ezmlm-manage '"); fputs(dir); fputs("'\n");
- fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir);
- fputs("' || exit 0\n");
- fclose();
-
- fopen("/editor");
- fputs("|"); fputs(auto_bin); fputs("/ezmlm-reject\n");
- fputs("|"); fputs(auto_bin); fputs("/ezmlm-send '"); fputs(dir); fputs("'\n");
- fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir);
- fputs("' || exit 0\n");
- fclose();
-
- fopen("/bouncer");
- fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir);
- fputs("' || exit 0\n");
- fputs("|"); fputs(auto_bin); fputs("/ezmlm-weed\n");
- fputs("|"); fputs(auto_bin); fputs("/ezmlm-return '"); fputs(dir); fputs("'\n");
- fclose();
-
- fopen("/headerremove");
- fputs("\
-return-path\n\
-return-receipt-to\n\
-content-length\n\
-");
- fclose();
-
- fopen("/headeradd");
- fclose();
-
-
- fopen("/text/top");
- fputs("Hi! This is the ezmlm program. I'm managing the\n");
- fputs(local); fputs("@"); fputs(host); fputs(" mailing list.\n\n");
- fclose();
-
- fopen("/text/bottom");
- fputs("\n--- Here are the ezmlm command addresses.\n\
-\n\
-I can handle administrative requests automatically.\n\
-Just send an empty note to any of these addresses:\n\n <");
- fputs(local); fputs("-subscribe@"); fputs(host); fputs(">:\n");
- fputs(" Receive future messages sent to the mailing list.\n\n <");
- fputs(local); fputs("-unsubscribe@"); fputs(host); fputs(">:\n");
- fputs(" Stop receiving messages.\n\n <");
- fputs(local); fputs("-get.12345@"); fputs(host); fputs(">:\n");
- fputs(" Retrieve a copy of message 12345 from the archive.\n\
-\n\
-DO NOT SEND ADMINISTRATIVE REQUESTS TO THE MAILING LIST!\n\
-If you do, I won't see them, and subscribers will yell at you.\n\
-\n\
-To specify God@heaven.af.mil as your subscription address, send mail\n\
-to <");
- fputs(local); fputs("-subscribe-God=heaven.af.mil@"); fputs(host);
- fputs(">.\n\
-I'll send a confirmation message to that address; when you receive that\n\
-message, simply reply to it to complete your subscription.\n\
-\n");
- fputs("\n--- Below this line is a copy of the request I received.\n\n");
- fclose();
-
- fopen("/text/sub-confirm");
- fputs("To confirm that you would like\n\
-\n\
-!A\n\
-\n\
-added to this mailing list, please send an empty reply to this address:\n\
-\n\
-!R\n\
-\n\
-Your mailer should have a Reply feature that uses this address automatically.\n\
-\n\
-This confirmation serves two purposes. First, it verifies that I am able\n\
-to get mail through to you. Second, it protects you in case someone\n\
-forges a subscription request in your name.\n\
-\n");
- fclose();
-
- fopen("/text/unsub-confirm");
- fputs("To confirm that you would like\n\
-\n\
-!A\n\
-\n\
-removed from this mailing list, please send an empty reply to this address:\n\
-\n\
-!R\n\
-\n\
-Your mailer should have a Reply feature that uses this address automatically.\n\
-\n\
-I haven't checked whether your address is currently on the mailing list.\n\
-To see what address you used to subscribe, look at the messages you are\n\
-receiving from the mailing list. Each message has your address hidden\n\
-inside its return path; for example, God@heaven.af.mil receives messages\n\
-with return path ...-God=heaven.af.mil.\n\
-\n");
- fclose();
-
- fopen("/text/sub-ok");
- fputs("Acknowledgment: I have added the address\n\
-\n\
-!A\n\
-\n\
-to this mailing list.\n\
-\n");
- fclose();
-
- fopen("/text/unsub-ok");
- fputs("Acknowledgment: I have removed the address\n\
-\n\
-!A\n\
-\n\
-from this mailing list.\n\
-\n");
- fclose();
-
- fopen("/text/sub-nop");
- fputs("Acknowledgment: The address\n\
-\n\
-!A\n\
-\n\
-is on this mailing list.\n\
-\n");
- fclose();
-
- fopen("/text/unsub-nop");
- fputs("Acknowledgment: The address\n\
-\n\
-!A\n\
-\n\
-is not on this mailing list.\n\
-\n");
- fclose();
-
- fopen("/text/sub-bad");
- fputs("Oops, that confirmation number appears to be invalid.\n\
-\n\
-The most common reason for invalid numbers is expiration. I have to\n\
-receive confirmation of each request within ten days.\n\
-\n\
-I've set up a new confirmation number. To confirm that you would like\n\
-\n\
-!A\n\
-\n\
-added to this mailing list, please send an empty reply to this address:\n\
-\n\
-!R\n\
-\n\
-Sorry for the trouble.\n\
-\n");
- fclose();
-
- fopen("/text/unsub-bad");
- fputs("Oops, that confirmation number appears to be invalid.\n\
-\n\
-The most common reason for invalid numbers is expiration. I have to\n\
-receive confirmation of each request within ten days.\n\
-\n\
-I've set up a new confirmation number. To confirm that you would like\n\
-\n\
-!A\n\
-\n\
-removed from this mailing list, please send an empty reply to this address:\n\
-\n\
-!R\n\
-\n\
-Sorry for the trouble.\n\
-\n");
- fclose();
-
- fopen("/text/get-bad");
- fputs("Sorry, I don't see that message.\n\n");
- fclose();
-
- fopen("/text/bounce-bottom");
- fputs("\n\
---- Below this line is a copy of the bounce message I received.\n\n");
- fclose();
-
- fopen("/text/bounce-warn");
- fputs("\n\
-Messages to you seem to have been bouncing. I've attached a copy of\n\
-the first bounce message I received.\n\
-\n\
-If this message bounces too, I will send you a probe. If the probe bounces,\n\
-I will remove your address from the mailing list, without further notice.\n\
-\n");
- fclose();
-
- fopen("/text/bounce-probe");
- fputs("\n\
-Messages to you seem to have been bouncing. I sent you a warning\n\
-message, but it bounced. I've attached a copy of the bounce message.\n\
-\n\
-This is a probe to check whether your address is reachable. If this\n\
-probe bounces, I will remove your address from the mailing list, without\n\
-further notice.\n\
-\n");
- fclose();
-
- fopen("/text/bounce-num");
- fputs("\n\
-I've kept a list of which messages bounced from your address. Copies of\n\
-these messages may be in the archive. To get message 12345 from the\n\
-archive, send an empty note to ");
- fputs(local); fputs("-get.12345@"); fputs(host); fputs(".\n\
-Here are the message numbers:\n\
-\n");
- fclose();
-
- fopen("/text/help");
- fputs("\
-This is a generic help message. The message I received wasn't sent to\n\
-any of my command addresses.\n\
-\n");
- fclose();
-
- fopen("/key");
- fput(key.s,key.len);
- fclose();
+ dcreate(""); /* This is all we do, the rest is up to ezmlmrc */
+ /* do it after opening template to avoid aborts */
+ /* with created DIR. Well we also write DIR/key */
+ /* at the end except in -e[dit] mode. */
+
+ substdio_fdbuf(&sstext,read,fdin,textbuf,sizeof(textbuf));
+ if (!stralloc_0(&oldfname)) die_nomem(); /* init oldfname */
+ flagdo = 0;
+
+ if (getln(&sstext,&line,&match,'\n') == -1)
+ strerr_die4sys(111,FATAL,ERR_READ,template.s,": ");
+ if (!match)
+ strerr_die4sys(111,FATAL,ERR_READ,template.s,": ");
+ i = str_rchr(EZIDX_VERSION,'-'); /* check version */
+ if (EZIDX_VERSION[i]) i++;
+ j = 0;
+ while (line.s[j] == EZIDX_VERSION[i] && j < line.len &&
+ EZIDX_VERSION[i] != '.' && EZIDX_VERSION[i]) {
+ i++; j++; /* major */
+ } /* first minor */
+ if (EZIDX_VERSION[i] != '.' || j + 1 >= line.len ||
+ EZIDX_VERSION[i+1] != line.s[j+1])
+ strerr_warn2(WARNING,ERR_VERSION, (struct strerr *) 0);
+
+ for (;;) {
+ if (getln(&sstext,&line,&match,'\n') == -1)
+ strerr_die4sys(111,FATAL,ERR_READ,template.s,": ");
+ if (!match)
+ break;
+ if (line.s[0] == '#') /* comment */
+ continue;
+ if (!stralloc_0(&line)) die_nomem();
+ if (line.s[0] == '<' && line.s[1] == '/') { /* tag */
+ if (line.s[str_chr(line.s,'.')])
+ strerr_die3x(100,FATAL,ERR_PERIOD,line.s);
+ flagdo = 1;
+ flagover = 0;
+ hashpos = 0;
+ pos = str_chr(line.s+2,'#')+2;
+ if (line.s[pos]) {
+ hashpos = pos;
+ pos++;
+ flagnot = 0;
+ while ((ch = line.s[pos]) &&
+ (line.s[pos] != '/' && line.s[pos+1] != '>')) {
+ if (ch == '^') {
+ flagnot = 1;
+ pos++;
+ continue;
+ }
+ /* E is ignored. For files => create unless exists */
+ if (ch == 'E' && !flagnot || ch == 'e' && flagnot) {
+ if (flags['e' - 'a'] && !flagforce)
+ flagover = 1; /* ignore #E & #^e, but set flagover */
+ } else if (ch >= 'a' && ch <= 'z')
+ flagdo &= (flags[ch - 'a'] ^ flagnot);
+ else if (ch >= 'A' && ch <= 'Z')
+ flagdo &= !(flags[ch - 'A'] ^ flagnot);
+ else if (ch >= '0' && ch <= '9')
+ flagdo &= (popt[ch - '0'] && *popt[ch - '0']) ^flagnot;
+ flagnot = 0;
+ pos++;
+ }
+ if (line.s[pos] != '/' || line.s[pos+1] != '>')
+ strerr_die3x(100,FATAL,ERR_ENDTAG,line.s);
+ } else {
+ flagdo = 1;
+ pos = 2; /* name needs to be >= 1 char */
+ while (line.s[pos = str_chr(line.s+pos,'/')+pos]) {
+ if (line.s[pos+1] == '>')
+ break;
+ pos++;
+ }
+ if (!line.s[pos])
+ strerr_die3x(100,FATAL,ERR_ENDTAG,line.s);
+ }
+ if (hashpos)
+ pos = hashpos; /* points to after file name */
+
+ if (line.s[2] == '+') { /* mkdir */
+ if (!flagdo)
+ continue;
+ if (!stralloc_copys(&dname,"/")) die_nomem();
+ if (!stralloc_catb(&dname,line.s+3,pos-3)) die_nomem();
+ if (!stralloc_0(&dname)) die_nomem();
+ dcreate(dname.s);
+ flagdo = 0;
+ continue;
+ } else if (line.s[2] == ':') { /* ln -s */
+ if (!flagdo)
+ continue;
+ slpos = str_chr(line.s + 3,'/') + 3;
+ if (slpos >= pos)
+ strerr_die3x(100,FATAL,ERR_LINKDIR,line.s);
+ if (!stralloc_copyb(&dname,line.s+slpos,pos-slpos)) die_nomem();
+ if (!stralloc_copyb(&lname,line.s+3,slpos-3)) die_nomem();
+ if (!stralloc_0(&dname)) die_nomem();
+ if (!stralloc_0(&lname)) die_nomem();
+ linkdotdir(lname.s,dname.s);
+ flagdo = 0;
+ continue;
+ } else if (line.s[2] == '-') { /* rm */
+ if (!flagdo)
+ continue;
+ if (!stralloc_copys(&dname,"/")) die_nomem();
+ if (!stralloc_catb(&dname,line.s+3,pos-3)) die_nomem();
+ if (!stralloc_0(&dname)) die_nomem();
+ frm(dname.s);
+ flagdo = 0;
+ continue;
+ }
+ /* only plain files left */
+ /* first get file name */
+ if (pos > 2) { /* </#ai/> => add to open file */
+ if (!stralloc_copyb(&fname,line.s+1,pos-1)) die_nomem();
+ if (!stralloc_0(&fname)) die_nomem();
+ }
+
+ if (str_diff(fname.s, oldfname.s)) {
+ flagnotexist = 1;
+ /* Treat special case of #E when editing which _should*/
+ /* write only if the file does not exist. flagover */
+ /* is set if we need to check */
+ if (flagover) { /* skip if exists */
+ dirplusmake(fname.s); /* decided by FIRST tag for file */
+ fdtmp = open_read(dirplus.s);
+ if (fdtmp == -1) {
+ if (errno != error_noent)
+ strerr_die3sys(111,ERR_OPEN,dirplus.s,": ");
+ } else {
+ flagnotexist = 0; /* already there - don't do it */
+ close(fdtmp);
+ }
+ }
+ if (oldfname.len > 1) {
+ f_close();
+ if (!stralloc_copys(&oldfname,"")) die_nomem();
+ if (!stralloc_0(&oldfname)) die_nomem();
+ }
+ if (flagdo && flagnotexist) {
+ if (!fname.len)
+ strerr_die3x(100,FATAL,ERR_FILENAME,line.s);
+ f_open(fname.s);
+ if (!stralloc_copy(&oldfname,&fname)) die_nomem();
+ }
+ }
+ if (flagdo) flagdo = flagnotexist;
+ continue;
+ } else if (!flagdo)
+ continue; /* part not to go out */
+ last = -1;
+ next = 0;
+ outline.len = 0;
+ for (;;) {
+ pos = next + str_chr(line.s+next,'<');
+ if (line.s[pos] &&
+ line.s[pos+1] == '#' &&
+ line.s[pos+2] &&
+ line.s[pos+3] == '#' &&
+ line.s[pos+4] == '>') { /* host/local */
+ if (!stralloc_catb(&outline,line.s+last+1,pos-last-1))
+ die_nomem();
+ switch (line.s[pos+2]) {
+ case 'B': /* path to ezmlm binaries (no trailing /) */
+ if (!stralloc_cats(&outline,auto_bin)) die_nomem();
+ last = pos + 4; next = pos + 5; break;
+ case 'C': /* digestcode */
+ if (code && *code)
+ if (!stralloc_cats(&outline,code)) die_nomem();
+ last = pos + 4; next = pos + 5; break;
+ case 'D': /* listdir */
+ if (!stralloc_cats(&outline,dir)) die_nomem();
+ last = pos + 4; next = pos + 5; break;
+ case 'F': /* flags */
+ if (!stralloc_cat(&outline,&f)) die_nomem();
+ last = pos + 4; next = pos + 5; break;
+ case 'H': /* hostname */
+ if (!stralloc_cats(&outline,host)) die_nomem();
+ last = pos + 4; next = pos + 5; break;
+ case 'L': /* local */
+ if (!stralloc_cats(&outline,local)) die_nomem();
+ last = pos + 4; next = pos + 5; break;
+ case 'T': /* dot */
+ if (!stralloc_cats(&outline,dot)) die_nomem();
+ last = pos + 4; next = pos + 5; break;
+ case 'X': /* config file name */
+ if (cfname)
+ if (!stralloc_cats(&outline,cfname)) die_nomem();
+ last = pos + 4; next = pos + 5; break;
+ default: /* copy unknown tag as is for e.g. <#A#> and*/
+ /* <#R#> to be processed by -manage/store */
+ /* stuff in args for <#0#> .. <#9#> */
+ if ((line.s[pos+2] >= '0') && (line.s[pos+2] <= '9')) {
+ if (popt[line.s[pos+2] - '0'])
+ if (!stralloc_cats(&outline,popt[line.s[pos+2]-'0']))
+ die_nomem();
+ } else
+ if (!stralloc_catb(&outline,line.s+pos,5)) die_nomem();
+ last = pos + 4; next = pos + 5; break;
+ }
+ } else { /* not tag */
+ if (line.s[pos]) {
+ next++;
+ } else {
+ if (!stralloc_catb(&outline,line.s+last+1,line.len-last-1))
+ die_nomem();
+ f_puts(outline.s);
+ break;
+ }
+ }
+ }
+ }
+
+ close(fdin);
+ if (oldfname.len > 1)
+ f_close();
+
+ if (!flags['e' - 'a']) { /* don't redo key when editing a list */
+ f_open("/key");
+ f_put(key.s,key.len);
+ f_close();
+ }
_exit(0);
}
+