ezmlmx 0.68
ezmlmx
Loading...
Searching...
No Matches
ezmlm-dispatch.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include "env.h"
5#include "getoptb.h"
6#include "buffer.h"
7#include "errtxt.h"
8#include "error.h"
9#include "byte.h"
10#include "fmt.h"
11#include "str.h"
12#include "stralloc.h"
13#include "qmail.h"
14#include "seek.h"
15#include "wrap.h"
16#include "readclose.h"
17#include "auto_version.h"
18#include "logmsg.h"
19
20#define WHO "ezmlm-dispatch"
21
27
28static void die_usage(void) { logmsg(WHO,100,USAGE,"ezmlm-dispatch dir [list]"); }
29static void die_nomem(void) { logmsg(WHO,111,FATAL,ERR_NOMEM); }
30
31static const char *sender;
32static const char *basedir;
33static const char *listdir;
34
35struct qmail qq;
36static stralloc path = {0};
37static char strnum[FMT_ULONG];
38static int did_program;
39static int did_forward;
40
41static void make_path(const char *fn)
42{
43 if (!stralloc_copys(&path,basedir)) die_nomem();
44 if (listdir) {
45 if (!stralloc_cats(&path,"/")) die_nomem();
46 if (!stralloc_cats(&path,listdir)) die_nomem();
47 }
48 if (fn) {
49 if (!stralloc_cats(&path,"/")) die_nomem();
50 if (!stralloc_cats(&path,fn)) die_nomem();
51 }
52 if (!stralloc_0(&path)) die_nomem();
53}
54
55static int is_dir(const char *fn)
56{
57 struct stat st;
58 make_path(fn);
59 return wrap_stat(path.s,&st) == 0
60 && S_ISDIR(st.st_mode);
61}
62
63static int is_file(const char *fn)
64{
65 struct stat st;
66 make_path(fn);
67 return (wrap_stat(path.s,&st) == 0 && S_ISREG(st.st_mode));
68}
69
70static void forward(const char *rcpt)
71{
72 char buf[4096];
73 const char *dtline;
74 const char *err;
75 int r;
76
77 if (qmail_open(&qq,0) == -1)
78 logmsg(WHO,111,FATAL,ERR_QMAIL_QUEUE);
79 if ((dtline = env_get("DTLINE")) != 0)
81 while ((r = read(0,buf,sizeof buf)) > 0)
82 qmail_put(&qq,buf,r);
83 if (r == -1)
84 logmsg(WHO,111,FATAL,ERR_READ);
85 qmail_from(&qq,sender);
86 qmail_to(&qq,rcpt);
87 if (*(err = qmail_close(&qq)) != '\0')
88 logmsg(WHO,111,FATAL,B(ERR_TMP_QMAIL_QUEUE,err + 1));
89 strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
90 buffer_puts(buffer_2,"qp ");
91 buffer_puts(buffer_2,strnum);
92 buffer_putsflush(buffer_2,"\n");
93 ++did_forward;
94}
95
96static void execute_line(const char *line)
97{
98 int child;
99 int code;
100 if (seek_begin(0) == -1)
101 logmsg(WHO,111,FATAL,ERR_SEEK_INPUT);
102 while (*line && (*line == '\t' || *line == ' '))
103 ++line;
104 switch (*line) {
105 case '#': break; /* ignore comments */
106 case '|': if ((child = wrap_fork()) == 0) wrap_execsh(line+1);
107 if ((code = wrap_waitpid(child)) != 0) _exit(code);
108 ++did_program; break;
109 case '/':
110 case '.': logmsg(WHO,100,FATAL,B("Delivery to files is not supported for: ",path.s)); break;
111 default: if (*line == '&') ++line;
112 forward(line);
113 }
114}
115
116static void execute_file(stralloc *file)
117{
118 int start;
119 int end;
120 int len;
121 for (start = 0; start < file->len; start = end + 1) {
122 len = byte_chr(file->s+start,file->len-start,'\n');
123 end = start + len;
124 file->s[end] = 0;
125 execute_line(file->s+start);
126 }
127}
128
129/* Load and execute a qmail command file. */
130
131static void execute(const char *fn,const char *def)
132{
133 stralloc file = {0, 0, 0};
134 if (def != 0)
135 env_put2("DEFAULT",def);
136 else
137 env_unset("DEFAULT");
138 make_path(fn);
139 if (openreadclose(path.s,&file,256) != 1)
140 logmsg(WHO,111,FATAL,B(ERR_READ_INPUT,path.s));
141 execute_file(&file);
142 buffer_puts(buffer_2,"did 0+");
143 buffer_put(buffer_2,strnum,fmt_ulong(strnum,did_forward));
144 buffer_puts(buffer_2,"+");
145 buffer_put(buffer_2,strnum,fmt_ulong(strnum,did_program));
146 buffer_putsflush(buffer_2,"\n");
147 _exit(0);
148}
149
150/* Test if def has a certain prefix, and if so execute the associated file. */
151
152static void try_dispatch(const char *def,const char *prefix,unsigned int len,const char *fn)
153{
154 if (str_diffn(def,prefix,len) == 0 && is_file(fn))
155 execute(fn,def+len);
156}
157
158/* Hand off control to one of the command files in the list directory. */
159
160static void dispatch(const char *dir,const char *def)
161{
162 listdir = dir;
163 /* FIXME: set up $EXT $EXT2 $EXT3 $EXT4 ? Is it feasable? */
164 if (def == 0)
165 execute("editor",0);
166 else if (str_diff(def,"owner") == 0)
167 execute("owner",0);
168 else if (str_diff(def,"digest-owner") == 0)
169 execute("owner",0);
170 else {
171 try_dispatch(def,"digest-return-",14,"bouncer");
172 try_dispatch(def,"return-",7,"bouncer");
173 try_dispatch(def,"confirm-",8,"confirmer");
174 try_dispatch(def,"discard-",8,"confirmer");
175 try_dispatch(def,"accept-",7,"moderator");
176 try_dispatch(def,"reject-",7,"moderator");
177 /* If nothing else matches, call the manager. */
178 execute("manager",def);
179 }
180}
181
182int main(int argc,char **argv)
183{
184 char *def;
185 int opt;
186 int dash;
187
188 while ((opt = getoptb(argc,argv,"vV")) != opteof)
189 switch (opt) {
190 case 'v':
191 case 'V': logmsg(WHO,0,VERSION,auto_version);
192 default: die_usage();
193 }
194
195 if ((basedir = argv[optind++]) == 0)
196 die_usage();
197 if (!is_dir(0))
198 logmsg(WHO,100,FATAL,B("Not a directory: ",basedir));
199
200 sender = env_get("SENDER");
201 if (!sender)
202 logmsg(WHO,100,FATAL,ERR_NOSENDER);
203 def = env_get("DEFAULT");
204 if (!def || !*def)
205 logmsg(WHO,100,FATAL,ERR_NODEFAULT);
206
207 if ((listdir = argv[optind++]) != 0) {
208 if (!is_dir(0))
209 logmsg(WHO,100,FATAL,B("Not a directory: ",path.s));
210 dispatch(def,def);
211 }
212 else {
213 if (def[str_chr(def,'/')] != 0)
214 logmsg(WHO,100,FATAL,"Recipient address may not contain '/'");
215
216 if (is_dir(def))
217 dispatch(def,0);
218
219 dash = str_len(def);
220 for (;;) {
221 while (--dash > 0)
222 if (def[dash] == '-')
223 break;
224 if (dash <= 0)
225 break;
226 def[dash] = 0;
227 if (is_dir(def))
228 dispatch(def,def+dash+1);
229 def[dash] = '-';
230 }
231 logmsg(WHO,100,FATAL,B("Could not match recipient name to any list: ",def));
232 }
233
234 return 0;
235}
const char auto_version[]
void wrap_execsh(const char *command)
Definition wrap_execsh.c:9
int wrap_fork(void)
Definition wrap_fork.c:15
int wrap_waitpid(int pid)
int wrap_stat(const char *fn, struct stat *st)
Definition wrap_stat.c:17
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_READ_INPUT
Definition errtxt.h:26
#define ERR_READ
Definition errtxt.h:18
#define ERR_QMAIL_QUEUE
Definition errtxt.h:53
#define ERR_NODEFAULT
Definition errtxt.h:35
#define ERR_SEEK_INPUT
Definition errtxt.h:27
#define ERR_NOSENDER
Definition errtxt.h:37
#define ERR_TMP_QMAIL_QUEUE
Definition errtxt.h:54
const char * qmail_close(struct qmail *)
Definition qmail.c:120
void qmail_puts(struct qmail *, const char *)
Definition qmail.c:94
void qmail_put(struct qmail *, const char *, int)
Definition qmail.c:87
void qmail_from(struct qmail *, const char *)
Definition qmail.c:103
void qmail_to(struct qmail *, const char *)
Definition qmail.c:113
unsigned long qmail_qp(struct qmail *)
Definition qmail.c:77
int qmail_open(struct qmail *, const stralloc *)
Definition qmail.c:25
void die_nomem()
Definition getconf.c:17
#define WHO
Definition author.c:1
stralloc fn
char * dir
int main()
Definition ezmlm-weed.c:69
#define end
Definition makehash.c:43
int opt
Definition ezmlm-cron.c:53
unsigned int len
Definition ezmlm-cron.c:68
const char * code
Definition ezmlm-cron.c:75
char buf[256]
Definition install.c:113
int child
Definition ezmlm-cgi.c:143
stralloc dtline
Definition ezmlm-cgi.c:125
stralloc prefix
Definition ezmlm-idx.c:69
struct qmail qq
Definition ezmlm-clean.c:73
Definition qmail.h:10
const char * logmsg(const char *dir, unsigned long num, unsigned long listno, unsigned long subs, int done)
Definition loginfo.c:32