Import ezmlm 0.53
[ezmlm] / subscribe.c
CommitLineData
5b62e993
MW
1#include "stralloc.h"
2#include "getln.h"
3#include "readwrite.h"
4#include "substdio.h"
5#include "strerr.h"
6#include "open.h"
7#include "byte.h"
8#include "case.h"
9#include "lock.h"
10#include "error.h"
11#include "uint32.h"
12#include "subscribe.h"
13
14static stralloc addr = {0};
15static stralloc line = {0};
16static stralloc fnnew = {0};
17static stralloc fn = {0};
18
19static int fd;
20static substdio ss;
21static char ssbuf[256];
22static int fdnew;
23static substdio ssnew;
24static char ssnewbuf[256];
25
26static int doit(userhost,flagadd)
27char *userhost;
28int flagadd;
29{
30 int j;
31 uint32 h;
32 char ch;
33 int match;
34 int flagwasthere;
35
36 if (userhost[str_chr(userhost,'\n')]) return -8;
37 if (!stralloc_copys(&addr,"T")) return -2;
38 if (!stralloc_cats(&addr,userhost)) return -2;
39 if (addr.len > 401) return -7;
40
41 j = byte_rchr(addr.s,addr.len,'@');
42 if (j == addr.len) return -6;
43 case_lowerb(addr.s + j + 1,addr.len - j - 1);
44
45 h = 5381;
46 for (j = 0;j < addr.len;++j)
47 h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
48 ch = 64 + (h % 53);
49
50 if (!stralloc_0(&addr)) return -2;
51
52 if (!stralloc_copys(&fn,"subscribers/")) return -2;
53 if (!stralloc_catb(&fn,&ch,1)) return -2;
54 if (!stralloc_copy(&fnnew,&fn)) return -2;
55 if (!stralloc_cats(&fnnew,"n")) return -2;
56 if (!stralloc_0(&fnnew)) return -2;
57 if (!stralloc_0(&fn)) return -2;
58
59 fdnew = open_trunc(fnnew.s);
60 if (fdnew == -1) return -4;
61 substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));
62
63 flagwasthere = 0;
64
65 fd = open_read(fn.s);
66 if (fd == -1) {
67 if (errno != error_noent) { close(fdnew); return -3; }
68 }
69 else {
70 substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
71
72 for (;;) {
73 if (getln(&ss,&line,&match,'\0') == -1) { close(fd); close(fdnew); return -3; }
74 if (!match) break;
75 if (line.len == addr.len)
76 if (!byte_diff(line.s,line.len,addr.s)) {
77 flagwasthere = 1;
78 if (!flagadd)
79 continue;
80 }
81 if (substdio_bput(&ssnew,line.s,line.len) == -1) { close(fd); close(fdnew); return -4; }
82 }
83
84 close(fd);
85 }
86
87 if (flagadd && !flagwasthere)
88 if (substdio_bput(&ssnew,addr.s,addr.len) == -1) { close(fdnew); return -4; }
89
90 if (substdio_flush(&ssnew) == -1) { close(fdnew); return -4; }
91 if (fsync(fdnew) == -1) { close(fdnew); return -4; }
92 close(fdnew);
93
94 if (rename(fnnew.s,fn.s) == -1) return -5;
95 return flagadd ^ flagwasthere;
96}
97
98struct strerr subscribe_err;
99
100int subscribe(userhost,flagadd)
101char *userhost;
102int flagadd;
103{
104 int fdlock;
105 int r;
106
107 fdlock = open_append("lock");
108 if (fdlock == -1)
109 STRERR_SYS(-1,subscribe_err,"unable to open lock: ")
110 if (lock_ex(fdlock) == -1) {
111 close(fdlock);
112 STRERR_SYS(-1,subscribe_err,"unable to obtain lock: ")
113 }
114
115 r = doit(userhost,flagadd);
116 close(fdlock);
117
118 if (r == -2) STRERR(-1,subscribe_err,"out of memory")
119 if (r == -3) STRERR_SYS3(-1,subscribe_err,"unable to read ",fn.s,": ")
120 if (r == -4) STRERR_SYS3(-1,subscribe_err,"unable to write ",fnnew.s,": ")
121 if (r == -5) STRERR_SYS3(-1,subscribe_err,"unable to move temporary file to ",fn.s,": ")
122 if (r == -6) STRERR(-2,subscribe_err,"address does not contain @")
123 if (r == -7) STRERR(-2,subscribe_err,"address is too long")
124 if (r == -8) STRERR(-2,subscribe_err,"address contains newline")
125
126 return r;
127}