
/***************************************************************************
 *   Copyright (C) 1997 to 2004 by Jonathan Duddington                     *
 *   email: jonsd@users.sourceforge.net                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write see:                           *
 *               <http://www.gnu.org/licenses/>.                           *
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "kernel.h"
#include "menu.h"
#include "wimp.h"
#include "werr.h"
#include "dbox.h"
#include "os.h"
#include "flex.h"
#include "msgs.h"
#include "alarm.h"

#include "narc.h"
#include "hdrs.h"

#ifdef MemCheck
#include "MemCheck:Flex.h"
#endif


extern OPTIONS options;
extern FOLDREC list_fr[N_LISTS];
extern int transport_opts;
extern char *atext_base;               /* article data in memory */
extern int atext_max;                  /* max. length of article data in memory */
extern char appended_art_file[N_ART_FILES_TOT];   /* note which article files have received news */
extern int fileno_append;              /* article file currently appending */
extern int article_total_length;

extern int lock_lists;

extern BLIST boxlist;
extern int lock_expiry;
extern int regex_err;
extern int n_filtered;
extern int n_binned;
extern int n_undelivered;
extern int  acks_held;       /* acks put in Hold directory */
extern int  acks_sent;       /* total acks produced */
extern int  boxes_unread_count[N_BOXES];
extern BOX box_table[N_BOXES];



static char *err_expiring = "Still expiring articles, please wait.";

static char *fname_leave = "<Pluto$Dir>.Backup.Undeliver";
FILE *f_leave_mail=NULL;

static int extract_err_count = 0;


int extract_news_article(char *fname, FILE *f, int start, int length, int box, int flags,
						 int type, int crlf)
/****************************************************************************************/
{
	char *p;
	int  i;
	int displ;
	FILE *f_out;
	char buf[80];

	if(length < 0) return(1);

	displ = (int)ftell(f);
	fseek(f,start,SEEK_SET);
	fflush(f);

	if((length + TEXT_EXTRA) > atext_max)
	{
		if(atext_max != 0)
			flex_free((flex_ptr)&atext_base);

		atext_max = length + TEXT_EXTRA*2;

		/* minimum memory for debatching, so we don't need to keep expanding
		   it too often */
		if(atext_max < 10000)
			atext_max = 10000;
		if(flex_alloc((flex_ptr)&atext_base,atext_max) == 0)
		{
			if(extract_err_count < 2)
			{
				/* just show error message for the first two failures */
				sprintf(buf,"to debatch article, size: %d",length);
				malloc_err_string(35,buf);
			}

			atext_max = 0;

			/* not enough memory.  Append article to !Pluto.Backup.ErrNews/ErrMail */
			if(type == X_NEWS)
				f_out = fopen_pluto("Backup.ErrNews","a");
			else
				f_out = fopen_pluto("Backup.ErrMail","a");

			if(f_out != NULL)
			{
				/* copy the article */
				for(i=0; i<length; i++)
				{
					fputc(fgetc(f),f_out);
				}

				if(crlf)
					fprintf(f_out,".\r\n");   /* terminator */

				fclose(f_out);
				extract_err_count++;
			}

			fseek(f,displ,SEEK_SET);
			return(2);
		}
	}


	if(crlf)
	{
		p = atext_base;
		for(i=0; i<length; i++)
		{
			if((*p++ = fgetc(f)) == '\r')
				p--;
		}
		length = p - atext_base;
	}
	else
	{
		fread(atext_base,1,length,f);
	}
	fseek(f,displ,SEEK_SET);


	if(interpret_file(fname,0xfff,flags,box,NULL,0,length,NULL,0) == NULL)
	{
		return(-1);
	}
	return(0);
}   /* end of extract_news_article */




unsigned int disc_free_space(char *fname)
/***************************************/
/* Return free space / 1024 */
{
	unsigned int result;
	os_regset regs;
	os_error *error;

	if(memcmp(fname,"NetFS:",6)==0)
		return(0x7fffffff);   /* don't know, so return large number */

	regs.r[0] = 55;
	regs.r[1] = (int)fname;
	error = os_swix(0x29,&regs);

	if(error == NULL)
	{
		result = (regs.r[0] >> 10) & 0x003fffff;
		result += regs.r[1] << 22;
	}
	else
	{
		regs.r[0] = 49;
		regs.r[1] = (int)fname;

		/* OS_FSControl 49  read free space */
		if((error = os_swix(0x29,&regs)) == NULL)
		{
			result = regs.r[1];
			result = result >> 10;
		}
		else
		{
			/* failed to read free space, return large value */
			result = 0x7fffffff;
		}
	}
	return(result);

}   /* end of disc_free_space */





