/*******************************************************
 * Sieve (mail filter) structure creation/destuction.
 *
 * Filename:      sieve-struct.h
 * Author:        Randall Gellens
 * Last Modified: 4 November 1998
 * Version:       
 * Copyright:     1998, QUALCOMM Incorporated,
 *                all rights reserved
 *******************************************************/


#ifndef __sieve_struct_def__
   #define __sieve_struct_def__


#ifndef TRUE
   #define TRUE 1
#endif

#ifndef FALSE
   #define FALSE 0
#endif

#include "skanx.h"


/*---------------   enums used in structures   --------------*/

typedef enum                    /* the tests */
    {
    tstAlwaysFalse = 1,         /* should perhaps be consumed at "compile" time */
    tstAlwaysTrue,              /* should perhaps be consumed at "compile" time */
    tstNot,                     /* nested: this_test points at test to negate */
    tstAnyOf,                   /* nested: this_test points at head of tests to "or" */
    tstAllOf,                   /* nested: this_test points at head of tests to "and" */
    tstSize,                    /* compare message size to num */
    tstSupport,                 /* should be consumed at "compile" time */
    tstExists,                  /* header comparison (for existance) */
    tstHeader,                  /* header comparison (substring match) */
    tstEnvelope                 /* envelope comparison (substring match) */
    } test_type;

typedef enum                    /* the comparison operations */
    {
    opContains = 1,             /* substring match ("" matches anything) */
    opExists,                   /* header exists */
    opMatches,                  /* wildcard match using "*", "?", "\" */
    opIs,                       /* exact match */
    opOver,                     /* SIZE > quantity */
    opUnder                     /* SIZE < quantity */
    } op_type;

typedef enum                    /* the comparators */
    {
    cprOctet = 1                /* ignore charset issues */
    } cmptr_type;

typedef enum                    /* statement types */
    {
	stmtIf = 1,                 /* statement is an IF */
	stmtAction                  /* statement is an action */
	} stmt_type;

typedef enum                    /* the actions */
    {
    acnReject = 1,              /* discard and issue DSN with text as human-readable text */
    acnDiscard,                 /* throw away */
    acnFileInto,                /* keep, but into folder other than default */
    acnForward,                 /* re-inject into SMTP stream, text is recipient */
    acnKeep,                    /* deliver as normal */
    acnReply,                   /* generate new message */
    acnMark,                    /* add header to message */
    acnStop,                    /* terminate script evaluation */
	acnVoid                     /* do nothing */
    } action_type;



/*---------------   common structures   --------------*/

typedef struct strScriptT            /* a parsed script object */
    {
    struct strStmtT    *start;       /* start of script (first statement) */
    char                fname[256];  /* full pathname to script file */
	int                 errCnt;      /* count of syntax errors */
    int                 warnCnt;     /* count of warnings */
	char               *errText;     /* text of syntax errors */
	char               *warnText;    /* text of warnings */
    int                 iMalloc;     /* number of items currently allocated */
    } strScript;

union if_or_actT					  /* an IF or an ACTION; used in strStmt */
	{
	struct strIfT      *this_if;      /* statement is an IF */
    struct strActionT  *action;       /* statement if an action */
	};

typedef struct strStmtT               /* a statement; an action or an IF */
    {
	stmt_type           stmtType;     /* is it an IF or an action */
    union  if_or_actT   stmt;         /* pointer to strIf or strAction */
    struct strStmtT    *next_stmt;    /* peer statement */
	int                 iLine;        /* line number in script where this statement appears */

    } strStmt;

typedef struct strIfT                 /* an IF */
    {
    struct strTestT    *test;         /* the test */
    struct strStmtT    *this_stmt;    /* statement to be executed if test is true */
    struct strStmtT    *else_stmt;    /* statement to be executed if test is false */
    }  strIf;

typedef struct strTestT              /* a test */
    {
    test_type           tstType;     /* simple type, or nested type */
    struct strCompareT *compare;     /* if simple type, this points at the comparison */
    struct strTestT    *this_test;   /* if nested type, this points at the head of the child list */
    struct strTestT    *next_test;   /* points at sibling test */
    } strTest;

typedef struct strCompareT           /* a comparison */
    {
    struct strTextT    *hdr;         /* header name(s) (no trailing colon) */
    op_type             op;          /* which comparison operation */
    cmptr_type          comparator;  /* which comparator */
    struct strTextT    *text;        /* used for HEADER comparisons */
    long                num;         /* used for SIZE comparison */
    } strCompare;

typedef struct strActionT            /* an action */
    {
    action_type         actnType;    /* which action */
    char               *text;        /* simple text used in action */
    struct strLinesT   *message;     /* CRLF-delimited lines used in action */
    } strAction;

