1 /*$Id: ezmlm-split.c,v 1.6 1999/05/12 22:17:54 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
19 #include "readwrite.h"
27 #define FATAL "ezmlm-split: fatal: "
28 #define INFO "ezmlm-split: info: "
30 int flagdo
= 1; /* default is manager function */
34 stralloc outhost
= {0};
35 stralloc inlocal
= {0};
36 stralloc outlocal
= {0};
37 stralloc target
= {0};
38 stralloc lctarget
= {0};
40 stralloc domain
= {0};
44 char strnum
[FMT_ULONG
];
49 strerr_die1x(100,"ezmlm-split: usage: ezmlm-split [-dD] dir [splitfile]"); }
51 void die_nomem() { strerr_die2x(111,FATAL
,ERR_NOMEM
); }
55 strerr_die2x(100,FATAL
,ERR_BAD_ADDRESS
);
60 strnum
[fmt_ulong(strnum
,lineno
)] = '\0';
61 strerr_die6x(111,FATAL
,split
," syntax error line ",strnum
,": ",line
.s
);
64 char spbuf
[1024]; /* should normally hold entire file */
68 int qqwrite(fd
,buf
,len
) int fd
; char *buf
; unsigned int len
;
70 qmail_put(&qq
,buf
,len
);
74 substdio ssqq
= SUBSTDIO_FDBUF(qqwrite
,-1,qqbuf
,(int) sizeof(qqbuf
));
77 substdio ssout
= SUBSTDIO_FDBUF(write
,1,outbuf
,(int) sizeof(outbuf
));
80 substdio ssin
= SUBSTDIO_FDBUF(read
,0,inbuf
,(int) sizeof(inbuf
));
83 /* returns 1 if a matching line was found, 0 otherwise. name will contain */
84 /* the correct list address in either case */
86 char *cpat
,*cp
,*cpname
,*cp1
,*cp2
,*cplast
;
89 unsigned char hash
,hash_hi
,hash_lo
;
90 unsigned int pos
,pos_name
,pos_hi
;
94 /* make case insensitive hash */
95 flagfound
= 0; /* default */
96 cpname
= ""; /* default */
97 if (!stralloc_copy(&lctarget
,&target
)) die_nomem();
98 case_lowerb(lctarget
.s
,lctarget
.len
-1);
101 while ((ch
= *cp
++)) {
102 h
= (h
+ (h
<< 5)) ^ (uint32
) ch
;
106 /* make domain pointer */
107 cpat
= lctarget
.s
+ str_chr(lctarget
.s
,'@');
109 strerr_die4x(100,FATAL
,ERR_ADDR_AT
,": ",target
.s
);
110 cplast
= cpat
+ str_len(cpat
) - 1;
111 if (*cplast
== '.') --cplast
; /* annonying special case */
112 cp1
= cpat
+ byte_rchr(cpat
,cplast
- cpat
, '.');
113 if (cp1
!= cplast
) { /* got one '.' */
114 if (!stralloc_copyb(&domain
,cp1
+ 1, cplast
- cp1
)) die_nomem();
115 cp2
= cpat
+ byte_rchr(cpat
, cp1
- cpat
,'.');
116 if (cp2
== cp1
) cp2
= cpat
;
118 if (!stralloc_append(&domain
,".")) die_nomem();
119 if (!stralloc_catb(&domain
,cp2
, cp1
- cp2
)) die_nomem();
121 if (!stralloc_copyb(&domain
,cpat
+ 1,cplast
- cpat
)) die_nomem();
122 if (!stralloc_0(&domain
)) die_nomem();
124 if ((fd
= open_read(split
)) == -1)
125 strerr_die4sys(111,FATAL
,ERR_OPEN
,split
,": ");
126 substdio_fdbuf(&sssp
,read
,fd
,spbuf
,(int) sizeof(spbuf
));
128 for (;;) { /* dom:hash_lo:hash_hi:listaddress */
129 if (getln(&sssp
,&line
,&match
,'\n') == -1)
130 strerr_die4sys(111,FATAL
,ERR_READ
,split
,": ");
134 if (line
.s
[0] == '#') continue; /* comment */
135 line
.s
[line
.len
- 1] = '\0'; /* no need to allow \0 in lines */
136 if (!line
.s
[pos
= str_chr(line
.s
,':')])
137 continue; /* usually blank line */
139 if (pos
== 0 || /* no domain */
140 (case_starts(domain
.s
,line
.s
))) { /* or matching domain */
141 if (!line
.s
[++pos
]) die_syntax();
142 pos_hi
= pos
+ str_chr(line
.s
+ pos
,':');
143 if (!line
.s
[pos_hi
]) die_syntax();
145 (void) scan_ulong(line
.s
+ pos
, &u
); /* scan_uint() not in ezmlm */
146 hash_lo
= (unsigned char) u
;
147 (void) scan_ulong(line
.s
+ pos_hi
, &u
);
148 hash_hi
= (unsigned char) u
;
149 pos_name
= pos_hi
+ str_chr(line
.s
+ pos_hi
,':');
150 if (pos_hi
== pos_name
) hash_hi
= 52L; /* default hi = 52 */
151 if (line
.s
[pos_name
]) pos_name
++;
152 if (hash
> hash_hi
|| hash
< hash_lo
) continue; /* not us */
153 cpname
= line
.s
+ pos_name
;
154 while (*cpname
&& /* isolate name */
155 (*cpname
== ' ' || *cpname
== '\t')) cpname
++;
157 while (pos
&& (line
.s
[pos
] == '\n' || line
.s
[pos
] == ' ' ||
158 line
.s
[pos
] == '\t')) line
.s
[pos
--] = '\0';
165 if (!stralloc_copys(&name
,cpname
)) die_nomem();
166 if (byte_chr(name
.s
,name
.len
,'@') == name
.len
) { /* local sublist */
167 if (!stralloc_append(&name
,"@")) die_nomem();
168 if (!stralloc_cat(&name
,&outhost
)) die_nomem();
170 if (!stralloc_0(&name
)) die_nomem();
172 } else { /* match without name or no match =>this list */
173 if (!stralloc_copy(&name
,&outlocal
)) die_nomem();
174 if (!stralloc_append(&name
,"@")) die_nomem();
175 if (!stralloc_cat(&name
,&outhost
)) die_nomem();
176 if (!stralloc_0(&name
)) die_nomem();
198 dir
= argv
[optind
++];
199 if (!dir
) die_usage();
201 if (dir
[1] == 'd') flagdo
= 1;
202 else if (dir
[1] == 'D') flagdo
= 0;
204 if (!(dir
= argv
[optind
++])) die_usage();
206 if (!(split
= argv
[optind
]))
209 if (chdir(dir
) == -1)
210 strerr_die4sys(111,FATAL
,ERR_SWITCH
,dir
,": ");
212 getconf_line(&outhost
,"outhost",1,FATAL
,dir
);
213 getconf_line(&outlocal
,"outlocal",1,FATAL
,dir
);
216 sender
= env_get("SENDER");
217 if (!sender
) strerr_die2x(100,FATAL
,ERR_NOSENDER
);
219 strerr_die2x(100,FATAL
,ERR_BOUNCE
);
220 if (!sender
[str_chr(sender
,'@')])
221 strerr_die2x(100,FATAL
,ERR_ANONYMOUS
);
222 if (str_equal(sender
,"#@[]"))
223 strerr_die2x(100,FATAL
,ERR_BOUNCE
);
225 def
= env_get("DEFAULT");
229 local
= env_get("LOCAL");
230 if (!local
) strerr_die2x(100,FATAL
,ERR_NOLOCAL
);
231 getconf_line(&inlocal
,"inlocal",1,FATAL
,dir
);
232 if (inlocal
.len
> str_len(local
)) die_badaddr();
233 if (case_diffb(inlocal
.s
,inlocal
.len
,local
)) die_badaddr();
234 action
= local
+ inlocal
.len
+ 1;
236 if (!stralloc_copys(&target
,sender
)) die_nomem();
238 i
= str_chr(action
,'-');
241 if (!stralloc_copys(&target
,action
+ i
+ 1)) die_nomem();
242 i
= byte_rchr(target
.s
,target
.len
,'=');
247 if (!stralloc_0(&target
)) die_nomem();
249 if (case_diffs(action
,ACTION_SUBSCRIBE
) &&
250 case_diffs(action
,ALT_SUBSCRIBE
) &&
251 case_diffs(action
,ACTION_UNSUBSCRIBE
) &&
252 case_diffs(action
,ALT_UNSUBSCRIBE
))
253 _exit(0); /* not for us */
257 if (!stralloc_copy(&from
,&outlocal
)) die_nomem();
258 if (!stralloc_cats(&from
,"-return-@")) die_nomem();
259 if (!stralloc_cat(&from
,&outhost
)) die_nomem();
260 if (!stralloc_0(&from
)) die_nomem();
261 if (name
.s
[i
= str_rchr(name
.s
,'@')]) { /* name must have '@'*/
265 if (!stralloc_copys(&to
,name
.s
)) die_nomem(); /* local */
266 if (!stralloc_append(&to
,"-")) die_nomem(); /* - */
267 if (!stralloc_cats(&to
,action
)) die_nomem(); /* subscribe */
268 if (!stralloc_append(&to
,"-")) die_nomem(); /* - */
269 if (target
.s
[i
= str_rchr(target
.s
,'@')])
271 if (!stralloc_cats(&to
,target
.s
)) die_nomem(); /* target */
272 if (!stralloc_append(&to
,"@")) die_nomem(); /* - */
273 if (!stralloc_cats(&to
,nhost
)) die_nomem(); /* host */
274 if (!stralloc_0(&to
)) die_nomem();
275 dtline
= env_get("DTLINE");
276 if (!dtline
) strerr_die2x(100,FATAL
,ERR_NODTLINE
);
278 if (qmail_open(&qq
,(stralloc
*) 0) == -1)
279 strerr_die2sys(111,FATAL
,ERR_QMAIL_QUEUE
);
280 qmail_puts(&qq
,dtline
); /* delivered-to */
281 if (substdio_copy(&ssqq
,&ssin
) != 0)
282 strerr_die2sys(111,FATAL
,ERR_READ_INPUT
);
283 qmail_from(&qq
,from
.s
);
286 if (*(err
= qmail_close(&qq
)) != '\0')
287 strerr_die3x(111,FATAL
,ERR_TMP_QMAIL_QUEUE
,err
+ 1);
289 strnum
[fmt_ulong(strnum
,qmail_qp(&qq
))] = 0;
290 strerr_die3x(99,INFO
,"qp ",strnum
);
296 if (getln(&ssin
,&line
,&match
,'\n') == -1)
297 strerr_die2sys(111,FATAL
,ERR_READ_INPUT
);
299 if (line
.len
== 1) continue; /* ignore blank lines */
300 if (line
.s
[0] == '#') continue; /* ignore comments */
301 if (!stralloc_copy(&target
,&line
)) die_nomem();
302 target
.s
[target
.len
- 1] = '\0';
304 if (!stralloc_cats(&name
,": ")) die_nomem();
305 if (!stralloc_cats(&name
,target
.s
)) die_nomem();
306 if (!stralloc_append(&name
,"\n")) die_nomem();
307 if (substdio_put(&ssout
,name
.s
,name
.len
) == -1)
308 strerr_die2sys(111,ERR_WRITE
,"output: ");
310 if (substdio_flush(&ssout
) == -1)
311 strerr_die2sys(111,ERR_FLUSH
,"output: ");