int debatch_file(char *path, int type, int box, int action_flags, char *stamp)
/*****************************************************************************/
/* Text file consisting of raw news or mail */
/* Action flag 14 = emails start with From, not rmail
   type = X_MAIL or X_NEWS,  bit 4 set means insist on appropriate rnews or rmail separator */
{
	FILE *f;
	char *p;
	int  *pi;
	int  articles;
	int  start_displ;
	int  next_displ=0;
	int  displ;
	int  prev_displ;
	int  length;
	int  news_length;
	int  i;
	int  file_length;
	int  file_length2;
	unsigned int file_length3;
	int  type2;
	char *separator;
	int  separator_len;
	int  err=0;
	char buf[400];
	char buf2[80];
	char filenos[N_ART_FILES];
	int  file_count=0;
	int  external_box=0;

	visdelay2_percent(1);

	regex_err = 0;
	n_filtered = 0;
	n_binned = 0;
	n_undelivered = 0;

	type2 = type & 0xf;

	if(path[0]<= ' ')
		return(0);

	f = fopen(path,"r");
	if(f==NULL)
	{
		clear_lock_lists(2);
		return(0);
	}

	if((box >= BOX_EXTERN) && (box < BOX_BIN))
		external_box = box;

	if(stamp != NULL)
		get_time_stamp2(path,stamp);

	file_length = get_filelength(path);
	if(file_length == 0)
	{
		fclose(f);
		clear_lock_lists(2);
		return(0);
	}

	file_length3 = file_length >> 10;
	if(file_length3 > disc_free_space(pluto_articles))
	{
		werr(0,"Warning: May not be enough disc space to debatch articles");
	}

	file_length2 = file_length/4;

	/* ensure index is sorted by msgid */
	msgid_lookup(1,NULL,0);

	article_open_shortest(box,0,-1);

	appended_art_file[fileno_append]=1;
	filenos[file_count++] = fileno_append;

	articles = 0;
	extract_err_count = 0;
	start_displ = -1;
	prev_displ = 0;

	if(((action_flags & 0x5000) == 0) &&
			(((type2==X_MAIL) && (transport_opts & TOPS_MAIL_CRLF)) ||
			 ((type2==X_NEWS) && (transport_opts & TOPS_NEWS_CRLF))))
	{

		/* articles separated by dot CR NL */
		separator = ".\r\n";
		separator_len = 3;

		start_displ = 0;
		while((!feof(f)) && (err >= 0))
		{
//         call_event_process(0);

			prev_displ = displ;
			displ = (int)ftell(f);

			p = fgets(buf,sizeof(buf),f);
			if(p==NULL)
				break;

			/* discount the separator if the previous line buffer was full */
			if((memcmp(p,separator,separator_len)==0) && ((displ-prev_displ) < (sizeof(buf)-1)))
			{
				call_event_process(0);
				visdelay2_percent((displ*25)/file_length2);
				articles++;

				length = displ - start_displ;

				if((type2 == X_MAIL) && (transport_opts & TOPS_MAIL_CRLF))
					err = extract_news_article(path,f,start_displ,length,box,action_flags,type2,1);  /* delete CRs */
				else
					err = extract_news_article(path,f,start_displ,length,box,action_flags,type2,0);

				article_total_length += length;
				if(article_total_length > 4000000)
				{
					/* start a new article file */
					article_open_shortest(box,0,-1);
					appended_art_file[fileno_append]=1;
					filenos[file_count++] = fileno_append;
				}
				start_displ = displ + 3;
			}
		}
	}
	else
	{
		/* articles separated by #! rnews */
		while((!feof(f)) && (err >= 0))
		{
//         call_event_process(0);

			if(next_displ != 0)
			{
				if(next_displ > file_length)
					next_displ = file_length;

				fseek(f,next_displ,SEEK_SET);
				next_displ = 0;
			}
			displ = (int)ftell(f);

			pi = (int *)fgets(buf,sizeof(buf),f);
			if(pi==NULL)
				break;

			if(action_flags & 0x4000)
			{
				if(memcmp((char *)pi,"From ",5)!=0)
					continue;
			}
			else
			{
				if((((char *)pi)[0] == 0x01) && (type2==X_MAIL) && (options.mail_transport == X_POPSTAR))
				{
					/* CTRL-A separator in POPStar, don't Continue */
				}
				else
				{
					/* look for "#! r" */
					if(pi[0] != 0x72202123)
						continue;

					if((memcmp((char *)pi,"#! rnews",8)!=0) && (memcmp((char *)pi,"#! rmail",8)!=0))
					{
						continue;
					}

#ifdef deleted
					/* check to insist on #! rnews for news files and #! rmail for emails
					   failed if an exported articles file contained a mixture of both */
					if((type2==X_NEWS) && (memcmp((char *)pi,"#! rnews",8)!=0))
					{
						continue;
					}
					if((type2==X_MAIL) && (memcmp((char *)pi,"#! rmail",8)!=0))
						continue;
#endif

					i = sscanf(buf,"#! %s %d",buf2,&news_length);
					next_displ = 0;
					if(i==2)
					{
						next_displ = (int)ftell(f) + news_length;
					}
				}
			}

			call_event_process(0);
			visdelay2_percent((displ*25)/file_length2);
			articles++;

			if(start_displ >= 0)
			{

				length = displ - start_displ;
				err = extract_news_article(path,f,start_displ,length,box,action_flags,type2,action_flags & 0x2000);

				article_total_length += length;
				if(article_total_length > 4000000)
				{
					/* start a new article file */
					article_open_shortest(box,0,-1);
					appended_art_file[fileno_append]=1;
					filenos[file_count++] = fileno_append;
				}
			}
			start_displ = displ;
		}

		if((start_displ >= 0) && (err >= 0))
		{
			length = displ - start_displ;
			err = extract_news_article(path,f,start_displ,length,box,action_flags,type2,action_flags & 0x2000);
		}
	}

	fclose(f);

	if(err < 0)
	{
		werr(0,"Debatching abandoned, address limit reached");
	}
	else if(extract_err_count > 0)
	{
		werr(0,"Insufficient memory.  %d articles have been put into !Pluto.Backup.ErrMail or ErrNews",
			 extract_err_count);
	}


	article_file_close();

	if(atext_max > 0)
	{
		flex_free((flex_ptr)&atext_base);
		atext_max = 0;
	}

	get_today_date2(buf2);
	f = fopen_pluto("Backup.log","a");
	if(f != NULL)
	{
		if(type2 == X_NEWS)
			p = "news";
		else
			p = "mail";

		fprintf(f,"%s  Debatch %4d %s into",buf2,articles,p);
		for(i=0; i<file_count; i++)
			fprintf(f," #%2d",filenos[i]);

		if((n_filtered > 0) || (n_binned > 0) || (n_undelivered > 0))
		{
			fprintf(f," %2d filtered %2d binned %d undelivered",n_filtered,n_binned,n_undelivered);

		}
		fputc('\n',f);
		fclose(f);
	}

	redraw_list_lines(NULL,0);
	return(articles);
}   /* end of debatch_file */



void news_backup(int n_backups, int type)
/***************************************/
/* Move the raw Mail or News file from "path" to backup.
   Move existing backups down one place */
{
	int count;
	char *type_string;
	char buf[256];
	char buf2[256];

	if(type == X_NEWS)
	{
		type_string = "News";
	}
	else
	{
		type_string = "Mail";
	}



	if(n_backups == 0)
		return;

	for(count=n_backups; count>1; count--)
	{
		sprintf(buf,"%sBackup.%s%d",pluto_path,type_string,count-1);
		sprintf(buf2,"%sBackup.%s%d",pluto_path,type_string,count);

		if(count == n_backups)
			file_delete(buf2);   /* can't use "remove" - won't work with a news directory */

		file_move(buf,buf2);
	}

	/* create directory */
	sprintf(buf,"%sBackup.%s1",pluto_path,type_string);
	if(n_backups == 1)
	{
		file_delete(buf);
	}
	os_swi2(0x08+os_X,8,(int)buf);   /* OS_File 8 */
}   /* end of news_backup */



void voyager_status(int code)
/***************************/
/* control the Voyager news and Mail flashing.
   0  no mail,  1 mail,  2 no news,  3 news */
{
	int  blk[6];

	blk[0] = 24;
	blk[1] = 0;
	blk[2] = 0;
	blk[3] = 0;
	blk[4] = 0x4a432;   /* Voyager message */
	blk[5] = code;

	os_swi3(0x400e7,17,(int)blk,0);    /* Wimp_SendMessage, return ACK if not acknowledged */
}   /* end of voyager_status */



void append_new_groups(char *path)
/********************************/
{
	int  i;
	FILE *f;
	FILE *f_in;
	char buf[256];

	sprintf(buf,"%sNewGrp",pluto_path);
	f = fopen(buf,"a");
	if(f==NULL)
		return;

	f_in = fopen(path,"r");
	if(f_in==NULL)
	{
		fclose(f);
		return;
	}

	while(!feof(f_in))
	{
		i = fread(buf,1,sizeof(buf),f_in);
		if(i > 0)
			fwrite(buf,1,i,f);
	}
	fclose(f);
	fclose(f_in);
}   /* end of append_new_groups */




