Import ezmlm-idx 0.40
[ezmlm] / sub_mysql / searchlog.c
CommitLineData
f8beb284
MW
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
18static stralloc line = {0};
19static stralloc outline = {0};
20static char date[DATE822FMT];
21static datetime_sec when;
22static struct datetime dt;
23static substdio ssin;
24static char inbuf[256];
25
26static void die_nomem(fatal)
27char *fatal;
28{
29 strerr_die2x(111,fatal,ERR_NOMEM);
30}
31
32static void lineout(subwrite,fatal)
33int subwrite();
34char *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
47void 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
53char *dir; /* work directory */
54char *search; /* search string */
55int subwrite(); /* output fxn */
56char *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}