/*****************************************************************************
 *
 * $Id: file.c,v 1.44 2007/06/09 11:48:49 mbse Exp $
 * Purpose ...............: All the file functions. 
 *
 *****************************************************************************
 * Copyright (C) 1997-2007
 *   
 * Michiel Broek		FIDO:		2:280/2802
 * Beekmansbos 10
 * 1971 BV IJmuiden
 * the Netherlands
 *
 * This file is part of MBSE BBS.
 *
 * This BBS 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 2, or (at your option) any
 * later version.
 *
 * MBSE BBS 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 MBSE BBS; see the file COPYING.  If not, write to the Free
 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *****************************************************************************/

#include "../config.h"
#include "../lib/mbselib.h"
#include "../lib/mbse.h"
#include "../lib/users.h"
#include "../lib/mbsedb.h"
#include "filesub.h"
#include "file.h"
#include "funcs.h"
#include "input.h"
#include "language.h"
#include "misc.h"
#include "timeout.h"
#include "exitinfo.h"
#include "whoson.h"
#include "change.h"
#include "dispfile.h"
#include "term.h"
#include "ttyio.h"
#include "openport.h"
#include "transfer.h"



extern int	arecno;		/* File area number in xxxScan() functions   */
int		Strlen = 0;
int		FileRecno = 0;
extern int	rows;


int CheckFile(char *, int);
int CheckFile(char *File, int iArea)
{
    struct _fdbarea *fdb_area = NULL;

    if ((fdb_area = mbsedb_OpenFDB(iArea, 30)) == NULL)
	return FALSE;

    /*
     * Check long and short filenames, case insensitive
     */
    while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) {
	if (((strcasecmp(fdb.Name, File)) == 0) || ((strcasecmp(fdb.LName, File)) == 0)) {
	    mbsedb_CloseFDB(fdb_area);
	    return TRUE;
	}
    }

    mbsedb_CloseFDB(fdb_area);
    return FALSE;
}



/*
 * Show filelist from current area, called from the menu.
 */
void File_List()
{
    int		    FileCount = 0;
    unsigned	    FileBytes = 0;
    _Tag	    T;
    struct _fdbarea *fdb_area = NULL;
    char	    temp[81];

    iLineCount = 0;
    WhosDoingWhat(FILELIST, NULL);

    Syslog('+', "Listing File Area # %d", iAreaNumber);

    if (Access(exitinfo.Security, area.LTSec) == FALSE) {
	Enter(1);
	/* You don't have enough security to list this area */
	pout(YELLOW, BLACK, (char *) Language(236));
	Enter(2);
	Pause();
	return;
    }

    InitTag();

    if ((fdb_area = mbsedb_OpenFDB(iAreaNumber, 30)) == NULL)
	return;

    if (utf8)
	chartran_init((char *)"CP437", (char *)"UTF-8", 'b');

    clear();
    Header();
    if (iLC(2) == 1) {
	mbsedb_CloseFDB(fdb_area);
	chartran_close();
	return;
    }

    while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) {
	memset(&T, 0, sizeof(T));
	T.Area   = iAreaNumber;
	T.Active = FALSE;
	T.Size   = fdb.Size;
	strncpy(T.SFile, fdb.Name, 12);
	strncpy(T.LFile, chartran(fdb.LName), 80);
	SetTag(T);

	if (ShowOneFile() == 1) {
	    mbsedb_CloseFDB(fdb_area);
	    chartran_close();
	    return;
	}

	if (fdb.Deleted) {
	    /* D E L E T E D */ /* Uploaded by: */
	    snprintf(temp, 81, " -- %-12s     %s     [%4d] %s%s\n", fdb.Name, (char *) Language(239), 
				fdb.TimesDL, (char *) Language(238), fdb.Uploader);
	    PUTSTR(temp);
	}

	FileCount++;			/* Increase File Counter by 1 */
	FileBytes += fdb.Size;		/* Increase File Byte Count   */
    }

    Mark();
	
    Enter(1);
    /* Total Files: */
    snprintf(temp, 81, "%s%d / %d bytes", (char *) Language(242), FileCount, FileBytes);
    pout(LIGHTCYAN, BLACK, temp);
    Enter(2);
    chartran_close();

    iLineCount = 0;
    mbsedb_CloseFDB(fdb_area);
    Pause();
}



/*
 * Download files already tagged, called from the menu.
 */
