chiark / gitweb /
Debianization and various other fixes.
[ezmlm] / copy.c
1 /*$Id: copy.c,v 1.10 1999/08/07 19:28:16 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
3
4 /* Copies a file relative the current directory and substitutes    */
5 /* !A at the beginning of a line for the target,                   */
6 /* !R at the beginning of a line for the confirm reply address,    */
7 /* The following substitutions are also made. If not set, ?????    */
8 /* will be printed:  <#l#> outlocal                                */
9 /* will be printed:  <#h#> outhost                                 */
10 /* will be printed:  <#n#> outmsgnum                               */
11 /* Other tags are killed, e.g. removed. A missing file is a        */
12 /* permanent error so owner finds out ASAP. May not have access to */
13 /* maillog. Content transfer encoding is done for 'B' and 'Q'. For */
14 /* 'H' no content transfer encoding is done, but blank lines are   */
15 /* suppressed. Behavior for other codes is undefined. This includes*/
16 /* lower case 'q'/'b'! If code is 'H' substitution of target and   */
17 /* verptarget is prevented as it may create illegal headers.       */
18
19 #include "stralloc.h"
20 #include "substdio.h"
21 #include "strerr.h"
22 #include "str.h"
23 #include "getln.h"
24 #include "case.h"
25 #include "readwrite.h"
26 #include "qmail.h"
27 #include "errtxt.h"
28 #include "error.h"
29 #include "quote.h"
30 #include "copy.h"
31 #include "mime.h"
32                         /* for public setup functions only */
33 #define FATAL "copy: fatal: "
34
35 static stralloc line = {0};
36 static stralloc outline = {0};
37 static stralloc qline = {0};
38 static stralloc outlocal = {0};
39 static stralloc outhost = {0};
40 static substdio sstext;
41 static char textbuf[256];
42 static char *target = "?????";
43 static char *verptarget = "?????";
44 static char *confirm = "?????";
45 static char *szmsgnum = "?????";
46
47 void set_cpoutlocal(ln)
48 stralloc *ln;
49 {       /* must be quoted for safety. Note that substitutions that use */
50         /* outlocal within an atom may create illegal addresses */
51   if (!quote(&outlocal,ln))
52         strerr_die2x(111,FATAL,ERR_NOMEM);
53 }
54
55 void set_cpouthost(ln)
56 stralloc *ln;
57 {
58   if (!stralloc_copy(&outhost,ln))
59         strerr_die2x(111,FATAL,ERR_NOMEM);
60 }
61
62 void set_cptarget(tg)
63 char *tg;
64 {
65   target = tg;
66 }
67
68 void set_cpverptarget(tg)
69 char *tg;
70 {
71   verptarget = tg;
72 }
73
74 void set_cpconfirm(cf)
75 char *cf;
76 {
77   confirm = cf;
78 }
79
80 void set_cpnum(cf)
81 char *cf;
82 {
83   szmsgnum = cf;
84 }
85
86 static struct qmail *qq;
87
88 static void codeput(l,n,code,fatal)
89 char *l;
90 unsigned int n;
91 char code;
92 char *fatal;
93
94 {
95   if (!code || code == 'H')
96     qmail_put(qq,l,n);
97   else {
98     if (code == 'Q')
99       encodeQ(l,n,&qline,fatal);
100     else
101       encodeB(l,n,&qline,0,fatal);
102     qmail_put(qq,qline.s,qline.len);
103   }
104 }
105
106 static void codeputs(l,code,fatal)
107 char *l;
108 char code;
109 char *fatal;
110 {
111   codeput(l,str_len(l),code,fatal);
112 }
113
114 void copy(qqp,fn,q,fatal)
115 struct qmail *qqp;
116 char *fn;               /* text file name */
117 char q;                 /* = '\0' for regular output, 'B' for base64, */
118                         /* 'Q' for quoted printable,'H' for header    */
119 char *fatal;            /* FATAL error string */
120
121 {
122   int fd;
123   int match, done;
124   unsigned int pos,nextpos;
125
126   qq = qqp;
127   if ((fd = open_read(fn)) == -1)
128     if (errno != error_noent)
129       strerr_die4sys(111,fatal,ERR_OPEN,fn,": ");
130     else
131       strerr_die4sys(100,fatal,ERR_OPEN,fn,": ");
132   substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
133   for (;;) {
134     if (getln(&sstext,&line,&match,'\n') == -1)
135       strerr_die4sys(111,fatal,ERR_READ,fn,": ");
136     if (match) {        /* suppress blank line for 'H'eader mode */
137       if (line.len == 1 && q == 'H') continue;
138       if (line.s[0] == '!') {
139         if (line.s[1] == 'R') {
140           codeput("   ",3,q,fatal);
141           codeputs(confirm,q,fatal);
142           codeput("\n",1,q,fatal);
143           continue;
144         }
145         if (line.s[1] == 'A') {
146           codeput("   ",3,q,fatal);
147           codeputs(target,q,fatal);
148           codeput("\n",1,q,fatal);
149           continue;
150         }
151       }
152                 /* Find tags <#x#>. Replace with for x=R confirm, for x=A */
153                 /* target, x=l outlocal, x=h outhost. For others, just    */
154                 /* skip tag. If outlocal/outhost are not set, the tags are*/
155                 /* skipped. If confirm/taget are not set, the tags are    */
156                 /* replaced by "???????" */
157       pos = 0;
158       nextpos = 0;
159       done = 0;
160       outline.len = 0;                  /* zap outline */
161       while ((pos += byte_chr(line.s+pos,line.len-pos,'<')) != line.len) {
162         if (pos + 4 < line.len &&
163             line.s[pos+1] == '#' &&
164             line.s[pos+3] == '#' &&
165             line.s[pos+4] == '>') {     /* tag. Copy first part of line */
166           done = 1;                             /* did something */
167           if (!stralloc_catb(&outline,line.s+nextpos,pos-nextpos))
168                          die_nomem(fatal);
169           switch(line.s[pos+2]) {
170             case 'A':
171               if (q == 'H') strerr_die(111,ERR_SUBST_UNSAFE);
172               if (!stralloc_cats(&outline,target)) die_nomem(fatal);
173               break;
174             case 'R':
175               if (!stralloc_cats(&outline,confirm)) die_nomem(fatal);
176               break;
177             case 'l':
178               if (!stralloc_cat(&outline,&outlocal)) die_nomem(fatal);
179               break;
180             case 'h':
181               if (!stralloc_cat(&outline,&outhost)) die_nomem(fatal);
182               break;
183             case 't':
184               if (q == 'H') strerr_die(111,ERR_SUBST_UNSAFE);
185               if (!stralloc_cats(&outline,verptarget)) die_nomem(fatal);
186               break;
187             case 'n':
188               if (!stralloc_cats(&outline,szmsgnum)) die_nomem(fatal);
189               break;
190             default:
191               break;                    /* unknown tags killed */
192           }
193           pos += 5;
194           nextpos = pos;
195         } else
196           ++pos;                                /* try next position */
197       }
198       if (!done)
199         codeput(line.s,line.len,q,fatal);
200       else {
201         if (!stralloc_catb(&outline,line.s+nextpos,line.len-nextpos))
202                 die_nomem(fatal);               /* remainder */
203         codeput(outline.s,outline.len,q,fatal);
204       }
205
206     } else
207       break;
208   }
209   close(fd);
210 }
211