#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <utility/tagitem.h>
#include <dos/dostags.h>
#include <clib/dos_protos.h>
#include <dos.h>
#include <time.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <libraries/dosextens.h>
#include <libraries/locale.h>
#include <proto/exec.h>
#include <clib/locale_protos.h>

/* These are only used in ks1.3 , in 2.0 we use System() */
long SyncRun(char *,char *,BPTR,BPTR);
#pragma libcall ArpBase SyncRun                 021C    109804
struct 	Library *ArpBase=NULL;

#include "/lib/iomodes.h"
#include "/lib/misc.h"

#define UID_NAME_ARRAY
#include "/lib/users.h"

#include "rn.h"
#define STRINGARRAY
#include "rnlanguage.h"

#define VERSTAG		"\0$VER: "
#define VERSION		"AXsh-rn 1.66 (2.12.95)\n"
const static char vers[]=VERSTAG VERSION;

#define NAMELEN		100
#define MAXNAMELEN	256

#define H_FLUSH	'f'	/* forget this entry */
#define H_CLEAR	'c'	/* clear cache */
#define H_GET	'g' /* get header */

#define G_BUF			8192	/* grab buffer size */

/*****************************************************************************
	readnews program for AXsh coded by Pasi Ojala and Juha Tuominen
	 9-Jan-92	Added configuration, conversion routine sf7->ISO.
	16-Jan-92	Some other bits to select (Date, Org, Grab all areas). Changed
				the accesslevel check to be done from the process-UID
	 8-Feb-92	Fixed a pointer bug .. rntidy bought it up
	 9-Feb-92	Really fixed the bug..
	10-Feb-92	Some corrections, some pointer recovery-functions to .newsrc
	25-Feb-92	Better getline (includes hotkeys) and followup-bugfix
	 7-Mar-92	Lowercases to group checks
	16-Mar-92	Continuous-option to more.
	28-Jun-92	Changed the message hierarchy comp.sys.amiga -> comp/sys/amiga
	28-Jun-92	Integrated rnnet and rntidy here too.
	24-Jul-92	Added copyfile() to misc.h
	29-Jul-92	Some bug fixes
	30-Jul-92	Localization added
	 6-Aug-92	Started chopping rn into pieces and rewriting the code
	12-Aug-92	Now everything works a lot like it used to be, a lot todo still
	16-Aug-92	The working version
	26-Aug-92	Now net works like it is supposed to be
	28-Dec-92	Added better Active support - Active is only read, and an
				external postnews is required. Newsrc filename changed to .rnnewsrc
	08-Jan-93	Added a binary article scan routine, %distribution: and
				"more unique" Message-ID:s.
	16-Jan-94	Possibility to have individual configurations for each
				user level (/etc/rc.news.<level>, e.g. rc.news.normal).
				If the corresponding config is not found, the next lowest
				level is tried, and finally rc.news is used.
	02-Jul-95	$REPLYTO added - now works with shell variables - no AXsh needed.
*****************************************************************************/

struct header
{
	int  Number;
	char File[NAMELEN];
	char From[MAXNAMELEN];
	char Subj[MAXNAMELEN];
	char ID[MAXNAMELEN];
	char Xref[MAXNAMELEN];
};

extern	struct ExecBase *SysBase;
extern	struct DosLibrary *DOSBase;

struct 	List grouplist={ (struct Node *)&grouplist.lh_Tail,NULL,(struct Node *)&grouplist.lh_Head };

struct	LocaleBase *LocaleBase;
struct	Catalog *catalog=NULL;

char	Newshome[NAMELEN]=		"AXsh:usr/spool/news/",
		Grabfile[NAMELEN]=		"Grab.rn",
		Batchfile[NAMELEN]=		"AXsh:usr/spool/news/%s.batch",
		Sysfile[NAMELEN]=		"AXsh:usr/spool/news/Sys",
		Activefile[NAMELEN]=	"none",
		Quotestring[NAMELEN]=	"> %s",
		Postnews[NAMELEN]=		"internal",
		Fupref[NAMELEN]=		"In %s %s writes:",
		Sendmail[NAMELEN]=		"AXsh:bin/mailserver %f",
		Netlogfile[NAMELEN]=	"AXsh:etc/adm/netlog",
		Newsgroupfile[NAMELEN]= "AXsh:usr/spool/news/NewsGroups",
		Spooldir[NAMELEN]=		"AXsh:usr/spool/outgoing/%s/",
		Distribution[NAMELEN]=	"world";


int		Accesslevel=0,Rows=24,Columns=80;
int		MAXHEAD=250;	/* max number of headers to be cached */
char	term=0;
char	Home[NAMELEN]="AXsh:home/root/",
		User[NAMELEN]="root",
		Realname[NAMELEN]="Pasi 'Albert' Ojala",
		Host[NAMELEN]="amiga.pasbox.fi", /* %thismachine */
		Organization[NAMELEN]="Digital Disaster Design - Europe",
		Upload[NAMELEN]="AXsh:usr/spool/upload",
		Tempdir[NAMELEN]="T:",
		Timezone[10]="GMT",
		Editor[80]="editor",
		ReplyTo[80]="",
		language[80]="";

struct header  *HeadCache=0L;
int				Headers=0;

struct RnPrefs prefs;

void __regargs __chkabort(void);
void __regargs __chkabort(void){}
VOID chkabort(VOID) {}

long MyRunCommand(char *,char *,BPTR,BPTR);

int  rn(void);
int  rntidy(int argc,char *argv[]);
int  rnnet(int argc,char *argv[]);

void read_config(void);
int  read_header(char mode,char *filename,int number,char *from,char *subject,char *id,char *xref);
void do_add_group(void);
void remove_group(struct groupnode *);
void read_usersettings(void);
int  read_messages(struct groupnode *group,char initial);
int  show_article(struct groupnode *group,int number,int rot);
int  post_article(struct groupnode *group,int reference,int quote);
void save_article(struct groupnode *group,int number,char *savefile);
void help(int);
int  more(char *file,int body,int rot);
int  mail_reply(struct groupnode *group,int ref,int quote);
void parsefrom(char *emailaddr,char *str);


long MyRunCommand(char *command,char *args,BPTR in,BPTR out)
{
	struct TagItem stags[3];
	static char commandbuffer[512];

	if(!in)
		in=Input();
	if(!out)
		out=Output();

	if(ArpBase)
	{
		return (SyncRun(command,args,in,out));
	}
	else
	{
		sprintf(commandbuffer,"%s %s\n",command,args);
		stags[0].ti_Tag = SYS_Input;
		stags[0].ti_Data = in;
		stags[1].ti_Tag = SYS_Output;
		stags[1].ti_Data = out;
		stags[2].ti_Tag = TAG_DONE;
		return(System(commandbuffer, stags));
	}
}


char *printout(ULONG strnum)
{
	if(catalog)
		return (char *)GetCatalogStr(catalog,strnum,AppStrings[strnum].as_Str);
	else
		return (char *)AppStrings[strnum].as_Str;

}

int main(int argc,char *argv[])
{
	int error, i;
	char temp[80];

	if(DOSBase->dl_lib.lib_Version<36)
	{
		if(!(ArpBase = OpenLibrary("arp.library",39)))
		{
			printf(printout(MSG_CANT_OPEN_ARP));
			exit(42);
		}
	}

	/*
		This new version works with the shell variables and
		also without AXsh, but it needs "accesslevel" valid
		and the levels spelled correctly..
	 */
	if(ArpBase)
	{
		who(COM_GET, NULL, "accesslevel", temp);
	}
	else
	{
		GetVar("accesslevel", temp, sizeof(temp), GVF_LOCAL_ONLY);
	}
	Accesslevel = 0; /* Default level (visitor) */
	for(i=0;UID_Name[i];i++)
	{
		if(UID_Name[i])
		{
			if(!stricmp(UID_Name[i], temp))
			{
				Accesslevel = i;
				break;
			}
		}
	}
	Accesslevel <<= UID_ACCESSSHIFT;

	LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38L);
	read_config();	/* setting up.. */

	if(argc==1)
	{
		setmode(MODE_RAW);
		error = rn();
		setmode(MODE_CONSOLE);
	}
	else if(!strcmp(argv[1],"net"))
	{
		error = rnnet(argc-1,++argv);
	}
	else if(!strcmp(argv[1],"tidy"))
	{
		if(!strcmp(Activefile,"none"))
			error = rntidy(argc-1,++argv);
		else
			printf(printout(MSG_ACTIVE_IN_USE),"Tidy");
	}
	else if(!strcmp(argv[1],"active"))
	{
		if(argc==3)
		{
			if(Accesslevel >= UID_SUPERUSER)
			{
				printf(printout(MSG_UPDATING_ACTIVE));
				update_active(argv[2]);
				error = 0;
			}
			else
			{
				printf(printout(MSG_NO_PRIVILEGES));
				error = 20;
			}
		}
		else
		{
			printf(printout(MSG_USAGE));
			error = 5;
		}
	}
	else
	{
		printf(printout(MSG_USAGE));
		error = 5;
	}

	if(catalog)
		CloseCatalog(catalog);

	if(LocaleBase)
		CloseLibrary((struct Library *)LocaleBase);
	if(ArpBase)
		CloseLibrary(ArpBase);

	SetSignal(0L,SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F );
	exit(error);
}


