ezmlmx 0.68
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;
68ssize_t bqrite(int fd,char *buf,unsigned int len)
69{
71 return (int) len;
72}
73char qqbuf[1];
74buffer bq = BUFFER_INIT(bqrite,-1,qqbuf,(int) sizeof(qqbuf));
75
81
83{
84 char *cpat, *cp, *cp1, *cp2, *cplast;
85 const char *cpname;
86 unsigned long u;
87 uint32 h;
88 unsigned char hash, hash_hi, hash_lo;
89 unsigned int pos, pos_name, pos_hi;
90 char ch;
91 int fd,match;
92
93 /* make case insensitive hash */
94 flagfound = 0; /* default */
95 cpname = ""; /* default */
96
97 if (!stralloc_copy(&lctarget,&target)) die_nomem(); // FIXME
98 case_lowerb(lctarget.s,lctarget.len - 1);
99 h = 5381;
100 cp = lctarget.s;
101 while ((ch = *cp++)) {
102 h = (h + (h << 5)) ^ (uint32) ch;
103 }
104 hash = (h % 53);
105
106 /* make domain pointer */
107 cpat = lctarget.s + str_chr(lctarget.s,'@');
108 if (!*cpat)
109 logmsg(WHO,100,FATAL,B(ERR_ADDR_AT,target.s));
110
111 cplast = cpat + str_len(cpat) - 1;
112 if (*cplast == '.') --cplast; /* annonying special case */
113 cp1 = cpat + byte_rchr(cpat,cplast - cpat, '.');
114 if (cp1 != cplast) { /* got one '.' */
115 if (!stralloc_copyb(&domain,cp1 + 1, cplast - cp1)) die_nomem();
116 cp2 = cpat + byte_rchr(cpat, cp1 - cpat,'.');
117 if (cp2 == cp1) cp2 = cpat;
118 ++cp2;
119 if (!stralloc_append(&domain,".")) die_nomem();
120 if (!stralloc_catb(&domain,cp2, cp1 - cp2)) die_nomem();
121 } else /* no '.' */
122 if (!stralloc_copyb(&domain,cpat + 1,cplast - cpat)) die_nomem();
123 if (!stralloc_0(&domain)) die_nomem();
124
125 if ((fd = open_read(split)) == -1)
126 logmsg(WHO,111,FATAL,B(ERR_OPEN,split));
127
128 buffer_init(&bi,buffer_unixread,fd,inbuf,(int) sizeof(inbuf));
129
130 lineno = 0;
131 for (;;) { /* dom:hash_lo:hash_hi:listaddress */
132 if (getln(&bi,&line,&match,'\n') == -1)
133 logmsg(WHO,111,FATAL,B(ERR_READ,split));
134 lineno++;
135 if (!match)
136 break;
137 if (line.s[0] == '#') continue; /* comment */
138 line.s[line.len - 1] = '\0'; /* no need to allow \0 in lines */
139 if (!line.s[pos = str_chr(line.s,':')])
140 continue; /* usually blank line */
141 line.s[pos] = '\0';
142 if (pos == 0 || (case_starts(domain.s,line.s))) { /* no domain or no matching domain */
143 if (!line.s[++pos]) die_syntax();
144 pos_hi = pos + str_chr(line.s + pos,':');
145 if (!line.s[pos_hi]) die_syntax();
146 pos_hi++;
147 scan_ulong(line.s + pos, &u); /* scan_uint() not in ezmlm */
148 hash_lo = (unsigned char) u;
149 scan_ulong(line.s + pos_hi, &u);
150 hash_hi = (unsigned char) u;
151 pos_name = pos_hi + str_chr(line.s + pos_hi,':');
152 if (pos_hi == pos_name) hash_hi = 52L; /* default hi = 52 */
153 if (line.s[pos_name]) pos_name++;
154 if (hash > hash_hi || hash < hash_lo)
155 continue; /* not us */
156
157 cpname = line.s + pos_name;
158 while (*cpname && (*cpname == ' ' || *cpname == '\t'))
159 cpname++; // isolated name
160
161 pos = line.len - 2;
162 while (pos && (line.s[pos] == '\n' || line.s[pos] == ' ' || line.s[pos] == '\t'))
163 line.s[pos--] = '\0';
164 break;
165 }
166 }
167 close(fd);
168
169 if (*cpname) {
170 if (!stralloc_copys(&name,cpname)) die_nomem();
171 if (byte_chr(name.s,name.len,'@') == name.len) { /* local sublist */
172 if (!stralloc_append(&name,"@")) die_nomem();
173 if (!stralloc_cat(&name,&outhost)) die_nomem();
174 }
175 if (!stralloc_0(&name)) die_nomem();
176 return 1;
177 } else { /* match without name or no match =>this list */
178 if (!stralloc_copy(&name,&outlocal)) die_nomem();
179 if (!stralloc_append(&name,"@")) die_nomem();
180 if (!stralloc_cat(&name,&outhost)) die_nomem();
181 if (!stralloc_0(&name)) die_nomem();
182 return 0;
183 }
184}
185
186int main(int argc,char **argv)
187{
188 char *dir;
189 char *action;
190 char *dtline;
191 char *nhost;
192 const char *err;
193 unsigned int i;
194 int match;
195 int optind = 1;
196
197 sig_pipeignore();
198
199 dir = argv[optind++];
200 if (!dir) die_usage();
201 if (dir[0] == '-') {
202 if (dir[1] == 'd') flagdo = 1;
203 else if (dir[1] == 'D') flagdo = 0;
204 else die_usage();
205 if (!(dir = argv[optind++])) die_usage();
206 }
207 if (!(split = argv[optind]))
208 split = "split";
209
210 if (chdir(dir) == -1)
211 logmsg(WHO,111,FATAL,B(ERR_SWITCH,dir));
212
213 getconf_line(&outhost,"outhost",1,dir);
214 getconf_line(&outlocal,"outlocal",1,dir);
215
216 if (flagdo) {
217 sender = env_get("SENDER");
218 if (!sender) logmsg(WHO,100,FATAL,ERR_NOSENDER);
219 if (!*sender)
220 logmsg(WHO,100,FATAL,ERR_BOUNCE);
221 if (!sender[str_chr(sender,'@')])
222 logmsg(WHO,100,FATAL,ERR_ANONYMOUS);
223 if (str_equal(sender,"#@[]"))
224 logmsg(WHO,100,FATAL,ERR_BOUNCE);
225
226 action = env_get("DEFAULT");
227 if (!action) logmsg(WHO,100,FATAL,ERR_NODEFAULT);
228 if (!stralloc_copys(&target,sender)) die_nomem();
229 if (action[0]) {
230 i = str_chr(action,'-');
231 if (action[i]) {
232 action[i] = '\0';
233 if (!stralloc_copys(&target,action + i + 1)) die_nomem();
234 i = byte_rchr(target.s,target.len,'=');
235 if (i < target.len)
236 target.s[i] = '@';
237 }
238 }
239 if (!stralloc_0(&target)) die_nomem();
240
241 if (case_diffs(action,ACTION_SUBSCRIBE) &&
242 case_diffs(action,ALT_SUBSCRIBE) &&
243 case_diffs(action,ACTION_UNSUBSCRIBE) &&
244 case_diffs(action,ALT_UNSUBSCRIBE))
245 _exit(0); /* not for us */
246
247 if (findname()) { /* new sender */
248 if (!stralloc_copy(&from,&outlocal)) die_nomem();
249 if (!stralloc_cats(&from,"-return-@")) die_nomem();
250 if (!stralloc_cat(&from,&outhost)) die_nomem();
251 if (!stralloc_0(&from)) die_nomem();
252 if (name.s[i = str_rchr(name.s,'@')]) { /* name must have '@'*/
253 nhost = name.s + i;
254 *(nhost++) = '\0';
255 }
256 if (!stralloc_copys(&to,name.s)) die_nomem(); /* local */
257 if (!stralloc_append(&to,"-")) die_nomem(); /* - */
258 if (!stralloc_cats(&to,action)) die_nomem(); /* subscribe */
259 if (!stralloc_append(&to,"-")) die_nomem(); /* - */
260 if (target.s[i = str_rchr(target.s,'@')])
261 target.s[i] = '=';
262 if (!stralloc_cats(&to,target.s)) die_nomem(); /* target */
263 if (!stralloc_append(&to,"@")) die_nomem(); /* - */
264 if (!stralloc_cats(&to,nhost)) die_nomem(); /* host */
265 if (!stralloc_0(&to)) die_nomem();
266 dtline = env_get("DTLINE");
267 if (!dtline) logmsg(WHO,100,FATAL,ERR_NODTLINE);
268
269 if (qmail_open(&qq,(stralloc *) 0) == -1)
270 logmsg(WHO,111,FATAL,ERR_QMAIL_QUEUE);
271 qmail_puts(&qq,dtline); /* delivered-to */
272 if (buffer_copy(&bq,buffer_0) != 0)
273 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
274 qmail_from(&qq,from.s);
275 qmail_to(&qq,to.s);
276
277 if (*(err = qmail_close(&qq)) != '\0')
278 logmsg(WHO,111,FATAL,B(ERR_TMP_QMAIL_QUEUE,err + 1));
279
280 strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
281 logmsg(WHO,99,ERROR,B("qp ",strnum));
282 }
283 _exit(0);
284
285 } else {
286
287 for (;;) {
288 if (getln(buffer_0,&line,&match,'\n') == -1) // stdin
289 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
290 if (!match) break;
291 if (line.len == 1) continue; /* ignore blank lines */
292 if (line.s[0] == '#') continue; /* ignore comments */
293 if (!stralloc_copy(&target,&line)) die_nomem();
294 target.s[target.len - 1] = '\0';
295 findname();
296 if (!stralloc_cats(&name,": ")) die_nomem();
297 if (!stralloc_cats(&name,target.s)) die_nomem();
298 if (!stralloc_append(&name,"\n")) die_nomem();
299 if (buffer_put(buffer_1,name.s,name.len) == -1)
300 logmsg(WHO,111,FATAL,B(ERR_WRITE,"output"));
301 }
302 if (buffer_flush(buffer_1) == -1)
303 logmsg(WHO,111,FATAL,B(ERR_FLUSH,"output "));
304 _exit(0);
305 }
306
307 return 0;
308}
#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
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
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
int flagdo
Definition ezmlm-get.c:50
char inbuf[1024]
char * dir
buffer bi
stralloc from
int main()
Definition ezmlm-weed.c:69
int findname()
Definition ezmlm-split.c:82
ssize_t bqrite(int fd, char *buf, unsigned int len)
Definition ezmlm-split.c:68
const char * split
Definition ezmlm-split.c:39
int flagfound
Definition ezmlm-split.c:53
stralloc lctarget
Definition ezmlm-split.c:45
unsigned long lineno
Definition ezmlm-split.c:52
stralloc name
Definition ezmlm-split.c:48
stralloc domain
Definition ezmlm-split.c:47
void die_syntax()
Definition ezmlm-cron.c:78
const char * cp
Definition ezmlm-cron.c:76
unsigned int len
Definition ezmlm-cron.c:68
char buf[256]
Definition install.c:113
unsigned long hash_lo
Definition ezmlm-send.c:87
unsigned long hash_hi
Definition ezmlm-send.c:88
int fd
Definition ezmlm-cgi.c:141
stralloc dtline
Definition ezmlm-cgi.c:125
int match
Definition ezmlm-cgi.c:140
buffer bq
Definition ezmlm-clean.c:81
stralloc to
Definition ezmlm-clean.c:97
struct qmail qq
Definition ezmlm-clean.c:73
stralloc action
Definition ezmlm-store.c:84
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