1 /*$Id: issub.c,v 1.4 1999/12/11 03:04:03 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
14 #include "subscribe.h"
19 static void die_nomem(fatal
)
22 strerr_die2x(111,fatal
,ERR_NOMEM
);
25 static stralloc addr
= {0};
26 static stralloc lcaddr
= {0};
27 static stralloc line
= {0};
28 static stralloc fn
= {0};
30 static char ssbuf
[512];
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 */
36 /* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/
38 char *dbname
; /* directory to basedir */
40 char *tab
; /* override table name */
55 if ((ret
= opensql(dbname
,&table
))) {
56 if (*ret
) strerr_die2x(111,fatal
,ret
);
57 /* fallback to local db */
59 if (!stralloc_copys(&addr
,"T")) die_nomem(fatal
);
60 if (!stralloc_cats(&addr
,userhost
)) die_nomem(fatal
);
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 */
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
];
75 lcch
= 64 + (lch
% 53);
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
);
86 if (errno
!= error_noent
)
87 strerr_die4sys(111,fatal
,ERR_OPEN
,fn
.s
,": ");
89 substdio_fdbuf(&ss
,read
,fd
,ssbuf
,sizeof(ssbuf
));
92 if (getln(&ss
,&line
,&match
,'\0') == -1)
93 strerr_die4sys(111,fatal
,ERR_READ
,fn
.s
,": ");
95 if (line
.len
== lcaddr
.len
)
96 if (!case_diffb(line
.s
,line
.len
,lcaddr
.s
))
97 { close(fd
); return line
.s
+1; }
102 /* here if file not found or (file found && addr not there) */
104 if (ch
== lcch
) return 0;
106 /* try case sensitive hash for backwards compatibility */
107 fn
.s
[fn
.len
- 2] = ch
;
108 fd
= open_read(fn
.s
);
110 if (errno
!= error_noent
)
111 strerr_die4sys(111,fatal
,ERR_OPEN
,fn
.s
,": ");
114 substdio_fdbuf(&ss
,read
,fd
,ssbuf
,sizeof(ssbuf
));
117 if (getln(&ss
,&line
,&match
,'\0') == -1)
118 strerr_die4sys(111,fatal
,ERR_READ
,fn
.s
,": ");
120 if (line
.len
== addr
.len
)
121 if (!case_diffb(line
.s
,line
.len
,addr
.s
))
122 { close(fd
); return line
.s
+1; }
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 ...". */
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);
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
);
146 if (!stralloc_0(&line
)) die_nomem(fatal
);
147 result
= PQexec(psql
,line
.s
);
149 strerr_die2x(111,fatal
,PQerrorMessage(psql
));
150 if (PQresultStatus(result
) != PGRES_TUPLES_OK
)
151 strerr_die2x(111,fatal
,PQresultErrorMessage(result
));
153 /* No data returned in QUERY */
154 if (PQntuples(result
) < 1)
157 if (!stralloc_copyb(&line
,PQgetvalue(result
,0,0),PQgetlength(result
,0,0)))
159 if (!stralloc_0(&line
)) die_nomem(fatal
);