/*
** This software is Copyright (c) 1989, 1990, 1991 by Kent Landfield.
**
** Permission is hereby granted to copy, distribute or otherwise
** use any part of this package as long as you do not try to make
** money from it or pretend that you wrote it.  This copyright
** notice must be maintained in any copy made.
**
*/

#if !defined(lint) && !defined(SABER)
static char SID[] = "@(#)retrieve.c	2.2 5/9/91";
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include "rkive.h"

#define TMPDIR "/tmp"

char newsgroup_directory[MAXNAMLEN];

extern FILE *inputfp;              
extern char *batch_file;

extern FILE *errfp;                /* standard error file pointer     */
extern struct group_archive *newsgrp;
extern struct stat sbuf;
extern char spooldir[];
extern int retrieve;
extern int test;

int valid_disk_article(fullname,fl)
char *fullname;
char *fl;
{
    int stat();
    /*
    ** Assure that the file is in place 
    */

    if (stat(fl, &sbuf) != 0)  {
        (void) fprintf(errfp,"can't stat %s - SKIPPING\n",fullname);
        return(0);
    }

    /*
    ** If its not a regular file, we can't archive it.
    */

    else if ((sbuf.st_mode & S_IFMT) != S_IFREG)
        return(0);
    
    /* Check to assure that the file has a size greater that 0 */
    /* Maybe I'm nuts but I don't see any reason to archive    */
    /* files unless they contain something.. :-)               */
       
    else if (sbuf.st_size == 0) {
        (void) fprintf(errfp, "%s is a Zero length file - SKIPPING\n",fullname);
        return(0);
    }
    return(1);
}

/*
** retrieve_article()
**
** The purpose of this function is to return the name of a file on disk
** that contains a news article. It does not care if the the article has
** or has not been archived at this point. There are currently four ways
** to retrieve an article:
**	1. Retrieve an article from a remote site via NNTP,
**	2. Search the newsgroup directory for newsarticles,
**	3. Read an article from standard input, 
**	4. Receive a newsarticle filename on standard input,
**	5. Receive newsarticle filenames from a batch file.
*/

