/* -*- C -*-
 * POP3Lite - 3lite POP3 Daemon
 * Copyright (C) 2000, 2001 Gergely Nagy <8@free.bsd.hu>
 *
 * This file is part of POP3Lite.
 *
 * POP3Lite 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 of the License, or
 * (at your option) any later version.
 *
 * POP3Lite 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/*
 * $Id: pop3lite.h.in,v 1.9 2001/01/12 16:02:59 algernon Exp $
 */

#ifndef __POP3LITE_H__
#define __POP3LITE_H__ 1

#include <glib.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#define POP3LITE_VERSION "0.2.4a"

/**
 * Some convenience macros
 **/
#define P3L_GET_OPTION(opt)		(GList *) g_hash_table_lookup ( control->config, opt )
#define P3L_GET_NTH_OPTION(opt,n)	(char *) g_list_nth_data ( P3L_GET_OPTION(opt), n )
#define P3L_GET_FIRST_OPTION(opt)	P3L_GET_NTH_OPTION ( opt, 0 )
#define P3L_GET_DATA(key)		(char *) g_hash_table_lookup ( control->data, key )
#define P3L_CALL_HOOK(type,hook)	(* (type) g_hash_table_lookup ( control->hooks, hook ) )
#define P3L_CMD_EXISTS(hash,cmd)	( g_hash_table_lookup ( control->hash, cmd ) != NULL )
#define P3L_HOOK_EXISTS(hook)		P3L_CMD_EXISTS ( hooks, hook )

#define p3l_clear(str)	\
do { \
	register char *__xx__; \
	if ( ( __xx__ = (str) ) ) \
		while ( *__xx__ ) \
			*__xx__++ = '\0'; \
} while ( 0 )

/**
 * POP3Code: Used in conjunction with p3l_respond.
 *
 *	+ POP3_NOTHING: No POP3 status indicator (+OK, -ERR) is sent,
 *	only the message.
 *	+ POP3_ANSWERED: Same as POP3_NOTHING, but has a different meaning
 *	when dealing with inheritance.
 *	+ POP3_OK: An +OK indicator is sent before the message.
 *	+ POP3_OK_HIDDEN: This is the same as POP3_OK, but the indicator
 *	won't be sent. Useful for functions which call their previous
 *	version. (Eg, when a function falls back to something)
 *	+ POP3_OK_EXIT: Same as POP3_OK, but exit immediately after
 *	sending the message.
 *	+ POP3_ERR: Send an +ERR indicator before the message
 *	+ POP3_FATAL: Same as POP3_ERR, but exit immediately after
 *	sending the message.
 **/
typedef enum
{
	POP3_NOTHING,
	POP3_ANSWERED,
	POP3_OK,
	POP3_OK_HIDDEN,
	POP3_OK_EXIT,
	POP3_ERR,
	POP3_FATAL
} POP3Code;

/**
 * POP3State: the actual state of the POP3 Session
 *	+ POP3_STATE_AUTH: authentication state.
 *	+ POP3_STATE_TRANS: transaction state.
 *	+ POP3_STATE_UPDATE: update state.
 **/
typedef enum
{
	POP3_STATE_AUTH,
	POP3_STATE_TRANS,
	POP3_STATE_UPDATE
} POP3State;

/**
 * AuthResult: result of authentication
 *
 *	+ AUTH_RESULT_OK: success
 *	+ AUTH_RESULT_FAIL: auth. failed, reason unspecified
 *	+ AUTH_RESULT_FAIL_USER: wrong username
 *	+ AUTH_RESULT_FAIL_PASS: wrong password
 **/
typedef enum
{
	AUTH_RESULT_OK,
	AUTH_RESULT_FAIL,
	AUTH_RESULT_FAIL_USER,
	AUTH_RESULT_FAIL_PASS
} AuthResult;

/**
 * CommandResponse: every command implementation returns this.
 *
 * Each and every function that implements a POP3 command, MUST
 * return a variable of this type. This allows a command to
 * call another and be sure that the other doesn't send
 * anything. (In most cases, eg RETR is an exception)
 **/
typedef struct _CommandResponse CommandResponse;
struct _CommandResponse
{
	POP3Code code;
	char *message;
};

/**
 * UserInfo: information about a user
 *
 * This is mainly used by the auth abstraction layer.
 **/
typedef struct _UserInfo UserInfo;
struct _UserInfo
{
	char *name;
	uid_t uid;
	gid_t gid;
	char *gecos;
	char *home;
	char *shell;
	long expire;
};

/** Pre-declarations to be used by the hooks **/
typedef struct _P3LControl P3LControl;
typedef struct _SysControl SysControl;

