/*
 * nntp.c: the protocol workhorse module for newsfetch 
 */  
#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#include "newsfetch.h"

extern int terminate, wait_after_articles, wait_for_time, articles_fetched;
extern int last_than_current, first_article, max_article, news_target;
extern int timeout, article_fetching;
extern char dirname[100], group[100], pipe_command[100];
extern FILE *rcfp, *rctmpfp, *socket_fp[2];

char *header;

#define MAXBUFSIZE 1000
char command_buf[MAXBUFSIZE + 1];

/* lots of protos */
void read_nntp_data(void);
int get_error(char *buf);
int get_error_noprint(char *buf);
int get_error_strmsg(char *buf);
int set_article_number(char *buf);
FILE * get_newsfilefd(void);
int fetch_article(FILE * pipefp);

/*
 * this function is called repeatedly to buffer in news streams 
 */ 
void read_nntp_data() 
{
	alarm(timeout);
	fgets(command_buf, MAXBUFSIZE, socket_fp[1]);
	alarm(0);
} 

/*
 * this is a dummy flush routine - very common 
 */ 
int set_reader_mode() 
{
	read_nntp_data();
	fprintf(socket_fp[0], "MODE READER\n");
	read_nntp_data();
	return (get_error(command_buf));
}

/*
 * does what it says 
 */ 
int get_error(char *buf) 
{
	int result;

	sscanf(buf, "%d", &result);

	if (result >= 200 && result < 300)
		return (1);
	    
	/*
	 * Print error message 
	 */ 
	fprintf(stderr, "%s", buf);
	    
	return (0);
}

int get_error_noprint(char *buf) 
{
	int result;

	sscanf(buf, "%d", &result);

	if (result >= 200 && result < 300)
		return (1);
	    
	return (0);
}

int get_error_strmsg(char *buf) 
{
	int result, space = 0x20;
	char *errMsg;
	    
	sscanf(buf, "%d", &result);
	    
	if (result >= 200 && result < 300)
		return (1);
	    
	errMsg = strchr(buf, space);
	    
	/*
	 * Print error message with a leading space 
	 */ 
	fprintf(stderr, "%s", errMsg);
	    
	return (0);
}

int set_article_number(char *buf) 
{
	int result;
	    
	sscanf(buf, "%d %d", &result, &first_article);
	    
	return (1);
}

FILE * get_newsfilefd() 
{
	char news_filename[200];
	FILE * newsfp;
	    
	if (news_target == 2 || news_target == 3)
		return (stdout);
	    
	if (news_target == 4) {
		newsfp = popen(pipe_command, "w");
		if (newsfp == NULL)
			perror(pipe_command);

		return (newsfp);
	}
	    
	strcpy(news_filename, dirname);
	    
	if (strlen(dirname))
		strcat(news_filename, "/");

	strcat(news_filename, group);
	    
#ifdef DEBUG
	fprintf(stderr, "maildir %s\n", news_filename);
#endif	/*  */
	    
	if ((newsfp = fopen(news_filename, "a+")) == NULL)
		fprintf(stderr, "Can not create news file...aborting\n");
	    
	return (newsfp);
}

int get_next_group() 
{
	char *tmp;
	int items_read, comment = 1;
	    
	max_article = -1;
	    
	while (comment) {
		tmp = fgets(command_buf, MAXBUFSIZE, rcfp);
		if (tmp == NULL)
			return (0);
		
#ifdef DEBUG
	fprintf(stderr, "get_next_group: %s\n", command_buf);
#endif	/*  */
		    
		for (items_read = 0; command_buf[items_read] == 
						0x20; items_read++);
	    
		if (command_buf[items_read] != '#' && 
				command_buf[items_read] != '\n')
			comment = 0;
		else
			fprintf(rctmpfp, "%s", command_buf);
		    
	}
	    
	items_read = sscanf(command_buf, "%s %d %d", 
	group, &first_article, &max_article);
	    
	if (items_read < 2)
		return (0);
	
	return (items_read);
}

int check_group() 
{
int first_art, last_art, total_art, tmp;
	    
fprintf(stderr, "%s: ", group);
fprintf(socket_fp[0], "GROUP %s\n", group);
read_nntp_data();
	    
#ifdef DEBUG
	    fprintf(stderr, "fetch group: %s\n", command_buf);
#endif	/*  */
	    
	if (!get_error_strmsg(command_buf)) {
		first_article--;
		return (0);
	}
	    
	sscanf(command_buf, "%d %d %d %d", 
			&tmp, &total_art, &first_art, &last_art);
	    
	if (first_article > last_art) {
		fprintf(stderr, "No new articles\n");
		first_article = last_art;
	return (0);
	}
	    
	if (first_article < first_art)
		first_article = first_art;
	    
	if (max_article != -1) {
		if ((last_art - first_article) + 1 > max_article)
			first_article = last_art - max_article + 1;
	}
	    
	fprintf(socket_fp[0], "STAT %d\n", first_article);
	read_nntp_data();
	    
	while (!get_error_noprint(command_buf)) {
		first_article++;
		    
		/*
		 * Some news server appear to give the article number  of 
		 * expired articles, check for the last_art 
		 */ 
		if (first_article > last_art) {
			fprintf(stderr, 
				"No new articles: Should not happen\n");
			    
			first_article = last_art;
			return (0);
		}
		    
		fprintf(socket_fp[0], "STAT %d\n", first_article);
		read_nntp_data();
	}
	    
	fprintf(stderr, "articles %d to %d\n", first_article, last_art);
	return (1);
}

