chiark / gitweb /
Import fastforward 0.51
[fastforward] / newinclude.c
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 }