/***********************************************
 * P3LControl & SysControl function prototypes *
 ***********************************************/

/**
 * P3LHook_get_mailbox: GET-MAILBOX hook
 * @control: the main control struct
 *
 * This hook is used to retrieve the FILENAME (or equivalent, if it is
 * not a file) of the mailbox. 
 *
 * Returns: a newly allocated string containing the result, or NULL on
 * failure. 
 **/
typedef char *(*P3LHook_get_mailbox) ( P3LControl *control );

/**
 * P3LControl_greeting: Send the initial greeting. 
 * @control: the main control struct
 *
 * This special hook is responsible for sending the initial POP3
 * greeting.
 *
 * Returns: +OK [Greeting] in a CommandResponse
 **/
typedef CommandResponse *(*P3LControl_greeting) ( P3LControl *control );

/**
 * P3LControl_send_response: send POP3 Response
 * @control: the main control struct
 * @code: POP3 response code
 * @message: the message itself
 *
 * This hook is used to send almost all server responses.
 *
 * Returns: nothing, this is an end-point.
 **/
typedef void (*P3LControl_send_response) ( P3LControl *control,
					   POP3Code code, const char *message );

/**
 * P3LControl_send_raw: send RAW data to the client
 * @control: the main control struct
 * @data: the data to send
 * @size: size of the data to send
 *
 * This is used to send raw data to the client, ideally, the
 * send_response hook should call it only. Except for the RETR/TOP/etc
 * commands, which return multiline input.
 *
 * Returns: nothing, this is an end-point.
 **/
typedef void (*P3LControl_send_raw) ( P3LControl *control, const gpointer data,
				      size_t size );
/**
 * P3LControl_trans_init: Initialise TRANSACTION state
 * @control: the main control struct
 *
 * This hook should initialise the transaction state, by locking the
 * mailbox, preparing uidls, etc. When this is called, the user is
 * authenticated, and the privileges are (hopefully) dropped.
 *
 * Returns: +OK [some greeting message] on success, -ERR [reason]
 * otherwise.
 **/
typedef CommandResponse *(*P3LControl_trans_init) ( P3LControl *control );

/**
 * P3LControl_update: handle the UPDATE state
 * @control: the main control struct
 *
 * This one does the really hard job: updating the mailbox. Errors
 * should always be fatal in this state.
 *
 * Returns: +OK [exit message] or -ERR [reason]
 **/
typedef CommandResponse *(*P3LControl_update) ( P3LControl *control );

/**
 * P3LSysCon_getuinam: Get UserInfo by name
 * @control: the main control struct
 * @name: the user's name
 *
 * This hook collects all the information listed in UserInfo about the
 * specified user.
 *
 * Returns: a newly allocated, filled out UserInfo struct.
 **/
typedef UserInfo *(*P3LSysCon_getuinam) ( P3LControl *control,
					  const char *name );

/**
 * P3LSysCon_authenticate: Do the effective authentication
 * @control: the main control struct
 * @name: username
 * @pass: password (probably clear-text)
 *
 * This hook is intended to authenticate the user. This is not a
 * command handler, it has nothing to do with the AUTH command. This
 * is merely here to separate the authentication mechanism from
 * command handling. Be very careful, when you replace this!
 *
 * Returns: the result of the authentication
 **/
typedef AuthResult (*P3LSysCon_authenticate) ( P3LControl *control,
					       const char *name,
					       const char *pass );

/**
 * P3LSysCon_drop_privileges: drop all possible privileges
 * @control: the main control struct
 *
 * This hook is used to get rid of ALL special privileges. Do not
 * change this! The only possible reason you might want to override
 * this is when you run POP3Lite on a Non-Unix system.
 *
 * Returns: nothing.
 **/
typedef void (*P3LSysCon_drop_privileges) ( P3LControl *control );

/**
 * P3LSysCon_openlog: open the logfile, or facility
 * @control: the main control struct
 *
 * This hook should open the logfile, or tell syslog about the
 * program.
 *
 * Returns: nothing.
 **/
typedef void (*P3LSysCon_openlog) ( P3LControl *control );

/**
 * P3LSysCon_log: do the actual logging
 * @control: the main control struct
 * @priority: message priority, see <syslog.h>
 * @format: printf-style format string
 *
 * This hooks does the actual logging.
 *
 * Returns: nothing
 **/
typedef void (*P3LSysCon_log) ( P3LControl *control, int priority,
				const char *format, ... );

