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 
doit(userhost,flagadd)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 
subscribe(userhost,flagadd)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 }
128