/* Includes -------------------------------------------------------------- */

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <signal.h>
#include <string.h>

#include <exec/exec.h>
#include <dos/dos.h>

/* Prototypes ------------------------------------------------------------ */

#include <proto/exec.h>
#include <proto/dos.h>

int mybreak(void);			/* 1.3: Changed break thing */
void myexit(int);
void tidyup(void);
int get_groups(char *);
long get_sequence(char *);

/* Variables ------------------------------------------------------------- */

char version[]="$VER: DanNews 1.4 (14-Oct-96) - By Dan Cannon <daniel_c@london.altris.com>";

extern char __stdiowin[]="CON:////";	/* 1.0: In case of error */
extern char __stdiov37[]="/AUTO/WAIT";

/* 0.3: FILE not /A 'cos can read from stdin now */
#define TEMPLATE "FILE,BLIP/K/N,CACHE/K/N,DELETE/S,DELETEOVERVIEW/S,PATH/S,READONLY/S,STATS/S,XREF/S,-1/S,-H/S,-N/S,-T/K,JUNK/M"
#define OPT_FILE	0		/* file to unbatch */
#define OPT_BLIP	1		/* 1.3: display blip */
#define OPT_CACHE	2		/* cache size */
#define OPT_DELETE	3		/* delete file after unbatch if unbatch was OK */
#define OPT_DELETEOVERVIEW 4		/* 1.1: wipe .overview files at end */
#define OPT_PATH	5		/* fix path header */
#define OPT_READONLY	6		/* not done: trim batch file when out of disk space? */
#define OPT_STATS	7		/* statistics when unbatch complete */
#define OPT_XREF	8		/* generate xref headers */
#define OPT_1		9		/* unbatch only to first OK group */
#define OPT_H		10		/* disable hard links */
#define OPT_N		11		/* no unbatching */
#define OPT_T		12		/* tempory dir for stdin */
#define OPT_JUNK	13		/* soak up rnews crap */
#define OPT_COUNT	14
LONG	opts[OPT_COUNT];
struct	RDArgs *rdargs=NULL;

#define STRING_LEN	512
#define FILE_LEN	256

BPTR filehandle_1=NULL;			/* 1.0: Changed from 4 ansi to 2 AmigaDOS */
BPTR filehandle_2=NULL;

struct group
	{
	char name[FILE_LEN+1];		/* like alt.music.techno */
	char path[FILE_LEN+1];		/* like UUNEWS:alt/music/techno/ */
	int length;			/* strlen(name) */
	long sequence;			/* from .next */
	long stat_number;		/* count of articles in this group */
	long stat_bytes;		/* total bytes for this group */
	long stat_largest;		/* largest article in this group */
	struct group *next;
	};

struct group *group_junk;		/* ptr to junk group info */
struct group *group_start;		/* ptr to junk+1 */
struct group *group_pos;		/* group working on now */

char *cache_start=NULL;			/* pointer to cache */
char *cache_end;			/* pointer to end+1 */
char *cache_real_end;			/* extra bit at end of cache */
char *cache_pos;			/* current position in the cache */
long cache_len;				/* length of cache */
long cache_real_len;			/* length + extra bit at end */
long cache_shift=0; /* 0.4: 0 */	/* amount of cache to shift */

char *header_start;			/* 0.3: start of header buffer */
char *header_pos;			/* 0.3: current pos */
long header_len;
long body_len;

char batch_name[FILE_LEN+1];
char batch_line[STRING_LEN+1];		/* 1 line from batch file */
long batch_len;				/* length of batch file */
long batch_read;			/* amount read in from batch */

struct group *unbatch_list[STRING_LEN+1]; /* arr of ng pointers for this art */
short unbatch_pos;			/* last + 1 ^^^ */
short unbatch_len;			/* length of ng name */
char *unbatch_start;			/* start ng name in article header */
char *unbatch_end;			/* end ng name: , or \n */
char unbatch_name[FILE_LEN+1];		/* filename of article unbatching now */
BPTR unbatch_lock=NULL; /* 0.3: NULL */	/* lock so link xposts to 1st */

