Import ezmlm-idx 0.40
[ezmlm] / sub_pgsql / issub.c
1 /*$Id: issub.c,v 1.4 1999/12/11 03:04:03 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
3 #include "stralloc.h"
4 #include "getln.h"
5 #include "readwrite.h"
6 #include "substdio.h"
7 #include "open.h"
8 #include "byte.h"
9 #include "case.h"
10 #include "strerr.h"
11 #include "error.h"
12 #include "uint32.h"
13 #include "fmt.h"
14 #include "subscribe.h"
15 #include "errtxt.h"
16 #include <unistd.h>
17 #include <libpq-fe.h>
18
19 static void die_nomem(fatal)
20 char *fatal;
21 {
22 strerr_die2x(111,fatal,ERR_NOMEM);
23 }
24
25 static stralloc addr = {0};
26 static stralloc lcaddr = {0};
27 static stralloc line = {0};
28 static stralloc fn = {0};
29 static substdio ss;
30 static char ssbuf[512];
31
32 char *issub(dbname,userhost,tab,fatal)
33 /* Returns (char *) to match if userhost is in the subscriber database */
34 /* dbname, 0 otherwise. dbname is a base directory for a list and may NOT */
35 /* be NULL */
36 /* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/
37
38 char *dbname; /* directory to basedir */
39 char *userhost;
40 char *tab; /* override table name */
41 char *fatal;
42
43 {
44 PGresult *result;
45 char *ret;
46 char *table;
47
48 int fd;
49 unsigned int j;
50 uint32 h,lch;
51 char ch,lcch;
52 int match;
53
54 table = tab;
55 if ((ret = opensql(dbname,&table))) {
56 if (*ret) strerr_die2x(111,fatal,ret);
57 /* fallback to local db */
58
59 if (!stralloc_copys(&addr,"T")) die_nomem(fatal);
60 if (!stralloc_cats(&addr,userhost)) die_nomem(fatal);
61
62 j = byte_rchr(addr.s,addr.len,'@');
63 if (j == addr.len) return 0;
64 case_lowerb(addr.s + j + 1,addr.len - j - 1);
65 if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal);
66 case_lowerb(lcaddr.s + 1,j - 1); /* totally lc version of addr */
67
68 h = 5381;
69 lch = h; /* make hash for both for backwards comp */
70 for (j = 0;j < addr.len;++j) { /* (lcaddr.len == addr.len) */
71 h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
72 lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j];
73 }
74 ch = 64 + (h % 53);
75 lcch = 64 + (lch % 53);
76
77 if (!stralloc_0(&addr)) die_nomem(fatal);
78 if (!stralloc_0(&lcaddr)) die_nomem(fatal);
79 if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
80 if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal);
81 if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal);
82 if (!stralloc_0(&fn)) die_nomem(fatal);
83
84 fd = open_read(fn.s);
85 if (fd == -1) {
86 if (errno != error_noent)
87 strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": ");
88 } else {
89 substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
90
91 for (;;) {
92 if (getln(&ss,&line,&match,'\0') == -1)
93 strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
94 if (!match) break;
95 if (line.len == lcaddr.len)
96 if (!case_diffb(line.s,line.len,lcaddr.s))
97 { close(fd); return line.s+1; }
98 }
99
100 close(fd);
101 }
102 /* here if file not found or (file found && addr not there) */
103
104 if (ch == lcch) return 0;
105
106 /* try case sensitive hash for backwards compatibility */
107 fn.s[fn.len - 2] = ch;
108 fd = open_read(fn.s);
109 if (fd == -1) {
110 if (errno != error_noent)
111 strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": ");
112 return 0;
113 }
114 substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
115
116 for (;;) {
117 if (getln(&ss,&line,&match,'\0') == -1)
118 strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
119 if (!match) break;
120 if (line.len == addr.len)
121 if (!case_diffb(line.s,line.len,addr.s))
122 { close(fd); return line.s+1; }
123 }
124
125 close(fd);
126
127 return 0;
128 } else { /* SQL version */
129 /* SELECT address FROM list WHERE address = 'userhost' AND hash */
130 /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */
131 /* even easier to defeat. Just faking sender to the list name would*/
132 /* work. Since sender checks for posts are bogus anyway, I don't */
133 /* know if it's worth the cost of the "WHERE ...". */
134
135 if (!stralloc_copys(&addr,userhost)) die_nomem(fatal);
136 j = byte_rchr(addr.s,addr.len,'@');
137 if (j == addr.len) return 0;
138 case_lowerb(addr.s + j + 1,addr.len - j - 1);
139
140 if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(fatal);
141 if (!stralloc_cats(&line,table)) die_nomem(fatal);
142 if (!stralloc_cats(&line," WHERE address ~* '^")) die_nomem(fatal);
143 if (!stralloc_cat(&line,&addr)) die_nomem(fatal);
144 if (!stralloc_cats(&line,"$'")) die_nomem(fatal);
145
146 if (!stralloc_0(&line)) die_nomem(fatal);
147 result = PQexec(psql,line.s);
148 if (result == NULL)
149 strerr_die2x(111,fatal,PQerrorMessage(psql));
150 if (PQresultStatus(result) != PGRES_TUPLES_OK )
151 strerr_die2x(111,fatal,PQresultErrorMessage(result));
152
153 /* No data returned in QUERY */
154 if (PQntuples(result) < 1)
155 return (char *)0;
156
157 if (!stralloc_copyb(&line,PQgetvalue(result,0,0),PQgetlength(result,0,0)))
158 die_nomem(fatal);
159 if (!stralloc_0(&line)) die_nomem(fatal);
160
161 PQclear(result);
162 return line.s;
163 }
164 }
165