int read_raw_news(int control,int announce)
/*****************************************/
/* Control bit 0:  mail
           bit 1:  news
   Announce: 0  don't announce,  1 only if messages, 2 always announce
           bit 8   don't open window
           bit 9   don't change "new unread" to "unread"
*/
{
	int mail_count;
	int news_count;
	int box_count[N_BOXES];
	int ix;
	int diff;
	int announce_boxes;
	char *msg_received;
	int backup_dir;
	int action_flags;
	os_error *error;
	char *name;
	char time_stamp[5];
	os_regset regs;
	char *p;
	char *fname_mail_in=NULL;
	FILE *f;
	int  n_files;
	int  file;
	int  still_fetching = 0;

#define N_DEBATCH_FILES   48
	char leafname[N_DEBATCH_FILES][16];
	char path[160];
	char buf[80];
	char fname_temp[128];
	char fname_backup[128];

	static char *pluto_backup_news = "%sBackup.News1.%s";
	static char *pluto_backup_mail = "%sBackup.Mail1.%s";
	static char *msg_previous = "Previous Debatch was interrupted.  Read ";


	if(lock_expiry)
	{
		werr(0,err_expiring);
		return(-1);
	}

	if(check_lock_lists(0xffff+0x20000) != 0)    /* don't display "busy" */
		return(0);   /* check for any multi-threading */

	set_lock_lists(2,NULL);
	visdelay2_begin();
	visdelay2_percent(0);

	call_event_process(0);

	memset(time_stamp,0,sizeof(time_stamp));
	for(ix=0; ix<N_BOXES; ix++)
	{
		box_count[ix] = boxes_unread_count[ix];
	}

	acks_held = 0;
	acks_sent = 0;

	news_count = 0;
	backup_dir = 0;

	if((control & 2) && (options.news_transport != 0))
	{
		sprintf(fname_temp,"%stmp.news",pluto_path);

		if(get_filelength(fname_temp) > 0)
		{
			sprintf(path,"%snews from %s?",msg_previous,fname_temp);
			if(query2(path,"Yes","No"))
				news_count = debatch_file(fname_temp,X_NEWS+0x10,-1,0x142,time_stamp);   /* raw news */

			news_backup(options.news_backups,X_NEWS);
			sprintf(fname_backup,pluto_backup_news,pluto_path,"old");
			file_move(fname_temp,fname_backup);
		}

		/* make sure that all subscribed groups are in the sources file */
		load_fetch_list();    /* list of individual news articles being fetched */
		if((transport_opts & TOPS_NEWS_MULT) == 0)
		{
			/* single raw news file */
			if(get_filelength(options.news_in) > 0)
			{
				if((announce & 0x200) == 0)
					cardfile_new_to_unread(2);  /* change all new->unread */

				news_count += debatch_file(options.news_in,X_NEWS+0x10,-1,0x142,time_stamp);   /* raw news */

				if(news_count > 0)
				{
					news_backup(options.news_backups,X_NEWS);

					sprintf(fname_backup,pluto_backup_news,pluto_path,"news");
					if(options.news_backups == 0)
						file_delete(options.news_in);
					else
						file_move(options.news_in,fname_backup);
				}
			}
		}
		else
		{
			/* debatch all the files in the directory */
			regs.r[0] = 10;
			regs.r[1] = (int)options.news_in;
			regs.r[2] = (int)buf;
			regs.r[3] = 1;
			regs.r[4] = 0;
			regs.r[5] = sizeof(buf);
			regs.r[6] = 0;

			n_files = 0;
			while(regs.r[3] > 0)
			{
				error = os_swix(0x0c,&regs);           /* OS_GBPB 10, read directory entries */
				if((error != NULL) || (regs.r[3] == 0))
					break;

				buf[20+sizeof(leafname[0])-1] = 0;
				strcpy(leafname[n_files++],&buf[20]);
				if(n_files >= N_DEBATCH_FILES)
					break;
			}

			for(file=0; file<n_files; file++)
			{
				name = leafname[file];
				sprintf(path,"%s.%s",options.news_in,name);

				f = fopen(path,"r");  /* check that the file is readable */
				if(f == NULL)
				{
					/* failed to read a news file, probably still fetching.
					   Don't delete the fetched-articles file */
					still_fetching = 1;
					continue;
				}
				fclose(f);

				if(get_filelength(path) > 0)
				{
					if((strlen(name)==9) && (strcmp(&name[3],"NewGrp")==0))
					{
						/* list of new user groups */
						append_new_groups(path);
						remove(path);
					}
					else if(strcmp(name,"ActiveList")==0)
					{
						/* leave ActiveList */
					}
					else
					{
						if(news_count == 0)
						{
							if((announce & 0x200) == 0)
								cardfile_new_to_unread(2);  /* change all new->unread */
						}

						visdelay2_percent(1);

						file_move(path,fname_temp);
						news_count += debatch_file(fname_temp,X_NEWS+0x10,-1,0x142,time_stamp);
						if((news_count > 0) && (backup_dir==0))
						{
							news_backup(options.news_backups,X_NEWS);
							backup_dir=1;
						}
						sprintf(fname_backup,pluto_backup_news,pluto_path,name);

						if(options.news_backups == 0)
							file_delete(fname_temp);
						else
							file_move(fname_temp,fname_backup);
					}
				}
			}
		}

		if(transport_opts & TOPS_VOYAGER)
		{
			/* switch off Voyager flashing indicators */
			voyager_status(2);
		}

		if(still_fetching)
			free_fetch_list(news_count,NULL);
		else
			free_fetch_list(news_count,time_stamp);
		remove(fname_temp);
	}


	mail_count = 0;
	backup_dir = 0;
	action_flags = 0x1a2;
	if(transport_opts & TOPS_MAIL_FROM)
		action_flags = 0x41a2;   /* "From " separator */

	if((control & 1) && (options.mail_transport != 0))
	{
		sprintf(fname_temp,"%stmp.mail",pluto_path);
		if(get_filelength(fname_temp) > 0)
		{
			sprintf(path,"%smail from %s?",msg_previous,fname_temp);
			if(query2(path,"Yes","No"))
				news_count = debatch_file(fname_temp,X_NEWS+0x10,-1,0x142,time_stamp);   /* raw mail */

			news_backup(options.mail_backups,X_MAIL);
			sprintf(fname_backup,pluto_backup_mail,pluto_path,"old");
			file_move(fname_temp,fname_backup);
		}

		f_leave_mail = NULL;

		if(options.leave_undelivered_mail == 1)
		{
			f_leave_mail = fopen_werr(fname_leave,"w",NULL);
		}

		if((transport_opts & TOPS_MAIL_MULT) == 0)
		{
			/* single raw mail file */
			fname_mail_in = options.mail_in;
			if(get_filelength(fname_mail_in) > 0)
			{
				if((announce & 0x200) == 0)
					cardfile_new_to_unread(1);  /* change all new->unread */

				mail_count = debatch_file(options.mail_in,X_MAIL+0x10,-1,action_flags,NULL);    /* raw mail */

				if(mail_count > 0)
				{
					news_backup(options.mail_backups,X_MAIL);

					sprintf(fname_backup,pluto_backup_mail,pluto_path,"email");
					if(options.mail_backups == 0)
						file_delete(options.mail_in);
					else
						file_move(options.mail_in,fname_backup);
				}
			}
		}
		else
		{
			/* debatch all the files in the directory */
			regs.r[0] = 10;
			regs.r[1] = (int)options.mail_in;
			regs.r[2] = (int)buf;
			regs.r[3] = 1;
			regs.r[4] = 0;
			regs.r[5] = sizeof(buf);
			regs.r[6] = 0;

			n_files = 0;
			while(regs.r[3] > 0)
			{
				error = os_swix(0x0c,&regs);           /* OS_GBPB 10, read directory entries */
				if((error != NULL) || (regs.r[3] == 0))
					break;

				strcpy(leafname[n_files++],&buf[20]);
				if(n_files >= N_DEBATCH_FILES)
					break;
			}

			for(file=0; file<n_files; file++)
			{
				sprintf(path,"%s.%s",options.mail_in,leafname[file]);

				f = fopen(path,"r");   /*check that raw mail file is readable */
				if(f == NULL)
					continue;
				fclose(f);

				if(get_filelength(path) > 0)
				{
					if(mail_count == 0)
					{
						if((announce & 0x200) == 0)
							cardfile_new_to_unread(1);  /* change all new->unread */
					}

					fname_mail_in = path;
					file_move(path,fname_temp);
					mail_count += debatch_file(fname_temp,X_MAIL+0x10,-1,action_flags,NULL);

					if((mail_count > 0) && (backup_dir == 0))
					{

						news_backup(options.mail_backups,X_MAIL);
						backup_dir = 1;
					}
					sprintf(fname_backup,pluto_backup_mail,pluto_path,leafname[file]);
					if(options.mail_backups == 0)
						file_delete(fname_temp);
					else
						file_move(fname_temp,fname_backup);
				}
			}
		}

		if(transport_opts & TOPS_VOYAGER)
		{
			/* switch off Voyager flashing indicators */
			voyager_status(0);
		}

		/* return any undelivered emails to the input queue */
		if(f_leave_mail)
		{
			fclose(f_leave_mail);
			f_leave_mail = NULL;
			if((get_filelength(fname_leave) > 0) && (fname_mail_in != NULL))
				file_move(fname_leave,fname_mail_in);

			/* set access rights of undelivered mail to RW/rw */
			regs.r[0] = 4;        /* write object attributes */
			regs.r[1] = (int)fname_mail_in;
			regs.r[5] = 0x33;     /* RW/rw access */
			os_swix(0x08,&regs);   /* OS_File 4 */
		}

		remove(fname_temp);
	}


	call_event_process(8);

	p = "s";
	if(control == 1)
	{
		if(mail_count==1)
			p = "";
	}
	else
	{
		if(news_count==1)
			p = "";
	}

	switch(control & 3)
	{
	case 1:
		sprintf(buf,msgs_lookup("Y16"),mail_count,p);
		break;
	case 2:
		sprintf(buf,msgs_lookup("Y17"),news_count,p);
		break;
	case 3:
		sprintf(buf,msgs_lookup("Y18"),mail_count,news_count,p);
		break;
	}

	if((news_count + mail_count) > 0)
	{
		if((announce & 0x100) == 0)
			set_boxlist_extent(0x47);   /* open boxlist window - was (0x43) */
		else
			set_boxlist_extent(6);      /* recalc and display if already open */
	}

	if((announce & 0xf) > 0)
	{
		announce_boxes = 0;
		diff = 0;
		for(ix=0; ix<N_BOXES; ix++)
		{
			if(box_table[ix].flags & BOX_ANNOUNCE)
			{
				announce_boxes = 1;
				if(boxes_unread_count[ix] > box_count[ix])
				{
					/* New messages have arrived in this box */
					diff = 1;
				}
			}
		}

		if(announce_boxes == 0)
		{
			/* No "Announce delivery" options set for any boxes, use the
			   old "Loaded x email y news" announcement */
			if(((announce & 0xf) > 1) ||  ((news_count + mail_count) > 0))
				announce_message(buf,2);
		}
		else if(diff > 0)
		{
			/* Received messages on boxes which have "Announce delivery"
			   option set */
			msg_received = "Received,  ";
			buf[0] = 0;
			for(ix=0; ix<N_BOXES; ix++)
			{
				if((box_table[ix].flags & BOX_ANNOUNCE) &&
						((diff = (boxes_unread_count[ix]-box_count[ix])) > 0))
				{
					if(buf[0] != 0)
					{
						strcat(buf,", ");
						announce_message(buf,1);
					}
					sprintf(buf,"%s%s, %d",msg_received,box_table[ix].name,diff);
					msg_received = "";
				}
			}
			if(buf[0] != 0)
			{
				strcat(buf,". ");
				announce_message(buf,1);
			}
		}

		if(acks_sent > 0)
		{
			p = "s";
			if(acks_sent==1)
				p = "";
			sprintf(buf,msgs_lookup("Y19"),acks_sent,p);
			announce_message(buf,1);
		}
	}

	visdelay2_end();
	clear_lock_lists(2);

	if((options.send_mail_acks==1) && (acks_held > 0))
		posted_open_list();
	else
		posted_make_list(7);
	return(mail_count + news_count);
}   /* end of read_raw_news */



