/*
** 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 = "@(#)nntpart.c	2.3 4/15/92";
#endif

/*LINTLIBRARY*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <nntp.h>
#include "cfg.h"

#define TMPDIR "/usr/tmp"

char *nntp_server;

int     server_init();
void    put_server();
int     get_server();
void    close_server();

int atoi();
int fputs();

extern int verbose;

/*
 *
 * First digit:
 *
 *	1xx	Informative message
 *	2xx	Command ok
 *	3xx	Command ok so far, continue
 *	4xx	Command was correct, but couldn't be performed
 *		for some specified reason.
 *	5xx	Command unimplemented, incorrect, or a
 *		program error has occured.
 *
 * Second digit:
 *
 *	x0x	Connection, setup, miscellaneous
 *	x1x	Newsgroup selection
 *	x2x	Article selection
 *	x3x	Distribution
 *	x4x	Posting
 */

struct nntp_resp {
    int     resp;
    char    *msg;
};

struct nntp_resp resps[] = {
{	INF_HELP,	"Help text on way"			},
{	INF_DEBUG,	"Debug output"				},
{	OK_CANPOST,	"Hello; you can post"			},
{	OK_NOPOST,	"Hello; you can't post"			},
{	OK_SLAVE,	"Slave status noted"			},
{	OK_GOODBYE,	"Closing connection"			},
{	OK_GROUP,	"Group selected"			},
{	OK_GROUPS,	"Newsgroups follow"			},
{	OK_ARTICLE,	"Article (head & body) follows"		},
{	OK_HEAD,	"Head follows"				},
{	OK_BODY,	"Body follows"				},
{	OK_NOTEXT,	"No text sent -- stat, next, last"	},
{	OK_NEWNEWS,	"New articles by message-id follow"	},
{	OK_NEWGROUPS,	"New newsgroups follow"			},
{	OK_XFERED,	"Article transferred successfully"	},
{	OK_POSTED,	"Article posted successfully"		},
{	CONT_XFER,	"Continue to send article"		},
{	CONT_POST,	"Continue to post article"		},
{	ERR_GOODBYE,	"Have to hang up for some reason"	},
{	ERR_NOGROUP,	"No such newsgroup"			},
{	ERR_NCING,	"Not currently in newsgroup"		},
{	ERR_NOCRNT,	"No current article selected"		},
{	ERR_NONEXT,	"No next article in this group"		},
{	ERR_NOPREV,	"No previous article in this group"	},
{	ERR_NOARTIG,	"No such article in this group"		},
{	ERR_NOART,	"No such article at all"		},
{	ERR_GOTIT,	"Already got that article, don't send"	},
{	ERR_XFERFAIL,	"Transfer failed"			},
{	ERR_XFERRJCT,	"Article rejected, don't resend"	},
{	ERR_NOPOST,	"Posting not allowed"			},
{	ERR_POSTFAIL,	"Posting failed"			},
{	ERR_COMMAND,	"Command not recognized"		},
{	ERR_CMDSYN,	"Command syntax error"			},
{	ERR_ACCESS,	"Access to server denied"		},
{	ERR_FAULT,	"Program fault, command not performed"	},
{	-1,	        NULL					},
};

char *get_nntpstr(resp_line,number)
    char *resp_line;
    int *number;
 {
    struct nntp_resp *ct;

    *number = atoi(resp_line);

    ct = &resps[0];
    while ((ct->resp) != -1) {
        if (*number == ct->resp)
            return(ct->msg);
        ct++;
    }
    return(NULL);
}

void print_server_response(line)
char *line;
{
	int rrc;
	static char *str;

        /*
        ** Verify the first character as a valid response code.
        */
        if ((*line != CHAR_INF) && (*line != CHAR_OK) 
            && (*line != CHAR_CONT) && (*line != CHAR_ERR)
            && (*line != CHAR_FATAL))  {
            (void) fprintf(logfp,"[%s]: Xxx : unknown response\n",line);
            return;
        }

        /*
        ** Verify the last two characters are 
        ** within range of valid responses.
        */
        
        if ((*(line+1) < '0') || (*(line+1) > '9')) {
            (void) fprintf(logfp,"[%s]: xXx : unknown response\n",line);
            return;
        }
        if ((*(line+2) < '0') || (*(line+2) > '9')) {
            (void) fprintf(logfp,"[%s]: xxX : unknown response\n",line);
            return;
        }

        if ((str = get_nntpstr(line,&rrc)) != NULL) 
            (void) fprintf(logfp,"%d: %s\n", rrc, str);
        else
            (void) fprintf(logfp,"%d: unknown response\n", rrc);

        /* If the response in within a range (190-199) it is not handled.. */
        /* fix later, I am too lazy now....*/
        return;
}

/*
** nntp_tmp_path[]
**
** Holds the full pathname of the nntp transfer file.
** For use with external command archiving...
*/

char nntp_tmp_path[MAXNAMLEN];   

