/*
 * techrep.c SUIT based utility to adminster a techreport archive
 * 
 * First version by Jerome Terry - May 92
 * 
 * Mods and bug fixes: 
 *   Removal of listrefs system call: 
 *       Mid October 92 - Dallas Wrege and Tongtong Zhang 
 *   Various permission problems:  
 *       22 Oct 92 - CLV 
 *   Bug in abstract handling   :  
 *       13 Nov 92 - CLV 
 *   More permission problems   :  
 *       13 Nov 92 - CLV
 *   Split into modules         :
 *       5 Jan 93 - CLV
 *       Note: I have made an attempt to split techrep.c into separate
 *             files that make some sort of sense, and to call these files
 *             modules. However, there is still a fair amount of depend-
 *             ence between modules.
 *   Upgrade to SUIT v 2.3
 *       March 93 - Dennis Cosgrove with some help from CLV.
 *
 *   New look.
 *   Copy utility.
 *   Multiple document types for posting, viewing, printing.
 *   Robust remote by negotiating with ftp server, rather than pipes to
 *     ftp client.
 *   Simple WAIS interface to WATERS.
 *   Search Capability.
 *       April/May 1993 - CLV.
 *
 *   Computing Categories and keywords
 *       July 1993 - CLV
 *
 *   Added translation routines using Mapfile instead of dir contents.
 *           (see xlate.c&h, maplist.c&h)
 *
 *   Added subdirectories for posting (see below and post.c).
 *       October 1993 - CLV
 *
 *   - Changed abstract checking from use of 'file' command
 *     to a simple check for legal ASCII characters. (see post.c & sitespec.c)
 *   - Deleted blank lines from abstract. (see post.c)
 *       November 1993 CLV
 
 *   Took SUIT out and implemented a command line interaction
 *   - All browser functionality gutted (WWW browsers do better)
 *   - Command line interface only
 *       November 1994 - Jon Gabel
 *   Various code clean-up
 *       September 1995 - CLV    
 *       
 */
#include <pwd.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include "techrep.h"
#include "util.h"
#include "com-util.h"
#include "citation.h"
#include "make_readme.h"
#include "sitespec.h"


#define N_ARGS 10    /* maximum number of args to exec'ed process */


void	initMisc 	(int argc, char **argv);
void    delete_cit	(char *trNumToDelete);
void  	read_cit	();
void	no_citation_database();
char   *findTechnicalReport (char *trId);
int     handle_post	(CitationPtr newCit, char *trLocation);
int     handle_get	(char *temp_filename);
int     handle_update	(CitationPtr newCit, char *trLocation);
int     handle_delete	(CitationPtr newCit);
int 	handle_get_all	(char *temp_filename);
int 	handle_bulk_load();
void    error_log	(char *errormessage);
CitationPtr   	lookup_trnum	(char *trId);
CitationPtr   	verifyArgs (char *filename, char *subDir);
void 	usage		();

/************************************************************************
 *  External Functions...				                *
 ************************************************************************/


void 
main(int argc, char *argv[], char *envp)
{
   CitationPtr newCit; 
    
   initEnvironment();     /* reads all site specific env variables */
   
   initMisc (argc, argv);

   if (argc < 2) {
      usage();
      error_log("bad command line");
      exit(BAD_CMD_LINE);
   }

   if (strcmp (argv[1], "-b") != 0) {
      newCit = verifyArgs (argv[2], argv[3]);
      if (!newCit) {
         error_log ("Citation file or TR file not found or unreadable");
         exit (DOC_DOES_NOT_EXIST);
      }
   }
   
   if (argv[1][1] == 'p') {
      handle_post(newCit, argv[3]);
   }  else if (argv[1][1] == 'g') {
      handle_get(argv[2]);
   } else if (argv[1][1] == 'u') {
      handle_update(newCit, argv[3]);
   } else if (argv[1][1] == 'd') {
      handle_delete(newCit);
   } else if (argv[1][1] == 'b') {
      handle_bulk_load();
   } else if (argv[1][1] == 'a') {
      handle_get_all(argv[2]);
   } else {
      usage();
      error_log("bad first argument");
      exit(BAD_CMD_LINE);
   }
}


