18 #include "auto_qmail.h"
20 #define FATAL "dot-forward: fatal: "
21 #define INFO "dot-forward: info: "
24 { strerr_die2x(111,FATAL
,"out of memory"); }
26 { strerr_die2sys(111,FATAL
,"unable to read controls: "); }
28 { strerr_die2sys(111,FATAL
,"unable to run qq: "); }
30 { strerr_die2sys(111,FATAL
,"unable to read message: "); }
36 if (!stralloc_0(&line
)) die_nomem();
37 strerr_die3x(111,FATAL
,"unable to parse this line: ",line
.s
);
58 int blindwrite(fd
,buf
,len
)
59 int fd
; char *buf
; int len
;
74 strerr_warn2("pipe through ",cmd
,0);
79 strerr_die2sys(111,FATAL
,"unable to create pipe: ");
81 switch (child
= fork()) {
83 strerr_die2sys(111,FATAL
,"unable to fork: ");
86 if (fd_move(0,pi
[0]) == -1)
87 strerr_die2sys(111,FATAL
,"unable to set fd: ");
88 args
[0] = "/bin/sh"; args
[1] = "-c"; args
[2] = cmd
; args
[3] = 0;
91 strerr_die2sys(111,FATAL
,"unable to run /bin/sh: ");
96 substdio_fdbuf(&ssmess
,read
,0,messbuf
,sizeof messbuf
);
97 substdio_fdbuf(&sschild
,blindwrite
,pi
[1],childbuf
,sizeof childbuf
);
99 substdio_puts(&sschild
,ufline
);
100 substdio_puts(&sschild
,rpline
);
101 substdio_puts(&sschild
,dtline
);
102 if (substdio_copy(&sschild
,&ssmess
) != 0) die_readmess();
103 substdio_flush(&sschild
);
107 wait_pid(&wstat
,child
);
108 if (wait_crashed(wstat
))
109 strerr_die2x(111,FATAL
,"child crashed");
111 switch(wait_exitcode(wstat
)) {
113 case 64: case 65: case 70: case 76: case 77: case 78: case 112:
121 if (seek_begin(0) == -1)
122 strerr_die2sys(111,FATAL
,"unable to rewind input: ");
125 stralloc targets
= {0};
128 stralloc defaulthost
= {0};
129 stralloc defaultdomain
= {0};
130 stralloc plusdomain
= {0};
137 fddir
= open_read(".");
139 strerr_die2sys(111,FATAL
,"unable to open current directory: ");
141 if (chdir(auto_qmail
) == -1)
142 strerr_die4sys(111,FATAL
,"unable to chdir to ",auto_qmail
,": ");
144 r
= control_readline(&me
,"control/me");
145 if (r
== -1) die_control();
146 if (!r
) if (!stralloc_copys(&me
,"me")) die_nomem();
148 r
= control_readline(&defaultdomain
,"control/defaultdomain");
149 if (r
== -1) die_control();
150 if (!r
) if (!stralloc_copy(&defaultdomain
,&me
)) die_nomem();
152 r
= control_readline(&defaulthost
,"control/defaulthost");
153 if (r
== -1) die_control();
154 if (!r
) if (!stralloc_copy(&defaulthost
,&me
)) die_nomem();
156 r
= control_readline(&plusdomain
,"control/plusdomain");
157 if (r
== -1) die_control();
158 if (!r
) if (!stralloc_copy(&plusdomain
,&me
)) die_nomem();
160 if (fchdir(fddir
) == -1)
161 strerr_die2sys(111,FATAL
,"unable to set current directory: ");
165 token822_alloc toks
= {0};
166 token822_alloc tokaddr
= {0};
167 stralloc address
= {0};
175 token822_reverse(&tokaddr
);
176 if (token822_unquote(&address
,&tokaddr
) != 1) die_nomem();
179 for (i
= 0;i
< tokaddr
.len
;++i
)
180 if (tokaddr
.t
[i
].type
== TOKEN822_AT
)
185 if (!address
.len
) return;
188 if (address
.len
== userlen
)
189 if (!case_diffb(address
.s
,address
.len
,user
)) {
196 if (address
.len
== userlen
+ 1 + hostlen
)
197 if (!case_diffb(address
.s
,userlen
,user
))
198 if (address
.s
[userlen
] == '@')
199 if (!case_diffb(address
.s
+ userlen
+ 1,hostlen
,host
)) {
206 if (address
.s
[0] == '/') {
207 if (!stralloc_0(&address
)) die_nomem();
208 strerr_die4x(111,FATAL
,"file delivery ",address
.s
," not supported");
212 if (address
.s
[0] == '|') {
213 if (!stralloc_0(&address
)) die_nomem();
220 if (!stralloc_cats(&address
,"@")) die_nomem();
221 if (!stralloc_cat(&address
,&defaulthost
)) die_nomem();
223 if (address
.s
[address
.len
- 1] == '+') {
224 address
.s
[address
.len
- 1] = '.';
225 if (!stralloc_cat(&address
,&plusdomain
)) die_nomem();
228 for (i
= 0;i
< address
.len
;++i
) if (address
.s
[i
] == '@') j
= i
;
229 for (i
= j
;i
< address
.len
;++i
) if (address
.s
[i
] == '.') break;
230 if (i
== address
.len
) {
231 if (!stralloc_cats(&address
,".")) die_nomem();
232 if (!stralloc_cat(&address
,&defaultdomain
)) die_nomem();
235 if (!stralloc_0(&address
)) die_nomem();
237 if (!stralloc_cats(&targets
,"T")) die_nomem();
238 if (!stralloc_cats(&targets
,address
.s
)) die_nomem();
239 if (!stralloc_0(&targets
)) die_nomem();
242 strerr_warn2("forward ",address
.s
,0);
249 struct token822
*beginning
;
252 r
= token822_parse(&toks
,&line
,&cbuf
);
253 if (r
== -1) die_nomem();
254 if (r
== 0) die_parse();
257 t
= toks
.t
+ toks
.len
;
260 if (!token822_readyplus(&tokaddr
,1)) die_nomem();
263 while (t
> beginning
)
264 switch((--t
)->type
) {
270 if (tokaddr
.len
) gotaddr();
271 while ((t
> beginning
) && (t
[-1].type
!= TOKEN822_LEFT
))
272 if (!token822_append(&tokaddr
,--t
)) die_nomem();
274 if (t
<= beginning
) die_parse();
276 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
)))
280 case TOKEN822_ATOM
: case TOKEN822_QUOTE
: case TOKEN822_LITERAL
:
281 if (!wordok
) if (tokaddr
.len
) gotaddr();
283 if (!token822_append(&tokaddr
,t
)) die_nomem();
285 case TOKEN822_COMMENT
:
286 /* comment is lexically a space; shouldn't affect wordok */
289 if (tokaddr
.len
) gotaddr();
294 if (!token822_append(&tokaddr
,t
)) die_nomem();
297 if (tokaddr
.len
) gotaddr();
303 char strnum
[FMT_ULONG
];
305 int mywrite(fd
,buf
,len
)
306 int fd
; char *buf
; int len
;
308 qmail_put(&qq
,buf
,len
);
313 substdio ssqq
= SUBSTDIO_FDBUF(mywrite
,-1,qqbuf
,sizeof qqbuf
);
326 if (errno
== error_noent
) return;
327 strerr_die4sys(111,FATAL
,"unable to open ",fn
,": ");
330 if (!stralloc_copys(&targets
,"")) die_nomem();
334 substdio_fdbuf(&ss
,read
,fd
,inbuf
,sizeof inbuf
);
337 if (getln(&ss
,&line
,&match
,'\n') == -1)
338 strerr_die4sys(111,FATAL
,"unable to read ",fn
,": ");
339 if (!line
.len
) break;
340 if (line
.s
[0] != '#') parseline();
349 if (qmail_open(&qq
) == -1)
350 strerr_die2sys(111,FATAL
,"unable to run qmail-queue: ");
352 qmail_puts(&qq
,dtline
);
354 substdio_fdbuf(&ssmess
,read
,0,messbuf
,sizeof messbuf
);
355 if (substdio_copy(&ssqq
,&ssmess
) != 0) die_readmess();
356 substdio_flush(&ssqq
);
358 qmail_from(&qq
,sender
);
359 qmail_put(&qq
,targets
.s
,targets
.len
);
361 qqx
= qmail_close(&qq
);
363 strerr_die3x(100,FATAL
,"unable to forward message: ",qqx
+ 1);
365 strerr_die3x(111,FATAL
,"unable to forward message: ",qqx
+ 1);
366 strnum
[fmt_ulong(strnum
,qp
)] = 0;
367 strerr_warn3(INFO
,"qp ",strnum
,0);
372 if (!flagdoit
) strerr_warn1("direct delivery",0);
376 if (!flagdoit
) strerr_warn2("skipping empty file ",fn
,0);
391 while ((opt
= getopt(argc
,argv
,"nN")) != opteof
)
398 strerr_die1x(100,"dot-forward: usage: dot-forward [ -nN ] file ...");
402 ufline
= env_get("UFLINE"); if (!ufline
) ufline
= "";
403 rpline
= env_get("RPLINE"); if (!rpline
) rpline
= "";
404 dtline
= env_get("DTLINE"); if (!dtline
) dtline
= "";
405 sender
= env_get("NEWSENDER"); if (!sender
) sender
= "";
407 user
= env_get("USER"); if (!user
) user
= "";
408 userlen
= str_len(user
);
409 host
= env_get("HOST"); if (!host
) host
= "";
410 hostlen
= str_len(host
);
417 if (!flagdoit
) strerr_warn1("direct delivery",0);