Import ezmlm-idx 0.40
[ezmlm] / copy.c
diff --git a/copy.c b/copy.c
new file mode 100644 (file)
index 0000000..24f0034
--- /dev/null
+++ b/copy.c
@@ -0,0 +1,211 @@
+/*$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);
+}
+