/**************************************************************************
 *                                                                         *
 *   GALEMLAH.CPP                                                          *
 *                                                                         *
 *   Copyright (c) 1997 Galacticomm, Inc.                                  *
 *                                                                         *
 *                                                                         *
 *   E-mail Active HTML.                                                   *
 *                                                                         *
 *                                                  - N.C. Osterc  7/01/97 *
 *                                                                         *
 ***************************************************************************/

#pragma option -w-par
#define _RWSTDLL
#include <windows.h>
#include "gcomm.h"
#include "majorbbs.h"
#include "gcspsrv.h"
#include "galacth.h"
#include "tvb.h"
#include "dnf.h"
#include "ahutil.h"
#include "ahusrxrf.h"
#include "webd.h"
#include "gme.h"
#include "galrtf.h"
#include "gmeutl.h"
#include "ftg.h"
#include "iostream.h"
#include "fioapi.h"
#include "msgatt.h"
#include "httpup.h"
#include "galmsg.h"
#include "galmsgah.h"
#include "cyctimer.h"
#include "gmetvbah.h"
#include "efhooks.h"
#include "galtext.h"
#include "msgah.h"
#include "dnfmgr.h"
#pragma option -w-aus
#include <deque>
#pragma option -w-aus
#include <cstring.h>
using namespace std;

#define FILREV "$Revision: 45 $"

#if defined(EXTRA_LOGGING)
#define LOGFILE "galme.log"        //HACK: change when want EML-only logging
static VOID logmsg(CHAR const * fmt,...);
static VOID vlogmsg(CHAR const * fmt,va_list ap);
#define LOG0(s)               logmsg(s)
#define LOG1(s,v1)            logmsg(s,v1)
#define LOG2(s,v1,v2)         logmsg(s,v1,v2)
#define LOG3(s,v1,v2,v3)      logmsg(s,v1,v2,v3)
#define LOG4(s,v1,v2,v3,v4)   logmsg(s,v1,v2,v3,v4)
#else
#define LOG0(s)               ((VOID)0)
#define LOG1(s,v1)            ((VOID)0)
#define LOG2(s,v1,v2)         ((VOID)0)
#define LOG3(s,v1,v2,v3)      ((VOID)0)
#define LOG4(s,v1,v2,v3,v4)   ((VOID)0)
#endif /* EXTRA_LOGGING */

#define PPFIX "galacth/galemlah/"   // main Active H directory
#define GETINPUT(X) (ses->param(X,strInpBuf,STRINPSIZ)) // macro for getting params
#define paramOK(X) (ses->paramIndex(X,m_pIndex)) // macro for checking parameter existence
#define userOK() ((m_usrPtr=ses->getUser()) != NULL) // macro ensures user exists
#define userAcc() (ses->getUser()->hasKey(hEmlKey)) // macro ensures user has access

#define STRINPSIZ             16385 // max input size of gotten Web parameter
#define TXTBUFLEN             16834 // size of text-storage area
#define CCSIZ                 1024  // size of storage buffer for CC list
#define URLSIZ                1024  // max URL size
#define NAMESIZ               32    // max size of parameter name in /delete
#define WRITECHUNKSIZ         256   // max bytes to write to file per cycle
#define SENDCYCSIZ            128   // max bytes to evaluate in format4send() per cycle
#define MAXQUOSIZ             79    // maximum quotation line size
#define MAXLINSIZ             72    // max regular line size
#define PFNWORD               5     // size of profane text to grab

#define PREF_HTML             1     // Global HTML preference value from .MSG
#define PREF_JAVA             2     // Global Java preference value from .MSG

#define PROCEED_AH_REQUEST    0     // Proceed with Request processing
#define PROCEED_AH_POST       1     // Proceed with Post processing
#define PROCEED_AH_RESPONSE   2     // Proceed with Response processing
#define PROCEED_AH_DELETE     3     // Proceed with Delete processing
#define PROCEED_AH_QUEUEUP    4     // Proceed queueing up message headers
#define PROCEED_AH_READMSG    5     // Proceed reading a message
#define PROCEED_AH_PREVMSG    6     // Proceed rading previous message
#define PROCEED_AH_NEXTMSG    7     // Proceed reading next message
#define PROCEED_AH_EXTHEAD    8     // Proceed doing extended header procing
#define PROCEED_AH_STRIPRTF   9     // Proceed stripping RTF (if required)
#define PROCEED_AH_FORMAT     10    // Proceed with message formatting
#define PROCEED_AH_LINKS      11    // Proceed with adding links
#define PROCEED_AH_REPLY      12    // Proceed with Reply processing
#define PROCEED_AH_NEARGELT   13    // Proceed reading message near in GELT order
#define PROCEED_AH_LISTALL    14    // Proceed Listing All message headers
#define PROCEED_AH_MOREHI     15    // Proceed checking if there are more hi msgs
#define PROCEED_AH_MORELO     16    // Proceed checking if there are more lo msgs
#define PROCEED_AH_VALIDATE   17    // Proceed validating message
#define PROCEED_AH_FORWARD    18    // Proceed forwarding message
#define PROCEED_AH_COPYMSG    19    // Proceed Copying message
#define PROCEED_AH_MARKREAD   20    // Proceed marking msg as read
#define PROCEED_AH_DOWNLOAD   21    // Proceed downloading file attachment
#define PROCEED_AH_QUOTE      22    // Proceed quoting message
#define PROCEED_AH_PRCSUBMIT  23    // Proceed processing /send submit
#define PROCEED_AH_MOVEFILE   24    // Proceed moving file
#define PROCEED_AH_ATTACH     25    // Proceed attachment processing
#define PROCEED_AH_SENDFORMAT 26    // Proceed formatting message when sent
#define PROCEED_AH_VALIDADR   27    // Proceed Validating Address
#define PROCEED_AH_VALIDPRI   28    // Proceed Validating Priority
#define PROCEED_AH_VALIDBLEN  29    // Proceed Validating Body Length
#define PROCEED_AH_VALIDRR    30    // Proceed Validating Return Receipt
#define PROCEED_AH_VALIDATT   31    // Proceed Validating Attachment
#define PROCEED_AH_VALIDPFN   32    // Proceed Profanity Checking
#define PROCEED_AH_VALIDPFBDY 33    // Proceed more Profanity Checking
#define PROCEED_AH_VALIDCCADR 34    // Proceed validating CC addresses
#define PROCEED_AH_VALIDCCATT 35    // Proceed Validating CC attachment

#define LIST_NEWMSGS          1     // New Messages flag
#define LIST_DIREC_LT         2     // Direction Less-than flag
#define LIST_DIREC_GT         4     // Direction Greater-than flag
#define LIST_DIREC_LE         8     // Direction less-than-equal flag
#define LIST_DIREC_GE         16    // Direction greater-than-equal flag
#define LIST_ORD_ASCEND       32    // Order ascending flag
#define LIST_ORD_DESCEND      64    // Order descending flag
#define LIST_ALL              128   // List all messages flag
#define LIST_SENT             256   // List all sent messages flag

#define READ_REFLOW           1     // Reflow message text flag
#define READ_NOTEXT           2     // Don't display text flag
#define READ_NEAR             4     // Read message near flag
#define READ_RETRECREQ        8     // Return receipt flag

#define WRITE_NEW             1     // Write new message flag
#define WRITE_REPLY           2     // Write a reply message flag
#define WRITE_RESEND          4     // Write a resend message flag
#define WRITE_QUOTE           8     // Enable Quoting flag
#define WRITE_TOALL           16    // Write "to all" flag
#define WRITE_PRI             32    // Generate priority msg flag
#define WRITE_RR              64    // Generate return-receipt flag
#define WRITE_KEEPFMT         128   // Keep msg format flag
#define WRITE_INCLIST         256   // Include CC's flag

#define SUBMIT_SEND           1     // Flag - actually send message
#define SUBMIT_ATTACH         2     // Flag - send form to submit upload
#define SUBMIT_UPLOAD         4     // Flag - process uploaded file
#define SUBMIT_DETACH         8     // Flag - detach message attachment
#define SUBMIT_PREVIEW        16    // Flag - preview message
#define SUBMIT_REDISPLAY      32    // Flag - redisplay write form
#define SUBMIT_CANCEL         64    // Flag - Cancel message being composed
#define SUBMIT_NOTEXT         128   // Flag - Don't show text

#define ERR_PARAMISSING      -100   // Error code - Parameter is missing
#define ERR_PROFANATT        -101   // Error code - Attachment is profane
#define ERR_PROFANTPC        -102   // Error code - Message topic is profane
#define ERR_PROFANBDY        -103   // Error code - Body text is profane
#define ERR_INVALIDFN        -104   // Error code - Invalid file name
#define ERR_BODY2LONG        -105   // Error code - Body of msg too long
#define ERR_2MANYCC          -106   // Error code - too many CC addresses

#define SUBMITARRSIZ         6      // size of submit arrays

#define WRITEURL             "write/"          // write url suffix
#define WRITE_ERR_URL        "write/error.htm" // default write error template
#define WRITE_IDX_URL        "write/index.htm" // default write success template
#define VIEW_ERR_URL         "view/error.htm"  // default view error template
#define VIEW_IDX_URL         "view/index.htm"  // default view success template
#define LISTURL              "list/"           // list url suffix
#define FRAMECOOKIE          "emailframe"      // frame cookie name

CHAR *valccatt;                    // error when checking cc attachment from .MSG
CHAR *valccadr;                    // error when checking cc addresses from .MSG
CHAR *noxhdr;                      // no extended header info from .MSG
CHAR *valadress;                   // error when validating address from .MSG
CHAR *valattach;                   // error when validating attachment from.MSG
CHAR *valpriority;                 // error when validating priority from.MSG
CHAR *valrr;                       // error when validating return receipt from.MSG
CHAR *erprfbt;                     // error - body profane from .MSG
CHAR *erinvfn;                     // error - invalid file name from .MSG
CHAR *erprfat;                     // error - attachment profane from .MSG
CHAR *erprftp;                     // error - topic profane from .MSG

typedef deque<struct message *> MHDRQUEUE, *LPMHDRQUEUE;

CHAR *submitArr[]={"send","attach","upload","detach","preview",
                    "redisplay","cancel"};

                                   // array of submit types (above)

SHORT subiarr[]={SUBMIT_SEND,SUBMIT_ATTACH,SUBMIT_UPLOAD,
                    SUBMIT_DETACH,SUBMIT_PREVIEW,SUBMIT_REDISPLAY,
                    SUBMIT_CANCEL};

                                   // array of submit values (above)

static
ULONG                              // returns unsigned long
atoul(                             // convert const char to unsigned long
const CHAR *);                     // passed const string

static GBOOL
isquoted(                          // does line start with quote symbol?
CHAR const * s);                   // pointer to start of line

static CHAR strInpBuf[STRINPSIZ];  // buffer for gotten parameter
static CHAR* ahemlkey=NULL;        // Active HTML (Java) access key from .MSG
static INT iPreference;            // global web-interface preference value from .MSG
static GBOOL bUseFrames;           // boolean - global use frames value from .MSG
static INT iTimeSlice;             // timeslice value from .MSG
static INT iMaxCC;                 // max CC's allowed from .MSG
static INT iDefListCount;          // default amount of msgs in list from .MSG
static INT iMaxListCount;          // maximum amount of msgs in list from .MSG

// enumerated values for use with Java and Pure Active HTML Dynafiles

enum {CYC,ARCHIVETYPE,TMPID,LISTITEM,BODYTEXT,BODYTEXT2,BODYTEXT3,BODYTEXT4,
      BODYTEXT5,BODYTEXT6,BODYTEXT7,HEADERS};

// end enumated values

// DnfStep instantiations for Java AH Dynafiles

dnfStep dnfCycleSteps[]={
     dnfStep(DNFTABLE),
          dnfStep(DNFCOLUMN,CYC,"CYCLE"),
     dnfStep(DNFTABLEEND),
     dnfStep(DNFMAPEND)
};

dnfStep mainSteps[] =
{
     dnfStep(DNFWATCH,ARCHIVETYPE,"ZIP"),
     dnfStep(DNFMAPEND)
};

dnfStep ulSteps[] =
{
     dnfStep(DNFWATCH,TMPID,"TMPID"),
     dnfStep(DNFMAPEND)
};

dnfStep popSteps[] =
{
     dnfStep(DNFWATCH,TMPID,"TMPID"),
     dnfStep(DNFMAPEND)
};

dnfStep uploadSteps[] =
{
     dnfStep(DNFMAPEND)
};

dnfStep inProgressSteps[] =
{
     dnfStep(DNFMAPEND)
};

// End DnfStep instantiations for Java AH Dynafiles

// dnfMap instantiations for Java AH Dynafiles

dnfMap emlCycleMap(PPFIX "emlcyc.htm", "Cycle", dnfCycleSteps);
dnfMap mainMap( PPFIX "email.htm", "Main", mainSteps);
dnfMap ulMap( PPFIX "ul.htm", "ul", ulSteps);
dnfMap popMap( PPFIX "pop.htm", "pop", popSteps);
dnfMap uploadMap( PPFIX "upload.htm", "upload", uploadSteps);
dnfMap inProgressMap( PPFIX "inprog.htm", "in progress", inProgressSteps);

// end dnfMap instantiations for Java AH Dynafiles


// DnfStep instantiations for Pure HTML Dynafiles

dnfStep dnfListSteps[]={
     dnfStep(DNFTABLE),
          dnfStep(DNFCOLUMN,LISTITEM,"LISTITEM"),
     dnfStep(DNFTABLEEND),
     dnfStep(DNFMAPEND)
};
dnfStep dnfViewSteps[]={
     dnfStep(DNFWATCH,BODYTEXT,"BODYTEXT"),
     dnfStep(DNFMAPEND)
};
dnfStep dnfWriteSteps[]={
     dnfStep(DNFWATCH,BODYTEXT2,"BODYTEXT"),
     dnfStep(DNFMAPEND)
};
dnfStep dnfPreViewSteps[]={
     dnfStep(DNFWATCH,BODYTEXT3,"BODYTEXT"),
     dnfStep(DNFMAPEND)
};
dnfStep dnfUplSteps[]={
     dnfStep(DNFWATCH,BODYTEXT4,"BODYTEXT"),
     dnfStep(DNFMAPEND)
};
dnfStep dnfRedispSteps[]={
     dnfStep(DNFWATCH,BODYTEXT5,"BODYTEXT"),
     dnfStep(DNFMAPEND)
};
dnfStep dnfDetachSteps[]={
     dnfStep(DNFWATCH,BODYTEXT6,"BODYTEXT"),
     dnfStep(DNFMAPEND)
};
dnfStep dnfAttachSteps[]={
     dnfStep(DNFWATCH,BODYTEXT7,"BODYTEXT"),
     dnfStep(DNFMAPEND)
};
dnfStep dnfViewExtSteps[]={
     dnfStep(DNFWATCH,HEADERS,"HEADERS"),
     dnfStep(DNFMAPEND)
};
dnfStep dnfRedispErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfPreviewErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfCancelSuccSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfCancelErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfUplErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfDetachErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfSentOkSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfSentErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfWriteErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfViewErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfExtErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfAttErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfAttachErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfDelErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfDelSuccSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfFwdErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfFwdSuccSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfPrefErrSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfPrefSuccSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfFileSuccSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfNoFrameSteps[]={
     dnfStep(DNFMAPEND)
};
dnfStep dnfFrameSteps[]={
     dnfStep(DNFMAPEND)
};

// end dnfStep instantiations for Pure HTML Dynafiles

// beging dnfMap instantiations for Pure HTML Dynafiles

dnfMap viewExtMap(PPFIX "view/ext/index.htm","View Header Info", dnfViewExtSteps);
dnfMap viewMap(PPFIX VIEW_IDX_URL,"View a Message", dnfViewSteps);
dnfMap writeMap(PPFIX WRITE_IDX_URL,"Write a Message", dnfWriteSteps);
dnfMap listMap(PPFIX "list/index.htm", "List Messages", dnfListSteps);
dnfMap redispMap(PPFIX WRITE_IDX_URL,"Redisp Success",dnfRedispSteps);
dnfMap redispErrMap(PPFIX WRITE_ERR_URL,"Redisp Error",dnfRedispErrSteps);
dnfMap previewMap(PPFIX VIEW_IDX_URL,"View Success",dnfPreViewSteps);
dnfMap previewErrMap(PPFIX VIEW_ERR_URL,"Preview Error",dnfPreviewErrSteps);
dnfMap cancelMap(PPFIX "write/cancel.htm","Cancel Success",dnfCancelSuccSteps);
dnfMap cancelErrMap(PPFIX WRITE_ERR_URL,"Cancel Error",dnfCancelErrSteps);
dnfMap attachMap(PPFIX "write/upload.htm","Upload Success",dnfAttachSteps);
dnfMap attachErrMap(PPFIX WRITE_ERR_URL,"Attachment Error",dnfAttachErrSteps);
dnfMap detachMap(PPFIX WRITE_IDX_URL,"Detach Success",dnfDetachSteps);
dnfMap detachErrMap(PPFIX WRITE_ERR_URL,"Detach Error",dnfDetachErrSteps);
dnfMap sendMap(PPFIX "write/sentok.htm","Sent ok",dnfSentOkSteps);
dnfMap sendErrMap(PPFIX WRITE_ERR_URL,"Sent error",dnfSentErrSteps);
dnfMap writeErrMap(PPFIX WRITE_ERR_URL,"Write Error",dnfWriteErrSteps);
dnfMap viewErrMap(PPFIX VIEW_ERR_URL,"View Error",dnfViewErrSteps);
dnfMap viewExtErrMap(PPFIX "view/ext/error.htm","Extended Header Error",dnfExtErrSteps);
dnfMap attErrMap(PPFIX "att/error.htm","Attachment Download Error",dnfAttErrSteps);
dnfMap deleteErrMap(PPFIX "delete/error.htm","Deleted Error",dnfDelErrSteps);
dnfMap deleteSuccMap(PPFIX "delete/index.htm","Delete Success",dnfDelSuccSteps);
dnfMap fwdErrMap(PPFIX "forward/error.htm","Forward Error",dnfFwdErrSteps);
dnfMap fwdSuccMap(PPFIX "forward/index.htm","Forward Success",dnfFwdSuccSteps);
dnfMap prefErrMap(PPFIX "pref/error.htm","Pref Error",dnfPrefErrSteps);
dnfMap prefSuccMap(PPFIX "pref/index.htm","Pref Success",dnfPrefSuccSteps);
dnfMap fileMap(PPFIX "file/index.htm","File Default",dnfFileSuccSteps);
dnfMap defnfMap(PPFIX "indexn.htm","No Frames Default",dnfNoFrameSteps);
dnfMap deffMap(PPFIX "indexf.htm","Frames Default",dnfFrameSteps);
dnfMap uplMap(PPFIX WRITE_IDX_URL,"Upload ok",dnfUplSteps);
dnfMap uplErrMap(PPFIX WRITE_ERR_URL,"Upload error",dnfUplErrSteps);

// end Pure HTML dnfMap Instantiations

class emlAgent : public acthAgent {              // Active HTML E-mail Agent
public:

     VOID
     getMsgOpts();                 // get Java message options

     VOID
     getHTMLMsgOpts();             // get Pure HTML message options

     VOID
     freeStgAllocs();              // free memory alloced in stgopt() calls

     emlAgent() : acthAgent("Worldgroup Email","email") // constructor
     {
          if (eUseHtml || eUseJava) {
               registerAgent(acthVersion);
               getMsgOpts();
               deldir(AHUPDIR);
               if (eUseHtml) {
                    getHTMLMsgOpts();
               }
          }

     }

     ~emlAgent()                   // destructor
     {
          if (eUseHtml || eUseJava) {
               freeStgAllocs();
          }
          delete [] valccatt;
          delete [] valccadr;
          delete [] noxhdr;
          delete [] valadress;
          delete [] valattach;
          delete [] valpriority;
          delete [] valrr;
          delete [] erinvfn;
          delete [] erprfat;
     }

     acthSynthesis *               // my session info (NULL=can't)
     newSynthesis(                 // instantiate my Synthesis class
     acthSession *ses);            // for passing to acthSynthesis's ctor
};

class emailCommon {                // Common Email class (used by both Java and Pure)
public:
     emailCommon(GBOOL _html) :    // constructor
          m_needToCycle(FALSE),
          m_merr_code(GMEOK),
          m_merr_message(""),
          m_bPureHTML(_html)
     {
          m_timer.setSlice(iTimeSlice);
     }

     ~emailCommon()                // destructor
     {
     }

     GBOOL
     startProc();                  // start with cycle process

     GBOOL
     contProc(                     // continue processing cycle timer?
     ACTHCODE rc);                 // code indicating whether to continue processing

public:

     INT m_merr_code;              // store MERR_CODE tvb value
     string m_merr_message;        // store MERR_MESSAGE tvb value
     cycleTimer m_timer;           // instance of cycletimer class
     GBOOL m_needToCycle;          // do we need to cycle?
     GBOOL m_bPureHTML;            // using w/ pure HTML synth?
};

static VOID
handleError(                       // handle GME error
emailCommon *ecPtr,                // Pointer to emailCommon instance
INT operation,                     // type of operation (GENERIC or VALIDATION)
const CHAR *additionalErrorMsg);   // any additional error message to append

class emlSynthesis : public acthSynthesis {      // AH-Java Email Synthesis
public:
     emlSynthesis(acthSession *_ses) :           // constructor
          acthSynthesis(_ses),
          xrfptr(NULL),
          exthdrptr(NULL),
          m_httpUp ( NULL ),
          m_doneFlg( FALSE ),
          m_gotText( FALSE ),
          m_attaching( FALSE ),
          m_doReply ( FALSE ),
          m_doCopy ( FALSE ),
          m_rrFlag ( FALSE ),
          m_priFlag ( FALSE ),
          m_doDl ( FALSE ),
          m_doFwd ( FALSE ),
          m_slExempt ( FALSE ),
          m_dnfPtr(NULL),
          m_usrPtr(NULL)
     {
          m_savMsgId=0;
          m_savFid=0;
          m_cclist[0]='\0';
          m_mhdrptr=&mhdr;
          m_topic[0]='\0';
          m_holdid[0]='\0';
          m_savoutsz=0;
          m_tmpid = ::GetTickCount();
          m_ecPtr=new emailCommon(FALSE);
     }

     ~emlSynthesis()               // destructor
     {
          if (xrfptr != NULL) {
               delete xrfptr;
               xrfptr=NULL;
          }
          if (m_doDl) {
               gdldone(m_usrPtr->userid(),tagbuf);
          }
          if (m_ecPtr != NULL) {
               delete m_ecPtr;
               m_ecPtr=NULL;
          }
          if (m_dnfPtr != NULL) {
               delete m_dnfPtr;
               m_dnfPtr=NULL;
          }
     }

     public:

