/*
 * MultiMail offline mail reader
 * mmail class

 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. */

#ifndef MMAIL_H 
#define MMAIL_H

#define MM_NAME "MultiMail"

#include "misc.h"
#include "resource.h"

#include <cctype>
#include <cstdlib>
#include <cstring>
#include <ctime>

extern "C" {
#include <unistd.h>
#include <sys/types.h>
}

// Number of the Reply area
#define REPLY_AREA 0

// Area types
#define COLLECTION 1
#define REPLYAREA 2
#define ACTIVE 4
#define ALIAS 8
#define NETMAIL 16
#define INTERNET 32
#define PUBLIC 64
#define PRIVATE 128
#define LATINCHAR 256

// Mail statuses -- bit f.
#define MS_READ		1
#define MS_REPLIED	2 
#define MS_MARKED	4

// For letter_list::sort
#define LS_SUBJ     0
#define LS_MSGNUM   1
#define LS_FROM     2
#define LS_TO       3

// Some error codes
#define UNCOMP_FAIL	1
#define PTYPE_UNK	2
#define NEW_DIR		3

// Some of the functions normally used by MultiMail don't exist in EMX,
// but are available under other names:

#ifdef __EMX__
# define strcasecmp stricmp
# define strncasecmp strnicmp
extern "C" {
int _chdir2(const char *);
char *_getcwd2(char *, int);
}
# define mychdir _chdir2
# define mygetcwd _getcwd2
#else
# define mychdir chdir
# define mygetcwd getcwd
#endif

// Letter sort type flag
extern int lsorttype;

class mmail;
class resource;
class file_header;
class file_list;
class area_header;
class area_list;
class letter_header;
class letter_list;
class specific_driver;
class reply_driver;
class driver_list;
class read_class;

class net_address
{
	char *inetAddr;

	void copy(net_address &);
 public:
	int zone, net, node, point;
	bool isInternet, isSet;

	net_address();
	net_address(net_address &);
	~net_address();
	bool operator==(net_address &);
	net_address &operator=(const char *);
	net_address &operator=(net_address &);
	operator const char *();
};
 
class mmail
{
 public:
	resource *resourceObject;
	file_list *workList;
	driver_list *driverList;
	area_list *areaList;
	letter_list *letterList;

	mmail();
	~mmail();
	int selectPacket(const char *);
	void Delete();
	void saveRead();
	file_header *getFileList();
	file_header **getBulletins();
};	

class file_header
{
	char *name;
	time_t date;
	off_t size;
 public:
	file_header *next;

	file_header(char *, time_t, off_t);
	~file_header();

	const char *getName() const;
	time_t getDate() const;
	off_t getSize() const;
};

class file_list
{
	file_header **files;
	char *DirName;
	size_t dirlen;
	int noOfFiles, activeFile;
	bool sorttype;

	void initFiles();
	friend int fnamecomp(file_header **, file_header **);
	friend int ftimecomp(file_header **, file_header **);
	void sort();
 public:
	file_list(const char *, bool = false);
	~file_list();

	void resort();

	int getNoOfFiles() const;
	const char *getDirName() const;
	void gotoFile(int);

	const char *getName() const;
	time_t getDate() const;
	off_t getSize() const;

	const char *getNext(const char *);
	file_header *getNextF(const char *);
	const char *exists(const char *);
	file_header *existsF(const char *);

	void addItem(file_header **, const char *, int &);

	const char *expandName(const char *);
	FILE *ftryopen(const char *, const char *);
	void kill();
};

class area_header
{
	mmail *mm;
	specific_driver *driver;
	const char *shortName, *name, *description, *areaType;
	int noOfLetters, noOfPersonal, num, type, maxtolen;
 public:
	area_header(mmail *, int, const char *, const char *, const char *,
		const char *, int, int, int, int);
	inline const char *getShortName() const;
	inline const char *getName() const;
	inline const char *getDescription() const;
	inline const char *getAreaType() const;
 	inline int getNoOfLetters() const;
	inline int getNoOfUnread();
	inline int getNoOfMarked();
	inline int getNoOfPersonal() const;
	inline bool getUseAlias() const;
	inline bool isCollection() const;
	inline bool isReplyArea() const;
	inline bool isNetmail() const;
	inline bool isInternet() const;
	inline bool isEmail() const;
	inline bool isUsenet() const;
	inline bool isLatin() const;
	inline bool hasTo() const;
	inline bool hasPublic() const;
	inline bool hasPrivate() const;
	inline int maxToLen() const;
	bool isActive() const;
};

class area_list
{
	mmail *mm;
	area_header **areaHeader;
	int no, noActive, current, *activeHeader;
	bool shortlist;

	void refreshArea();
 public:
	area_list(mmail *);
	~area_list();
	void relist();

	const char *getShortName() const;
	const char *getName() const;
	const char *getName(int);
	const char *getDescription() const;
	const char *getDescription(int);
	const char *getAreaType() const;
	int getNoOfLetters() const;
	int getNoOfUnread() const;
	int getNoOfMarked() const;
	int getNoOfPersonal() const;
	bool getUseAlias() const;
	bool isCollection() const;
	bool isReplyArea() const;
	bool isEmail() const;
	bool isInternet() const;
	bool isUsenet() const;
	bool isLatin() const;
	bool hasTo() const;
	bool hasPublic() const;
	bool hasPrivate() const;
	int maxToLen() const;