void Download(void)
{
    FILE	    *tf, *fd;
    int		    rc = 0, i, Count = 0, OldArea;
    char	    *local, *temp;
    int		    Size = 0, CostSize = 0, dsize;
    struct _fdbarea *fdb_area = NULL;
    down_list	    *dl = NULL, *tmpf;

    Enter(2);
    OldArea = iAreaNumber;
    WhosDoingWhat(DOWNLOAD, NULL);

    /*
     * Clean users tag directory.
     */
    temp = calloc(PATH_MAX, sizeof(char));
    snprintf(temp, PATH_MAX, "-rf %s/%s/tag", CFG.bbs_usersdir, exitinfo.Name);
    execute_pth((char *)"rm", temp, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null");
    snprintf(temp, PATH_MAX, "%s/%s/tag", CFG.bbs_usersdir, exitinfo.Name);
    CheckDir(temp);

    if ((tf = fopen("taglist", "r+")) == NULL) {
	Syslog('+', "Download command but no files marked");
	/* No files marked for download. */
	pout(LIGHTRED, BLACK, (char *) Language(258));
	Enter(2);
	Pause();
	return;
    }

    local   = calloc(PATH_MAX, sizeof(char));
    /* Checking your marked downloads, please wait... */
    pout(LIGHTMAGENTA, BLACK, (char *) Language(255));
    Enter(2);

    ReadExitinfo();
    while (fread(&Tag, sizeof(Tag), 1, tf) == 1) {
	if (Tag.Active) {

	    SetFileArea(Tag.Area);

	    /*
	     * Check password for selected file  FIXME: Where???
	     */
	    memset(&fdb, 0, sizeof(fdb));
	    if ((fdb_area = mbsedb_OpenFDB(Tag.Area, 30)) != NULL) {
		while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) {
		    if (strcmp(fdb.LName, Tag.LFile) == 0)
			break;
		}
		mbsedb_CloseFDB(fdb_area);
	    }

	    if (strcmp(fdb.LName, Tag.LFile) == 0) {
		Syslog('b', "Found file %s in area %d", fdb.LName, Tag.Area);
		if (fdb.Deleted) {
		    /* Sorry that file is unavailable for download */
		    snprintf(temp, 81, "%s (%s)", (char *) Language(248), fdb.LName);
		    poutCR(CFG.HiliteF, CFG.HiliteB, temp);
		    Tag.Active = FALSE;
		    Syslog('+', "File %s in area %d unavailable for download, deleted", fdb.LName, Tag.Area);
		}
	    }

	    if (Tag.Active) {
		/*
		 * Create/Append file description list while we're
		 * busy checking. If the users doesn't want it we
		 * can unlink it aftwerwards. We also insert CR
		 * characters to please the poor DOS (M$oft) users.
		 */
		snprintf(local, PATH_MAX, "./tag/filedesc.%d", exitinfo.Downloads % 256);
		if ((fd = fopen(local, "a")) != NULL) {
		    fprintf(fd, "%s (%s)\r\n", fdb.LName, fdb.Name);
		    for (i = 0; i < 25; i++) {
			if (strlen(fdb.Desc[i]) > 1)
			    fprintf(fd, "  %s\r\n", fdb.Desc[i]);
		    }
		    fprintf(fd, "\r\n");
		    fclose(fd);
		    Syslog('b', "Added info to %s", local);
		} else {
		    WriteError("Can't add info to %s", local);
		}

		snprintf(local, PATH_MAX, "%s/%s", sAreaPath, Tag.LFile);
		add_download(&dl, local, Tag.LFile, Tag.Area, fdb.Size, FALSE);

		Home();
	    } 

	    if (!Tag.Active) {
		/*
		 * Update the download active flag in the
		 * taglist
		 */
		fseek(tf, - sizeof(Tag), SEEK_CUR);
		fwrite(&Tag, sizeof(Tag), 1, tf);
		Syslog('b', "Download file %s marked inactive in taglist", Tag.LFile);
	    } else {
		/*
		 * Count file and sizes.
		 */
		Count++;
		Size += fdb.Size;
		if (!area.Free)
		    CostSize += fdb.Size;
	    }
	}
    }
    fclose(tf);

    /*
     * If anything left to download...
     */
    if (!Count) {
	SetFileArea(OldArea);
	unlink("taglist");
	/* No files marked for download */
	pout(LIGHTRED, BLACK, (char *) Language(258));
	Enter(2);
	Pause();
	free(temp);
	free(local);
	tidy_download(&dl);
	Syslog('+', "No files left to download");
	return;
    }

    /*
     * Add descriptions file to the queue.
     */
    snprintf(local, PATH_MAX, "%s/%s/tag/filedesc.%d", CFG.bbs_usersdir, exitinfo.Name, exitinfo.Downloads % 256);
    dsize = file_size(local);
    snprintf(temp, PATH_MAX, "filedesc.%d", exitinfo.Downloads % 256);
    add_download(&dl, local, temp, 0, dsize, TRUE);
    free(local);

    /* You have */ /* files( */ /* bytes) marked for download */
    snprintf(temp, PATH_MAX, "%s %d %s%d %s", (char *) Language(249), Count, (char *) Language(280), Size, (char *) Language(281));
    pout(YELLOW, BLACK, temp);
    Enter(2);

    if (!CheckBytesAvailable(CostSize)) {
	SetFileArea(OldArea);
	free(temp);
	tidy_download(&dl);
	return;
    }

    Pause();

    if ((rc = download(dl))) {
	/*
	 * Download error
	 */
	Syslog('+', "Download error rc=%d", rc);
	free(temp);
	tidy_download(&dl);
	return;
    }
    
    /*
     * Checking the successfull sent files, they are missing from
     * the ./tag directory. Failed files are still there.
     */
    PUTCHAR('\r');
    /* Updating download counters, please wait ... */
    pout(LIGHTCYAN, BLACK, (char *) Language(352));
    Count = Size = 0; 

    /*
     * Update downloadcounters, don't log anything because the state
     * of sucessfull sent files is already logged by the download
     * function.
     */
    if ((tf = fopen("taglist", "r+")) != NULL) {
	while (fread(&Tag, sizeof(Tag), 1, tf) == 1) {
	    PUTCHAR('.');
	    if (Tag.Active) {
		for (tmpf = dl; tmpf; tmpf = tmpf->next) {
		    if (strcmp(tmpf->remote, Tag.LFile) == 0) {
			if (tmpf->sent) {
		
			    Tag.Active = FALSE;
			    fseek(tf, - sizeof(Tag), SEEK_CUR);
			    fwrite(&Tag, sizeof(Tag), 1, tf);

			    /*
			     * Update the download counter and the last download date.
			     */
			    SetFileArea(Tag.Area);
			    if ((fdb_area = mbsedb_OpenFDB(Tag.Area, 30))) {
				while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) {
				    if (strcmp(fdb.LName, Tag.LFile) == 0)
					break;
				}
				Size += fdb.Size;
				fdb.TimesDL++;
				fdb.LastDL = time(NULL);
				if (mbsedb_LockFDB(fdb_area, 30)) {
				    fseek(fdb_area->fp, - fdbhdr.recsize, SEEK_CUR);
				    fwrite(&fdb, fdbhdr.recsize, 1, fdb_area->fp);
				    mbsedb_UnlockFDB(fdb_area);
				}
				mbsedb_CloseFDB(fdb_area);
				Count++;
			    }
			}
			break;
		    }
		}
	    }
	}
	fclose(tf);
    }
    Enter(2);

    /*
     * Update the users record.
     */
    ReadExitinfo();

    exitinfo.Downloads += Count;          /* Increase download counter      */
    exitinfo.DownloadK += (Size / 1024);  /* Increase amount download today */

    /*
     * Minus the amount downloaded today from downloadktoday
     * if less than zero, it won't let the user download anymore.
     */
    if (LIMIT.DownK || LIMIT.DownF) {
	exitinfo.DownloadKToday -= (Size / 1024);
    }

    WriteExitinfo();
    Pause();
    SetFileArea(OldArea);
    free(temp);
    tidy_download(&dl);
}



/*
 * Show Raw directory
 */
void File_RawDir(char *OpData)
{
    DIR		    *dirp;
    char	    *FileName, *temp, temp2[81];
    int		    iFileCount = 0, LineCount = 2, iBytes = 0;
    struct dirent   *dp;
    struct stat	    statfile;

    FileName = calloc(PATH_MAX, sizeof(char));
    temp     = calloc(PATH_MAX, sizeof(char));

    if ((strcmp(OpData, "/F")) == 0)
	strcpy(temp, sAreaPath);
    else
	strcpy(temp, OpData);

    if ((dirp = opendir(temp)) == NULL) {
	clear();
	WriteError("$RawDir: Can't open dir: %s", temp);
	Enter(1);
	pout(LIGHTRED, BLACK, (char *)"Can't open directory for raw listing!");
	Enter(2);
	Pause();
    } else {
	if (utf8)
	    chartran_init((char *)"CP437", (char *)"UTF-8", 'b');

	clear();
	/* Filename                                   Size        Date */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(261));
	Enter(1);
	PUTSTR(chartran(fLine_str(78)));

	while ((dp = readdir( dirp )) != NULL ) {
	    snprintf(FileName, PATH_MAX, "%s/%s", temp, dp->d_name);

	    if (*(dp->d_name) != '.') {
		iFileCount++;
		if (stat(FileName, &statfile) != 0) {
		    pout(LIGHTRED, BLACK, (char *)"Can't stat file ");
		    PUTSTR(FileName);
		} else {
		    iBytes += statfile.st_size;

		    snprintf(temp2, 81, "%-54s " , dp->d_name);
		    pout(YELLOW, BLACK, temp2);

		    snprintf(temp2, 81, "%-12d", (int)(statfile.st_size));
		    pout(LIGHTMAGENTA, BLACK, temp2);

		    snprintf(temp2, 81, "%-10s", StrDateDMY(statfile.st_mtime));
		    pout(LIGHTGREEN, BLACK, temp2);
		}
		Enter(1);

		LineCount++;
		if (LineCount == rows) {
		    Pause();
		    LineCount = 0;
		}
	    }
	}

	colour(CFG.HiliteF, CFG.HiliteB);
	PUTSTR(chartran(fLine_str(78)));
	/* Total Files: */ /* Bytes */
	snprintf(temp2, 81, "%s %d, %d %s", (char *) Language(242), iFileCount, iBytes, (char *) Language(354));
	pout(LIGHTGREEN, BLACK, temp2);
	Enter(2);

	Pause();
	closedir(dirp);
	chartran_close();
    }

    free(temp);
    free(FileName);
}



