Import ezmlm-idx 0.40
[ezmlm] / sub_mysql / searchlog.c
diff --git a/sub_mysql/searchlog.c b/sub_mysql/searchlog.c
new file mode 100644 (file)
index 0000000..8d8278f
--- /dev/null
@@ -0,0 +1,163 @@
+/*$Id: searchlog.c,v 1.15 1999/11/10 04:08:27 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "case.h"
+#include "scan.h"
+#include "stralloc.h"
+#include "str.h"
+#include "open.h"
+#include "datetime.h"
+#include "date822fmt.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "strerr.h"
+#include "error.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include <mysql.h>
+
+static stralloc line = {0};
+static stralloc outline = {0};
+static char date[DATE822FMT];
+static datetime_sec when;
+static struct datetime dt;
+static substdio ssin;
+static char inbuf[256];
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static void lineout(subwrite,fatal)
+int subwrite();
+char *fatal;
+{
+  (void) scan_ulong(line.s,&when);
+  datetime_tai(&dt,when);              /* there is always at least a '\n' */
+  if (!stralloc_copyb(&outline,date,date822fmt(date,&dt) - 1))
+       die_nomem(fatal);
+  if (!stralloc_cats(&outline,": ")) die_nomem(fatal);
+  if (!stralloc_catb(&outline,line.s,line.len - 1)) die_nomem(fatal);
+  if (subwrite(outline.s,outline.len) == -1)
+       strerr_die3x(111,fatal,ERR_WRITE,"output");
+  return;
+}
+
+void searchlog(dir,search,subwrite,fatal)
+/* opens dir/Log, and outputs via subwrite(s,len) any line that matches   */
+/* search. A '_' is search is a wildcard. Any other non-alphanum/'.' char */
+/* is replaced by a '_'. mysql version. Falls back on "manual" search of  */
+/* local Log if no mysql connect info. */
+
+char *dir;             /* work directory */
+char *search;          /* search string */
+int subwrite();                /* output fxn */
+char *fatal;           /* fatal */
+{
+
+  register unsigned char x;
+  register unsigned char y;
+  register unsigned char *cp;
+  register unsigned char *cpsearch;
+  unsigned register char *cps;
+  unsigned register char ch;
+  unsigned char *cplast, *cpline;
+  unsigned int searchlen;
+  int fd,match;
+  char *ret;
+
+  MYSQL_RES *result;
+  MYSQL_ROW row;
+  char *table = (char *) 0;
+  char **ptable = &table;
+  char *sublist = (char *) 0;
+  unsigned long *lengths;
+
+  if (!search) search = "";    /* defensive */
+  searchlen = str_len(search);
+  case_lowerb(search,searchlen);
+  cps = (unsigned char *) search;
+  while ((ch = *(cps++))) {    /* search is potentially hostile */
+    if (ch >= 'a' && ch <= 'z') continue;
+    if (ch >= '0' && ch <= '9') continue;
+    if (ch == '.' || ch == '_') continue;
+    *(cps - 1) = '_';          /* will match char specified as well */
+  }
+
+  if ((ret = opensql(dir,ptable))) {
+    if (*ret) strerr_die2x(111,fatal,ret);
+                                               /* fallback to local log */
+  if (!stralloc_copys(&line,dir)) die_nomem(fatal);
+  if (!stralloc_cats(&line,"/Log")) die_nomem(fatal);
+  if (!stralloc_0(&line)) die_nomem(fatal);
+  fd = open_read(line.s);
+  if (fd == -1)
+    if (errno != error_noent)
+       strerr_die4sys(111,fatal,ERR_OPEN,line.s,": ");
+    else
+        strerr_die3x(100,fatal,line.s,ERR_NOEXIST);
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,fatal,ERR_READ_INPUT);
+    if (!match) break;
+    if (!searchlen) {
+      lineout(subwrite,fatal);
+    } else {
+      cpline = (unsigned char *) line.s - 1;
+      cplast = cpline + line.len - searchlen; /* line has \0 at the end */
+      while ((cp = ++cpline) <= cplast) {
+       cpsearch = (unsigned char *) search;
+       for (;;) {
+         x = *cpsearch++;
+         if (!x) break;
+         y = *cp++ - 'A';
+         if (y <= (unsigned char) ('Z' - 'A')) y += 'a'; else y += 'A';
+         if (x != y && x != '_') break;                /* '_' = wildcard */
+       }
+       if (!x) {
+         lineout(subwrite,fatal);
+         break;
+       }
+      }
+    }
+  }
+  close(fd);
+  } else {
+
+/* SELECT (*) FROM list_slog WHERE fromline LIKE '%search%' OR address   */
+/* LIKE '%search%' ORDER BY tai; */
+/* The '*' is formatted to look like the output of the non-mysql version */
+/* This requires reading the entire table, since search fields are not   */
+/* indexed, but this is a rare query and time is not of the essence.     */
+
+    if (!stralloc_cats(&line,"SELECT CONCAT(FROM_UNIXTIME(UNIX_TIMESTAMP(tai)),"
+       "'-0000: ',UNIX_TIMESTAMP(tai),' ',edir,etype,' ',address,' ',"
+       "fromline) FROM ")) die_nomem(fatal);
+    if (!stralloc_cats(&line,table)) die_nomem(fatal);
+    if (!stralloc_cats(&line,"_slog ")) die_nomem(fatal);
+    if (*search) {     /* We can afford to wait for LIKE '%xx%' */
+      if (!stralloc_cats(&line,"WHERE fromline LIKE '%")) die_nomem(fatal);
+      if (!stralloc_cats(&line,search)) die_nomem(fatal);
+      if (!stralloc_cats(&line,"%' OR address LIKE '%")) die_nomem(fatal);
+      if (!stralloc_cats(&line,search)) die_nomem(fatal);
+      if (!stralloc_cats(&line,"%'")) die_nomem(fatal);
+    }  /* ordering by tai which is an index */
+      if (!stralloc_cats(&line," ORDER by tai")) die_nomem(fatal);
+
+    if (mysql_real_query((MYSQL *) psql,line.s,line.len))      /* query */
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    if (!(result = mysql_use_result((MYSQL *) psql)))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    while ((row = mysql_fetch_row(result))) {
+    if (!(lengths = mysql_fetch_lengths(result)))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+      if (subwrite(row[0],lengths[0]) == -1) die_write(fatal);
+    }
+    if (!mysql_eof(result))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    mysql_free_result(result);
+  }
+}