/*
 *  Project   : tin - a threaded Netnews reader
 *  Module    : active.c
 *  Author    : I.Lea
 *  Created   : 16-02-92
 *  Updated   : 08-06-92
 *  Notes     :
 *  Copyright : (c) Copyright 1991-92 by Iain Lea
 *              You may  freely  copy or  redistribute  this software,
 *              so  long as there is no profit made from its use, sale
 *              trade or  reproduction.  You may not change this copy-
 *              right notice, and it must be included in any copy made
 */

#include	"tin.h"

int group_hash[TABLE_SIZE];			/* group name --> active[] */
int reread_active_file = FALSE;


/*
 *  Resync active file when SIGALRM signal received that
 *  is triggered by alarm (RESYNC_ACTIVE_SECS) call.
 */

void resync_active_file ()
{
	if (reread_active_file) {
		free_active_arrays ();
		max_active = DEFAULT_ACTIVE_NUM;
		expand_active ();
		read_active_file ();
		read_newsgroups_file ();
		read_newsrc (TRUE);
		set_alarm_signal ();
		mail_setup ();
		group_selection_page ();
	}
}

/*
 *  Load the active file into active[] and create copy of active ~/.tin/active
 */

int read_active_file ()
{
	FILE *fp;
	char *p, *q, *r;
	char buf[LEN];
	char moderated = 'y';
	int created, i;
	long h;
	
	num_active = 0;

	if (! update) {
		wait_message (txt_reading_active_file);
	}

	if ((fp = open_active_fp ()) == NULL) {
		if (compiled_with_nntp) {
			sprintf (msg, txt_cannot_open_active_file, active_file, progname);
			wait_message (msg);
		} else {
			fputc ('\n', stderr);
			fprintf (stderr, txt_cannot_open, active_file);
			fputc ('\n', stderr);
			fflush (stderr);
		}
		exit (1);
	}

	for (i = 0; i < TABLE_SIZE; i++) {
		group_hash[i] = -1;
	}

	while (fgets (buf, sizeof (buf), fp) != NULL) {
		for (p = buf; *p && *p != ' '; p++)
			continue;
		if (*p != ' ') {
			error_message (txt_bad_active_file, buf);
			continue;
		}
		*p++ = '\0';

		if (num_active >= max_active) {
			debug_nntp ("read_active_file", "EXPANDING active file");
			expand_active ();
		}

		h = hash_groupname (buf);

		if (group_hash[h] == -1) {
			group_hash[h] = num_active;
		} else {				/* hash linked list chaining */
			for (i=group_hash[h]; active[i].next >= 0; i=active[i].next) {
				if (strcmp(active[i].name, buf) == 0) {
					goto read_active_continue;		/* kill dups */
				}
			}
			if (strcmp(active[i].name, buf) == 0)
				goto read_active_continue;
			active[i].next = num_active;
		}

		for (q = p; *q && *q != ' '; q++)
			continue;
		if (*q != ' ') {
			error_message (txt_bad_active_file, buf);
			continue;
		}
		*q++ = '\0';

		for (r = q; *r && *r != '\n'; r++) {
			if (*r == 'y' || *r == 'm') {
				moderated = *r;
				break;
			}
		}

		/*
		 * Group info.
		 */
		active[num_active].name = str_dup (buf);
		active[num_active].description = (char *) 0;
		active[num_active].max = (long) atol (p);
		active[num_active].min = (long) atol (q);
		active[num_active].moderated = moderated;
		active[num_active].next = -1;			/* hash chaining */
		active[num_active].flag = UNSUBSCRIBED;	/* not in my_group[] yet */
		/*
		 * Per group attributes
		 */
		active[num_active].attribute.server  = (char *) 0;
		active[num_active].attribute.maildir = default_maildir;
		active[num_active].attribute.savedir = default_savedir;
		active[num_active].attribute.sigfile = default_sigfile;
		active[num_active].attribute.read    = FALSE;	/* read/unread */
		active[num_active].attribute.showall = show_only_unread;
		active[num_active].attribute.thread  = thread_arts;
		active[num_active].attribute.sortby  = sort_art_type;
		active[num_active].attribute.author  = show_author;
		active[num_active].attribute.autosave= save_archive_name;
		active[num_active].attribute.process = post_proc_type; 

		num_active++;

read_active_continue:;

	}
	fclose (fp);

	/*
	 *  exit if active file is empty
	 */
	if (! num_active) {
		error_message (txt_active_file_is_empty, active_file);
		exit (1);
	}

	/*
	 * create backup of LIBDIR/active for use by -n option to notify new groups 
	 */
	created = backup_active (TRUE);

/*	if (cmd_line && (read_news_via_nntp && update == FALSE)) {
		if (! (update && ! verbose)) {
			wait_message ("\n");
		}
	}
*/
	if (cmd_line && ! update && ! verbose) {
		wait_message ("\n");
	}

	return (created);
}