/*
 * Search for keyword, called from menu.
 */
int KeywordScan()
{
    FILE	    *pAreas;
    int		    i, z, y, Found, Count = 0;
    char	    *Name, *tmpname, *BigDesc, temp[81];
    _Tag	    T;
    unsigned int    OldArea;
    struct _fdbarea *fdb_area = NULL;

    Name     = calloc(81, sizeof(char));
    tmpname  = calloc(81, sizeof(char));
    BigDesc  = calloc(1230, sizeof(char));
    OldArea  = iAreaNumber;

    iLineCount = 2; /* Reset Line Counter to Zero */
    arecno     = 1; /* Reset Area Number to One */

    Enter(2);
    /* Enter keyword to use for Search: */
    pout(LIGHTCYAN, BLACK, (char *) Language(267));

    colour(CFG.InputColourF, CFG.InputColourB);
    GetstrC(Name, 80);

    if ((strcmp(Name, "")) == 0)
	return 0;

    strcpy(tmpname, tl(Name));
    strcpy(Name, "");
    y = strlen(tmpname);
    for (z = 0; z <  y; z++) {
	if (tmpname[z] != '*') {
	    snprintf(temp, 81, "%c", tmpname[z]);
	    strcat(Name, temp);
	}
    }
    Syslog('+', "KeywordScan(): \"%s\"", Name);

    clear();
    /* File search by keyword */
    pout(WHITE, BLACK, (char *) Language(268));
    Enter(1);
    InitTag();

    if ((pAreas = OpenFareas(FALSE)) == NULL)
	return 0;

    while (fread(&area, areahdr.recsize, 1, pAreas) == 1) {

	if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) {

	    if ((fdb_area = mbsedb_OpenFDB(arecno, 30))) {
		Nopper();
		Found = FALSE;
		Sheader();

		while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) {
		    for (i = 0; i < 25; i++)
			snprintf(BigDesc, 1230, "%s%s", BigDesc, *(fdb.Desc + i));

		    if ((strstr(fdb.Name,Name) != NULL) || (strstr(tl(BigDesc), Name) != NULL)) {

			if (!Found) {
			    Enter(2);
			    if (iLC(2) == 1) {
				free(BigDesc);
				free(Name);
				free(tmpname);
				SetFileArea(OldArea);
				return 1;
			    }
			    Found = TRUE;
			}

			memset(&T, 0, sizeof(T));
			T.Area   = arecno;
			T.Active = FALSE;
			T.Size   = fdb.Size;
			strncpy(T.SFile, fdb.Name, 12);
			strncpy(T.LFile, fdb.LName, 80);
			SetTag(T);
			Count++;
			if (ShowOneFile() == 1) {
			    free(BigDesc);
			    free(Name);
			    free(tmpname);
			    SetFileArea(OldArea);
			    return 1;
			}
		    }
		    strcpy(BigDesc, "");  /* Clear BigDesc */

		} /* while */

		mbsedb_CloseFDB(fdb_area);
		if (Found) {
		    Enter(2);
		    if (iLC(2) == 1) {
			free(BigDesc);
			free(Name);
			free(tmpname);
			SetFileArea(OldArea);
			return 1;
		    }
		}

	    } /* End check for LTSec */
	} /* if access */
	arecno++; /* Go to next file area */
    } /* End of Main */

    Syslog('+', "Found %d files", Count);
    free(BigDesc);
    free(Name);
    free(tmpname);
    fclose(pAreas);
    Enter(1);
    if (Count)
	Mark();
    else
	Pause();
    SetFileArea(OldArea);
    return 1;
}



/*
 * Search for a file, called from the menu.
 */
int FilenameScan()
{
    FILE	    *pAreas;
    int		    Found, Count = 0;
    char	    mask[256];
    char	    *Name;
    _Tag	    T;
    unsigned int    OldArea;
    struct _fdbarea *fdb_area = NULL;

    Name     = calloc(81, sizeof(char));
    OldArea  = iAreaNumber;

    iLineCount = 2; /* Reset Line Counter to Zero */
    arecno     = 1; /* Reset Area Number to One  */

    Enter(2);
    /* Accepts wildcards such as : *.zip, *.gz, *.* */
    pout(WHITE, BLACK, (char *) Language(269));

    Enter(2);
    /* Enter filename to search for : */
    pout(LIGHTCYAN, BLACK, (char *) Language(271));

    colour(CFG.InputColourF, CFG.InputColourB);
    GetstrC(Name, 80);

    if ((strcmp(Name, "")) == 0) {
	free(Name);
	return 0;
    }

    strcpy(mask, re_mask(Name, TRUE));
    Syslog('+', "FilenameScan(): \"%s\" -> \"%s\"", Name, mask);
    free(Name);
    re_comp(mask);

    clear();
    /* File Search by Filename */
    pout(WHITE, BLACK, (char *) Language(272));
    Enter(1);
    InitTag();

    if ((pAreas = OpenFareas(FALSE)) == NULL)
	return 0;

    while (fread(&area, areahdr.recsize, 1, pAreas) == 1) {
	if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) {

	    if ((fdb_area = mbsedb_OpenFDB(arecno, 30))) {
		Found = FALSE;
		Sheader();
		Nopper();

		while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) {
		    if (re_exec(fdb.Name) || re_exec(fdb.LName)) {
			if (!Found) {
			    Enter(2);
			    if (iLC(2) == 1) {
				SetFileArea(OldArea);
				return 1;
			    }
			    Found = TRUE;
			}

			memset(&T, 0, sizeof(T));
			T.Area   = arecno;
			T.Active = FALSE;
			T.Size   = fdb.Size;
			strncpy(T.SFile, fdb.Name, 12);
			strncpy(T.LFile, fdb.LName, 81);
			SetTag(T);
			Count++;
			if (ShowOneFile() == 1) {
			    SetFileArea(OldArea);
			    return 1;
			}
		    }

		} /* End of while */

		mbsedb_CloseFDB(fdb_area);
		if (Found) {
		    Enter(2);
		    if (iLC(2) == 1) {
			SetFileArea(OldArea);
			return 1;
		    }
		}

	    } /* End Check for LTSec */
	} /* if access */
	arecno++; /* Go to next file area */

    } /* End of Main */

    Syslog('+', "Found %d files", Count);
    fclose(pAreas);
    Enter(1);
    if (Count)
	Mark();
    else
	Pause();
    SetFileArea(OldArea);
    return 1;
}