	void getLetterList();
	void enterLetter(int, const char *, const char *, const char *,
			const char *, int, bool, net_address &,
			const char *, int);
	void killLetter(int);
	void makeReply();
	void gotoArea(int);
	void gotoActive(int);
	int getAreaNo() const;
	int getActive();
	int noOfAreas() const;
	int noOfActive() const;
	int findNetmail() const;
	int findInternet() const;
};

class letter_header
{
	driver_list *dl;
	read_class *readO;
	specific_driver *driver;
	char *subject, *to, *from, *date, *msgid;
	int replyTo, LetterID, AreaID, length, msgNum;
	bool privat, personal, charset;
	net_address netAddr;
 public:
	letter_header(mmail *, const char *, const char *, const char *,
		const char *, const char *, int, int, int, int, bool, int,
		specific_driver *, net_address &, bool = false);
	~letter_header();

	void changeSubject(const char *);
	void changeTo(const char *);
	void changeFrom(const char *);
	void changeMsgID(const char *);

	const char *getSubject() const;
	const char *getTo() const;
	const char *getFrom() const;
	const char *getMsgID() const;
	net_address &getNetAddr();
	int getReplyTo() const;
	bool getPrivate() const;
	inline specific_driver *getDriver() const;
	inline const char *getDate() const;
	inline const char *getBody();
	int getLetterID() const;
	int getAreaID() const;
	inline int getMsgNum() const;
	inline int getLength() const;
	inline bool isPersonal() const;
	inline bool isLatin() const;

	void setLatin(bool);

	inline bool getRead();
	inline void setRead();
	inline int getStatus();
	inline void setStatus(int);
};

class letter_list
{ 
	driver_list *dl;
	specific_driver *driver;
	read_class *readO;
	letter_header **letterHeader;
	int noOfLetters, noActive, areaNumber, currentLetter;
	int *activeHeader;
	bool isColl, shortlist;

	void init();
	void cleanup();
	friend int lettercomp(letter_header **, letter_header **);
	friend int lmsgncomp(letter_header **, letter_header **);
	void sort();
 public:
	letter_list(mmail *, int, bool);
	~letter_list();
	void relist();
	void resort();

	const char *getSubject() const;
	const char *getTo() const;
	const char *getFrom() const;
	const char *getDate() const;
	const char *getMsgID() const;
	const char *getBody();
	net_address &getNetAddr();
	int getReplyTo() const;
	int getMsgNum() const;
	int getAreaID() const;
	bool getPrivate() const;
	int getLength() const;
	bool isPersonal() const;
	bool isLatin() const;

	int getStatus();
	void setStatus(int);
	bool getRead();
	void setRead();
	
	void rrefresh();
	bool findReply(int, int);
	int noOfLetter() const;
	int noOfActive() const;
	void gotoLetter(int);
	void gotoActive(int);
	int getCurrent() const;
	int getActive() const;
};

class driver_list
{
	struct driver_struct {
		specific_driver *driver;
		read_class *read;
		int offset;
	} driverList[2];

	int noOfDrivers, attributes;
 public:
	driver_list(mmail *);
	~driver_list();
	int getNoOfDrivers() const;
	specific_driver *getDriver(int);
	reply_driver *getReplyDriver();
	read_class *getReadObject(specific_driver *);
	int getOffset(specific_driver *);
	bool hasPersonal() const;
	bool useTearline() const;
};

class read_class
{
 public:
	read_class();
	virtual ~read_class();
	virtual void setRead(int, int, bool) = 0;
	virtual bool getRead(int, int) = 0;
	virtual void setStatus(int, int, int) = 0;
	virtual int getStatus(int, int) = 0;
	virtual int getNoOfUnread(int) = 0;
	virtual int getNoOfMarked(int) = 0;
	virtual void saveAll() = 0;
};

class main_read_class : public read_class
{
	resource *ro;
	int noOfAreas, **readStore, *noOfLetters;
 public:
	main_read_class(mmail *, specific_driver *);
	~main_read_class();
	void setRead(int, int, bool);
	bool getRead(int, int);
	void setStatus(int, int, int);
	int getStatus(int, int);
	int getNoOfUnread(int);
	int getNoOfMarked(int);
	void saveAll();
	const char *readFilePath(const char *);
};

class reply_read_class: public read_class
{
 public:
	reply_read_class(mmail *, specific_driver *);
	~reply_read_class();
	void setRead(int, int, bool);
	bool getRead(int, int);
	void setStatus(int, int, int);
	int getStatus(int, int);
	int getNoOfUnread(int);
	int getNoOfMarked(int);
	void saveAll();
};	

struct bodytype
{
	long pointer, msgLength;
};

class specific_driver
{
 public:
	virtual ~specific_driver();
	virtual int getNoOfAreas() = 0;
	virtual void resetAll() = 0;
	virtual area_header *getNextArea() = 0;
	virtual void selectArea(int) = 0;
	virtual int getNoOfLetters() = 0;
	virtual void resetLetters() = 0;
	virtual letter_header *getNextLetter() = 0;
	virtual const char *getBody(letter_header &) = 0;
	virtual file_header *getFileList() = 0;
	virtual file_header **getBulletins() = 0;
};

class reply_driver : public specific_driver
{
 public:	
	virtual ~reply_driver();
	virtual void enterLetter(letter_header &, const char *, int) = 0;
	virtual void killLetter(int) = 0;
	virtual area_header *refreshArea() = 0;
	virtual void makeReply() = 0;
};

#endif