int rn(void)
{
	int done=0,read,count;
    unsigned char oldc,c=0,p[NAMELEN];
    long file1,file2,pituus;
	struct groupnode *old,*current,*temppi;

	printf("%s",vers+7);

	if(!(HeadCache=(struct header *)AllocMem(MAXHEAD*sizeof(struct header),MEMF_PUBLIC | MEMF_CLEAR)))
	{
		MAXHEAD=20;
		HeadCache=(struct header *)AllocMem(MAXHEAD*sizeof(struct header),MEMF_PUBLIC | MEMF_CLEAR);
	}

	if(!HeadCache)	goto freememory;

	read_usersettings();	/* get username,realname,home,visual,rows.. */
	sprintf(p,"%s.rnnewsrc",Home);
	read_newsrc(p,&grouplist);
	sprintf(p,"%s.rnprefs",Home);
	read_prefs(&prefs,p,term);
	if(file1 = Lock(p, ACCESS_READ))
	{
		UnLock(file1);
	}
	else
	{
		sprintf(p,"%s.rnprefs",Home);
		write_prefs(&prefs,p);
	}

	check_unread(Activefile,Newsgroupfile,&grouplist,&prefs);
	old=(struct groupnode *)grouplist.lh_Head;

	current=get_group(1,0,old); /* find first group with unread articles */
	while(!done)
	{
		if(!c)
		{
			if(current)
				printf(printout(MSG_UNREAD_ARTICLES),current->unread,prefs.Groupname,current->name,prefs.Normal);
			else
				printf(printout(MSG_END_OF_NEWSGROUP));

			fflush(stdout);
			if(getline(" y\r\n-1=copnPNlgarsGhHqQeEu\003",p,NAMELEN,0,1))
				break;

			c=p[0];
			if(c=='q')
			{
				sprintf(p,"%s.rnnewsrc",Home);
				write_newsrc(p,&grouplist);
				break;
			}
			if(c==0x03 || (SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C))
			{
				sprintf(p,"%s.newnewsrc",Home);
				write_newsrc(p,&grouplist);
				break;
			}
		}

		if(current && (c==' ' || c==0x0d) && current->unread)
			c='y';

		oldc=c;
		c=0;
		switch(oldc)
		{
		case '-':
			temppi=current;
			current=old;
			old=temppi;
			break;
		case '1':
			current=(struct groupnode *)grouplist.lh_Head;
			break;
		case 'u':
		case '=':
		case 'c':
		case 'o':
		case 'y':
			if(current)
			{
				if(read_messages(old=current,oldc))
					done=1;
				c='n';
			}
			break;
		case 'l':
			printf(printout(MSG_SUBSCRIBED_GROUPS));
			count=0;
			temppi=(struct groupnode *)grouplist.lh_Head;
			while(temppi->Node.ln_Succ)
			{
				if(!(temppi->flags & FLAG_UNSUBSCRIBED))
				{
					if(temppi->unread)
						printf("(%4d) %s%s%s\n",temppi->unread,prefs.Groupname,temppi->name,prefs.Normal);
					else
						printf("(READ) %s%s%s\n",prefs.Groupname,temppi->name,prefs.Normal);
					if(++count>Rows-3)
					{
						printf("%sMore?%s",prefs.More,prefs.Normal);
						fflush(stdout);
						if(getline(NULL,&c,2,0,0))
						{
							done=-1;
							break;
						}
						printf("\b\b\b\b\b\033[K");
						fflush(stdout);
						if(c==0x03 || c=='q')
						{
							printf("\n");
							c=0;
							break;
						}
						count=0;
					}
				}
				temppi=(struct groupnode *)temppi->Node.ln_Succ;
			}
			if(done || temppi->Node.ln_Succ)
			{
				break;
			}

			printf(printout(MSG_MENTIONED_IN_RC));
			count=0;
			temppi=(struct groupnode *)grouplist.lh_Head;
			while(temppi->Node.ln_Succ)
			{
				if(temppi->flags & FLAG_UNSUBSCRIBED)
				{
					printf("%s\n",temppi->name);
					if(++count>Rows-3)
					{
						printf("%sMore?%s",prefs.More,prefs.Normal);
						fflush(stdout);
						if(getline(NULL,&c,2,0,0))
						{
							done=-1;
							break;
						}
						printf("\b\b\b\b\b\033[K");
						fflush(stdout);
						if(c==0x03 || c=='q')
						{
							printf("\n");
							break;
						}
						count=0;
					}
				}
				temppi=(struct groupnode *)temppi->Node.ln_Succ;
			}
			c=0;
			printf("\n");
			break;
		case 'P':
			if(current)
			{
				current=get_group(-1,1,old=current);
			}
			else
				current=(struct groupnode *)grouplist.lh_TailPred;
			break;
		case 'p':
			if(current)
			{
				current=get_group(-1,0,(struct groupnode *)(old=current)->Node.ln_Pred);
			}
			else
				current=get_group(-1,0,(struct groupnode *)grouplist.lh_TailPred);
			break;
		case 'N':
			if(current)
			{
				current=get_group(1,1,old=current);
			}
			else
				current=(struct groupnode *)grouplist.lh_Head;
			break;
		case ' ':
		case 'n':
			if(current)
			{
				current=get_group(1,0,(struct groupnode *)(old=current)->Node.ln_Succ);
			}
			else
			{
				current=get_group(1,0,(struct groupnode *)grouplist.lh_Head);
				if(!current)
					done=1;
			}
			break;
		case 'H':
		case 'h':
			if(current)
			{
				help(1);
			}
			else
				help(1);
			break;
		case 'a':
			if(Accesslevel >= UID_PRIVILEGED)
				do_add_group();
			break;
		case 'r':
			if(Accesslevel >= UID_SUPERUSER)
				remove_group(old=current);
			break;
		case 's':
			sort_newsrc(&grouplist);
			current=get_group(1,0,(struct groupnode *)&grouplist);
			break;
		case 'E':
		case 'e':
			if(Rows>22)
			{
				edit_prefs(&prefs,Rows);
				sprintf(p,"%s.rnprefs",Home);
				write_prefs(&prefs,p);
			}
			else
				printf(printout(MSG_NEED_AT_LEAST_ROWS));
			break;
		case 'g':	/* goto a newsgroup */
			printf(printout(MSG_NAME_OF_THE_GROUP));
			fflush(stdout);
			if(getline("",p,NAMELEN-2,0,1))
			{
				done=1;
				break;
			}
			lowercase(p,p);

			current=search_group(&grouplist,p);
			if(current)
			{
				if(current->flags & FLAG_UNSUBSCRIBED)
				{
					current->flags&=~FLAG_UNSUBSCRIBED;
					printf(printout(MSG_RESUBSCRIBED_TO),current->name);
					checkgroup(Activefile,current);
				}
			}
			else
			{
				printf(printout(MSG_NO_MATCHES_FOR_NG),p);
				current=old;
			}
			break;
		case 'G':	/* grab messages */
			if((prefs.Bits & RN_GRABALL) || current)
			{
				if(prefs.Bits & RN_GRABALL)
					temppi=(struct groupnode *)&grouplist.lh_Head;
				else
					temppi=current;

				pituus=0;
				sprintf(p,"%s%s",Home,Grabfile);
				if(file1=Open(p,MODE_OLDFILE))
				{
					printf(printout(MSG_OVERWRITE_GRAB));
					fflush(stdout);
					if(getline(NULL,&c,2,0,1))
					{
						done=-1;
						break;
					}
					if(c==0x03 || c=='q')
						break;
					if(c!='y' && c!='Y')
						Seek(file1,0,OFFSET_END);
					pituus=Seek(file1,0,OFFSET_CURRENT);
				}
				else
					file1=Open(p,MODE_NEWFILE);

				if(file1)
				{	UBYTE *buffer;

					c=0;
					printf(printout(MSG_GRAB_ACTIVE));
					if(buffer=(UBYTE *)AllocMem(G_BUF,MEMF_PUBLIC | MEMF_CLEAR))
					{
						while(temppi->Node.ln_Succ)
						{
							if(!(temppi->flags & FLAG_UNSUBSCRIBED) && temppi->unread)
							{
								printf("%s\n",temppi->name);
								for(read=Findnextbit(temppi,temppi->lowest);temppi->unread;read=Findnextbit(temppi,read))
								{
									Setbit(temppi,read);
									articlename(buffer,temppi->name,read,0);
									if(file2=Open(buffer,MODE_OLDFILE))
									{
										while((count=Read(file2,buffer,G_BUF))>0)
										{
											Write(file1,buffer,count);
											pituus+=count;
										}
										Close(file2);
									}
									Write(file1,&"\n*****\n\n",8);
									pituus+=8;
									printf("%4d ",read);
									fflush(stdout);
									if(WaitForChar(Input(),0))
									{
										(void)getchar();
										printf(printout(MSG_GRAB_BREAK));
										c = 1;
										break;
									}
								}
								printf("\n");
							}
							if(c)
								break;

							if(prefs.Bits & RN_GRABALL)
								temppi=(struct groupnode *)temppi->Node.ln_Succ;
							else
								break;
						}
						c=0;
						FreeMem(buffer,G_BUF);
						Close(file1);
						if(pituus)
							printf(printout(MSG_GRAB_OK),p,pituus);
						else
						{
							printf(printout(MSG_GRAB_NO_MSGS));
							DeleteFile(p);
						}
					}
					else
					{
						printf(printout(MSG_MEM_LOW));
						Close(file1);
					}
				}
				else
					printf(printout(MSG_CANT_OPEN_GRAB),p);
			}
			break;
		default:
			if(current)
			{
				printf(printout(MSG_H_FOR_HELP));
			}
			else
				printf(printout(MSG_H_FOR_HELP));
			break;
		}
	}
	if(done)
	{
		sprintf(p,"%s.rnnewsrc",Home);
		write_newsrc(p,&grouplist);
	}

freememory:
	if(HeadCache)
		FreeMem((UBYTE *)HeadCache,MAXHEAD*sizeof(struct header));
	free_newsrc(&grouplist);

	return 0;
}


