#ifndef _msg_h_
#define _msg_h_

/*****************************************************/
/* This file contains the header file for the Msg    */
/* (message) object used in Athena Information Lens. */
/* Written Brian R. Gardner, 1988.                   */
/*****************************************************/

typedef struct AlMsg_Object_struct *Msg;

#include "sysdep.h"
#include "bool.h"
#include "folder.h"
#include "registry.h"
#include "darray.h"
#include "FieldCore.h"
#include "FieldType.h"
#include "memory.h"

#define KEY char *
#define CONSTKEY const char *
#define INDICES unsigned *
#define STRING char *
#define CONSTSTRING const char *

/*************************************************************/
/*******  Definitions for Generalized Fields          ********/
/*******  ------------------------------------------  ********/
/*******    these are used by state and uprop code    ********/
/*************************************************************/

/* ------------------------------------------------------------------------- */
/* Note: A Generalized field is how states & uprops are saved within a msg.  */
/*       They contain in a typical mail field consisting of a specific       */
/*       outer key (with colon), and a value string, like all mail fields.   */
/*       If the outer key is recognizable as a special symbol (here,         */
/*       #define'd as AlMsg_STATE_PREFIX or AlMsg_UPROP_PREFIX), then the    */
/*       value portion of the field is parsed and decoded. The value string  */
/*       is parsed as a generalized key, followed by an equal sign,          */
/*       followed by the value of that key. Since both the generalized key   */
/*       and its value may contain ANY characters (even unprintables), the   */
/*       whole field is encoded using a typical Unix/C-like escape character */
/*       scheme: Any equal sign in the key or value is written with a        */
/*       preceding back-slash ('\=') to differenciate it from the delimeter. */
/*       The back-slash ('\') is also written with a preceding back-slash    */
/*       ("\\"). All unprintables are converted to a two character           */
/*       hexadecimal, and written with a pecending back-slash ("\13").       */
/*       A generalized field may be used to encode any info., and may appear */
/*       anywhere in the header of a msg; however, if the gen field is to be */
/*       interpreted as a msg-state, then it must appear before all other    */
/*       msg header fields. Those interpreted as user-properties must appear */
/*       above all other mail header fields (other than the state fields).   */
/*       If a state or uprop field occurs out of order, or inter-shuffled,   */
/*       then it will be treated as just another normal mail field.          */
/* ------------------------------------------------------------------------- */

/* Define special characters for generalized mail field. */
/* ----------------------------------------------------- */
#define ENCODING_DELIMETER   ""     /* Obsolete, for now.   :-)  */
#define DELIM_CH  '=' /* delimeter between key & value of generalized fields */
#define ESC_CH  '\\'  /* escape character (for literal quoting) in gen field */

/* Define the inner key strings for the state fields. */
/* -------------------------------------------------- */
#define FIELD_COUNT_KEY "field-count:"
#define RULES_FIRED_KEY "num-rules-fired:"
#define MOVED_FROM_KEY  "moved-from-folder:"
#define TIMES_MOVED_KEY "how-many-times-moved:"

/* Define the outer key strings for the mail field (for states & uprops). */
/* ---------------------------------------------------------------------- */
#define AlMsg_STATE_PREFIX "X-Alens-state:"
#define AlMsg_UPROP_PREFIX "X-Alens-uprop:"

#define AlMsgNAMEDEFAULT ""


/*************************************************************/
/*******  Definitions for Error Codes                 ********/
/*******  ------------------------------------------  ********/
/*******    these are returned by:                    ********/
/*******         AlMsg_get_error_code(Msg);           ********/
/*************************************************************/