/*
 * Scan for new files, called from menu.
 */
int NewfileScan(int AskStart) 
{ 
    FILE    *pAreas;
    int	    ifDate, itDate;
    char    *temp, *Date;
    int	    Found, Count = 0;
    _Tag    T;
    struct _fdbarea *fdb_area = NULL;

    Date     = calloc(81, sizeof(char));
    temp     = calloc(81, sizeof(char));

    iLineCount = 2;
    arecno     = 1; /* Reset Area Number to One  */

    if (AskStart) {
	Enter(2);
	/* Search for new since your last call [Y/n]: */
	pout(LIGHTCYAN, BLACK, (char *) Language(273));
	colour(CFG.InputColourF, CFG.InputColourB);

	if (toupper(Readkey()) == Keystroke(273, 1)) {
	    Enter(1);
	    /* Enter new date to search for [DD-MM-YYYY]: */
	    pout(GREEN, BLACK, (char *) Language(274));
	    colour(CFG.InputColourF, CFG.InputColourB);
	    GetDate(temp, 10);
	} else {
	    strcpy(temp, LastLoginDate);
	}
    } else {
	strcpy(temp, LastLoginDate);
    }

    Syslog('+', "NewfileScan() since %s", temp);
    clear();
    /* File Search by Date */
    pout(WHITE, BLACK, (char *) Language(275));
    Enter(2);

    Date[0] = temp[6];	/* Swap the date around      */
    Date[1] = temp[7];	/* Instead of   DD-MM-YYYY   */
    Date[2] = temp[8];	/* Let it equal YYYYMMDD     */
    Date[3] = temp[9];	/* Swap the date around      */
    Date[4] = temp[3];	/* Swap the date around      */
    Date[5] = temp[4];	/* because when you convert  */
    Date[6] = temp[0];	/* a string to an int you    */
    Date[7] = temp[1];	/* loose the front Zero      */
    Date[8] = '\0';   	/* making the number smaller */
    itDate = atol(Date);

    InitTag();

    if ((pAreas = OpenFareas(FALSE)) == NULL)
	return 0;

    while (fread(&area, areahdr.recsize, 1, pAreas) == 1) {

	if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0) && (area.New)) {

	    if ((fdb_area = mbsedb_OpenFDB(arecno, 30))) {
		Sheader();
		Found = FALSE;
		Nopper();

		while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) {
		    strcpy(temp, StrDateDMY(fdb.UploadDate));	/* Realloc Space for Date */
		    Date[0] = temp[6];	    /* Swap the date around      */
		    Date[1] = temp[7];	    /* Instead of   DD-MM-YYYY   */
		    Date[2] = temp[8];	    /* Let it equal YYYYMMDD     */
		    Date[3] = temp[9];	    /* Swap the date around      */
		    Date[4] = temp[3];	    /* Swap the date around      */
		    Date[5] = temp[4];	    /* because when you convert  */
		    Date[6] = temp[0];	    /* a string to an int you    */
		    Date[7] = temp[1];	    /* loose the front Zero      */
		    Date[8] = '\0';	    /* making the number smaller */
					    /* and invalid to this cause */
		    ifDate = atol(Date);

		    if (ifDate >= itDate) {
			if (!Found) {
			    Enter(2);
			    if (iLC(2) == 1) {
				free(Date);
				free(temp);
				mbsedb_CloseFDB(fdb_area);
				fclose(pAreas);
				return 1;
			    }
			    Found = TRUE;
			}

			memset(&T, 0, sizeof(T));
			T.Area   = arecno;
			T.Active = FALSE;
			T.Size   = fdb.Size;
			strncpy(T.SFile, fdb.Name, 12);
			strncpy(T.LFile, fdb.LName, 80);
			SetTag(T);

			Count++;
			if (ShowOneFile() == 1) {
			    free(Date);
			    free(temp);
			    mbsedb_CloseFDB(fdb_area);
			    fclose(pAreas);
			    return 1;
			}
		    } /* End of if */
		} /* End of while */

		mbsedb_CloseFDB(fdb_area);
		
		/*
		 * Add 2 blank lines after found files.
		 */
		if (Found) {
		    Enter(2);
		    if (iLC(2) == 1) {
			free(Date);
			free(temp);
			fclose(pAreas);
			return 1;
		    }
		}

	    } /* End of open filebase */

	} /* End of check new files scan */
	arecno++; /* Go to next file area */
    } /* End of Main */

    if (Count)
	Syslog('+', "Found %d new files", Count);
    fclose(pAreas);
    Enter(1);
    if (Count)
	Mark();
    else
	Pause();

    free(temp);
    free(Date);
    return 1;
}



/*
 * Upload a file.
 */
int Upload()
{
    int		    Area, rc;
    unsigned int    OldArea;
    char	    *arc, *temp;
    up_list	    *up = NULL, *tmpf;

    WhosDoingWhat(UPLOAD, NULL); 
    Enter(1);
    Area = OldArea = iAreaNumber;

    /*
     * If there is a special upload area for the current area
     * then select it.
     */
    if (area.Upload)
	Area = area.Upload;
    SetFileArea(Area);
    Syslog('+', "Upload area is %d %s", Area, area.Name);

    /*
     * Check upload access for the real upload directory.
     */
    if (!Access(exitinfo.Security, area.UPSec)) {
	Enter(1);
	/* You do not have enough access to upload to this area */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(278));
	Enter(2);
	SetFileArea(OldArea);
	Pause();
	return 0;
    }

    clear();
    Enter(2);

    rc = upload(&up);

    if (rc) {
	Syslog('+', "Upload failed, rc=%d", rc);
	SetFileArea(OldArea);
	return 0;
    }
    Syslog('b', "upload done, start checks");

    Enter(2);
    pout(CFG.UnderlineColourF, CFG.UnderlineColourB, (char *)"Checking your upload(s)");
    Enter(1);

    temp = calloc(PATH_MAX, sizeof(char));
    for (tmpf = up; tmpf; tmpf = tmpf->next) {
	snprintf(temp, PATH_MAX, "%s/%s/upl", CFG.bbs_usersdir, exitinfo.Name);
	chdir(temp);

	Syslog('b', "Checking upload %s", tmpf->filename);
	if ((arc = GetFileType(tmpf->filename)) == NULL) {
	    /*
	     * If the filetype is unknown, it is probably 
	     * a textfile or so. Import it direct.
	     */
	    Syslog('b', "Unknown file type");
	    if (!ScanDirect(basename(tmpf->filename)))
		ImportFile(tmpf->filename, Area, FALSE, tmpf->size);
	} else {
	    /*
	     * We figured out the type of the uploaded file.
	     */
	    Syslog('b', "File type is %s", arc);

	    /*
	     * MS-DOS executables are handled direct.
	     */
	    if ((strcmp("EXE", arc) == 0) || (strcmp("COM", arc) == 0)) {
	        if (!ScanDirect(basename(tmpf->filename))) 
		   ImportFile(tmpf->filename, Area, FALSE, tmpf->size);
	    } else {
		switch (ScanArchive(basename(tmpf->filename), arc)) {
		    case 0: ImportFile(tmpf->filename, Area, TRUE, tmpf->size);
			    break;
		    case 1: break;
		    case 2: break;
		    case 3: /*
			     * No valid unarchiver found, just import after scanning,
			     * may catch macro viri.
			     */
			    if (!ScanDirect(basename(tmpf->filename)))
				ImportFile(tmpf->filename, Area, FALSE, tmpf->size);
			    break;
		}
	    }
	}
    }

    tidy_upload(&up);
    free(temp);
    Home();
    SetFileArea(OldArea);
    Pause();
    return 1;
}