int read_messages(struct groupnode *group,char initial)
{
	int curr,done=0,ch,old,i,j;
	char from[NAMELEN],subject[NAMELEN],sub2[NAMELEN],apu[MAXNAMELEN];
	BPTR lock;

	ch=initial;
	read_header(H_CLEAR,0L,0,0L,0L,0L,0L);
/* TODO: if(..) check newsgroup consistency etc. */
	checkgroup(Activefile,group);

	if(group->unread<0)	/* Make sure we don't show funny numbers */
	{
		group->unread = 0;
		group->lowest = group->highest;
	}

	if(group->unread>0)
	{
		if(ch == 'y')
		{
			curr = Findnextbit(group,group->lowest)-1;
			ch = 'n';
		}
		else
		{
			if(ch=='=')
				curr=group->lowest;
			else
				curr=Findnextbit(group,group->lowest);
		}
	}
	else
	{
		curr=group->highest;
		if(ch=='y')
			ch='\0';
	}
	while(!done)
	{
		if( ch=='n' || ch=='p' || ch=='N'  || ch=='P' || ch==0x0e || ch==0x10 || ch==' ' ||
			ch=='f' || ch=='F' || ch==0x06 ||
			ch=='c' || ch=='o' || ch=='k'  ||
			ch=='=' || ch==0x12 || ch==0x18 ||
			ch=='s' || ch=='r' || ch=='R'  || ch=='m'  ||
			ch=='C' || ch=='S' || ch=='u')
		{
			apu[0]=ch;
			apu[1]='\0';
		}
		else
		{
			if(ch==-1)
			{
				printf(printout(MSG_SKIPPING_UNAVAILABLE));
				if(checkgroup(Activefile,group))
					return 0;

				ch=0;
				/*curr=group->lowest;*/
			}
			if(group->unread==0)
				printf(printout(MSG_END_OF_NEWSGROUP_2),prefs.Groupname,group->name,prefs.Normal);
			printf(printout(MSG_END_OF_ARTICLE_WHAT_NEXT),prefs.More,curr,group->highest,prefs.Normal);

			apu[0]=ch;
			apu[1]=0;
			fflush(stdout);
			if(getline("n \r\nnN\016pP\020\022\006fFcComqu=ksSrRh\030",apu,NAMELEN,1,1))
				return -1;
			ch=apu[0];
		}

		old=ch;
		ch=0;
		switch(old)
		{
		case 'n':
		case ' ':
		case 0x0d:
			if(group->unread>0)
			{
				if((ch=show_article(group,curr=Findnextbit(group,curr+1),0))==-1)
				{
					printf(printout(MSG_SKIPPING_UNAVAILABLE));
					if(strcmp(Activefile,"none"))
					{
						group->lowest = findlowest(group->name,group->highest,group->lowest);
					}
					else
					if(checkgroup(Activefile,group))
						return 0;

					group->unread=Countbits(group);
					if(curr < group->lowest)
						curr = group->lowest-1;
					while(curr<group->highest)
					{
						curr++;
						if(!Testbit(group,curr))
						{
							articlename(apu,group->name,curr,0);
							if(lock = Lock(apu, ACCESS_READ))
							{
								UnLock(lock);
								ch = show_article(group,curr,0);
								break;
							}
							printf(".");
							Setbit(group, curr);
							fflush(stdout);
						}
					}
				}
			}
			else
				done=1;
			break;
		case 'N':
			if(curr<group->highest)
				ch=show_article(group,++curr,0);
			break;
		case 'p':	/* previous unread */
			if(group->unread>0)
			{
				if((ch=show_article(group,curr=Findprevbit(group,curr-1),0))==-1)
				{
					printf(printout(MSG_SKIPPING_UNAVAILABLE));
					if(strcmp(Activefile,"none"))
					{
						group->lowest = findlowest(group->name,group->highest,group->lowest);
					}
					else
					if(checkgroup(Activefile,group))
						return 0;

					group->unread=Countbits(group);
					while(curr>group->lowest)
					{
						curr--;
						if(!Testbit(group,curr))
						{
							articlename(apu,group->name,curr,0);
							if(lock = Lock(apu, ACCESS_READ))
							{
								UnLock(lock);
								ch = show_article(group,curr,0);
								break;
							}
							printf(".");
							Setbit(group, curr);
							fflush(stdout);
						}
					}
				}
			}
			break;
		case 'P':
			if(curr>group->lowest)
				ch=show_article(group,--curr,0);
			break;
		case 0x12:	/* ^r restart article */
			ch=show_article(group,curr,0);
			break;
		case 0x18:	/* ^x restart article rot-13 */
			ch=show_article(group,curr,1);
			break;
		case 0x06:	/* ^f post an article */
/*
			if(strcmp(Activefile,"none") && !strcmp(Postnews,"internal"))
			{
				printf(printout(MSG_ACTIVE_IN_USE),"Internal-Postnews");
			}
			else
*/
			if(!(group->flags & FLAG_READ_ONLY))
			{
				if(post_article(group,-1,0))	return -1;
				curr=Findnextbit(group,group->lowest);
				if(curr<=group->highest)
					ch=show_article(group,curr,0);
			}
			else
				printf(printout(MSG_READ_ONLY_GROUP));
			break;
		case 'f':	/* followup to an article (no quote) */
/*
			if(strcmp(Activefile,"none") && !strcmp(Postnews,"internal"))
			{
				printf(printout(MSG_ACTIVE_IN_USE),"Internal-Postnews");
			}
			else
*/
			if(!(group->flags & FLAG_READ_ONLY))
			{
				if(post_article(group,curr,0))	return -1;
				curr=Findnextbit(group,group->lowest);
				if(curr<=group->highest)
					ch=show_article(group,curr,0);
			}
			else
				printf(printout(MSG_READ_ONLY_GROUP));
			break;
		case 'F':	/* followup to an article */
/*
			if(strcmp(Activefile,"none") && !strcmp(Postnews,"internal"))
			{
				printf(printout(MSG_ACTIVE_IN_USE),"Internal-Postnews");
			}
			else
*/
			if(!(group->flags & FLAG_READ_ONLY))
			{
				if(post_article(group,curr,-1))	return -1;
				curr=Findnextbit(group,group->lowest);
				if(curr<=group->highest)
					ch=show_article(group,curr,0);
			}
			else
				printf(printout(MSG_READ_ONLY_GROUP));
			break;
		case 'c':	/* catch up = mark articles read */
			printf(printout(MSG_WANNA_MARK_ARTICLES_READ));
			fflush(stdout);
			if(getline("ynYN\n\r",apu,8,0,1))
				return -1;
			if(apu[0]=='y' || apu[0]=='Y')
			{
				Setallbits(group,0);
				group->unread=0;
				printf(printout(MSG_MARKED_GROUP),prefs.Groupname,group->name,prefs.Normal);
				done=1;
			}
			break;
		case 'C':
			if(Accesslevel >= UID_PRIVILEGED)	/* Cancel an article */
			{
				printf(printout(MSG_ARTICLE_TO_BE_CANCELLED));
				fflush(stdout);
				if(getline("",apu,NAMELEN-2,0,1))
					return -1;
				i=atoi(apu);

				checkgroup(Activefile,group);

				if(i<group->lowest || i>group->highest)
				{
					printf(printout(MSG_NO_SUCH_ARTICLE));
				}
				else
				{
					if(!Testbit(group,i))
					{
						Setbit(group,i);
					}
					articlename(apu,group->name,i,0);
					DeleteFile(apu);
					printf(printout(MSG_ARTICLE_CANCELLED),i);
				}
			}
			else
				printf(printout(MSG_NO_PRIVILEGES));
			break;
		case 'u':
			group->flags|=FLAG_UNSUBSCRIBED;
			printf(printout(MSG_UNSUBSCRIBED_TO),group->name);
			/* Fall thru */
		case 'q':
			done=1;
			break;
		case 'o':	/* only */
			printf(printout(MSG_HOW_MANY_NEWEST));
			fflush(stdout);
			if(getline("",apu,NAMELEN-2,0,1))
				return -1;
			i=atoi(apu);
			if(i>0)
			{
				Setallbits(group,i);
			}
			break;
		case 'm':	/* mark an article as still unread */
			if(Testbit(group,curr))
			{
				Clearbit(group,curr);
			}
			printf(printout(MSG_ARTICLE_MARKED_UNREAD),curr);
			break;
		case '=':
			j=0;
			for(i=Findnextbit(group,group->lowest);i<=group->highest;i++)
			{
				if(!Testbit(group,i))
				{
					articlename(apu,group->name,i,0);
					if(read_header(H_GET,apu,i,from,subject,0L,0L))
					{
						printf("%2d %s\n",i,subject);
						j++;
					}
					else
					{
						Setbit(group,i);	/* mark unavailable article as read */
					}
					if(j>Rows-3)
					{
						printf("%sMore?%s",prefs.More,prefs.Normal);
						fflush(stdout);
						if(getline(NULL,apu,2,0,0))
							return -1;
						if(apu[0]==0x03 || apu[0]=='q')
						{
							printf("\n");
							break;
						}

						printf("\b\b\b\b\b\033[K");
						fflush(stdout);
						j=0;
					}
					if(WaitForChar(Input(),0))
					{
						getchar();
						printf("** aborted\n");
						break;
					}
				}
			}
			break;
		case 'k':	/* kill by subject */
			articlename(apu,group->name,curr,0);
			if(read_header(H_GET,apu,curr,0L,subject,0L,0L))
			{
				printf(printout(MSG_MARKING_SUBJECT_READ),subject);
				lowercase(subject,subject);
				if(!strnicmp(subject,"re: ",4))
					strcpy(subject,subject+4);
				for(i=Findnextbit(group,group->lowest);i<=group->highest;i++)
				{
					if(!Testbit(group,i))
					{
						articlename(apu,group->name,i,0);
						if(read_header(H_GET,apu,i,0L,sub2,0L,0L))
						{
							lowercase(sub2,sub2);
							if(!strnicmp(sub2,"re: ",4))
							{
								if(!strcmp(subject,sub2+4))
								{
									Setbit(group,i);
									printf(printout(MSG_JUNKED),i);
									read_header(H_FLUSH,apu,i,0L,0L,0L,0L);
								}
							}
							else
							{
								if(!strcmp(subject,sub2))
								{
									Setbit(group,i);
									printf(printout(MSG_JUNKED),i);
									read_header(H_FLUSH,apu,i,0L,0L,0L,0L);
								}
							}
						}
						else
						{
							Setbit(group,i);	/* mark unavailable article as read */
						}
						if(WaitForChar(Input(),0))
						{
							getchar();
							printf("** aborted\n");
							break;
						}
					}
				}
				group->unread=Countbits(group);
				ch='n';	/* jump to next article */
			}
			else
				printf(printout(MSG_CANNOT_KILL));
			break;
		case 0x10:	/* ^p search by subject */
		case 0x0e:	/* ^n search by subject */
			articlename(apu,group->name,curr,0);
			j=curr;
			if(read_header(H_GET,apu,curr,0L,subject,0L,0L))
			{
				printf(printout(MSG_SEARCHING_FOR),subject);
				lowercase(subject,subject);
				if(!strnicmp(subject,"re: ",4))
					strcpy(subject,subject+4);

				if(old==0x10)
				{
					for(i=Findprevbit(group,curr);i>=group->lowest;i--)
					{
						if(!Testbit(group,i))
						{
							articlename(apu,group->name,i,0);
							if(read_header(H_GET,apu,i,0L,sub2,0L,0L))
							{
								lowercase(sub2,sub2);
								if(!strnicmp(sub2,"re: ",4))
								{
									if(!strcmp(subject,sub2+4))	curr=i;
								}
								else
								{
									if(!strcmp(subject,sub2))	curr=i;
								}
							}
							else
							{
								Setbit(group,i);		/* mark unavailable article as read */
							}
							if(WaitForChar(Input(),0))
							{
								getchar();
								printf("** aborted\n");
								break;
							}
						}
					}
				}
				else
				{
					for(i=Findnextbit(group,curr);i<=group->highest;i++)
					{
						if(!Testbit(group,i))
						{
							articlename(apu,group->name,i,0);
							if(read_header(H_GET,apu,i,0L,sub2,0L,0L))
							{
								lowercase(sub2,sub2);
								if(!strnicmp(sub2,"re: ",4))
								{
									if(!strcmp(subject,sub2+4))	curr=i;
								}
								else
								{
									if(!strcmp(subject,sub2))	curr=i;
								}
							}
							else
							{
								Setbit(group,i);	/* mark unavailable article as read */
							}
							if(WaitForChar(Input(),0))
							{
								getchar();
								printf("** aborted\n");
								break;
							}
						}
					}
				}
			}
			else
				printf(printout(MSG_CANNOT_SEARCH_WITH));
			if(old==0x10)
			{
				ch='p';	/* goto previous, if we don't find any */
				if(j==curr)
				{
					if(group->unread)
						ch=show_article(group,curr=Findprevbit(group,0),0);
					else
						ch=' ';
				}
				else
				{
					if(curr<group->lowest)
						curr=group->lowest;
					else
						ch=show_article(group,curr,0);
				}
			}
			else
			{
				ch='n';	/* goto next, if we don't find any */
				if(j==curr)
				{
					if(group->unread)
						ch=show_article(group,curr=Findnextbit(group,0),0);
					else
						ch=' ';
				}
				else
				{
					if(curr>group->highest)
						curr=group->highest;
					else
						ch=show_article(group,curr,0);
				}
			}
			break;
		case 's':
			printf(printout(MSG_SAVE));
			fflush(stdout);
			if(getline("",apu,NAMELEN-2,0,1))
				return -1;
			if(apu[0])
			{
				j=strlen(apu);
				while(apu[j]!=':' && apu[j]!='/' && j) j--;
				if(!j)
					save_article(group,curr,apu);
				else
					printf(printout(MSG_SAVE_UNALLOWED_FILENAME));
			}
			break;
		case 'S':	/* skandimuunnos */
			if(Accesslevel >= UID_PRIVILEGED)
			{
				articlename(apu,group->name,curr,0);
				sf7toiso(apu);
				ch=0x12;
			}
			break;
		case 'r':	/* r - reply by mail */
			mail_reply(group,curr,0);
			break;
		case 'R':	/* R - reply by mail, include */
			mail_reply(group,curr,-1);
			break;
		case 'h':
		default:
			if(i=atoi(apu))	/* read a specified article */
			{
				if(i>=group->lowest && i<=group->highest)
					ch=show_article(group,curr=i,0);
			}
			else
			{
				if(old=='h')
				{
					help(2);
					while(WaitForChar(Input(),0))
						getchar();
				}
				else
					printf(printout(MSG_H_FOR_HELP));
			}
			break;
		}
	}
	return 0;
}