/*
 *  create ~/.tin/active from LIBDIR/active if it does not exist 
 */

int backup_active (create)
	int create;
{
	char buf[LEN];
	FILE *fp;
	int created = FALSE;
	int i;
	struct stat sb;
	
	sprintf (buf, "%s/active", rcdir);
	
	if (create) {
		if (stat (buf, &sb) != -1) {
			goto backup_active_done;
		}
	}
	
	if ((fp = fopen (buf, "w")) != NULL) {
		for (i = 0; i < num_active ; i++) {	/* for each group */
			fprintf (fp, "%s\n", active[i].name);
		}
		fclose (fp);
		chmod (buf, 0644);
		created = TRUE;
	}

backup_active_done:
	return (created);
}

/*
 *  Option -n to check for any newly created newsgroups.
 */

void notify_groups ()
{
	char buf[LEN];
	FILE *fp;
	int group_not_found;
	int index;
	int num = 0;
	int update_old_active = FALSE;
	int max_old_active;
	register int i, j;
	struct notify_t {
		char name[LEN];
		int len;
		int visited;
	} *old_active = (struct notify_t *) 0;
	
	sprintf (buf, "%s/active", rcdir);
	
	if ((fp = fopen (buf, "r")) == NULL) {
		perror_message (txt_cannot_open, buf);
		goto notify_groups_done;
	}

	Raw (TRUE);
	
	wait_message (txt_checking_active_file);

	max_old_active = num_active;
	
	old_active = (struct notify_t *) my_malloc ((unsigned) sizeof (struct notify_t) * max_old_active);
	if (old_active == (struct notify_t *) 0) {
		error_message (txt_out_of_memory, progname);
		goto notify_groups_done;
	}
	
	while (fgets (old_active[num].name, sizeof (old_active[num].name), fp) != NULL) {
		old_active[num].len = strlen (old_active[num].name)-1;
		old_active[num].name[old_active[num].len] = '\0';
		old_active[num].visited = FALSE;
		num++;
		if (num >= max_old_active) {
			max_old_active= max_old_active + (max_old_active / 2);
			old_active= (struct notify_t*) my_realloc(
				(char *) old_active, 
				(unsigned) sizeof(struct notify_t) * max_old_active);
			if (old_active == (struct notify_t *) 0) {
				error_message (txt_out_of_memory, progname);
				goto notify_groups_done;
			}
		}
	}

	for (i = 0 ; i < num_active ; i++) {	
		group_not_found = TRUE;
		for (j=0; j < num ; j++) {
			if (strcmp (old_active[j].name, active[i].name) == 0) {
				group_not_found = FALSE;	/* found it so read in next group */
				old_active[j].visited = TRUE;
				break;
			}
		}

		if (group_not_found == FALSE) {
			continue;
		}	

		update_old_active = TRUE;
		do {
			fputc ('\r', stdout);
			CleartoEOLN();
			printf (txt_subscribe_to_new_group, active[i].name);
			fflush (stdout);
			buf[0] = ReadCh();
		} while (buf[0] != 'y' && buf[0] != 'n');
			
		if (buf[0] == 'y') {
			index = add_group (active[i].name, TRUE);
			subscribe (active[my_group[index]].name, ':',
				   my_group[index], FALSE);
		}
		printf ("\r\n%s", txt_checking);
		fflush (stdout);
	}
	fclose (fp);
	fputc ('\r', stdout);
	fflush (stdout);
	CleartoEOLN();

	/*
	 * Look for bogus groups 
	 */
	for (j = 0 ; j < num ; j++)  {
		if (old_active[j].visited) {
			continue;
		}
		do {	
			update_old_active= 1;
			fputc ('\r', stdout);
			CleartoEOLN ();
			printf (txt_delete_bogus_group, old_active[j].name);
			fflush (stdout);
			buf[0] = ReadCh ();
		} while (buf[0] != 'y' && buf[0] != 'n');
		if (buf[0] == 'y') {
			delete_group (old_active[j].name);
		}
		printf ("\r\n");
	}
	
	Raw (TRUE);

	/*
	 *  write active[] to ~/.tin/active
	 */
	if (update_old_active) {
		backup_active (FALSE);
	}

notify_groups_done:
	if (old_active != (struct notify_t *) 0) {
		free ((char *) old_active);
		old_active = (struct notify_t *) 0;
	}
}

