Commit | Line | Data |
---|---|---|
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 | ||
14 | static stralloc addr = {0}; | |
15 | static stralloc line = {0}; | |
16 | static stralloc fnnew = {0}; | |
17 | static stralloc fn = {0}; | |
18 | ||
19 | static int fd; | |
20 | static substdio ss; | |
21 | static char ssbuf[256]; | |
22 | static int fdnew; | |
23 | static substdio ssnew; | |
24 | static char ssnewbuf[256]; | |
25 | ||
26 | static int doit(userhost,flagadd) | |
27 | char *userhost; | |
28 | int 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 | ||
98 | struct strerr subscribe_err; | |
99 | ||
100 | int subscribe(userhost,flagadd) | |
101 | char *userhost; | |
102 | int 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 | } |