/* newsfetch.c: driver file for the newsfetch program */

#include <stdio.h>
#include <signal.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 <stdlib.h>
#include <sys/syscall.h>

#include "newsfetch.h"

extern char **environ;

/* global variables */
char copy_cmd[200], dirname[100];
int terminate = 1;
int wait_after_articles = 0, articles_fetched = 0, last_than_current;
int wait_for_time = 0, timeout = READ_TIMEOUT, article_fetching = 0;
int cleanup = 1, max_article, news_target = 0, first_article, only_list = 0;
char group[100], pipe_command[100];
FILE *rcfp, *rctmpfp, *socket_fp[2];
char lockfile[100];

/* private protos */
int exec_groupcmd(char *command, char *group);
void quit_now(int exit_status);
void exit_handler(int sig);
void pipe_handler(int sig);
void check_lockfile(char *homedir);

/* this is the function that attempts to run a command along with newsfetch */
int exec_groupcmd(char *command, char *group)
{
	char tmp_command[100];
	pid_t pid;

	mkcmd(command, COMMAND_GROUP_REPLACE, group, tmp_command);

	pid = fork();
	if (pid < 0) {
		perror("fork Error");
		return -1;
	}
	if (pid == 0) {
		char *argv[4];
		argv[0] = "sh";
		argv[1] = "-c";
		argv[2] = tmp_command;
		argv[3] = 0;
		if ((execve("/bin/sh", argv, environ)) < 0)
			perror("Error Executing Command");
		exit(0);
	}
	return 0;
}

/* start the cleanup and communications quit process */
void quit_now(int exit_status)
{
	fill_tmpfile();
	send_quit(); /* notify the server (see nntp.c) */
	fclose(socket_fp[0]);
	fclose(socket_fp[1]);
	fclose(rcfp);
	fclose(rctmpfp);
	if (cleanup)
		system(copy_cmd);
	else
		fprintf(stderr, "Not cleaning\n");
	exit_now(exit_status);
}

/* let the user know we got it */
void exit_handler(int sig)
{

	if (article_fetching) {
		fprintf(stderr, "termintating signal recieved, ");
		fprintf(stderr, "informed process\n");
		terminate = 0;
	} else
		pipe_handler(SIGINT);

	signal(sig, SIG_DFL);
}

/* perform any additional cleanup for piping to other commands */
void pipe_handler(int sig)
{
	if (sig == SIGALRM)
		fprintf(stderr, "timeout waiting for data\n");
	if (sig == SIGPIPE)
		fprintf(stderr, "broken connection\n");
	if (sig == SIGINT)
		fprintf(stderr, "terminating\n");
	if (group[0] != '\0') {
		fprintf(rctmpfp, "%s %d %d\n", 
			group, last_than_current, max_article);
		fill_tmpfile();
	}
	fclose(rcfp);
	fclose(rctmpfp);
	if (group[0] != '\0' && cleanup)
		system(copy_cmd);
	else
		fprintf(stderr, "Not Updating\n");
	fclose(socket_fp[0]);
	fclose(socket_fp[1]);
	exit_now(1);
}

/* finish the whole cleanup process and exit */
void exit_now(int exit_status)
{
	if (lockfile[0] != '\0')
		unlink(lockfile);
	exit(exit_status);
}

/* general maintenance routines for the local lockfile */
void check_lockfile(char *homedir)
{
	FILE *lockfp;
	int lockpid;

	strcpy(lockfile, homedir);
	strcat(lockfile, "/");
	strcat(lockfile, NEWSFETCHLOCK);

	/*
	 * preliminary lockfile
	 */
	lockfp = fopen(lockfile, "r");
	if (lockfp == NULL) {
		if ((lockfp = fopen(lockfile, "w+")) == NULL) {
			fprintf(stderr, "lockfile creation error\n");
			exit(1);
		}
		fprintf(lockfp, "%d\n", (int) getpid());
		fclose(lockfp);
	} else {
		fscanf(lockfp, "%d", &lockpid);
		fclose(lockfp);
		if (kill(lockpid, SIGUSR1) < 0) {
			fprintf(stderr, "removing old lock file\n");
			if ((lockfp = fopen(lockfile, "w+")) == NULL) {
				fprintf(stderr, "lockfile creation error\n");
				exit(1);
			}
			fprintf(lockfp, "%d\n", (int) getpid());
			fclose(lockfp);
		} else {
			fprintf(stderr, "other %s ", NAME);
			fprintf(stderr, "is running at %d\n",
					lockpid);
			exit(1);
		}
	}

}