void
initMisc (int argc, char **argv)
{

   /* saves big trouble later */
   umask(022);
}


int  handle_get_all(char *temp_filename)
{  
     fileCopy (temp_filename, getCitationDataFilePath(), 0644);
}

int  handle_bulk_load()
{

   char  buf[STRING_SIZE];
   CitationPtr C;
   FILE *citation_fp;

   /* open for reading */ 
   if ((citation_fp = fopen(getCitationDataFilePath(), "r")) == NULL) {
      no_citation_database();
      error_log( "get: no cit-dbase so TR not found");
      exit(DOC_DOES_NOT_EXIST);
   }

   while ((C = read_one_citation(citation_fp)) != NULL) {
      if (!C->trId) {
         fprintf (stderr, "Problem with Bulk Load - No report number\n");
         exit (1);
      }
      if (!C->title) {
         fprintf (stderr, "Problem with Bulk Load - No title\n");
         exit (1);
      }
      if (!C->author) {
         fprintf (stderr, "Problem with Bulk Load - No author\n");
         exit (1);
      }
      if (!C->date) {
         fprintf (stderr, "Problem with Bulk Load - No date\n");
         exit (1);
      }

      if (!C->modified) {
         C->modified = rfc1123date();
      }
      write_one_citation(stdout, C);
   }
   fclose (citation_fp);
   update_readme();
}

/* Note: trLocation is a subdirectory relative to the reports directory.
         It should be NULL if the TR is placed at top level.
*/
int  
handle_post (CitationPtr newCit, char *trLoc)
{
   int             answer, c, is_doc,i,is_compressed, in_url_line;
   FILE            *tmp_cit_fp, *cit_dbase_fp;
   CitationPtr     tr_exists;
   char            *trId, fname[STRING_SIZE], url[STRING_SIZE];
   char	    copy_filename[STRING_SIZE];
   char            suffix[STRING_SIZE], command[STRING_SIZE];
   char            newDocFileName[STRING_SIZE], docFileName[STRING_SIZE];
   char            *fextention,*fnameonly,*all_extentions;
   char	    trLocation[STRING_SIZE];

    
   /* makes trLocation a null string if it is a null pointer */
   if (!trLoc) {
      strcpy(trLocation, "");
   }
   else {
      strcpy(trLocation, trLoc);

      /* otherwise, makes sure trLocation ends in a slash */
      if (trLocation[strlen(trLocation)-1] != '/') {
         strcat (trLocation, "/");
      }
   }

   trId=getTrId(newCit);

   if (get_semaphore(getSemaphoreFilePath()) == ERROR) {
      error_log("You have been denied exclusive access to the citation data base.  Please try your operation again.\n");
      exit(ACCESS_DENIED);
   }

   tr_exists=lookup_trnum(trId);

   if (tr_exists) {
      free (tr_exists);
      error_log("TR already exists\n");
      fprintf (stderr, "%s already exists so cannot be post-ed. Try update.\n", trId);
      release_semaphore(getSemaphoreFilePath());
      exit(DOC_EXISTS);   
   }

   /*
    * Build filename for Citation database
    */
   strcpy(fname, getCitationDataFilePath());

   if ((cit_dbase_fp = fopen(fname, "a")) == NULL) {   /* open file */
      release_semaphore(getSemaphoreFilePath());
      error_log("no citation database creating one...");
      no_citation_database();
   }

   /* 
    * if copying file create url and add to cit dbase
    */
   if (newCit->url) {
      strcpy (copy_filename, newCit->url);
      fextention = strrchr(copy_filename,'.');

      fnameonly = strrchr(copy_filename,'/');
      if (fnameonly ==NULL) {
         fnameonly=copy_filename;
      }
      else {
         fnameonly++;  /* gets rid of slash, don't have to do this really */
      }
	
      all_extentions = strchr(fnameonly,'.');
      if (all_extentions == NULL) {
         all_extentions = strdup("");
      }
  
      is_compressed=FALSE;

      if (fextention != NULL) {
         if ((strcmp(fextention,".tiff") == 0) || 
             (strcmp(fextention,".TIFF") == 0) ||
             (strcmp(fextention,".Z") == 0) ||
             (strcmp(fextention,".z") == 0) ||
             (strcmp(fextention,".gz") == 0) ||
             (strcmp(fextention,".GZ") == 0) ) {

            is_compressed=TRUE; 

         }
      }

      /*
       * Compress and move file to reports directory
       */
      sprintf(newDocFileName, "%s", getReportDirectoryPath());
      strcat(newDocFileName, trLocation); 
	
      strcat(newDocFileName, trId);
      strcat(newDocFileName, all_extentions);
  
      if( fileCopy(newDocFileName, copy_filename, 0644) == -1 ) {
         release_semaphore(getSemaphoreFilePath());
         error_log("Unable to copy and compress file");
         exit( FILE_NOT_COPIED );
      }
	
      if (is_compressed==FALSE) {  /* compress if not already */
         sprintf(command, "%s -f %s", getCompressPath(), newDocFileName);
         system(command);
	   
         /* this assumes compression will add a .Z */
         sprintf(url, "%s%s%s%s.Z", getUrlPrefix(), trLocation, trId, all_extentions);
      } else {
         sprintf(url, "%s%s%s%s", getUrlPrefix(), trLocation, trId, all_extentions); 
      }
      newCit->url = strdup(url);
   }

   newCit->modified = rfc1123date();
   write_one_citation (cit_dbase_fp, newCit);
   freeCitation(newCit);
   fclose(cit_dbase_fp);

   release_semaphore(getSemaphoreFilePath());

   /* 
    * Update the Index file in the reports directory.
    */
   if ((answer = update_readme()) == NO_README) {
      error_log("Could not open README file. This is normal if no documents have been posted or the README file has been deleted.");
   } else if (answer == NO_TMP_README) {
      error_log("Could not open temporary README file.");
   }

   free(trLocation);
}

