/* 
 * "$Id: nmzmail.c,v 1.9 2005/05/23 18:47:18 hofmann Exp $"
 *
 * flpsed program.
 *
 * Copyright 2004,2005 by Johannes Hofmann
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *  
 * You should have received a copy of the GNU General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <strings.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "util.h"
#include "../config.h"

char *get_query();
int   create_result_dir(char *nmz_result);
int   generate_result(char *query, char *nmz_index, 
		      char *nmz_result, int result_limit);
void  build_index(char *nmz_index, char *mail_dirs[], int num_mail_dirs);
void  usage();

#define BUF_LEN 1024
#define MAX_MAIL_DIRS 32

int 
main(int argc, char **argv) {
  char *query, *home, *result = 0, **my_argv;
  int c, errflg = 0, count, index_flag = 0, num_mail_dirs = 0, my_argc, i;
  char  nmz_base[BUF_LEN];
  char  nmz_result[BUF_LEN];
  char  nmz_index[BUF_LEN];
  char *mail_dirs[MAX_MAIL_DIRS];
  int   result_limit = 2000;

  home = getenv("HOME");
  if (!home) {
    perror("getenv");
    exit(1);
  }
  
  snprintf(nmz_base, sizeof(nmz_base), "%s/.nmzmail", home);
  mkdir(nmz_base, 0777);

  while ((c = getopt(argc, argv, "b:r:im:n:")) != -1) {
    switch (c) {
    case 'b':
      strncpy(nmz_base, optarg, sizeof(nmz_base));
      break;
    case 'r':
      result = optarg;
      break;
    case 'i':
      index_flag = 1;
      break;
    case 'm':
      fprintf(stderr, "Warning: -m option is deprecated.\n");
      if (num_mail_dirs < MAX_MAIL_DIRS) {
        mail_dirs[num_mail_dirs++] = optarg;
      } else {
        fprintf(stderr,
		"maximum number (%d) of mail directories exceeded.\n", 
		MAX_MAIL_DIRS);
      }
      break;
    case 'n':
      result_limit = atoi(optarg);
      if (result_limit <= 0) {
	errflg++;
      }
      break;
    case '?':
      errflg++;
    }
  }

  if (errflg) {
    usage();
    exit(1);
  }

  my_argc = argc - optind;
  my_argv = argv + optind;

  for (i=0; i<my_argc; i++) {
    if (num_mail_dirs < MAX_MAIL_DIRS) {
      mail_dirs[num_mail_dirs++] = my_argv[i];
    } else {
      fprintf(stderr,
	      "maximum number (%d) of mail directories exceeded.\n", 
	      MAX_MAIL_DIRS);
      break;
    }
  }
  
  if (result) {
    strncpy(nmz_result, result, sizeof(nmz_result));
  } else {
    snprintf(nmz_result, sizeof(nmz_result), "%s/result", nmz_base);
  }

  snprintf(nmz_index, sizeof(nmz_index), "%s/index", nmz_base);

  if (index_flag) {
    build_index(nmz_index, mail_dirs, num_mail_dirs);
  } else {
    query = get_query(nmz_base);
    
    if (query == NULL) {
      fprintf(stderr, "Could not get query string.\n");
      exit(1);
    }

    if (create_result_dir(nmz_result) != 0) {
      fprintf(stderr, "Could not setup result directory %s.\n", nmz_result);
      exit(1);
    }
    
    count = generate_result(query, nmz_index, nmz_result, result_limit);
    
    printf("%d matches.\n", count);
  }
  
  exit(0);
}


char *
get_query(char *nmz_base) {
  char *query;
  char  nmz_history[BUF_LEN];

  snprintf(nmz_history, sizeof(nmz_history), "%s/history", nmz_base); 
  using_history();
  read_history(nmz_history);
  
  query = readline("Query: ");
  
  if (query != NULL) {
    add_history(query);
    write_history(nmz_history);
    history_truncate_file(nmz_history, 50);
  }
  
  return query;
}

int 
remove_links(char *dir) {
  DIR *dirp;
  struct dirent *dp;
  struct stat stat_buf;
  int retval = 0;
  char buf[BUF_LEN];
  
  dirp = opendir(dir);
  
  if (!dirp) {
    if (errno == ENOENT) {
      return 0;
    } else {
      perror("opendir");
      return 1;
    }
  }
  
  while(dirp) {
    errno = 0;
    if ((dp = readdir(dirp)) != NULL) {
      snprintf(buf, sizeof(buf), "%s/%s", dir, dp->d_name);
      if (lstat(buf, &stat_buf) != 0) {
	perror("lstat");
      } else {
	if ((stat_buf.st_mode&S_IFMT)==S_IFLNK) {
	  unlink(buf);
	} else if ((stat_buf.st_mode&S_IFMT)!=S_IFDIR) {
	  fprintf(stderr, "%s is not a symbolic link; aborting.\n", buf);
	  retval = 1;
	  break;
	}
      }
    } else if (errno != 0) {
      perror("readdir");
      retval = 1;
      break;
    } else {
      break;
    }
  }
  
  closedir(dirp);
  return retval;
}

int 
create_result_dir(char *nmz_result) { 
  char buf[BUF_LEN];
	
  snprintf(buf, sizeof(buf), "%s/cur", nmz_result);
  if (remove_links(buf) != 0) {
    return 1;
  }
  
  mkdir(nmz_result, 0777);
  snprintf(buf, sizeof(buf), "%s/cur", nmz_result);
  mkdir(buf, 0777);
  snprintf(buf, sizeof(buf), "%s/new", nmz_result);
  mkdir(buf, 0777);
  snprintf(buf, sizeof(buf), "%s/tmp", nmz_result);
  mkdir(buf, 0777);
	
  return 0;
}


int 
generate_result(char *query, char *nmz_index, 
		char *nmz_result, int result_limit) {
  char buf[BUF_LEN], buf1[BUF_LEN], result_limit_str[BUF_LEN];
  int  count = 0;
  FILE *fp;
  char *args[32];
  int status, i;
  pid_t pid;

  snprintf(result_limit_str, sizeof(result_limit_str), "%d", result_limit);

  i = 0;
  args[i++] = "namazu";
  args[i++] = "-q";
  args[i++] = "-n";
  args[i++] = result_limit_str;
  args[i++] = "-l";
  args[i++] = "-s";
  args[i++] = query;
  args[i++] = nmz_index;
  args[i++] = NULL;

  fp = pexecvp("namazu", args, &pid, "r");
	
  if (!fp) {
    perror("pexecvp");
    return 0;
  }
  
  while (fgets(buf, sizeof(buf), fp)) {
    int ret;
    char *newl = strchr(buf, (int) '\n');
    if (*newl) {
      *newl = '\0';
    }
    
    snprintf(buf1, sizeof(buf1), "%s/cur/%s", nmz_result, basename(buf));
    
    ret = symlink(buf, buf1);
    if (ret != 0) {
      perror("symlink");
    } else {
      count++;
    }
  }
  
  fclose(fp);
  waitpid(pid, &status, 0); 
  if(WEXITSTATUS(status) == 127) {
    fprintf(stderr, "namazu executable not found.\n");
  }
  
  return count;
}


void 
build_index(char *nmz_index, char *mail_dirs[], int num_mail_dirs) {
  char *args[MAX_MAIL_DIRS + 10];
  int j, i = 0;
  mkdir(nmz_index, 0777);
  args[i++] = "mknmz";
  args[i++] = "-Len_US.ISO8859-1";
  args[i++] = "-O";
  args[i++] = nmz_index;
  args[i++] = "--mailnews";
  args[i++] = "--allow=.*";

  for (j = 0; j<num_mail_dirs && i<MAX_MAIL_DIRS+10; j++) {
    args[i++] = mail_dirs[j];
  }

  args[i] = NULL;
  
  execvp("mknmz", args);
  perror("execvp");
}

void 
usage() {
  fprintf(stderr,
	  "nmzmail version %s\n"
	  "usage: nmzmail [-b <base>] [-r <result>] -i <maildirs> |\n"
	  "               [-b <base>] [-r <result>] [-n <limit>]\n"
	  , VERSION);
}


syntax highlighted by Code2HTML, v. 0.9.1