int show_article(struct groupnode *group,int nu,int rot)
{
	char name[MAXNAMELEN];

	if(!Testbit(group,nu))
	{
		Setbit(group,nu);
	}

	articlename(name,group->name,nu,0);

	if(!(prefs.Bits & RN_NOCLEAR))
		printf("\033[;H\033[2J");

	if(group->unread)
	{
		printf(printout(MSG_ARTICLE_MORE),nu,group->unread);
	}
	else
	{
		printf(printout(MSG_ARTICLE),nu);
	}
	printf(printout(MSG_IN_GROUP),prefs.Groupname,group->name,prefs.Normal);
	return more(name,0,rot);
}


int read_header(char mode,char *name,int number,char *from,char *subject,char *id,char *xref)
{
	FILE *handle;
	char line[2*MAXNAMELEN];
	int i,j;

	if(mode==H_CLEAR)
	{
		Headers=0;
		return -1;
	}
	j=0;
	while(j<Headers && HeadCache[j].Number!=number)
		j++;

	if(mode==H_FLUSH)
	{
		if(j<Headers)
			memcpy(&HeadCache[j],&HeadCache[--Headers],sizeof(struct header));
		return -1;
	}
	if(j==Headers)
	{
		if(!name)
			return -1;

		strcpy(HeadCache[j].File, name);
		HeadCache[j].Number = number;
		HeadCache[j].From[0] = HeadCache[j].Subj[0] = HeadCache[j].ID[0] = 0;
		if(handle=fopen(name,"rb"))
		{
			while(!feof(handle))
			{
				if(fgets(line,2*MAXNAMELEN-2,handle)==0)
					break;
				if(i=strlen(line))
					line[i-1]=0;

				if(!line[0])
					break;	/* end of header or file */

				if(!HeadCache[j].From[0] && !strnicmp(line,"From: ",6))
				{
					strncpy(HeadCache[j].From,line+6,MAXNAMELEN);
					HeadCache[j].From[MAXNAMELEN-1] = '\0';
				}
				if(!HeadCache[j].Subj[0] && !strnicmp(line,"Subject: ",9))
				{
					strncpy(HeadCache[j].Subj,line+9,MAXNAMELEN);
					HeadCache[j].Subj[MAXNAMELEN-1] = '\0';
				}
				if(!HeadCache[j].ID[0] && !strnicmp(line,"Message-ID: ",12))
				{
					strncpy(HeadCache[j].ID,line+12,MAXNAMELEN);
					HeadCache[j].ID[MAXNAMELEN-1] = '\0';
				}
				if(!HeadCache[j].Xref[0] && !strnicmp(line,"Xref: ",12))
				{
					strncpy(HeadCache[j].Xref,line+12,MAXNAMELEN);
					HeadCache[j].Xref[MAXNAMELEN-1] = '\0';
				}

				if(!strnicmp(line,"Reply-To: ", 9))
				{
					strncpy(HeadCache[j].From, line+9,MAXNAMELEN);
					HeadCache[j].From[MAXNAMELEN-1] = '\0';
				}
			}
			fclose(handle);
			if(Headers<MAXHEAD-1)
				Headers++;
		}
		else
			return 0;
	}
	if(from)
		strcpy(from,HeadCache[j].From);
	if(subject)
		strcpy(subject,HeadCache[j].Subj);
	if(id)
		strcpy(id,HeadCache[j].ID);
	if(xref)
		strcpy(xref,HeadCache[j].Xref);

	return -1;
}