     CHAR mywrkarea[GMEWRKSZ];     // GME Work Area 'tween cycle
     CHAR txtbuf[TXTBUFLEN];       // text buffer
     CHAR txtbuf2[TXTBUFLEN];      // text buffer
     CHAR m_cclist[CCSIZ];          // 'tween cycle cclist storage
     CHAR tagbuf[TSLENG];          // 'tween cycle tagbuf storage
     CHAR m_holdid[MAXADR];        // 'tween cycle user-id storage
     struct message mhdr;          // Instance of message structure
     struct message *m_mhdrptr;    // Pointer to message structure
     struct otscan ots;            // Instace of "one time search" struct
     struct qscfg qsc;             // Instance of quickscan storage struct
     emailCommon *m_ecPtr;         // common email stuff

     ACTHCODE
     proceed();                    // proceed called by base ses class

     protected:

     acthUserXrf *xrfptr;          // Pointer to XRF-object
     const CHAR *exthdrptr;        // Pointer to Extended Header Info
     ULONG m_savMsgId;             // between-cycle msgid storage
     ULONG m_savFid;               // between-cycle forum id
     GBOOL m_rrFlag;               // flag indicates return request
     GBOOL m_priFlag;              // flag indicates priority
     GBOOL m_doneFlg;              // Is Cycle process done?
     GBOOL m_doReply;              // Boolean "can we rply?" flag
     GBOOL m_doCopy;               // Boolean "can we cpy?" flag
     GBOOL m_doFwd;                // Boolean "can we fwd?" flag
     GBOOL m_gotText;              // Boolean "got text yet?" flag
     GBOOL m_doDl;                 // Boolean download progress flag
     CHAR m_topic[TPCSIZ];         // Store text
     INT m_savoutsz;               // Keep track of sent text size
     ULONG m_tmpid;                // attachment / message temp ID
     httpUpload *m_httpUp;         // HTTP upload tracking
     GBOOL m_attaching;            // attachment in progress?
     GBOOL m_slExempt;             // exempt from end-slash
     dnfHandler *m_dnfPtr;         // pointer to dnfHandler class
     acthUserID *m_usrPtr;         // pointer to acthUserID class
     GMEUSERHANDLE m_gmeuh;        // Gme user handle

     VOID
     abort();                      // called if web session aborted

     ACTHCODE
     proceedGet();                 // proceed with "GET" type processing

     ACTHCODE
     proceedPost();                // proceed with "POST" type processing

     ACTHCODE
     dnf_attach();                 // do attachment dynafile

     ACTHCODE
     dnf_copymsg();                // Copy a Message

     ACTHCODE
     dnf_inProgress();             // attachment-already-in-progress

     VOID
     getTmpId();                   // get tmpid param

     ACTHCODE
     dnf_ReadMsgs();               // Read messages starting from msgid

     ACTHCODE
     dnf_ReadaMsg(                 // Read a part. message
     ULONG msgid,                  // the message-ID
     GBOOL txohdr);                // text or header of message?

     ACTHCODE
     dnf_sendmsg();                // Send a message

     ACTHCODE
     dnf_replymsg();               // Reply to a message

     ACTHCODE
     dnf_forwardmsg();             // Forward a message

     ACTHCODE
     dnf_delmsg();                 // Delete a message

     ACTHCODE
     dnf_downloadAtt(              // Download an attachment
     ULONG msgid);                 // the message-ID

     ACTHCODE
     dnf_getExtHeaderInfo();       // Get Extended Header Information

     GBOOL
     getMsgParam();                // Handle same parametrs

     GBOOL
     getMsgParams();               // Handles other params

     VOID
     getTopicParam();              // Process incoming topic

     VOID
     getCCParam();                 // Process incoming cclist

     GBOOL
     validateRR(
     CHAR* to);                    // Return Receipt available?

     GBOOL
     validatePri(
     CHAR* to);                    // Priority Msg Available?

     const CHAR *
     getHistory();                 // get message history

     const CHAR *
     getAttName();                 // get name of attachment

     const CHAR *
     getTopic();                   // get topic name

     const CHAR *
     getDate();                    // get date of message

     const CHAR *
     getTime();                    // get time of message

     VOID
     handleError(                  // handle error
     INT err,                      // the error code
     INT op);                      // operation (GENERIC or VALIDATION)
};

class rootEmailSynth : public acthSynthesis { // handles base ("root") "/email" URL
public:
     rootEmailSynth(acthSession *_ses):       // constructor
          acthSynthesis(_ses),
          m_usingFrames(FALSE),
          m_firstTime(TRUE),
          m_dnfPtr(NULL),
          m_usrPtr(NULL),
          m_savMsgId(0),
          m_doDl(FALSE),
          m_doneFlg(FALSE),
          m_inigmeuCalled(FALSE),
          m_qscptr(NULL),
          m_webFlags(0),
          m_eSyn(NULL)
     {
          m_ecPtr=new emailCommon(TRUE);
          m_mhdrptr=&mhdr;
          txtbuf=new CHAR[TXTLEN];
          txtbuf2=new CHAR[TXTLEN];
     }

     virtual
     ~rootEmailSynth()             // destructor
     {
          if (m_dnfPtr != NULL) {
               delete m_dnfPtr;
               m_dnfPtr = NULL;
          }
          if (m_doDl) {
               gdldone(m_usrPtr->userid(),tagbuf);
          }
          delete [] txtbuf;
          delete [] txtbuf2;

          if (m_ecPtr != NULL) {
               delete m_ecPtr;
               m_ecPtr=NULL;
          }

          if (m_eSyn != NULL) {
               delete m_eSyn;
               m_eSyn=NULL;
          }
     }

     virtual
     ACTHCODE
     proceed();                    // virtual proceed

     ACTHCODE
     proceedJava();                // proceed with Java applet

     ACTHCODE
     respDynafile();               // generic dynafile

     GMEUSERHANDLE
     initGmeUser();                // init gme user account stuff

     VOID
     initHTMLGMEUser();            // set up gme stuff

     VOID
     destructHTMLGMEUser();        // destroy gme stuff

     VOID
     initPrefVariables();          // initialize preference text variables

public:
     acthUserID *m_usrPtr;         // userid
     GBOOL m_usingFrames;          // are we using frames?
     GBOOL m_firstTime;            // first time in procd?
     dnfHandler *m_dnfPtr;         // Pointer to DNF object
     emailCommon *m_ecPtr;         // pointer to common stuff
     CHAR mywrkarea[GMEWRKSZ];     // GME Work Area 'tween cycle
     CHAR *txtbuf;                 // text buffer
     CHAR *txtbuf2;                // text buffer
     CHAR tagbuf[TSLENG];          // 'tween cycle tagbuf storage
     CHAR m_cclist[CCSIZ];          // 'tween cycle cclist storage
     CHAR m_holdid[MAXADR];        // 'tween cycle user-id storage
     struct message mhdr;          // Instance of message structure
     struct message *m_mhdrptr;    // Pointer to message structure
     GBOOL m_doDl;                 // boolean kept for dl aborts
     ULONG m_savMsgId;             // between-cycle msgid storage
     GBOOL m_doneFlg;              // done?
     emlSynthesis *m_eSyn;         // pointer to eml synthesis
     struct qscfg *m_qscptr;       // pointer to qs config
     LONG m_webFlags;              // web preferences
     GBOOL m_inigmeuCalled;        // boolean - did we init gme?
     GMEUSERHANDLE m_gmeuh;          // Gme user handle
};

class pureHTMLSynth : public rootEmailSynth { // pure HTML synthesis
public:
     pureHTMLSynth(acthSession *_ses) :       // constructor
          rootEmailSynth(_ses),
          m_ahState(PROCEED_AH_REQUEST),
          m_moreLow(FALSE),
          m_moreHi(FALSE),
          m_showExtHeadInfo(FALSE),
          m_wrkHeader(NULL),
          m_commentBufPtr(NULL),
          m_orgForId(EMLID),
          m_orgMsgId(0),
          m_writeFlags(0),
          m_sendFlags(0),
          m_forum(0),
          m_forumName(""),
          m_toAdr(""),
          m_topic(""),
          m_cclist(""),
          m_paramText(""),
          m_orgText(""),
          m_attachName(""),
          m_attFile(""),
          m_tmpid(0),
          m_curPos(0),
          m_ofstr(NULL),
          m_gmefname(""),
          m_tickId(::GetTickCount()),
          m_readFlags(0),
          m_succTempPtr(NULL),
          m_errTempPtr(NULL),
          m_iSendPos(0),
          m_lastSpaceLoc(0),
          m_lastCRLF(0),
          m_lineSize(0),
          m_ccPtr(NULL),
          m_ccCount(0),
          m_pfnLoc(0),
          m_msgHdrPtr(NULL)
     {
          m_wrkHeader=new struct message;
          m_commentBufPtr=new CHAR[TXTLEN];
          setmem(mywrkarea,GMEWRKSZ,0);
          inigmerq(mywrkarea);
     }

     virtual
     ~pureHTMLSynth()              // destructor
     {
          delete m_wrkHeader;
          delete [] m_commentBufPtr;
          if (gmerqopn(mywrkarea)) {
               clsgmerq(mywrkarea);
          }
          if (m_ofstr != NULL) {
               delete m_ofstr;
          }
     }

     virtual
     ACTHCODE
     proceed();                    // AH request/response entry point method

     VOID
     getTemplates();               // get templates

     VOID
     initSuccVariables();          // initializes success text variables

     VOID
     initErrVariables();           // initializes error text variables

     ACTHCODE
     handleTemplates(              // handle template response
     dnfMap *succMap,              // success map
     dnfMap *errMap,               // error map
     const CHAR * baseDir,         // base directory
     const CHAR *synthDir);        // synthesis directory

     INT
     SetAutoFwd(                   // set new auto-forwardee
     CHAR* newfwde);               // new address to use

     VOID
     initVars();                   // init vars based on success/error status

     VOID
     updatePref(                   // update a part. preference
     LONG pref,
     GBOOL on);

     GBOOL                         // successfully got all params
     getCompositionParams();       // get common write/send parameters

     VOID
     initCompositionVbs();         // set up write/send variables

     ACTHCODE
     dynaWriteResp();              // dynafile "/write" type response

     ACTHCODE
     dynaReadResp();               // dynafile "/read" type response

     VOID
     sendTemplates();              // handle send custom template stuff

     ULONG
     validateMsgId(                // assure message id isn't out of range
     ULONG msgid);                 // the msgid

     GBOOL
     format4Send();                // format text on a send

     VOID
     removeSubString(              // in-place remove sub string
     CHAR *string,                 // string in question
     INT idx,                      // index to start removing at
     INT len);                     // length of string to remove

     VOID
     insert(                       // in-place insert sub string
     CHAR *orgString,              // original strings
     CHAR *subString,              // string ot insert
     INT idx,                      // index to insert at
     INT bufSiz);                  // total size of buffer

     VOID
     badParam(                     // set up variables for missing param
     const CHAR *param);           // the parameter name

     VOID
     profaneBody();                // sets up message w/ profane string in body

     VOID
     profaneTopic();               // sets up message w/ profane string in topic

protected:

     ULONG m_mhdr_msgid;           // variable contains MHDR_MSGID value
     SHORT m_ahState;              // handling requestor response?
     CHAR m_errorTemplate[URLSIZ]; // error template from "onError" param
     CHAR m_successTemplate[URLSIZ];// success template from "onSuccess" param
     GBOOL m_moreLow;              // more message below
     GBOOL m_moreHi;               // more messages above
     GBOOL m_showExtHeadInfo;      // display extended header info
     INT (*m_readMethod)(VOID *,struct message*,CHAR *); // gme func pointer
     INT m_readType;               // type of read to do
     string m_sMsgTxt;             // store message body text
     INT m_pIndex;                 // dummy value for paramIndex req
     struct message *m_wrkHeader;  // message struct pointer
     CHAR *m_commentBufPtr;        // pointer to buffer for comment storage
     ULONG m_writeFlags;           // store write bit flags
     ULONG m_sendFlags;            // stoer send bit flags
     ULONG m_orgForId;             // orig. forum req'ed on reply/resend
     ULONG m_orgMsgId;             // orig. msgid req'ed on reply/resend
     ULONG m_forum;                // where new msg should be placed
     string m_forumName;           // name of forum msg should be placed
     string m_toAdr;               // to address
     string m_topic;               // topic
     string m_cclist;              // carbon copy list
     string m_paramText;           // text in param
     string m_orgText;             // actual orig. text
     string m_attachName;          // name of attachment
     string m_attFile;             // name of file attached
     ULONG m_tmpid;                // identifier id for use w/ uploads
     istream *m_ulistr;            // pointer to pointer to an istream
     ofstream *m_ofstr;            // output file stream instance
     LONG m_curPos;                // current position in file
     string m_gmefname;            // GME's filename
     ULONG m_tickId;               // id to write uploaded file to
     LONG m_readFlags;             // flags used during read processing
     CHAR *m_succTempPtr;          // pointer to succes template buffer
     CHAR *m_errTempPtr;           // pointer to error template buffer
     CHAR m_writeBuf[WRITECHUNKSIZ]; // where to store stream data for writing
     INT m_iSendPos;               // position in text to send
     INT m_lastSpaceLoc;           // position of last space
     INT m_lastCRLF;               // position of last CR/LF
     INT m_lineSize;               // size of line we're working with
     CHAR *m_ccPtr;                // pointer to CC addresses
     INT m_ccCount;                // count of CC addresses
     INT m_pfnLoc;                 // location inside body of message for profanity checking
     struct message *m_msgHdrPtr;  // message Header pointer
};

class downloadSynthesis : public pureHTMLSynth { // handle download request
public:
     downloadSynthesis(acthSession *_ses) :      // constructor
          pureHTMLSynth(_ses)
     {
     }

     ~downloadSynthesis()          // destructor
     {
     }

     ACTHCODE
     proceed();                    // AH entry point method

     VOID
     abort();                      // attempt to catch email d/l abort
};

class deleteSynthesis : public pureHTMLSynth {   // handle delete request
public:
     deleteSynthesis(acthSession *_ses) :        // constructor
          pureHTMLSynth(_ses),
          m_delCount(0)
     {
     }

     ~deleteSynthesis()            // destructor
     {
     }

     ACTHCODE
     proceed();                    // AH entry point method

private:

     INT m_delCount;               // number of delete parameters
};

class fileSynthesis : public pureHTMLSynth {     // handle generic file request
public:
     fileSynthesis(acthSession *_ses) :          // constructor
          pureHTMLSynth(_ses)
     {
     }

     ~fileSynthesis()              // destructor
     {
     }

     ACTHCODE
     proceed();                    // AH entry point method
};

class forwardSynthesis : public pureHTMLSynth {  // handle forward request
public:
     forwardSynthesis(acthSession *_ses) :       // constructor
          pureHTMLSynth(_ses),
          m_bDeleteMsg(FALSE)
     {
     }

     ~forwardSynthesis()           // destructor
     {
     }

     ACTHCODE
     proceed();                    // AH entry point method

private:

     GBOOL m_bDeleteMsg;           // delete message on forward?
};

class listSynthesis : public pureHTMLSynth {     // handle list request
public:
     listSynthesis(acthSession *_ses) :          // constructor
          pureHTMLSynth(_ses),
          m_listFlags(0),
          m_startMsgId(0),
          m_forum(EMLID),
          m_count(0),
          m_readSoFar(0),
          m_mhdrqueue(NULL),
          m_tableDone(FALSE),
          m_lowId(0),
          m_hiId(0),
          m_bFoundMsgs(false)

     {
          m_mhdrqueue=new MHDRQUEUE;
     }

     ~listSynthesis()                 // destructor
     {
          if (m_mhdrqueue != NULL) {  // ensure queue is empty then delete
               emptyQueue();
               delete m_mhdrqueue;
          }
     }

     ACTHCODE
     proceed();                    // AH entry point method

     VOID
     emptyQueue();                 // ensure queue is empty b4 deleting

     VOID
     initListContextVbs();         // initialize list context variables

     ACTHCODE
     queueUpMessages();            // deque message header structures

     ACTHCODE
     outputMessageList();          // actually do the response dynafile

     ACTHCODE
     procAllMsgsInList();          // process all messages available

private:

     ULONG m_listFlags;            // stores list parameters
     ULONG m_startMsgId;           // starting message
     INT m_count;                  // count of messages to put in list
     INT m_readSoFar;              // messages read so far
     LPMHDRQUEUE m_mhdrqueue;      // pointer to queue that holds msg headers
     INT m_forum;                  // normally EMLID
     GBOOL m_tableDone;            // done processing table?
     ULONG m_lowId, m_hiId;        // store low and hi id's
     bool m_bFoundMsgs;            // did we find any messages on this req?
};

class prefSynthesis : public pureHTMLSynth {     // handle pref request
public:
     prefSynthesis(acthSession *_ses) :          // constructor
          pureHTMLSynth(_ses)
     {
          m_ahState=PROCEED_AH_POST;
     }

     ~prefSynthesis()              // destructor
     {
     }

     ACTHCODE
     proceed();                    // AH entry point method

};

class viewSynthesis : public pureHTMLSynth {     // handle view request
public:
     viewSynthesis(acthSession *_ses) :          // constructor
          pureHTMLSynth(_ses),
          m_viewFlags(0)
     {
     }

     ~viewSynthesis()              // destructor
     {
     }

     ACTHCODE
     proceed();                    // overriden proceed

     ACTHCODE
     dynaExtHeadResp();            // extended header dynafile

private:

     string m_sAppInfo;            // store ext header info here
     ULONG m_viewFlags;          
};

class writeSynthesis : public pureHTMLSynth {    // handle write request
public:
     writeSynthesis(acthSession *_ses) :         // constructor
          pureHTMLSynth(_ses)
     {
     }

     ~writeSynthesis()             // destructor
     {
     }

     ACTHCODE
     proceed();                    // AH entry point method
};

class sendSynthesis : public pureHTMLSynth {     // handle send request
public:
     sendSynthesis(acthSession *_ses) :          // constructor
          pureHTMLSynth(_ses)
     {
          m_ahState=PROCEED_AH_POST;
     }

     ~sendSynthesis()              // destructor
     {
     }

     ACTHCODE
     proceed();                    // overriden proceed

     VOID
     submitError();                // submit hard-coded error

     SHORT
     sendHeaderSetup();            // set up message header stuff

     VOID
     deleteAttachment();           // delete attachment on message "DETACH"

     VOID
     addCCs();                     // add carbon copy addresses to msg text

     GBOOL
     writeFileStream();            // do the bulk of writing to file

     GBOOL
     getFileStream();              // get the file stream

     VOID
     preventTimeout();             // prevent a browser timeout on big upload

     SHORT
     getState();                   // determine next PROCEED state
};

emlAgent theemlAgent;              // the one and only instance of emlAgent

MARKSOURCE(galemlah);

acthSynthesis *                    // new session-specific structure
emlAgent::newSynthesis(            // instantiate Synthesis class
acthSession *ses)                  // passed to acthSynthesis's constructor
{
     rootEmailSynth *synPtr=NULL;

     if (ses->urlargc() > 0 && eUseHtml) {
          if (sameas(ses->urlargv(0),"att")) {
               synPtr=new downloadSynthesis(ses);
          }
          else if (sameas(ses->urlargv(0),"delete")) {
               synPtr=new deleteSynthesis(ses);
          }
          else if (sameas(ses->urlargv(0),"file")) {
               synPtr=new fileSynthesis(ses);
          }
          else if (sameas(ses->urlargv(0),"list")) {
               synPtr=new listSynthesis(ses);
          }
          else if (sameas(ses->urlargv(0),"pref")) {
               synPtr=new prefSynthesis(ses);
          }
          else if (sameas(ses->urlargv(0),"send")) {
               synPtr=new sendSynthesis(ses);
          }
          else if (sameas(ses->urlargv(0),"forward")) {
               synPtr=new forwardSynthesis(ses);
          }
          else if (sameas(ses->urlargv(0),"view")) {
               synPtr=new viewSynthesis(ses);
          }
          else if (sameas(ses->urlargv(0),"write")) {
               synPtr=new writeSynthesis(ses);
          }
     }

     if (eUseJava
      && (ses->urlargc() == 1 && (sameas(ses->urlargv(0),"email.htm") // used by Java
       || sameas(ses->urlargv(0),"pop.htm")
       || sameas(ses->urlargv(0),"ul.htm")))) {
          return(new emlSynthesis(ses));
     }
     else if (eUseHtml && (ses->urlargc() == 0 || (ses->urlargc() == 1     // default "email" URL
      && (samend(ses->urlargv(0),".htm")
      || samend(ses->urlargv(0),".html"))))) {
          synPtr=new rootEmailSynth(ses);
     }
     if (synPtr == NULL) {  // if everything falls through, pass to Java
          return(new emlSynthesis(ses));
     }
     return(synPtr);
}

ACTHCODE
rootEmailSynth::proceed()          // handles default /email URL
{
     ACTHCODE retval=ACTHMORE;
     LONG prefs;

     if ((m_usrPtr=ses->getUser()) == NULL) {
          return(ACTHNOANON);
     }

     if ((strchr(ses->urlsfx(),'.')) == NULL) {
          if (ses->forceDir()) {
               return(ACTHDONE);
          }
     }
     if (m_firstTime) {
          prefs=getWebPrefs(m_usrPtr->userid());
          GETINPUT("type");
          if (strInpBuf[0] != '\0') {
              if (sameas(strInpBuf,"html set")) {
                    prefs|=EPREF_TYPE_HTML;
                    prefs&=~EPREF_TYPE_JAVA;
              }
              else if (eUseJava && sameas(strInpBuf,"java")) {
                    return(proceedJava());
              }
              else if (eUseJava && sameas(strInpBuf,"java set")) {
                    prefs|=EPREF_TYPE_JAVA;
                    prefs&=~EPREF_TYPE_HTML;
                    setWebPrefs(m_usrPtr->userid(),prefs);
                    return(proceedJava());
              }
          }
          else if (eUseJava && ses->urlargc() == 0 && prefs&EPREF_TYPE_JAVA) {
               return (proceedJava());
          }
          else if (eUseJava && ses->urlargc() == 0 && iPreference == PREF_JAVA) {
               return (proceedJava());
          }
          GETINPUT("useframes");
          if (prefs&EPREF_USEFRAMES) {
               m_usingFrames=TRUE;
          }
          if (strInpBuf[0] != '\0') {
               if (sameas(strInpBuf,"0")) {
                    m_usingFrames=FALSE;
               }
               else if (sameas(strInpBuf,"1")) {
                    m_usingFrames=TRUE;
               }
               else if (sameas(strInpBuf,"~")) {
                    if (!(prefs&EPREF_USEFRAMES)) {
                         m_usingFrames=TRUE;
                    }
               }
               else if (sameas(strInpBuf,"0 set")) {
                    prefs&=~EPREF_USEFRAMES;
                    prefs|=EPREF_NOFRAMES;
                    m_usingFrames=FALSE;
               }
               else if (sameas(strInpBuf,"1 set")) {
                    m_usingFrames=TRUE;
                    prefs|=EPREF_USEFRAMES;
                    prefs&=~EPREF_NOFRAMES;
               }
               else if (sameas(strInpBuf,"~ set")) {
                    if (!(prefs&EPREF_USEFRAMES)) {
                         m_usingFrames=TRUE;
                         prefs|=EPREF_USEFRAMES;
                         prefs&=~EPREF_NOFRAMES;
                    }
                    else {
                         m_usingFrames=FALSE;
                         prefs&=~EPREF_USEFRAMES;
                         prefs|=EPREF_NOFRAMES;
                    }
              }
          }
          else if (!(prefs&EPREF_NOFRAMES) && !(prefs&EPREF_USEFRAMES) &&
           bUseFrames) {
               m_usingFrames=TRUE;
          }
          if (!userAcc()) {        // boot them out and don't save prefs if
               return(ACTHFORBID); // they don't have HTML access
          }
          if (m_usingFrames) {
               setCookie(FRAMECOOKIE,"1",NULL,NULL,NULL,FALSE,ses);
          }
          else {
               setCookie(FRAMECOOKIE,"0",NULL,NULL,NULL,FALSE,ses);
          }
          m_firstTime=FALSE;
          setWebPrefs(m_usrPtr->userid(),prefs);
     }
     if (m_usingFrames) {
          setEmailTargetTvbs(TRUE);
     }
     else {
          setEmailTargetTvbs(FALSE);
     }

     if (m_dnfPtr == NULL) {
          if (m_usingFrames) {
               m_dnfPtr=dnfCreateHandlerURL(ses,&deffMap,PPFIX);
          }
          else {
               m_dnfPtr=dnfCreateHandlerURL(ses,&defnfMap,PPFIX);
          }
     }
     clearAllDefs();
     initHTMLGMEUser();
     initPrefVariables();
     retval=respDynafile();
     destructHTMLGMEUser();
     return(retval);
}