/* main */
int main(int argc, char *argv[])
{
	int socket_id, tmp;
	char rcfile[100], execute_command[100], homedir[100];
	char hostname[100]; /* the nntp server hostname */
	int command_flag = 0, pipe_flag = 0, procmailrc = 0;

	if (argc < 2) {
		opt_help(argv[0]);
		exit(1);
	}

	getcwd(dirname, 99);

	/* set the files to nada, zip, zilch */
	rcfile[0] = '\0';
	lockfile[0] = '\0';
	group[0] = '\0';

	gethome(homedir);

	/* an important note here, hostname refers to the nntp server */
	strcpy(hostname, argv[1]);

	/* use opt.c to parse out all of our options */
	get_commandline(argc, argv, dirname, rcfile,
			&cleanup, &wait_after_articles, &wait_for_time,
			&command_flag, execute_command,
			&pipe_flag, pipe_command, &only_list,
			&procmailrc, &timeout);

	if (!only_list) {
		/*
		 * We do not need to do all these things for list only 
		 */
		signal(SIGUSR1, SIG_IGN);
		check_lockfile(homedir);
		/* call util.c for creating default rcfiles ??? */
		default_rcfiles(homedir, rcfile, copy_cmd);
		if (procmailrc)
			/* call util.c & build procmailrcfile if requested */
			generate_procmailrc(homedir, rcfile, 
						dirname, pipe_command);
	}

	/* call net.c to establish connection to nntp server */
	socket_id = connect_server(hostname, 119, 0);

	/* 
	 * use net.c to open up a socket file descriptor, there are
	 * two descriptors for portability
	 */
	create_fd(socket_id, socket_fp);
	setvbuf(socket_fp[0], (char *) NULL, _IOLBF, 0);
	setvbuf(socket_fp[1], (char *) NULL, _IOLBF, 0);

	/*
	 * set signal handler for termination 
	 */
	if (!only_list) {
		signal(SIGPIPE, pipe_handler);
		signal(SIGALRM, pipe_handler);
		signal(SIGINT, exit_handler);
		signal(SIGHUP, exit_handler);
		signal(SIGTERM, exit_handler);
	}

	/* use nntp.c to set the reader mode */
	set_reader_mode();

	if (only_list)
		/* use nntp.c to get the group list */
		get_group_list();

	article_fetching = 1;

	/* run this loop while we still have groups to get */
	while ((tmp = get_next_group()) > 0) {

		/* we could end up here by accident even if there was
		   termination request                               */
		if (!terminate) {
			/*
			 * If we have received signal in get_next_group 
			 */
			fprintf(rctmpfp, "%s %d %d\n", 
				group, first_article, max_article);
			break;
		}

		/*
		 * Increase first_article to point to next new message 
		 */
		last_than_current = first_article;
		first_article++;
		article_fetching = 0;

		/* both check_group and fetch_group are in nntp.c */
		tmp = check_group();
		if (tmp > 0)
			tmp = fetch_group();

		article_fetching = 1;
		fprintf(rctmpfp, "%s %d %d\n", 
				group, first_article, max_article);
		article_fetching = 0;

		if (command_flag)
			exec_groupcmd(execute_command, group);

		if (tmp < 0)
			break;
		article_fetching = 1;
	}
	quit_now(0);
	return 0;
}

