Import ezmlm-idx 0.40
[ezmlm] / sub_pgsql / putsubs.c
1 #include "error.h"
2 #include "strerr.h"
3 #include "readwrite.h"
4 #include "str.h"
5 #include "fmt.h"
6 #include "stralloc.h"
7 #include "open.h"
8 #include "substdio.h"
9 #include "case.h"
10 #include "errtxt.h"
11 #include "subscribe.h"
12 #include "qmail.h"
13 #include <unistd.h>
14 #include <libpq-fe.h>
15
16 static substdio ssin;
17 static char inbuf[512];
18 char strnum[FMT_ULONG];
19 static stralloc line = {0};
20 static stralloc fn = {0};
21
22 static void die_nomem(fatal)
23 char *fatal;
24 {
25 strerr_die2x(111,fatal,ERR_NOMEM);
26 }
27
28 static void die_write(fatal)
29 char *fatal;
30 {
31 strerr_die3x(111,fatal,ERR_WRITE,"stdout");
32 }
33
34 unsigned long putsubs(dbname,hash_lo,hash_hi,
35 subwrite,flagsql,fatal)
36 /* Outputs all userhostesses in 'dbname' to stdout. If userhost is not null */
37 /* that userhost is excluded. 'dbname' is the base directory name. For the */
38 /* mysql version, dbname is the directory where the file "sql" with mysql */
39 /* access info is found. If this file is not present or if flagmysql is not */
40 /* set, the routine falls back to the old database style. subwrite must be a*/
41 /* function returning >=0 on success, -1 on error, and taking arguments */
42 /* (char* string, unsigned int length). It will be called once per address */
43 /* and should take care of newline or whatever needed for the output form. */
44
45 char *dbname; /* database base dir */
46 unsigned long hash_lo;
47 unsigned long hash_hi;
48 int subwrite(); /* write function. */
49 int flagsql;
50 char *fatal; /* fatal error string */
51
52 {
53 PGresult *result;
54 int row_nr;
55 int length;
56 char *row;
57 char *table = (char *) 0;
58
59 unsigned int i;
60 int fd;
61 unsigned long no = 0L;
62 int match;
63 unsigned int hashpos;
64 char *ret = (char *) 0;
65
66 if (!flagsql || (ret = opensql(dbname,&table))) {
67 if (flagsql && *ret) strerr_die2x(111,fatal,ret);
68 /* fallback to local db */
69 if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
70 if (!stralloc_catb(&fn,"/subscribers/?",15)) die_nomem(fatal);
71 /* NOTE: Also copies terminal '\0' */
72 hashpos = fn.len - 2;
73 if (hash_lo > 52) hash_lo = 52;
74 if (hash_hi > 52) hash_hi = 52;
75 if (hash_hi < hash_lo) hash_hi = hash_lo;
76
77 for (i = hash_lo;i <= hash_hi;++i) {
78 fn.s[hashpos] = 64 + i; /* hash range 0-52 */
79 fd = open_read(fn.s);
80 if (fd == -1) {
81 if (errno != error_noent)
82 strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
83 } else {
84 substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
85 for (;;) {
86 if (getln(&ssin,&line,&match,'\0') == -1)
87 strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
88 if (!match)
89 break;
90 if (subwrite(line.s + 1,line.len - 2) == -1) die_write(fatal);
91 no++;
92 }
93 close(fd);
94 }
95 }
96 return no;
97
98 } else { /* SQL Version */
99
100 /* main query */
101 if (!stralloc_copys(&line,"SELECT address FROM "))
102 die_nomem(fatal);
103 if (!stralloc_cats(&line,table)) die_nomem(fatal);
104 if (!stralloc_cats(&line," WHERE hash BETWEEN ")) die_nomem(fatal);
105 if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash_lo)))
106 die_nomem(fatal);
107 if (!stralloc_cats(&line," AND ")) die_nomem(fatal);
108 if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash_hi)))
109 die_nomem(fatal);
110 if (!stralloc_0(&line)) die_nomem(fatal);
111 result = PQexec(psql,line.s);
112 if (result == NULL)
113 strerr_die2x(111,fatal,PQerrorMessage(psql));
114 if (PQresultStatus(result) != PGRES_TUPLES_OK)
115 strerr_die2x(111,fatal,PQresultErrorMessage(result));
116
117 no = 0;
118 for (row_nr=0;row_nr<PQntuples(result);row_nr++) {
119 /* this is safe even if someone messes with the address field def */
120 length = PQgetlength(result,row_nr,0);
121 row = PQgetvalue(result,row_nr,0);
122 if (subwrite(row,length) == -1) die_write(fatal);
123 no++; /* count for list-list fxn */
124 }
125 PQclear(result);
126 return no;
127 }
128 }