#define NO_ERROR 0
#define BAD_STATE_FILE 1
#define TOO_MANY_STATE_FIELDS 2
#define TOO_FEW_STATE_FIELDS 3
#define BAD_UPROP_FILE 4
#define TOO_MANY_UPROP_FIELDS 5
#define TOO_FEW_UPROP_FIELDS 6
#define NO_FIELD_COUNT_IN_UPROP_FILE 7
#define UPROP_NONEXISTANT_CANT_DELETE 8
#define UPROP_NONEXISTANT_CANT_APPEND 9
#define UPROP_NONEXISTANT_CANT_RENAME 10
#define UPROP_NONEXISTANT_CANT_COPY 11
#define UPROP_EXISTANT_CANT_RENAME 12
#define UPROP_NONEXISTANT_CANT_GET 13
#define UPROP_NONEXISTANT_CANT_GETLEN 14
#define UPROP_NONEXISTANT_CANT_PERM 15

/*************************************************************/
/*******  Definitions for Error Msgs (doc'ed here)    ********/
/*******  ------------------------------------------  ********/
/*******    these are indexed by:                     ********/
/*******         AlMsg_get_error_code(Msg);           ********/
/*******    and are returned by:                      ********/
/*******         AlMsg_get_error_msg(Msg);            ********/
/*******    the actually storage for the strings is   ********/
/*******    in the private header file "msgP.h"       ********/
/*************************************************************/
/*
0 "Msg :: No Error. All is fine in Msg Object."
1 "Msg :: State File for this Msg contains erroneous data."
2 "Msg :: State File for this Msg contains more fields than it should."
3 "Msg :: State File for this Msg contains less fields than it should."
4 "Msg :: User Property File for this Msg contains erroneous data."
5 "Msg :: User Property File for this Msg contains more fields than it should."
6 "Msg :: User Property File for this Msg contains less fields than it should."
7 "Msg :: User Property File for this Msg is missing required 'field-count:'."
8 "Msg :: Can not delete. User property specified does not exist."
9 "Msg :: Can not append. User property specified does not exist."
10 "Msg :: Can not rename uprop. User property specified does not exist."
11 "Msg :: Can not copy uprop. User property specified does not exist."
12 "Msg :: Can not rename uprop. New user property specified already exists."
13 "Msg :: Can not get uprop. User property specified does not exist."
14 "Msg :: Can't get length of uprop. User property specified doesn't exist.",
15 "Msg :: Can't set permanence of uprop. User property specified doesn't exist."
*/

#ifdef __STDC__

/*********************************************************************/
/****** Functions to Create, Print, and Destroy a Message Object *****/
/*********************************************************************/

/* The create and destroy functions are strickly called by the Folder    */
/* Object. (see "AlFolder_next_msg()" in folder's header file (folder.h) */
/* --------------------------------------------------------------------- */
extern Msg AlMsg_create(STRING, STRING, STRING, Registry, AlFolder);
extern STRING AlMsg_write_uprops_to_buffer(Msg);
extern STRING AlMsg_write_states_to_buffer(Msg);
extern Bool AlMsg_destroy(Msg);

extern NORET AlMsg_print_self(Msg, FILE *);


/****************************************************************************/
/****** Functions to parse a msg buffer. (Used only by the folder object) ***/
/****************************************************************************/

char *AlMsg_readkey(STRING *, int *, int *);      /* read a mail header key */
char *AlMsg_readvalue(STRING *, int *, int *);    /* read a mail header val */


/********************************************/
/****** Functions to Store Information ******/
/********************************************/

/* Set Folder Dependent Information */
/* -------------------------------- */
extern Bool AlMsg_set_folder(Msg, AlFolder);  /* called by the folder object */
extern NORET AlMsg_set_msg_buffer(Msg, STRING);  /* called by folder object */
extern Bool AlMsg_set_fs_state_registry(Msg, Registry); /* called by folder */

/* Manipulate State Information */
/* ---------------------------- */
/* (Note: Not User Excessable.) */
extern NORET AlMsg_set_name(Msg, STRING);        /* called by folder object */
extern NORET AlMsg_set_removed_flag(Msg, Bool);
extern Bool  AlMsg_set_moved_from_state(Msg, CONSTSTRING);
extern Bool  AlMsg_set_how_many_times_moved(Msg, int);
extern Bool  AlMsg_set_num_rules_fired_state(Msg, int);
extern int   AlMsg_incr_num_rules_fired_state(Msg, int);
extern NORET AlMsg_set_suppress_states_out(Msg, Bool);
extern NORET AlMsg_set_suppress_uprops_out(Msg, Bool);
extern NORET AlMsg_set_init_uprop_field_count(Msg, unsigned int);

