ezmlmx 0.68
ezmlmx
Loading...
Searching...
No Matches
ezmlm-receipt.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include "direntry.h"
3#include "stralloc.h"
4#include "str.h"
5#include "env.h"
6#include "readclose.h"
7#include "getconf.h"
8#include "strerr.h"
9#include "byte.h"
10#include "case.h"
11#include "quote.h"
12#include "getln.h"
13#include "buffer.h"
14#include "error.h"
15#include "readwrite.h"
16#include "fmt.h"
17#include "now.h"
18#include "seek.h"
19#include "idx.h"
20#include "errtxt.h"
21#include "logmsg.h"
22#include "ezmlm.h"
23
24#define WHO "ezmlm-receipt"
25
33
34static void die_usage() { logmsg(WHO,100,USAGE,"ezmlm-receipt [-dD] dir"); }
35static void die_nomem() { logmsg(WHO,111,FATAL,ERR_NOMEM); }
36static void die_badaddr() { logmsg(WHO,100,FATAL,ERR_BAD_ADDRESS); }
37static void die_trash() { logmsg(WHO,0,INFO,"trash address"); }
38
39outhost = {0};
40outlocal = {0};
41quoted = {0};
42
43stralloc line = {0};
44stralloc quoted = {0};
45stralloc intro = {0};
46stralloc bounce = {0};
47stralloc header = {0};
48stralloc failure = {0};
49stralloc paragraph = {0};
50stralloc ddir = {0};
51stralloc inlocal = {0};
52stralloc tagline = {0};
53stralloc listaddr = {0};
54stralloc fndate = {0};
55stralloc fndir = {0};
56stralloc fndatenew = {0};
57
58void die_datenew() { logmsg(WHO,111,FATAL,B(ERR_WRITE,fndatenew.s)); }
59void die_msgin() { logmsg(WHO,111,FATAL,ERR_READ_INPUT); }
60
61char strnum[FMT_ULONG];
62char inbuf[1024];
63buffer bi;
64
65char outbuf[256]; /* small - rarely used */
66buffer bo;
67
68unsigned long when;
69unsigned long addrno = 0L;
70
71char *sender;
72char *dir;
73char *workdir;
74void **psql = (void **) 0;
75stralloc listno = {0};
76
86
87void doit(char *addr,unsigned long msgnum,unsigned long when,stralloc *bounce)
88{
89 int fd;
90 unsigned int pos;
91 DIR *bouncedir;
92 direntry *d;
93 unsigned int no;
94
95 if (!stralloc_copys(&fndir,workdir)) die_nomem();
96 if (!stralloc_cats(&fndir,"/bounce")) die_nomem();
97 if (!stralloc_0(&fndir)) die_nomem();
98 bouncedir = opendir(fndir.s);
99 if (!bouncedir)
100 if (errno != ENOENT)
101 logmsg(WHO,111,FATAL,B(ERR_OPEN,line.s));
102 else
103 logmsg(WHO,111,FATAL,B(fndir.s,ERR_NOEXIST));
104
105 no = MAX_MAIN_BOUNCES; /* no more than this many allowed */
106 while (no && (d = readdir(bouncedir))) {
107 if (str_equal(d->d_name,".")) continue;
108 if (str_equal(d->d_name,"..")) continue;
109 --no;
110 }
111 closedir(bouncedir);
112 if (!no) /* max no of bounces exceeded */
113 logmsg(WHO,0,INFO,ERR_MAX_BOUNCE);
114
115 if (!stralloc_copys(&fndate,workdir)) die_nomem(); /* save bounce */
116 if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem();
117 pos = fndate.len - 1;
118 if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem();
119 if (!stralloc_cats(&fndate,".")) die_nomem();
120 if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid())))
121 die_nomem();
122 if (addrno) { /* so that pre-VERP bounces make a d... file per address */
123 /* for the first one we use the std-style fname */
124 if (!stralloc_cats(&fndate,".")) die_nomem();
125 if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,addrno))) die_nomem();
126 }
127 addrno++; /* get ready for next */
128 if (!stralloc_0(&fndate)) die_nomem();
129 if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
130 fndatenew.s[pos] = 'D';
131
132 fd = open_trunc(fndatenew.s);
133 if (fd == -1) die_datenew();
134 buffer_fdbuf(&bo,write,fd,outbuf,sizeof(outbuf));
135 if (buffer_puts(&bo,addr) == -1) die_datenew();
136 if (buffer_put(&bo,"",1) == -1) die_datenew();
137 if (buffer_put(&bo,strnum,fmt_ulong(strnum,msgnum)) == -1)
138 die_datenew();
139 if (buffer_put(&bo,"",1) == -1) die_datenew();
140
141 if (buffer_puts(&bo,"Return-Path: <") == -1) die_datenew();
142 if (!quote2(&quoted,sender)) die_nomem();
143 if (buffer_put(&bo,quoted.s,quoted.len) == -1) die_datenew();
144 if (buffer_puts(&bo,">\n") == -1) die_datenew();
145 if (buffer_put(&bo,bounce->s,bounce->len) == -1) die_datenew();
146 if (buffer_flush(&bo) == -1) die_datenew();
147 if (fsync(fd) == -1) die_datenew();
148 if (close(fd) == -1) die_datenew(); /* NFS stupidity */
149 if (rename(fndatenew.s,fndate.s) == -1)
150 logmsg(WHO,111,FATAL,B(ERR_MOVE,fndatenew.s," to ",fndate.s));
151}
152
153int main(int argc,char **argv)
154{
155 char *local;
156 char *host;
157 char *action;
158 char *def;
159 int flagdig = 1;
160 int flaghaveintro;
161 int flaghaveheader;
162 int match;
163 unsigned long msgnum;
164 unsigned int i;
165 unsigned int len;
166 char *cp;
167
168 umask(022);
169 sig_pipeignore();
170
171 when = (unsigned long) now();
172
173 dir = argv[1];
174 if (!dir) die_usage();
175 if (*dir == '-') {
176 if (dir[1] == 'd') {
177 flagdig = 2;
178 } else if (dir[1] == 'D') {
179 flagdig = 0;
180 } else
181 die_usage();
182 dir = argv[2];
183 if (!dir) die_usage();
184 }
185 if (chdir(dir) == -1)
186 logmsg(WHO,111,FATAL,B(ERR_SWITCH,dir));
187
188 sender = env_get("SENDER");
189 def = env_get("DEFAULT");
190 local = env_get("LOCAL");
191
192 getconf_line(&outhost,"outhost",1,FATAL,dir);
193 getconf_line(&outlocal,"outlocal",1,FATAL,dir);
194 workdir = dir;
195 if (def) { /* qmail>=1.02 */
196 action = def; /* now see if -digest-return- */
197 if (flagdig == 1) {
198 flagdig = 0;
199 if (str_len(local) >= str_len(def) + 14)
200 if (str_start(local + str_len(local) - 14 - str_len(def),"digest-"))
201 flagdig = 2;
202 }
203 }
204 if (flagdig) {
205 if (!stralloc_copys(&ddir,dir)) die_nomem();
206 if (!stralloc_cats(&ddir,"/digest")) die_nomem();
207 if (!stralloc_0(&ddir)) die_nomem();
208 workdir = ddir.s;
209 if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
210 }
211 if (!*action) die_trash();
212
213 buffer_init(&bi,unixread,0,inbuf,sizeof(inbuf));
214
215 if (!case_diffs(action,"receipt")) {
216 host = sender + str_rchr(sender,'@');
217 if (*host)
218 *(host++) = '\0';
219 cp = sender;
220 /* check recipient in case it's a bounce*/
221 while (*(cp++)) { /* decode sender */
222 cp += str_chr(cp,'-');
223 if (case_starts(cp,"-return-")) {
224 if (!scan_ulong(cp + 8,&msgnum))
225 logmsg(WHO,100,FATAL,"bad VERP format for receipt");
226 *cp = '\0';
227 if (!stralloc_copys(&listaddr,sender)) die_nomem();
228 if (!stralloc_append(&listaddr,"@")) die_nomem();
229 if (!stralloc_cats(&listaddr,host)) die_nomem();
230 if (!stralloc_0(&listaddr)) die_nomem();
231 break;
232 }
233 }
234 for (;;) { /* Get X-tag from hdr*/
235 if (getln(&bi,&line,&match,'\n') == -1) die_msgin();
236 if (!match)
237 break;
238
239 if (line.len == 1) break;
240 if (case_startb(line.s,line.len,TXT_TAG)) {
241 len = str_len(TXT_TAG);
242 if (!stralloc_catb(&tagline,line.s +len,line.len - len -1)) die_nomem();
243 /* NOTE: tagline is dirty! We quote it for sql and rely on */
244 /* std log clean for maillog */
245 break;
246 }
247 }
248
249 /* feedback ok even if not sub. Will be filtered by subreceipt*/
250 /* For instance, main list feedback is ok, but !issub. */
251
252 subreceipt(workdir,msgnum,&tagline,listaddr.s,2,INFO,FATAL);
253 closesql();
254 _exit(0);
255 }
256 /* not receipt - maybe bounce */
257 /* no need to lock. dttt.pid can be assumed */
258 /* to be unique and if not would be over- */
259 /* written even with lock */
260
261 action += scan_ulong(action,&msgnum);
262 if (*action != '-') die_badaddr();
263 ++action;
264 /* scan bounce for tag. It'll be in the BODY! */
265 for (;;) {
266 if (getln(&bi,&line,&match,'\n') == -1)
267 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
268 if (!match) break;
269 if (case_startb(line.s,line.len,TXT_TAG)) {
270 len = str_len(TXT_TAG);
271 if (!stralloc_catb(&tagline,line.s +len,line.len - len -1)) die_nomem();
272 /* NOTE: tagline is dirty! We quote it for sql and rely on */
273 /* std log clean for maillog */
274 break;
275 }
276 }
277 if (seek_begin(0) == -1)
278 logmsg(WHO,111,FATAL,ERR_SEEK_INPUT);
279 buffer_init(&bi,unixread,0,inbuf,sizeof(inbuf));
280
281 if (*action) { /* normal bounce */
282 if (readclose(0,&bounce,1024) == -1) die_msgin();
283 i = str_rchr(action,'=');
284 if (!stralloc_copyb(&listaddr,action,i)) die_nomem();
285 if (action[i]) {
286 if (!stralloc_cats(&listaddr,"@")) die_nomem();
287 if (!stralloc_cats(&listaddr,action + i + 1)) die_nomem();
288 }
289 if (!stralloc_0(&listaddr)) die_nomem();
290 /* don't check for sub, since issub() doesn't see sublists */
291 switch (subreceipt(workdir,msgnum,&tagline,listaddr.s,-1,INFO,FATAL)) {
292 case -1: logmsg(WHO,0,INFO,ERR_COOKIE);
293 case -2: logmsg(WHO,0,INFO,ERR_NOT_ACTIVE);
294 default: doit(listaddr.s,msgnum,when,&bounce);
295 }
296 closesql();
297 _exit(0);
298 } /* pre-VERP bounce, in QSBMF format */
299
300 flaghaveheader = 0;
301 flaghaveintro = 0;
302
303 for (;;) {
304 if (!stralloc_copys(&paragraph,"")) die_nomem();
305 for (;;) {
306 if (getln(&bi,&line,&match,'\n') == -1)
307 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
308 if (!match) die_trash();
309 if (!stralloc_cat(&paragraph,&line)) die_nomem();
310 if (line.len <= 1) break;
311 }
312
313 if (!flaghaveheader) {
314 if (!stralloc_copy(&header,&paragraph)) die_nomem();
315 flaghaveheader = 1;
316 continue;
317 }
318
319 if (!flaghaveintro) {
320 if (paragraph.s[0] == '-' && paragraph.s[1] == '-')
321 continue; /* skip MIME boundary if it exists */
322 if (paragraph.len < 15) die_trash();
323 if (str_diffn(paragraph.s,"Hi. This is the",15)) die_trash();
324 if (!stralloc_copy(&intro,&paragraph)) die_nomem();
325 flaghaveintro = 1;
326 continue;
327 }
328
329 if (paragraph.s[0] == '-')
330 break;
331
332 if (paragraph.s[0] == '<') { /* find address */
333 if (!stralloc_copy(&failure,&paragraph)) die_nomem();
334 if (!stralloc_copy(&bounce,&header)) die_nomem();
335 if (!stralloc_cat(&bounce,&intro)) die_nomem();
336 if (!stralloc_cat(&bounce,&failure)) die_nomem();
337
338 i = byte_chr(failure.s,failure.len,'\n');
339 if (i < 3) die_trash();
340
341 if (!stralloc_copyb(&listaddr,failure.s + 1,i - 3)) die_nomem();
342 if (byte_chr(listaddr.s,listaddr.len,'\0') == listaddr.len) {
343 if (!stralloc_0(&listaddr)) die_nomem();
344 if (subreceipt(workdir,msgnum,&tagline,listaddr.s,-1,INFO,FATAL) == 0)
346 }
347 }
348 }
349 closesql();
350 _exit(0);
351
352 return 0;
353}
datetime_sec now(void)
Definition now.c:5
#define MAX_MAIN_BOUNCES
Definition idx.h:283
#define TXT_TAG
Definition idx.h:280
int quote2(stralloc *sa, const char *s)
Definition quote.c:65
Error messages. If you translate these, I would urge you to keep the English version as well....
#define ERR_NOMEM
Definition errtxt.h:14
#define ERR_OPEN
Definition errtxt.h:30
#define ERR_MOVE
Definition errtxt.h:29
#define ERR_NOT_ACTIVE
Definition errtxt.h:154
#define ERR_NOEXIST
Definition errtxt.h:40
#define ERR_READ_INPUT
Definition errtxt.h:26
#define ERR_COOKIE
Definition errtxt.h:153
#define ERR_BAD_ADDRESS
Definition errtxt.h:50
#define ERR_SWITCH
Definition errtxt.h:42
#define ERR_WRITE
Definition errtxt.h:17
#define ERR_SEEK_INPUT
Definition errtxt.h:27
#define ERR_MAX_BOUNCE
Definition errtxt.h:157
charset, outhost, outlocal and flagcd are shared
void closesql(void)
close connection to SQL server, if open
Definition opensql.c:21
void die_nomem()
Definition getconf.c:17
int getconf_line(stralloc *sa, const char *fn, int flagrequired, const char *dir)
Definition getconf.c:53
#define WHO
Definition author.c:1
char * workdir
Definition ezmlm-get.c:129
stralloc listno
Definition ezmlm-get.c:78
stralloc ddir
Definition ezmlm-get.c:116
char inbuf[1024]
char outbuf[1024]
char * dir
buffer bi
buffer bo
int flagdig
int main()
Definition ezmlm-weed.c:69
void die_datenew()
stralloc inlocal
stralloc fndate
stralloc failure
stralloc bounce
unsigned long addrno
stralloc header
void ** psql
stralloc intro
void die_msgin()
stralloc fndatenew
stralloc paragraph
stralloc fndir
stralloc tagline
void doit(char *addr, unsigned long msgnum, unsigned long when, stralloc *bounce)
stralloc listaddr
Definition ezmlm-cron.c:49
const char * cp
Definition ezmlm-cron.c:76
unsigned int len
Definition ezmlm-cron.c:68
stralloc addr
Definition ezmlm-cron.c:45
char * host
Definition ezmlm-cgi.c:107
char * local
Definition ezmlm-cgi.c:106
int fd
Definition ezmlm-cgi.c:141
datetime_sec when
Definition ezmlm-cgi.c:173
int match
Definition ezmlm-cgi.c:140
int flaghaveheader
int flaghaveintro
unsigned long msgnum
stralloc quoted
Definition ezmlm-clean.c:90
stralloc action
Definition ezmlm-store.c:84
const char * logmsg(const char *dir, unsigned long num, unsigned long listno, unsigned long subs, int done)
Definition loginfo.c:32
int subreceipt(char *dir, unsigned long msgnum, stralloc *cookie, char *listaddr, int done, char *info, char *fatal)
Definition subreceipt.c:40