int  handle_get(char *temp_filename)
{

    FILE            *temp_fp, *citation_fp;
    CitationPtr     Cit,C;
    char            *trId, c;
    int             tr_exists, error;
    long            begin_cit, end_cit;

     /* open temp_filename file */      
    temp_fp = fopen(temp_filename, "r");
    Cit = read_one_citation(temp_fp);
    fclose(temp_fp);
    trId=getTrId(Cit);

    if (get_semaphore(getSemaphoreFilePath()) == ERROR) {
        error_log("You have been denied exclusive access to the citation data base.  Please try your operation again.\n");
        exit(ACCESS_DENIED);
    }
 
    /* open citation file */
    if ((citation_fp = fopen(getCitationDataFilePath(), "r")) == NULL) {
        no_citation_database();
        error_log( "get: no cit-dbase so TR not found");
        release_semaphore(getSemaphoreFilePath());
	exit(DOC_DOES_NOT_EXIST);
    }

    while ((C = read_one_citation(citation_fp)) != NULL) {
        

	    /* copy the citation to the tempfile */
       if (strcmp(trId, getTrId(C)) == 0) {

	  temp_fp = fopen(temp_filename, "w");
	  
	  /* write cit-data to temp file */
	  write_one_citation (temp_fp, C);
	  fclose(citation_fp);
	  fclose(temp_fp);
	  release_semaphore(getSemaphoreFilePath());
	  freeCitation (C);
	  return (0);
       }
       freeCitation (C);
    }

    fclose(citation_fp); 
    error_log("TR doesn't exist\n");
    release_semaphore(getSemaphoreFilePath());
    exit(DOC_DOES_NOT_EXIST); 
}

int handle_update (CitationPtr newCit, char *trLocation) 
{ 
   int retval;

   retval = handle_delete(newCit);
   if (retval != DOC_DOES_NOT_EXIST) {
      handle_post(newCit, trLocation); 
   }
}