int nntp_retrieve_article(filename,which_time)
char *filename;
int which_time;
{
     int sscanf();
     int fclose();
     int chdir();

     char buf[256];
     char ser_line[512];
     int  response;
     int  rc;               /* response code */
     FILE *tfp;             /* transfer file pointer */ 
     static int n;          /* extimated number of articles */
     static int f;          /* first article number */
     static int l;          /* last article number */
   
     if (which_time == 1) {
         if (chdir(TMPDIR) != 0) {
             (void) fprintf(errfp,"can't cd to %s.\n",TMPDIR);
             return(ERROR_ENCOUNTERED);
         }

         /* 
         ** Need to establish the connection with the nntp_server.
         */

         if ((response = server_init(nntp_server)) < 0) {
             (void) fprintf(errfp,"can't connect to %s.\n",nntp_server);
             return(ERROR_ENCOUNTERED);
         }

         /* 
         ** Assure that the connection succeeded...
         */

         if (response == ERR_ACCESS) {
             (void) fprintf(errfp,
                       "Connection permission to the %s news server denied.\n",
                       nntp_server);
             return(ERROR_ENCOUNTERED);
         }
         else if ((response != OK_NOPOST) && (response != OK_CANPOST)) {
             (void) fprintf(errfp,
                       "Unexpected response code from %s news server: %d\n",
                       nntp_server, response);
             return(ERROR_ENCOUNTERED);
         }

         /* 
         ** Need to tell the server which newsgroup to process.
         */

         (void) sprintf(buf,"GROUP %s", newsgrp->ng_name);
         put_server(buf);    /* tell server we want to select the group */

         if (get_server(ser_line, sizeof(ser_line)) < 0) {
             (void) fprintf(errfp,
               "Unexpected close of %s connection\n", nntp_server);
             return(ERROR_ENCOUNTERED);
         }

         if (*ser_line != CHAR_OK) {      /* and then see if that's ok */
             print_server_response(ser_line);
             return(ERROR_ENCOUNTERED);
         }

         /* 
         ** Get the newsgroup article information from the returned buffer 
         ** 
         ** rc    = response code (211 or 411)
         **  n    = estimated number of articles in group,
         **  f    = first article number in the group,
         **  l    = last article number in the group,
         **  smsg = name of the group.)
         */

         (void) sscanf(ser_line,"%d%d%d%d%s",  &rc, &n, &f, &l, buf);
         if (verbose) {
             print_server_response(ser_line);
     	     (void) fprintf(logfp,"Newsgroup\t%s\n",buf);
     	     (void) fprintf(logfp,"First\t%d\tLast \t%d\n",f,l);
     	     (void) fprintf(logfp,"Est. No. Articles\t%d\n",n);
         }
     }
        
     while (f <= l) {
        /* 
        ** Store the article number as the file name for the
        ** temporary file transfer. This is mainly to support
        ** the Article-Number form of archiving.
        */
        (void) sprintf(filename,"%d",f);
        (void) sprintf(nntp_tmp_path,"%s/%d",TMPDIR,f);

        /* 
        ** Build the nntp command string 
        ** designating which article to transfer.
        */
        (void) sprintf(buf,"ARTICLE %ld", f);
        put_server(buf);    /* tell server we want the article */
        (void) get_server(ser_line, sizeof(ser_line));
        if (verbose)
 	   (void) fprintf(logfp,"Retrieving <%d> from %s\n",f, nntp_server);
        ++f;
        if (*ser_line != CHAR_OK) {      /* and then see if that's ok */
            if ((rc = atoi(ser_line)) != ERR_NOART && rc != ERR_NOARTIG) {
               if (verbose)
                  print_server_response(ser_line);
            }
            continue;
        }

        /* 
        ** Here we have a valid article. Create a temporary file
        ** to transfer the article from the nntp server to the
        ** local system into.
        */
        if ((tfp = fopen(filename, "w+")) == NULL)
             return(ERROR_ENCOUNTERED);

        /* 
        ** Read a line from the server and write it out to
        ** the file to be used for archiving. This file is
        ** removed when it is no longer needed.
        */
        while (get_server(ser_line, sizeof(ser_line)) >= 0) {  /* while */
            if (ser_line[0] == '.' && ser_line[1] == '\0')  /* valid input */
                break;                          /* get it and write it  */
          /* 
            ** If the text contained a period as the first character of the 
            ** text line in the original, that first period is doubled.  
            ** Therefore, the client must examine the first character of 
            ** each line received, and for those beginning with a period, 
            ** determine either that this is the end of the text or whether 
            ** to collapse the doubled period to a single one.
            */
 
            if (ser_line[0] == '.')
                (void) fputs(ser_line+1, tfp);  /* doubled '.'  - collapse */
            else
                (void) fputs(ser_line, tfp);    /* general textual input   */
            (void) fputs("\n", tfp);
        }
        (void) fclose(tfp);
        return(RETRIEVED);
     }
     close_server();
     return(DONE);
}
