/*
 * This file is provided for unrestricted use
 * provided that this legend is included on all tape media
 * and as a part of the software program in whole or part.  Users
 * may copy or modify this file without charge, but are not authorized to
 * license or distribute it to anyone else except as part of a product
 * or program developed by the user.
 *
 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 *
 * This file is provided with no support and without any obligation on the
 * part of Sun Microsystems, Inc. to assist in its use, correction,
 * modification or enhancement.
 *
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE
 * OR ANY PART THEREOF.
 *
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even
 * if Sun has been advised of the possibility of such damages.
 *
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */

#include <stdio.h>
#include <sys/stat.h>
#include <xview/xview.h>
#include <xview/font.h>
#include <xview/canvas.h>
#include <xview/panel.h>
#include <xview/termsw.h>
#include <xview/text.h>

#include "xvnews_ui.h"
#include "xvnews.h"
#include "codes.h"

extern struct globals *Global;

/*
 *
 *	Check the .newsrc file. If it is not there create one from the server.
 *  If there is one, parse it and check for bogus entries, old newsgroups
 *  and new newsgroups available to the user. Returns the head of a linked list.
 *
 */

check_newsrc(ip)
xvnews_xvnews_window_objects    *ip;
{

	char		aline[BUFFERLEN + 1], ngroup[80], sgroup[80], group[80];
	char		line[80], file[256], *newslist[MAX_NEWS_GROUPS * 5];
	char		*getenv();
	int		articles[MAX_NEWS_GROUPS * 5];
	int		active=0, lines=0, done=0, row=0, i, first, last, count=0;
	FILE		*ifp_in;
	struct		newsrc_node	*head = NULL, *new, *prev = NULL, *curr;
	struct		newsrc_node	*create_newsrc(), *createSingleNewsrc();
	struct		stat	statbuf;

	if (Global->single == NULL) {
		put_server("LIST");
		get_server(aline, sizeof(aline));
		while (*aline != '.') {
			get_server(aline, sizeof(aline));
			if ((strlen(aline) != 1) && (aline[0] != '.')) {
				sscanf(aline, "%s%d%d", group, &first, &last);
				articles[lines] = first - last;
				newslist[lines] = (char *)malloc(strlen(group) + 1);
				if (newslist[lines] == NULL) {
					printf("Malloc failed\n");
					exit(-1);
				}
				strcpy(newslist[lines], group);
				if (++lines > MAX_NEWS_GROUPS * 5) {
					printf("xvnews only supports %d newsgroups, exiting...\n", MAX_NEWS_GROUPS * 5); 
					exit(-1);
				}
			}
		}
	}

	if ((ifp_in = fopen(Global->newsrc, "r")) == NULL) {
		printf("No %s found, creating a new one...\n", Global->newsrc);
		if (Global->single != NULL)
			Global->head = createSingleNewsrc();
		else {
			Global->head = create_newsrc(newslist, lines, articles);
			get_descriptions();
			sort_newsrc();
		}
		Global->mode = GROUP_MODE;
		get_groups(ip, 1);
		return;
	}

	if (Global->single != NULL) {
		parseSingleNewsrc(ifp_in);
		fclose(ifp_in);
		return;
	}

	while(fgets(aline, BUFFERLEN, ifp_in) != NULL) {
		aline[BUFFERLEN] = '\0';
		++count;
		sscanf(aline, "%79s", ngroup);
		ngroup[79] = '\0';
		if ((strchr(ngroup, '!') == NULL) &&
			 (strchr(ngroup, ':') == NULL)) {
			printf("Bogus entry %s on line %d of %s\n",
				 ngroup, count, Global->newsrc);
			continue;
		}
		strncpy(sgroup, ngroup, strlen(ngroup) - 1);
                sgroup[strlen(ngroup) - 1] = '\0';
		done = 0;
		for (i = 0; i < lines; ++i) {
			if (newslist[i] == NULL)
				continue;
			if (!strcmp(sgroup, newslist[i])) {
				new = (struct newsrc_node *)parse_line(aline, newslist[i]);
				if (new != NULL) {
					if (articles[i] < 0)
						new->articles = 0;
					else
						new->articles = articles[i];
					done = 1;
					newslist[i] = NULL;
					break;
				}
			}
		}
		if (done == 0)
			printf("Invalid newsgroup %s, line %d of %s\n",
				 sgroup, count, Global->newsrc);
		else
			++active;
	}
	fclose(ifp_in);

	if (active != lines) {
		printf("Checking for new newsgroups...\n");
		for (i = 0; i < lines; i++) {
			if (newslist[i] == NULL)
				continue;
			done = 0;
			for (curr = Global->head;curr != NULL;curr = curr->nextgroup) {
				if (!strcmp(curr->newsgroup, newslist[i])) {
					done = 1;
					break;
				} else
					prev = curr;
			}
			if (done == 0) {
				Global->mode = NEW_GROUPS;
				new = (struct newsrc_node *) malloc(sizeof(struct newsrc_node));
				if (new == NULL) {
					printf("Malloc failed\n");
					exit(-1);
				}
				if (prev == NULL)
					Global->head = new;
				else
					prev->nextgroup = new;
				new->nextgroup = NULL;
				new->artlist = NULL;
				new->newsgroup = newslist[i];
				new->subscribed = UNSUBSCRIBED;
				new->kill = NULL;
				/*
				add_articles(new, "0", "0");
				*/
				new->description = NULL;
				if (articles[i] < 0)
					new->articles = 0;
				else
					new->articles = articles[i];
				sprintf(line, "%-64.64sunsubscribed", newslist[i]);
				xv_set(ip->groups_list,
				    PANEL_LIST_INSERT, row,
				    PANEL_LIST_STRING, row, line,
				    PANEL_LIST_FONT, row, Global->listfont,
				    NULL);
				if (row == 0) {
					xv_set(ip->groups_list,
				 	   PANEL_LIST_SELECT, 0, TRUE, NULL);
					strcpy(Global->group, newslist[i]);
				}
				++row;
				++active;
			}
			if (active == lines) {
				get_descriptions();
				return;
			}
		}
	}
	get_descriptions();
}