GMEUSERHANDLE
rootEmailSynth::initGmeUser()
{
     struct usracc *uptr=GetAccPtr(m_usrPtr->userid());
     switch(gmeUserOpen(uptr,&m_gmeuh)) {
     case GMERST:
          if (onsysn(m_usrPtr->userid(),1)) {
               updaccu(uptr);
          }
     case GMEOK:
          LOG2("EML.initGmeUser Open succeeded: this=%08lX h=%lu",this,m_gmeuh);
          return(m_gmeuh);
     default:
          LOG1("EML.initGmeUser Open failed: this=%08lX",this);
          return(NULL);
     }
}

VOID
rootEmailSynth::initHTMLGMEUser()
{
     setmbk(gmeAHmbk);
     usaptr=GetAccPtr(m_usrPtr->userid());
     initGmeUser();
     setUserNum4AH(m_usrPtr->userid());
}

VOID
rootEmailSynth::destructHTMLGMEUser()
{
     rstmbk();
     if (m_gmeuh != NULL) {
          LOG2("EML.destructHTMLGMEUser closing: this=%08lX h=%lu",this,m_gmeuh);
          gmeUserClose(m_gmeuh);
          m_gmeuh=NULL;
     }
     if (m_usrPtr != NULL) {
          resetUserNum4AH(m_usrPtr->userid());
     }
}

VOID
rootEmailSynth::initPrefVariables() // init preference variables
{
     m_qscptr=gmeUserGetQS(m_gmeuh);

     ASSERT(m_qscptr != NULL);

     m_webFlags=getWebPrefs(m_usrPtr->userid());

     if (m_webFlags&EPREF_TYPE_HTML) {
          ePrefType.set("html");
          ePrefTypeHtml.set("CHECKED");
     }
     else if (m_webFlags&EPREF_TYPE_JAVA) {
          ePrefType.set("java");
          ePrefTypeJava.set("CHECKED");
     }
     if (m_webFlags&EPREF_USEFRAMES) {
          ePrefUseFrames.set("CHECKED");
     }
     if (m_webFlags&MPREF_REFLOW) {
          mPrefReflow.set("CHECKED");
     }
     if (m_webFlags&MPREF_QUOTE) {
          mPrefQuote.set("CHECKED");
     }
     if (m_webFlags&MPREF_INCLIST) {
          mPrefIncList.set("CHECKED");
     }
     if (m_qscptr->fwdee[0] != '\0') {
          ASSERT(strlen(m_qscptr->fwdee) <= MAXADR);
          ePrefForwardee.set(m_qscptr->fwdee);
     }
     if (m_qscptr->flags&CLARPL) {
          ePrefClrReply.set("CHECKED");
     }
     if (m_qscptr->flags&FORUM2) {
          ePrefForumTo.set("CHECKED");
     }
}

ACTHCODE
rootEmailSynth::proceedJava()       // proceed with java synthesis
{
     if (m_eSyn == NULL) {
          m_eSyn=new emlSynthesis(ses);
     }
     return(m_eSyn->proceed());
}

ACTHCODE
rootEmailSynth::respDynafile()      // response dynafile
{
     ACTHCODE retval=ACTHMORE;

     if (m_dnfPtr == NULL) {
          return(ACTHDONE);
     }

     if (m_ecPtr->startProc()) {
          do {
               switch(m_dnfPtr->process()) {
               case DNFEND:
                    retval=ACTHDONE;
                    break;
               }
          } while (m_ecPtr->contProc(retval));
     }
     return(retval);
}


ACTHCODE
pureHTMLSynth::proceed()           // pureHTML proceed
{
     ACTHCODE retval=ACTHMORE;
     CHAR *ckPtr;

     if (!eUseHtml) {
          return(ACTHNOTFND);
     }
     else if (!userOK()) {
          return(ACTHNOANON);
     }
     else if (!userAcc()) {
          retval=ACTHFORBID;
     }
     else {
          if (strchr(ses->urlsfx(),'.') == NULL) {
               if (ses->forceDir()) {
                    return(ACTHDONE);
               }
          }
          if ((ckPtr=getCookie(FRAMECOOKIE,ses)) != NULL) {
               if(sameas(ckPtr,"1")) {
                    setEmailTargetTvbs(TRUE);
               }
               else {
                    setEmailTargetTvbs(FALSE);
               }
          }
          else if ((getWebPrefs(m_usrPtr->userid()))&EPREF_USEFRAMES) {
               setEmailTargetTvbs(TRUE);
          }
          else {
               setEmailTargetTvbs(FALSE);
          }
          clearAllDefs();
          initHTMLGMEUser();
          initPrefVariables();
          getTemplates();
     }
     return(retval);
}

VOID
pureHTMLSynth::profaneBody()
{
     INT len=strlen(pfnptr);
     if (len > PFNWORD) {
          pfnptr[PFNWORD]='\0';
     }
     prfmsg(ERPRFBT,pfnptr);
     erprfbt=stpans(prfbuf);
}

VOID
pureHTMLSynth::profaneTopic()
{
     INT len=strlen(pfnptr);
     if (len > PFNWORD) {
          pfnptr[PFNWORD]='\0';
     }
     prfmsg(ERPRFTP,pfnptr);
     erprftp=stpans(prfbuf);
}

VOID
pureHTMLSynth::removeSubString(     // in-place remove sub string
CHAR *string,                       // string to operate on
INT idx,                            // idx in string to start at
INT len)                            // length to remove
{
     ASSERT(len != 0);
     ASSERT(idx+len < strlen(string)+1);

     CHAR *ptr=string+idx+len;
     CHAR *prevptr=string+idx;

     while (*ptr != '\0') {
          *prevptr++=*ptr++;
     }
     *prevptr='\0';
}

VOID
pureHTMLSynth::insert(             // insert new string into old string
CHAR *orgString,                   // original string
CHAR *subString,                   // string to add
INT idx,                           // index in string to add
INT bufSiz)                        // size of original string
{
     ASSERT(orgString != NULL && subString != NULL);

     if (strlen(orgString)+strlen(subString) >= bufSiz) {
          return;
     }

     CHAR *wrkBuf= new CHAR[bufSiz];
     setmem(wrkBuf,bufSiz,0);
     if (idx > 0) {
          stlcpy(wrkBuf,orgString,bufSiz);
          wrkBuf[idx]='\0';
     }
     stlcat(wrkBuf,subString,bufSiz);
     if (idx > 0) {
          stlcat(wrkBuf,orgString+idx,bufSiz);
     }
     else {
          stlcat(wrkBuf,orgString,bufSiz);
     }
     stlcpy(orgString,wrkBuf,bufSiz);

     delete [] wrkBuf;
}

GBOOL
pureHTMLSynth::format4Send()       // format message so GME doesn't choke
{
     CHAR * OutBuf=new CHAR[TXTLEN];
     CHAR * pOut=OutBuf;
     CHAR const * pIn=m_paramText.c_str();
     bool more=true;

     // copy the input into the output buffer
     do {

          // find end/length of current line
          INT LineLen;
          CHAR const * pEOL=::strchr(pIn,'\r');
          if (pEOL == NULL) {
               LineLen=::strlen(pIn);
          }
          else {
               LineLen=(INT)(pEOL-pIn);
               if (*++pEOL == '\n') {
                    ++pEOL;
               }
          }

          // remove trailing whitespace
          while (LineLen > 0 && isspace(pIn[LineLen-1])) {
               --LineLen;
          }

          // process current line
          CHAR const * pNext=pEOL;      // point to start of next line
          if (::isquoted(pIn) || LineLen <= MAXLINSIZ) {
               more=(pEOL != NULL);
          }
          else {                   // word-wrap non-quoted long lines

               // find last space on line
               pEOL=pIn+MAXLINSIZ;
               while (!isspace(*pEOL) && pEOL > pIn) {
                    --pEOL;
               }

               // do word wrapping
               if (isspace(*pEOL)) {
                    LineLen=(INT)(pEOL-pIn);
                    pNext=pEOL+1;

                    // remove trailing whitespace
                    while (LineLen > 0 && isspace(pIn[LineLen-1])) {
                         --LineLen;
                    }
               }
               else {                   // no spaces, just chop it
                    LineLen=MAXLINSIZ;
                    pNext=pIn+MAXLINSIZ;
               }
          }

          // account for output buffer room
          INT OutUsed=(INT)(pOut-OutBuf);
          INT OutAvailable=TXTLEN-OutUsed;
          INT OutRequired=LineLen+2;         // +2 for '\r' & '\0'
          if (OutRequired > OutAvailable) {
               more=false;
               LineLen=OutAvailable-2;
          }

          // add current line to output buffer
          *pOut++='\r';
          if (LineLen != 0) {
               ::memcpy(pOut,pIn,LineLen);
               pOut+=LineLen;
          }

          // point to next line
          ASSERT(!more || pNext != NULL);
          pIn=pNext;
     } while (more);

     // terminate output
     *pOut='\0';

     // remove any trailing garbage (usually blank lines)
     --pOut;
     while (pOut >= OutBuf && *pOut <= ' ') {
          *pOut--='\0';
     }

     m_paramText=OutBuf;
     delete [] OutBuf;
     return(true);
}

ACTHCODE
pureHTMLSynth::dynaWriteResp()     // dynafile "/write" response
{
     ACTHCODE retval=ACTHMORE;

     if (m_ecPtr->startProc()) {
          do {
              switch(m_dnfPtr->process()) {
               case BODYTEXT2:
               case BODYTEXT4:
               case BODYTEXT5:
               case BODYTEXT6:
               case BODYTEXT7:
                    if (m_sendFlags != 0 && !(m_sendFlags&SUBMIT_SEND) &&
                     !(m_sendFlags&SUBMIT_CANCEL)
                     && m_writeFlags&SUBMIT_NOTEXT) {
                         //bout << " ";
                         break;
                    }
                    if (m_paramText.length() != 0) {
                         if (m_sendFlags&SUBMIT_ATTACH) {
                              bout << cgiEncode(m_paramText.c_str());
                         }
                         else {
                              bout << cgiDecode(m_paramText.c_str());
                         }
                    }
                    else if (m_webFlags&MPREF_QUOTE
                     || m_writeFlags&WRITE_QUOTE || m_writeFlags&WRITE_KEEPFMT) {
                         bout << m_orgText.c_str();
                    }
                    else {
                         //bout << " ";
                    }
                    break;
               case DNFEND:
                    retval=ACTHDONE;
                    break;
               }
          } while (m_ecPtr->contProc(retval));
     }
     return(retval);
}


ACTHCODE
pureHTMLSynth::dynaReadResp()      // read/view response dynafile
{
     ACTHCODE retval=ACTHMORE;

     setMoreLowTvb(m_moreLow);
     setMoreHiTvb(m_moreHi);

     if (m_ecPtr->startProc()) {
          do {
               switch(m_dnfPtr->process()) {
               case BODYTEXT:
               case BODYTEXT3:
                    if (!(m_readFlags&READ_NOTEXT)) {
                         bout << m_sMsgTxt.c_str();
                    }
                    break;
               case DNFEND:
                    retval=ACTHDONE;
                    break;
               }
          } while (m_ecPtr->contProc(retval));
     }
     return(retval);
}

GBOOL
pureHTMLSynth::getCompositionParams()  // get common write parameters
{
     GETINPUT("type");
     if (strInpBuf[0] != '\0') {
          if (sameas(strInpBuf,"new")) {
               m_writeFlags|=WRITE_NEW;
          }
          else if (sameas(strInpBuf,"reply")) {
               m_writeFlags|=WRITE_REPLY;
          }
          else if (sameas(strInpBuf,"resend")) {
               m_writeFlags|=WRITE_RESEND;
          }
          else {
               m_writeFlags|=WRITE_NEW;
          }
     }
     else {
          m_writeFlags|=WRITE_NEW;
     }
     GETINPUT("orgforid");
     if (strInpBuf[0] != '\0' && alldgs(strInpBuf)) {
          m_orgForId=::atoul(strInpBuf);
          if (m_orgForId != EMLID && !fidxst(m_orgForId)) {
               badParam("orgforid");
               return(FALSE);
          }
     }
     else if (m_writeFlags&(WRITE_REPLY|WRITE_RESEND)) {
          badParam("orgforid");
          return(FALSE);
     }
     GETINPUT("orgmsgid");
     if (strInpBuf[0] != '\0' && alldgs(strInpBuf)) {
          m_orgMsgId=::atoul(strInpBuf);
     }
     else if (m_writeFlags&(WRITE_REPLY|WRITE_RESEND)) {
          badParam("orgmsgid");
          return(FALSE);
     }
     GETINPUT("override");
     if (strInpBuf[0] != '\0') {
          if (samein("quote",strInpBuf)) {
               if (paramOK("quote") && m_writeFlags&WRITE_REPLY) {
                    m_writeFlags|=WRITE_QUOTE;
               }
               else if (paramOK("quote set") && m_writeFlags&WRITE_REPLY) {
                    m_writeFlags|=WRITE_QUOTE;
                    updatePref(MPREF_QUOTE,TRUE);
               }
          }
          if (samein("inclist",strInpBuf)) {
               if (paramOK("inclist")) {
                    m_writeFlags|=WRITE_INCLIST;
               }
               else if (paramOK("inclist set")) {
                    m_writeFlags|=WRITE_INCLIST;
                    updatePref(MPREF_INCLIST,TRUE);
               }
          }
     }
     if (paramOK("toall") && m_writeFlags&WRITE_REPLY) {
          m_writeFlags|=WRITE_TOALL;
     }
     GETINPUT("forum");
     if (strInpBuf[0] != '\0' && alldgs(strInpBuf)) {
          m_forum=::atoul(strInpBuf);
          if (m_forum != EMLID && !fidxst(m_forum)) {
               badParam("forum");
               return(FALSE);
          }
     }
     GETINPUT("forumname");
     if (strInpBuf[0] != '\0') {
          m_forumName=strInpBuf;
          if (!paramOK("forum")) {
               m_forum=getfid(m_forumName.c_str());
               if (m_forum != EMLID && !fidxst(m_forum)) {
                    badParam("forumname");
                    return(FALSE);
               }
          }
     }
     GETINPUT("to");
     if (strInpBuf[0] != '\0') {
          m_toAdr=strInpBuf;
     }
     GETINPUT("topic");
     if (strInpBuf[0] != '\0') {
          m_topic=strInpBuf;
     }
     if (paramOK("pri")) {
          m_writeFlags|=WRITE_PRI;
     }
     if (paramOK("rr")) {
          m_writeFlags|=WRITE_RR;
     }
     GETINPUT("cclist");
     if (strInpBuf[0] != '\0') {
          m_cclist=strInpBuf;
          /*if (strInpBuf[strlen(strInpBuf)-1] != ';') {
               m_cclist+=";";
          } */
     }
     GETINPUT("text");
     if (strInpBuf[0] != '\0') {
          m_paramText=strInpBuf;
     }
     if (paramOK("keepformat")) {
          m_writeFlags|=WRITE_KEEPFMT;
     }
     GETINPUT("tmpid");
     if (strInpBuf[0] != '\0' && alldgs(strInpBuf)) {
          m_tmpid=::atoul(strInpBuf);
          GETINPUT("attname");
          if (strInpBuf[0] != '\0') {
               m_attachName=mkdosn(strInpBuf);
          }
     }
     if (paramOK("notext")) {
          m_sendFlags|=SUBMIT_NOTEXT;
     }
     return(TRUE);
}

VOID
pureHTMLSynth::badParam(
const CHAR *param)
{
     ASSERT(param != NULL);

     m_ecPtr->m_merr_code=ERR_PARAMISSING;
     clrprf();
     prfmsg(ERPMISS,param);
     m_ecPtr->m_merr_message=stpans(prfbuf);
     clrprf();
}

VOID
pureHTMLSynth::updatePref(         // update a preference value
LONG pref,
GBOOL on)
{
     LONG curPrefs=getWebPrefs(ses->getUser()->userid());

     if (on) {
          curPrefs|=pref;
     }
     else {
          curPrefs&=~pref;
     }
     setWebPrefs(ses->getUser()->userid(),curPrefs);
}

VOID
pureHTMLSynth::getTemplates()       // reads in template URLs/files
{
     ses->param("onsuccess",m_successTemplate,URLSIZ);
     ses->param("onerror",m_errorTemplate,URLSIZ);
     m_succTempPtr=m_successTemplate;
     m_errTempPtr=m_errorTemplate;
}

VOID
pureHTMLSynth::initSuccVariables() // initialize variables on success
{
     if (m_dnfPtr != NULL) {
          dnfSetTemplateTvb(m_dnfPtr);
     }
     if (m_mhdrptr != NULL) {
          setUpMessageHeaderDefs(m_mhdrptr);
     }
}

VOID
pureHTMLSynth::initVars()          // init appropriate variables
{
     if (m_ecPtr->m_merr_code >= GMEOK && m_ecPtr->m_merr_code <= GMEAFWD) {
          initSuccVariables();
     }
     else {
          initErrVariables();
     }
}

VOID
pureHTMLSynth::initErrVariables()  // init error variables
{
     mMsgId.set("%d",m_mhdr_msgid);
     if (m_dnfPtr != NULL) {
          dnfSetTemplateTvb(m_dnfPtr);
     }
     setErrorCode(m_ecPtr->m_merr_code);
     setErrorMessage(m_ecPtr->m_merr_message.c_str());
}

ULONG
pureHTMLSynth::validateMsgId(      // validate msg id
ULONG msgid)
{
     if (msgid > (himsgid()+1)) {
          return(himsgid()+1);
     }
     return(msgid);
}

VOID
pureHTMLSynth::initCompositionVbs()// initialize variables on message compose
{
     if (m_dnfPtr != NULL) {
          dnfSetTemplateTvb(m_dnfPtr);
     }
     mForId.set("%d",m_forum);
     const CHAR *fnam=NULL;
     if (m_forum != 0) {
          fnam=getfnm(m_forum);
     }
     if (fnam != NULL) {
          mForName.set(fnam);
     }
     if (m_forum == 0) {
          mForDisp.set(dispEml);
     }
     else if (fnam != NULL) {
          prfmsg(DISPFOR,fnam);
          mForDisp.set(stpans(prfbuf));
          clrprf();
     }
     mTo.set(m_toAdr.c_str());
     mTopic.set(m_topic.c_str());
     if (m_writeFlags&WRITE_PRI) {
          mPriority.set(priDsp);
     }
     if (m_writeFlags&WRITE_RR) {
          mReceipt.set(rrrDsp);
     }
     if (m_writeFlags&WRITE_PRI && m_forum == 0) {
          mPriImage.set(imgPriy);
     }
     else {
          mPriImage.set(imgPrin);
     }
     if (m_writeFlags&WRITE_RR && m_forum == 0) {
          mRRRImage.set(imgrrry);
     }
     else {
          mRRRImage.set(imgrrrn);
     }

     if (m_writeFlags&(WRITE_NEW|WRITE_RESEND)) {
          mWriteType.set("new");
     }
     else if (m_writeFlags&WRITE_REPLY) {
          mWriteType.set("reply");
     }
     mWriteOrgForId.set("%d",m_orgForId);
     mWriteOrgMsgId.set("%d",m_orgMsgId);
     if (m_writeFlags&WRITE_PRI) {
          mWritePriChk.set("checked");
     }
     if (m_writeFlags&WRITE_RR) {
          mWriteRRRChk.set("checked");
     }
     mWriteCCList.set(m_cclist.c_str());
     mWriteTmpid.set(spr("%lu",m_tmpid));  // insert initial tmpid value here
     if (m_writeFlags&WRITE_INCLIST || m_webFlags&MPREF_INCLIST) {
          mWriteIncList.set("checked");
     }
     mAttName.set(m_attachName.c_str());
     if (m_attachName.length() == 0) {
          mAttPfx.set(attFmt);
          mAttImage.set(imgAttn);
          mWriteAttFlag.set("0");
     }
     else {
          mAttImage.set(imgAtty);
          mWriteAttFlag.set("1");
     }
}

VOID
pureHTMLSynth::sendTemplates()     // handle send custome template stuff
{
     GBOOL foundSuccess=FALSE;
     GBOOL foundError=FALSE;

     if (m_sendFlags != 0) {
          CHAR *truncPtr=NULL;
          INT fndidx=0;

          for (INT i=0; i <= SUBMITARRSIZ; i++) {
               if (m_sendFlags&subiarr[i]) {
                    if (m_successTemplate[0] != '\0'
                     && (fndidx=findstg(submitArr[i],m_successTemplate)) != 0) {
                         if (m_successTemplate[fndidx+1] != '\0') {
                              m_succTempPtr=&(m_successTemplate[fndidx+1]);
                              truncPtr=strchr(m_succTempPtr,',');
                              if (truncPtr != NULL) {
                                   *truncPtr='\0';
                              }
                              foundSuccess=TRUE;
                         }
                    }
                    if (m_errorTemplate[0] != '\0'
                     && (fndidx=findstg(submitArr[i],m_errorTemplate)) != 0) {
                         if (m_errorTemplate[fndidx+1] != '\0') {
                              m_errTempPtr=&(m_errorTemplate[fndidx+1]);
                              truncPtr=strchr(m_errTempPtr,',');
                              if (truncPtr != NULL) {
                                   *truncPtr='\0';
                              }
                              foundError=TRUE;
                         }
                    }
                    break;
               }
          }
          if (!foundSuccess) {
               m_successTemplate[0]='\0';
               m_succTempPtr=m_successTemplate;
          }
          if (!foundError) {
               m_errorTemplate[0]='\0';
               m_errTempPtr=m_errorTemplate;
          }
     }
}

