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