int fetch_group() 
{
	FILE * newsfp;
	int tmp = 1;
	    
	if ((newsfp = get_newsfilefd()) == NULL) {
		/*
		 * This is perfect even if article number became invalid
		 * since  in next run ++ operation will make it valid
		 * article and save  STAT time 
		 */ 
		first_article--;
		return (-1);
	}

	/* NOTE: during the debug process it was suggested
	   that i create this double braced assignment     */
	for(; (tmp = fetch_article(newsfp))  && terminate;); 
	    
	first_article = last_than_current;
    
	if (news_target < 3)
		fclose(newsfp);
	    
	if (news_target == 4)
		pclose(newsfp);
	
#ifndef NO_STATUS_METER
	if (isatty(2))
		    fprintf(stderr, "                                             %c", 0xd);
#endif	/*  */

	if (terminate)
		return (1);
	    
	return (-1);
}

int fetch_article(FILE * pipefp) 
{
int check_header = 1;
	/*
	 * Limit is article_fetched and wait_for articles are interger 
	 * In rare case, article fetched can be wrap around      
	 */ 
	if (wait_after_articles && articles_fetched == wait_after_articles) {
		if (isatty(2))
			fprintf(stderr, "Waiting for %d seconds%c", 
				wait_for_time, 0xd);

		articles_fetched = 0;
		sleep(wait_for_time);
		if (isatty(2))
			fprintf(stderr, "                                    %c", 0xd);
	}
	    
	fprintf(socket_fp[0], "ARTICLE\n");
	read_nntp_data();
	    
	if (!get_error(command_buf))
		return (0);
	    
	articles_fetched++;
	    
	if (news_target == 3) {
		/*
		 * forget about old pipefp, make it more simple 
		 */ 
		pipefp = popen(pipe_command, "w");
		    
		if (pipefp == NULL) {
			perror(pipe_command);
			return (-1);
		}
	}
	    
	/*
	 * Make it little fast 
	 */ 
	fprintf(socket_fp[0], "NEXT\n");
	article_fetching = 1;
	    
#ifndef NO_STATUS_METER
	if (isatty(2)) {
		fprintf(stderr, "                                             %c", 0xd);
		fprintf(stderr, "%d%c", first_article, 0xd);
	}
#endif	/*  */
	    
	read_nntp_data();
	    
	/*
	 * Put any date, require by many mail reader 
	 */ 
	fprintf(pipefp, "From localhost Sat Apr 26 18:57:03 WAT 1997\n");
	    
	while (command_buf[0] != '.' || command_buf[1] != 13) {
		if (command_buf[0] == '.' && command_buf[1] == '.')
			command_buf[1] = 0x20;
		    
		if (command_buf[strlen(command_buf) - 2] == 0xd || 
			command_buf[strlen(command_buf) - 2] == 0x0a)
				command_buf[strlen(command_buf) - 2] = '\0';
		
		if (command_buf[strlen(command_buf) - 1] == 0xd || 
			command_buf[strlen(command_buf) - 1] == 0x0a)
				command_buf[strlen(command_buf) - 1] = '\0';
		
		fprintf(pipefp, "%s\n", command_buf);
		
		if (check_header && (strncasecmp(command_buf, 
				"Newsgroups:", 10)) == 0) {
			fprintf(pipefp, "%s: %s\n", 
				NEWSFETCH_HEADER_INCL, group);
			    
			check_header = 0;
			    
		}
		read_nntp_data();
	}
	    
	fprintf(pipefp, "\n");
	    
	if (news_target == 3)
		pclose(pipefp);
	    
	last_than_current = first_article;
	article_fetching = 0;

	if (terminate) {
		read_nntp_data();
		if (!get_error_noprint(command_buf))
			return (0);
	
		set_article_number(command_buf);
	}
    
	return (1);
}

void get_group_list() 
{
	char groupname[100];
	    
	fprintf(stderr, "\nList of NewsGroups:\n");
	fprintf(socket_fp[0], "LIST\n");
	read_nntp_data();
	    
	if (!get_error_strmsg(command_buf))
		exit(1);
	    
	read_nntp_data();
	sscanf(command_buf, "%s", groupname);
	    
	while (command_buf[0] != '.' || command_buf[1] != 13) {
		fprintf(stderr, "%s\n", groupname);
		read_nntp_data();
		sscanf(command_buf, "%s", groupname);
	}
	exit(1);
	    
}

void send_quit() 
{
	fprintf(socket_fp[0], "QUIT\n");
	read_nntp_data();
}

void fill_tmpfile() 
{
	char *tmp;
	    
	while ((tmp = fgets(command_buf, MAXBUFSIZE, rcfp)) != NULL)
		fprintf(rctmpfp, "%s", command_buf);
}