/*
 * Function will download a specific file
 */
int DownloadDirect(char *Name, int Wait)
{
    int		rc = 0;
    int		Size;
    down_list	*dl = NULL;

    if ((Size = file_size(Name)) == -1) {
	WriteError("No file %s", Name);
	pout(CFG.HiliteF, CFG.HiliteB, (char *)"File not found");
	Enter(2);
	Pause();
    }

    Syslog('+', "Download direct %s", Name);

    add_download(&dl, Name, basename(Name), 0, Size, FALSE);
    WhosDoingWhat(DOWNLOAD, NULL);

    if ((rc = download(dl))) {
	/*
	 * Error
	 */
	Syslog('+', "Download failed rc=%d", rc);
	poutCR(LIGHTRED, BLACK, (char *)Language(353));
    } else {
	/*
	 * Update the users record. The file is free, so only statistics.
	 */
	ReadExitinfo();
	exitinfo.Downloads++;    /* Increase download counter */
	WriteExitinfo();
    }

    if (Wait)
	Pause();
    return rc;
}



/*
 * Function will list users home directory
 */
void List_Home()
{
    DIR		    *dirp;
    char	    *FileName, *temp;
    int		    iFileCount = 0, iBytes = 0;
    struct dirent   *dp;
    struct stat	    statfile;

    FileName = calloc(PATH_MAX, sizeof(char));
    temp     = calloc(PATH_MAX, sizeof(char));

    iLineCount = 2;
    clear();
    snprintf(temp, PATH_MAX, "%s/%s/wrk", CFG.bbs_usersdir, exitinfo.Name);

    if ((dirp = opendir(temp)) == NULL) {
	WriteError("$List_Home: Can't open dir: %s", temp);
	Enter(1);
	/* Can't open directory for listing: */
	pout(LIGHTRED, BLACK, (char *) Language(290));
	Enter(2);
	Pause();
    } else {
	/* Home directory listing for */
	snprintf(temp, 81, " %s", (char *) Language(291));
	pout(BLUE, LIGHTGRAY, temp);
	snprintf(temp, 81, "%-51s", exitinfo.sUserName);
	pout(RED, LIGHTGRAY, temp);
	Enter(1);

	while ((dp = readdir( dirp )) != NULL ) {
	    snprintf(temp, PATH_MAX, "%s/%s/wrk", CFG.bbs_usersdir, exitinfo.Name);
	    snprintf(FileName, PATH_MAX, "%s/%s", temp, dp->d_name);
	    /*
	     * Check first letter of file for a ".", do not display hidden files
	     * This includes the current directory and parent directory . & ..
	     */
	    if (*(dp->d_name) != '.') {
		iFileCount++;
		if (stat(FileName, &statfile) != 0) {
		    WriteError("$Can't stat file %s",FileName);
		} else {
		    iBytes += statfile.st_size;
		    snprintf(temp, 81, "%-20s", dp->d_name);
		    pout(YELLOW, BLACK, temp);
		    snprintf(temp, 81, "%-12d", (int)(statfile.st_size));
		    pout(LIGHTMAGENTA, BLACK, temp);
		    snprintf(temp, 81, "%s  ", StrDateDMY(statfile.st_mtime));
		    pout(LIGHTGREEN, BLACK, temp);
		    snprintf(temp, 81, "%s", StrTimeHMS(statfile.st_mtime));
		    pout(LIGHTCYAN, BLACK, temp);
		    Enter(1);
		}
	    }
	    if (iLC(1) == 1)
		return;
	}

	Enter(2);
	/* Total Files: */ /* Bytes */
	snprintf(temp, 81, "%s%d / %d %s", (char *) Language(242), iFileCount, iBytes, (char *) Language(354));
	pout(LIGHTCYAN, BLACK, temp);
	Enter(1);
	Pause();
	closedir(dirp);
    }

    free(temp);
    free(FileName);
}



/*
 * Delete files from home directory
 */
void Delete_Home()
{
    char    *temp, *temp1, msg[81];
    int	i;

    temp  = calloc(PATH_MAX, sizeof(char));
    temp1 = calloc(PATH_MAX, sizeof(char));

    snprintf(temp, PATH_MAX, "%s/%s/wrk/", CFG.bbs_usersdir, exitinfo.Name);

    Enter(1);
    /* Please enter filename to delete: */
    pout(LIGHTBLUE, BLACK, (char *) Language(292));
    colour(CFG.InputColourF, CFG.InputColourB);
    GetstrC(temp1, 80);

    if (strcmp(temp1, "") == 0) {
	free(temp);
	free(temp1);
	return;
    }

    if (temp1[0] == '.') {
	Enter(1);
	/* Sorry you may not delete hidden files ...*/
	pout(LIGHTRED, BLACK, (char *) Language(293));
    } else {
	strcat(temp, temp1);

	if ((access(temp, R_OK)) == 0) {
	    Enter(1);
	    /* Delete file: */ /* Are you Sure? [Y/n]: */
	    snprintf(msg, 81, "%s %s, %s", (char *) Language(368), temp1, (char *) Language(369));
	    pout(LIGHTGREEN, BLACK, msg);
	    i = toupper(Readkey());

	    if (i == Keystroke(369, 0) || i == 13) {
		i = unlink(temp);

		if (i == -1) {
		    Enter(1);
		    /* Unable to delete file ... */
		    pout(LIGHTRED, BLACK, (char *) Language(294));
		} else {
		    Syslog('+', "Delete %s from homedir", temp1);
				}
	    } else {
		Enter(2);
		/* Aborting ... */
		pout(DARKGRAY, BLACK, (char *) Language(116));
	    }
	} else {
	    Enter(1);
	    /*  Invalid filename, please try again ... */
	    pout(LIGHTRED, BLACK, (char *) Language(295));
	}

    }

    Enter(2);
    free(temp);
    free(temp1);
    Pause();
}



/*
 * Function allows user to download from his/her home directory
 * but still does all the necessary checks
 */