struct newsrc_node *
create_newsrc(newslist, lines, articles)
char *newslist[];
int lines;
int *articles;
{
	int	i;
	struct newsrc_node	*head = NULL, *new, *prev = NULL;

	for (i = 0; i < lines; ++i) {
		new = (struct newsrc_node *) malloc(sizeof(struct newsrc_node));
		if (new == NULL) {
			printf("Malloc failed!\n");
			exit(-1);
		}
		head == NULL ? head = new:NULL;
		new->artlist = NULL;
		new->newsgroup = newslist[i];
		if (articles[i] > 0)
			new->articles = articles[i];
		else
			new->articles = 0;
		if (!strcmp(newslist[i], "news.newusers.questions") ||
			!strcmp(newslist[i], "news.announce.newusers"))
			new->subscribed = SUBSCRIBED;
		else
			new->subscribed = UNSUBSCRIBED;
		prev != NULL ? prev->nextgroup = new:NULL;
		new->nextgroup = NULL;
		prev = new;
	}
	return head;
}

struct newsrc_node *
createSingleNewsrc()
{
	char		command[MAX_COMMAND_LEN], message[MAX_MESSAGE_LEN];
	int status;
	struct newsrc_node	*new = NULL;

	new = (struct newsrc_node *) malloc(sizeof(struct newsrc_node));
	if (new == NULL) {
		printf("Malloc failed!\n");
		exit(-1);
	}
	new->artlist = NULL;
	new->subscribed = SUBSCRIBED;
	new->newsgroup = Global->single;
	new->nextgroup = NULL;
	new->articles = 0;
	sprintf(command, "GROUP %s", new->newsgroup);
	put_server(command);
	get_server(message, sizeof(message));
	sscanf(message, "%d", &status);
	if (status != OK_GROUP) {
		printf("Invalid group %s, exiting...\n", new->newsgroup);
		close_server();
		exit(-1);
	}
	return new;
}