int post_article(struct groupnode *group,int ref,int quote)
{
	char name[NAMELEN],arg[MAXNAMELEN],magicname[8],
		 from[NAMELEN],subject[NAMELEN],id[NAMELEN],apu[MAXNAMELEN],
		 *aika;
	FILE *handle,*reffile;
	int ret,i,j,wrapped;
	long magicnumber;
	struct DateStamp ds;

	subject[0]=0;
	if(ref!=-1)
	{
		articlename(arg,group->name,ref,0);
		if(read_header(H_GET,arg,ref,from,apu,id,0L))
		{
			if(strlen(apu)>NAMELEN-5)
				apu[NAMELEN-5]=0;
			if(!strnicmp(apu,"Re: ",4))
				strcpy(subject,apu);
			else
				sprintf(subject,"Re: %s",apu);
		}
		else
		{
			ref=-1;
		}
	}
	printf(printout(MSG_SUBJECT_OF_ARTICLE));
	fflush(stdout);
	if(getline("",subject,NAMELEN,1,1))
		return -1;

	aika=get_time();
	DateStamp(&ds);
	magicnumber=ds.ds_Days+74000*ds.ds_Minute+ds.ds_Tick*1440+(((struct Process *)(SysBase->ThisTask))->pr_Pad & ~UID_ACCESSMASK);
	strncpy(magicname,User,7);
	magicname[7]=0;

	sprintf(name,"%s%s-article",Tempdir,User);
	if(handle=fopen(name,"wb"))
	{
		if(ref!=-1)
		{
			fprintf(handle,Fupref,id,from);
			fputc('\n',handle);
			if(quote && (reffile=fopen(arg,"rb")))
			{
				ret=0;
				do
				{
					i=ret;
					ret=fgetc(reffile);
				}
				while(!(ret==0x0a && i==0x0a) && ret!=EOF);
				/* hope there is 2 linefeeds after header*/

				i=wrapped=0;
				while((ret=fgetc(reffile))!=EOF)
				{
					if(ret==0x0a || ret==0x0d)
					{
						arg[i]=0;
						if(i || !wrapped)
						{
							fprintf(handle,Quotestring,arg);
							fputc('\n',handle);
						}
						i=wrapped=0;
					}
					else
					{
						arg[i++]=ret;
						if(i>74)
						{
							arg[i]=0;
							while(i && arg[i]!=' ')	i--;
							if(i>64)
							{
								arg[i]=0;
								fprintf(handle,Quotestring,arg);
								fputc('\n',handle);
								strcpy(arg,arg+i+1);
								i=strlen(arg);
							}
							else
							{
								fprintf(handle,Quotestring,arg);
								fputc('\n',handle);
								i=0;
							}
							wrapped=1;
						}
					}
				}
				fputc(0x0a,handle);
				fclose(reffile);
			}
		}
		fclose(handle);
		apu[0]='e';
		do
		{
			if(apu[0]=='e')
			{
				sprintf(apu,"AXsh:bin/%s",Editor);
				MyRunCommand(apu,name,Input(),Output());
				setmode(MODE_RAW);
			}
			if(apu[0]=='l')
			{
				if(!(prefs.Bits & RN_NOCLEAR))
					printf("\033[;H\033[2J");

				printf("%sNewsgroups:%s %s%s%s\n",prefs.Header,prefs.Normal,prefs.Groupname,group->name,prefs.Normal);
				printf("%sFrom:%s %s%s@%s (%s)%s\n",prefs.Header,prefs.Normal,prefs.From,User,Host,Realname,prefs.Normal);
				printf("%sSubject:%s %s%s%s\n",prefs.Header,prefs.Normal,prefs.Subject,subject,prefs.Normal);
				printf("%sDate: %s\n",prefs.Header,aika);
				if(ReplyTo[0])
				{
					fprintf(handle,"Reply-To: %s\n",ReplyTo);
				}
				printf("Organization: %s\n",Organization);
				printf("Message-ID: <%s.%08X@%s>\n",magicname,magicnumber,Host);
				printf("X-Newsreader: "VERSION);
				printf("Distribution: %s%s\n",Distribution,prefs.Normal);

				if(ref!=-1)
					printf("%sReferences: %s%s\n",prefs.Header,id,prefs.Normal);
				printf("\n");
				more(name,1,0);
			}
			printf(printout(MSG_WHAT_NOW));

			fflush(stdout);
			if(getline("sael",apu,20,0,1))
				return -1;
		}
		while(apu[0]!='s' && apu[0]!='a');
		if(apu[0]=='s')
		{
			if(reffile=fopen(name,"rb"))
			{
				sprintf(name,"%s.article",Home);
				if(handle=fopen(name,"wb"))
				{
					fprintf(handle,"Newsgroups: %s\n",group->name);
					if(!strcmp(Postnews,"internal"))
					{
						fprintf(handle,"Path: %s\n",User);
						fprintf(handle,"From: %s@%s (%s)\n",User,Host,Realname);
						fprintf(handle,"Date: %s\n",aika);
						fprintf(handle,"Organization: %s\n",Organization);
					}

					if(ReplyTo[0])
					{
						fprintf(handle,"Reply-To: %s\n",ReplyTo);
					}

					fprintf(handle,"Subject: %s\n",subject);
					fprintf(handle,"Message-ID: <%s.%08X@%s>\n",magicname,magicnumber,Host);
					fprintf(handle,"X-Newsreader: "VERSION );
					fprintf(handle,"Distribution: %s\n",Distribution);
					if(ref!=-1) fprintf(handle,"References: %s\n",id);
					fprintf(handle,"\n");

					while(!feof(reffile))
					{
						if(fgets(apu,MAXNAMELEN,reffile)==0)
							break;
						if(!feof(reffile))
							fputs(apu,handle);
					}
					fclose(reffile);

					sprintf(name,"%s.signature%d",Home,(ds.ds_Tick/2)%10);
					if(reffile=fopen(name,"rb"))
					{
						while(fgets(apu,MAXNAMELEN,reffile))
							fputs(apu,handle);
						fclose(reffile);
					}
					else
					{
						sprintf(name,"%s.signature",Home);
						if(reffile=fopen(name,"rb"))
						{
							while(fgets(apu,MAXNAMELEN,reffile))
								fputs(apu,handle);
							fclose(reffile);
						}
						else
							printf(printout(MSG_CANT_OPEN_SIGNATURE));
					}
					fclose(handle);
				}

				if(!strcmp(Postnews,"internal"))
				{
/*
					if(!strcmp(Activefile,"none"))
					{
*/
						articlename(apu,group->name,inc_next(group->name),0);

						sprintf(arg,"%s.article",Home);
						if(copyfile(apu,arg))
						{
							printf(printout(MSG_ARTICLE_COPY_FAILED));
						}
						else
						{
							/* add the article name to the batch files */
							if(batchfile(apu,group->name,User))
								printf(printout(MSG_BATCH_ERROR));
						}
/*
					}
					else
					{
						printf(printout(MSG_ARTICLE_ABORTED));
						printf(printout(MSG_ACTIVE_IN_USE),"Internal-Postnews");
						Delay(200);
					}
*/
				}
				else
				{
					i=j=0;
					while(Postnews[i])
					{
						if(Postnews[i]=='%')
						{
							switch(Postnews[i+1])
							{
							case 'f':
								strcpy(apu+j,Home);
								strcat(apu,".article");
								j+=strlen(Home)+8;
								i+=2;
								break;
							case 'u':
								strcpy(apu+j,User);
								j+=strlen(User);
								i+=2;
								break;
							case 'r':
								strcpy(apu+j,Realname);
								j+=strlen(Realname);
								i+=2;
								break;
							default:
								i++;
							}
						}
						else
							apu[j++]=Postnews[i++];
					}
					apu[j]=0;
					if(Accesslevel >= UID_SUPERUSER)
						printf("Running \"%s\"\n",apu);
					Execute(apu,0,Output());

					/*	PostNews <%f -f "%u" -r "%r" -R reffile -x delfile */
				}
			}
			else
			{
				printf(printout(MSG_TEMP_FILE_DISAPPEARED),name);
			}
		}
		else
			printf(printout(MSG_ARTICLE_ABORTED));

		sprintf(name,"%s%s-article",Tempdir,User);
		DeleteFile(name);
	}
	else
		printf(printout(MSG_CANT_OPEN),name);

	checkgroup(Activefile,group);
	return 0;
}


void save_article(struct groupnode *group,int nr,char *name)
{
	char file1[MAXNAMELEN],file2[100];
	long lock,size;
	char *buffer;
	BPTR fp1,fp2;

	articlename(file1,group->name,nr,0);

	sprintf(file2,"%sNews",Home);
	if(lock=Lock(file2, ACCESS_READ))
	{
		UnLock(lock);
	}
	else
	{
		mkdir(file2);
	}

	strcat(file2,"/");
	strcat(file2,name);

	if(fp2=Lock(file2, ACCESS_READ))
	{
		UnLock(fp2);
		if(fp2=Open(file2,MODE_READWRITE))
		{
			printf(printout(MSG_APPEND),file2);
			Seek(fp2, 0, OFFSET_END);
		}
		else
		{
			printf(printout(MSG_CANT_OPEN_FOR_APPENDING),file2);
			return;
		}
	}
	else
	{
		if(fp2=Open(file2,MODE_NEWFILE))
		{
			printf(printout(MSG_SAVING),file2);
		}
		else
		{
			printf(printout(MSG_CANT_OPEN_FOR_APPENDING),file2);
			return;
		}
	}

	if(fp1=Open(file1, MODE_OLDFILE))
	{
		if(buffer=(UBYTE *)AllocMem(G_BUF,MEMF_PUBLIC | MEMF_CLEAR))
		{
			while(size = Read(fp1, buffer, G_BUF))
			{
				if(size<0)
				{
					printf(printout(MSG_ARTICLE_NOT_FOUND));
					break;
				}
				Write(fp2, buffer, size);
			}
			FreeMem(buffer,G_BUF);
		}
		else
		{
			while(size = Read(fp1, file1, MAXNAMELEN))
			{
				if(size<0)
				{
					printf(printout(MSG_ARTICLE_NOT_FOUND));
					break;
				}
				Write(fp2, file1, size);
			}
		}
		Close(fp1);
	}
	else
		printf(printout(MSG_ARTICLE_NOT_FOUND));
	Close(fp2);
}