/**
 * P3LSysCon_closelog: close the logfile or facility
 * @control: the main control struct
 *
 * This hook should close the logfile or anything openlog opened.
 *
 * Returns: nothing
 **/
typedef void (*P3LSysCon_closelog) ( P3LControl *control );

/**
 * SysControl: system-specific control functions
 *
 * Change with extreme caution!
 **/
struct _SysControl
{
	P3LSysCon_getuinam getuinam;
	P3LSysCon_authenticate authenticate;
	P3LSysCon_drop_privileges drop_privileges;
	P3LSysCon_openlog openlog;
	P3LSysCon_log log;
	P3LSysCon_closelog closelog;

	/** A GList of UserInfo structs, serves as a cache **/
	GList *users;
	/** Miscelleanous system-specific data **/
	GHashTable *data;
};

/**
 * P3LControl: the main control structure.
 *
 * The whole POP3Lite session is controlled via this
 * structure. See the docs for more info.
 **/
struct _P3LControl
{
	P3LControl_greeting greeting;
	P3LControl_send_response send_response;
	P3LControl_send_raw send_raw;
	P3LControl_trans_init trans_init;
	P3LControl_update update;

	/** Commands available in the AUTHENTICATION state **/
	GHashTable *auth_commands;
	/** Commands available in the TRANSACTION state **/
	GHashTable *trans_commands;
	/** Misc. capabilities, mainly useful for the CAPA module **/
	GHashTable *capabilities;
	/** Session-related data, such as the username, etc **/
	GHashTable *data;
	/** Configuration data, it should NOT be modified **/
	GHashTable *config;
	/** A table of loaded modules **/
	GHashTable *modules;
	/** The current state of our session **/
	POP3State state;
	/** A GList of MessageInfo structs **/
	GList *msg_info;

	/** System-specific hooks **/
	SysControl *system;

	/** Misc. hooks, used throughout the daemon **/
	GHashTable *hooks;
};

/**
 * P3LString: NULL-aware string representation
 **/
typedef struct _P3LString P3LString;
struct _P3LString
{
	unsigned long length;
	char *str;
};

/**
 * p3l_module_hook: module_init/module_done definition
 * int module_init ( P3LControl *control)
 * int module_done ( P3LControl *control)
 * Returns 0 on succes, anything else on failure
 **/
typedef int (*p3l_module_hook) ( P3LControl *control );

/**
 * HandlerInfo: information about a signal handler
 *
 * This is used by the main SIGALRM handler
 **/
typedef struct _HandlerInfo HandlerInfo;
struct _HandlerInfo
{
	unsigned int counter;
	unsigned int tick_max;
	p3l_module_hook hook;
};

/**
 * p3l_pop3_command: definition for POP3 Commands
 * @control: the main control struct
 * @arguments: the arguments as read from the client
 *
 * Returns: Whatever it likes...
 **/
typedef CommandResponse *(*p3l_pop3_command) ( P3LControl *control,
					       const char *arguments );

/**
 * MailInfo: information about a message
 *
 * Many default commands use this to give information to the user,
 * without having to re-read the whole mailbox.
 *
 * The fields that are driver-independent:
 *	+ virtual_size: the size the message is said to be,
 *	after replacing the From [...] header with our own
 *	Received: header. This should be fully independent
 *	of everything, no matter where the message is read
 *	from, functions using this (and only this or other
 *	independent fields) can be left untouched when
 *	adding a new driver (maildir eg)
 *	+ digest: MD5 digest of the message. Should be
 *	independent.
 *	+ deleted: deleted state of the message.
 *
 * The other fields are:
 *	+ driver_data: driver-dependent data
 **/
typedef struct _MailInfo MailInfo;
struct _MailInfo
{
	size_t virtual_size;
	char digest[16];
	gboolean deleted;
	GHashTable *driver_data;
};

/**
 * p3l_received_header: return a POP3Lite header
 * @data: control->data
 *
 * Constructcs a Received: header
 *
 * Returns: the header, which should be freed
 **/
char *p3l_received_header ( GHashTable *data );

/**
 * p3l_parse_buffer: replace From [...] with Received:
 * @buffer: the mail text
 * @data: control->data
 * @buffer_size: size of the buffer
 * @new_size: pointer where the new size will be placed
 *
 * Replaces the first line (From [...]) of the message with
 * the POP3Lite-specific Received: header. (buffer will be
 * freed!)
 *
 * Returns: the new buffer
 **/
char *p3l_parse_buffer ( char *buffer, GHashTable *data,
			 size_t buffer_size, size_t *new_size );