ACTHCODE
pureHTMLSynth::handleTemplates( // handle template response
dnfMap *succMap,                   // success map
dnfMap *errMap,                    // error map
const CHAR * baseDir,              // base directory
const CHAR *synthDir)              // synthesis directory
{
     ACTHCODE retval=ACTHMORE;
     string theDir;

     sendTemplates();

     if (m_ecPtr->m_merr_code >= GMEOK && m_ecPtr->m_merr_code <= GMEAFWD) {
          if (*m_succTempPtr != '\0') {
               if (isURLTemplate(m_succTempPtr)) {
                    ses->redirect(m_succTempPtr);
                    return(ACTHDONE);
               }
               else if (succMap != NULL) {
                    theDir=baseDir;
                    theDir+=synthDir;
                    theDir+=m_succTempPtr;
                    succMap=dnfGetMap(succMap,theDir.c_str());
                    if (m_dnfPtr != NULL) {
                         delete m_dnfPtr;
                         m_dnfPtr=NULL;
                    }
                    m_dnfPtr=new dnfHandler(*succMap,bout);
               }
          }
          else if (succMap != NULL) {
               m_dnfPtr=dnfCreateHandlerURL(ses,succMap,baseDir);
          }
     }
     else {
          if (*m_errTempPtr != '\0') {
               if (isURLTemplate(m_errTempPtr)) {
                    ses->redirect(m_errTempPtr);
                    return(ACTHDONE);
               }
               else if (errMap != NULL) {
                    theDir=baseDir;
                    theDir+=synthDir;
                    theDir+=m_errTempPtr;
                    errMap=dnfGetMap(errMap,theDir.c_str());
                    if (m_dnfPtr != NULL) {
                         delete m_dnfPtr;
                         m_dnfPtr=NULL;
                    }
                    m_dnfPtr=new dnfHandler(*errMap,bout);
               }
          }
          else if (errMap != NULL) {
               if (m_dnfPtr != NULL) {
                    delete m_dnfPtr;
                    m_dnfPtr=NULL;
               }
               m_dnfPtr=new dnfHandler(*errMap,bout);
          }
     }
     if (m_dnfPtr == NULL) {
          return(ACTHNOTFND);
     }
     return(retval);
}

INT
pureHTMLSynth::SetAutoFwd(         // set new auto-forwardee
CHAR* newfwde)                     // new address to use
{
     INT rc;

     ASSERT(m_qscptr != NULL);
     ASSERT(newfwde != NULL);
     if (*newfwde == '\0') {
          setmem(m_qscptr->fwdee,MAXADR,0);
          return(VALYES);
     }
     if (strlen(newfwde) >= MAXADR || isdlst(newfwde) || isforum(newfwde)) {
          return(VALNO);
     }
     rc=valadr(mywrkarea,usaptr->userid,newfwde,EMLID);
     if (rc == VALCRD) {
          rc=VALYES;
     }
     if (rc == VALYES) {
          m_qscptr->fwdate=today();
          stlcpy(m_qscptr->fwdee,newfwde,MAXADR);
     }
     return(rc);
}


ACTHCODE
downloadSynthesis::proceed()       // entry point for download synth
{
     ACTHCODE retval=pureHTMLSynth::proceed();

     if (retval == ACTHMORE ) {
          if (ses->urlargc() >= 2 && alldgs(ses->urlargv(1))) {
               switch (m_ahState) {
               case PROCEED_AH_REQUEST:
                    m_mhdr_msgid=validateMsgId(::atoul(ses->urlargv(1)));
                    inictx(mywrkarea,m_usrPtr->userid()
                          ,ESQTOU,EMLID,m_mhdr_msgid,0);
                    m_ahState=PROCEED_AH_DOWNLOAD;
                    break;
               case PROCEED_AH_DOWNLOAD:
                    m_ecPtr->m_merr_code=readmsg(mywrkarea,m_mhdrptr,txtbuf);
                    switch (m_ecPtr->m_merr_code) {
                    case GMEAGAIN:
                         break;
                    case GMEOK:
                         m_ecPtr->m_merr_code=tagatt(mywrkarea
                                                    ,m_mhdrptr,tagbuf);
                         if (m_ecPtr->m_merr_code == GMEOK) {
                              if (gdlstart(m_usrPtr->userid(),tagbuf)) {

                                   // set Content-Length and -Type headers
                                   string pth=dlname(m_mhdrptr);
                                   struct ffblk fb;
                                   fndfile(&fb,pth.c_str(),0);
                                   ostrstream ost;
                                   ost << "Content-Length: " << fb.ff_fsize
                                       << ends;
                                   ses->headerField(ost.str());
                                   ost.rdbuf()->freeze(0);
                                   CHAR ext[GCMAXEXT+1];
                                   fileparts(GCPART_EXTN,pth.c_str()
                                            ,ext,GCMAXEXT+1);
                                   ses->contypeFext(ext);

                                   // send the file
                                   ses->sndfile(pth.c_str());
                                   m_doDl=TRUE;
                                   retval=ACTHDONE;
                                   break;
                              }
                              else {
                                   m_ecPtr->m_merr_code=GMECRD;
                              }
                         } // intentional fall through to handleError()
                    default:
                         ::handleError(m_ecPtr,OP_GENERIC,NULL);
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }
                    break;
               case PROCEED_AH_RESPONSE:
                    initVars();
                    if (m_dnfPtr == NULL) {
                         retval=handleTemplates(NULL,&attErrMap,PPFIX,"att/");
                    }
                    else {
                         retval=respDynafile();
                    }
                    break;
               }
          }
          else {
               retval=ACTHNOTFND;
          }
          destructHTMLGMEUser();
     }
     return(retval);
}

VOID
downloadSynthesis::abort()         // should be called if request died
{
     if (m_doDl) {
          gdlabt(m_usrPtr->userid(),tagbuf);
          m_doDl=FALSE;
     }
}


ACTHCODE
deleteSynthesis::proceed()         // delete request entry point
{
     ACTHCODE retval=pureHTMLSynth::proceed();

     if (retval == ACTHMORE ) {
          switch (m_ahState) {
          case PROCEED_AH_REQUEST:
               if (m_delCount < ses->nparam()) {
                    CHAR namBuf[NAMESIZ];
                    ses->param(m_delCount,namBuf,NAMESIZ,strInpBuf,STRINPSIZ);
                    if (sameas(namBuf,"id") && alldgs(strInpBuf)) {
                         m_savMsgId=validateMsgId(::atoul(strInpBuf));
                         ASSERT(gmerqopn(mywrkarea));
                         m_mhdr_msgid=m_savMsgId;
                         inictx(mywrkarea,m_usrPtr->userid(),ESQTOU,EMLID,
                          m_savMsgId,0);
                         m_ahState=PROCEED_AH_DELETE;
                    }
                    ++m_delCount;
               }
               else {
                    m_ahState=PROCEED_AH_RESPONSE;
               }
               break;
          case PROCEED_AH_DELETE:
               switch (m_ecPtr->m_merr_code=delmsg(mywrkarea)) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    m_ahState=PROCEED_AH_REQUEST;
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
               }
               break;
          case PROCEED_AH_RESPONSE:
               if (m_dnfPtr == NULL) {
                    retval=handleTemplates(&deleteSuccMap,
                     &deleteErrMap,PPFIX,"delete/");
               }
               else {
                    initVars();
                    retval=respDynafile();
               }
               break;
          }
          destructHTMLGMEUser();
     }
     return(retval);
}

ACTHCODE
fileSynthesis::proceed()           // generic file request entry point
{
     ACTHCODE retval=pureHTMLSynth::proceed();

     if (retval == ACTHMORE ) {
          if (m_dnfPtr == NULL) {
                m_dnfPtr=dnfCreateHandlerURL(ses,&fileMap,PPFIX);
                if (m_dnfPtr == NULL) {
                     retval=ACTHNOTFND;
                }
                else {
                     CHAR fileExtension[GCMAXEXT+1];
                     const CHAR* fileName=m_dnfPtr->getMap().getFile();
                     fileparts(GCPART_EXTN,fileName,fileExtension,GCMAXEXT+1);
                     ses->contypeFext(fileExtension);
                }
          }
          else {
               dnfSetTemplateTvb(m_dnfPtr);
               retval=respDynafile();
          }
          destructHTMLGMEUser();
     }
     return(retval);
}

ACTHCODE
forwardSynthesis::proceed()        // forward request entry point
{
     INT adrCode,attCode,priCode;  // validation codes for address, etc.
     ACTHCODE retval=pureHTMLSynth::proceed();

     if (retval == ACTHMORE) {
          switch (m_ahState) {
          case PROCEED_AH_REQUEST:
               GETINPUT("id");
               if (strInpBuf[0] == '\0' || !alldgs(strInpBuf)) {
                   retval=ACTHFORBID;
                   break;
               }
               m_savMsgId=validateMsgId(::atoul(strInpBuf));
               if (paramOK("orgdelete")) {
                   m_bDeleteMsg=TRUE;
               }
               ses->param("comment",m_commentBufPtr,TXTLEN);
               ses->param("to",m_holdid,MAXADR);
               inictx(mywrkarea,m_usrPtr->userid(),ESQTOU,EMLID,m_savMsgId,0);
               m_ahState=PROCEED_AH_READMSG;
               break;
          case PROCEED_AH_READMSG:
               switch ((m_ecPtr->m_merr_code=readmsg(mywrkarea,m_mhdrptr,txtbuf))) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    m_ahState=PROCEED_AH_VALIDATE;
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_VALIDATE:

               // handle copy vs. forward
               if (m_bDeleteMsg) {   // forwarding, use vfwd*()
                    adrCode=vfwdadr(mywrkarea,m_usrPtr->userid(),m_holdid,EMLID);
                    attCode=vfwdatt(mywrkarea,m_usrPtr->userid(),m_holdid,EMLID);
                    priCode=vfwdpri(mywrkarea,m_usrPtr->userid(),m_holdid,EMLID);
                    m_ahState=PROCEED_AH_FORWARD;
               }
               else {              // copying, use val*()
                    adrCode=valadr(mywrkarea,m_usrPtr->userid(),m_holdid,EMLID);
                    attCode=valatt(mywrkarea,m_usrPtr->userid(),m_holdid,EMLID);
                    priCode=valpri(mywrkarea,m_usrPtr->userid(),m_holdid,EMLID);
                    m_ahState=PROCEED_AH_COPYMSG;
               }

               // validate destination address
               if (adrCode != VALYES) {
                    m_ecPtr->m_merr_code=adrCode;
                    ::handleError(m_ecPtr,OP_VALIDATION,valadress);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }

               // validate attachment
               if ((m_mhdrptr->flags&FILATT) && attCode != VALYES) {
                    m_ecPtr->m_merr_code=attCode;
                    ::handleError(m_ecPtr,OP_VALIDATION,valattach);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }

               // deal with priority
               if ((m_mhdrptr->flags&PRIMSG) && priCode != VALYES) {
                    m_mhdrptr->flags&=~PRIMSG;
               }

               // add comments if any
               if (m_commentBufPtr[0] != '\0') {

                    // check for profanity
                    USHORT tmpfid=(isforum(m_holdid) ? getAdrForID(m_holdid)
                                                   : EMLID);
                    if (pfnerr(m_usrPtr->userid(),m_commentBufPtr,tmpfid)) {
                         m_ecPtr->m_merr_code=ERR_PROFANBDY;
                         profaneBody();
                         m_ecPtr->m_merr_message=erprfbt;
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }

                    // prepend to text
                    AddComment(txtbuf,m_commentBufPtr,txtbuf2,TXTLEN
                              ,ses->getUser()->userid());
                    m_sMsgTxt=txtbuf2;
               }
               else {
                    m_sMsgTxt=txtbuf;
               }

               memmove(m_wrkHeader,m_mhdrptr,sizeof(struct message));
               m_mhdrptr->forum=EMLID;
               stlcpy(m_mhdrptr->to,m_holdid,MAXADR);
               break;
          case PROCEED_AH_FORWARD:
               m_ecPtr->m_merr_code=fwdmsg(mywrkarea,m_mhdrptr,m_sMsgTxt.c_str());
               if (m_ecPtr->m_merr_code > GMEAGAIN) {
                    m_ahState=PROCEED_AH_RESPONSE;
               }
               else if (m_ecPtr->m_merr_code < GMEAGAIN) {
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
               }
               break;

          case PROCEED_AH_COPYMSG:
               m_ecPtr->m_merr_code=copymsg(mywrkarea,m_mhdrptr,m_sMsgTxt.c_str());
               if (m_ecPtr->m_merr_code > GMEAGAIN) {
                    m_ahState=PROCEED_AH_MARKREAD;
               }
               else if (m_ecPtr->m_merr_code < GMEAGAIN) {
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
               }
               break;

          case PROCEED_AH_MARKREAD:
               m_ecPtr->m_merr_code=markreadf(mywrkarea,m_wrkHeader,txtbuf);
               if (m_ecPtr->m_merr_code > GMEAGAIN) {
                    m_ahState=PROCEED_AH_RESPONSE;
               }
               else if (m_ecPtr->m_merr_code < GMEAGAIN) {
                    m_ahState=PROCEED_AH_RESPONSE;
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
               }
               break;

          case PROCEED_AH_RESPONSE:
               if (m_dnfPtr == NULL) {
                    retval=handleTemplates(&fwdSuccMap,&fwdErrMap,PPFIX,
                     "forward/");
               }
               else {
                    mWriteOrgMsgId.set("%d",m_savMsgId);
                    initVars();
                    retval=respDynafile();
               }
               break;
          }
          destructHTMLGMEUser();
     }
     return(retval);
}

ACTHCODE
listSynthesis::proceed()           // list request entry point
{
     ACTHCODE retval=pureHTMLSynth::proceed();

     if (retval == ACTHMORE ) {
          switch (m_ahState) {
          case PROCEED_AH_REQUEST:
               if (m_dnfPtr == NULL) {
                    m_ahState=PROCEED_AH_QUEUEUP;
                    GETINPUT("order");
                    if (strInpBuf[0] != '\0') {
                         if (sameas(strInpBuf,"descending")) {
                              m_listFlags|=LIST_ORD_DESCEND;
                         }
                         else {
                              m_listFlags|=LIST_ORD_ASCEND;
                         }
                    }
                    else {
                         m_listFlags|=LIST_ORD_ASCEND;
                    }
                    if (paramOK("sent")) {
                         m_listFlags|=LIST_ALL;
                         m_listFlags|=LIST_SENT;
                         if (m_listFlags&LIST_ORD_DESCEND) {
                              m_startMsgId=himsgid()+1;
                         }
                         m_ahState=PROCEED_AH_LISTALL;
                         retval=handleTemplates(&listMap,NULL,PPFIX,LISTURL);
                         break;
                    }
                    if (!paramOK("all")) {
                         GETINPUT("start");
                         if (strInpBuf[0] != '\0') {
                              if (sameas(strInpBuf,"new")) {
                                   m_listFlags|=LIST_NEWMSGS;
                                   m_startMsgId=firstnew(m_usrPtr->userid(),EMLID);
                              }
                              else if (alldgs(strInpBuf)) {
                                   m_startMsgId=validateMsgId(::atoul(strInpBuf));
                              }
                         }
                         GETINPUT("direction");
                         if (strInpBuf[0] != '\0') {
                              if (sameas(strInpBuf,"lt")) {
                                   m_listFlags|=LIST_DIREC_LT;
                              }
                              else if (sameas(strInpBuf,"gt")) {
                                   m_listFlags|=LIST_DIREC_GT;
                              }
                              else if (sameas(strInpBuf,"ge")) {
                                   m_listFlags|=LIST_DIREC_GE;
                              }
                              else if (sameas(strInpBuf,"le")) {
                                   m_listFlags|=LIST_DIREC_LE;
                              }
                         }
                         GETINPUT("count");
                         if (strInpBuf[0] != '\0') {
                              if (alldgs(strInpBuf) && ::atoul(strInpBuf) > 0
                               && ::atoul(strInpBuf) <= iMaxListCount) {
                                   m_count=(INT)::atoul(strInpBuf);
                              }
                              else {
                                   m_count=iDefListCount;
                              }
                         }
                         else {
                              m_count=iDefListCount;
                         }
                    }
                    else {
                         m_listFlags|=LIST_ALL;
                         if (m_listFlags&LIST_ORD_DESCEND) {
                              m_startMsgId=himsgid()+1;
                         }
                         m_ahState=PROCEED_AH_LISTALL;
                         retval=handleTemplates(&listMap,NULL,PPFIX,LISTURL);
                         break;
                    }
                    if (m_dnfPtr != NULL) {
                         delete m_dnfPtr;
                         m_dnfPtr=NULL;
                    }
                    m_dnfPtr=new dnfHandler(emlCycleMap,bout);
               }
               break;
          case PROCEED_AH_LISTALL:
               retval=procAllMsgsInList();
               break;
          case PROCEED_AH_QUEUEUP:
               retval=queueUpMessages();
               if (retval == ACTHDONE) {
                    m_ahState=PROCEED_AH_MOREHI;
                    retval=ACTHMORE;
                    if (!m_mhdrqueue->empty()) {
                         m_lowId=m_mhdrqueue->back()->msgid;
                         m_hiId=m_mhdrqueue->front()->msgid;
                         m_startMsgId=m_mhdrqueue->front()->msgid;
                    }
                    else if (m_mhdrqueue->empty() && m_listFlags&LIST_NEWMSGS) {
                         ++m_startMsgId;
                    }
                    inictx(mywrkarea,m_usrPtr->userid(),(m_listFlags&LIST_SENT)? ESQFRU : ESQTOU,EMLID,m_startMsgId,0);
                    if (m_dnfPtr != NULL) {
                         delete m_dnfPtr;
                         m_dnfPtr=NULL;
                    }
                    retval=handleTemplates(&listMap,NULL,PPFIX,LISTURL);
               }
               break;
          case PROCEED_AH_MOREHI:
               switch ((m_ecPtr->m_merr_code=nextmsg(mywrkarea,m_mhdrptr,
                txtbuf))) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    m_moreHi=TRUE;
                    m_ahState=PROCEED_AH_MORELO;
                    if (m_readSoFar != 0) {
                         m_startMsgId=m_mhdrqueue->back()->msgid;
                    }
                    inictx(mywrkarea,m_usrPtr->userid(),(m_listFlags&LIST_SENT)? ESQFRU : ESQTOU,EMLID, m_startMsgId,0);
                    break;
               case GMENFND:
                    m_moreHi=FALSE;
                    m_ahState=PROCEED_AH_MORELO;
                    if (m_readSoFar != 0) {
                         m_startMsgId=m_mhdrqueue->back()->msgid;
                    }
                    inictx(mywrkarea,m_usrPtr->userid(),(m_listFlags&LIST_SENT)? ESQFRU : ESQTOU,EMLID, m_startMsgId,0);
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_MORELO:
               switch ((m_ecPtr->m_merr_code=prevmsg(mywrkarea,m_mhdrptr,
                txtbuf))) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    m_moreLow=TRUE;
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               case GMENFND:
                    m_ahState=PROCEED_AH_RESPONSE;
                    m_moreLow=FALSE;
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_RESPONSE:
               initListContextVbs();
               retval=outputMessageList();
               break;
          }
          destructHTMLGMEUser();
     }
     return(retval);
}

VOID
listSynthesis::emptyQueue()        // empty message header queue b4 deleting
{
     while (!m_mhdrqueue->empty()) {
          delete m_mhdrqueue->back();
          m_mhdrqueue->pop_back();
     }
}

ACTHCODE
listSynthesis::outputMessageList() // cycle through header structures, set up variables
{
     ACTHCODE retval=ACTHMORE;

     if (m_ecPtr->startProc()) {
          do {
               if (m_mhdrptr != NULL) {
                    initSuccVariables();
               }
               if (m_readSoFar == 0) {
                    setUpNoMessages();
               }
               switch (m_dnfPtr->process()) {
               case DNFROWBEGIN:
                    if (m_mhdrqueue->empty()) {
                         m_dnfPtr->tableDone();
                         break;
                    }
                    if (m_listFlags&LIST_ORD_ASCEND) {
                         m_mhdrptr=m_mhdrqueue->back();
                    }
                    else {
                         m_mhdrptr=m_mhdrqueue->front();
                    }
                    break;
               case DNFROWEND:
                    if (m_mhdrqueue->empty()) {
                         m_dnfPtr->tableDone();
                         break;
                    }
                    if (m_listFlags&LIST_ORD_ASCEND) {
                         delete m_mhdrqueue->back();
                         m_mhdrqueue->pop_back();
                    }
                    else {
                         delete m_mhdrqueue->front();
                         m_mhdrqueue->pop_front();
                    }
                    m_mhdrptr=NULL;
                    break;
               case DNFEND:
                    retval=ACTHDONE;
                    break;
               }
          } while (m_ecPtr->contProc(retval));
     }
     return(retval);
}

