1 /*$Id: subscribe.c,v 1.5 1999/10/12 23:38:36 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
13 #include "subscribe.h"
20 static void die_nomem(fatal
)
23 strerr_die2x(111,fatal
,ERR_NOMEM
);
26 static stralloc addr
= {0};
27 static stralloc lcaddr
= {0};
28 static stralloc line
= {0};
29 static stralloc domain
= {0};
30 static stralloc logline
= {0};
31 static stralloc quoted
= {0};
32 static stralloc fnnew
= {0};
33 static stralloc fn
= {0};
34 static stralloc fnlock
= {0};
35 static char szh
[FMT_ULONG
];
40 strerr_die4sys(111,fatal
,ERR_READ
,fn
.s
,": ");
46 strerr_die4sys(111,fatal
,ERR_WRITE
,fnnew
.s
,": ");
51 static char ssbuf
[256];
53 static substdio ssnew
;
54 static char ssnewbuf
[256];
56 int subscribe(dbname
,userhost
,flagadd
,comment
,event
,flagmysql
,
58 /* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database */
59 /* dbname. Comment is e.g. the subscriber from line or name. It is added to */
60 /* the log. Event is the action type, e.g. "probe", "manual", etc. The */
61 /* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0 */
62 /* on failure. If flagmysql is set and the file "sql" is found in the */
63 /* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */
64 /* >=0 it is used in place of the calculated hash. This makes it possible to */
65 /* add addresses with a hash that does not exist. forcehash has to be 0..99. */
66 /* for unsubscribes, the address is only removed if forcehash matches the */
67 /* actual hash. This way, ezmlm-manage can be prevented from touching certain*/
68 /* addresses that can only be removed by ezmlm-unsub. Usually, this would be */
69 /* used for sublist addresses (to avoid removal) and sublist aliases (to */
70 /* prevent users from subscribing them (although the cookie mechanism would */
71 /* prevent the resulting duplicate message from being distributed. */
85 char szhash
[3] = "00";
89 unsigned char ch
,lcch
;
93 if (userhost
[str_chr(userhost
,'\n')])
94 strerr_die2x(100,fatal
,ERR_ADDR_NL
);
96 if (!stralloc_copys(&addr
,"T")) die_nomem(fatal
);
97 if (!stralloc_cats(&addr
,userhost
)) die_nomem(fatal
);
99 strerr_die2x(100,fatal
,ERR_ADDR_LONG
);
101 j
= byte_rchr(addr
.s
,addr
.len
,'@');
103 strerr_die2x(100,fatal
,ERR_ADDR_AT
);
104 case_lowerb(addr
.s
+ j
+ 1,addr
.len
- j
- 1);
105 if (!stralloc_copy(&lcaddr
,&addr
)) die_nomem(fatal
);
106 case_lowerb(lcaddr
.s
+ 1,j
- 1); /* make all-lc version of address */
108 if (forcehash
>= 0 && forcehash
<= 52) {
109 ch
= lcch
= (unsigned char) forcehash
;
113 for (j
= 0;j
< addr
.len
;++j
) {
114 h
= (h
+ (h
<< 5)) ^ (uint32
) (unsigned char) addr
.s
[j
];
115 lch
= (lch
+ (lch
<< 5)) ^ (uint32
) (unsigned char) lcaddr
.s
[j
];
117 lcch
= 64 + (lch
% 53);
121 if (!stralloc_0(&addr
)) die_nomem(fatal
);
122 if (!stralloc_0(&lcaddr
)) die_nomem(fatal
);
123 if (!stralloc_copys(&fn
,dbname
)) die_nomem(fatal
);
124 if (!stralloc_copys(&fnlock
,dbname
)) die_nomem(fatal
);
126 if (!stralloc_cats(&fn
,"/subscribers/")) die_nomem(fatal
);
127 if (!stralloc_catb(&fn
,&lcch
,1)) die_nomem(fatal
);
128 if (!stralloc_copy(&fnnew
,&fn
)) die_nomem(fatal
);
129 /* code later depends on fnnew = fn + 'n' */
130 if (!stralloc_cats(&fnnew
,"n")) die_nomem(fatal
);
131 if (!stralloc_cats(&fnlock
,"/lock")) die_nomem(fatal
);
132 if (!stralloc_0(&fnnew
)) die_nomem(fatal
);
133 if (!stralloc_0(&fn
)) die_nomem(fatal
);
134 if (!stralloc_0(&fnlock
)) die_nomem(fatal
);
136 fdlock
= open_append(fnlock
.s
);
138 strerr_die4sys(111,fatal
,ERR_OPEN
,fnlock
.s
,": ");
139 if (lock_ex(fdlock
) == -1)
140 strerr_die4sys(111,fatal
,ERR_OBTAIN
,fnlock
.s
,": ");
142 /* do lower case hashed version first */
143 fdnew
= open_trunc(fnnew
.s
);
144 if (fdnew
== -1) die_write(fatal
);
145 substdio_fdbuf(&ssnew
,write
,fdnew
,ssnewbuf
,sizeof(ssnewbuf
));
149 fd
= open_read(fn
.s
);
151 if (errno
!= error_noent
) { close(fdnew
); die_read(fatal
); }
154 substdio_fdbuf(&ss
,read
,fd
,ssbuf
,sizeof(ssbuf
));
157 if (getln(&ss
,&line
,&match
,'\0') == -1) {
158 close(fd
); close(fdnew
); die_read(fatal
);
161 if (line
.len
== addr
.len
)
162 if (!case_diffb(line
.s
,line
.len
,addr
.s
)) {
167 if (substdio_bput(&ssnew
,line
.s
,line
.len
) == -1) {
168 close(fd
); close(fdnew
); die_write(fatal
);
175 if (flagadd
&& !flagwasthere
)
176 if (substdio_bput(&ssnew
,addr
.s
,addr
.len
) == -1) {
177 close(fdnew
); die_write(fatal
);
180 if (substdio_flush(&ssnew
) == -1) { close(fdnew
); die_write(fatal
); }
181 if (fsync(fdnew
) == -1) { close(fdnew
); die_write(fatal
); }
184 if (rename(fnnew
.s
,fn
.s
) == -1)
185 strerr_die6sys(111,fatal
,ERR_MOVE
,fnnew
.s
," to ",fn
.s
,": ");
187 if ((ch
== lcch
) || flagwasthere
) {
189 if (flagadd
^ flagwasthere
) {
190 if (!stralloc_0(&addr
)) die_nomem(fatal
);
191 log(dbname
,event
,addr
.s
+1,comment
);
197 /* If unsub and not found and hashed differ, OR */
198 /* sub and not found (so added with new hash) */
199 /* do the 'case-dependent' hash */
201 fn
.s
[fn
.len
- 2] = ch
;
202 fnnew
.s
[fnnew
.len
- 3] = ch
;
203 fdnew
= open_trunc(fnnew
.s
);
204 if (fdnew
== -1) die_write(fatal
);
205 substdio_fdbuf(&ssnew
,write
,fdnew
,ssnewbuf
,sizeof(ssnewbuf
));
207 fd
= open_read(fn
.s
);
209 if (errno
!= error_noent
) { close(fdnew
); die_read(fatal
); }
211 substdio_fdbuf(&ss
,read
,fd
,ssbuf
,sizeof(ssbuf
));
214 if (getln(&ss
,&line
,&match
,'\0') == -1)
215 { close(fd
); close(fdnew
); die_read(fatal
); }
217 if (line
.len
== addr
.len
)
218 if (!case_diffb(line
.s
,line
.len
,addr
.s
)) {
220 continue; /* always want to remove from case-sensitive hash */
222 if (substdio_bput(&ssnew
,line
.s
,line
.len
) == -1)
223 { close(fd
); close(fdnew
); die_write(fatal
); }
229 if (substdio_flush(&ssnew
) == -1) { close(fdnew
); die_write(fatal
); }
230 if (fsync(fdnew
) == -1) { close(fdnew
); die_write(fatal
); }
233 if (rename(fnnew
.s
,fn
.s
) == -1)
234 strerr_die6sys(111,fatal
,ERR_MOVE
,fnnew
.s
," to ",fn
.s
,": ");
237 if (flagadd
^ flagwasthere
) {
238 if (!stralloc_0(&addr
)) die_nomem(fatal
);
239 log(dbname
,event
,addr
.s
+1,comment
);