int retrieve_article(filename,which_time)
char *filename;
int which_time;
{
    int chdir();
    int strcmp();
    int strlen();
    int unlink();
    int fclose();
    int creat();
    char *strcpy();

    FILE *efopen();
#ifdef NNTP
    int nntp_retrieve_article();
#endif /*NNTP*/

    char *rp;
    static struct dirent *dp;
    static DIR *dfd;
    static char *dir = ".";
    char ibuf[BUFSIZ];
    int len;
    int tmpfp;


    if (which_time == 1) {
       (void) strcpy(newsgrp->ng_path, newsgrp->ng_name);
       rp = newsgrp->ng_path; /* convert newsgroup name into a disk path */
    
        /*
        ** convert all '.' to '/' to generate a path to the
        ** newsgroup directory relative from the specified SPOOLDIR.
        */
    
        while (*rp) {             /* convert all */
            if (*rp == '.')       /* '.'s to '/' */
                *rp = '/';        /* to create   */
            rp++;                 /* the disk    */
        }                         /* location    */
    }

#ifdef NNTP
    if (retrieve == FROM_NNTP) 
         return(nntp_retrieve_article(filename,which_time));
#endif /*NNTP*/

    if (which_time == 1) {
        (void) sprintf(newsgroup_directory,"%s/%s", spooldir,newsgrp->ng_path);
    
        if (chdir(newsgroup_directory) != 0) {
            (void) fprintf(errfp,"change directory to %s failed, %s not archived\n",
                                  newsgroup_directory, newsgrp->ng_path);
            return(ERROR_ENCOUNTERED);
        }
    }

    if (retrieve == FROM_DISK) {
        /*
        ** locate a file that needs to be archived. This is done by
        ** a linear search of the directory with a linear search of
        ** of the contents of the .archived file. If the file is not
        ** specified in the .archived file, it has not been archived
        ** before and we can proceed with the archiving.
        */
        if (which_time == 1) {
            if ((dfd = opendir(dir)) == NULL) {
                (void) fprintf(errfp, "can't open %s\n", newsgroup_directory);
                return(ERROR_ENCOUNTERED);
            }
        }
    
        while ((dp = readdir(dfd)) != NULL) {
           if (strcmp(dp->d_name,".") == 0 || strcmp(dp->d_name,"..") == 0)
               continue;
    
           (void) sprintf(ibuf,"%s/%s", newsgroup_directory,dp->d_name);
           /*
           ** Check to assure the file is available and contains
           ** some data...
           */
           if (!valid_disk_article(ibuf,dp->d_name)) 
               continue;

            (void) strcpy(filename,dp->d_name);
            return(RETRIEVED);
        }
    
        /* 
        ** done reading the directory...
        */
        (void) closedir(dfd);
        return(DONE);
    }

    /*
    ** FROM_STDIN archiving.
    **
    ** First create a temp file name and write the information into
    ** the temp file. Write the data passed on stdin into the temp file.
    ** Then pass the temp file name back to rkive to use from then on.
    */

    if (retrieve == FROM_STDIN) {
        if ((rp = tempnam(TMPDIR, "rkiveXXXXXX")) == NULL) {
            (void) fprintf(errfp, "Can't create tmpfile name\n");
            return(ERROR_ENCOUNTERED);
        }

        if ((tmpfp = creat(rp, 0644)) == NULL) {
            (void) fprintf(errfp, "Can't create tmpfile\n");
            return(ERROR_ENCOUNTERED);
        }

        len = -1;

        while (fgets(ibuf, BUFSIZ, inputfp) != NULL) {
             len = strlen(ibuf);
             if (write(tmpfp, ibuf, len) != len) 
                 perror("write");
        }
        (void) close(tmpfp);

        /*
        ** If len was never assigned then stdin was closed.
        ** and no reason at all to go any further, we are
        ** done. Return so...
        */
        if (len == -1) {
            /* 
            ** no more filenames on inputfp...
            */

            (void) unlink(rp);
            return(DONE);
        }

        /*
        ** Check to assure the file is available and contains
        ** some data...
        */
        if (!valid_disk_article(rp,rp)) {
            return(ERROR_ENCOUNTERED);
        }

        /*
        ** We have real data here...
        */
        (void) strcpy(filename,rp);
        free(rp);
        return(RETRIEVED);
    }

    /*
    ** The following code is for retrieval types FROM_NAME and FROM_BATCHFILE
    ** only. Any other type is an unknown software error ...
    */
    if (retrieve != FROM_NAME && retrieve != FROM_BATCHFILE) {
        (void) fprintf(errfp, "Invalid retrieval type encountered - %d\n",
                       retrieve);
        return(ERROR_ENCOUNTERED);
    }

    /* 
    ** If the user specified that a batchfile is to be used,
    ** open the batchfile up so that the article names to 
    ** archive can be read. Unlink it so that it does not
    ** get in the way of other incoming articles. If the
    ** batchfile cannot be unlinked, warn the user but
    ** continue archiving. This is a non-fatal condition 
    ** since we can determine if the article has been 
    ** archived previously via the .archived file.
    */

    if (retrieve == FROM_BATCHFILE) {
        if (which_time == 1) {
            inputfp = efopen(batch_file,"r");
            if (!test) {
                if (unlink(batch_file) == -1) {
                    (void) fprintf(errfp, 
                          "Unable to unlink batchfile %s, continuing\n",
                           batch_file);
                }
            }
        }
    }
       
    /*
    ** Now retrieve the article to be archived from
    ** the inputfp which could either be stdin or
    ** the batchfile depending on what the user
    ** specified on the command line.
    */

    while (fgets(ibuf,sizeof ibuf,inputfp) != NULL) {
        ibuf[strlen(ibuf) -1] = '\0';

        /*
        ** Check to assure the file is available and contains
        ** some data...
        */
        if (!valid_disk_article(ibuf,ibuf))
            continue;

        (void) strcpy(filename,ibuf);
        return(RETRIEVED);
    }

    /* 
    ** no more filenames on inputfp...
    */

    if (retrieve == FROM_BATCHFILE) {
        (void) fclose(inputfp);
        inputfp = stdin;
    }
    return(DONE);
}