void auto_debatch(int time, void *handle)
/************************************/
{
	if(options.auto_debatch == 0)
		return;

	if((time != 0) && (lock_lists == 0))
	{
		read_raw_news(3,1);

		/* ANT inetsuite, do a send if there are any outgoing messages waiting */
	}

	if(alarm_anypending((void *)124) == 0)
		alarm_set(alarm_timenow() + options.auto_debatch*6000, auto_debatch, (void *)124);
}   /* end of auto_debatch */





/********************************************************************************/
/*            MAKE DIGEST              */
/********************************************************************************/
extern char *get_current_date_string(int *date_enc);
extern char *postedlist_dir(int type);
extern char *reply_extract_email_addr(char *buf, int control);


#define N_DIGEST_FILES 40

void digest_make(char *fname_selected)
/************************************/
{
	FILE *f;
	FILE *f_msg;
	FILE *f_env;
	int  c;
	char *directory;
	char *directory_env;
	char *message_id;
	OPTIONS_MAILBOX *user=NULL;
	int  err;
	int  ix;
	char *user_addr;
	int  env_length;
	int  file_count = 0;
	os_error *error;
	os_regset regs;
	char *fname_envelope = "<pluto$dir>.tmp.digest_env";
	char leafname[12];
	char fname[140];
	char fname_digest[140];
	char boundary[30];
	char buf[256];
	char buf2[80];
	char digested[N_DIGEST_FILES][12];

	static char *digest_err[] = {
		"Not a mailing list broadcast",
		"Message is not in the mail out directory",
		"Can't recognise To: address as a mailing list",
		"Can't read envelope file"
	};


	directory = postedlist_dir(1);      /* mail out */
	directory_env = postedlist_dir(0);  /* mail envelopes */


	/* is the selected item a broadcast email message ? */
	err = 0;
	if((fname_selected[0] != 'X') && (fname_selected[0] != 'P'))
	{
		err = 1;
	}
	else
	{
		sprintf(fname,"%s.%s",directory,fname_selected);
		f = fopen(fname,"r");
		if(f==NULL)
		{
			err = 2;
		}
		else
		{
			while(!feof(f))
			{
				if(fgets(buf,sizeof(buf),f) == NULL)
					break;

				if((buf[0] == '\n') || (buf[0] == '\r'))
					break;   /* end of header */

				if(memcmp(buf,"To: ",4) == 0)
				{
					user_addr = reply_extract_email_addr(&buf[4],3);
					if(user_addr == NULL)
						err = 3;
					else
					{
						for(ix=0; ix<N_MAIL_BOX; ix++)
						{
							user = &options.mailbox[ix];
							if(user->email_addr[0] == 0)
								continue;

							if(strcmp_lc(user_addr,user->email_addr) == 0)
							{
								break;
							}
						}
						if(ix == N_MAIL_BOX)
							err = 3;
					}
				}
			}
			fclose(f);
		}
		if(user == NULL)
			err = 3;
	}
	if(err == 0)
	{
		sprintf(fname,"%s.%s",directory_env,fname_selected);
		env_length = get_filelength(fname);
		file_copy(fname,fname_envelope);

		f_env = fopen(fname_envelope,"r");
		if((f_env == NULL) || (env_length <= 0))
			err = 4;
	}

	if(err != 0)
	{
		werr(0,"Digest: error with selected message: %s",digest_err[err-1]);
		return;
	}

	message_id = get_message_id(0,5);
	sprintf(fname_digest,"%stmp.digest_msg",pluto_path);
	f = fopen_werr(fname_digest,"w",NULL);
	if(f == NULL)
		return;

	sprintf(boundary,"digest--%s",message_id);


	regs.r[0] = 10;
	regs.r[1] = (int)directory;
	regs.r[2] = (int)buf;
	regs.r[3] = 1;
	regs.r[4] = 0;
	regs.r[5] = sizeof(buf);
	regs.r[6] = 0;

	while((regs.r[3] > 0) && (file_count < N_DIGEST_FILES))
	{
		error = os_swix(0x0c,&regs);           /* OS_GBPB 10, read directory entries */
		if((error != NULL) || (regs.r[3] == 0))
			break;

		strcpy(leafname,&buf[20]);

		c = leafname[0];
		if((c == 'X') || (c == 'P'))
		{
			sprintf(fname,"%s.%s",directory_env,leafname);
			if(get_filelength(fname) != env_length)
				continue;  /* envelope file is different */

			f_msg = fopen_werr(fname,"r",NULL);
			if(f_msg == NULL)
				continue;

			/* compare the contents of the envelope files */
			rewind(f_env);
			err = 0;
			for(;;)
			{
				fgets(buf,sizeof(buf),f_env);
				fgets(buf2,sizeof(buf2),f_msg);

				if(feof(f_env) && feof(f_msg))
					break;

				if(strcmp(buf,buf2) != 0)
				{
					err = 1;
					break;
				}
			}
			if(err)
			{
				/* envelope files do not match */
				continue;
			}
			fclose(f_msg);

			sprintf(fname,"%s.%s",directory,leafname);
			f_msg = fopen_werr(fname,"r",NULL);
			if(f_msg == NULL)
				continue;

			fprintf(f,"\n--%s\nContent-Type: message/rfc822\n\n",boundary);
			while(!feof(f_msg))
			{
				if(fgets(buf,sizeof(buf),f_msg) == NULL)
					break;

				/* skip lines in the message header */
				if(memcmp_lc(buf,"precedence: ",12)==0)
					continue;
				if(memcmp_lc(buf,"reply-to: ",10)==0)
					continue;

				fprintf(f,"%s",buf);
			}
			fclose(f_msg);

			strcpy(digested[file_count++],leafname);
		}
	}
	fprintf(f,"\n--%s--\n",boundary);
	fclose(f);
	fclose(f_env);

	sprintf(fname,"%s.%s",directory_env,message_id);
	file_move(fname_envelope,fname);
	sprintf(fname,"%s.%s",directory,message_id);

	f = fopen_werr(fname,"w",NULL);
	f_msg = fopen_werr(fname_digest,"r",NULL);

	if((f != NULL) && (f_msg != NULL))
	{
		fprintf(f,"MIME-Version: 1.0\nDate: %s\n",get_current_date_string(NULL));
		fprintf(f,"From: %s\n",user->email_addr);
		fprintf(f,"To: %s\n",user->email_addr);
		fprintf(f,"Subject: %s, %d messages\n",user->full_name,file_count);
		fprintf(f,"Message-ID: <%s%s>\n",message_id,user->email_addr);
		fprintf(f,"Content-Type: multipart/digest; boundary=\"%s\"\n",boundary);
		fprintf(f,"Precedence: Bulk\n");

		while(!feof(f_msg))
		{
			c = fgetc(f_msg);
			if(!feof(f_msg))
			{
				fputc(c,f);
			}
		}
		fclose(f);
		fclose(f_msg);
		remove(fname_digest);
	}


	/* now delete the originals */
	for(ix=0; ix<file_count; ix++)
	{
		sprintf(fname,"%s.%s",directory,digested[ix]);
		remove(fname);
		sprintf(fname,"%s.%s",directory_env,digested[ix]);
		remove(fname);
	}

	werr(0,"Digest completed, %d messages",file_count);
}   /* end of digest_make */