/* Manipulate User Properties */
/* -------------------------- */
extern NORET AlMsg_set_uprop(Msg, KEY, STRING);
extern Bool AlMsg_set_uprop_permanence(Msg, KEY, Bool);
extern Bool AlMsg_delete_uprop(Msg, KEY);
extern Bool AlMsg_append_uprop(Msg, KEY, STRING);
extern Bool AlMsg_copy_uprop(Msg, KEY, KEY);
extern Bool AlMsg_rename_uprop(Msg, KEY, KEY);

/* Manipulate Error Code Information, after an error has occurred */
/* -------------------------------------------------------------- */
extern NORET AlMsg_clear_error_code(Msg);

/********************************************/
/***** Functions to Retrieve Information ****/
/********************************************/

/* Get Keyed Field Information */
/* --------------------------- */
extern int AlMsg_number_of(Msg, KEY);
extern STRING *AlMsg_get_raw_fields(Msg, KEY);
extern Bool AlMsg_get_fields(Msg, CONSTKEY, AlFieldType, Darray);
extern int AlMsg_number_of_type(Msg, KEY, AlFieldType);
extern AlFieldCore AlMsg_get_nth_field(Msg, KEY, AlFieldType, unsigned);
extern AlFieldCore AlMsg_get_indexed_field(Msg, KEY, INDICES, 
					   STRING, AlFieldType);

/* Get Folder Dependent Information */
/* -------------------------------- */
extern AlFolder AlMsg_get_folder(Msg);
extern char *AlMsg_get_msg_buffer(Msg);           /* called by folder object */
extern Registry AlMsg_get_fs_state_registry(Msg); /* called by folder object */

/* Get State Information */
/* --------------------- */
extern char *AlMsg_name(Msg);
extern Bool AlMsg_get_removed_flag(Msg);
extern STRING AlMsg_get_moved_from_state(Msg);
extern int AlMsg_get_how_many_times_moved(Msg);
extern int AlMsg_get_num_rules_fired_state(Msg);
extern int AlMsg_get_num_of_fields(Msg);
extern int AlMsg_get_msg_line_length(Msg);
extern int AlMsg_get_msg_char_length(Msg);
extern int AlMsg_get_body_line_length(Msg);
extern int AlMsg_get_body_char_length(Msg);
extern char *AlMsg_get_msg_body(Msg);
extern Bool AlMsg_unprintables_in_body(Msg);
extern int AlMsg_get_state_field_count(Msg);
extern Bool AlMsg_get_suppress_states_out(Msg);
extern Bool AlMsg_get_suppress_uprops_out(Msg);
extern unsigned int AlMsg_get_init_uprop_field_count(Msg);
extern int AlMsg_get_num_perm_uprops(Msg);


/* Get User Property Information */
/* ----------------------------- */
extern CONSTSTRING AlMsg_get_uprop(Msg, CONSTKEY);
extern int AlMsg_get_length_uprop(Msg, CONSTKEY);

/* Get Error Code Information, after an error has occurred */
/* ------------------------------------------------------- */
extern int AlMsg_get_error_code(Msg);
extern const char *AlMsg_get_error_msg(Msg);


#else


/*********************************************************************/
/****** Functions to Create, Print, and Destroy a Message Object *****/
/*********************************************************************/

/* The create and destroy functions are strickly called by the Folder    */
/* Object. (see "AlFolder_next_msg()" in folder's header file (folder.h) */
/* --------------------------------------------------------------------- */
extern Msg AlMsg_create();
extern STRING AlMsg_write_uprops_to_buffer();
extern STRING AlMsg_write_states_to_buffer();
extern Bool AlMsg_destroy();

extern NORET AlMsg_print_self();


