#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef WIN32
#ifndef NOUNISTD
#include <unistd.h>
#endif
#endif

#include "newhash.h"


#define MDROP_SIZE	1000		/* if maildrop filenames exceed this size, they will be truncated */


/*	Structure containing information about a maildrop.  
 *
 *	This structure should NEVER be accessed directly - it should only be accessed
 *	by the functions that comprise the mdrop API.  Direct access to the contents
 *	of a maildrop structure is likely to invoke undefined behaviour.
 */
struct maildrop 
{
	char	maildrop_filename[MDROP_SIZE];			/* filename of maildrop */
	FILE	*maildrop_file;							/* pointer to maildrop file */
	int		status;									/* status of maildrop read */
	int		content_len;
	int		inhead; 
	int		upto;
};

     
/*	mdrop_open() opens a maildrop for user 'user', domain 'domain', in path 
 *	'path'.  If 'drop_filename' is not NULL, then 'drop_filename' is used
 *	rather than creating a drop filename from the aforementioned components.
 * 
 *	If non-empty, 'domain_prefix' is prepended to the username 'user'.
 *	mdrop_open() hashes the specified path using 'user' as the username and 
 *	'hash_spool' as the hashing level.  When hashing, all characters in the
 *	string pointed to by 'invalid' are considered to be invalid.
 *
 *	mdrop_open() places all maildrop info
 *	in the maildrop structure pointed to by 'mdrop'.
 *
 *	mdrop_open() returns one of the following conditions:
 *
 *		MDROP_OKAY				maildrop was successfully opened
 *		MDROP_FAIL_INIT			failed to initialise maildrop structure
 *		MDROP_FAIL_FILE_IO		specified maildrop can't be opened
 *		
 *	If mdrop_open() succeeds, the maildrop structure pointed to by 'mdrop' will
 *	be initialised, and mdrop_open() will return MDROP_OKAY.  Once initialised,
 *	the maildrop structure may not be initialised again until it has been
 *	closed with mdrop_close().
 *
 *	If mdrop_open() fails, mdrop_open() will return MDROP_FAIL_FILE_IO.
 *
 *	If mdrop_open() returns MDROP_FAIL_FILE_IO, and 'failure' is not NULL, 
 *	*'failure' will be set to errno, thus allowing the calling function to 
 *	determine the reason for failure in detail.
 *
 *	If 'mdrop', 'user', 'path', 'domain_prefix' or 'invalid' are NULL, 
 *	mdrop_open() will fail, returning MDROP_FAIL_INIT.
 */
int	mdrop_open(struct maildrop *mdrop, char *user, char *path, const char *domain_prefix, char *invalid, int hash_spool, int *failure, char *drop_filename, char *reason);


/*	mdrop_dele() deletes the maildrop for user 'user', domain 'domain', in path 
 *	'path'.  If 'drop_filename' is not NULL, then 'drop_filename' is used
 *	rather than creating a drop filename from the aforementioned components. 
 * 
 *	If mdrop_dele() fails, mdrop_dele() will return MDROP_FAIL_FILE_IO.
 *
 *	If mdrop_dele() returns MDROP_FAIL_FILE_IO, and 'failure' is not NULL, 
 *	*'failure' will be set to errno, thus allowing the calling function to 
 *	determine the reason for failure in detail.
 *
 *	If 'mdrop', 'user', 'path', 'domain_prefix' or 'invalid' are NULL, 
 *	mdrop_dele() will fail, returning MDROP_FAIL.
 */
int	mdrop_dele(char *user, char *path, const char *domain_prefix, char *invalid, int hash_spool, int *failure, char *drop_filename);



/*	mdrop_get_filename() returns a pointer to a string containing the filename
 *	of the maildrop contained within 'mdrop'.
 *
 *	Note that the filename is only set after a call to mdrop_open() - calling
 *	mdrop_get_filename() on a maildrop which has not been opened, or had an
 *	attempt at opening fail, will invoke undefined behaviour.
 *
 *	mdrop_get_filename() will return NULL if 'mdrop' is NULL.
 */
const char *mdrop_get_filename(struct maildrop *mdrop);


/*	mdrop_close() closes maildrop structure 'mdrop'.
 *
 *	If mdrop_close() succeeds, the maildrop structure pointed to by 'mdrop' will
 *	be closed, and mdrop_close() will return MDROP_OKAY.  Any open files will be
 *	closed, and all allocated memory will be freed.  The maildrop structure 
 *	pointed to by 'mdrop' will then be free for use by mdrop_close().
 *
 *	If mdrop_close() fails, or if 'mdrop' is NULL, mdrop_close() will return 
 *	MDROP_FAIL.
 */
int	mdrop_close(struct maildrop *mdrop);


/*	mdrop_status() returns an integer specifying the status of the maildrop 
 *	pointed to by 'mdrop'. 
 *
 *	The results of calling mdrop_open() on an unopened 'mdrop' are undefined.
 * 
 *	The possible return values of mdrop_status() are:
 *
 *		MDROP_STATUS_IN_MSG		maildrop is open, and currently in the midst of a message
 *		MDROP_STATUS_EOF		maildrop is open, and currently at the end of the file
 *		MDROP_STATUS_EOM		maildrop is open, and currently at the end of a message
 *		MDROP_STATUS_ERROR		maildrop is not open, due to an unspecified error
 *		MDROP_CLOSED			maildrop has been closed by mdrop_close()
 *		MDROP_FAIL				'mdrop' is NULL.
 */
int mdrop_status(struct maildrop *mdrop);


/*	mdrop_next_message() moves to the next message in the maildrop pointed to by 
 *	'mdrop'. 
 *	
 *	If mdrop_next_message() succeeds, mdrop_next_message() returns MDROP_OKAY if
 *	there is another message, or MDROP_FAIL_EOF if at the end of the last message.
 *
 *	If mdrop_next_message() fails, mdrop_next_message() will return MDROP_FAIL_FILE_IO.
 *
 *	mdrop_next_message() returns MDROP_FAIL if 'mdrop' is NULL.
 */
int	mdrop_next_message(struct maildrop *mdrop);


/*	mdrop_gets() attempts to read up to one character less than 'size' characters
 *	from maildrop 'mdrop'. 
 *	
 *	Reading stops at the end of the current message, or a newline.  Newlines are
 *	stored in the buffer; they are not discarded.  
 *
 *	If mdrop_gets() succeeds, it returns 'buf', and returns NULL on failure or
 *	upon being passed a NULL 'mdrop'.
 */
char *mdrop_gets(char *buf, int size, struct maildrop *mdrop);


/* enums returned by various functions */
enum {	MDROP_OKAY,				/* maildrop function performed correctly */
		MDROP_FAIL,				/* miscellaneous nasal demons */
		MDROP_FAIL_EOF,			/* failed to get next message as at end of maildrop */
		MDROP_FAIL_INIT,		/* maildrop failed to initialise */
		MDROP_FAIL_FILE_IO,		/* maildrop failed to open due to IO error */
		MDROP_STATUS_EOM,		/* at the end of a message in maildrop */
		MDROP_STATUS_EOF,		/* at the end of maildrop */
		MDROP_STATUS_ERROR,		/* can't read from maildrop for some reason */
		MDROP_STATUS_IN_MSG,	/* currently within a message in maildrop */
		MDROP_STATUS_CLOSED,	/* maildrop has been closed by mdrop_close() */

		/* do not add any enums below MDROP_NUM */		
		MDROP_NUM
};


int mdrop_use_content(int x);