ACTHCODE
listSynthesis::procAllMsgsInList() // dump out all messages
{
     ACTHCODE retval=ACTHMORE;

     initListContextVbs();
     if (m_ecPtr->startProc()) {
          do {
               if (m_mhdrptr != NULL) {
                    initSuccVariables();
                    if (m_listFlags&LIST_SENT) {
                       // 'from' param tacked on to msgid let user read msgs From himself.
                       mMsgId.set("%d&from",m_mhdrptr->msgid);
                       mFrom.set(m_mhdrptr->to);
                    }
               }
               if (m_readSoFar == 0 && m_tableDone) {
                    setUpNoMessages();
               }
               switch (m_dnfPtr->process()) {
               case DNFBEGIN:
                    inictx(mywrkarea,m_usrPtr->userid(),(m_listFlags&LIST_SENT)? ESQFRU : ESQTOU,EMLID, m_startMsgId,0);
                    break;
               case DNFROWBEGIN:
                    if (m_doneFlg) {
                         m_dnfPtr->tableDone();
                         m_tableDone=TRUE;
                         break;
                    }
                    if (m_listFlags&LIST_ORD_ASCEND) {
                         switch ((m_ecPtr->m_merr_code=nextmsg(mywrkarea,
                          m_mhdrptr,txtbuf))) {
                         case GMEAGAIN:
                               m_dnfPtr->sayAgain();
                               m_ecPtr->m_needToCycle=TRUE;
                               break;
                         case GMEOK:
                               if (m_mhdrptr->forum != EMLID
                                && !(m_qscptr->flags&FORUM2)) {
                                    m_dnfPtr->sayAgain();
                                    break;
                               }
                               ++m_readSoFar;
                               break;
                         case GMENFND:
                               m_doneFlg=TRUE;
                               m_dnfPtr->sayAgain();
                               break;
                         default:
                               m_doneFlg=TRUE;
                               m_dnfPtr->sayAgain();
                               ::handleError(m_ecPtr,OP_GENERIC,NULL);
                               break;
                         }
                    }
                    else {
                         switch ((m_ecPtr->m_merr_code=prevmsg(mywrkarea,
                          m_mhdrptr,txtbuf))) {
                         case GMEAGAIN:
                               m_dnfPtr->sayAgain();
                               m_ecPtr->m_needToCycle=TRUE;
                               break;
                         case GMEOK:
                               if (m_mhdrptr->forum != EMLID
                                && !(m_qscptr->flags&FORUM2)) {
                                    m_dnfPtr->sayAgain();
                                    break;
                               }
                               ++m_readSoFar;
                               break;
                         case GMENFND:
                               m_doneFlg=TRUE;
                               m_dnfPtr->sayAgain();
                               break;
                         default:
                               m_doneFlg=TRUE;
                               m_dnfPtr->sayAgain();
                               ::handleError(m_ecPtr,OP_GENERIC,NULL);
                               break;
                         }
                    }
                    break;
               case DNFEND:
                    retval=ACTHDONE;
                    break;
               }
          } while (m_ecPtr->contProc(retval));
     }
     return(retval);
}

ACTHCODE
listSynthesis::queueUpMessages()      // stick message headers in queue
{
     ACTHCODE retval=ACTHMORE;

     if (m_ecPtr->startProc()) {
          do {
               switch (m_dnfPtr->process()) {
               case DNFBEGIN:
                    if (m_listFlags&LIST_DIREC_LT) {
                         m_readMethod=prevmsg;
                    }
                    else if (m_listFlags&LIST_DIREC_LE) {
                         m_readMethod=prevmsg;
                         ++m_startMsgId;
                    }
                    else {
                         m_readMethod=nextmsg;
                         if (m_startMsgId > 0 && !(m_listFlags&LIST_NEWMSGS)
                          && !(m_listFlags&LIST_DIREC_GT)) {
                              --m_startMsgId;
                         }
                    }
                    inictx(mywrkarea,m_usrPtr->userid(),(m_listFlags&LIST_SENT)? ESQFRU : ESQTOU,EMLID,m_startMsgId,0);
                    m_msgHdrPtr=new struct message;
                    break;
               case DNFROWBEGIN:
                    switch ((m_ecPtr->m_merr_code=m_readMethod(mywrkarea,
                     m_msgHdrPtr,txtbuf))) {
                    case GMEAGAIN:
                         m_ecPtr->m_needToCycle=TRUE;
                         m_dnfPtr->sayAgain();
                         break;
                    case GMEOK:
                         if (m_msgHdrPtr->forum != EMLID
                          && !(m_qscptr->flags&FORUM2)) {
                              delete m_msgHdrPtr;
                              m_msgHdrPtr=NULL;
                              break;
                         }
                         ++m_readSoFar;
                         if (m_listFlags&LIST_DIREC_LT) {
                               m_mhdrqueue->push_back(m_msgHdrPtr);
                         }
                         else {
                               m_mhdrqueue->push_front(m_msgHdrPtr);
                         }
                         break;
                    case GMENFND:
                         if (m_msgHdrPtr != NULL) {
                              delete m_msgHdrPtr;
                              m_msgHdrPtr=NULL;
                         }
                         m_doneFlg=TRUE;
                         m_ecPtr->m_merr_code=GMEOK; // when generating list, we don't want to error out
                         break;
                    default:
                         if (m_msgHdrPtr != NULL) {
                              delete m_msgHdrPtr;// delete newed struct
                              m_msgHdrPtr=NULL;
                         }
                         m_doneFlg=TRUE;
                         ::handleError(m_ecPtr,OP_GENERIC,NULL);
                         break;
                    }
                    break;
               case DNFROWEND:
                    if (m_readSoFar == m_count || m_doneFlg) {
                         m_dnfPtr->tableDone();
                    }
                    else {
                         m_msgHdrPtr=new struct message;
                    }
                    break;
               case DNFEND:
                    if (m_readSoFar == 0 && m_msgHdrPtr != NULL) {
                         delete m_msgHdrPtr;// no msgs read, delete struct newed in DNFBEGIN
                         m_msgHdrPtr=NULL;
                    }
                    retval=ACTHDONE;
                    break;
               }
          } while (m_ecPtr->contProc(retval));
     }
     return(retval);
}

VOID
listSynthesis::initListContextVbs()// initialize list-specific tvbs
{
     if (m_dnfPtr != NULL) {
          dnfSetTemplateTvb(m_dnfPtr);
     }
     if (!(m_listFlags&LIST_ALL)) {
          mCount.set("%d",m_count);
          if ((m_mhdrqueue != NULL && !m_mhdrqueue->empty())
           || m_bFoundMsgs) {
               mMsgIdLow.set("%d",m_lowId);
               mMsgIdHi.set("%d",m_hiId);
               m_bFoundMsgs=true;
          }
          else {
               if (m_startMsgId > 0) {
                    mMsgIdHi.set("%d",m_startMsgId-1);
               }
               else {
                    mMsgIdHi.set("%d",m_startMsgId);
               }
               mMsgIdLow.set("%d",m_startMsgId+1);
          }
     }
     setMoreLowTvb(m_moreLow);
     setMoreHiTvb(m_moreHi);
     if (m_listFlags&LIST_ORD_DESCEND) {
          mOrder.set("descending");
     }
     else {
          mOrder.set("ascending");
     }
}

ACTHCODE
prefSynthesis::proceed()           // pref request entry point
{
     ACTHCODE retval=pureHTMLSynth::proceed();

     if (retval == ACTHMORE ) {
          switch (m_ahState) {
          case PROCEED_AH_POST:
               GETINPUT("type");
               if (strInpBuf[0] != '\0') {
                    if (sameas(strInpBuf,"html")) {
                         m_webFlags&=~EPREF_TYPE_JAVA;
                         m_webFlags|=EPREF_TYPE_HTML;
                    }
                    else if (sameas(strInpBuf,"java")) {
                         m_webFlags|=EPREF_TYPE_JAVA;
                         m_webFlags&=~EPREF_TYPE_HTML;
                    }
               }
               GETINPUT("forwardee");
               if (paramOK("forwardee")) {
                    if ((m_ecPtr->m_merr_code=SetAutoFwd(strInpBuf)) != VALYES) {
                         ::handleError(m_ecPtr,OP_VALIDATION,"Invalid Forwardee");
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }
               }
               GETINPUT("override");
               if (paramOK("override") && strInpBuf[0] == '\0') {
                    m_webFlags&=~(EPREF_NOFRAMES+EPREF_USEFRAMES+MPREF_REFLOW+MPREF_QUOTE+MPREF_INCLIST);
                    m_qscptr->flags&=~(CLARPL+FORUM2);
                    if (paramOK("useframes")) {
                         m_webFlags|=EPREF_USEFRAMES;
                    }
                    else {
                         m_webFlags|=EPREF_NOFRAMES;
                    }
                    if (paramOK("reflow")) {
                         m_webFlags|=MPREF_REFLOW;
                    }
                    if (paramOK("quote")) {
                         m_webFlags|=MPREF_QUOTE;
                    }
                    if (paramOK("inclist")) {
                         m_webFlags|=MPREF_INCLIST;
                    }
                    if (paramOK("clrreply")) {
                         m_qscptr->flags|=CLARPL;
                    }
                    if (paramOK("forumto")) {
                         m_qscptr->flags|=FORUM2;
                    }
               }
               else if (strInpBuf[0] != '\0') {
                    if (findstg("useframes",strInpBuf)) {
                          m_webFlags&=~EPREF_USEFRAMES;
                          m_webFlags&=~EPREF_NOFRAMES;
                          if (paramOK("useframes")) {
                               m_webFlags|=EPREF_USEFRAMES;
                          }
                          else {
                               m_webFlags|=EPREF_NOFRAMES;
                          }
                    }
                    if (findstg("reflow",strInpBuf)) {
                          m_webFlags&=~MPREF_REFLOW;
                          if (paramOK("reflow")) {
                               m_webFlags|=MPREF_REFLOW;
                          }
                    }
                    if (findstg("quote",strInpBuf)) {
                         m_webFlags&=~MPREF_QUOTE;
                         if (paramOK("quote")) {
                              m_webFlags|=MPREF_QUOTE;
                         }
                    }
                    if (findstg("inclist",strInpBuf)) {
                         m_webFlags&=~MPREF_INCLIST;
                         if (paramOK("inclist")) {
                              m_webFlags|=MPREF_INCLIST;
                         }
                    }
                    if (findstg("clrreply",strInpBuf)) {
                         m_qscptr->flags&=~CLARPL;
                         if (paramOK("clrreply")) {
                              m_qscptr->flags|=CLARPL;
                         }
                    }
                    if (findstg("forumto",strInpBuf)) {
                         m_qscptr->flags&=~FORUM2;
                         if (paramOK("forumto")) {
                              m_qscptr->flags|=FORUM2;
                         }
                    }
               }
               setWebPrefs(m_usrPtr->userid(),m_webFlags);
               m_ahState=PROCEED_AH_RESPONSE;
               break;
          case PROCEED_AH_RESPONSE:
               if (m_dnfPtr == NULL) {
                    retval=handleTemplates(&prefSuccMap,&prefErrMap,PPFIX,
                     "pref/");
               }
               else {
                    dnfSetTemplateTvb(m_dnfPtr);
                    retval=respDynafile();
               }
               break;
          }
          destructHTMLGMEUser();
     }
     return(retval);
}

ACTHCODE
viewSynthesis::proceed()           // view request entry point
{
     ACTHCODE retval=pureHTMLSynth::proceed();

     if (retval == ACTHMORE ) {
          if (ses->urlargc() > 2 && sameas(ses->urlargv(1),"ext") &&
              m_ahState == PROCEED_AH_REQUEST) {
               m_showExtHeadInfo=TRUE;
               m_ahState=PROCEED_AH_EXTHEAD;
          }
          switch (m_ahState) {
          case PROCEED_AH_EXTHEAD:
               if (paramOK("from")) {
                 m_viewFlags|=LIST_SENT;
               }
               GETINPUT("id");
               if (strInpBuf[0] != '\0' && alldgs(strInpBuf)) {
                    m_savMsgId=validateMsgId(::atoul(strInpBuf));
               }
               else {
                    m_savMsgId=0;
               }
               m_mhdr_msgid = m_savMsgId;
               inictx(mywrkarea,m_usrPtr->userid(),(m_viewFlags&LIST_SENT)? ESQFRU : ESQTOU,EMLID,m_savMsgId,0);
               m_readType=RDEXCT;
               m_ahState=PROCEED_AH_READMSG;
               break;
          case PROCEED_AH_REQUEST:
               m_ahState=PROCEED_AH_READMSG;
               if (paramOK("from")) {
                 m_viewFlags|=LIST_SENT;
               }
               GETINPUT("id");
               if (strInpBuf[0] != '\0' && alldgs(strInpBuf)) {
                    m_savMsgId=validateMsgId(::atoul(strInpBuf));
               }
               else {
                    m_savMsgId=0;
               }
               m_mhdr_msgid = m_savMsgId;
               GETINPUT("direction");
               if (strInpBuf[0] != '\0') {
                    if (sameas(strInpBuf,"lt")) {
                         m_readType=RDPREV;
                    }
                    else if (sameas(strInpBuf,"gt")) {
                         m_readType=RDNEXT;
                    }
                    else if (sameas(strInpBuf,"ge")) {
                         m_readType=RDGELT;
                    }
                    else if (sameas(strInpBuf,"le")) {
                         m_readType=RDLEGT;
                    }
                    else if (sameas(strInpBuf,"near")) {
                         m_ahState=PROCEED_AH_NEARGELT;
                    }
                    else {
                         m_readType=RDEXCT;
                    }
               }
               else {
                    m_readType=RDEXCT;
               }
               GETINPUT("reflow");
               if (strInpBuf[0] != '\0') {
                    if (sameas(strInpBuf,"1")) {
                         m_readFlags|=READ_REFLOW;
                    }
                    else if (sameas(strInpBuf,"~")) {
                         if (!(m_webFlags&MPREF_REFLOW)) {
                              m_readFlags|=READ_REFLOW;
                         }
                    }
                    else if (sameas(strInpBuf,"0 set")) {
                         updatePref(MPREF_REFLOW,FALSE);
                    }
                    else if (sameas(strInpBuf,"1 set")) {
                         updatePref(MPREF_REFLOW,TRUE);
                         m_readFlags|=READ_REFLOW;
                    }
                    else if (sameas(strInpBuf,"~ set")) {
                         if (m_webFlags&MPREF_REFLOW) {
                              updatePref(MPREF_REFLOW,FALSE);
                         }
                         else {
                              updatePref(MPREF_REFLOW,TRUE);
                              m_readFlags|=READ_REFLOW;
                         }
                    }
                    else {
                        if (m_webFlags&MPREF_REFLOW) {
                              m_readFlags|=READ_REFLOW;
                         }
                    }
               }
               if (getWebPrefs(m_usrPtr->userid())&MPREF_REFLOW) {
                    m_readFlags|=READ_REFLOW;
               }
               if (paramOK("notext")) {
                    m_readFlags|=READ_NOTEXT;
               }
               inictx(mywrkarea,m_usrPtr->userid(),(m_viewFlags&LIST_SENT)? ESQFRU : ESQTOU,EMLID,m_savMsgId,0);
               break;
          case PROCEED_AH_READMSG:
               switch ((m_ecPtr->m_merr_code=frdmsg(mywrkarea,m_readType,
                m_mhdrptr,txtbuf))) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    m_orgText=txtbuf;
                    m_sAppInfo=gmeGetAppInfo();
                    if (m_sAppInfo.length() == 0) {
                         m_sAppInfo=noxhdr;
                    }
                    m_ahState=PROCEED_AH_MARKREAD;
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_NEARGELT:
               switch ((m_ecPtr->m_merr_code=nearmsgf(mywrkarea,GELT,m_mhdrptr,
                txtbuf))) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    m_orgText=txtbuf;
                    m_sAppInfo=gmeGetAppInfo();
                    if (m_sAppInfo.length() == 0) {
                         m_sAppInfo=noxhdr;
                    }
                    m_ahState=PROCEED_AH_MARKREAD;
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_MARKREAD:
               m_ecPtr->m_merr_code=markreadf(mywrkarea,m_mhdrptr,txtbuf2);
               if (m_ecPtr->m_merr_code > GMEAGAIN) {
                    inictx(mywrkarea,m_usrPtr->userid(),(m_viewFlags&LIST_SENT)? ESQFRU : ESQTOU,EMLID,m_mhdrptr->msgid,0); 
                     if (m_ecPtr->m_merr_code == GMERRG) {
                         m_readFlags|=READ_RETRECREQ;
                     }
                     m_ahState=PROCEED_AH_PREVMSG;
               }
               else if (m_ecPtr->m_merr_code < GMEAGAIN) {
                    m_ahState=PROCEED_AH_RESPONSE;
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
               }
               break;

          case PROCEED_AH_PREVMSG:
               switch ((m_ecPtr->m_merr_code=prevmsg(mywrkarea,m_wrkHeader,
                txtbuf2))) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    inictx(mywrkarea,m_usrPtr->userid(),(m_viewFlags&LIST_SENT)? ESQFRU : ESQTOU,EMLID,m_mhdrptr->msgid,0);
                    m_moreLow=TRUE;
                    m_ahState=PROCEED_AH_NEXTMSG;
                    break;
               case GMENFND:
                    m_ahState=PROCEED_AH_NEXTMSG;
                    m_ecPtr->m_merr_code=GMEOK; // don't want to error out
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_NEXTMSG:
               switch ((m_ecPtr->m_merr_code=nextmsg(mywrkarea,m_wrkHeader,
                txtbuf2))) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    if (m_readFlags&READ_NOTEXT) {
                         m_ahState=PROCEED_AH_RESPONSE;
                    }
                    else {
                         m_ahState=PROCEED_AH_STRIPRTF;
                    }
                    m_moreHi=TRUE;
                    break;
               case GMENFND:
                    if (m_readFlags&READ_NOTEXT) {
                        m_ahState=PROCEED_AH_RESPONSE;
                    }
                    else {
                         m_ahState=PROCEED_AH_STRIPRTF;
                    }
                    m_moreHi=FALSE;
                    m_ecPtr->m_merr_code=GMEOK; // don't want to error out
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_STRIPRTF:
               setmem(txtbuf2,TXTLEN,0);
               stlcpy(txtbuf,m_orgText.c_str(),TXTLEN);
               if (stripfmt(txtbuf,txtbuf2,TXTLEN)) {
                    m_sMsgTxt=txtbuf2;
               }
               else {
                    m_sMsgTxt=txtbuf;
               }
               m_ahState=PROCEED_AH_FORMAT;
               break;
          case PROCEED_AH_FORMAT:
               if (m_readFlags&READ_REFLOW) {
                    m_sMsgTxt=formatMessage(m_sMsgTxt.c_str(),TRUE,FALSE);
               }
               else {
                    m_sMsgTxt=formatMessage(m_sMsgTxt.c_str(),FALSE,FALSE);
               }
               m_ahState=PROCEED_AH_LINKS;
               break;
          case PROCEED_AH_LINKS:
               m_sMsgTxt=formatURLs(m_sMsgTxt.c_str(),anchorTag);
               m_ahState=PROCEED_AH_RESPONSE;
               break;
          case PROCEED_AH_RESPONSE:
               if (m_showExtHeadInfo) {
                    if (m_dnfPtr == NULL) {
                         retval=handleTemplates(&viewExtMap,&viewExtErrMap,
                          PPFIX,"view/ext/");
                    }
                    else {
                         initVars();
                         if (m_ecPtr->m_merr_code >= GMEOK &&
                             m_ecPtr->m_merr_code <= GMEAFWD) {
                              retval=dynaExtHeadResp();
                         }
                         else {
                              retval=respDynafile();
                         }
                    }
               }
               else {
                    if (m_dnfPtr == NULL) {
                         retval=handleTemplates(&viewMap,&viewErrMap,PPFIX,
                          "view/");
                    }
                    else {
                         initVars();
                         if (m_readFlags&READ_RETRECREQ) {
                              mReceipt.set(rrrDsp);
                         }
                         if (m_ecPtr->m_merr_code >= GMEOK &&
                             m_ecPtr->m_merr_code <= GMEAFWD) {
                              retval=dynaReadResp();
                         }
                         else {
                              retval=respDynafile();
                         }
                    }
               }
              break;
          }
          destructHTMLGMEUser();
     }
     return(retval);
}

ACTHCODE
viewSynthesis::dynaExtHeadResp()   // read/view response dynafile
{
     ACTHCODE retval=ACTHMORE;

     setMoreLowTvb(m_moreLow);
     setMoreHiTvb(m_moreHi);

     if (m_ecPtr->startProc()) {
          do {
               switch(m_dnfPtr->process()) {
               case HEADERS:
                    bout << formatMessage(m_sAppInfo.c_str(),FALSE,FALSE);
                    break;
               case DNFEND:
                    retval=ACTHDONE;
                    break;
               }
          } while (m_ecPtr->contProc(retval));
     }
     return(retval);
}