int handle_delete(CitationPtr newCit)
{ 
   int answer, result; 
   char *trId, *url, *newUrl, *trLocation;
   FILE *citation_fp; 
   CitationPtr Cit, tr_exists;
   char *StandardUrl;
   char fullname[STRING_SIZE];

   /* Get a valid technical report number */
   trId=getTrId(newCit);

   /* delete citation */ 
   if (get_semaphore(getSemaphoreFilePath()) == ERROR) { 
      error_log("You have been denied exclusive access to the citation data base.  Please try your operation again."); 
      exit(ACCESS_DENIED); 	
   } 
      
   /* open citation file */ 
   if ((citation_fp = fopen(getCitationDataFilePath(), "r")) == NULL) {
      no_citation_database();
      error_log("no cit dbase created one (in delete)"); 
      exit(DOC_DOES_NOT_EXIST); 
   }


   /* Search for TR number */ 
   tr_exists=NULL;
   while ((Cit = read_one_citation(citation_fp)) != NULL) { 
      /* check to see if correct technical report */ 
      if (strcmp(trId, getTrId(Cit)) == 0) {
         tr_exists = Cit;
         break; 
      }
   }

   fclose(citation_fp); 
   if (!tr_exists) { 
      error_log("TR doesn't exist\n"); 
      release_semaphore(getSemaphoreFilePath());
      fprintf (stderr, "TR %s does not exist so cannot be deleted\n", trId);
      return(DOC_DOES_NOT_EXIST); 
   }
      
   /* delete the file if it exists */ 
   url = Cit->url;
   if (url != NULL) {
      StandardUrl = strdup(getUrlPrefix());
      if (strncmp(StandardUrl,url,strlen(StandardUrl)) == 0) {
         trLocation = url+strlen(StandardUrl);
         strcpy (fullname,getReportDirectoryPath()); 
         strcat(fullname,trLocation);
         unlink(fullname);
      }
   }
  
   /* remove citation from bib file */
   delete_cit(trId);
      
   release_semaphore(getSemaphoreFilePath());

   /* update index file */
   if((result = update_readme()) == NO_README) {
      error_log("Could not open README file. This is normal if no documents have been posted or the README file has been deleted.");
   } else if (result == NO_TMP_README) {
      error_log("Could not open temporary README file.");
   }
}

/*
 * Checks to see if the requested trnum is there.
 */
CitationPtr
lookup_trnum(char *trId)
{
    FILE           *citation_fp;
    CitationPtr     C;

 
    /* open citation file */
    if ((citation_fp = fopen(getCitationDataFilePath(), "r")) == NULL) {
        no_citation_database();
        return(FALSE);
    }
    /*
     * Search for TR number
     */
    while ((C = read_one_citation(citation_fp)) != NULL) {

          /* check to see if correct technical report */
        if (strcmp(trId, getTrId(C)) == 0) {
            fclose(citation_fp);
            return (C);
        }

        freeCitation (C);
     }
    fclose(citation_fp);
    return (NULL);
}

void 
delete_cit(char *trId)
{
    FILE           *cit_dbase_fp;
    FILE           *new_dbase_fp;
    char            citFileName[STRING_SIZE];
    char            tmpCitFileName[STRING_SIZE];
    CitationPtr	    C;

    sprintf(tmpCitFileName, "/tmp/%d-tmp-cit-dbase", getpid());
    if ((new_dbase_fp = fopen(tmpCitFileName, "w")) == NULL) {
       error_log("Can't open tmp citation DB");
       return;
    }

    strcpy(citFileName, getCitationDataFilePath());
    if ((cit_dbase_fp = fopen(citFileName, "r")) == NULL) {
       error_log("Can't open citation DB");
       return;
    }

/*    printf ("Reading ...,"); fflush (stdout); */
    while (C = read_one_citation(cit_dbase_fp)) {
/*       printf ("Read %s,", getTrId(C)); fflush (stdout); */
       if (strcmp (getTrId(C), trId)) {
	  write_one_citation(new_dbase_fp, C);
/*	  printf ("wrote %s\n", getTrId(C)); fflush (stdout); */
       }
    }	
    fclose (new_dbase_fp);
    fclose(cit_dbase_fp);

    fileCopy(citFileName, tmpCitFileName, 0644);
    unlink (tmpCitFileName);
    return;
}

