/*
 * $Id: getarticles.c,v 1.3 2002/06/10 04:10:06 conrads Exp $
 */

#include <string.h>
#include <unistd.h>

#include "msuck.h"
#include "nntp.h"

extern FILE * sucklog;
extern CONNECTION local, remote;

static char artpath[PATH_MAX + 1];

/*
 * feed an article to local server
 * 
 * returns 0 on success, -1 on error
 */
static int
ihave(char *artpath, char *mess_id)
{
	FILE * artfile;
	char linebuf[MAXLINE + 1];

	if ((artfile = fopen(artpath, "r")) == NULL)
	{
		perror("ihave(): can't open article file");
		return -1;
	}

	if (connect_to_server("localhost", &local) <= 0)
	{
		fprintf(stderr, "ihave(): connection to local server failed\n");
		fclose(artfile);
		return -1;
	}

	fprintf(local.out, "ihave %s\r\n", mess_id);
	if (fgets(linebuf, MAXLINE, local.in) == NULL)
	{
		perror("ihave(): read error on socket after IHAVE command");
		close_server(local);
		fclose(artfile);
		return -1;
	}

	/* check response code */
	if (strncmp(linebuf, NNTP_SENDIT, 3) != 0)
	{
		fprintf(stderr, "ihave(): unexpected reply to IHAVE from local server: %s\n", linebuf);
		quit_server(local);
		fclose(artfile);
		return -1;
	}

	/* write article to local server */
	while (!feof(artfile))
	{
		if (fgets(linebuf, MAXBUFF, artfile) == NULL)
			break;
		if (fputs(linebuf, local.out) == EOF)
		{
			perror("ihave(): error writing article to local server");
			close_server(local);
			fclose(artfile);
			return -1;
		}
	}

	if (fputs(".\r\n", local.out) == EOF)
	{
		perror("ihave(): error writing article to local server");
		close_server(local);
		fclose(artfile);
		return -1;
	}

	fclose(artfile);

	/* get result code */
	if (fgets(linebuf, MAXLINE, local.in) == NULL)
	{
		perror("ihave(): read error on socket after sending article");
		close_server(local);
		return -1;
	}

	/* check response code */
	if (strncmp(linebuf, NNTP_TOOKIT, 3) != 0)
	{
		fprintf(stderr, "ihave(): unexpected reply from local server after sending article: %s\n", linebuf);
		quit_server(local);
		return -1;
	}

	quit_server(local);
	return 0;
}

/*
 * Get a single article
 * 
 * returns 1 on success, 0 on no such article, or -1 on error
 */
static int
getarticle(const char *group, const char *artnum)
{
	FILE *artfile;
	char buf[MAXBUFF + 1];

	/* open the article file we're writing to */
	snprintf(artpath, PATH_MAX, "/tmp/article.%s.%s", group, artnum);

	if ((artfile = fopen(artpath, "w")) == NULL)
	{
		perror(artpath);
		return -1;
	}

	fprintf(remote.out, "article %s\r\n", artnum);
	if (fgets(buf, MAXBUFF, remote.in) == NULL)
	{
		perror("getarticle(): read error on socket after ARTICLE command");
		fclose(artfile);
		return -1;
	}
	/* should have gotten "220" article reply */
	if (strncmp(buf, NNTP_ARTICLE_FOLLOWS, 3) != 0)
	{
		fprintf(stderr, "getarticle(): unexpected reply in %s to ARTICLE %s: %s\n", group, artnum, buf);
		fclose(artfile);
		return 0;
	}

	/* just read and write everything up to the terminating "." */
	for (;;)
	{
		if (fgets(buf, MAXBUFF, remote.in) == NULL)
		{
			perror("getarticle(): read error on socket while reading article");
			fclose(artfile);
			return -1;
		}
		if (END_OF_OUTPUT(buf))
			break;
		if (fputs(buf, artfile) != 0)
		{
			perror("getarticle(): write error on article file");
			fclose(artfile);
			return -1;
		}
	}

	fclose(artfile);
	return 1;
}

/*
 * Get all new articles in a group
 * 
 * Returns the number actually fetched, or -1
 */

int
getarticles(const char *group, int numarts)
{
	char artlistpath[PATH_MAX + 1];
	FILE *artlist;
	char artnum[MAXART + 1];
	char mess_id[MAXLINE + 1];
	char buf[MAXLINE + 1];
	int numfetched = 0;
	int count = 0;
	int n;

	/* open the articles list */
	snprintf(artlistpath, PATH_MAX, ARTLIST_PATH_TEMPLATE, group);

	if ((artlist = fopen(artlistpath, "r")) == NULL)
	{
		perror("getarticles(): can't open article list");
		return -1;
	}

	fprintf(remote.out, "mode reader\r\n");
	if (fgets(buf, MAXLINE, remote.in) == NULL)
	{
		perror("getarticles(): read error on socket after MODE READER command");
		return -1;
	}

	/* should have gotten second server greeting */
	if (strncmp(buf, NNTP_POSTOK, 3) != 0)
	{
		fprintf(stderr, "getarticles(): unexpected reply to MODE READER command: %s\n", buf);
		return -1;
	}

	fprintf(remote.out, "group %s\r\n", group);
	if (fgets(buf, MAXLINE, remote.in) == NULL)
	{
		perror("getarticles(): read error on socket after GROUP command");
		return -1;
	}

	/* should have gotten group info */
	if (strncmp(buf, NNTP_GROUPOK, 3) != 0)
	{
		fprintf(stderr, "getarticles(): unexpected reply to GROUP command: %s\n", buf);
		return -1;
	}

	while (!feof(artlist))
	{
		if (fscanf(artlist, "%s %s\n", artnum, mess_id) != 2)
		{
			perror("getarticles(): read error on filtered articles list file");
			fclose(artlist);
			return -1;
		}

		/*
		 * It's possible that the article may have already been
		 * fetched by another process by now, so check one last time
		 * before we start fetching it
		 */
		if (connect_to_server("localhost", &local) <= 0)
		{
			fprintf(stderr, "getarticles(): connection to local server failed\n");
			fclose(artlist);
			return -1;
		}
		if (article_exists(group, artnum, mess_id) != 0)
		{
			fprintf(sucklog, "Article %s %s (%d of %d) in %s already exists\n",
				artnum, mess_id, ++count, numarts, group);
			quit_server(local);
			continue;
		}

		quit_server(local);

		fprintf(sucklog, "Getting article %s (%d of %d) in %s\n",
			artnum, ++count, numarts, group);

		if ((n = getarticle(group, artnum)) > 0)
		{
			if (ihave(artpath, mess_id) == 0)
				++numfetched;
			unlink(artpath);
		}
		else
		{
			--numfetched;
			if (n == 0)	/* probably just a "no such article"
					 * result */
			{
				continue;
			}
			if (n < 0)	/* uh-oh! */
			{
				fclose(artlist);
				unlink(artlistpath);
				return -1;
			}
		}
	}

	fclose(artlist);
	unlink(artlistpath);

	return numfetched;
}


syntax highlighted by Code2HTML, v. 0.9.1