chiark / gitweb /
Debianization and various other fixes.
[ezmlm] / sub_mysql / searchlog.c
1 /*$Id: searchlog.c,v 1.15 1999/11/10 04:08:27 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
3 #include "case.h"
4 #include "scan.h"
5 #include "stralloc.h"
6 #include "str.h"
7 #include "open.h"
8 #include "datetime.h"
9 #include "date822fmt.h"
10 #include "substdio.h"
11 #include "readwrite.h"
12 #include "strerr.h"
13 #include "error.h"
14 #include "errtxt.h"
15 #include "subscribe.h"
16 #include <mysql.h>
17
18 static stralloc line = {0};
19 static stralloc outline = {0};
20 static char date[DATE822FMT];
21 static datetime_sec when;
22 static struct datetime dt;
23 static substdio ssin;
24 static char inbuf[256];
25
26 static void die_nomem(fatal)
27 char *fatal;
28 {
29   strerr_die2x(111,fatal,ERR_NOMEM);
30 }
31
32 static void lineout(subwrite,fatal)
33 int subwrite();
34 char *fatal;
35 {
36   (void) scan_ulong(line.s,&when);
37   datetime_tai(&dt,when);               /* there is always at least a '\n' */
38   if (!stralloc_copyb(&outline,date,date822fmt(date,&dt) - 1))
39         die_nomem(fatal);
40   if (!stralloc_cats(&outline,": ")) die_nomem(fatal);
41   if (!stralloc_catb(&outline,line.s,line.len - 1)) die_nomem(fatal);
42   if (subwrite(outline.s,outline.len) == -1)
43         strerr_die3x(111,fatal,ERR_WRITE,"output");
44   return;
45 }
46
47 void searchlog(dir,search,subwrite,fatal)
48 /* opens dir/Log, and outputs via subwrite(s,len) any line that matches   */
49 /* search. A '_' is search is a wildcard. Any other non-alphanum/'.' char */
50 /* is replaced by a '_'. mysql version. Falls back on "manual" search of  */
51 /* local Log if no mysql connect info. */
52
53 char *dir;              /* work directory */
54 char *search;           /* search string */
55 int subwrite();         /* output fxn */
56 char *fatal;            /* fatal */
57 {
58
59   register unsigned char x;
60   register unsigned char y;
61   register unsigned char *cp;
62   register unsigned char *cpsearch;
63   unsigned register char *cps;
64   unsigned register char ch;
65   unsigned char *cplast, *cpline;
66   unsigned int searchlen;
67   int fd,match;
68   char *ret;
69
70   MYSQL_RES *result;
71   MYSQL_ROW row;
72   char *table = (char *) 0;
73   char **ptable = &table;
74   char *sublist = (char *) 0;
75   unsigned long *lengths;
76
77   if (!search) search = "";     /* defensive */
78   searchlen = str_len(search);
79   case_lowerb(search,searchlen);
80   cps = (unsigned char *) search;
81   while ((ch = *(cps++))) {     /* search is potentially hostile */
82     if (ch >= 'a' && ch <= 'z') continue;
83     if (ch >= '0' && ch <= '9') continue;
84     if (ch == '.' || ch == '_') continue;
85     *(cps - 1) = '_';           /* will match char specified as well */
86   }
87
88   if ((ret = opensql(dir,ptable))) {
89     if (*ret) strerr_die2x(111,fatal,ret);
90                                                 /* fallback to local log */
91   if (!stralloc_copys(&line,dir)) die_nomem(fatal);
92   if (!stralloc_cats(&line,"/Log")) die_nomem(fatal);
93   if (!stralloc_0(&line)) die_nomem(fatal);
94   fd = open_read(line.s);
95   if (fd == -1)
96     if (errno != error_noent)
97         strerr_die4sys(111,fatal,ERR_OPEN,line.s,": ");
98     else
99         strerr_die3x(100,fatal,line.s,ERR_NOEXIST);
100   substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
101
102   for (;;) {
103     if (getln(&ssin,&line,&match,'\n') == -1)
104       strerr_die2sys(111,fatal,ERR_READ_INPUT);
105     if (!match) break;
106     if (!searchlen) {
107       lineout(subwrite,fatal);
108     } else {
109       cpline = (unsigned char *) line.s - 1;
110       cplast = cpline + line.len - searchlen; /* line has \0 at the end */
111       while ((cp = ++cpline) <= cplast) {
112         cpsearch = (unsigned char *) search;
113         for (;;) {
114           x = *cpsearch++;
115           if (!x) break;
116           y = *cp++ - 'A';
117           if (y <= (unsigned char) ('Z' - 'A')) y += 'a'; else y += 'A';
118           if (x != y && x != '_') break;                /* '_' = wildcard */
119         }
120         if (!x) {
121           lineout(subwrite,fatal);
122           break;
123         }
124       }
125     }
126   }
127   close(fd);
128   } else {
129
130 /* SELECT (*) FROM list_slog WHERE fromline LIKE '%search%' OR address   */
131 /* LIKE '%search%' ORDER BY tai; */
132 /* The '*' is formatted to look like the output of the non-mysql version */
133 /* This requires reading the entire table, since search fields are not   */
134 /* indexed, but this is a rare query and time is not of the essence.     */
135
136     if (!stralloc_cats(&line,"SELECT CONCAT(FROM_UNIXTIME(UNIX_TIMESTAMP(tai)),"
137         "'-0000: ',UNIX_TIMESTAMP(tai),' ',edir,etype,' ',address,' ',"
138         "fromline) FROM ")) die_nomem(fatal);
139     if (!stralloc_cats(&line,table)) die_nomem(fatal);
140     if (!stralloc_cats(&line,"_slog ")) die_nomem(fatal);
141     if (*search) {      /* We can afford to wait for LIKE '%xx%' */
142       if (!stralloc_cats(&line,"WHERE fromline LIKE '%")) die_nomem(fatal);
143       if (!stralloc_cats(&line,search)) die_nomem(fatal);
144       if (!stralloc_cats(&line,"%' OR address LIKE '%")) die_nomem(fatal);
145       if (!stralloc_cats(&line,search)) die_nomem(fatal);
146       if (!stralloc_cats(&line,"%'")) die_nomem(fatal);
147     }   /* ordering by tai which is an index */
148       if (!stralloc_cats(&line," ORDER by tai")) die_nomem(fatal);
149
150     if (mysql_real_query((MYSQL *) psql,line.s,line.len))       /* query */
151         strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
152     if (!(result = mysql_use_result((MYSQL *) psql)))
153         strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
154     while ((row = mysql_fetch_row(result))) {
155     if (!(lengths = mysql_fetch_lengths(result)))
156         strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
157       if (subwrite(row[0],lengths[0]) == -1) die_write(fatal);
158     }
159     if (!mysql_eof(result))
160         strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
161     mysql_free_result(result);
162   }
163 }