chiark / gitweb /
Debianization and various other fixes.
[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