Import ezmlm-idx 0.40
[ezmlm] / copy.c
CommitLineData
f8beb284
MW
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
35static stralloc line = {0};
36static stralloc outline = {0};
37static stralloc qline = {0};
38static stralloc outlocal = {0};
39static stralloc outhost = {0};
40static substdio sstext;
41static char textbuf[256];
42static char *target = "?????";
43static char *verptarget = "?????";
44static char *confirm = "?????";
45static char *szmsgnum = "?????";
46
47void set_cpoutlocal(ln)
48stralloc *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
55void set_cpouthost(ln)
56stralloc *ln;
57{
58 if (!stralloc_copy(&outhost,ln))
59 strerr_die2x(111,FATAL,ERR_NOMEM);
60}
61
62void set_cptarget(tg)
63char *tg;
64{
65 target = tg;
66}
67
68void set_cpverptarget(tg)
69char *tg;
70{
71 verptarget = tg;
72}
73
74void set_cpconfirm(cf)
75char *cf;
76{
77 confirm = cf;
78}
79
80void set_cpnum(cf)
81char *cf;
82{
83 szmsgnum = cf;
84}
85
86static struct qmail *qq;
87
88static void codeput(l,n,code,fatal)
89char *l;
90unsigned int n;
91char code;
92char *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
106static void codeputs(l,code,fatal)
107char *l;
108char code;
109char *fatal;
110{
111 codeput(l,str_len(l),code,fatal);
112}
113
114void copy(qqp,fn,q,fatal)
115struct qmail *qqp;
116char *fn; /* text file name */
117char q; /* = '\0' for regular output, 'B' for base64, */
118 /* 'Q' for quoted printable,'H' for header */
119char *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