void read_config()
{
	FILE *handle;
	char line[NAMELEN];
	register int i,found=0,mask=0;

	if(handle=fopen("AXsh:etc/rc","rb"))	/* luetaan config */
	{
		while(!feof(handle))
		{
			if(fgets(line,NAMELEN-1,handle)==0)
				break;
			if(i=strlen(line))
				line[i-1]=0;

			if(found==0)
			{
				if(!strnicmp(line,"%thismachine:",13))
					found=1;
				else if(!strnicmp(line,"%organization:",14))
					found=2;
				else if(!strnicmp(line,"%upload:",8))
					found=3;
				else if(!strnicmp(line,"%tempdir:",9))
					found=4;
				else if(!strnicmp(line,"%timezone:",10))
					found=5;
				else if(!strnicmp(line,"%spooldir:",10))
					found=6;
				else if(!strnicmp(line,"%news:",6))
					found=7;
			}
			else
			{
				switch(found)
				{
				case 1:
					strcpy(Host,line);
					mask |= 0x01;
					break;
				case 2:
					strcpy(Organization,line);
					mask |= 0x02;
					break;
				case 3:
					strcpy(Upload,line);
					mask |= 0x04;
					break;
				case 4:
					strcpy(Tempdir,line);
					mask |= 0x08;
					break;
				case 5:
					strncpy(Timezone,line,9);
					Timezone[9]=0;
					mask |= 0x10;
					break;
				case 6:
					strcpy(Spooldir,line);
					mask |= 0x20;
					break;
				case 7:
					strcpy(Newshome,line);
					break;
				}
				found=0;
				if(mask == 0x3f)
					break;	/* found them all already */
			}
		}
		fclose(handle);
	}
	else
	{
		printf(printout(MSG_CANT_OPEN),"AXsh:etc/rc");
	}

	for(i=(Accesslevel>>UID_ACCESSSHIFT);i>=0;i--)
	{
		if(UID_Name[i] && strlen(UID_Name[i]))
		{
			sprintf(line,"AXsh:etc/rc.news.%s",UID_Name[i]);
			if(handle=fopen(line,"rb"))
			{
				break;
			}
		}
	}
	if(handle || (handle=fopen("AXsh:etc/rc.news","rb")))	/* luetaan news-config */
	{
		while(!feof(handle))
		{
			if(fgets(line,NAMELEN-1,handle)==0)
				break;
			if(i=strlen(line))
				line[i-1]=0;

			if(!found)
			{
				if(!strnicmp(line,"%grabfile:",10))
					found=1;
				else if(!strnicmp(line,"%batchfile:",11))
					found=2;
				else if(!strnicmp(line,"%sysfile:",9))
					found=3;
				else if(!strnicmp(line,"%quotestring:",13))
					found=4;
				else if(!strnicmp(line,"%postnews:",10))
					found=5;
				else if(!strnicmp(line,"%fupref:",8))
					found=6;
				else if(!strnicmp(line,"%sendmail:",10))
				 	found=7;
				else if(!strnicmp(line,"%netlogfile:",12))
					found=8;
				else if(!strnicmp(line,"%newsgroupfile:",15))
					found=9;
				else if(!strnicmp(line,"%activefile:",12))
					found=10;
				else if(!strnicmp(line,"%distribution:",14))
					found=11;
				else if(!strnicmp(line,"%newshome:",10))
					found=12;
			}
			else
			{
				switch(found)
				{
				case 1:
					strcpy(Grabfile,line);
					break;
				case 2:
					strcpy(Batchfile,line);
					break;
				case 3:
					strcpy(Sysfile,line);
					break;
				case 4:
					strcpy(Quotestring,line);
					break;
				case 5:
					strcpy(Postnews,line);
					break;
				case 6:
					strcpy(Fupref,line);
					break;
				case 7:
					strcpy(Sendmail,line);
					break;
				case 8:
					strcpy(Netlogfile,line);
					break;
				case 9:
					strcpy(Newsgroupfile,line);
					break;
				case 10:
					lowercase(Activefile,line);
					break;
				case 11:
					strcpy(Distribution,line);
					break;
				case 12:
					strcpy(Newshome,line);
					break;
				}
				found=0;
			}
		}
		fclose(handle);
	}
	lowercase(line,Postnews);
	if(!strcmp(line,"internal"))
	{
		strcpy(Postnews,"internal");
/*
		if(Accesslevel >= UID_SUPERUSER && strcmp(Activefile,"none"))
		{
			printf(printout(MSG_ACTIVE_IN_USE),"Internal-Postnews");
		}
*/
	}
}


void do_add_group()
{
	char name[MAXNAMELEN],apu1[NAMELEN];
	struct groupnode *node;

	if(strcmp(Activefile,"none"))
	{
		printf(printout(MSG_ACTIVE_IN_USE),"Addgroup");
		return;
	}

	printf(printout(MSG_GROUP_NAME_TO_ADD));
	fflush(stdout);
	if(getline("",name,NAMELEN-2,0,1))
		return;
	lowercase(apu1,name);

	if(name[0]!=0)
	{
		if(!(node=search_group(&grouplist,apu1)))
		{
			printf(printout(MSG_ADDING_TO_SYS),prefs.Groupname,name,prefs.Normal);
			if(add_group(apu1,60,0))
			{
				printf(printout(MSG_EXISTS),name);
			}
			else
			{
				if(node=(struct groupnode *)AllocMem(sizeof(struct groupnode),MEMF_CLEAR))
				{
					NewList(&node->ReadRanges);
					node->Node.ln_Name=node->name;
					strcpy(node->name,apu1);
					node->flags=0;
					node->expire=60;

					AddTail(&grouplist,(struct Node *)node);
					printf(printout(MSG_ADDED_TO_NEWSRC),prefs.Groupname,node->name,prefs.Normal);
				}
				else
					printf(printout(MSG_TO_ADD),node->name);
			}
		}
		else
			printf(printout(MSG_EXISTS),name);
	}
}


void remove_group(struct groupnode *curnode)
{
	char name[NAMELEN];
	struct groupnode *node;

	if(strcmp(Activefile,"none"))
	{
		printf(printout(MSG_ACTIVE_IN_USE),"Deletegroup");
		return;
	}

	printf(printout(MSG_GROUP_TO_REMOVE));
	fflush(stdout);
	if(getline("",name,NAMELEN-2,0,1))
		return;
	lowercase(name,name);

	if(node=search_group(&grouplist,name))
	{
		if(node!=curnode)
		{
			delete_group(name);
			printf(printout(MSG_GROUP_REMOVED),prefs.Groupname,node->name,prefs.Normal);
			Remove((struct Node *)node);
			FreeMem((char *)node,sizeof(struct groupnode));
		}
		else
			printf("Cannot delete the group you are at.. press N or P and try again\n");
	}
	else
		printf(printout(MSG_GROUP_DOESNT_EXISTS));
}


void read_usersettings(void)
{
	char line[80];

	if(ArpBase)
	{
		who(COM_GET,NULL,"user",User);
		who(COM_GET,NULL,"home",Home);
		who(COM_GET,NULL,"realname",Realname);

		who(COM_GET,NULL,"language",language);
		if(language[0] && LocaleBase)
		{
			if(!(catalog=(struct Catalog *)OpenCatalog(NULL,"AXsh.rn.catalog",OC_Language,language,TAG_DONE)))
				printf("Can't access language %s - using English as default\n",language);
		}

		who(COM_GET,NULL,"visual",Editor);	/* default was 'editor' */
		if(!who(COM_GET,NULL,"rows",line))
		{
			Rows=atoi(line);
			if(!Rows)	Rows=24;
			if(Rows<5)	Rows=5;
			if(Rows>100)	Rows=100;
		}
		else
		{
			Rows=24;
		}

		if(!who(COM_GET,NULL,"columns",line))
		{
			Columns=atoi(line);
			if(!Columns)	Columns=80;
			if(Columns<5)	Columns=5;
			if(Columns>200)	Columns=200;
		}
		else
		{
			Columns=80;
		}

		if(who(COM_GET,NULL,"replyto",ReplyTo))
		{
			ReplyTo[0] = '\0';
		}

		who(COM_GET,NULL,"term",line);
		if(!strcmp(line,"vt100") || !strcmp(line,"vt102"))	term=VT100;
		if(!strcmp(line,"ansi"))	term=ANSI;
	}
	else
	{
		GetVar("user", User, sizeof(User), GVF_LOCAL_ONLY);
		GetVar("home", Home, sizeof(Home), GVF_LOCAL_ONLY);
		GetVar("realname", Realname, sizeof(Realname), GVF_LOCAL_ONLY);

		GetVar("language", language, sizeof(language), GVF_LOCAL_ONLY);
		if(language[0] && LocaleBase)
		{
			if(!(catalog=(struct Catalog *)OpenCatalog(NULL,"AXsh.rn.catalog",OC_Language,language,TAG_DONE)))
				printf("Can't access language %s - using English as default\n",language);
		}

		GetVar("visual", Editor, sizeof(Editor), GVF_LOCAL_ONLY); /* default was 'editor' */
		if(GetVar("rows", line, sizeof(line), GVF_LOCAL_ONLY) != -1)
		{
			Rows = atoi(line);
			if(!Rows)
				Rows = 24;
			if(Rows<5)
				Rows = 5;
			if(Rows>150)
				Rows = 150;
		}
		else
		{
			Rows = 24;
		}

		if(GetVar("columns", line, sizeof(line), GVF_LOCAL_ONLY) != -1)
		{
			Columns = atoi(line);
			if(!Columns)
				Columns = 80;
			if(Columns<5)
				Columns = 5;
			if(Columns>200)
				Columns = 200;
		}
		else
		{
			Columns = 80;
		}

		if(GetVar("replyto", ReplyTo, sizeof(ReplyTo), GVF_LOCAL_ONLY) == -1)
		{
			ReplyTo[0] = '\0';
		}

		GetVar("term", line, sizeof(line), GVF_LOCAL_ONLY);
		if(!strcmp(line,"vt100") || !strcmp(line,"vt102"))
			term = VT100;
		if(!strcmp(line,"ansi"))
			term = ANSI;
	}
}


