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