/**
 * p3l_respond: generate a POP3Lite response
 * code: response code see %POP3Code abouce
 * message: the actual message
 *
 * Generates a response suitable to be used as the
 * return value of POP3 Command implementations.
 *
 * Returns: the POP3Lite response struct
 **/
CommandResponse *p3l_respond ( POP3Code code, const char *message );

/**
 * p3l_is_enabled: check if an option is enabled
 * @option: the option string
 *
 * Parses @option, and returns a boolean indicating
 * wheter it is enabled or not. (true, yes, on means
 * enabled, everything else is disabled)
 *
 * Returns: a boolean
 **/
gboolean p3l_is_enabled ( const char *option );

/**
 * bintohex: convert a binary string to hexadecimal
 * @ptr: the binary sequence
 * @size: length of the sequence
 * @checkendian: wheter to check endianness, or not
 *
 * Converts a binary sequence to its hexadecimal
 * representation.
 *
 * Returns: the hexadecimal representation
 **/
const char *bintohex ( const void *ptr, size_t size, const int checkendian );

/**
 * p3l_command_replace: replace a command
 * @commands: the command table (control->{auth,trans}_commands
 * @name: the command name
 * @new_command: the new command
 *
 * Replaces a command in a given table.
 *
 * Returns: the old command
 **/
const gpointer p3l_command_replace ( GHashTable *commands,
				     const char *name,
				     gpointer new_command );

/**
 * p3l_split_lines: split a buffer into lines
 * @buffer: source
 * @size: the buffer's size
 *
 * Splits the buffer into lines. This is NULL-aware, that means,
 * that the strings are NOT null terminated, therefore, their
 * size must be stored.
 *
 * Returns: a pointer to a P3LString array
 **/
P3LString **p3l_split_lines ( char *buffer, size_t size,
			      size_t *lines );

/**
 * p3l_lock_fd: lock a file
 * @fd: file descriptor
 * @fn: file name, in case we use lockfile_create
 *
 * Locks a file.
 *
 * Returns: 0 on success, -1 otherwise
 **/
int p3l_lock_fd ( int fd, char *fn );

/**
 * p3l_unlock_fd: unlock a file
 * @fd: file descriptor
 * @fn: file name, in case we use lockfile_create
 *
 * Unlocks a file.
 *
 * Returns: 0 on success, -1 otherwise
 **/
int p3l_unlock_fd ( int fd, char *fn );

/**
 * p3l_read_file: read the contents of a file
 * @fn: filename
 * @size: variable to put filesize into
 *
 * Opens the file and reads its contents.
 *
 * Returns: the contents, free-able
 **/
gpointer p3l_read_file ( const char *filename, size_t *size );

/**
 * p3l_read_fd: read the contents of an opened file
 * @fd: file descriptor
 * @size: variable to put filesize into
 *
 * Reads the contents of an already opened file.
 *
 * Returns: the contents, free-able
 **/
gpointer p3l_read_fd ( int fd, size_t *size );

/**
 * p3l_load_config: loads configuration
 * @control: the usual control struct
 * @filename: where to load configuration from
 * @table: destination
 *
 * This loads a configuration file.
 *
 * Returns: nothing
 **/
void p3l_load_config ( P3LControl *control, const char *filename,
		       GHashTable *table );

/**
 * p3l_get_peer_name: get the peer's hostname
 *
 * This one figures out the remote end's hostname.
 *
 * Returns: the hostname.
 **/
char *p3l_get_peer_name ( void );

/**
 * p3l_is_numeric: check if a string represents a number
 * @str: the string to check
 *
 * Determines if a string represents a number or not.
 *
 * Returns: TRUE if it does, FALSE if not.
 **/
gboolean p3l_is_numeric ( const char* str );

/**
 * p3l_register_alarm: register an alarm hook
 * @hook: the hook to run
 * @interval: the interval (in seconds) to wait between calls
 *
 * Installs a new hook to run on SIGALRM.
 *
 * Returns: nothing.
 **/
void p3l_register_alarm ( p3l_module_hook hook, unsigned int interval );

/**
 * p3l_get_alarm_hooks: returns the registered SIGALRM hooks
 *
 * This function returns a GList of HandlerInfo structs of the
 * registered SIGALRM hooks.
 *
 * Returns: the list
 **/
GList *p3l_get_alarm_hooks ( void );

/**
 * p3l_unregister_alarm: unregister an alarm hook
 * @hook: the hook to remove
 *
 * Removes an registered SIGALRM hook.
 *
 * Returns: nothing.
 **/
void p3l_unregister_alarm ( p3l_module_hook hook );

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* ! __POP3LITE_H__ */


syntax highlighted by Code2HTML, v. 0.9.1