/*$Id: copy.c,v 1.10 1999/08/07 19:28:16 lindberg Exp $*/ /*$Name: ezmlm-idx-040 $*/ /* Copies a file relative the current directory and substitutes */ /* !A at the beginning of a line for the target, */ /* !R at the beginning of a line for the confirm reply address, */ /* The following substitutions are also made. If not set, ????? */ /* will be printed: <#l#> outlocal */ /* will be printed: <#h#> outhost */ /* will be printed: <#n#> outmsgnum */ /* Other tags are killed, e.g. removed. A missing file is a */ /* permanent error so owner finds out ASAP. May not have access to */ /* maillog. Content transfer encoding is done for 'B' and 'Q'. For */ /* 'H' no content transfer encoding is done, but blank lines are */ /* suppressed. Behavior for other codes is undefined. This includes*/ /* lower case 'q'/'b'! If code is 'H' substitution of target and */ /* verptarget is prevented as it may create illegal headers. */ #include "stralloc.h" #include "substdio.h" #include "strerr.h" #include "str.h" #include "getln.h" #include "case.h" #include "readwrite.h" #include "qmail.h" #include "errtxt.h" #include "error.h" #include "quote.h" #include "copy.h" #include "mime.h" /* for public setup functions only */ #define FATAL "copy: fatal: " static stralloc line = {0}; static stralloc outline = {0}; static stralloc qline = {0}; static stralloc outlocal = {0}; static stralloc outhost = {0}; static substdio sstext; static char textbuf[256]; static char *target = "?????"; static char *verptarget = "?????"; static char *confirm = "?????"; static char *szmsgnum = "?????"; void set_cpoutlocal(ln) stralloc *ln; { /* must be quoted for safety. Note that substitutions that use */ /* outlocal within an atom may create illegal addresses */ if (!quote(&outlocal,ln)) strerr_die2x(111,FATAL,ERR_NOMEM); } void set_cpouthost(ln) stralloc *ln; { if (!stralloc_copy(&outhost,ln)) strerr_die2x(111,FATAL,ERR_NOMEM); } void set_cptarget(tg) char *tg; { target = tg; } void set_cpverptarget(tg) char *tg; { verptarget = tg; } void set_cpconfirm(cf) char *cf; { confirm = cf; } void set_cpnum(cf) char *cf; { szmsgnum = cf; } static struct qmail *qq; static void codeput(l,n,code,fatal) char *l; unsigned int n; char code; char *fatal; { if (!code || code == 'H') qmail_put(qq,l,n); else { if (code == 'Q') encodeQ(l,n,&qline,fatal); else encodeB(l,n,&qline,0,fatal); qmail_put(qq,qline.s,qline.len); } } static void codeputs(l,code,fatal) char *l; char code; char *fatal; { codeput(l,str_len(l),code,fatal); } void copy(qqp,fn,q,fatal) struct qmail *qqp; char *fn; /* text file name */ char q; /* = '\0' for regular output, 'B' for base64, */ /* 'Q' for quoted printable,'H' for header */ char *fatal; /* FATAL error string */ { int fd; int match, done; unsigned int pos,nextpos; qq = qqp; if ((fd = open_read(fn)) == -1) if (errno != error_noent) strerr_die4sys(111,fatal,ERR_OPEN,fn,": "); else strerr_die4sys(100,fatal,ERR_OPEN,fn,": "); substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); for (;;) { if (getln(&sstext,&line,&match,'\n') == -1) strerr_die4sys(111,fatal,ERR_READ,fn,": "); if (match) { /* suppress blank line for 'H'eader mode */ if (line.len == 1 && q == 'H') continue; if (line.s[0] == '!') { if (line.s[1] == 'R') { codeput(" ",3,q,fatal); codeputs(confirm,q,fatal); codeput("\n",1,q,fatal); continue; } if (line.s[1] == 'A') { codeput(" ",3,q,fatal); codeputs(target,q,fatal); codeput("\n",1,q,fatal); continue; } } /* Find tags <#x#>. Replace with for x=R confirm, for x=A */ /* target, x=l outlocal, x=h outhost. For others, just */ /* skip tag. If outlocal/outhost are not set, the tags are*/ /* skipped. If confirm/taget are not set, the tags are */ /* replaced by "???????" */ pos = 0; nextpos = 0; done = 0; outline.len = 0; /* zap outline */ while ((pos += byte_chr(line.s+pos,line.len-pos,'<')) != line.len) { if (pos + 4 < line.len && line.s[pos+1] == '#' && line.s[pos+3] == '#' && line.s[pos+4] == '>') { /* tag. Copy first part of line */ done = 1; /* did something */ if (!stralloc_catb(&outline,line.s+nextpos,pos-nextpos)) die_nomem(fatal); switch(line.s[pos+2]) { case 'A': if (q == 'H') strerr_die(111,ERR_SUBST_UNSAFE); if (!stralloc_cats(&outline,target)) die_nomem(fatal); break; case 'R': if (!stralloc_cats(&outline,confirm)) die_nomem(fatal); break; case 'l': if (!stralloc_cat(&outline,&outlocal)) die_nomem(fatal); break; case 'h': if (!stralloc_cat(&outline,&outhost)) die_nomem(fatal); break; case 't': if (q == 'H') strerr_die(111,ERR_SUBST_UNSAFE); if (!stralloc_cats(&outline,verptarget)) die_nomem(fatal); break; case 'n': if (!stralloc_cats(&outline,szmsgnum)) die_nomem(fatal); break; default: break; /* unknown tags killed */ } pos += 5; nextpos = pos; } else ++pos; /* try next position */ } if (!done) codeput(line.s,line.len,q,fatal); else { if (!stralloc_catb(&outline,line.s+nextpos,line.len-nextpos)) die_nomem(fatal); /* remainder */ codeput(outline.s,outline.len,q,fatal); } } else break; } close(fd); }