/****************************************************************************/
/****** Functions to parse a msg buffer. (Used only by the folder object) ***/
/****************************************************************************/

char *AlMsg_readkey();                            /* read a mail header key */
char *AlMsg_readvalue();                        /* read a mail header value */


/********************************************/
/****** Functions to Store Information ******/
/********************************************/

/* Set Folder Dependent Information */
/* -------------------------------- */
extern Bool AlMsg_set_folder();               /* called by the folder object */
extern NORET AlMsg_set_msg_buffer();              /* called by folder object */
extern Bool AlMsg_set_fs_state_registry();               /* called by folder */

/* Manipulate State Information */
/* ---------------------------- */
/* (Note: Not User Excessable.) */
extern NORET AlMsg_set_name();                    /* called by folder object */
extern NORET AlMsg_set_removed_flag();
extern Bool  AlMsg_set_moved_from_state();
extern Bool  AlMsg_set_how_many_times_moved();
extern Bool  AlMsg_set_num_rules_fired_state();
extern int   AlMsg_incr_num_rules_fired_state();
extern NORET AlMsg_set_suppress_states_out();
extern NORET AlMsg_set_suppress_uprops_out();
extern NORET AlMsg_set_init_uprop_field_count();


/* Manipulate User Properties */
/* -------------------------- */
extern NORET AlMsg_set_uprop();
extern Bool AlMsg_set_uprop_permanence();
extern Bool AlMsg_delete_uprop();
extern Bool AlMsg_append_uprop();
extern Bool AlMsg_copy_uprop();
extern Bool AlMsg_rename_uprop();

/* Manipulate Error Code Information, after an error has occurred */
/* -------------------------------------------------------------- */
extern NORET AlMsg_clear_error_code();

/********************************************/
/***** Functions to Retrieve Information ****/
/********************************************/

/* Get Keyed Field Information */
/* --------------------------- */
extern int AlMsg_number_of();
extern STRING *AlMsg_get_raw_fields();
extern Bool AlMsg_get_fields();
extern int AlMsg_number_of_type();
extern AlFieldCore AlMsg_get_nth_field();
extern AlFieldCore AlMsg_get_indexed_field();

/* Get Folder Dependent Information */
/* -------------------------------- */
extern AlFolder AlMsg_get_folder();
extern char *AlMsg_get_msg_buffer();              /* called by folder object */
extern Registry AlMsg_get_fs_state_registry();    /* called by folder object */

/* Get State Information */
/* --------------------- */
extern char *AlMsg_name();
extern Bool AlMsg_get_removed_flag();
extern STRING AlMsg_get_moved_from_state();
extern int AlMsg_get_how_many_times_moved();
extern int AlMsg_get_num_rules_fired_state();
extern int AlMsg_get_num_of_fields();
extern int AlMsg_get_msg_line_length();
extern int AlMsg_get_msg_char_length();
extern int AlMsg_get_body_line_length();
extern int AlMsg_get_body_char_length();
extern char *AlMsg_get_msg_body();
extern Bool AlMsg_unprintables_in_body();
extern int AlMsg_get_state_field_count();
extern Bool AlMsg_get_suppress_states_out();
extern Bool AlMsg_get_suppress_uprops_out();
extern unsigned int AlMsg_get_init_uprop_field_count();
extern int AlMsg_get_num_perm_uprops();

/* Get User Property Information */
/* ----------------------------- */
extern char *AlMsg_get_uprop();
extern int AlMsg_get_length_uprop();

/* Get Error Code Information, after an error has occurred */
/* ------------------------------------------------------- */
extern int AlMsg_get_error_code();
extern char *AlMsg_get_error_msg();

#endif          /* end of  #ifdef _STDC_  */

/**************************************************************************/
/*********  Restrictions to be documented in Lens Documentation  **********/
/**************************************************************************/
/*                                                                        */
/* Note: User Properties (both property name and value) can contain ANY   */
/*  non-null characters.                                                  */
/**************************************************************************/

#endif         /* end of ifndef _msg_h_  :: DO NOT WRITE BELOW THIS LINE. */