int Download_Home()
{
    char	*temp, *File;
    struct stat statfile;
    int		rc;

    File  = calloc(PATH_MAX, sizeof(char));
    temp  = calloc(PATH_MAX, sizeof(char));

    WhosDoingWhat(DOWNLOAD, NULL);

    Enter(1);
    /* Please enter filename: */
    pout(YELLOW, BLACK, (char *) Language(245));
    colour(CFG.InputColourF, CFG.InputColourB);
    GetstrC(File, 80);

    if (( strcmp(File, "")) == 0) {
	Enter(2);
	/* No filename entered, Aborting. */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(246));
	Enter(2);
	Pause();
	free(File);
	free(temp);
	return FALSE;
    }

    if (*(File) == '/' || *(File) == ' ') {
	Enter(2);
	/* Illegal Filename! */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(247));
	Enter(2);
	Pause();
	free(File);
	free(temp);
	return FALSE;
    }

    /*
     * Get path for users home directory
     */
    snprintf(temp, PATH_MAX, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, File);

    if (stat(temp, &statfile) != 0) {
	Enter(2);
	/* File does not exist, please try again ...*/
  	pout(LIGHTRED, BLACK, (char *) Language(296));
	Enter(2);
	Pause();
	free(File);
	free(temp);
	return FALSE;
    }

    rc = DownloadDirect(temp, TRUE);

    free(File);
    free(temp);
    return rc;
}



/*
 * Function will upload to users home directory
 */
int Upload_Home()
{
    char    *temp, *arc;
    int	    rc = 0, Count = 0;
    up_list *up = NULL, *tmpf;

    WhosDoingWhat(UPLOAD, NULL);

    temp      = calloc(PATH_MAX, sizeof(char));

    clear();
    Enter(2);

    rc = upload(&up);

    if (rc) {
	Syslog('+', "Upload home failed, rc=%d", rc);
	Home();
	return 1;
    }
    
    Syslog('b', "Start checking uploaded files");
    Enter(2);
    pout(CFG.UnderlineColourF, CFG.UnderlineColourB, (char *)"Checking your upload(s)");
    Enter(2);

    for (tmpf = up; tmpf; tmpf = tmpf->next) {
	snprintf(temp, PATH_MAX, "%s/%s/upl", CFG.bbs_usersdir, exitinfo.Name);
	chdir(temp);

	Syslog('b', "Checking upload %s", tmpf->filename);
	if ((arc = GetFileType(tmpf->filename)) == NULL) {
	    /*
	     * If the filetype is unknown, it is probably 
	     * a textfile or so. Import it direct.
	     */
	    Syslog('b', "Unknown file type");
	    ImportHome(basename(tmpf->filename));
	    Count++;
	} else {
	    /*
	     * We figured out the type of the uploaded file.
	     */
	    Syslog('b', "File type is %s", arc);

	    /*
	     * MS-DOS executables are handled direct.
	     */
	    if ((strcmp("EXE", arc) == 0) || (strcmp("COM", arc) == 0)) {
	        if (!ScanDirect(basename(tmpf->filename))) {
		    ImportHome(basename(tmpf->filename));
		    Count++;
		}
	    } else {
		switch(ScanArchive(basename(tmpf->filename), arc)) {
		    case 0: ImportHome(basename(tmpf->filename));
			    Count++;
			    break;
		    case 1: break;
		    case 2: break;
		    case 3: /*
			     * No valid unarchiver found, just import
			     */
			    ImportHome(basename(tmpf->filename));
			    Count++;
			    break;
		}
	    }
	}
    }
    Home();

    ReadExitinfo();
    exitinfo.Uploads += Count;
    WriteExitinfo();	

    tidy_upload(&up);
    Pause();
    free(temp);
    return rc;
}



/*
 * Select filearea, called from menu.
 */
void FileArea_List(char *Option)
{
    FILE    *pAreas;
    int	    iAreaCount = 6, Recno = 1, iOldArea, iAreaNum = 0;
    int	    iGotArea = FALSE; /* Flag to check if user typed in area */
    int	    offset;
    char    *temp;

    /*
     * Save old area, incase he picks a invalid area
     */
    iOldArea = iAreaNumber;
    if ((pAreas = OpenFareas(FALSE)) == NULL)
	return;

    /*
     * Count howmany records there are
     */
    fseek(pAreas, 0, SEEK_END);
    iAreaNum = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize;

    /*
     * If there are menu options, select area direct.
     */
    if (strlen(Option) != 0) {

	if (strcmp(Option, "F+") == 0) {
	    while (TRUE) {
		iAreaNumber++;
		if (iAreaNumber > iAreaNum)
		    iAreaNumber = 1;

		offset = areahdr.hdrsize + ((iAreaNumber - 1) * areahdr.recsize);
		if (fseek(pAreas, offset, 0) != 0) {
		    printf("Can't move pointer here");
		}

		fread(&area, areahdr.recsize, 1, pAreas);
		if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0))
		    break;
	    }
	}
	
	if (strcmp(Option, "F-") == 0) {
	    while (TRUE) {
		iAreaNumber--;
		if (iAreaNumber < 1)
		    iAreaNumber = iAreaNum;

		offset = areahdr.hdrsize + ((iAreaNumber - 1) * areahdr.recsize);
		if (fseek(pAreas, offset, 0) != 0) {
		    printf("Can't move pointer here");
		}

		fread(&area, areahdr.recsize, 1, pAreas);
		if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0))
		    break;
	    }
	}
	    
	SetFileArea(iAreaNumber);
	Syslog('+', "File area %lu %s", iAreaNumber, sAreaDesc);
	fclose(pAreas);
	return;
    }

    /*
     * Interactive mode
     */
    clear();
    Enter(1);
    /* File Areas */
    pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(298));
    Enter(2);
    temp = calloc(81, sizeof(char));

    fseek(pAreas, areahdr.hdrsize, 0);

    while (fread(&area, areahdr.recsize, 1, pAreas) == 1) {

	if ((Access(exitinfo.Security, area.LTSec)) && (area.Available)) {
	    area.Name[31] = '\0';
	    snprintf(temp, 81, "%5d", Recno);
	    pout(WHITE, BLACK, temp);
	    snprintf(temp, 81, " %c ", 46);
	    pout(LIGHTBLUE, BLACK, temp);
	    snprintf(temp, 81, "%-31s", area.Name);
	    pout(CYAN, BLACK, temp);
	    iAreaCount++;

	    if ((iAreaCount % 2) == 0) {
		Enter(1);
	    } else {
		PUTCHAR(' ');
	    }
	}

	Recno++; 

	if ((iAreaCount / 2) == rows) {
	    /* More (Y/n/=/Area #): */
	    pout(CFG.MoreF, CFG.MoreB, (char *) Language(207)); 
	    /*
	     * Ask user for Area or enter to continue
	     */
	    colour(CFG.InputColourF, CFG.InputColourB);
	    GetstrC(temp, 7);

	    if (toupper(*(temp)) == Keystroke(207, 1))
		break;

	    if ((strcmp(temp, "")) != 0) {
		iGotArea = TRUE;
		break;
	    }

	    iAreaCount = 2;
	}
    }

    /*
     * If user type in area above during area listing
     * don't ask for it again
     */
    if (!iGotArea) {
	Enter(1);
	/* Select Area: */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(232));
	colour(CFG.InputColourF, CFG.InputColourB);
	GetstrC(temp, 80);
    } 

    /*
     * Check if user pressed ENTER
     */
    if ((strcmp(temp, "")) == 0) {
	fclose(pAreas);
	return;
    }

    iAreaNumber = atoi(temp);

    /*
     * Do a check in case user enters a negative value
     */
    if (iAreaNumber < 1) 
	iAreaNumber = 1;

    offset = areahdr.hdrsize + ((iAreaNumber - 1) * areahdr.recsize); 
    if (fseek(pAreas, offset, 0) != 0) 
	printf("Can't move pointer there."); 
    else
	fread(&area, areahdr.recsize, 1, pAreas);

    /*
     * Do a check if area is greater or less number than allowed,
     * security access level, is oke, and the area is active.
     */
    if (iAreaNumber > iAreaNum || iAreaNumber < 1 || 
	    (Access(exitinfo.Security, area.LTSec) == FALSE) || 
	    (strlen(area.Name) == 0)) {
	Enter(1);
	/* Invalid area specified - Please try again ...*/
	pout(LIGHTRED, BLACK, (char *) Language(233));
	Enter(2);
	Pause();
	fclose(pAreas);
	iAreaNumber = iOldArea;
	SetFileArea(iAreaNumber);
	free(temp);
	return;
    }

    SetFileArea(iAreaNumber);
    Syslog('+', "File area %lu %s", iAreaNumber, sAreaDesc);

    /*
     * Check if file area has a password, if it does ask user for it
     */ 
    if ((strlen(area.Password)) > 2) {
	Enter(2);
	/* Please enter Area Password: */
	pout(WHITE, BLACK, (char *) Language(299));
	colour(CFG.InputColourF, CFG.InputColourB);
	GetstrC(temp, 20);
	Enter(1);

	if ((strcmp(temp, area.Password)) != 0) { 
	    /* Password is incorrect */
	    pout(LIGHTRED, BLACK, (char *) Language(234));
	    Syslog('!', "Incorrect File Area # %d password given: %s", iAreaNumber, temp);
	    SetFileArea(iOldArea);
	} else {
	    /* Password is correct */
	    pout(WHITE, BLACK, (char *) Language(235));
	}
	Enter(2);
	Pause();
    } 

    free(temp);
    fclose(pAreas);
}