typedef struct strLinesT             /* CRLF-delimited lines */
    {
    long                length;      /* total length of text, including CRLFs */
    char               *lines;       /* the CRLF-delimited lines */
    } strLines;

typedef struct strTextT              /* linked list of simple text items */
    {
    char               *text;        /* simple text */
    struct strTextT    *next;        /* points at next text item */
    } strText;


/* flags for do_script and scheck_syntax */

#define PARSE_ABORT_ON_ERROR       1
#define PARSE_ABORT_ON_WARNING     2


/* macros for turning enums into names */

#define szACTION_TYPE_NAME(t)    szActionTypeNames+(t*5)
#define szOP_TYPE_NAME(t)        szOpTypeNames    +(t*5)
#define szTEST_TYPE_NAME(t)      szTestTypeNames  +(t*5)
#define szSTMT_TYPE_NAME(t)      szStmtTypeNames  +(t*5)


/* structure used by sieve-parse.c and syntax_error */

/* The error and warning text strings are formatted to be easy to generate and parse;
 * each is a series of CRLF-delimited lines.  Each line reports on one error or 
 * warning, and takes the MIME-header-like form of semicolon-separated attribute/value
 * pairs, as specified in the ACAP Email Accounts dataset.
 *
 * Attributes include 'text', 'line', 'offset', and 'length'.  'text' must be the last
 * attribute on a line.  Other attributes may be added in the future.  'line', 
 * 'offset', and 'length' refer to a specific location within the Sieve script file;
 * 'text' contains the actual error or warning.
 *
 * Example:
 *     line: 6; offset: 0; length: 12; text: semicolon expected
 *     line: 9; offset: 6; length:  2; text: unrecognized test
 *
 */

typedef struct                  
    {
    strParseLine  ParseLine,     /* structure used by skanx */
                 *psPL;          /* points at ParseLine (makes life easier) */
    FILE         *pfScript;      /* pointer to script FILE */
    int           iLineNum;      /* current line of file (1-relative) */
    char          szLine[1024];  /* buffer for current line */
    char          fname[256];    /* name of script file (full path). */
    char          stamp[64];     /* for debugging */
    int           debug;
    int           errCnt;        /* count of syntax errors */
    int           warnCnt;       /* count of warnings */
	char         *errText;       /* text of syntax errors (in 'attribute: value' notated lines) */
	char         *warnText;      /* text of warnings in 'attribute: value' notated lines) */
	int           errSize;       /* allocated size of error text buffer */
	int           warnLeft;      /* allocated size of warning text buffer */
	int           errLeft;       /* free bytes in error text buffer */
	int           warnSize;      /* free bytes in warning text buffer */
    size_t        iHiMalloc;     /* total number of items ever allocated */
    size_t        iHiSize;       /* total size of all items ever allocated */
    size_t        iScanned;      /* number of tokens (more or less) */
    } strParseFile;


/*-------- flags to control aspects of behavior ---------*/

#define DO_ALLOC_COUNT             1
#define ERR_WARN_CHUNK_SIZE     2048



/*------------------   prototypes   --------------------*/

#ifdef __cplusplus
   extern "C" {
#endif

void        syntax_error(int warn, const char *psz, strParseFile *psPF, int ln);

void       *my_malloc(size_t iSize, strParseFile *psPF, const char *what, int ln);
void        my_free(void *ptr, int debug, int ln);
 
strScript  *new_script   (FILE *fscr, const char *fname, int flags, int debug, int ln);
strStmt    *new_stmt     (strParseFile *psPF);
strIf      *new_if       (strParseFile *psPF);
strTest    *new_test     (test_type type, strParseFile *psPF);
strCompare *new_compare  (strText *hdr, op_type op, cmptr_type ctor, 
                                 strText *text, long num, strParseFile *psPF);
strAction  *new_action   (action_type type, strParseFile *psPF);
strText    *new_text     (char *ptext,      strParseFile *psPF);
strLines   *new_lines    (char *line,       strParseFile *psPF);

void        free_script  (strScript  *strPtr, int debug);
void        free_stmt    (strStmt    *strPtr, int debug);
void        free_if      (strIf      *strPtr, int debug);
void        free_test    (strTest    *strPtr, int debug);
void        free_compare (strCompare *strPtr, int debug);
void        free_action  (strAction  *strPtr, int debug);
void        free_text    (strText    *strPtr, int debug);
void        free_lines   (strLines   *strPtr, int debug);

#ifdef __cplusplus
   }
#endif

#endif /* __sieve_struct_def__ */