sort_newsrc()
{
	struct newsrc_node	*new_head = NULL, *curr = Global->head;
	struct newsrc_node	*new = NULL, *prev_new = NULL, *prev = NULL;

	new_head = (struct newsrc_node *)malloc(sizeof(struct newsrc_node));
	if (new_head == NULL) {
		printf("Malloc failed!\n");
		return -1;
	}
	new_head->nextgroup = NULL;
	new_head->newsgroup = curr->newsgroup;
	new_head->artlist = curr->artlist;
	new_head->description = curr->description;
	new_head->articles = curr->articles;
	curr = curr->nextgroup;
	while(curr != NULL) {
			new = new_head;
			prev_new = NULL;
			while(new != NULL) {
				if (strcmp(curr->newsgroup,new->newsgroup) < 0) {
					prev = curr->nextgroup;
					curr->nextgroup = new;
					if (prev_new == NULL)
						new_head = curr;
					else
						prev_new->nextgroup = curr;
					curr = prev;
					break;
				} else {
					prev_new = new;
					new = new->nextgroup;
				}
				if (new == NULL) {
					prev_new->nextgroup = curr;
					curr = curr->nextgroup;
					prev_new->nextgroup->nextgroup = NULL;
				}
			}
	}
	Global->head = new_head;
	return 1;
}

get_descriptions()
{
	char	aline[256], group[80];
	char	*c;
	int	status;
	struct newsrc_node	*curr;

	if (!Global->list)
		return -1;

	put_server("LIST NEWSGROUPS");
	get_server(aline, sizeof(aline));
	sscanf(aline, "%d", &status);

	if (status != OK_GROUPS)
		return -1;

	while(*aline != '.') {
		get_server(aline, sizeof(aline));
		sscanf(aline, "%s", group);
		for (curr = Global->head; curr != NULL; curr = curr->nextgroup) {
			if (!strcmp(curr->newsgroup, group)) {
				c = &aline[strlen(group)+1];
				while(*c == ' ' || *c == '	' || *c == '\n')
					++c;
				curr->description = (char *)malloc(sizeof(aline));
				if (curr->description == NULL) {
					printf("Malloc failed\n");
					return -1;
				}
				sscanf(c, "%[^\n]s", curr->description);
				break;
			}
		}
	}
	return 1;
}

print_newsrc(group)
char	*group;
{
	struct newsrc_node      *curr;
        struct article_node     *art = NULL;

	if (!strlen(group)) {
        for (curr = Global->head; curr != NULL; curr = curr->nextgroup) {
                art = curr->artlist;
                printf("%s%c %d-%d", curr->newsgroup,
                         curr->subscribed == SUBSCRIBED ? ':':'!',
                                art->first, art->last);
                art = art->nextart;
                while (art != NULL) {
                        if (art->last)
                                printf(",%d-%d",art->first, art->last);
                        else
                                printf(",%d", art->first);
		art = art->nextart;
                }
                printf("\n");
        }
	} else {
        	for (curr = Global->head;curr != NULL; curr = curr->nextgroup) {
			if (!strcmp(group, curr->newsgroup)) 
				break;
		}
                art = curr->artlist;
                printf("%s%c %d-%d", curr->newsgroup,
                         curr->subscribed == SUBSCRIBED ? ':':'!',
                                art->first, art->last);
                art = art->nextart;
                while (art != NULL) {
                        if (art->last)
                                printf(",%d-%d",art->first, art->last);
                        else
                                printf(",%d", art->first);
		art = art->nextart;
                }
                printf("\n");
	}
}
parseSingleNewsrc(ifp_in)
FILE	*ifp_in;
{
	int count = 0, status;
	char		aline[BUFFERLEN], ngroup[80], sgroup[80];
	char		command[MAX_COMMAND_LEN], message[MAX_MESSAGE_LEN];
	struct		newsrc_node	*new = NULL;

	while(fgets(aline, BUFFERLEN, ifp_in) != NULL) {
		count++;
		sscanf(aline, "%s", ngroup);
		if ((strchr(ngroup, '!') == NULL) &&
			 (strchr(ngroup, ':') == NULL)) {
			printf("Bogus entry %s on line %d of %s\n",
				 ngroup, count, Global->newsrc);
			continue;
		}
		strncpy(sgroup, ngroup, strlen(ngroup) - 1);
                sgroup[strlen(ngroup) - 1] = '\0';
		if (strcmp(sgroup, Global->single))
			continue;
		new = (struct newsrc_node *)parse_line(aline, sgroup);
		new->articles = 0;
		sprintf(command, "GROUP %s", sgroup);
		put_server(command);
		get_server(message, sizeof(message));
		sscanf(message, "%d", &status);
		if (status != OK_GROUP) {
			printf("Invalid group %s, exiting...\n", sgroup);
			close_server();
			exit(-1);
		}
		return;
	}
}