void help(int msg)
{
	if(msg==1)
	{
		printf(printout(MSG_HELP_MAIN_Q));
		printf(printout(MSG_HELP_MAIN_N));
		printf(printout(MSG_HELP_MAIN_NN));
		printf(printout(MSG_HELP_MAIN_P));
		printf(printout(MSG_HELP_MAIN_PP));
		printf(printout(MSG_HELP_MAIN_G));
		printf(printout(MSG_HELP_MAIN_Y));
		printf(printout(MSG_HELP_MAIN_U));
		printf(printout(MSG_HELP_MAIN_L));
		printf(printout(MSG_HELP_MAIN_S));
		printf(printout(MSG_HELP_MAIN_GG));
		printf(printout(MSG_HELP_MAIN_E));

		printf(printout(MSG_HELP_ARTICLE_EQ));

		if(Accesslevel >= UID_PRIVILEGED)
			printf(printout(MSG_HELP_MAIN_A));
		if(Accesslevel >= UID_SUPERUSER)
			printf(printout(MSG_HELP_MAIN_R));
		printf("\n");
	}
	if(msg==2)
	{
		printf(printout(MSG_HELP_ARTICLE_N));
		printf(printout(MSG_HELP_ARTICLE_P));
		printf(printout(MSG_HELP_ARTICLE_NN));
		printf(printout(MSG_HELP_ARTICLE_PP));
		printf(printout(MSG_HELP_ARTICLE_CN));
		printf(printout(MSG_HELP_ARTICLE_CP));
		printf(printout(MSG_HELP_ARTICLE_CR));
		printf(printout(MSG_HELP_ARTICLE_CX));
		printf(printout(MSG_HELP_ARTICLE_CF));
		printf(printout(MSG_HELP_ARTICLE_F));
		printf(printout(MSG_HELP_ARTICLE_FF));
		printf(printout(MSG_HELP_ARTICLE_R));
		printf(printout(MSG_HELP_ARTICLE_S));
		printf(printout(MSG_HELP_ARTICLE_K));
		printf(printout(MSG_HELP_ARTICLE_C));
		printf(printout(MSG_HELP_ARTICLE_O));
		printf(printout(MSG_HELP_ARTICLE_M));
		printf(printout(MSG_HELP_ARTICLE_Q));
		printf(printout(MSG_HELP_ARTICLE_EQ));
		printf(printout(MSG_HELP_ARTICLE_NUM));
		printf(printout(MSG_HELP_MAIN_U));

		if(Accesslevel >= UID_PRIVILEGED)
			printf(printout(MSG_HELP_ARTICLE_CC));
	}
	if(msg==3)
	{
		printf(printout(MSG_WELCOME));
	}
}

#define MORE_NORMAL		0
#define MORE_HEADER		1
#define MORE_ARTICLE	2
#define MORE_INCLUDE	3

int more(char *name,int body,int rot)
{
	int i,lines=1,len,found=0,esc=0,disp=MORE_NORMAL;
	char c,line[2*MAXNAMELEN],mode=0,nomore=prefs.Bits & RN_NOMORE;
	FILE *handle;

	if(handle=fopen(name,"rb"))
	{
		if(prefs.Bits & RN_NOCURSOR)
			printf("\033[0 p");	/* Hide cursor */
		fflush(stdout);

		if(body)
			mode=2;

		line[0]='\0';

		while(!feof(handle))
		{
			i=strlen(line);
			if(fgets(line+i,2*MAXNAMELEN-2-i,handle)==0)
				break;

			i=len=0;
			while(c=line[i])
			{
				if(len>=Columns-1)
				{
					if(c!=0x0a)
					{
						c = 0x0a;
						esc = strlen(line+i)+1;
						while(esc--)
							line[i+1+esc]=line[i+esc];
/* how does that work ? */
					}
					esc=0;
				}
				if(esc)
				{
					if(c!=';' && (c<'0' || c>'9'))
						esc=0;
				}
				else
				{
					switch(c)
					{
					case 0x0c:
						printf("^L\n");
						lines=Rows-1;	/* fall through */
					case 0x0d:
						if(line[i+1]=='\n')
						{
							line[i++]='\0';
						}
					case 0x0a:
						line[i]='\0';
						len=0;
						while(line[len] && (line[len]==' ' || line[len]=='\t'))
							++len;

						if((++lines>Rows-1 && !nomore) || WaitForChar(Input(),0))
						{
							do
							{
								if(SetSignal(SIGBREAKF_CTRL_C,0) & SIGBREAKF_CTRL_C)
								{
									fclose(handle);
									if(prefs.Bits & RN_NOCURSOR)
										printf("\033[ p");	/* Reveal cursor */
									fflush(stdout);
									return -1;
								}
								if(WaitForChar(Input(),0))
								{
									if(disp!=MORE_NORMAL)
									{
										printf("%s",prefs.Normal);
										disp=MORE_NORMAL;
									}
									Read(Input(),&c,1);
								}
								else
								{
									printf("%s%sMore?%s",prefs.Normal,prefs.More,prefs.Normal);
									fflush(stdout);
									disp=MORE_NORMAL;
									Read(Input(),&c,1);
									printf("\b\b\b\b\b\033[K");
									fflush(stdout);
								}
								if(c=='h')
								{
									printf(printout(MSG_PAGER_HELP));
									help(2);
									printf("----------------\n");
								}
							}
							while(c=='h');
							switch(c)
							{
							case '.':
								nomore=TRUE;
								break;
							case ' ':
								lines-=Rows-2;
								if(prefs.Bits & RN_NOSCROLL)
									printf("\014");	/* ^L - clearscreen */
								break;
							case 0x0a:
							case 0x0d:
								lines--;
								break;
							case 'd':
								lines-=(Rows-2)/2;
								break;
							case 'q':
								c=0;	/* fall through! */
							default:
								fclose(handle);
								printf("\n");
								if(prefs.Bits & RN_NOCURSOR)
									printf("\033[ p");	/* Reveal cursor */
								return (int)c;
							}
							fflush(stdout);
						}
						if(mode<2 && !(found & 1) && !strnicmp(line,"From: ",6))
						{
							if(disp!=MORE_HEADER)
							{
								printf("%s%s",prefs.Normal,prefs.Header);
								disp=MORE_HEADER;
							}
							printf("From:%s %s%s%s\n",prefs.Normal,prefs.From,line+6,prefs.Header);
							found|=1;
						}
						else if(mode<2 && !(found & 2) && !strnicmp(line,"Date: ",6) && (prefs.Bits & RN_SHOWDATE))
						{
							if(disp!=MORE_HEADER)
							{
								printf("%s%s",prefs.Normal,prefs.Header);
								disp=MORE_HEADER;
							}
							printf("%s\n",line);
							found|=2;
						}
						else if(mode<2 && !(found & 4) && !strnicmp(line,"Organization: ",13) && (prefs.Bits & RN_SHOWORG))
						{
							if(disp!=MORE_HEADER)
							{
								printf("%s%s",prefs.Normal,prefs.Header);
								disp=MORE_HEADER;
							}
							printf("%s\n",line);
							found|=4;
						}
						else if(mode<2 && !(found & 8) && !strnicmp(line,"Subject: ",9))
						{
							if(disp!=MORE_HEADER)
							{
								printf("%s%s",prefs.Normal,prefs.Header);
								disp=MORE_HEADER;
							}
							printf("Subject:%s %s%s%s\n",prefs.Normal,prefs.Subject,line+9,prefs.Header);
							found|=8;
						}
						else if(mode==2 && line[len]=='>')
						{
							if(!(prefs.Bits & RN_HIDEINCLUDE))
							{
								if(disp!=MORE_INCLUDE)
								{
									printf("%s%s",prefs.Normal,prefs.Include);
									disp=MORE_INCLUDE;
								}
								printf("%s\n",line);
							}
							else
								lines--;
						}
						else
						{
							if(mode==1 && line[0]==0)	mode=2;
							if(mode==0 && line[0])		mode=1;
							if(line[0])
							{
								if(mode==2)
								{
									if(disp!=MORE_ARTICLE)
									{
										printf("%s%s",prefs.Normal,prefs.Article);
										disp=MORE_ARTICLE;
									}
									printf("%s\n",line);
								}
								else if(mode<2 && (prefs.Bits & RN_FULLHEADER))
								{
									if(disp!=MORE_HEADER)
									{
										printf("%s%s",prefs.Normal,prefs.Header);
										disp=MORE_HEADER;
									}
									printf("%s\n",line);
								}
								else
									lines--;
							}
							else
								printf("\n");
							if(!strnicmp(line,"Xref: ",6))
							{
								if(!strnicmp(line+6,Host,strlen(Host)))
								{
printf("TODO: handle Xref:-line\n");
								}
								else
printf("TODO: somebody elses Xref:-line!\n");
							}
						}

						if(line[i+1])
						{
							strcpy(line,line+i+1);
							i=-1;
						}
						else
						{
							line[0]=0;
						}
						len=0;
						/* line was cut */
						break;
					case 0x08:
					case 0x7f:
						if(len)
							len--;
						break;
					case 0x09:
						len=(len/8)*8+8;
						break;
					case 0x9b:
					case 0x1b:
						esc=-1;
						break;
					default:
						if(rot && mode==2)
						{
							if(c>0x3f && c<0x5b)
								c=((c-0x40)+13)%26+0x40;
							if(c>0x5f && c<0x7b)
								c=((c-0x60)+13)%26+0x60;
							line[i]=c;
						}
						++len;
						break;
					}
				}
				i++;
			}
		}
		if(disp!=MORE_NORMAL)
		{
			printf("%s",prefs.Normal);
			/*disp=MORE_NORMAL;*/
		}
		fclose(handle);
	}
	else
	{
		return -1;
	}
	if(prefs.Bits & RN_NOCURSOR)
		printf("\033[ p");	/* Reveal cursor */
	fflush(stdout);
	return 0;
}

