ezmlmx 0.69
ezmlmx
Loading...
Searching...
No Matches
ezmlm-split.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include "error.h"
5#include "stralloc.h"
6#include "str.h"
7#include "env.h"
8#include "sig.h"
9#include "getconf.h"
10#include "open.h"
11#include "scan.h"
12#include "byte.h"
13#include "getln.h"
14#include "case.h"
15#include "qmail.h"
16#include "buffer.h"
17#include "readwrite.h"
18#include "quote.h"
19#include "now.h"
20#include "uint_t.h"
21#include "fmt.h"
22#include "errtxt.h"
23#include "idx.h"
24#include "logmsg.h"
25#include "ezmlm.h"
26
27#define WHO "ezmlm-split"
28
34
35
36int flagdo = 1; /* default is manager function */
37
38const char *sender;
39const char *split;
40
41stralloc outhost = {0};
42stralloc outlocal = {0};
43
44stralloc target = {0};
45stralloc lctarget = {0};
46stralloc line = {0};
47stralloc domain = {0};
48stralloc name = {0};
49stralloc from = {0};
50stralloc to = {0};
51char strnum[FMT_ULONG];
52unsigned long lineno;
54
55static void die_usage() { logmsg(WHO,100,USAGE,"ezmlm-split [-dD] dir [splitfile]"); }
56static void die_nomem() { logmsg(WHO,111,FATAL,ERR_NOMEM); }
57
58static void die_syntax()
59{
60 strnum[fmt_ulong(strnum,lineno)] = '\0';
61 logmsg(WHO,111,FATAL,B("syntax error line :",line.s,"[",strnum,"]"));
62}
63
64char inbuf[BUFFER_INSIZE] ;/* should normally hold entire file */
65buffer bi;
66
67struct qmail qq;
68
69ssize_t bqrite(int fd,char *buf,size_t len)
70{
72 return (int) len;
73}
74
75char qqbuf[1];
76buffer bq = BUFFER_INIT(bqrite,-1,qqbuf,(int) sizeof(qqbuf));
77
83
85{
86 char *cpat, *cp, *cp1, *cp2, *cplast;
87 const char *cpname;
88 unsigned long u;
89 uint32 h;
90 unsigned char hash, hash_hi, hash_lo;
91 unsigned int pos, pos_name, pos_hi;
92 char ch;
93 int fd,match;
94
95 /* make case insensitive hash */
96 flagfound = 0; /* default */
97 cpname = ""; /* default */
98
99 if (!stralloc_copy(&lctarget,&target)) die_nomem(); // FIXME
100 case_lowerb(lctarget.s,lctarget.len - 1);
101 h = 5381;
102 cp = lctarget.s;
103 while ((ch = *cp++)) {
104 h = (h + (h << 5)) ^ (uint32) ch;
105 }
106 hash = (h % 53);
107
108 /* make domain pointer */
109 cpat = lctarget.s + str_chr(lctarget.s,'@');
110 if (!*cpat)
111 logmsg(WHO,100,FATAL,B(ERR_ADDR_AT,target.s));
112
113 cplast = cpat + str_len(cpat) - 1;
114 if (*cplast == '.') --cplast; /* annonying special case */
115 cp1 = cpat + byte_rchr(cpat,cplast - cpat, '.');
116 if (cp1 != cplast) { /* got one '.' */
117 if (!stralloc_copyb(&domain,cp1 + 1, cplast - cp1)) die_nomem();
118 cp2 = cpat + byte_rchr(cpat, cp1 - cpat,'.');
119 if (cp2 == cp1) cp2 = cpat;
120 ++cp2;
121 if (!stralloc_append(&domain,".")) die_nomem();
122 if (!stralloc_catb(&domain,cp2, cp1 - cp2)) die_nomem();
123 } else /* no '.' */
124 if (!stralloc_copyb(&domain,cpat + 1,cplast - cpat)) die_nomem();
125 if (!stralloc_0(&domain)) die_nomem();
126
127 if ((fd = open_read(split)) == -1)
128 logmsg(WHO,111,FATAL,B(ERR_OPEN,split));
129
130 buffer_init(&bi,buffer_unixread,fd,inbuf,(int) sizeof(inbuf));
131
132 lineno = 0;
133 for (;;) { /* dom:hash_lo:hash_hi:listaddress */
134 if (getln(&bi,&line,&match,'\n') == -1)
135 logmsg(WHO,111,FATAL,B(ERR_READ,split));
136 lineno++;
137 if (!match)
138 break;
139 if (line.s[0] == '#') continue; /* comment */
140 line.s[line.len - 1] = '\0'; /* no need to allow \0 in lines */
141 if (!line.s[pos = str_chr(line.s,':')])
142 continue; /* usually blank line */
143 line.s[pos] = '\0';
144 if (pos == 0 || (case_starts(domain.s,line.s))) { /* no domain or no matching domain */
145 if (!line.s[++pos]) die_syntax();
146 pos_hi = pos + str_chr(line.s + pos,':');
147 if (!line.s[pos_hi]) die_syntax();
148 pos_hi++;
149 scan_ulong(line.s + pos, &u); /* scan_uint() not in ezmlm */
150 hash_lo = (unsigned char) u;
151 scan_ulong(line.s + pos_hi, &u);
152 hash_hi = (unsigned char) u;
153 pos_name = pos_hi + str_chr(line.s + pos_hi,':');
154 if (pos_hi == pos_name) hash_hi = 52L; /* default hi = 52 */
155 if (line.s[pos_name]) pos_name++;
156 if (hash > hash_hi || hash < hash_lo)
157 continue; /* not us */
158
159 cpname = line.s + pos_name;
160 while (*cpname && (*cpname == ' ' || *cpname == '\t'))
161 cpname++; // isolated name
162
163 pos = line.len - 2;
164 while (pos && (line.s[pos] == '\n' || line.s[pos] == ' ' || line.s[pos] == '\t'))
165 line.s[pos--] = '\0';
166 break;
167 }
168 }
169 close(fd);
170
171 if (*cpname) {
172 if (!stralloc_copys(&name,cpname)) die_nomem();
173 if (byte_chr(name.s,name.len,'@') == name.len) { /* local sublist */
174 if (!stralloc_append(&name,"@")) die_nomem();
175 if (!stralloc_cat(&name,&outhost)) die_nomem();
176 }
177 if (!stralloc_0(&name)) die_nomem();
178 return 1;
179 } else { /* match without name or no match =>this list */
180 if (!stralloc_copy(&name,&outlocal)) die_nomem();
181 if (!stralloc_append(&name,"@")) die_nomem();
182 if (!stralloc_cat(&name,&outhost)) die_nomem();
183 if (!stralloc_0(&name)) die_nomem();
184 return 0;
185 }
186}
187
188int main(int argc,char **argv)
189{
190 char *dir;
191 char *action;
192 char *dtline;
193 char *nhost;
194 const char *err;
195 unsigned int i;
196 int match;
197 int optind = 1;
198
199 sig_pipeignore();
200
201 dir = argv[optind++];
202 if (!dir) die_usage();
203 if (dir[0] == '-') {
204 if (dir[1] == 'd') flagdo = 1;
205 else if (dir[1] == 'D') flagdo = 0;
206 else die_usage();
207 if (!(dir = argv[optind++])) die_usage();
208 }
209 if (!(split = argv[optind]))
210 split = "split";
211
212 if (chdir(dir) == -1)
213 logmsg(WHO,111,FATAL,B(ERR_SWITCH,dir));
214
215 getconf_line(&outhost,"outhost",1,dir);
216 getconf_line(&outlocal,"outlocal",1,dir);
217
218 if (flagdo) {
219 sender = env_get("SENDER");
220 if (!sender) logmsg(WHO,100,FATAL,ERR_NOSENDER);
221 if (!*sender)
222 logmsg(WHO,100,FATAL,ERR_BOUNCE);
223 if (!sender[str_chr(sender,'@')])
224 logmsg(WHO,100,FATAL,ERR_ANONYMOUS);
225 if (str_equal(sender,"#@[]"))
226 logmsg(WHO,100,FATAL,ERR_BOUNCE);
227
228 action = env_get("DEFAULT");
229 if (!action) logmsg(WHO,100,FATAL,ERR_NODEFAULT);
230 if (!stralloc_copys(&target,sender)) die_nomem();
231 if (action[0]) {
232 i = str_chr(action,'-');
233 if (action[i]) {
234 action[i] = '\0';
235 if (!stralloc_copys(&target,action + i + 1)) die_nomem();
236 i = byte_rchr(target.s,target.len,'=');
237 if (i < target.len)
238 target.s[i] = '@';
239 }
240 }
241 if (!stralloc_0(&target)) die_nomem();
242
243 if (case_diffs(action,ACTION_SUBSCRIBE) &&
244 case_diffs(action,ALT_SUBSCRIBE) &&
245 case_diffs(action,ACTION_UNSUBSCRIBE) &&
246 case_diffs(action,ALT_UNSUBSCRIBE))
247 _exit(0); /* not for us */
248
249 if (findname()) { /* new sender */
250 if (!stralloc_copy(&from,&outlocal)) die_nomem();
251 if (!stralloc_cats(&from,"-return-@")) die_nomem();
252 if (!stralloc_cat(&from,&outhost)) die_nomem();
253 if (!stralloc_0(&from)) die_nomem();
254 if (name.s[i = str_rchr(name.s,'@')]) { /* name must have '@'*/
255 nhost = name.s + i;
256 *(nhost++) = '\0';
257 }
258 if (!stralloc_copys(&to,name.s)) die_nomem(); /* local */
259 if (!stralloc_append(&to,"-")) die_nomem(); /* - */
260 if (!stralloc_cats(&to,action)) die_nomem(); /* subscribe */
261 if (!stralloc_append(&to,"-")) die_nomem(); /* - */
262 if (target.s[i = str_rchr(target.s,'@')])
263 target.s[i] = '=';
264 if (!stralloc_cats(&to,target.s)) die_nomem(); /* target */
265 if (!stralloc_append(&to,"@")) die_nomem(); /* - */
266 if (!stralloc_cats(&to,nhost)) die_nomem(); /* host */
267 if (!stralloc_0(&to)) die_nomem();
268 dtline = env_get("DTLINE");
269 if (!dtline) logmsg(WHO,100,FATAL,ERR_NODTLINE);
270
271 if (qmail_open(&qq,(stralloc *) 0) == -1)
272 logmsg(WHO,111,FATAL,ERR_QMAIL_QUEUE);
273 qmail_puts(&qq,dtline); /* delivered-to */
274 if (buffer_copy(&bq,buffer_0) != 0)
275 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
276 qmail_from(&qq,from.s);
277 qmail_to(&qq,to.s);
278
279 if (*(err = qmail_close(&qq)) != '\0')
280 logmsg(WHO,111,FATAL,B(ERR_TMP_QMAIL_QUEUE,err + 1));
281
282 strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
283 logmsg(WHO,99,ERROR,B("qp ",strnum));
284 }
285 _exit(0);
286
287 } else {
288
289 for (;;) {
290 if (getln(buffer_0,&line,&match,'\n') == -1) // stdin
291 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
292 if (!match) break;
293 if (line.len == 1) continue; /* ignore blank lines */
294 if (line.s[0] == '#') continue; /* ignore comments */
295 if (!stralloc_copy(&target,&line)) die_nomem();
296 target.s[target.len - 1] = '\0';
297 findname();
298 if (!stralloc_cats(&name,": ")) die_nomem();
299 if (!stralloc_cats(&name,target.s)) die_nomem();
300 if (!stralloc_append(&name,"\n")) die_nomem();
301 if (buffer_put(buffer_1,name.s,name.len) == -1)
302 logmsg(WHO,111,FATAL,B(ERR_WRITE,"output"));
303 }
304 if (buffer_flush(buffer_1) == -1)
305 logmsg(WHO,111,FATAL,B(ERR_FLUSH,"output "));
306 _exit(0);
307 }
308
309 return 0;
310}
void die_syntax()
Definition ezmlm-cron.c:80
const char * cp
Definition ezmlm-cron.c:78
unsigned int len
Definition ezmlm-cron.c:70
#define WHO
Definition author.c:1
int flagdo
Definition ezmlm-get.c:52
void die_nomem()
Definition getconf.c:17
int getconf_line(stralloc *sa, const char *fn, int flagrequired, const char *dir)
Definition getconf.c:53
int main()
Definition ezmlm-weed.c:69
int findname()
Definition ezmlm-split.c:84
const char * split
Definition ezmlm-split.c:39
int flagfound
Definition ezmlm-split.c:53
stralloc lctarget
Definition ezmlm-split.c:45
ssize_t bqrite(int fd, char *buf, size_t len)
Definition ezmlm-split.c:69
unsigned long lineno
Definition ezmlm-split.c:52
stralloc name
Definition ezmlm-split.c:48
stralloc domain
Definition ezmlm-split.c:47
char inbuf[1024]
char * dir
buffer bi
buffer bq
Definition ezmlm-clean.c:81
stralloc to
Definition ezmlm-clean.c:97
struct qmail qq
Definition ezmlm-clean.c:73
stralloc from
char buf[256]
Definition install.c:113
int fd
Definition ezmlm-cgi.c:141
stralloc dtline
Definition ezmlm-cgi.c:125
int match
Definition ezmlm-cgi.c:140
stralloc action
Definition ezmlm-store.c:84
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
charset, outhost, outlocal and flagcd are shared
#define ALT_SUBSCRIBE
Definition idx.h:54
#define ACTION_SUBSCRIBE
Definition idx.h:208
#define ALT_UNSUBSCRIBE
Definition idx.h:56
#define ACTION_UNSUBSCRIBE
Definition idx.h:209
Error messages. If you translate these, I would urge you to keep the English version as well....
#define ERR_FLUSH
Definition errtxt.h:20
#define ERR_NOMEM
Definition errtxt.h:14
#define ERR_OPEN
Definition errtxt.h:30
#define ERR_ADDR_AT
Definition errtxt.h:148
#define ERR_ANONYMOUS
Definition errtxt.h:44
#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_SWITCH
Definition errtxt.h:42
#define ERR_WRITE
Definition errtxt.h:17
#define ERR_NOSENDER
Definition errtxt.h:37
#define ERR_TMP_QMAIL_QUEUE
Definition errtxt.h:54
#define ERR_BOUNCE
Definition errtxt.h:38
#define ERR_NODTLINE
Definition errtxt.h:36
unsigned long hash_lo
Definition ezmlm-send.c:87
unsigned long hash_hi
Definition ezmlm-send.c:88
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