char sitename_xref[STRING_LEN+1];	/* 0.3: machine name */
char sitename_xref_len;
char sitename_path[STRING_LEN+1];	/* 0.3: full name + ! */
char sitename_path_len;
char *sitename_ptr;

long article_len;			/* 0.2: length of this article */
long article_max=0;			/* 0.2: length of biggest article */
long article_tot=0;			/* 0.2: total length of articles */
long article_count=0;			/* 0.2: total number of articles */

int main_i;				/* 0.3: main for loop var, renamed */
long block_len;				/* length of largest block of memory */
int from_stdin=0;			/* 0.3: if file is from stdin */
int normal_article=0;

int seq_i;				/* 0.3: get_sequence stuff, moved */
long seq_number;
char seq_name[FILE_LEN+1];

long total_number=0;
long total_bytes=0;
long total_largest=0;

int display_blip=0;			/* 1.3: Blip setting */
int display_article=0;			/* 1.3: Articles done so far */
int display_countdown;			/* 1.3: Articles left until next blip */
#define DISPLAY_HEADER "Unbatching...    0/%4d\b\b\b\b\b\b\b\b\b\b",article_count

/* Code ------------------------------------------------------------------ */

int mybreak() /* 1.3: Changed break thing */
	{
	/* 1.3: Wipe blip */
	if(display_blip)
		{
		fprintf(stderr,"\r                       \r");
		fflush(stderr);
		}
	tidyup();
	return 1;
	}

void myexit(int return_code)
	{
	tidyup();
	exit(return_code);
	}

/* 1.3: Nulled variables that I've finished with */
void tidyup()
	{
	if(unbatch_lock) /* 0.3: hit ^C could leave a file locked */
		{
		UnLock(unbatch_lock);
		unbatch_lock=NULL;
		}
	if(rdargs)
		{
		FreeArgs(rdargs);
		rdargs=NULL;
		}
	while(group_junk)
		{
		group_pos=group_junk->next;
		free(group_junk);
		group_junk=group_pos;
		}
	if(cache_start)
		{
		free(cache_start);
		cache_start=NULL;
		}
	if(header_start) /* 0.3 */
		{
		free(header_start);
		header_start=NULL;
		}
	if(filehandle_1)
		{
		Close(filehandle_1);
		filehandle_1=NULL;
		}
	if(filehandle_2)
		{
		Close(filehandle_2);
		filehandle_2=NULL;
		}
	}

