Commit | Line | Data |
---|---|---|
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 | ||
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 |