/********************************************************************************/
/*                      POSTED MESSAGE MANAGEMENT                               */
/********************************************************************************/

static int posted_waiting=0;
static int posted_held = 0;

static int n_posted = 0;
static int n_posted_list_previous = 0;
static POSTED_LIST *posted_list = NULL;
static POSTED_LIST *posted_list_previous = NULL;
static char *posted_cache_refresh=NULL;

extern BLIST postedlist;
extern int standard_font;
extern int status_sprite_offset;
extern int lists_line_height;




void postedlist_open(int open)
/****************************/
{
	blist_set_extent(&postedlist,open+0x40);   /* opn full_size */
}


void postedlist_status_all(int status)
/************************************/
{
	int  i;

	for(i=0; i<n_posted; i++)
		posted_list[i].selected = status;
	redraw_blist(&postedlist);
}   /* end of postedlist_status_all */



char *postedlist_dir(int type)
/****************************/
{
	switch(type)
	{
	case 0:
		return(options.mail_envs);
	case 1:
		return(options.mail_out);
	case 2:
		return(options.news_out);
	case 4:
		return("<Pluto$Dir>.Hold.Envs");
	case 5:
		return("<Pluto$Dir>.Hold.Mail");
	case 6:
	case 7:
		return("<Pluto$Dir>.Hold.News");

	case 8:   /* news fetch list */
		return(options.ngroups_data);
	case 9:
		return("<Pluto$Dir>.Hold.Fetch"); /* held news fetch list */
	}
	return("");
}   /* end of postedlist_dir */