/*
 *  Mark any groups in my_group[] that are in ~/.tin/unthread so they
 *  will not be threaded
 */
 
void mark_unthreaded_groups ()
{
	FILE *fp;
	char buf[LEN];
	int i, len;
	long h;

#ifndef INDEX_DAEMON

	if ((fp = fopen (unthreadfile, "r")) == NULL) {
		perror_message (txt_cannot_open, unthreadfile);
		return;
	}

	while (fgets (buf, sizeof (buf), fp) != NULL) {
		buf[strlen (buf)-1] = '\0'; 
		h = hash_groupname (buf);
		sprintf (msg, "Unthreading %s...\n", buf);
		wait_message (msg);
		
		i = group_hash[h];
		
		if (active[i].next == -1) {
			len = strlen (active[i].name);
			if (strncmp (active[i].name, buf, len) == 0) {
				active[i].attribute.thread = FALSE;
			}
		
		} else {
			for (i=group_hash[h] ; i >= 0 ; i=active[i].next) {
				len = strlen (active[i].name);
				if (strncmp (active[i].name, buf, len) == 0) {
					active[i].attribute.thread = FALSE;
					break;
				}
			}
		}	
	}

	fclose (fp);
#endif /* INDEX_DAEMON */
}

/*
 *  Load the text description from LIBDIR/newsgroups for each group
 *  into the active[] array.
 */

void read_newsgroups_file ()
{
	FILE *fp;
	char *p, *q;
	char buf[LEN];
	char group[PATH_LEN];
	int i;
	long h;
	
	if (! show_description || update) {
		return;
	}

	wait_message (txt_reading_newsgroups_file);

	if ((fp = open_newsgroups_fp ()) == NULL) {
		return;
	}

	while (fgets (buf, sizeof (buf), fp) != NULL) {
		buf[strlen (buf)-1] = '\0';

		for (p = buf, q = group ; *p && *p != ' ' && *p != '\t' ; p++, q++) {
			*q = *p;
		}
		*q = '\0';

		for (;*p == '\t' || *p == ' '; p++) {
			;
		}	
				
		h = hash_groupname (group);

		i = group_hash[h];

		if (debug == 2) {
			fprintf (stderr, "HASH=[%5ld] IDX=[%5d] GRP=[%s] TXT=[%s]\n", h, i, group, p);
		}
		
		if (active[i].next == -1) {
			if (strcmp (active[i].name, group) == 0) {
if (debug == 2) {
	fprintf (stderr, "FOUND HEAD\n");
}	
				if (active[i].description == (char *) 0) {
					active[i].description = str_dup (p);
				}
			}
		} else {
			for (; i >= 0 ; i = active[i].next) {
				if (strcmp (active[i].name, group) == 0) {
if (debug == 2) {
	fprintf (stderr, "FOUND LINK\n");
}	
					if (active[i].description == (char *) 0) {
						active[i].description = str_dup (p);
						break;
					}
				}
			}
		}
	}
	fclose (fp);

	if (cmd_line && ! update && ! verbose) {
		wait_message ("\n");
	}
}