ACTHCODE
writeSynthesis::proceed()          // write request entry point
{
     ACTHCODE retval=pureHTMLSynth::proceed();
     quotfunc qfunc;

     if (retval == ACTHMORE ) {
          switch(m_ahState) {
          case PROCEED_AH_REQUEST:
               if (!getCompositionParams()) {
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               if (m_writeFlags&WRITE_REPLY || m_writeFlags&WRITE_RESEND) {
                    SHORT seq=ESQTOU;
                    if (m_orgForId != EMLID) {
                         seq=FSQFOR;
                    }
                    inictx(mywrkarea,m_usrPtr->userid(),seq,m_orgForId,
                     m_orgMsgId,0);
                    m_ahState=PROCEED_AH_REPLY;
               }
               else {
                    m_ahState=PROCEED_AH_RESPONSE;
               }
               break;
          case PROCEED_AH_REPLY:
               switch ((m_ecPtr->m_merr_code=readmsgf(mywrkarea,m_mhdrptr,txtbuf))) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    m_orgText=txtbuf;
                    m_toAdr=m_mhdrptr->from;
                    m_topic=m_mhdrptr->topic;
                    if (m_writeFlags&WRITE_TOALL) {
                         m_cclist=getCCAddresses(txtbuf,strlen(txtbuf)+1,
                          (CHAR *)m_usrPtr->userid());
                    }
                    if ((m_webFlags&MPREF_QUOTE || m_writeFlags&WRITE_QUOTE)
                     && !(m_writeFlags&WRITE_KEEPFMT)) {
                         m_ahState=PROCEED_AH_STRIPRTF;
                    }
                    else {
                         m_ahState=PROCEED_AH_RESPONSE;
                    }
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_STRIPRTF:
               setmem(txtbuf,TXTLEN,0);
               stlcpy(txtbuf,m_orgText.c_str(),TXTLEN);
               gmePlainText(txtbuf);
               m_orgText=txtbuf;
               m_ahState=PROCEED_AH_QUOTE;
               break;
          case PROCEED_AH_QUOTE:
               m_ahState=PROCEED_AH_RESPONSE;
               if (!(m_writeFlags&WRITE_RESEND)) {
                    stlcpy(txtbuf2,m_orgText.c_str(),TXTLEN);
                    qfunc=setquoter(NULL);
                    stlcpy(m_mhdrptr->to,m_mhdrptr->from,MAXADR);
                    (*qfunc)(m_mhdrptr,txtbuf2,TXTLEN);
                    setquoter(*qfunc);
                    m_orgText=txtbuf2;
               }
               break;
          case PROCEED_AH_RESPONSE:
               if (m_dnfPtr == NULL) {
                    retval=handleTemplates(&writeMap,&writeErrMap,PPFIX,
                     WRITEURL);
               }
               else {
                    dnfSetTemplateTvb(m_dnfPtr);
                    if (m_ecPtr->m_merr_code >= GMEOK
                      && m_ecPtr->m_merr_code <= GMEAFWD) {
                          initCompositionVbs();
                          mWriteTmpid.set("%d",m_tickId);  // insert initial tmpid value here
                          retval=dynaWriteResp();
                    }
                    else {
                          initErrVariables();
                          retval=respDynafile();
                    }
               }
               break;
          }
          destructHTMLGMEUser();
     }
     return(retval);
}

ACTHCODE
sendSynthesis::proceed()           // send request entry point
{
     ACTHCODE retval=pureHTMLSynth::proceed();
     CHAR ccadr[MAXADR];
     string fname;
     INT bdylen;
     INT numSubTypes=0;

     if (retval == ACTHMORE) {
          switch(m_ahState) {
          case PROCEED_AH_POST:
               if (paramOK("send")) {
                    m_sendFlags|=SUBMIT_SEND;
                    ++numSubTypes;
               }
               if (paramOK("attach")) {
                    ++numSubTypes;
                    m_sendFlags|=SUBMIT_ATTACH;
               }
               if (paramOK("upload")) {
                    ++numSubTypes;
                    m_sendFlags|=SUBMIT_UPLOAD;
               }
               if (paramOK("detach")) {
                    ++numSubTypes;
                    m_sendFlags|=SUBMIT_DETACH;
               }
               if (paramOK("preview")) {
                    ++numSubTypes;
                    m_sendFlags|=SUBMIT_PREVIEW;
               }
               if (paramOK("redisplay")) {
                    ++numSubTypes;
                    m_sendFlags|=SUBMIT_REDISPLAY;
               }
               if (paramOK("cancel")) {
                    ++numSubTypes;
                    m_sendFlags|=SUBMIT_CANCEL;
               }
               if (numSubTypes != 1) {
                    submitError();
                    retval=ACTHDONE;
                    break;
               }
               if (!getCompositionParams()) {
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               if (m_sendFlags&SUBMIT_SEND) {
                    setmem(m_mhdrptr,sizeof(struct message),0);
                    if (m_writeFlags&WRITE_REPLY) {
                         SHORT seq=ESQTOU;
                         if (m_orgForId != EMLID) {
                              seq=FSQFOR;
                         }
                         inictx(mywrkarea,m_usrPtr->userid(),seq,m_orgForId,
                          m_orgMsgId,0);
                         m_ahState=PROCEED_AH_READMSG;
                    }
                    else {
                         m_ahState=sendHeaderSetup();
                    }
               }
               else if (m_sendFlags&(SUBMIT_ATTACH|SUBMIT_REDISPLAY)) {
                    m_ahState=PROCEED_AH_RESPONSE;
               }
               else if (m_sendFlags&(SUBMIT_UPLOAD|SUBMIT_DETACH|SUBMIT_CANCEL)) {
                    m_ahState=PROCEED_AH_PRCSUBMIT;
               }
               else if (m_sendFlags&SUBMIT_PREVIEW) {
                    setmem(m_mhdrptr,sizeof(struct message),0);
                    sendHeaderSetup();
                    m_mhdrptr->crdate=today();
                    m_mhdrptr->crtime=now();
                    m_ahState=PROCEED_AH_VALIDADR;
               }
               break;
          case PROCEED_AH_VALIDADR:
               if ((m_ecPtr->m_merr_code=valadr(mywrkarea,m_mhdrptr->from,
                m_mhdrptr->to,m_mhdrptr->forum)) != VALYES) {
                    ::handleError(m_ecPtr,OP_VALIDATION,valadress);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               m_ahState=PROCEED_AH_VALIDATT;
               break;
          case PROCEED_AH_VALIDATT:
               m_ahState=PROCEED_AH_VALIDPRI;
               if (strlen(m_mhdrptr->attname) > 0) {
                    if ((m_ecPtr->m_merr_code=valatt(mywrkarea,m_mhdrptr->from,
                     m_mhdrptr->to,m_mhdrptr->forum)) != VALYES) {
                         ::handleError(m_ecPtr,OP_VALIDATION,valattach);
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }
                    if (m_attachName.length() > 0) {
                         if (!isvalfn((CHAR *)m_attachName.c_str())) {
                              m_ecPtr->m_merr_code=ERR_INVALIDFN;
                              m_ecPtr->m_merr_message=erinvfn;
                              m_ahState=PROCEED_AH_RESPONSE;
                              break;
                         }
                    }
                    break;
               }
               // intentional drop through
          case PROCEED_AH_VALIDPRI:
               if (m_writeFlags&WRITE_PRI
                && (m_ecPtr->m_merr_code=valpri(mywrkarea,m_mhdrptr->from,
                m_mhdrptr->to,m_mhdrptr->forum)) != VALYES) {
                    ::handleError(m_ecPtr,OP_VALIDATION,valpriority);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               m_ahState=PROCEED_AH_VALIDRR;
               break;
          case PROCEED_AH_VALIDRR:
               if (m_writeFlags&WRITE_RR
                && (m_ecPtr->m_merr_code=valrrr(mywrkarea,m_mhdrptr->from,
                m_mhdrptr->to,m_mhdrptr->forum)) != VALYES) {
                    ::handleError(m_ecPtr,OP_VALIDATION,valrr);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               m_ahState=PROCEED_AH_VALIDBLEN;
               break;
          case PROCEED_AH_VALIDBLEN:
               if ((bdylen=m_paramText.length()) > TXTLEN) {
                    clrprf();
                    prfmsg(ERBDYTL,TXTLEN,ses->paramRoom("text"));
                    m_ecPtr->m_merr_code=ERR_BODY2LONG;
                    m_ecPtr->m_merr_message=stpans(prfbuf);
                    clrprf();
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               m_ahState=PROCEED_AH_VALIDPFN;
               break;
          case PROCEED_AH_VALIDPFN:
               if (m_attachName.length() > 0) {
                    if(pfnerr(m_usrPtr->userid(),(CHAR *)m_attachName.c_str(),m_mhdrptr->forum)) {
                         m_ecPtr->m_merr_code=ERR_PROFANATT;
                         m_ecPtr->m_merr_message=erprfat;
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }
               }
               if (strlen(m_mhdrptr->topic) > 0) {
                    if (pfnerr(m_usrPtr->userid(),m_mhdrptr->topic,m_mhdrptr->forum)) {
                         m_ecPtr->m_merr_code=ERR_PROFANTPC;
                         profaneTopic();
                         m_ecPtr->m_merr_message=erprftp;
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }
               }
               m_ahState=PROCEED_AH_VALIDPFBDY;
               break;
          case PROCEED_AH_VALIDPFBDY:
               if (m_paramText.length() > 0) {
                    if (pfnerr(m_usrPtr->userid(),(CHAR *)m_paramText.c_str(),m_mhdrptr->forum)) {
                         m_ecPtr->m_merr_code=ERR_PROFANBDY;
                         profaneBody();
                         m_ecPtr->m_merr_message=erprfbt;
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }
               }
               if (m_cclist.length() > 0) {
                    m_ccPtr=(CHAR *)m_cclist.c_str();
                    m_ahState=PROCEED_AH_VALIDCCADR;
               }
               else {
                    m_ahState=getState();
               }
               break;
          case PROCEED_AH_VALIDCCADR:
               if ((m_ccPtr=parscc(ccadr,m_ccPtr)) != NULL) {
                    ++m_ccCount;
                    if (m_ccCount > iMaxCC) {
                         m_ecPtr->m_merr_code=ERR_2MANYCC;
                         clrprf();
                         prfmsg(ERCC2MNY,iMaxCC);
                         m_ecPtr->m_merr_message=stpans(prfbuf);
                         clrprf();
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }
                    if ((m_ecPtr->m_merr_code=valadr(mywrkarea,m_mhdrptr->from,
                     ccadr,m_mhdrptr->forum)) != VALYES) {
                         ::handleError(m_ecPtr,OP_VALIDATION,valccadr);
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }
               }
               else {
                    if (strlen(m_mhdrptr->attname) > 0) {
                         m_ccPtr=(CHAR *)m_cclist.c_str();
                         m_ahState=PROCEED_AH_VALIDCCATT;
                    }
                    else {
                         m_ahState=getState();
                    }
               }
               break;
          case PROCEED_AH_VALIDCCATT:
               if ((m_ccPtr=parscc(ccadr,m_ccPtr)) != NULL) {
                    if ((m_ecPtr->m_merr_code=valatt(mywrkarea,m_mhdrptr->from,
                     ccadr,m_mhdrptr->forum)) != VALYES) {
                         ::handleError(m_ecPtr,OP_VALIDATION,valccatt);
                         m_ahState=PROCEED_AH_RESPONSE;
                         break;
                    }
               }
               else {
                    m_ahState=getState();
               }
               break;
          case PROCEED_AH_STRIPRTF:
               setmem(txtbuf2,TXTLEN,0);
               stlcpy(txtbuf,m_paramText.c_str(),TXTLEN);
               if (stripfmt(txtbuf,txtbuf2,TXTLEN)) {
                    m_paramText=txtbuf2;
               }
               else {
                    m_paramText=txtbuf;
               }
               m_ahState=PROCEED_AH_SENDFORMAT;
               break;
          case PROCEED_AH_FORMAT:
               m_paramText=formatMessage(m_paramText.c_str(),FALSE,FALSE);
               m_ahState=PROCEED_AH_LINKS;
               break;
          case PROCEED_AH_LINKS:
               m_paramText=formatURLs(m_paramText.c_str(),anchorTag);
               m_ahState=PROCEED_AH_RESPONSE;
               break;
          case PROCEED_AH_SENDFORMAT:
               if (format4Send()) {
                    if (m_sendFlags&SUBMIT_PREVIEW) {
                         m_ahState=PROCEED_AH_FORMAT;
                    }
                    else {
                         m_ahState=PROCEED_AH_PRCSUBMIT;
                    }
               }
               break;
          case PROCEED_AH_ATTACH:
               if (writeFileStream()) {
                    m_ahState=PROCEED_AH_MOVEFILE;
               }
               break;
          case PROCEED_AH_MOVEFILE:
               fname=AHUPDIR;
               fname+="\\";
               fname+=spr("%lu",m_tmpid);
               if (rename(fname.c_str(),m_gmefname.c_str()) == -1) {
                    // this should never happen
                    shocst("ACTIVE H E-MAIL: RENAME ERROR",
                     "Couldn't rename attachment file");
               }
               m_ahState=PROCEED_AH_VALIDADR;
               break;
          case PROCEED_AH_READMSG:
               switch (m_ecPtr->m_merr_code=readmsg(mywrkarea,m_mhdrptr,txtbuf)) {
               case GMEAGAIN:
                    break;
               case GMEOK:
                    m_ahState=sendHeaderSetup();
                    break;
               default:
                    ::handleError(m_ecPtr,OP_GENERIC,NULL);
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_DELETE:
               switch (m_ecPtr->m_merr_code=delmsg(mywrkarea)) {
               case GMEAGAIN:
                    break;
               default:
                    m_ahState=PROCEED_AH_RESPONSE;
               }
               break;
          case PROCEED_AH_PRCSUBMIT:
               if (m_sendFlags&SUBMIT_SEND) {
                    if (m_writeFlags&WRITE_REPLY) {
                         m_ecPtr->m_merr_code=reply(mywrkarea,m_mhdrptr,
                          m_paramText.c_str(),m_gmefname.c_str(),m_cclist.c_str());
                         if (m_ecPtr->m_merr_code > GMEAGAIN) {
                              if (m_qscptr->flags&CLARPL && m_forum == EMLID) {
                                   m_savMsgId=m_orgMsgId;
                                   inigmerq(mywrkarea); // re-init work area cause it was closed
                                   inictx(mywrkarea,m_usrPtr->userid(),
                                    ESQTOU,EMLID,m_savMsgId,0);
                                   m_ahState=PROCEED_AH_DELETE;
                                   break;
                              }
                              m_ahState=PROCEED_AH_RESPONSE;
                         }
                         else if (m_ecPtr->m_merr_code < GMEAGAIN) {
                              ::handleError(m_ecPtr,OP_GENERIC,NULL);
                              m_ahState=PROCEED_AH_RESPONSE;
                         }
                    }
                    else {
                         switch ((m_ecPtr->m_merr_code=gmeSendMsg(mywrkarea,
                          m_mhdrptr,m_paramText.c_str(),m_gmefname.c_str(),
                          m_cclist.c_str()))) {
                         case GMEAGAIN:
                              break;
                         case GMEOK:
                              m_ahState=PROCEED_AH_RESPONSE;
                              break;
                         default:
                              ::handleError(m_ecPtr,OP_GENERIC,NULL);
                              m_ahState=PROCEED_AH_RESPONSE;
                              break;
                         }
                    }
               }
               else if (m_sendFlags&SUBMIT_UPLOAD) {
                    if (m_firstTime) {
                         if (!paramOK("attfile")) {
                              badParam("attfile");
                              m_ahState=PROCEED_AH_RESPONSE;
                              break;
                         }
                         if (m_tmpid == 0) {
                              badParam("tmpid");
                              m_ahState=PROCEED_AH_RESPONSE;
                              break;
                         }
                         if (!getFileStream()) {
                              badParam("attachment file data");
                              m_ahState=PROCEED_AH_RESPONSE;
                              break;
                         }
                         m_firstTime=FALSE;
                    }
                    if (writeFileStream()) {
                         m_ahState=PROCEED_AH_RESPONSE;
                    }
               }
               else if (m_sendFlags&SUBMIT_DETACH) {
                    if (m_tmpid == 0) {
                         badParam("tmpid");
                    }
                    else {
                         deleteAttachment();
                    }
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               else if (m_sendFlags&SUBMIT_CANCEL) {
                    if (m_tmpid != 0) {
                         deleteAttachment();
                    }
                    m_ahState=PROCEED_AH_RESPONSE;
                    break;
               }
               break;
          case PROCEED_AH_RESPONSE:
               if (m_ecPtr->m_merr_code < GMEOK
                || m_ecPtr->m_merr_code > GMEAFWD) {
                    initErrVariables();
               }
               else {
                    initCompositionVbs();
               }
               if (m_dnfPtr == NULL) {
                    if (m_sendFlags&SUBMIT_SEND) {
                         retval=handleTemplates(&sendMap,&sendErrMap,PPFIX,
                          WRITEURL);
                    }
                    else if (m_sendFlags&SUBMIT_ATTACH) {
                         retval=handleTemplates(&attachMap,&attachErrMap,
                          PPFIX,WRITEURL);
                    }
                    else if (m_sendFlags&SUBMIT_UPLOAD) {
                         retval=handleTemplates(&uplMap,&uplErrMap,PPFIX,
                          WRITEURL);
                    }
                    else if (m_sendFlags&SUBMIT_DETACH) {
                         retval=handleTemplates(&detachMap,&detachErrMap,
                          PPFIX,WRITEURL);
                    }
                    else if (m_sendFlags&SUBMIT_PREVIEW) {
                         // since preview passed all validation, handle special
                         // case forum address.. i.e. "/hello" etc.
                         if (isforum(m_mhdrptr->to)) {
                              m_mhdrptr->forum=getfid(&m_mhdrptr->to[1]);
                              stlcpy(m_mhdrptr->to,ALLINF,MAXADR);
                         }
                         retval=handleTemplates(&previewMap,&previewErrMap,
                          PPFIX,WRITEURL);
                    }
                    else if (m_sendFlags&SUBMIT_REDISPLAY) {
                         retval=handleTemplates(&redispMap,&redispErrMap,
                          PPFIX,WRITEURL);
                    }
                    else if (m_sendFlags&SUBMIT_CANCEL) {
                         retval=handleTemplates(&cancelMap,&cancelErrMap,
                          PPFIX,WRITEURL);
                    }
               }
               else {
                    dnfSetTemplateTvb(m_dnfPtr);
                    if (m_sendFlags&(SUBMIT_UPLOAD|SUBMIT_DETACH
                     |SUBMIT_REDISPLAY|SUBMIT_ATTACH)) {
                         if (m_ecPtr->m_merr_message.length() == 0) {
                              retval=dynaWriteResp();
                              break;
                         }
                    }
                    else if (m_sendFlags&SUBMIT_PREVIEW) {
                         initSuccVariables();
                         m_sMsgTxt=m_paramText;
                         retval=dynaReadResp();
                         break;
                    }
                    retval=respDynafile();
               }
               break;
          }
          destructHTMLGMEUser();
     }
     return(retval);
}

SHORT
sendSynthesis::getState()          // determine state based on formatting and flags
{
     if (m_sendFlags&SUBMIT_SEND && !isfmtted(m_paramText.c_str())) {
          return(PROCEED_AH_SENDFORMAT);
     }
     else if (m_sendFlags&SUBMIT_PREVIEW) {
          return(PROCEED_AH_STRIPRTF);
     }
     return(PROCEED_AH_PRCSUBMIT);
}

VOID
sendSynthesis::deleteAttachment()  // nuke attachment
{
     string fname=AHUPDIR;
     fname+="\\";
     fname+=spr("%lu",m_tmpid);
     unlink(fname.c_str());
     m_attachName="";
}

VOID
sendSynthesis::submitError()       // submit type error
{
     shocst("ACTIVE H E-MAIL: SEND ERROR",
            "AH Email Error: Multiple (or no) submit types in the \"send\" URL.");
     bout << "There are multiple (or no) submit types in the \"send\" URL." <<
             "  Please notify the System Administrator.";
}

VOID
sendSynthesis::addCCs()            // add CCs to body of message
{
     if (m_cclist.length() > 0) {
          ccadfunc ccfunc;
          ccfunc=setccadder(NULL);
          stlcpy(txtbuf2,(CHAR *)m_paramText.c_str(),TXTLEN);
          (*ccfunc)(txtbuf2,(CHAR *)m_cclist.c_str(),m_mhdrptr->to);
          setccadder(*ccfunc);
          m_paramText=txtbuf2;
     }
}

SHORT
sendSynthesis::sendHeaderSetup()   // set up header info
{
     if (m_writeFlags&WRITE_REPLY && !(m_sendFlags&SUBMIT_PREVIEW)) {
          stlcpy(m_mhdrptr->to,m_mhdrptr->from,MAXADR);
     }
     else {
          stlcpy(m_mhdrptr->to,m_toAdr.c_str(),MAXADR);
     }
     stlcpy(m_mhdrptr->from,m_usrPtr->userid(),MAXADR);
     stlcpy(m_mhdrptr->topic,m_topic.c_str(),TPCSIZ);
     m_mhdrptr->forum=m_forum;
     m_mhdrptr->flags=0;
     if (m_writeFlags&WRITE_RR) {
          m_mhdrptr->flags|=RECREQ;
     }
     if (m_writeFlags&WRITE_PRI) {
          m_mhdrptr->flags|=PRIMSG;
     }
     if (m_writeFlags&WRITE_INCLIST
      || getWebPrefs(m_usrPtr->userid())&MPREF_INCLIST) {
          addCCs();
     }
     if (m_attachName.length() > 0) {
          stlcpy(m_mhdrptr->attname,m_attachName.c_str(),GCMAXFNM);
          m_mhdrptr->flags|=FILATT;
          m_mhdrptr->flags&=~FILIND;
          m_gmefname=ulname(m_mhdrptr);
          return(PROCEED_AH_MOVEFILE);
     }
     else if (paramOK("attfile")) {
          m_tmpid=::GetTickCount();
          if (!getFileStream()) {
               m_tmpid=0;
               return(PROCEED_AH_VALIDADR);
          }
          stlcpy(m_mhdrptr->attname,m_attachName.c_str(),GCMAXFNM);
          m_mhdrptr->flags|=FILATT;
          m_mhdrptr->flags&=~FILIND;
          m_gmefname=ulname(m_mhdrptr);
          return(PROCEED_AH_ATTACH);
     }
     return(PROCEED_AH_VALIDADR);
}

GBOOL
sendSynthesis::writeFileStream()   // do the bulk of writing to file
{
     ASSERT(m_ulistr != NULL);

     if (m_ulistr != NULL) {
          setmem(m_writeBuf,sizeof(m_writeBuf),0);
          m_ulistr->read(m_writeBuf,sizeof(m_writeBuf));
          ASSERT(m_ofstr != NULL);
          m_ofstr->write(m_writeBuf,m_ulistr->gcount());
          preventTimeout();
          if (m_ulistr->eof() || m_ulistr->fail()) {
               ses->paramStreamClose(m_ulistr);
               return(TRUE);
          }
     }
     else {
          return(TRUE);
     }
     return(FALSE);
}

VOID
sendSynthesis::preventTimeout()    // prevent a timeout on big upload
{
     bout << "<!--\n";
     bout << "\\-->";
}

GBOOL
sendSynthesis::getFileStream()     // get the file stream
{
     string hdr;
     size_t valsiz=STRINPSIZ;

     ses->paramHeader("attfile","Content-Disposition",
          strInpBuf,STRINPSIZ);
     hdr=strInpBuf;
     acthGetHeaderParam(hdr.c_str(),"filename",&valsiz,strInpBuf);
     if (strInpBuf[0] == '\0') {
          return(FALSE);
     }
     if (!isdir(AHUPDIR)) {
          if (mkdir(AHUPDIR) == -1) {
               shocst("ACTIVE H E-MAIL: MAKE DIR ERROR",
                "Failed to create AH Email Upload Directory");
          }
     }
     string fname=AHUPDIR;
     fname+="\\";
     fname+=spr("%lu",m_tmpid);
     CHAR fbuf[GCMAXFNM];
     m_attachName=fileparts(GCPART_FNAM,strInpBuf,fbuf,GCMAXFNM);
     m_attachName=mkdosn(m_attachName.c_str());
     if (m_ofstr != NULL) {
          delete m_ofstr;
     }
     m_ofstr=new ofstream(fname.c_str(),ios::binary);
     ses->paramStreamOpen("attfile",&m_ulistr);
     if (m_ulistr != NULL) {
          setmem(m_writeBuf,sizeof(m_writeBuf),0);
          m_ulistr->read(m_writeBuf,sizeof(m_writeBuf));
          INT len=m_ulistr->gcount();
          if (len == 0) {
               ses->paramStreamClose(m_ulistr);
               m_attachName="";
               return(FALSE);
          }
          else {
               m_ofstr->write(m_writeBuf,len);
          }
     }
     return(TRUE);
}

GBOOL
emailCommon::startProc()           // start processing?
{
     return(m_timer.start());
}

GBOOL
emailCommon::contProc(             // continue to process?
ACTHCODE rc)                       // are we all done?
{
     return(rc == ACTHMORE && !m_needToCycle && m_timer.haveTime());
}

ACTHCODE
emlSynthesis::proceed()            // proceed with HTML synthesis
{
     ACTHCODE retval;

     if (!eUseJava) {
          return(ACTHNOTFND);
     }
     if ((m_usrPtr=ses->getUser()) == NULL)
     {
          return(ACTHNOANON);
     }
     if (m_usrPtr->hasKey(ahemlkey))
     {
         usaptr=GetAccPtr((CHAR *)m_usrPtr->userid());
         struct usracc *uptr=GetAccPtr(m_usrPtr->userid());
         switch (gmeUserOpen(uptr,&m_gmeuh)) {
         case GMERST:
               if (onsysn(m_usrPtr->userid(),1)) {
                   updaccu(uptr);
               }
         case GMEOK:
               LOG2("EML.emlSynthesis Open succeeded: this=%08lX h=%lu",this,m_gmeuh);
               break;
         default:
               LOG1("EML.emlSynthesis Open failed: this=%08lX",this);
               return(ACTHNOTFND);
         }
         setUserNum4AH(m_usrPtr->userid());
         if (sameas(ses->method(),"GET"))
         {
              retval=proceedGet();
         }
         else if (sameas(ses->method(),"POST"))
         {
              retval=proceedPost();
         }
         else
         {
              ses->setStatus("501 Not implemented");
              retval=ACTHDONE;
         }
          LOG2("EML.emlSynthesis closing: this=%08lX h=%lu",this,m_gmeuh);
         gmeUserClose(m_gmeuh);
         resetUserNum4AH(m_usrPtr->userid());
     }
     else
     {
          return( ACTHFORBID );
     }
     if ( retval == ACTHDONE && !m_slExempt )
     {
          streambuf *stbuf = bout.rdbuf();

          if ( stbuf->out_waiting() <= 0 )
          {
               bout << "/";
          }
     }
     return(retval);
}

VOID
emlSynthesis::abort()
{
     if (m_doDl) {
          gdlabt(m_usrPtr->userid(),tagbuf);
          m_doDl=FALSE;
     }
}

ACTHCODE
emlSynthesis::proceedGet()         // proceed synthesizing response to GET
{
     ACTHCODE retval=ACTHMORE;
     struct qscfg *qscptr;
     INT narg;

     if ((narg=ses->urlargc()) == 1 && strchr(ses->urlargv(0),'.') != NULL)
     {
          if (ses->getUser() == NULL)
          {
               retval=ACTHNOANON;
          }
          else if (sameto( "email.", ses->urlargv( 0 ) ))
          {
               if (m_dnfPtr == NULL)
               {
                    m_dnfPtr = new dnfHandler(mainMap,bout);
               }

               switch( m_dnfPtr->process() )
               {
                    case ARCHIVETYPE:
                    {
                              CHAR      agentStr[ 1024 ];
                              GBOOL     useJar = FALSE;

                              if (ses->header( "User-Agent", agentStr, sizeof( agentStr ) ))
                              {
                                   BrowserType type = getClientType( agentStr );
                                   int  ver = getClientVer( agentStr );

                                   if ((type == BROWSER_NETSCAPE) && (ver >= 4))
                                   {
                                        useJar = TRUE;
                                  }
                              }

                              if (useJar)
                              {
                                   bout << "jar";
                              }
                              else
                              {
                                   bout << "zip";
                              }
                         }
                         break;

                    case DNFEND:
                         retval = ACTHDONE;
                         break;
               }
          }
          else if (sameto( "ul", ses->urlargv( 0 ) ))
          {
               if (m_dnfPtr == NULL)
               {
                    m_dnfPtr = new dnfHandler(ulMap,bout);
               }

               switch( m_dnfPtr->process() )
               {
                    case TMPID:
                         getTmpId();
                         bout << m_tmpid;
                         break;

                    case DNFEND:
                         retval = ACTHDONE;
                         break;
               }
          }
          else if (sameto( "pop", ses->urlargv( 0 ) ))
          {
               if (m_dnfPtr == NULL)
               {
                    m_dnfPtr = new dnfHandler(popMap,bout);
               }

               switch( m_dnfPtr->process() )
               {
                    case TMPID:
                         getTmpId();
                         bout << m_tmpid;
                         break;

                    case DNFEND:
                         retval = ACTHDONE;
                         break;
               }
          }
          else
          {
               m_slExempt = TRUE;
               ostrstream ost;
               ost << PPFIX << ses->urlargv(0) << ends;
               ses->sndfile(ost.str());
               ost.rdbuf()->freeze(0);
               retval=ACTHDONE;
          }
     }
     else if (narg == 1) {
          if (sameas(ses->urlargv(0),"ulabort"))
          {
               CHAR tmpid[20];

               ses->param("tmpid",tmpid,sizeof(tmpid));
               messageAborted( ::atoul(tmpid) );
               retval = ACTHDONE;
          }
          else if (sameas(ses->urlargv(0),"prefs"))
          {
               qscptr=gmeUserGetQS(m_gmeuh);

               ASSERT(qscptr != NULL);

               qscptr->flags&P4NEWM ? bout << "1" : bout << "0";
               bout << "\t";
               qscptr->flags&GORTIN ? bout << "1" : bout << "0";
               bout << "\t";
               qscptr->flags&FORUM2 ? bout << "1" : bout << "0";
               bout << "\t";
               qscptr->flags&MSGQUO ? bout << "1" : bout << "0";
               bout << "\t";
               qscptr->flags&ALWQUO ? bout << "1" : bout << "0";
               bout << "\t";
               qscptr->flags&CLARPL ? bout << "1" : bout << "0";
               bout << "\t";
               qscptr->flags&CFWCMT ? bout << "1" : bout << "0";
               bout << "\t";
               qscptr->flags&ALWCMT ? bout << "1" : bout << "0";
               bout << endl;

               retval=ACTHDONE;
          }
          else if (sameas(ses->urlargv(0),"copymsg"))
          {
               if (m_dnfPtr == NULL)
               {
                    if (!getMsgParams())
                    {
                         bout << "Input Error" << endl;
                         retval=ACTHDONE;
                    }
               }
               else
               {
                    retval= dnf_copymsg();
               }
          }
          else if (sameas(ses->urlargv(0),"prefsave"))
          {

               CHAR afwd[MAXADR];
               INT rc;

               ses->param ("afid",afwd,MAXADR );

               if ((rc=setafwd(afwd)) != VALYES )
               {
                    gmeErrorHandler (rc,OP_VALIDATION,&bout);
               }
               retval=ACTHDONE;
          }
          else if (sameas(ses->urlargv(0),"afid"))
          {
               qscptr=gmeUserGetQS(m_gmeuh);
               ASSERT(qscptr != NULL);

               bout << qscptr->fwdee << endl;
               retval=ACTHDONE;
          }
          else if (sameas(ses->urlargv(0),"quick"))
          {
               struct qikdat qkd, *qkdptr;
               CHAR *qchptr;
               CHAR modentry[MAXADR];

               qkdptr=getqik(&qkd,(CHAR *)m_usrPtr->userid());

               if (ses->param("delete",modentry,MAXADR))
               {
                    for (INT i = 0 ; i < MAXQIK ; i++)
                    {
                         if (qkdptr->idx[i] != NOIDX)
                         {
                              qchptr=&qkdptr->list[qkdptr->idx[i]];
                              if (sameas(qchptr,modentry))
                              {
                                   delqik(i,qkdptr);
                                   savqik(qkdptr);
                                   break;
                              }
                         }
                    }
               }
               else if (ses->param("add",modentry,MAXADR))
               {
                    for (INT i = 0 ; i < MAXQIK ; i++)
                    {
                         if (qkdptr->idx[i] == NOIDX)
                         {
                              insqik(i,modentry,qkdptr);
                              savqik(qkdptr);
                              break;
                         }
                    }
               }
               else
               {
                    for (INT i= 0 ; i < MAXQIK ; i++)
                    {
                         if (qkdptr->idx[i] != NOIDX)
                         {
                              qchptr=&qkdptr->list[qkdptr->idx[i]];
                              bout << qchptr << "\t";
                         }
                    }
                    bout << endl;
               }
               retval=ACTHDONE;
          }
          else if (sameas(ses->urlargv(0),"distlist"))
          {
                CHAR lstnam[DLNMSZ];
                CHAR lstkey[KEYSIZ];
                SHORT surcharge, *surptr;
                surptr=&surcharge;
                CHAR tadrbuf[MAXADR];
                CHAR dist[DLNMSZ];
                CHAR distkey[KEYSIZ];
                CHAR distchg[10];
                INT rc;

                setmem(mywrkarea,sizeof(mywrkarea),0);
                inigmerq(mywrkarea);
                if (ses->param("addentry",tadrbuf,MAXADR))
                {
                     ses->param("listname",dist,DLNMSZ);
                     if ((rc=edtslst(mywrkarea,dist)) == GMEOK)
                     {
                          if ((rc=addslst(mywrkarea,tadrbuf)) != GMEOK)
                          {
                               gmeErrorHandler(rc,OP_GENERIC,&bout);
                          }
                          clsgmerq(mywrkarea);
                     }
                     else
                     {
                          gmeErrorHandler(rc,OP_GENERIC,&bout);
                     }
                }
                else if (ses->param("createdist",dist,DLNMSZ))
                {
                     ses->param("createkey",distkey,KEYSIZ);
                     ses->param("createchg",distchg,10);
                     if (distchg[0] == '\0')
                     {
                          distchg[0] == '0';
                     }
                     if (!alldgs(distchg))
                     {
                         bout << "Invalid surcharge value.";
                         return (ACTHDONE);
                     }
                     switch((rc=newslst(mywrkarea,dist,distkey,::atoul(distchg))))
                     {
                     case GMEOK:
                          clsgmerq(mywrkarea);
                          break;
                     default:
                          gmeErrorHandler(rc,OP_GENERIC,&bout);
                     }
                }
                else if (ses->param("deldist",dist,DLNMSZ))
                {
                     switch((rc=delslst(dist)))
                     {
                     case GMEOK:
                          break;
                     default:
                          gmeErrorHandler(rc,OP_GENERIC,&bout);
                     }
                }
                else if (ses->param("listname",lstnam,DLNMSZ))
                {
                     if (getslst(lstnam,lstkey,surptr) == GMEOK)
                     {
                          if (m_usrPtr->hasKey(lstkey))
                          {
                               if (edtslst(mywrkarea,lstnam) == GMEOK &&
                                   rstlstp(mywrkarea) == GMEOK) {
                                    while (nxtsys(mywrkarea,tadrbuf))
                                    {
                                         bout << tadrbuf << "\t";
                                    }
                                    clsgmerq(mywrkarea);
                               }
                               bout << endl;
                          }
                     }
                }
                else
                {
                     lstnam[0]='@';
                     while (nxtslst(lstnam,lstkey,surptr) == GMEOK)
                     {
                          if (m_usrPtr->hasKey(lstkey))
                          {
                              bout << lstnam << "\t";
                          }
                     }
                     bout << endl;
                }
                retval=ACTHDONE;
           }
           else if (sameas(ses->urlargv(0),"access"))
           {

                m_usrPtr->hasKey(emlkey) ? bout << "1" : bout << "0";
                bout << "\t";
                m_usrPtr->hasKey(eatkey) ? bout << "1" : bout << "0";
                bout << "\t";
                m_usrPtr->hasKey(rrrkey) ? bout << "1" : bout << "0";
                bout << "\t";
                m_usrPtr->hasKey(prikey) ? bout << "1" : bout << "0";
                bout << "\t";
                m_usrPtr->hasKey(qikkey) ? bout << "1" : bout << "0";
                bout << "\t";
                m_usrPtr->hasKey(massky) ? bout << "1" : bout << "0";
                bout << "\t";
                m_usrPtr->hasKey(edstky) ? bout << "1" : bout << "0";
                bout << "\t";

                retval = ACTHDONE;

           }
           else if (sameas(ses->urlargv(0),"exporters"))
           {
                if (expavl)
                {
                     const struct expinfo *exptr;
                     for (INT i=0 ; i < numexp() ; i++)
                     {
                          exptr=expinf(i);
                          if (m_usrPtr->hasKey(exptr->wrtkey))
                          {
                               bout << exptr->prefix << "\t";
                               bout << exptr->name << "\t";
                               bout << exptr->desc << "\t";
                               bout << exptr->exmp << "\t";
                               bout << exptr->wrtkey << "\t";
                               bout << exptr->attkey << "\t";
                               bout << exptr->rrrkey << "\t";
                               bout << exptr->prikey << "\t";
                               exptr->flags&EXPATT ? bout << "1" : bout << "0";
                               bout << "\t";
                               exptr->flags&EXPRRR ? bout << "1" : bout << "0";
                               bout << "\t";
                               exptr->flags&EXPPRI ? bout << "1" : bout << "0";
                               bout << endl;
                          }
                     }
                }
                retval=ACTHDONE;
          }
          else if (sameas(ses->urlargv(0),"xrf"))
          {
               CHAR tempid[UIDSIZ];
               CHAR *uidp;

               tempid[ 0 ] = '\0';

               ses->param("partid",tempid,UIDSIZ);
               xrfptr = new acthUserXrf(tempid,10);
               while ((uidp=xrfptr->getmatch()) != NULL)
               {
                    bout << uidp << endl;
               }
               retval=ACTHDONE;
          }
          else if (sameas(ses->urlargv(0),"himsgid"))
          {
               bout << himsgid() << endl;
               retval=ACTHDONE;
          }
          else if (sameas(ses->urlargv(0),"forwardmsg"))
          {

               if (m_dnfPtr == NULL)
               {
                    if (!getMsgParams())
                    {
                         bout << "Input Error" << endl;
                         retval=ACTHDONE;
                    }
               }
               else
               {
                    retval= dnf_forwardmsg();
               }
          }
          else if (sameas(ses->urlargv(0),"delmsg"))
          {

               if (m_dnfPtr == NULL) {
                    if (!getMsgParam())
                    {
                         bout << "Request contained invalid parameters" << endl;
                         retval=ACTHDONE;
                    }
               }
               else
               {
                    retval = dnf_delmsg();
               }
          }
          else if (sameas(ses->urlargv(0),"extheaderinf"))
          {

               if ( m_dnfPtr == NULL)
               {
                    if ( !getMsgParam())
                    {
                         bout << "Request contained invalid parameters" << endl;
                         retval=ACTHDONE;
                    }
               }
               else
               {
                    retval = dnf_getExtHeaderInfo();
               }

          }
          else if (sameas(ses->urlargv(0),"getheaders"))
          {
               if (m_dnfPtr == NULL)
               {
                    CHAR msgid[10];
                    ses->param("msgid",msgid,10);
                    if (msgid[0] == '-' && msgid[1] == '1')
                    {
                         m_savMsgId=firstnew((CHAR *)m_usrPtr->userid(),EMLID);
                    }
                    else
                    {
                         m_savMsgId=atol(msgid);
                    }
                    m_dnfPtr = new dnfHandler(emlCycleMap,bout);
               }
               else
               {
                    retval=dnf_ReadMsgs();
               }
          }
          else
          {
               retval=ACTHNOTFND;
          }
     }
     else if (narg == 3)
     {
          if (sameas(ses->urlargv(0),"dl"))
          {
               CHAR *midptr = (CHAR *)ses->urlargv(1);

               if ( m_dnfPtr == NULL )
               {
                    m_slExempt = TRUE;

                    if ( alldgs(midptr) )
                    {
                         m_dnfPtr = new dnfHandler ( emlCycleMap , bout );
                    }
                    else
                    {
                         retval = ACTHDONE;
                    }
               }
               else
               {
                    retval = dnf_downloadAtt(atol(midptr));
               }
          }
          else if (sameas(ses->urlargv(0),"ReadMsg"))
          {
               if (alldgs((CHAR *)ses->urlargv(1)) &&
                   alldgs((CHAR *)ses->urlargv(2)))
               {
                    if (m_dnfPtr == NULL)
                    {
                         m_dnfPtr = new dnfHandler(emlCycleMap,bout);
                    }
                    else
                    {
                         retval=dnf_ReadaMsg(atoi(ses->urlargv(1)),
                                             atoi(ses->urlargv(2)));
                    }
               }
               else
               {
                    retval=ACTHDONE;
               }
          }
          else
          {
               retval=ACTHNOTFND;
          }
     }
     else
     {
          m_slExempt = TRUE;
          ses->redirect( "/email/index.htm" );
          retval = ACTHDONE;
     }
     return(retval);
}

ACTHCODE
emlSynthesis::proceedPost()        // proceed synthesizing response to POST
{
     ACTHCODE retval=ACTHMORE;
     CHAR to[MAXADR];
     CHAR rr[5];
     CHAR pri[5];
     CHAR mid[10];
     CHAR fid[10];

     if (ses->urlargc() >= 1)
     {
          if (sameas(ses->urlargv(0),"sendmsg"))
          {
               if (m_dnfPtr == NULL)
               {
                   getTmpId();
                   ses->param("to",to,MAXADR);
                   getTopicParam();
                   getCCParam();

                   setmem(mywrkarea,sizeof(mywrkarea),0);
                   inigmerq(mywrkarea);

                   ses->param("text",txtbuf2,TXTBUFLEN);
                   if (strlen(txtbuf2) > TXTLEN)
                   {
                        *(txtbuf2+(TXTLEN-1))='\0';
                   }
                   stlcpy(m_mhdrptr->from,(CHAR *)m_usrPtr->userid(),MAXADR);

                   stpans(txtbuf2);

                   if (valadr(mywrkarea,m_mhdrptr->from,to,EMLID)
                       == VALYES)
                   {

                        m_mhdrptr->forum=EMLID;

                        stlcpy(m_mhdrptr->to,to,MAXADR);

                        if (m_topic != NULL)
                        {
                             stlcpy(m_mhdrptr->topic,stpans(m_topic),TPCSIZ);
                        }

                        ses->param("rr",rr,5);

                        if ( rr[0] != '\0' )
                        {
                              if ( !validateRR(to))
                              {
                                  return ( ACTHDONE );
                              }
                        }

                        ses->param("pri",pri,5);

                        if ( pri[0] != '\0')
                        {
                              if ( !validatePri(to))
                              {
                                  return ( ACTHDONE );
                              }
                        }

                        m_dnfPtr = new dnfHandler(emlCycleMap,bout);
                   }
                   else
                   {
                        bout << "The recipient address is invalid.";
                        retval=ACTHDONE;
                   }
               }
               else
               {
                    retval=dnf_sendmsg();
               }
          }
          else if (sameas(ses->urlargv(0),"replymsg"))
          {
               if (m_dnfPtr == NULL)
               {
                    getTmpId();
                    ses->param("msgid",mid,10);
                    ses->param("forum",fid,10);

                    if (mid[0] == '\0' || !alldgs(mid))
                    {
                         bout << "Request contained invalid parameters" << endl;
                         return(ACTHDONE);
                    }
                    else
                    {
                         m_savMsgId=atol(mid);
                    }

                    if (fid[0] == '\0' || !alldgs(fid))
                    {
                         bout << "Request contained invalid parameters" << endl;
                         return(ACTHDONE);
                    }
                    else
                    {
                         m_savFid=atol(fid);
                    }

                    getTopicParam();

                    ses->param("rr",rr,5);

                    if ( rr[0] != '\0' )
                    {

                         m_rrFlag = TRUE;

                    }

                    ses->param("pri",pri,5);

                    if ( pri[0] != '\0' )
                    {

                         m_priFlag = TRUE;

                    }

                    getCCParam();
                    ses->param("text",txtbuf2,TXTBUFLEN);

                    if (strlen(txtbuf2) > TXTLEN)
                    {
                         *(txtbuf2+(TXTLEN-1))='\0';
                    }

                    stpans ( txtbuf2 );
                    m_dnfPtr = new dnfHandler(emlCycleMap,bout);

               }
               else
               {
                    retval=dnf_replymsg();
               }
          }
          else if (sameas(ses->urlargv(0),"attach"))
          {
               if (m_dnfPtr == NULL)
               {
                    if (ses->urlargc() > 1)
                    {
                         m_tmpid = ::atoul( ses->urlargv( 1 ) );
                    }

                    if (attachInProgress( m_tmpid ))
                    {
                         m_dnfPtr = new dnfHandler( inProgressMap, bout );
                         m_attaching = FALSE;
                    }
                    else
                    {
                         m_httpUp = new httpUpload( ses );

                         char      tmpname[ 20 ];
                         sprintf( tmpname, "%lu", m_tmpid );

                         if (startFile( m_tmpid, tmpname ))
                         {
                              m_dnfPtr = new dnfHandler( uploadMap, bout );
                              m_httpUp->setFile( getFile( m_tmpid ) );
                              ses->setStatus( "200 OK" );
                              bout << "<html><head><title>File Upload</title></head><body>\n";
                              bout.flush();
                              m_attaching = TRUE;
                         }
                    }

                    if (m_dnfPtr == NULL)
                    {
                         retval = ACTHNOTFND;
                    }
               }
               else if (m_attaching)
               {
                    retval = dnf_attach();
               }
               else
               {
                    retval = dnf_inProgress();
               }
          }
          else
          {
               retval=ACTHNOTFND;
          }

     }
     else
     {
          m_slExempt=TRUE;
          ses->redirect( "/email/index.htm" );
          retval = ACTHDONE;
     }
     return(retval);
}

ACTHCODE
emlSynthesis::dnf_ReadMsgs()        // Sequentially read through messages
{
     ACTHCODE retval=ACTHMORE;
     INT rc;
     const struct fordef *finfptr;

     switch (m_dnfPtr->process())
     {
     case DNFBEGIN:               // initialize the read context
          setmem(mywrkarea,sizeof(mywrkarea),0);
          inigmerq(mywrkarea);
          inictx(mywrkarea,(CHAR *)m_usrPtr->userid(),ESQTOU,EMLID,m_savMsgId,0);
          break;
     case DNFROWBEGIN:
          switch ((rc=nextmsg(mywrkarea,m_mhdrptr,txtbuf)))
          {
          case GMEAGAIN:
               break;
          case GMEOK:
               bout << m_mhdrptr->msgid << "\t" << m_mhdrptr->from << "\t" <<
               m_mhdrptr->to << "\t";
               bout << getHistory() << "\t";
               bout << getAttName() << "\t";
               bout << getDate() << "\t";
               bout << getTime() << "\t";
               bout << getTopic() << "\t";
               bout << m_mhdrptr->forum << "\t";
               if (m_mhdrptr->forum != EMLID
               && (finfptr=getdefp(m_mhdrptr->forum)) != NULL) {
                    bout << finfptr->name;
               }
               else {
                    bout << "EMAIL";
               }
               bout << "\t";
               m_mhdrptr->flags&PRIMSG ? bout << "1" : bout << "0";
               bout << "\t";
               m_mhdrptr->flags&RECREQ ? bout << "1" : bout << "0";
               bout << endl;
               m_savMsgId=m_mhdrptr->msgid;
               break;
          case GMENFND:
              m_doneFlg=TRUE;
               break;
          default:
               handleError(rc,OP_GENERIC);
               break;
          }
          break;
     case DNFROWEND:
          if (m_doneFlg)
          {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          clsgmerq(mywrkarea);
          retval=ACTHDONE;
          break;
     }
     return(retval);
}

ACTHCODE
emlSynthesis::dnf_ReadaMsg(        // Read a part. message
ULONG msgid,
GBOOL txohdr)
{
     ACTHCODE retval=ACTHMORE;
     INT rc;
     INT tmpsiz;

     switch (m_dnfPtr->process())
     {
     case DNFBEGIN:               // initialize the read context
          setmem(mywrkarea,sizeof(mywrkarea),0);
          inigmerq(mywrkarea);
          inictx(mywrkarea,(CHAR *)m_usrPtr->userid(),ESQTOU,EMLID,msgid,0);
          break;
     case DNFROWBEGIN:
          if (!m_gotText)
          {
              switch ((rc=readmsg(mywrkarea,m_mhdrptr,txtbuf))) {
              case GMEAGAIN:
                   break;             // cycle
              case GMEOK:             // got the message!
                   if (txohdr)
                   {
                        m_gotText=TRUE;
                   }
                   else
                   {
                        bout << m_mhdrptr->msgid << "\t" << m_mhdrptr->from << "\t" <<
                        m_mhdrptr->to << "\t";
                        bout << getHistory() << "\t";
                        bout << getAttName() << "\t";
                        bout << getDate() << "\t";
                        bout << getTime() << "\t";
                        bout << getTopic() << endl;
                        m_doneFlg=TRUE;
                   }
                   break;
              default:
                   gmeErrorHandler(rc,OP_GENERIC,&bout);
                   m_doneFlg=TRUE;
                   break;
              }
          }
          else
          {
               tmpsiz=ses->sndrsp(txtbuf+m_savoutsz);
               m_savoutsz+=tmpsiz;
               if (m_savoutsz >= strlen(txtbuf))
               {
                    m_doneFlg=TRUE;
               }
          }
          break;
     case DNFROWEND:
          if (m_doneFlg)
          {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          rc=markread(mywrkarea,m_mhdrptr,txtbuf);
          if (rc != GMEAGAIN) {
                gmeErrorHandler(rc,OP_GENERIC,&bout);
                clsgmerq(mywrkarea);
                retval=ACTHDONE;
          }
          break;
     }
     return(retval);
}


ACTHCODE
emlSynthesis::dnf_getExtHeaderInfo()       // Get Extended Header Info
{

     ACTHCODE retval=ACTHMORE;
     INT rc;
     INT tmpsiz;


     switch (m_dnfPtr->process()) {
     case DNFBEGIN:
          setmem(mywrkarea,sizeof(mywrkarea),0);
          inigmerq(mywrkarea);
          inictx(mywrkarea,(CHAR *)m_usrPtr->userid(),ESQTOU,EMLID,m_savMsgId,0);
          break;
     case DNFROWBEGIN:

          switch ((rc=readmsg(mywrkarea,m_mhdrptr,txtbuf)))
          {

          case GMEAGAIN:

                break;

          case GMEOK:
                if ( exthdrptr == NULL )
                {
                     exthdrptr = gmeGetAppInfo();
                }
                tmpsiz=ses->sndrsp(exthdrptr+m_savoutsz);
                m_savoutsz+=tmpsiz;

                if (m_savoutsz >= strlen(exthdrptr))
                {
                    m_doneFlg=TRUE;
                }
                break;

          default:

                gmeErrorHandler(rc,OP_GENERIC,&bout);
                m_doneFlg=TRUE;
                break;

          }
          break;
     case DNFROWEND:
          if (m_doneFlg)
          {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          retval = ACTHDONE;
          break;
     }
     return(retval);
}

ACTHCODE
emlSynthesis::dnf_sendmsg()       // Send a message ("post" - not a reply)
{
     ACTHCODE retval=ACTHMORE;
     INT rc;

     switch (m_dnfPtr->process())
     {
     case DNFROWBEGIN:
          if (readyToSend( m_tmpid ))
          {
               switch( rc = sendMessage( m_tmpid ))
               {
                    case GMEAGAIN:
                         break;             // cycle
                    case GMEOK:
                         m_doneFlg=TRUE;
                         break;
                    default:
                         gmeErrorHandler(rc,OP_GENERIC,&bout);
                         m_doneFlg=TRUE;
                         break;
               }
          }
          else
          {
               storeMessageData( m_tmpid, FALSE, mywrkarea, txtbuf2, m_cclist, m_mhdrptr );
          }

          break;
     case DNFROWEND:
          if (m_doneFlg)
          {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          retval=ACTHDONE;
          break;
     }
     return(retval);
}

ACTHCODE
emlSynthesis::dnf_replymsg()        // Reply to a message
{
     ACTHCODE retval=ACTHMORE;
     INT rc;

     switch (m_dnfPtr->process()) {
     case DNFBEGIN:               // initialize the read context

          setmem(mywrkarea,sizeof(mywrkarea),0);
          inigmerq(mywrkarea);

          if (m_savFid == EMLID)
          {
               inictx(mywrkarea,(CHAR *)m_usrPtr->userid(),ESQTOU,EMLID,m_savMsgId,0);
          }
          else
          {
               inictx(mywrkarea,(CHAR *)m_usrPtr->userid(),FSQFOR,m_savFid,m_savMsgId,0);
          }
          break;
     case DNFROWBEGIN:
          if (!m_doReply)
          {
               switch ((rc=readmsg(mywrkarea,m_mhdrptr,txtbuf)))
               {
               case GMEAGAIN:
                    break;             // cycle
               case GMEOK:

                    stlcpy(m_mhdrptr->to,m_mhdrptr->from,MAXADR);
                    stlcpy(m_mhdrptr->from,(CHAR *)m_usrPtr->userid(),MAXADR);
                    if (m_topic != NULL)
                    {
                         stlcpy(m_mhdrptr->topic,m_topic,TPCSIZ);
                    }

                    if (valadr(mywrkarea,m_mhdrptr->from,m_mhdrptr->to,EMLID) ==
                        VALYES) {

                        if ( m_rrFlag )
                        {

                             if ( !validateRR(m_mhdrptr->to))
                             {

                                  return ( ACTHDONE );

                             }
                        }

                        if ( m_priFlag )
                        {

                             if ( !validatePri(m_mhdrptr->to))
                             {
                                  return ( ACTHDONE );
                             }
                        }

                        m_doReply=TRUE;
                    }
                    else
                    {
                         bout << "Validation error" << endl;
                         return(ACTHDONE);
                    }
                    break;
               default:
                    gmeErrorHandler(rc,OP_GENERIC,&bout);
                    m_doneFlg=TRUE;
                    break;
               }
          }
          else
          {
               if (readyToSend( m_tmpid ))
               {

                    switch (rc = sendMessage( m_tmpid ))
                    {
                         case GMEAGAIN:
                              break;
                         case GMEOK:
                              m_doneFlg=TRUE;
                              break;
                         default:
                              gmeErrorHandler(rc,OP_GENERIC,&bout);
                              m_doneFlg=TRUE;
                              break;
                    }
               }
               else
               {
                    storeMessageData( m_tmpid, TRUE, mywrkarea, txtbuf2, m_cclist, m_mhdrptr );
               }
          }
          break;
     case DNFROWEND:
          if (m_doneFlg)
          {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          retval=ACTHDONE;
          break;
     }
     return(retval);
}

ACTHCODE
emlSynthesis::dnf_forwardmsg()        // Forward Message
{
     ACTHCODE retval=ACTHMORE;
     INT rc;

     switch (m_dnfPtr->process()) {
     case DNFBEGIN:               // initialize the read context
          setmem(mywrkarea,sizeof(mywrkarea),0);
          inigmerq(mywrkarea);
          inictx(mywrkarea,(CHAR *)m_usrPtr->userid(),ESQTOU,EMLID,m_savMsgId,0);
          break;
     case DNFROWBEGIN:
          if (!m_doFwd) {
               switch ((rc=readmsg(mywrkarea,m_mhdrptr,txtbuf))) {
               case GMEAGAIN:
                    break;             // cycle
               case GMEOK:
                    if ((rc=vfwdadr(mywrkarea,(CHAR *)m_usrPtr->userid(),m_holdid,EMLID))
                         == VALYES) {
                         m_mhdrptr->forum=EMLID;
                         if (fnmxst(m_holdid+1) == NOIDX) {
                              stlcpy(m_mhdrptr->to,m_holdid,MAXADR);
                         }
                         m_doFwd=TRUE;
                    }
                    else {
                         handleError(rc,OP_VALIDATION);
                         m_doneFlg=TRUE;
                    }
                    break;
               default:
                    handleError(rc,OP_GENERIC);
                    m_doneFlg=TRUE;
                    break;
               }
          }
          else {
               rc=fwdmsg(mywrkarea,m_mhdrptr,txtbuf2);
               if (rc > GMEAGAIN) {
                    m_doneFlg=TRUE;
               }
               else if (rc < GMEAGAIN) {
                    handleError(rc,OP_GENERIC);
                    m_doneFlg=TRUE;
               }
          }
          break;
     case DNFROWEND:
          if (m_doneFlg) {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          clsgmerq(mywrkarea);
          retval=ACTHDONE;
          break;
     }
     return(retval);
}

ACTHCODE
emlSynthesis::dnf_delmsg()        // Delete Message
{
     ACTHCODE retval=ACTHMORE;
     INT rc;

     switch (m_dnfPtr->process()) {
     case DNFBEGIN:               // initialize the read context
          setmem(mywrkarea,sizeof(mywrkarea),0);
          inigmerq(mywrkarea);
          inictx(mywrkarea,(CHAR *)m_usrPtr->userid(),ESQTOU,EMLID,m_savMsgId,0);
          break;
     case DNFROWBEGIN:
          switch ((rc=delmsg(mywrkarea))) {
          case GMEAGAIN:
               break;
          case GMEOK:
               m_doneFlg=TRUE;
               break;
          default:
               handleError(rc,OP_GENERIC);
               m_doneFlg=TRUE;
               break;
          }
          break;
     case DNFROWEND:
          if (m_doneFlg) {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          clsgmerq(mywrkarea);
          retval=ACTHDONE;
          break;
     }
     return(retval);
}

ACTHCODE
emlSynthesis::dnf_copymsg()        // Copy a message
{
     ACTHCODE retval=ACTHMORE;
     INT rc;

     switch (m_dnfPtr->process())
     {
     case DNFBEGIN:               // initialize the read context

          setmem(mywrkarea,sizeof(mywrkarea),0);
          inigmerq(mywrkarea);
          inictx(mywrkarea,(CHAR *)m_usrPtr->userid(),ESQTOU,EMLID,m_savMsgId,0);
          break;
     case DNFROWBEGIN:
          if (!m_doCopy)
          {
               switch ((rc=readmsg(mywrkarea,m_mhdrptr,txtbuf)))
               {
               case GMEAGAIN:
                    break;             // cycle
               case GMEOK:
                    if (valadr(mywrkarea,(CHAR *)m_usrPtr->userid(),m_holdid,EMLID) == VALYES) {
                         stlcpy(m_mhdrptr->to,m_holdid,MAXADR);
                         if ( m_mhdrptr->flags&PRIMSG )
                         {

                              if ( !validatePri(m_holdid) )
                              {
                                   return ( ACTHDONE );
                              }

                         }

                         if ( m_mhdrptr->flags&(FILATT|FILIND))
                         {

                              if ((rc=valatt(mywrkarea,(CHAR *)m_usrPtr->userid(),m_holdid,
                                    EMLID)) != VALYES)
                              {

                                   gmeErrorHandler (rc,OP_VALIDATION,&bout);
                                   return ( ACTHDONE );
                              }

                         }

                         m_doCopy=TRUE;
                    }
                    else
                    {
                         bout << "Validation error!" << endl;
                         m_doneFlg=TRUE;
                    }
                    break;
               default:
                    gmeErrorHandler(rc,OP_GENERIC,&bout);
                    m_doneFlg=TRUE;
                    break;
               }
          }
          else {
               rc=copymsg(mywrkarea,m_mhdrptr,txtbuf);
               if (rc > GMEAGAIN) {
                    m_doneFlg=TRUE;
               }
               else if (rc < GMEAGAIN) {
                    gmeErrorHandler(rc,OP_GENERIC,&bout);
                    m_doneFlg=TRUE;
               }
          }
          break;
     case DNFROWEND:
          if (m_doneFlg)
          {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          clsgmerq(mywrkarea);
          retval=ACTHDONE;
          break;
     }
     return(retval);
}


ACTHCODE
emlSynthesis::dnf_downloadAtt(     // download an attachment
ULONG msgid)
{
     ACTHCODE retval=ACTHMORE;
     INT rc;

     switch (m_dnfPtr->process()) {
     case DNFBEGIN:                // initialize the read context
          setmem(mywrkarea,sizeof(mywrkarea),0);
          inigmerq(mywrkarea);
          inictx(mywrkarea,(CHAR *)m_usrPtr->userid(),ESQTOU,EMLID,msgid,0);
          break;
     case DNFROWBEGIN:
          switch ((rc=readmsg(mywrkarea,m_mhdrptr,txtbuf))) {
          case GMEAGAIN:
               break;             // cycle
          case GMEOK:             // got the message!
               if ((rc=tagatt(mywrkarea,m_mhdrptr,tagbuf)) == GMEOK) {
                    if (gdlstart(m_usrPtr->userid(),tagbuf)) {
                         ses->sndfile(dlname(m_mhdrptr));
                         m_doDl=TRUE;
                    }
                    else {
                         handleError(GMECRD,OP_GENERIC);
                    }
                    m_doneFlg=TRUE;
               }
               else {
                    handleError(rc,OP_GENERIC);
                    m_doneFlg=TRUE;
               }
               break;
          default:
               handleError(rc,OP_GENERIC);
               m_doneFlg=TRUE;
               break;
          }
          break;
     case DNFROWEND:
          if (m_doneFlg) {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          retval = ACTHDONE;
          break;
     }
     return(retval);
}

GBOOL
emlSynthesis::getMsgParam()     // Handle parameters
{
     CHAR mid[10];

     ses->param("msgid",mid,10);
     if (mid[0] != '\0' && alldgs(mid))
     {
          m_savMsgId=atol(mid);
          m_dnfPtr= new dnfHandler(emlCycleMap,bout);
          return(TRUE);
     }
     return(FALSE);
}

GBOOL
emlSynthesis::getMsgParams()     // Handle parameters
{
     CHAR mid[10];

     ses->param("msgid",mid,10);
     ses->param("to",m_holdid,MAXADR);
     if (mid[0] != '\0' && alldgs(mid))
     {
           m_savMsgId=atol(mid);
           m_dnfPtr= new dnfHandler(emlCycleMap,bout);
           return(TRUE);
     }
     return(FALSE);
}

VOID
emlSynthesis::getTmpId()           // get tmpid param
{
     CHAR idparam[ 20 ];

     if (ses->param( "tmpid", idparam, sizeof(idparam))) {
          m_tmpid = ::atoul( idparam );
     }
}

VOID
emlSynthesis::getCCParam()         // get cclist parameter
{
     ses->param("cclist",m_cclist,CCSIZ);

     if (m_cclist[0] == '0') {
          m_cclist[0]='\0';
     }
}

VOID
emlSynthesis::getTopicParam()      // get topic parameter
{
     ses->param("topic",m_topic,TPCSIZ);

     if (m_topic[0] == '\0') {
          return;
     }
     else if (sameas(m_topic,"(none)")) {  // no topic was specified
          m_topic[0]='\0';
     }
     else {
          stpans(m_topic);
     }
}

static
ULONG
atoul(                             // convert string to unsigned long
const CHAR *st)
{
     ULONG     result = 0;
     const CHAR *digits = st;

     while (isdigit( *digits ))
     {
          ULONG     thisChar = (ULONG)(*digits - '0');

          result = (result * 10) + thisChar;

          ++digits;
     }


     return( result );
}


ACTHCODE
emlSynthesis::dnf_inProgress()     // attachment-already-in-progress
{
     ACTHCODE result = ACTHMORE;

     switch( m_dnfPtr->process() )
     {
          case DNFEND:
               result = ACTHDONE;
               break;
     }

     return( result );
}


ACTHCODE
emlSynthesis::dnf_attach()         // proceed upload attachment
{
     ACTHCODE result = m_httpUp->proceed();

     if (result == ACTHDONE)
     {
          finishFile( m_tmpid );
          renameFile( m_tmpid, m_httpUp->getFileName() );

          if (m_httpUp->needIeAddon())
          {
               bout << "Need IE addon.";
          }
          else
          {
               bout << "<strong>" << m_httpUp->getFileName() << "</strong>"
                    << " (" << m_httpUp->getFileSize() << " bytes)<br>"
                    << "Uploaded successfully.\n";
          }

          bout << "<div align=right>"
               << "<FORM NAME=\"closeform\">"
              << "<INPUT TYPE=\"button\" NAME=\"closer\" VALUE=\"Close\" onClick=\"window.close()\">"
               << "</FORM>"
               << "</div>\n";

          bout << "</body></html>\n";
     }

     return( result );
}

GBOOL
emlSynthesis::validateRR(          // validate return receipt
CHAR *to)
{
     if ( to != NULL && valrrr (mywrkarea,(CHAR *)m_usrPtr->userid(),
          to, EMLID ) == VALYES )
     {
          m_mhdrptr->flags|=RECREQ;
     }
     else
     {
          m_mhdrptr->flags&=~RECREQ;
     }
     return ( TRUE );
}

GBOOL
emlSynthesis::validatePri(         // validate priority
CHAR *to)
{

     if ( to != NULL && valpri (mywrkarea,(CHAR *)m_usrPtr->userid(),
          to, EMLID ) == VALYES )
     {
          m_mhdrptr->flags|=PRIMSG;
     }
     else
     {
          m_mhdrptr->flags&=~PRIMSG;
     }

     return ( TRUE );
}

VOID
emlAgent::getMsgOpts()             // get Java msg opts
{

     HMCVFILE msg;

     msg=opnmsg("GALMSG.MCV");
     setmbk(msg);
     ahemlkey=stgopt(AHEMLKEY);
     rstmbk();
     clsmsg(msg);

}

VOID
emlAgent::getHTMLMsgOpts()         // get pure HTML msg options
{
     setmbk(gmeAHmbk);
     iPreference=tokopt(EPRFTYP,"html","java",NULL);
     bUseFrames=ynopt(EPRFFRM);
     iDefListCount=numopt(DFTLSTC,1,32767);
     iMaxListCount=numopt(MAXLSTC,1,32767);
     iTimeSlice=numopt(TIMSLC,1,1000);
     CHAR *mPtr;
     mPtr=stpans(getmsg(VALCCATT));
     valccatt=new CHAR[strlen(mPtr)+1];
     stlcpy(valccatt,mPtr,strlen(mPtr)+1);
     mPtr=stpans(getmsg(VALCCADR));
     valccadr=new CHAR[strlen(mPtr)+1];
     stlcpy(valccadr,mPtr,strlen(mPtr)+1);
     mPtr=stpans(getmsg(NOXHDR));
     noxhdr=new CHAR[strlen(mPtr)+1];
     stlcpy(noxhdr,mPtr,strlen(mPtr)+1);
     mPtr=stpans(getmsg(VALADR));
     valadress=new CHAR[strlen(mPtr)+1];
     stlcpy(valadress,mPtr,strlen(mPtr)+1);
     mPtr=stpans(getmsg(VALATT));
     valattach=new CHAR[strlen(mPtr)+1];
     stlcpy(valattach,mPtr,strlen(mPtr)+1);
     mPtr=stpans(getmsg(VALPRI));
     valpriority=new CHAR[strlen(mPtr)+1];
     stlcpy(valpriority,mPtr,strlen(mPtr)+1);
     mPtr=stpans(getmsg(VALRR));
     valrr=new CHAR[strlen(mPtr)+1];
     stlcpy(valrr,mPtr,strlen(mPtr)+1);
     mPtr=stpans(getmsg(ERINVFN));
     erinvfn=new CHAR[strlen(mPtr)+1];
     stlcpy(erinvfn,mPtr,strlen(mPtr)+1);
     mPtr=stpans(getmsg(ERPRFAT));
     erprfat=new CHAR[strlen(mPtr)+1];
     stlcpy(erprfat,mPtr,strlen(mPtr)+1);
     rstmbk();
     setmbk(efmbAH);
     iMaxCC=numopt(CSMAXCC,0,32767);
     rstmbk();
}

VOID
emlAgent::freeStgAllocs()          // free allocated string
{
     if ( ahemlkey != NULL )
     {
          free ( ahemlkey );
     }
}

const CHAR *
emlSynthesis::getTopic()           // fetch topic from header
{
     return ( m_mhdrptr->topic[0] != '\0' ? m_mhdrptr->topic : "(none)" );
}

const CHAR *
emlSynthesis::getAttName()         // fetch attachment name from header
{
     return ( m_mhdrptr->attname[0] != '\0' ? m_mhdrptr->attname : "(none)" );
}

const CHAR *
emlSynthesis::getHistory()         // fetch history from header
{
     return ( m_mhdrptr->history[0] != '\0' ? m_mhdrptr->history : "(none)" );
}

const CHAR *
emlSynthesis::getTime()            // fetch time from header
{
    return( nctime(m_mhdrptr->crtime) );
}

const CHAR *
emlSynthesis::getDate()            // fetch date from header
{
    return ( ::prndat(PRND_MMDYY,m_mhdrptr->crdate,0) );
}

VOID
emlSynthesis::handleError(         // handle GME Error
INT err,                           // error code
INT op)                            // operation type (GENERIC or VALIDATION)
{
     bout << gmeErrorHandler(err,op,NULL);
}


static VOID
handleError(                       // handle Error
emailCommon *ecPtr,                // common Email Class ptr
INT operation,                     // operation type (GENERIC or VALIDATION)
const CHAR *additionalErrorMsg)    // additional msg to tack on
{
     ASSERT(ecPtr != NULL);

     CHAR *msgBuf=NULL;
     if (additionalErrorMsg != NULL) {
          msgBuf=new CHAR[strlen(additionalErrorMsg)+1];
          stlcpy(msgBuf,additionalErrorMsg,strlen(additionalErrorMsg)+1);
     }

     ecPtr->m_merr_message=gmeErrorHandler(ecPtr->m_merr_code,operation,NULL);
     if (msgBuf != NULL) {
          ecPtr->m_merr_message+=msgBuf;
          delete [] msgBuf;
     }
}

static GBOOL
isquoted(                          // does line start with quote symbol?
CHAR const * s)                    // pointer to start of line
{
     if (isalnum(*s)) {
          ++s;
          if (isalnum(*s)) {
               ++s;
          }
     }
     return(strchr("<>{}[]|:",*s) != NULL);
}

#ifdef EXTRA_LOGGING

static VOID
vlogmsg(                           /* output to log file                   */
CHAR const * fmt,
va_list ap)
{
     FILE * fp;

     if ((fp=fopen(LOGFILE,FOPAA)) != NULL) {
          fprintf(fp,"%s %s: ",ncdate(today()),nctime(now()));
          vfprintf(fp,fmt,ap);
          fprintf(fp,"\n");
          fclose(fp);
     }
}

static VOID
logmsg(                            /* output to log file                   */
CHAR const * fmt,
...)
{
     va_list ap;

     va_start(ap,fmt);
     vlogmsg(fmt,ap);
     va_end(ap);
}

#endif /* EXTRA_LOGGING */