void 
no_citation_database()
{

    int             f1;

    if ((f1 = creat(getCitationDataFilePath(), 0664)) == -1) 
      	error_log( "techrep:can`t create cit dbase\n");
    close(f1);
    return;

}

void error_log(char *errormessage)
{
    FILE *fp;
    char buf[1024];
    time_t the_time;

/*    fprintf(stderr,"%s\n", errormessage);*/
    the_time = time(0);

    strcpy(buf, ctime(&the_time));
   
    fp = fopen(getErrorLogFile(),"a");
 
    fprintf(fp,"\n----------------------------------\nCurrent time: %s",buf);
    fprintf(fp,"%s\n",errormessage);
    fclose(fp);

}

CitationPtr
verifyArgs(char *filename, char *subDir)
{
   CitationPtr C;
   FILE *fp;
   char trLocation[STRING_SIZE];
   struct stat sbuf;
 
   /* Is the file there? */
   if ((fp = fopen(filename, "r")) == NULL) {
      return NULL;
   }

   /* Check to make sure there is a citation there */
   C = read_one_citation(fp);
   if (!C) {
      close (fp);
      return NULL;
   }
   close(fp);

   /* check url to make sure it's readable */  
   if (C->url) {
      
/*      printf ("%s\n", C->url); */
      C->url = tilde_sub(C->url);
/*      printf ("%s\n", C->url); */
      if ((fp = fopen(C->url, "r")) == NULL) {
         fprintf (stderr, "The TR file does not exist or is unreadable\n");
         return NULL;
      }
      fclose (fp);
   }

   /* Finally, make sure the subdirectory exists */
   if (subDir) {
      strcpy (trLocation, getReportDirectoryPath());
      strcat (trLocation, subDir);
      if (stat(trLocation, &sbuf) == -1) {
         fprintf (stderr, "%s does not exist. You need to create it.\n", trLocation);
         return NULL;
      }
   }
   return C;
}

void
usage()
{

      fprintf(stderr, "Usage: techrep [-p|-g|-u|-d|-b] temp_filename [tr_location]\n");
      fprintf(stderr, "\n");
      fprintf(stderr, "'temp_filename' is a file that contains all of the citation \n");
      fprintf(stderr, "information in it. This file is in refer format. For post \n");
      fprintf(stderr, "and update, a minimal file should contain Author (%%A), \n");
      fprintf(stderr, "Report ID (%%R), Title (%%T), Date (%%D), and the full path\n");
      fprintf(stderr, "to the technical report (%%U). Omitting %%U means that only a\n");
      fprintf(stderr, "citation for the report will be available. Optional fields \n");
      fprintf(stderr, "are abstract (%%X), key words (%%K), and computing reviews \n");
      fprintf(stderr, "categories (%%Y)\n");
      fprintf(stderr, "\n");
      fprintf(stderr, "For delete, 'temp_filename' only needs to contain the report ID\n");
      fprintf(stderr, "\n");
      fprintf(stderr, "'tr_location' is a subdirectory relative to the reports\n");
      fprintf(stderr, "directory. Omit if you want the report at the root.\n");
      fprintf(stderr, "The reports directory is located in\n\t%s\nfor this archive.\n",
	              getReportDirectoryPath());
      fprintf(stderr, "\n");
      fprintf(stderr, "The -b option does not require a temp_filename. This option\n");
      fprintf(stderr, "causes techrep to regenerate the README files. As a side effect,\n");
      fprintf(stderr, "the bibliographic file is printed to stdout, with any\n");
      fprintf(stderr, "citations previously without last-modified (%%Z) fields\n");
      fprintf(stderr, "now containing them. The -b option is useful if you are\n");
      fprintf(stderr, "going to add a bunch of citations directly to the biblio \n");
      fprintf(stderr, "file and need the README files regenerated.\n");

}