/*
 * Show filelist from current area, called from the menu.
 */
void Copy_Home()
{
    char    *File, *temp1, *temp2;
    int	    err, Found = FALSE;
    struct _fdbarea *fdb_area = NULL;

    File  = calloc(81, sizeof(char));
    temp1 = calloc(PATH_MAX, sizeof(char));
    temp2 = calloc(PATH_MAX, sizeof(char));
	
    Enter(1);
    /* Please enter filename: */
    pout(YELLOW, BLACK, (char *) Language(245));
    colour(CFG.InputColourF, CFG.InputColourB);
    GetstrC(File, 80);
    Enter(2);

    if ((strcmp(File, "")) == 0) {
	/* No filename entered, Aborting. */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(246));
	Enter(2);
	Pause();
	free(File);
	free(temp1);
	free(temp2);
	return;
    }

    if (*(File) == '/' || *(File) == ' ') {
	/* Illegal Filename! */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(247));
	Enter(2);
	Pause();
        free(File);
        free(temp1);
        free(temp2);
	return;
    }

    if (Access(exitinfo.Security, area.DLSec) == FALSE) {
	pout(YELLOW, BLACK, (char *) Language(236));
	Enter(2);
	Pause();
        free(File);
        free(temp1);
        free(temp2);
	return;
    }

    if ((fdb_area = mbsedb_OpenFDB(iAreaNumber, 30)) == NULL) {
	free(File);
        free(temp1);
        free(temp2);
	return;
    }

    while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) {
	if ((strcasecmp(File, fdb.Name) == 0) || (strcasecmp(File, fdb.LName) == 0)) {

	    Found = TRUE;
	    if (((fdb.Size + Quota()) > (CFG.iQuota * 1048576))) {
		/* You have not enough diskspace free to copy this file */
		pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(279));
		Enter(1);
		Syslog('+', "Copy homedir, not enough quota");
	    } else {
		snprintf(temp1, PATH_MAX, "%s/%s", area.Path, fdb.LName); /* Use real longname here */
		snprintf(temp2, PATH_MAX, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, File);
		colour(CFG.TextColourF, CFG.TextColourB);
		/* Start copy: */
		pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(289));
		PUTSTR(File);
		PUTCHAR(' ');

		Syslog('b', "Copy from : %s", temp1);
		Syslog('b', "Copy to   : %s", temp2);

		if ((err = file_cp(temp1, temp2))) {
		    /* Failed! */
		    pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(353));
		    WriteError("Copy %s to homedir failed, code %d", File, err);
		} else {
		    /* Ok */
		    PUTSTR((char *) Language(200));
		    Syslog('+', "Copied %s from area %d to homedir", File, iAreaNumber);
		}
		Enter(1);
	    }
	}
    }
    mbsedb_CloseFDB(fdb_area);

    if (!Found) {
	/* File does not exist, please try again ... */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(296));
	Enter(1);
    }

    Pause();
    free(File);
    free(temp1);
    free(temp2);
}



/*
 * Edit the list of tagged files.
 */