int mail_reply(struct groupnode *group,int ref,int quote)
{
	char name[NAMELEN],arg[MAXNAMELEN],
		 from[NAMELEN],subject[NAMELEN],id[NAMELEN],apu[MAXNAMELEN],
		 *aika;
	FILE *handle,*reffile;
	int ret,i,j,wrapped;
	struct DateStamp ds;

	DateStamp(&ds);
	articlename(arg,group->name,ref,0);
	if(read_header(H_GET,arg,ref,from,apu,id,0L))
	{
		/* parse From: , currently "Full Name <email@address>" is also supported */
		parsefrom(arg,from);
		strcpy(from,arg);

		if(strlen(apu)>NAMELEN-10)
			apu[NAMELEN-10]=0;
		if(!strnicmp(apu,"Re: ",4))
			sprintf(subject,"%s (News)",apu);
		else
			sprintf(subject,"Re: %s (News)",apu);
	}
	else
	{
		printf(printout(MSG_CANNOT_REPLY));
		return 0;
	}

	printf(printout(MSG_SUBJECT_OF_ARTICLE));
	fflush(stdout);
	if(getline("",subject,NAMELEN,1,1))
		return -1;

	aika=get_time();

	sprintf(name,"%s%s-message",Tempdir,User);
	if(handle=fopen(name,"wb"))
	{
		fprintf(handle,Fupref,id,from);
		fputc('\n',handle);
		if(quote && (reffile=fopen(arg,"rb")))
		{
			ret=0;
			do
			{
				i=ret;
				ret=fgetc(reffile);
			}
			while(!(ret==0x0a && i==0x0a) && ret!=EOF);
			/* hope there is 2 linefeeds after header*/

			i=wrapped=0;
			while((ret=fgetc(reffile))!=EOF)
			{
				if(ret==0x0a || ret==0x0d)
				{
					arg[i]=0;
					if(i || !wrapped)
					{
						fprintf(handle,Quotestring,arg);
						fputc('\n',handle);
					}
					i=wrapped=0;
				}
				else
				{
					arg[i++]=ret;
					if(i>74)
					{
						arg[i]=0;
						while(i && arg[i]!=' ')	i--;
						if(i>64)
						{
							arg[i]=0;
							fprintf(handle,Quotestring,arg);
							fputc('\n',handle);
							strcpy(arg,arg+i+1);
							i=strlen(arg);
						}
						else
						{
							fprintf(handle,Quotestring,arg);
							fputc('\n',handle);
							i=0;
						}
						wrapped=1;
					}
				}
			}
			fputc(0x0a,handle);
			fclose(reffile);
		}
		fclose(handle);

		apu[0]='e';
		do
		{
			if(apu[0]=='e')
			{
				sprintf(apu,"AXsh:bin/%s",Editor);
				MyRunCommand(apu,name,Input(),Output());
				setmode(MODE_RAW);
			}
			if(apu[0]=='l')
			{
				if(!(prefs.Bits & RN_NOCLEAR))
					printf("\033[;H\033[2J");

				printf("From %s@%s at %s\n",User,Host,aika);
				printf("From: %s@%s (%s)\n",User,Host,Realname);
				printf("To: %s\n",from);
				printf("Date: %s\n",aika);
				printf("Organization: %s\n",Organization);

				if(ReplyTo[0])
				{
					printf("Reply-To: %s\n",ReplyTo);
				}

				printf("Subject: %s\n",subject);
				printf("X-Newsreader: "VERSION );
				printf("\n");

				more(name,1,0);
			}
			printf(printout(MSG_WHAT_NOW));
			fflush(stdout);

			if(getline("sael",apu,20,0,1))
				return -1;
		}
		while(apu[0]!='s' && apu[0]!='a');
		if(apu[0]=='s')
		{
			if(reffile=fopen(name,"rb"))
			{
				sprintf(name,"%s.letter",Home);
				if(handle=fopen(name,"wb"))
				{
					if(strstr(Sendmail,"mailserver"))
					{
						fprintf(handle,"From %s@%s at %s\n",User,Host,aika);
						fprintf(handle,"From: %s@%s (%s)\n",User,Host,Realname);
						fprintf(handle,"To: %s\n",from);
						fprintf(handle,"Date: %s\n",aika);
						fprintf(handle,"Organization: %s\n",Organization);
					}
					if(ReplyTo[0])
					{
						fprintf(handle,"Reply-To: %s\n",ReplyTo);
					}

					fprintf(handle,"Subject: %s\n",subject);
					fprintf(handle,"X-Newsreader: "VERSION );
					fprintf(handle,"\n");

					while(!feof(reffile))
					{
						if(fgets(apu,MAXNAMELEN,reffile)==0)
							break;
						if(!feof(reffile))
							fputs(apu,handle);
					}
					fclose(reffile);

					sprintf(name,"%s.signature%d",Home,(ds.ds_Tick/2)%10);
					if(reffile=fopen(name,"rb"))
					{
						while(fgets(apu,MAXNAMELEN,reffile))
							fputs(apu,handle);
						fclose(reffile);
					}
					else
					{
						sprintf(name,"%s.signature",Home);
						if(reffile=fopen(name,"rb"))
						{
							while(fgets(apu,MAXNAMELEN,reffile))
								fputs(apu,handle);
							fclose(reffile);
						}
						else
							printf(printout(MSG_CANT_OPEN_SIGNATURE));
					}
					fclose(handle);
				}

				i=j=0;
				while(Sendmail[i])
				{
					if(Sendmail[i]=='%')
					{
						switch(Sendmail[i+1])
						{
						case 'f':
							strcpy(arg+j,Home);
							strcat(arg,".letter");
							j+=strlen(Home)+7;
							i+=2;
							break;
						case 'u':
							strcpy(arg+j,User);
							j+=strlen(User);
							i+=2;
							break;
						case 'r':
							strcpy(arg+j,Realname);
							j+=strlen(Realname);
							i+=2;
							break;
						case 't':
							strcpy(arg+j,from);
							j+=strlen(from);
							i+=2;
							break;
						default:
							i++;
						}
					}
					else
						arg[j++]=Sendmail[i++];
				}
				arg[j]=0;
				if(Accesslevel >= UID_SUPERUSER)
					printf("Running \"%s\"\n",arg);
				Execute(arg,0,Output());
			}
			else
			{
				printf(printout(MSG_TEMP_FILE_DISAPPEARED),name);
			}
		}

		sprintf(name,"%s%s-message",Tempdir,User);
		DeleteFile(name);
	}
	else
		printf(printout(MSG_CANT_OPEN),name);

	checkgroup(Activefile,group);
	return 0;
}


void parsefrom(char *emailaddr,char *str)
{
	int i=0,j=0,lmode=1;

	while(str[i])
	{
		switch(str[i])
		{
		case '(':
			lmode=0;
			break;
		case ')':
			lmode=1;
			break;
		case '<':
			j=0;
			break;
		case '>':
			emailaddr[j]='\0';
			return;
		default:
			if(lmode)
				emailaddr[j++]=str[i];
		}
		i++;
	}
	emailaddr[j]='\0';
	i=0;
	while(emailaddr[i] && emailaddr[i]==' ')
		i++;
	if(i)
		strcpy(emailaddr,emailaddr+i);	/* remove leading spaces */
	i=0;
	while(emailaddr[i] && emailaddr[i]!=' ')
		i++;
	emailaddr[i]='\0';			/* take only first word */
}