CARD *posted_find_article(char *id)
/*********************************/
/* Search cardfile for an article which has this id in its comment field */
{
	char *p;
	int  ix;
	CARD *cptr;
	unsigned int *ixlist;
	int n_entries;

	ixlist = list_fr[0].ixlist;
	n_entries = list_fr[0].n_entries;

	for(ix=0; ix<n_entries; ix++)
	{
		cptr = (CARD *)((ixlist[ix] & IXLIST_MASK) << 2);
		p = &cptr->data[cptr->d_comment];
		if(*p == 0)
			continue;

		if((cptr->date_box >> 26) == BOX_BIN)
			continue;

		if(strcmp(id,&cptr->data[cptr->d_comment]) == 0)
			return(cptr);
	}

	return(NULL);   /* not found */
}   /* end of posted_find_article */






void postedlist_delete()
/**********************/
/* Delete selected articles */
{
	int  i;
	POSTED_LIST *pl;
	char fname[256];

	for(i=0; i<n_posted; i++)
	{
		if(!posted_list[i].selected)
			continue;

		pl = &posted_list[i];

		sprintf(fname,"%s.%s",postedlist_dir(pl->type),pl->fname);
		file_delete(fname);

		/* Voyager has an additional envelope file for mail messages */
		if((transport_opts & TOPS_ENVS_FILES) && ((pl->type & 3)== 1))
		{
			sprintf(fname,"%s.%s",postedlist_dir(pl->type & ~1),pl->fname);
			file_delete(fname);
		}

		if(pl->card == NULL)
		{
			pl->card = posted_find_article(pl->fname);
		}

		if(pl->card != NULL)
		{
			if(cardfile_remove(NULL,pl->card,BOX_BIN) < 0)
				break;    /* check_lock_lists failed */
		}
	}
	postedlist_status_all(0);
	/*   postedlist_open(3); */
	posted_make_list(7);   /* re-calculate and display the list */
}   /* end of postedlist_delete */




void file_move_append(char *fname1, char *fname2)
/***********************************************/
{
	int  c;
	FILE *f1, *f2;

	if((f1 = fopen_werr(fname1,"r",NULL)) == NULL)
		return;

	if((f2 = fopen_werr(fname2,"a",NULL)) == NULL)
	{
		fclose(f1);
		return;
	}

	while(!feof(f1))
	{
		c = fgetc(f1);
		if(!feof(f1))
			fputc(c,f2);
	}
	fclose(f2);
	fclose(f1);
	remove(fname1);
}   /* file_move_append */




void postedlist_hold(int hold)
/****************************/
/* Hold/Unhold selected articles */
{
	int  i;
	int  type;
	POSTED_LIST *pl;
	char fname[200];
	char fnameH[200];
	static char held_type[10] =
	{4,5,6,7,4,5,6,7,9,9};
	static char unheld_type[10] =
	{0,1,2,3,0,1,2,3,8,8};

	for(i=0; i<n_posted; i++)
	{
		if(!posted_list[i].selected)
			continue;

		pl = &posted_list[i];

		type = unheld_type[pl->type];
		sprintf(fname,"%s.%s",postedlist_dir(type),pl->fname);
		sprintf(fnameH,"%s.%s",postedlist_dir(held_type[type]),pl->fname);

		if(type == 8)
		{
			if(hold)
				file_move_append(fname,fnameH);
			else
				file_move_append(fnameH,fname);
		}
		else
		{
			if(hold)
				file_move(fname,fnameH);
			else
				file_move(fnameH,fname);
		}


		/* Voyager has an additional envelope file for mail messages */
		if((transport_opts & TOPS_ENVS_FILES) && (type == 1))
		{
			sprintf(fname,"%s.%s",postedlist_dir(0),pl->fname);
			sprintf(fnameH,"%s.%s",postedlist_dir(4),pl->fname);

			if(hold)
				file_move(fname,fnameH);
			else
				file_move(fnameH,fname);
		}
	}

	postedlist_status_all(0);
	/*   postedlist_open(3); */
	posted_make_list(7);   /* re-calculate and display the list */
}   /* end of postedlist_hold */




void postedlist_edit(int linenum, int adjust)
/*******************************************/
{
	POSTED_LIST *pl;
	int  type;
	char fname[200];

	/* Really, we need External Edit to tell us when the file
	   has been editied, so we can delete the original mail/new log
	   article and replace it with the new version of this file */

	pl = &posted_list[linenum];
	/*   if(pl->fname == 0)
	      return;
	*/
	type = pl->type;
	if((transport_opts & TOPS_ENVS_FILES) == 0)
		adjust = 0;

	if((adjust) && ((type==1) || (type==5)))
	{
		/* show envelope rather than mail message */
		type ^= 1;
	}

	sprintf(fname,"%s.%s",postedlist_dir(type),pl->fname);

	if(adjust)
	{
		/* edit in place, don't reload into Pluto */
		dataopen(fname,0xfff);
	}
	else
	{
		OLE_start(fname,0xfff,1,postedlist.w_list,0,NULL);
	}

}   /* end of postedlist_edit */





void postedlist_digest()
/**********************/
/* Make a digest of this and similar articles */
{
	int  i;

	for(i=0; i<n_posted; i++)
	{
		if(!posted_list[i].selected)
			continue;

		digest_make(posted_list[i].fname);
		break;
	}
	posted_make_list(7);   /* re-calculate and display the list */
}   /* end of postedlist_digest */




void postedlist_select(int line,int selected)
/***************************************/
{
	if(selected == 2)
		posted_list[line].selected ^= 1;
	else
		posted_list[line].selected = selected;
	redraw_blist_line(&postedlist,line);
}   /* end of postedlist_selected */




void postedlist_click_window(BLIST *b,int linenum,int bbits)
/********************************************************/
{
	POSTED_LIST *pl;
	int  i;

	pl = &posted_list[linenum];

	switch(bbits)
	{
	case wimp_BCLICKLEFT:
		for(i=0; i<n_posted; i++)
		{
			if(posted_list[i].selected)
			{
				posted_list[i].selected = 0;
				redraw_blist_line(b,i);
			}
		}

		pl->selected = 1;
		redraw_blist_line(b,linenum);
		break;

	case wimp_BCLICKRIGHT:
		pl->selected ^= 1;
		redraw_blist_line(b,linenum);
		break;

	case wimp_BLEFT:
		postedlist_edit(linenum,0);
		break;

	case wimp_BRIGHT:        /* adjust, 2nd click */
		postedlist_edit(linenum,1);
		break;
	}
}   /* end of postedlist_click_window */