int main(int argc,char *argv[])
	{
	onbreak(mybreak); /* 1.3: Changed break thing */

/* Read shell args -------------------------------------------------------- */

	setmem(opts,sizeof(opts),0);
	rdargs=ReadArgs(TEMPLATE,opts,NULL);
	if(!rdargs)
		{
		PrintFault(IoErr(),NULL);
		myexit(RETURN_ERROR);
		}

	if(opts[OPT_READONLY]) /* 0.4 */
		printf("READONLY doesn't work yet: ignored\n");

/* Read in sitename ------------------------------------------------------- */

	if(opts[OPT_PATH]||opts[OPT_XREF])
		{
		filehandle_1=Open("UULIB:sitename",MODE_OLDFILE);
		if(!filehandle_1)
			filehandle_1=Open("UUCP:sitename",MODE_OLDFILE);
		if(!filehandle_1)
			{
			PrintFault(IoErr(),"Couldn't open UULIB:sitename or UUCP:sitename for reading");
			myexit(RETURN_FAIL);
			}
		FGets(filehandle_1,sitename_path,STRING_LEN);
		Close(filehandle_1); filehandle_1=NULL;

		if(sitename_ptr=strchr(sitename_path,'\n'))
			*sitename_ptr='\0';
		strcpy(sitename_xref,sitename_path);
		if(sitename_ptr=strchr(sitename_xref,'.'))
			*sitename_ptr='\0';
		strcat(sitename_path,"!");

		sitename_path_len=strlen(sitename_path);
		sitename_xref_len=strlen(sitename_xref);
		}

/* Read in newsgroups ----------------------------------------------------- */

	/* Junk group first */
	group_junk=(struct group *)malloc(sizeof(struct group));
	if(!group_junk)
		{
		printf("Couldn't allocate memory for group list\n");
		myexit(RETURN_FAIL);
		}
	strcpy(group_junk->name,"junk");
	strcpy(group_junk->path,"UUNEWS:junk/");
	group_junk->length=4;
	group_junk->sequence=get_sequence(group_junk->path);
	group_junk->stat_number=0;
	group_junk->stat_bytes=0;
	group_junk->stat_largest=0;
	group_junk->next=NULL;
	group_pos=group_junk;

	if(!get_groups("UULIB:newsgroups"))
		{
		PrintFault(IoErr(),"Couldn't open UULIB:newsgroups for reading");
		myexit(RETURN_FAIL);
		}
	get_groups("UULIB:DanNewsGroups");
	group_pos->next=NULL;
	group_start=group_junk->next;

/* Read from stdin if no file given -------------------------------------- */

	if(opts[OPT_FILE])
		strcpy(batch_name,(char *)opts[OPT_FILE]);
	else
		{
		from_stdin=1;
		if(opts[OPT_T])
			{
			strcpy(batch_name,(char *)opts[OPT_T]);
			if(batch_name[strlen(batch_name)-1]!=':'&&
			   batch_name[strlen(batch_name)-1]!='/')
				strcat(batch_name,"/");
			}
		else
			strcpy(batch_name,"T:");
		strcat(batch_name,"DanNews-Temp");
		filehandle_1=Open(batch_name,MODE_NEWFILE);
		if(!filehandle_1)
			{
			sprintf(batch_line,"Couldn't open %s for writing",batch_name);
			PrintFault(IoErr(),batch_line);
			myexit(RETURN_FAIL);
			}
		while(fgets(batch_line,STRING_LEN,stdin))
			Write(filehandle_1,batch_line,strlen(batch_line));
		Close(filehandle_1); filehandle_1=NULL;
		}

/* First scan of batch file ----------------------------------------------- */

	filehandle_1=Open(batch_name,MODE_OLDFILE);
	if(!filehandle_1) /* 0.4: Don't whine */
		myexit(RETURN_OK);

	FGets(filehandle_1,batch_line,STRING_LEN); /* 0.4: Normal article??? */
	if(memcmp(batch_line,"#! ",3))
		{
		Seek(filehandle_1,0,OFFSET_END);
		if(IoErr())
			{
			sprintf(batch_line,"Couldn't unbatch %s",batch_name);
			PrintFault(IoErr(),batch_line);
			myexit(RETURN_FAIL);
			}
		normal_article=article_count=1;
		article_max=article_len=Seek(filehandle_1,0,OFFSET_CURRENT);
		if(article_max>0)
			batch_len=article_max+STRING_LEN; /* bit for #! rnews <x>\n */
		else
			batch_len=0;
		}
	else
		{
		do
			{
			if(memcmp(batch_line,"#! rnews ",9))
				{
				if(batch_line[strlen(batch_line)-1]=='\n')
					batch_line[strlen(batch_line)-1]='\0';
				printf("Couldn't unbatch %s: ",batch_name);
				if(memcmp(batch_line,"#! ",3))
					printf("corrupt batch file");
				else
					printf("unknown unbatch type '%s'",batch_line);
				printf("\nError around %ld bytes into the file: full line reads '%s'\n",Seek(filehandle_1,0,OFFSET_CURRENT),batch_line);
				myexit(RETURN_FAIL);
				}

			article_count++;
			article_len=atol(batch_line+9);
			article_tot+=article_len;

			if(article_max<article_len)
				article_max=article_len;

			Seek(filehandle_1,article_len,OFFSET_CURRENT);
			if(IoErr())
				{
				sprintf(batch_line,"Couldn't unbatch %s",batch_name);
				PrintFault(IoErr(),batch_line);
				myexit(RETURN_FAIL);
				}
			} while(FGets(filehandle_1,batch_line,STRING_LEN));
		batch_len=Seek(filehandle_1,0,OFFSET_CURRENT);
		}

	Close(filehandle_1); filehandle_1=NULL;

	if(!batch_len)
		goto end;

/* Work out cache len & malloc it ----------------------------------------- */

	if(!opts[OPT_CACHE])
		cache_len=-100000;
	else
		cache_len=*(long *)opts[OPT_CACHE];

	Forbid();
	block_len=AvailMem(MEMF_LARGEST);
	if(cache_len>0)
		{
		if(block_len<cache_len)
			cache_len=block_len-100000; /* 1.3: better than 50K */
		}
	else
		cache_len=block_len+cache_len; /* 0.2: was - */
	if(cache_len>batch_len+STRING_LEN)
		cache_len=batch_len+STRING_LEN;
	if(cache_len>=article_max+STRING_LEN)
		cache_start=malloc(cache_len+STRING_LEN);
	Permit();

	if(!cache_start)
		{
		printf("Couldn't allocate memory for cache: need at least %ld bytes in the largest block\n",article_max+STRING_LEN); /* 0.3 */
		myexit(RETURN_FAIL);
		}

	cache_pos=cache_start;
	cache_end=cache_start+cache_len;
	cache_real_end=cache_end+STRING_LEN;
	cache_real_len=cache_len+STRING_LEN;

/* Header buffer ---------------------------------------------------------- */

	header_start=malloc(article_max); /* 0.3 */
	if(!header_start)
		{
		printf("Couldn't allocate memory for header buffer\n");
		myexit(RETURN_FAIL);
		}

/* Unbatch 'em ------------------------------------------------------------ */

	/* Open file again - AmigaDOS way (READWRITE for trim batch file when disk full someday) */
	filehandle_1=Open(batch_name,MODE_READWRITE);
	if(!filehandle_1)
		{
		sprintf(batch_line,"Couldn't open %s for updating",batch_name);
		PrintFault(IoErr(),batch_line);
		myexit(RETURN_FAIL); /* 0.3 */
		}

	if(normal_article) /* 0.4 */
		{
		strcpy(cache_start,"#! rnews ");
		cache_shift=9+stci_d(cache_start+9,article_len);
		*(cache_start+cache_shift++)='\n';
		}

	/* read in first bit. duh */
	batch_read=Read(filehandle_1,cache_start+cache_shift,cache_real_len-cache_shift);
	/* 0.4: bad batch eof fix */
	/* 1.3: Another fix */
	if(cache_start+cache_shift+batch_read<=cache_end)
		{
		memcpy(cache_start+cache_shift+batch_read,"\n\n",2);
		memcpy(cache_start+cache_shift+batch_read+9,"0\0",2);
		}

	/* 1.3: Blip option */
	if(opts[OPT_BLIP])
		if((display_blip=*(long *)opts[OPT_BLIP])<1)
			display_blip=0;
	if(display_blip)
		{
		fprintf(stderr,DISPLAY_HEADER);
		fflush(stderr);
		}
	display_countdown=display_blip;

	/* 1.3: From do to while, got rid of an if */
	/* get len */
	while(article_len=atol(cache_pos+9))
		{
		/* 1.3: Blip option */
		if(display_blip)
			{
			display_article++;
			if(!--display_countdown)
				{
				display_countdown=display_blip;
				fprintf(stderr," %4d\b\b\b\b\b",display_article);
				fflush(stderr);
				}
			}

		/* move past nl */
		cache_pos=strchr(cache_pos,'\n')+1;

		/* would we fall off the end? */
		if(cache_pos+article_len>cache_end)
			{
			/* amount to shift */
			cache_shift=cache_real_end-cache_pos;

			/* copy from current to end back to start of cache */
			memcpy(cache_start,cache_pos,cache_shift);

			/* read as much into the cache as possible */
			batch_read=Read(filehandle_1,cache_start+cache_shift,cache_real_len-cache_shift);

			/* 0.4: bad batch eof fix */
			/* 1.3: Another fix */
			if(article_len+batch_read<=cache_len)
				{
				memcpy(cache_start+cache_shift+batch_read,"\n\n",2);
				memcpy(cache_start+cache_shift+batch_read+9,"0\0",2);
				}

			/* pointer back */
			cache_pos=cache_start;
			}

		unbatch_pos=0;

/* --- 0.3 --- */

		unbatch_start=cache_pos;
		header_pos=header_start;

/* 1.3: Changed to cope with \n and #! as end of header markers, also changed
 * to cases instead of ifs.
 */
		while(*unbatch_start!='\n'&&*unbatch_start!='#')
			switch(*unbatch_start)
				{
				case 'C':
					if(!memcmp(unbatch_start+1,"ontrol: ",8))
						{
						header_len=strchr(unbatch_start,'\n')-unbatch_start+1;
						memcpy(header_pos,unbatch_start,header_len);
						header_pos+=header_len;
						unbatch_start+=9;

						unbatch_len=strpbrk(unbatch_start,"\n ,")-unbatch_start;
						group_pos=group_start;
						while(group_pos)
							{
							if(group_pos->length==unbatch_len+8)
								if(!memcmp(group_pos->name,"control.",8)&&
								   !memcmp(group_pos->name+8,unbatch_start,unbatch_len))
									{
									unbatch_list[unbatch_pos++]=group_pos;
									break;
									}
							group_pos=group_pos->next;
							}
						unbatch_start=strchr(unbatch_start,'\n')+1;
						continue;
						}

				case 'N':
					if(!memcmp(unbatch_start+1,"ewsgroups: ",11))
						{
						header_len=strchr(unbatch_start,'\n')-unbatch_start+1;
						memcpy(header_pos,unbatch_start,header_len);
						header_pos+=header_len;
						unbatch_start+=11;

						/* make array of valid ngs */
						while(*(unbatch_start++)!='\n')
							{
							unbatch_end=strpbrk(unbatch_start,"\n,");
							unbatch_len=unbatch_end-unbatch_start;
							group_pos=group_start;
							while(group_pos)
								{
								if(group_pos->length==unbatch_len)
									if(!memcmp(group_pos->name,unbatch_start,unbatch_len))
										{
										unbatch_list[unbatch_pos++]=group_pos;
										break;
										}
								group_pos=group_pos->next;
								}
							unbatch_start=unbatch_end;
							}
						continue;
						}

				case 'P':
					if(opts[OPT_PATH]&&!memcmp(unbatch_start+1,"ath: ",5))
						{
						header_len=strchr(unbatch_start,'\n')-unbatch_start+1;
						memcpy(header_pos,unbatch_start,6);
						strcpy(header_pos+6,sitename_path);
						memcpy(header_pos+6+sitename_path_len,unbatch_start+6,header_len-6);
						header_pos+=header_len+sitename_path_len;
						unbatch_start+=header_len;
						continue;
						}

				case 'X':
					if(opts[OPT_XREF]&&!memcmp(unbatch_start+1,"ref: ",5))
						{
						unbatch_start=strchr(unbatch_start,'\n')+1;
						continue;
						}

				default:
					header_len=strchr(unbatch_start,'\n')-unbatch_start+1;
					memcpy(header_pos,unbatch_start,header_len);
					header_pos+=header_len;
					unbatch_start+=header_len;
				}

/* --- 0.3 end --- */

		/* if no valid ng, put in junk */
		if(!unbatch_pos)
			unbatch_list[unbatch_pos++]=group_junk;

		if(opts[OPT_1])
			unbatch_pos=1;

		if(unbatch_pos>1&&opts[OPT_XREF])
			{
			strcpy(header_pos,"Xref: ");
			strcat(header_pos,sitename_xref);
			for(main_i=0;main_i<unbatch_pos;main_i++)
				{
				strcat(header_pos," ");
				strcat(header_pos,unbatch_list[main_i]->name);
				strcat(header_pos,":");
				stci_d(header_pos+strlen(header_pos),unbatch_list[main_i]->sequence);
				}
			header_pos=strchr(header_pos,'\0');
			*header_pos++='\n';
			}

		header_len=header_pos-header_start;
		body_len=article_len-(unbatch_start-cache_pos);

		/* got our ngs, unbatch article to each ng */
		for(main_i=0;main_i<unbatch_pos;main_i++)
			{
			/* unbatch first */
			strcpy(unbatch_name,unbatch_list[main_i]->path);
			stci_d(unbatch_name+unbatch_list[main_i]->length+8,unbatch_list[main_i]->sequence++);
			unbatch_list[main_i]->stat_number++;
			unbatch_list[main_i]->stat_bytes+=article_len;
			if(article_len>unbatch_list[main_i]->stat_largest)
				unbatch_list[main_i]->stat_largest=article_len;

			/* can we link? */
			if(unbatch_lock)
				{
				if(!MakeLink(unbatch_name,unbatch_lock,LINK_HARD))
					{
					filehandle_2=Open(unbatch_name,MODE_NEWFILE);
					if(filehandle_2)
						{
						Write(filehandle_2,header_start,header_len);
						Write(filehandle_2,unbatch_start,body_len);
						Close(filehandle_2); filehandle_2=NULL;
						}
					else
						{
						if(display_blip)
							{
							fprintf(stderr,"\r");
							fflush(stderr);
							}
						sprintf(batch_line,"Couldn't link or open %s for writing",unbatch_name);
						PrintFault(IoErr(),batch_line);
						if(display_blip)
							fprintf(stderr,DISPLAY_HEADER);
						}
					}
				}
			else if(!opts[OPT_N])
				{
				/* write */
				filehandle_2=Open(unbatch_name,MODE_NEWFILE);
				if(filehandle_2)
					{
					Write(filehandle_2,header_start,header_len);
					Write(filehandle_2,unbatch_start,body_len);
					Close(filehandle_2); filehandle_2=NULL;
					if(!opts[OPT_H]&&unbatch_pos!=1)
						unbatch_lock=Lock(unbatch_name,SHARED_LOCK);
					}
				else
					{
					if(display_blip)
						{
						fprintf(stderr,"\r");
						fflush(stderr);
						}
					sprintf(batch_line,"Couldn't open %s for writing",unbatch_name);
					PrintFault(IoErr(),batch_line);
					if(display_blip)
						fprintf(stderr,DISPLAY_HEADER);
					}
				}
			}
		if(unbatch_lock)
			{
			UnLock(unbatch_lock);
			unbatch_lock=NULL; /* 0.3: moved for ^C */
			}
		cache_pos+=article_len;
		}
	Close(filehandle_1); filehandle_1=NULL;

/* Write out new sequence no's -------------------------------------------- */

	if(display_blip)
		{
		fprintf(stderr,"\r                       \r");
		fflush(stderr);
		}

	if(!opts[OPT_N])
		{
		group_pos=group_junk;
		while(group_pos)
			{
			if(group_pos->stat_number)
				{
				strcpy(unbatch_name,group_pos->path);
				strcat(unbatch_name,".next");
				filehandle_1=Open(unbatch_name,MODE_NEWFILE);
				if(filehandle_1)
					{
					VFPrintf(filehandle_1,"%ld",&group_pos->sequence);
					Close(filehandle_1); filehandle_1=NULL;
					}
				/* 1.1: Delete .overview files */
				if(opts[OPT_DELETEOVERVIEW])
					{
					strcpy(unbatch_name+strlen(unbatch_name)-4,"overview");
					DeleteFile(unbatch_name); /* 1.3: Wiped error check */
					}
				}
			group_pos=group_pos->next;
			}
		}

end:

	if(from_stdin||opts[OPT_DELETE]&&!opts[OPT_N])
		if(!DeleteFile(batch_name))
			{
			sprintf(batch_line,"Couldn't delete %s",batch_name);
			PrintFault(IoErr(),batch_line);
			}

/* End -------------------------------------------------------------------- */

	if(opts[OPT_STATS])
		{
		printf(" Number   Bytes Largest\n");
		printf("------- ------- -------\n");
		group_pos=group_junk;
		while(group_pos)
			{
			if(group_pos->stat_number)
				{
				printf("%7ld %7ld %7ld %s\n",group_pos->stat_number,group_pos->stat_bytes,group_pos->stat_largest,group_pos->name);
				total_number+=group_pos->stat_number;
				total_bytes+=group_pos->stat_bytes;
				if(group_pos->stat_largest>total_largest)
					total_largest=group_pos->stat_largest;
				}
			group_pos=group_pos->next;
			}
		printf("------- ------- -------\n");
		printf("%7ld %7ld %7ld Total\n",total_number,total_bytes,total_largest);
		}
	else
		printf("Unbatch completed\n");

	myexit(RETURN_OK);
	}