void EditTaglist()
{
    FILE    *tf;
    int	    i, x, Fg, Count;
    char    *temp;

    if ((tf = fopen("taglist", "r+")) == NULL) {
	Enter(1);
	/* No files tagged. */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(361));
	Enter(2);
	Pause();
	return;
    }

    temp = calloc(81, sizeof(char));
    if (utf8)
	chartran_init((char *)"CP437", (char *)"UTF-8", 'B');

    while (TRUE) {
	clear();
	fseek(tf, 0, SEEK_SET);
	Count = 0;
	/*   #  Area Active     Size  Cost File */
	/* 123 12345 123456 12345678 12345 */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(355));
	Enter(1);
	colour(LIGHTGREEN, BLACK);
	PUTSTR(chartran(fLine_str(79)));

	while ((fread(&Tag, sizeof(Tag), 1, tf) == 1)) {
	    Count++;

	    if (Tag.Active)
		Fg = WHITE;
	    else
		Fg = LIGHTGRAY;

	    snprintf(temp, 81, "%3d ", Count);
	    pout(Fg, BLACK, temp);

	    Fg--;
	    snprintf(temp, 81, "%5d ", Tag.Area);
	    pout(Fg, BLACK, temp);

	    Fg--;
	    if (Tag.Active)
		/* Yes */
		snprintf(temp, 81, "%-6s ", (char *) Language(356));
	    else
		/* No */
		snprintf(temp, 81, "%-6s ", (char *) Language(357));
	    pout(Fg, BLACK, temp);

	    Fg--;
	    snprintf(temp, 81, "%8d ", (int)(Tag.Size));
	    pout(Fg, BLACK, temp);

	    Fg--;
	    snprintf(temp, 81, "%5d ", Tag.Cost);
	    pout(Fg, BLACK, temp);

	    Fg--;
	    snprintf(temp, 81, "%s", Tag.LFile);
	    pout(Fg, BLACK, temp);

	    Enter(1);
	}
	colour(LIGHTGREEN, BLACK);
	PUTSTR(chartran(fLine_str(79)));

	/* (T)oggle active, (E)rase all, (ENTER) to continue: */
	pout(WHITE, RED, (char *) Language(358));

	i = toupper(Readkey());
	colour(CFG.CRColourF, CFG.CRColourB);

	if (i == Keystroke(358, 0)) {
	    Enter(2);
	    /* Enter file number, 1.. */
	    snprintf(temp, 81, "%s%d ", (char *) Language(359), Count);
	    PUTSTR(temp);

	    GetstrC(temp, 5);
	    x = atoi(temp);

	    if ((x > 0) && (x <= Count)) {
		if (fseek(tf, (x - 1) * sizeof(Tag), SEEK_SET) == 0) {
		    if (fread(&Tag, sizeof(Tag), 1, tf) == 1) {
			if (Tag.Active)
			    Tag.Active = FALSE;
			else
			    Tag.Active = TRUE;

			fseek(tf,(x - 1) * sizeof(Tag), SEEK_SET);
			fwrite(&Tag, sizeof(Tag), 1, tf);
		    }
		}
	    }
	}

	chartran_close();

	if (i == Keystroke(358, 1)) {
	    fclose(tf);
	    unlink("taglist");
	    free(temp);
	    return;
	}

	if ((i == '\r') || (i == '\n')) {
	    fclose(tf);
	    free(temp);
	    return;
	}
    }
}



/*
 * View a file in the current area, menu 103.
 * If a file name is given, display direct,
 * else ask for filename to view.
 */
void ViewFile(char *name)
{
    char    *File, *temp, *arc;
    int	    count, total, rc, found = FALSE;
    FILE    *fp;
    struct _fdbarea *fdb_area = NULL;

    Syslog('+', "ViewFile(%s)", printable(name, 0));

    if (Access(exitinfo.Security, area.LTSec) == FALSE) {
	Enter(1);
	/* You don't have enough security to list this area */
	pout(YELLOW, BLACK, (char *) Language(236));
	Enter(2);
	Pause();
	return;
    }

    File = calloc(PATH_MAX, sizeof(char));

    if ((name != NULL) && strlen(name)) {
	strcpy(File, name);
    } else {
	Enter(2);
	/* Please enter filename: */
	pout(YELLOW, BLACK, (char *) Language(245));
	colour(CFG.InputColourF, CFG.InputColourB);
	GetstrC(File, 80);

	if ((strcmp(File, "")) == 0) {
	    free(File);
	    return;
	}
	
	if (*(File) == '.' || *(File) == '*' || *(File) == ' ' || *(File) == '/') {
	    Enter(1);
	    /* Illegal Filename! */
	    pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(247));
	    Enter(2);
	    Pause();
	    free(File);
	    return;
	}

	Strlen = strlen(File);
	Strlen--;

	if (*(File + Strlen) == '.' || *(File + Strlen) == '/' || *(File + Strlen) == ' ') {
	    Enter(1);
	    /* Illegal Filename! */
	    pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(247));
	    Enter(2);
	    Pause();
	    free(File);
	    return;
	}

	if ((!strcmp(File, "files.bbs")) || (!strcmp(File, "00index")) || (strstr(File, (char *)".html"))) {
	    Enter(1);
	    /* Illegal Filename! */
	    pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(247));
	    Enter(2);
	    Pause();
	    free(File);
	    return;
	}
    }

    /*
     * Now check if this file is present
     */
    if ((fdb_area = mbsedb_OpenFDB(iAreaNumber, 30)) == NULL) {
	free(File);
	return;
    }

    while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) {
	if (((strcasecmp(File, fdb.Name) == 0) || (strcasecmp(File, fdb.LName) == 0)) && (!fdb.Deleted)) {
	    found = TRUE;
	    break;
	}
    }
    mbsedb_CloseFDB(fdb_area);

    if (!found) {
	Enter(1);
	/* File does not exist, please try again ... */
	pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(296));
	Enter(2);
	free(File);
	Pause();
	return;
    }

    snprintf(File, PATH_MAX, "%s/%s", sAreaPath, fdb.LName);
    arc = GetFileType(File);
    Syslog('+', "File to view: %s, type %s", fdb.LName, printable(arc, 0));

    if (arc != NULL) {
	found = FALSE;
	temp = calloc(PATH_MAX, sizeof(char));
	snprintf(temp, PATH_MAX, "%s/etc/archiver.data", getenv("MBSE_ROOT"));
	
	if ((fp = fopen(temp, "r")) != NULL) {
	    fread(&archiverhdr, sizeof(archiverhdr), 1, fp);
	    while (fread(&archiver, archiverhdr.recsize, 1, fp) == 1) {
		if ((strcmp(arc, archiver.name) == 0) && (archiver.available)) {
		    found = TRUE;
		    break;
		}
	    }
	    fclose(fp);
	}

	if (!found || (strlen(archiver.varc) == 0)) {
	    Syslog('+', "No archiver view for %s available", File);
	    Enter(1);
	    /* Archiver not available */
	    pout(CFG.HiliteF, CFG.HiliteB, Language(442));
	    Enter(2);
	    free(File);
	    free(temp);
	    Pause();
	    return;
	}

	/*
	 * Archiver viewer is available. Make a temp file which we will
	 * display to the user.
	 */
	snprintf(temp, PATH_MAX, "%s/%s/temptxt", CFG.bbs_usersdir, exitinfo.Name);
	rc = execute_str(archiver.varc, File, NULL, (char *)"/dev/null", temp, (char *)"/dev/null");
	Syslog('+', "Display temp file %s", temp);
	DisplayTextFile(temp);
	unlink(temp);
	free(temp);
    } else {
	/*
	 * Most likely a textfile, first check.
	 */
	total = count = 0;
	if ((fp = fopen(File, "r"))) {
	    while (TRUE) {
		rc = fgetc(fp);
		if (rc == EOF)
		    break;
		total++;
		if (isascii(rc))
		    count++;
	    }
	    fclose(fp);
	}
	if (((count * 10) / total) < 8) {
	    Syslog('+', "This is not a ASCII textfile");
	    Enter(1);
	    pout(CFG.HiliteF, CFG.HiliteB, Language(17));
	    Enter(2);
	    Pause();
	    free(File);
	    return;
	}
	Syslog('+', "Display text file %s", File);
	DisplayTextFile(File);
    }

    free(File);
}