void postedlist_key_window(BLIST *b,wimp_eventdata *d)
/***************************************************/
{
	int  c;

	switch(c = d->key.chcode)
	{
	case 01:   /* CTRL-A */
		postedlist_status_all(1);
		break;

	case 24:   /* CTRL-X */
		postedlist_delete();
		break;

	case 26:   /* CTRL-Z */
		postedlist_status_all(0);
		break;

	case 04:   /* CTRL-D */
		if(akbd_pollsh())
		{
			postedlist_digest();
		}
		break;

	default:
		wimp_processkey(c);
		break;
	}
}   /* end of postedlist_key_window */





void postedlist_display_window(BLIST *b,wimp_redrawstr *r,int line,int end_line,int x,int y)
/******************************************************************************************/
{
	int  n_chars;
	int  type;
	int  width;
	POSTED_LIST *pl;
	os_regset regs;
	static char *attachment = "+";
	static char status_icon[10] =
	{0x20,0x21,0x22,0x22,0x24,0x25,0x26,0x26,0x22,0x26};

	for(line=line; line<end_line; line++)
	{
		if(line >= b->n_entries)
			break;

		pl = &posted_list[line];
		width = 380;

		list_set_colour(0,pl->selected ^ 1,x,y);

		if(standard_font >= 0)
		{
			n_chars = strlen(pl->title);

			print_justify(x+960-128,y,120,pl->size);
			paint_string(pl->title,x+66,y,width);
			paint_string(pl->author,x+86+width,y,960-204-width);

			if(pl->attachment)
			{
				regs.r[0] = standard_font;
				regs.r[1] = (int)attachment;
				regs.r[2] = 0x190;    /* bit 4, bit 7, bit 8 */
				regs.r[3] = x+44;
				regs.r[4] = y+4;
				regs.r[7] = 1;
				os_swi(0x40086,&regs);
			}
		}
		else
		{
			bbc_move(x+44,y-4);
			if(pl->attachment)
				printf(attachment);
			else
				printf(" ");

			pl->title[25] = 0;
			printf("%s",pl->title);

			bbc_move(x+width+96, y-4);
			pl->author[23] = 0;
			printf("%s",pl->author);

			bbc_move(x+960-130, y-4);
			printf("%7d",pl->size);
		}

		type = pl->type;
		if(type == 3) type = 2;
		display_icon(status_icon[pl->type],2,y - r->box.y1 + r->scy + status_sprite_offset,1);

		y -= lists_line_height;
	}
}   /* postedlist_display_window */




void posted_read_header(POSTED_LIST *pl, char *fname, int type)
/*************************************************************/
/* type: 0 To:  1 From:  2 Subject (into author)  3 Newsgroup:  4 Subject (into title)  */
{
	FILE *f;
	int  i;
	char *string;
	int  length;
	char buf[256];

	static char *strings[] = {"To: ","From: ","Subject: ", "Newsgroups: ", "Subject: "};

	/* look through previous posted_list for this filename */
	if(posted_list_previous)
	{
		for(i=0; i<n_posted_list_previous; i++)
		{
			if(strcmp(pl->fname,posted_list_previous[i].fname)==0)
			{
				pl->size = posted_list_previous[i].size;
				if(type == 4)
					strcpy(pl->title,posted_list_previous[i].title);
				else
					strcpy(pl->author,posted_list_previous[i].author);
				return;
			}
		}
	}

	pl->size = get_filelength(fname);

	f = fopen(fname,"r");
	if(f == NULL)
		return;

	string = strings[type];
	length = strlen(string);

	while(!feof(f))
	{
		if(fgets(buf,sizeof(buf),f) == NULL)
			break;

		if((buf[0] == '\n') || (buf[0] == '\r'))
			break;   /* end of header */

		if(memcmp(buf,string,length)==0)
		{
			/* replace NL terminator by 0 */
			i = strlen(buf);
			buf[i-1] = 0;   /* NL */
			if(buf[i-2] < ' ')
				buf[i-2] = 0;  /* CR */

			buf[sizeof(buf)-1] = 0;
			decode_iso8859(&buf[length],0);

			if(memcmp(&buf[length],"Re: ",4)==0)
				length+=4;

			if(type == 4)
				strcpy_printable(pl->title,&buf[length],sizeof(pl->title));
			else
				strcpy_printable(pl->author,&buf[length],sizeof(pl->author));
		}
	}
	fclose(f);
}   /* end of posted_read_header */




int posted_read_titles(int type, int base, POSTED_LIST *list)
/***********************************************************/
{
	int  count = 0;
	int  msg_type;
	int  c;
	POSTED_LIST *pl;
	char *directory;
	os_error *error;
	os_regset regs;
	char buf[64];
	char fname[128];

	if(type==3)
		return(0);

	if(((type <= 1) && (options.mail_transport==0)) ||
			((type == 2) && (options.news_transport==0)))
	{
		return(0);
	}

	directory = postedlist_dir(type);

	regs.r[0] = 10;
	regs.r[1] = (int)directory;
	regs.r[2] = (int)buf;
	regs.r[3] = 1;
	regs.r[4] = 0;
	regs.r[5] = sizeof(buf);
	regs.r[6] = 0;

	while(regs.r[3] > 0)
	{
		error = os_swix(0x0c,&regs);           /* OS_GBPB 10, read directory entries */
		if((error != NULL) || (regs.r[3] == 0))
			break;

		if((type==3) && (!isdigit(buf[20])))
		{
			if(memcmp(&buf[20],"nn",2)==0)
				return(0); /* don't show OG if there are any IC */
			continue;  /* don't show any non numeric files */
		}

		if((type==8) || (type==9))
		{
			/* fetch list for news */
			switch(options.news_transport)
			{
			case X_NEWSHOUND:
				if((memcmp(&buf[23],"Get",3) != 0) &&
						(memcmp(&buf[23],"Fet",3) != 0))
					continue;
				break;

			case X_ANT:
				if(strcmp(&buf[20],"/fetch") != 0)
					continue;
				break;

			default:
				continue;    /* no fetch list for this news transport */
			}
		}


		if(list != NULL)
		{
			/* add title of article to list */
			pl = &list[base+count];

			pl->card = NULL;
			pl->type = type;
			pl->author[0] = 0;
			pl->wide = 0;
			strcpy(pl->fname,&buf[20]);
			sprintf(fname,"%s.%s",directory,pl->fname);

			c = pl->fname[0];

			if((c >= 'P') && (c <= 'Z'))
			{
				msg_type = 'Z' - pl->fname[0] + 2;
			}
			else
			{
				msg_type = 0;
			}

			switch(msg_type & 0x7)
			{
			case 2:
				strcpy(pl->title,"Ack");    /* email acknowledgement */
				posted_read_header(pl,fname,0);
				break;

			case 3:
				strcpy(pl->title,"Bounce");
				posted_read_header(pl,fname,2);
				break;

			case 4:
				strcpy(pl->title,"Broadcast");
				posted_read_header(pl,fname,1);
				break;

			case 5:
				strcpy(pl->title,"Digest");
				posted_read_header(pl,fname,2);
				break;

			default:
				if((type == 8) || (type == 9))
				{
					strcpy(pl->author,pl->fname);
					strcpy(pl->title,"FETCH BODIES");
				}
				else if(memcmp(pl->fname,"jm",2)==0)
				{
					strcpy(pl->title,"JunkMail");
					posted_read_header(pl,fname,2);
				}
				else
				{
					posted_read_header(pl,fname,4);

					if((type & 3) > 1)
						posted_read_header(pl,fname,3);   /* Newsgroups: */
					else
						posted_read_header(pl,fname,0);   /* To: */
					pl->wide = 1;

#ifdef deleted
					cptr = posted_find_article(&buf[20]);
					pl->card = cptr;

					if(cptr != NULL)
					{
						strncpy(pl->title,&cptr->data[cptr->d_title],sizeof(pl->title));
						pl->title[sizeof(pl->title)-1]=0;

						strncpy(pl->author,&cptr->data[cptr->d_author],sizeof(pl->author));
						pl->author[sizeof(pl->author)-1]=0;

						pl->wide = 1;
					}
					else
					{
						strcpy(pl->title,"???");
					}
#endif
				}
				break;
			}

			/* does message have an attachment */
			pl->attachment = (msg_type & 0x8);
		}
		count++;
	}
	return(count);
}   /* end of posted_read_titles */