/* Loads newsgroups list in from the file name ---------------------------- */

int get_groups(char *name)
	{
	/* Open file */
	if(!(filehandle_1=Open(name,MODE_OLDFILE)))
		return 0;

	while(FGets(filehandle_1,batch_line,STRING_LEN))
		{
		group_pos=group_pos->next=(struct group *)malloc(sizeof(struct group));
		if(!group_pos)
			{
			printf("Couldn't allocate memory for group list\n");
			myexit(RETURN_FAIL);
			}

		batch_len=strpbrk(batch_line,"\t\n ")-batch_line;
		memcpy(group_pos->name,batch_line,batch_len);
		group_pos->name[batch_len]='\0';

		strcpy(group_pos->path,"UUNEWS:");
		strcat(group_pos->path,group_pos->name);
		for(main_i=7;group_pos->path[main_i]!='\0';main_i++)
			if(group_pos->path[main_i]=='.')
				group_pos->path[main_i]='/';
		strcat(group_pos->path,"/");

		group_pos->length=batch_len;
		group_pos->sequence=get_sequence(group_pos->path);
		group_pos->stat_number=0;
		group_pos->stat_bytes=0;
		group_pos->stat_largest=0;
		}
	Close(filehandle_1); filehandle_1=NULL;
	return 1;
	}

/* Returns sequence number from path, makes path if need to --------------- */

long get_sequence(char *seq_path)
	{
	strcpy(seq_name,seq_path);
	strcat(seq_name,".next");

	filehandle_2=Open(seq_name,MODE_OLDFILE);
	if(!filehandle_2)
		{
		if(opts[OPT_N])
			return 1;
		for(seq_i=7;seq_name[seq_i]!='\0';seq_i++)
			if(seq_name[seq_i]=='/')
				{
				seq_name[seq_i]='\0';
				UnLock(CreateDir(seq_name));
				seq_name[seq_i]='/';
				}
		return 1;
		}
	FGets(filehandle_2,batch_line,STRING_LEN);
	Close(filehandle_2); filehandle_2=NULL;
	if((seq_number=atol(batch_line))<1)
		seq_number=1;
	return seq_number;
	}
