/*
 * MultiMail offline mail reader
 * file_header and file_list

 Copyright (c) 1996 Toth Istvan <stoty@vma.bme.hu>
 Copyright (c) 1999 William McBrine <wmcbrine@clark.net>

 Distributed under the GNU General Public License.
 For details, see the file COPYING in the parent directory. */

#include "mmail.h"

extern "C" {
#include <dirent.h>
#include <sys/stat.h>
}

// --------------------------------------------------------------------------
// file_header methods
// --------------------------------------------------------------------------
file_header::file_header(char *nameA, time_t dateA, off_t sizeA)
{
	name = strdupplus(nameA);
	date = dateA;
	size = sizeA;
	next = 0;
}

file_header::~file_header()
{
	delete[] name;
}

const char *file_header::getName() const
{
	return name;
}

time_t file_header::getDate() const
{
	return date;
}

off_t file_header::getSize() const
{
	return size;
}

// ------------------------------------------------------------------------
// file_list methods
// ------------------------------------------------------------------------

file_list::file_list(const char *FileDir, bool sorttypeA)
{
	sorttype = sorttypeA;

	dirlen = strlen(FileDir);
	DirName = new char[dirlen + 81];
	strcpy(DirName, FileDir);

	initFiles();
}

file_list::~file_list()
{
	while (noOfFiles)
		delete files[--noOfFiles];
	delete[] files;
	delete[] DirName;
}

void file_list::initFiles()
{
	DIR *Dir;
	struct dirent *entry;
	struct stat fileStat;

	if (!(Dir = opendir(DirName)))
		fatalError("There is no Packet Dir!");

	mychdir(DirName);

	noOfFiles = 0;

	file_header head("", 0, 0);
	file_header *filept = &head;

	while ((entry = readdir(Dir)))
		if (!(stat(entry->d_name, &fileStat)))
			if (!(S_ISDIR(fileStat.st_mode)))
				if (!access(entry->d_name, R_OK | W_OK)) {
					filept->next =
					    new file_header(entry->d_name,
						fileStat.st_mtime,
							fileStat.st_size);
					filept = filept->next;
					noOfFiles++;
				}

	files = new file_header *[noOfFiles];
	int c = 0;
	filept = head.next;
	while (filept) {
		files[c++] = filept;
		filept = filept->next;
	}

	closedir(Dir);
	sort();
}

void file_list::sort()
{
	if (noOfFiles > 1)
		qsort(files, noOfFiles, sizeof(file_header *), sorttype ?
			ftimecomp : fnamecomp);
}

void file_list::resort()
{
	sorttype = !sorttype;
	sort();
}

int fnamecomp(file_header **a, file_header **b)
{
	int d;

	const char *p = (*a)->getName();
	const char *q = (*b)->getName();

	d = strcasecmp(p, q);
	if (!d)
		d = strcmp(q, p);

	return d;
}

int ftimecomp(file_header **a, file_header **b)
{
	return (*b)->getDate() - (*a)->getDate();
}

const char *file_list::getDirName() const
{
	DirName[dirlen] = '\0';
	return DirName;
}

int file_list::getNoOfFiles() const
{
	return noOfFiles;
}

void file_list::gotoFile(int fileNo)
{
	if (fileNo < noOfFiles)
		activeFile = fileNo;
}

const char *file_list::getName() const
{
	return files[activeFile]->getName();
}

time_t file_list::getDate() const
{
	return files[activeFile]->getDate();
}

off_t file_list::getSize() const
{
	return files[activeFile]->getSize();
}

const char *file_list::getNext(const char *fname)
{
	int c, len;
	const char *p, *q;
	bool isExt;

	if (fname) {
		isExt = (*fname == '.');

		for (c = activeFile + 1; c < noOfFiles; c++) {
			q = files[c]->getName();

			if (isExt) {
				len = strlen(q);
				if (len > 5) {
				p = q + len - 4;
					if (!strcasecmp(p, fname)) {
						activeFile = c;
						return q;
					}
				}
			} else
				if (!strncasecmp(q, fname, strlen(fname))) {
					activeFile = c;
					return q;
				}
        	}
	}
        return 0;
}

file_header *file_list::getNextF(const char *fname)
{
	return getNext(fname) ? files[activeFile] : 0;
}

const char *file_list::exists(const char *fname)
{
	gotoFile(-1);
	return getNext(fname);
}

file_header *file_list::existsF(const char *fname)
{
	return exists(fname) ? files[activeFile] : 0;
}

void file_list::addItem(file_header **list, const char *q, int &filecount)
{
	file_header *p;
	int x;

	gotoFile(-1);
	while ((p = getNextF(q))) {
		for (x = 0; x < filecount; x++)
			if (list[x] == p)
				break;
		if (x == filecount) {
			list[x] = p;
			filecount++;
		}
	}
}

const char *file_list::expandName(const char *fname)
{
	sprintf(DirName + dirlen, "/%.79s", fname);
	return DirName;
}

FILE *file_list::ftryopen(const char *fname, const char *mode)
{
	const char *p = exists(fname);
	return p ? fopen(expandName(p), mode) : 0;
}

void file_list::kill()
{
	remove(expandName(getName()));

	delete files[activeFile];
	noOfFiles--;
	for (int i = activeFile; i < noOfFiles; i++)
		files[i] = files[i + 1];
}
