/*
 *
 *      Copyright (C) 1991 by the Massachusetts Institute of Technology
 *      Developed by the MIT Student Information Processing Board (SIPB).
 *      For copying information, see the file mit-copyright.h in this release.
 *
 */

#ifndef lint
#ifndef SABER
static char *RCSid = "$Header: /mit/discuss/source/dsgrep/RCS/dsgrep.c,v 1.2 91/07/06 17:34:59 bjaspan Exp $";
#endif
#endif

#include "regexp.h"

#define MAX_MEETINGS 128
#define DEFAULT_MFILE "/mit/consult/lib/dsgrep/default_meetings"
#define LOCAL_MFILE "/tmp/dsgrep_mtgsXXXXXX"

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/stat.h>
#ifdef SVR4
#include <fcntl.h>
#endif
#include <discuss/discuss.h>

#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif

extern tfile unix_tfile();
extern tfile mem_tfile();
extern char *malloc(),*calloc();

extern int errno;
extern char *sys_errlist[];
extern int sys_nerr;

int verbose_errors;
int bsize;
char *buffer;

main(argc,argv)
     int argc;
     char *argv[];
{
  extern int optind;
  extern char *optarg;

  char *meetings_file,*homedir,*getenv();
  name_blk *meetings,*tmp_mtg;
  mtg_info meeting_info[MAX_MEETINGS];
  char tmp_meeting_file[MAXPATHLEN];
  int n_meetings,result,setenv(),i,cur_meeting,n_to_look,j,c;
  int print_trans,use_re,search_trans,search_deleted,s_trans();
  int case_insens,trans_num;
  int high,low;
  regexp *search_re;
  tfile tf;
  trn_info2 ti;
  void s_to_lower();
  int tmp_fd1,tmp_fd2;
  int using_dflt_mtgs = 0;
  char *tmp_buf;
  struct stat statb;
  
  n_to_look = 50;
  print_trans = 0;
  search_trans = 0;
  use_re = 0;
  verbose_errors = 0;
  case_insens = 0;
  search_deleted = 0;
  trans_num = 0;
  meetings_file = NULL;

  while ((c = getopt(argc,argv, "n:e:f:t:apvdhil")) != EOF)
    switch(c) {
    case 'n':
      n_to_look = atoi(optarg);
      break;
    case 't':
      trans_num = atoi(optarg);
      break;
    case 'p':
      print_trans=1;
      break;
    case 'd':
      search_deleted = 1;
      break;
    case 'a':
      search_trans=1;
      bsize = 4096;
      if ((buffer = malloc((unsigned) bsize)) == NULL) {
        fprintf(stderr,"dsgrep: malloc failed\n");
	exit(1);
      }
      break;
    case 'e':
      if ((search_re = regcomp(optarg)) == NULL) {
	fprintf(stderr,"dsgrep: Invalid regular expression %s\n",optarg);
	exit(1);
      }
      use_re = 1;
      break;
    case 'f':
      meetings_file = optarg;
      break;
    case 'v':
      verbose_errors=1;
      break;
    case 'i':
      case_insens=1;
      break;
    case 'l':
      strcpy(tmp_meeting_file,LOCAL_MFILE);
      mktemp(tmp_meeting_file);
      if ((tmp_fd1 = open(tmp_meeting_file,O_WRONLY|O_CREAT|O_TRUNC,0600))
	  < 0) {
	fprintf(stderr,"dsgrep: error opening temp meetings file %s: %s\n",
		tmp_meeting_file, sys_errlist[errno]);
	exit(errno);
      }
      if ((tmp_fd2 = open(DEFAULT_MFILE,O_RDONLY,0)) < 0) {
	fprintf(stderr,"dsgrep: error opening default meetngs file %s: %s\n",
		DEFAULT_MFILE, sys_errlist[errno]);
	exit(errno);
      }
      if (fstat(tmp_fd2,&statb) < 0) {
	fprintf(stderr,"dsgrep: error stat'ing default meetings file %s: %s\n",
		tmp_meeting_file, sys_errlist[errno]);
	exit(errno);
      }
      if ((tmp_buf = (char *)malloc(statb.st_size)) == NULL) {
	fprintf(stderr,"dsgrep: error malloc'ing %d bytes\n", statb.st_size);
	exit(-1);
      }
      if (read(tmp_fd2,tmp_buf,statb.st_size) != statb.st_size) {
	fprintf(stderr,"dsgrep: error reading %s: %s\n",DEFAULT_MFILE,
		sys_errlist[errno]);
	exit(errno);
      }
      close(tmp_fd2);
      if (write(tmp_fd1,tmp_buf,statb.st_size) != statb.st_size) {
	fprintf(stderr,"dsgrep: error writing %s: %s\n",tmp_meeting_file,
		sys_errlist[errno]);
	exit(errno);
      }
      if (close(tmp_fd1) < 0) {
	fprintf(stderr,"dsgrep: error closing %s: %s\n",tmp_meeting_file,
		sys_errlist[errno]);
	exit(errno);
      }
      using_dflt_mtgs = 1;
      meetings_file = tmp_meeting_file;
      break;
    case '?':
    case 'h':
      fprintf(stderr,"usage: dsgrep [-n n_trans]\n");
      fprintf(stderr,"           [-e title_regexp]\n");
      fprintf(stderr,"           [-t trans_num] print out a specific trans\n");
      fprintf(stderr,"           [-a]  (search text as well as title)\n");
      fprintf(stderr,"           [-p]  (print matching transactions)\n");
      fprintf(stderr,"           [-v]  (print out verbose error messages)\n");
      fprintf(stderr,"           [-d]  (search deleted transactions as well)\n");
      fprintf(stderr,"           [-i]  (convert text to lower case before searching)\n");
      fprintf(stderr,"           [-f alt_meeting_file]\n");
      fprintf(stderr,"           [-l]  (search through OLC logs)\n");
      fprintf(stderr,"           [meetings]   (this must be last)\n");
      exit(1);
      break;
    }

  if (meetings_file == NULL) {  /* Nothing set, use out of home directory */
    if ((homedir = getenv("HOME")) == NULL) {
      fprintf(stderr,"dsgrep: could not get HOME environment variable\n");
      exit(1);
    }
    meetings_file = (char *)malloc(256);
    strcpy(meetings_file,homedir);
    strcat(meetings_file,"/.meetings");
  }
  if (setenv("MEETINGS",meetings_file,1) == -1) {
    fprintf(stderr,"dsgrep: could not add environment variable\n");
    exit(1);
  }

  switch (optind - argc) {
  case 0:
    dsc_expand_mtg_set(NULL,"*",&meetings,&cur_meeting,&result);
    break;
  case 1:
    dsc_expand_mtg_set(NULL,argv[optind],&meetings,&cur_meeting,&result);
    break;
  default:
    meetings = (name_blk *)calloc((unsigned)MAX_MEETINGS,sizeof(name_blk)); 
    cur_meeting = 0;
    for(i=optind;i<argc;i++) {
      dsc_expand_mtg_set(NULL,argv[i],&tmp_mtg,&n_meetings,&result);
      if ((n_meetings == 0) && (result == 0)) {
	fprintf(stderr,"dsgrep: no such meeting %s in %s\n",argv[i],
		meetings_file);
	continue;
      }
      if (result != 0) {
	fprintf(stderr,"dsgrep: error %d expanding meeting %s\n",result,argv[i]);
	exit(1);
      }
      bcopy((char *)tmp_mtg,(char *)&meetings[cur_meeting],sizeof(name_blk));
      cur_meeting++;
    }
  }

  if (cur_meeting == 0) {
    fprintf(stderr,"No meetings selected.\n");
    exit(1);
  }

  tf = unix_tfile(1); /*stdout */

  for(i=0;i<cur_meeting;i++) {
    dsc_get_mtg_info(&meetings[i],&meeting_info[i],&result);
     if (result != 0) {
       fprintf(stderr,"dsgrep: error %d getting meeting info for meeting %s:%s\n",
             result, meetings[i].hostname, meetings[i].pathname);
     }
    if (trans_num != 0) {
      low = trans_num;
      high = trans_num;
    } else {
      low = meeting_info[i].highest-n_to_look+1; 
      low = MAX(low,1);
      high = meeting_info[i].highest;
    }
    for(j=low;j<=high;j++)
      {
	dsc_get_trn_info2(&meetings[i],j,&ti,&result);
	if ((result != 0) && verbose_errors) {
	  fprintf(stderr,"dsgrep: error %d getting transaction info for %s[%d]\n",
		  result, (char *) (rindex(meetings[i].pathname,'/')+1),j);
	}
	if (!search_deleted && (ti.flags & TRN_FDELETED))
	  continue;
	if (case_insens) s_to_lower(ti.subject);
	if (!use_re || regexec(search_re,ti.subject) ||
	    (search_trans &&
	     s_trans(meetings[i],j,ti.num_chars,search_re,case_insens)))  {
	  printf("%s [%d]: %s\n",(char *)
		 (rindex(meetings[i].pathname,'/')+1), j, ti.subject);
	  if (print_trans) {
	    dsc_get_trn(&meetings[i],j,tf,&result);
	    if ((result != 0) && verbose_errors)
	      fprintf(stderr,"dsgrep: error %d getting transaction %s[%d]\n",
		      result,(char *) (rindex(meetings[i].pathname,'/')+1),j );
	    printf("*** End of Transaction ***\n");
	  }
	}
      }
  }
  if (using_dflt_mtgs)
    unlink(tmp_meeting_file);
  exit(0);
}

int
s_trans(nbp,trans_no,n_chars,search_re,case_insens)
     name_blk nbp;
     int trans_no,n_chars;
     regexp *search_re;
     int case_insens;
{
  tfile tf;
  int result;
  void s_to_lower();

  if (++n_chars > bsize) {
    free(buffer);
    if ((buffer = malloc((unsigned)n_chars)) == NULL) {
      fprintf(stderr,"dsgrep: malloc failed\n");
      exit(1);
    }
    bsize = n_chars;
  }
  tf = mem_tfile(buffer,bsize);
  dsc_get_trn(&nbp,trans_no,tf,&result);
  if ((result != 0) && verbose_errors){
    fprintf(stderr,"dsgrep: error %d getting transation %s[%d]\n", result,
	    (char *) (rindex(nbp.pathname,'/')+1),trans_no);
  }
  tdestroy(tf);
  buffer[n_chars-1] = '\0';
  if (case_insens) s_to_lower(buffer);
  return(regexec(search_re,buffer));
}

void
s_to_lower(bufp)
     char *bufp;
{
  while (*bufp != '\0') {
    if (isupper(*bufp)) *bufp = tolower(*bufp);
    bufp++;
    }
}
