Commit | Line | Data |
---|---|---|
8d5530c4 MW |
1 | #include "substdio.h" |
2 | #include "strerr.h" | |
3 | #include "stralloc.h" | |
4 | #include "getln.h" | |
5 | #include "open.h" | |
6 | #include "readwrite.h" | |
7 | #include "token822.h" | |
8 | #include "control.h" | |
9 | #include "auto_qmail.h" | |
10 | #include "env.h" | |
11 | ||
12 | #define FATAL "newinclude: fatal: " | |
13 | ||
14 | void nomem() | |
15 | { | |
16 | strerr_die2x(111,FATAL,"out of memory"); | |
17 | } | |
18 | void usage() | |
19 | { | |
20 | strerr_die1x(100,"newinclude: usage: newinclude list"); | |
21 | } | |
22 | ||
23 | ||
24 | char *fnlist; | |
25 | substdio sslist; | |
26 | char listbuf[1024]; | |
27 | ||
28 | stralloc bin = {0}; | |
29 | #define fnbin bin.s | |
30 | stralloc tmp = {0}; | |
31 | #define fntmp tmp.s | |
32 | substdio sstmp; | |
33 | char tmpbuf[1024]; | |
34 | ||
35 | void readerr() | |
36 | { | |
37 | strerr_die4sys(111,FATAL,"unable to read ",fnlist,": "); | |
38 | } | |
39 | void writeerr() | |
40 | { | |
41 | strerr_die4sys(111,FATAL,"unable to write to ",fntmp,": "); | |
42 | } | |
43 | ||
44 | void out(s,len) | |
45 | char *s; | |
46 | int len; | |
47 | { | |
48 | if (substdio_put(&sstmp,s,len) == -1) writeerr(); | |
49 | } | |
50 | ||
51 | void doincl(buf,len) | |
52 | char *buf; | |
53 | int len; | |
54 | { | |
55 | if (!len) | |
56 | strerr_die2x(111,FATAL,"empty :include: filenames not permitted"); | |
57 | if (byte_chr(buf,len,'\n') != len) | |
58 | strerr_die2x(111,FATAL,"newlines not permitted in :include: filenames"); | |
59 | if (byte_chr(buf,len,'\0') != len) | |
60 | strerr_die2x(111,FATAL,"NUL not permitted in :include: filenames"); | |
61 | if ((buf[0] != '.') && (buf[0] != '/')) | |
62 | out("./",2); | |
63 | out(buf,len); | |
64 | out("",1); | |
65 | } | |
66 | ||
67 | void dorecip(buf,len) | |
68 | char *buf; | |
69 | int len; | |
70 | { | |
71 | if (!len) | |
72 | strerr_die2x(111,FATAL,"empty recipient addresses not permitted"); | |
73 | if (byte_chr(buf,len,'\n') != len) | |
74 | strerr_die2x(111,FATAL,"newlines not permitted in recipient addresses"); | |
75 | if (byte_chr(buf,len,'\0') != len) | |
76 | strerr_die2x(111,FATAL,"NUL not permitted in recipient addresses"); | |
77 | if (len > 800) | |
78 | strerr_die2x(111,FATAL,"addresses must be under 800 bytes"); | |
79 | if ((buf[len - 1] == ' ') || (buf[len - 1] == '\t')) | |
80 | strerr_die2x(111,FATAL,"spaces and tabs not permitted at ends of addresses"); | |
81 | out("&",1); | |
82 | out(buf,len); | |
83 | out("",1); | |
84 | } | |
85 | ||
86 | ||
87 | void die_control() | |
88 | { | |
89 | strerr_die2sys(111,FATAL,"unable to read controls: "); | |
90 | } | |
91 | ||
92 | stralloc me = {0}; | |
93 | stralloc defaulthost = {0}; | |
94 | stralloc defaultdomain = {0}; | |
95 | stralloc plusdomain = {0}; | |
96 | ||
97 | void readcontrols() | |
98 | { | |
99 | int r; | |
100 | int fddir; | |
101 | char *x; | |
102 | ||
103 | fddir = open_read("."); | |
104 | if (fddir == -1) | |
105 | strerr_die2sys(111,FATAL,"unable to open current directory: "); | |
106 | ||
107 | if (chdir(auto_qmail) == -1) | |
108 | strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": "); | |
109 | ||
110 | r = control_readline(&me,"control/me"); | |
111 | if (r == -1) die_control(); | |
112 | if (!r) if (!stralloc_copys(&me,"me")) nomem(); | |
113 | ||
114 | r = control_readline(&defaultdomain,"control/defaultdomain"); | |
115 | if (r == -1) die_control(); | |
116 | if (!r) if (!stralloc_copy(&defaultdomain,&me)) nomem(); | |
117 | x = env_get("QMAILDEFAULTDOMAIN"); | |
118 | if (x) if (!stralloc_copys(&defaultdomain,x)) nomem(); | |
119 | ||
120 | r = control_readline(&defaulthost,"control/defaulthost"); | |
121 | if (r == -1) die_control(); | |
122 | if (!r) if (!stralloc_copy(&defaulthost,&me)) nomem(); | |
123 | x = env_get("QMAILDEFAULTHOST"); | |
124 | if (x) if (!stralloc_copys(&defaulthost,x)) nomem(); | |
125 | ||
126 | r = control_readline(&plusdomain,"control/plusdomain"); | |
127 | if (r == -1) die_control(); | |
128 | if (!r) if (!stralloc_copy(&plusdomain,&me)) nomem(); | |
129 | x = env_get("QMAILPLUSDOMAIN"); | |
130 | if (x) if (!stralloc_copys(&plusdomain,x)) nomem(); | |
131 | ||
132 | if (fchdir(fddir) == -1) | |
133 | strerr_die2sys(111,FATAL,"unable to set current directory: "); | |
134 | } | |
135 | ||
136 | stralloc cbuf = {0}; | |
137 | token822_alloc toks = {0}; | |
138 | token822_alloc tokaddr = {0}; | |
139 | stralloc address = {0}; | |
140 | ||
141 | void gotincl() | |
142 | { | |
143 | token822_reverse(&tokaddr); | |
144 | if (token822_unquote(&address,&tokaddr) != 1) nomem(); | |
145 | tokaddr.len = 0; | |
146 | doincl(address.s,address.len); | |
147 | } | |
148 | ||
149 | void gotaddr() | |
150 | { | |
151 | int i; | |
152 | int j; | |
153 | int flaghasat; | |
154 | ||
155 | token822_reverse(&tokaddr); | |
156 | if (token822_unquote(&address,&tokaddr) != 1) nomem(); | |
157 | ||
158 | flaghasat = 0; | |
159 | for (i = 0;i < tokaddr.len;++i) | |
160 | if (tokaddr.t[i].type == TOKEN822_AT) | |
161 | flaghasat = 1; | |
162 | ||
163 | tokaddr.len = 0; | |
164 | ||
165 | if (!address.len) return; | |
166 | ||
167 | if (!flaghasat) | |
168 | if (address.s[0] == '/') { | |
169 | if (!stralloc_0(&address)) nomem(); | |
170 | strerr_die4x(111,FATAL,"file delivery ",address.s," not supported"); | |
171 | } | |
172 | if (!flaghasat) | |
173 | if (address.s[0] == '|') { | |
174 | if (!stralloc_0(&address)) nomem(); | |
175 | strerr_die4x(111,FATAL,"program delivery ",address.s," not supported"); | |
176 | } | |
177 | ||
178 | if (!flaghasat) { | |
179 | if (!stralloc_cats(&address,"@")) nomem(); | |
180 | if (!stralloc_cat(&address,&defaulthost)) nomem(); | |
181 | } | |
182 | if (address.s[address.len - 1] == '+') { | |
183 | address.s[address.len - 1] = '.'; | |
184 | if (!stralloc_cat(&address,&plusdomain)) nomem(); | |
185 | } | |
186 | j = 0; | |
187 | for (i = 0;i < address.len;++i) if (address.s[i] == '@') j = i; | |
188 | for (i = j;i < address.len;++i) if (address.s[i] == '.') break; | |
189 | if (i == address.len) { | |
190 | if (!stralloc_cats(&address,".")) nomem(); | |
191 | if (!stralloc_cat(&address,&defaultdomain)) nomem(); | |
192 | } | |
193 | ||
194 | dorecip(address.s,address.len); | |
195 | } | |
196 | ||
197 | ||
198 | stralloc line = {0}; | |
199 | int match; | |
200 | ||
201 | void parseerr() | |
202 | { | |
203 | if (!stralloc_0(&line)) nomem(); | |
204 | strerr_die3x(111,FATAL,"unable to parse this line: ",line.s); | |
205 | } | |
206 | ||
207 | void parseline() | |
208 | { | |
209 | int wordok; | |
210 | struct token822 *t; | |
211 | struct token822 *beginning; | |
212 | ||
213 | switch(token822_parse(&toks,&line,&cbuf)) { | |
214 | case -1: nomem(); | |
215 | case 0: parseerr(); | |
216 | } | |
217 | ||
218 | beginning = toks.t; | |
219 | t = toks.t + toks.len; | |
220 | wordok = 1; | |
221 | ||
222 | if (!token822_readyplus(&tokaddr,1)) nomem(); | |
223 | tokaddr.len = 0; | |
224 | ||
225 | while (t > beginning) | |
226 | switch((--t)->type) { | |
227 | case TOKEN822_SEMI: | |
228 | break; /*XXX*/ | |
229 | case TOKEN822_COLON: | |
230 | if (t >= beginning + 2) | |
231 | if (t[-2].type == TOKEN822_COLON) | |
232 | if (t[-1].type == TOKEN822_ATOM) | |
233 | if (t[-1].slen == 7) | |
234 | if (!byte_diff(t[-1].s,7,"include")) { | |
235 | gotincl(); | |
236 | t -= 2; | |
237 | } | |
238 | break; /*XXX*/ | |
239 | case TOKEN822_RIGHT: | |
240 | if (tokaddr.len) gotaddr(); | |
241 | while ((t > beginning) && (t[-1].type != TOKEN822_LEFT)) | |
242 | if (!token822_append(&tokaddr,--t)) nomem(); | |
243 | gotaddr(); | |
244 | if (t <= beginning) parseerr(); | |
245 | --t; | |
246 | while ((t > beginning) && ((t[-1].type == TOKEN822_COMMENT) || (t[-1].type == TOKEN822_ATOM) || (t[-1].type == TOKEN822_QUOTE) || (t[-1].type == TOKEN822_AT) || (t[-1].type == TOKEN822_DOT))) | |
247 | --t; | |
248 | wordok = 0; | |
249 | continue; | |
250 | case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: | |
251 | if (!wordok) if (tokaddr.len) gotaddr(); | |
252 | wordok = 0; | |
253 | if (!token822_append(&tokaddr,t)) nomem(); | |
254 | continue; | |
255 | case TOKEN822_COMMENT: | |
256 | /* comment is lexically a space; shouldn't affect wordok */ | |
257 | break; | |
258 | case TOKEN822_COMMA: | |
259 | if (tokaddr.len) gotaddr(); | |
260 | wordok = 1; | |
261 | break; | |
262 | default: | |
263 | wordok = 1; | |
264 | if (!token822_append(&tokaddr,t)) nomem(); | |
265 | continue; | |
266 | } | |
267 | if (tokaddr.len) gotaddr(); | |
268 | } | |
269 | ||
270 | ||
271 | void main(argc,argv) | |
272 | int argc; | |
273 | char **argv; | |
274 | { | |
275 | int fd; | |
276 | ||
277 | umask(033); | |
278 | readcontrols(); | |
279 | ||
280 | fnlist = argv[1]; if (!fnlist) usage(); | |
281 | ||
282 | if (!stralloc_copys(&bin,fnlist)) nomem(); | |
283 | if (!stralloc_cats(&bin,".bin")) nomem(); | |
284 | if (!stralloc_0(&bin)) nomem(); | |
285 | ||
286 | if (!stralloc_copys(&tmp,fnlist)) nomem(); | |
287 | if (!stralloc_cats(&tmp,".tmp")) nomem(); | |
288 | if (!stralloc_0(&tmp)) nomem(); | |
289 | ||
290 | fd = open_read(fnlist); | |
291 | if (fd == -1) readerr(); | |
292 | substdio_fdbuf(&sslist,read,fd,listbuf,sizeof listbuf); | |
293 | ||
294 | fd = open_trunc(fntmp); | |
295 | if (fd == -1) writeerr(); | |
296 | substdio_fdbuf(&sstmp,write,fd,tmpbuf,sizeof tmpbuf); | |
297 | ||
298 | for (;;) { | |
299 | if (getln(&sslist,&line,&match,'\n') == -1) readerr(); | |
300 | if (!line.len) break; | |
301 | if (line.s[0] != '#') parseline(); | |
302 | if (!match) break; | |
303 | } | |
304 | ||
305 | if (substdio_flush(&sstmp) == -1) writeerr(); | |
306 | if (fsync(fd) == -1) writeerr(); | |
307 | if (close(fd) == -1) writeerr(); /* NFS stupidity */ | |
308 | ||
309 | if (rename(fntmp,fnbin) == -1) | |
310 | strerr_die6sys(111,FATAL,"unable to move ",fntmp," to ",fnbin,": "); | |
311 | ||
312 | _exit(0); | |
313 | } |