void posted_cache_delete(char *fname)
/***********************************/
{
	posted_cache_refresh = fname;
}   /* end of posted_cache_delete */



void posted_make_list(int open)
/*****************************/
{
	int  i;
	int  count;
	static char types[8] = {0,2,3,6,1,5,8,9};
	char counts[8];
	char counts_acc[8];

#ifdef deleted
	if((options.news_transport == 0) && (options.mail_transport == 0))
	{
		err_no_transport();
		return;
	}
#endif

	/* count number of outgoing articles */
	counts_acc[0] = 0;
	for(i=1; i<=7; i++)
	{
		counts_acc[i] = counts[i] = posted_read_titles(types[i],0,NULL);
		counts_acc[i] += counts_acc[i-1];
	}
	count = counts_acc[7];

	posted_waiting = counts[1]+counts[4]+counts[2]+counts[6];
	posted_held = counts[3]+counts[5]+counts[7];


	n_posted_list_previous = n_posted;
	posted_list_previous = posted_list;

	if(posted_cache_refresh != NULL)
	{
		/* force a re-read of title from this file */
		for(i=0; i<n_posted_list_previous; i++)
		{
			if(strcmp(posted_cache_refresh,posted_list_previous[i].fname)==0)
			{
				posted_list_previous[i].fname[0] = 0;
			}
		}
	}
	posted_cache_refresh = NULL;

	posted_list = calloc(count,sizeof(POSTED_LIST));
	if(posted_list == NULL)
	{
		malloc_err(21);
		return;
	}
	n_posted = count;


	/* read the outgoing article titles */
	for(i=1; i<=7; i++)
	{
		if(counts_acc[i] > counts_acc[i-1])
			posted_read_titles(types[i],counts_acc[i-1],posted_list);
	}

	postedlist.n_entries = count;
	if(postedlist.open)
	{
		if((count==0) && (options.close_og_list!=0))
		{
			/* list is now empty, close it */
			blist_close(&postedlist);
		}
		else
		{
			postedlist_open(open);
		}
	}

	box_set_postedlist_icon(posted_waiting,posted_held);

	if(posted_list_previous != NULL)
	{
		free(posted_list_previous);
		posted_list_previous = NULL;
	}
	n_posted_list_previous = 0;
}   /* end of posted_make_list */



void postedlist_reopen()
/**********************/
/* A message has been added to the outgoing queue */
{
	posted_make_list(7);
}   /* end of postedlist_reopen */



void postedlist_click_buttons(BLIST *b, wimp_eventdata *d)
/********************************************************/
/* Click on the posted articles list button bar */
{
	int  icon;
	int  click;

	icon = d->but.m.i;
	click = d->but.m.bbits;

	switch(icon)
	{
	case 3:   /* delete */
		postedlist_delete();
		break;

	case 1:   /* un-hold */
		postedlist_hold(0);
		break;

	case 2:   /* hold */
		postedlist_hold(1);
		break;
	}
}   /* end of postedlist_click_buttons */



int postedlist_check_dir(int type)
/********************************/
/* Count total size of files in outgoing directories */
{
	int  total=0;
	os_error *error;
	os_regset regs;
	int buf[12];

	if(((type <= 1) && (options.mail_transport==0)) ||
			((type == 2) && (options.news_transport==0)))
	{
		return(0);
	}

	regs.r[0] = 10;
	regs.r[1] = (int)postedlist_dir(type);
	regs.r[2] = (int)buf;
	regs.r[3] = 1;
	regs.r[4] = 0;
	regs.r[5] = sizeof(buf);
	regs.r[6] = 0;

	while(regs.r[3] > 0)
	{
		error = os_swix(0x0c,&regs);           /* OS_GBPB 10, read directory entries */
		if((error != NULL) || (regs.r[3] == 0))
			break;

		total += buf[2];
	}

	return(total);
}   /* end of postedlist_check_dir */




void postedlist_alarm_handler(int called_at, void *handle)
/********************************************************/
/* Called with handle=NULL when window opens */
{
	int total;
	int  period;
	static int last_total;

	if(handle==NULL)
		last_total = -1;

	period = 12000;  /* 2 minutes */
	if(options.poll_og)
		period = 300;  /* 3 seconds */


	if(postedlist.open || (boxlist.open && posted_waiting))
	{
		total = postedlist_check_dir(1) + postedlist_check_dir(2);

		if(transport_opts & TOPS_NEWS_FETCH)
		{
			/* There may be a list of message ids to be fetched */
			total += postedlist_check_dir(8);
		}

		if(total != last_total)
		{
			/* don't remake the list unless something's changed */
			posted_make_list(7);
			last_total = total;
		}
	}

	/* set next alarm time */
	if(postedlist.open)
		period = 200;   /* 2 seconds */

	if(alarm_anypending((void *)123) != 0)
		alarm_removeall((void *)123);
	alarm_set(alarm_timenow() + period, postedlist_alarm_handler, (void *)123);  /* 1.5 seconds */
}   /* end of postedlist_alarm_handler */




void posted_open_list()
/********************/
{
	/* open the list and start periodic timing */

	postedlist.open = 1;
	posted_make_list(7);

	if(postedlist.n_entries > 0)
		postedlist_open(3);
	postedlist_alarm_handler(0,NULL);
}   /* end of postedlist_open_list */




void postedlist_init()
/******************/
{
	/* window for list of posted articles */
	blist_register(&postedlist,BLIST_POSTED,"PostedBar");
	posted_make_list(7);
}   /* end of postedlist_init */

