/*****************************************************************************/
/*
                                  public.c

For public access ...

Displays a list of messages in a folder.
Displays the contents of a message (header, body, links to attachments).
Displays a 'print-view' (more suitable for printing) of a message.
Displays the raw message (header+body, or header alone).

Of course with limitations and in a format that is suitable for public access!


COPYRIGHT
---------
Copyright (C) 2005-2025 Mark G.Daniel
This program, comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it under the
conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or any later version.


VERSION HISTORY
---------------
04-NOV-2014  MGD  bugfix; PublicPageBegin() FORM_ACCEPT_CHARSET
09-JUN-2013  MGD  PublicFooter() and [public-footer]
19-JUL-2006  MGD  PublicMessageFolderList() user optional message ordering
27-APR-2006  MGD  bugfix; PublicMessageRequest() detect [search] button
03-APR-2005  MGD  significant rework to rationalise public and private
                  significant changes to support public wildcard folders
30-MAR-2006  MGD  PublicMessagePage() precede each message part/attachment
                  with an anchor/link for right-click browser save-as
28-FEB-2006  MGD  major refinements to public access
01-FEB-2005  MGD  initial
*/

/*****************************************************************************/

#ifdef SOYMAIL_VMS_V7
#undef _VMS_V6_SOURCE
#define _VMS_V6_SOURCE
#undef __VMS_VER
#define __VMS_VER 70000000
#undef __CRTL_VER
#define __CRTL_VER 70000000
#endif

#pragma nomember_alignment

/* standard C header files */
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* VMS related header files */
#include <descrip.h>
#include <mailmsgdef.h>
#include <ssdef.h>
#include <stsdef.h>

/* application header file */
#include "soymail.h"
#include "attach.h"
#include "callmail.h"
#include "cgilib.h"
#include "compose.h"
#include "config.h"
#include "html.h"
#include "mainmenu.h"
#include "other.h"
#include "public.h"
#include "message.h"
#include "request.h"

/* can't get the include dependencies settled (this'll do in the interim) */
int ComposeWrapAt (int, USER_OPTIONS*);

#define FI_LI "PUBLIC", __LINE__

/* global storage */

/* external storage */

extern BOOL  Debug,
             WatchEnabled;

extern int  VmsVersion;

extern char  *CgiEnvironmentPtr;

extern char  CurrentVmsTimeString[],
             DocType[],
             SoftwareCopy[],
             SoftwareEnv[],
             SoftwareId[],
             SoftwareVn[];

extern CONFIG_DATA  SoyMailConfig;
extern REQUEST_DATA  RequestData;
extern VMS_MAIL_USER  VmsMailUser;

/* ad hoc prototypes */
int lib$day_of_week(__unknown_params);
int sys$fao(__unknown_params);

/****************************************************************************/
/*
Parse the buttons associated with the public folder message list.
*/ 

void PublicFolderRequest (REQUEST_DATA *rdptr)

{
   int  cnt, hash;
   char  *cptr, *sptr, *zptr,
         *MsgRangeListPtr;
   char  MsgBtnString [32],
         MsgCbxString [32],
         MsgHashString [32];
   VMS_MAIL_USER  *muptr;
   USER_OPTIONS  *uoptr;
   REQUEST_DATA  *sdptr;

   /*********/
   /* begin */
   /*********/

   if (WatchEnabled) WatchThis (FI_LI, "PublicFolderRequest()");

   muptr = &VmsMailUser;
   uoptr = &rdptr->UserOptions;
   sdptr = (REQUEST_DATA*)rdptr->StateDataPtr;
 
   rdptr->MassageMessage = uoptr->MassageRead;

   /* the string containing comma-separated message id dot hashes */
   CGIVAR (MsgRangeListPtr, "FORM_MSG_RANGE_LIST");

   /*****************/
   /* search button */
   /*****************/

   CGIVARNULL (cptr, "FORM_MAIN_BTN");
   if (cptr && *cptr)
   {
      /* searching can be disabled */
      rdptr->SearchData.InProgress = FALSE;
      if (LangSame ("search", cptr) ||
          LangSame ("search_new", cptr))
      {
         if (SearchPageRequest (rdptr)) return;
      }
   }

   /*****************************/
   /* individual message button */
   /*****************************/

   CGIVARNULL (cptr, "FORM_MSG_BTN");
   if (cptr)
   {
      rdptr->MessageId = atol(cptr);
      rdptr->MessageHash = MessageRangeString (rdptr->MessageId,
                                               MsgRangeListPtr);
      PublicMessagePage (rdptr);
      return;
   }

   /************************/
   /* popup message button */
   /************************/

   CGIVARNULL (cptr, "FORM_MSG_BTN_POPUP");
   if (cptr && (cnt = atol(cptr)))
   {
      rdptr->MessageId = cnt;
      rdptr->MessageHash = MessageRangeString (rdptr->MessageId,
                                               MsgRangeListPtr);
      PublicMessagePage (rdptr);
      return;
   }

   /*****************/
   /* message range */
   /*****************/

   /* the range button or range 'onchange=' */
   CGIVARNULL (cptr, "FORM_RANGE_MSGS");
   if (!cptr) CGIVARNULL (cptr, "FORM_RANGE_LIST_CHANGE");
   if (cptr && *cptr) CGIVARNULL (cptr, "FORM_RANGE_LIST");
   /* also check that the range list is not empty */
   if (cptr && *cptr)
   {
      rdptr->RangeIdStart = atoi(cptr);
      while (*cptr && *cptr != '-') cptr++;
      if (*cptr)
      {
         cptr++;
         rdptr->RangeIdCount = atoi(cptr);
         rdptr->RangeIdCount -= rdptr->RangeIdStart - 1;
      }
      else
         rdptr->RangeIdCount = uoptr->MessagesPerPage;
      rdptr->RangeIdVector = +1;
      PublicFolderPage (rdptr);
      return;
   }

   /******************************/
   /* previous range of messages */
   /******************************/

   CGIVARNULL (cptr, "FORM_RANGE_PREV");
   if (cptr)
   {
      /* get the lowest id in the list and start one less than that */
      rdptr->RangeIdStart = MessageRangeString (-1, MsgRangeListPtr);
      if (rdptr->RangeIdStart <= 1)
      {
         rdptr->RangeIdStart = sdptr->RangeIdStart;
         StatusMessage (FI_LI, 1, LangFor("no_more_messages"));
      }
      else
         rdptr->RangeIdStart--;
      rdptr->RangeIdCount = uoptr->MessagesPerPage;
      rdptr->RangeIdVector = -1;
      PublicFolderPage (rdptr);
      return;
   }

   /**************************/
   /* next range of messages */
   /**************************/

   CGIVARNULL (cptr, "FORM_RANGE_NEXT");
   if (cptr)
   {
      /* the highest id is always the first one in the string */
      rdptr->RangeIdStart = atoi(MsgRangeListPtr) + 1;
      if (rdptr->RangeIdStart >= sdptr->FolderMessageCount)
      {
         /* just go back to the start of whatever we had before */
         rdptr->RangeIdStart = sdptr->RangeIdStart;
         StatusMessage (FI_LI, 1, LangFor("no_more_messages"));
      }
      rdptr->RangeIdCount = uoptr->MessagesPerPage;
      rdptr->RangeIdVector = +1;
      PublicFolderPage (rdptr);
      return;
   }

   /******************************/
   /* default to latest messages */
   /******************************/

   rdptr->RangeIdStart = RANGE_MOST_RECENT;
   rdptr->RangeIdCount = uoptr->MessagesPerPage;

   PublicFolderPage (rdptr);
}

/****************************************************************************/
/*
Parse the buttons from the public message display page.
*/ 

void PublicMessageRequest (REQUEST_DATA *rdptr)

{
   static char  SingleMessageList [32];

   char  *cptr, *sptr, *zptr;
   USER_OPTIONS  *uoptr;
   REQUEST_DATA  *sdptr;
   VMS_MAIL_USER  *muptr;

   /*********/
   /* begin */
   /*********/

   if (WatchEnabled) WatchThis (FI_LI, "PublicMessageRequest()");

   muptr = &VmsMailUser;
   uoptr = &rdptr->UserOptions;
   sdptr = (REQUEST_DATA*)rdptr->StateDataPtr;

   rdptr->MassageMessage = uoptr->MassageRead;

   /*****************/
   /* search button */
   /*****************/

   CGIVARNULL (cptr, "FORM_MAIN_BTN");
   if (cptr && *cptr)
   {
      /* searching can be disabled */
      rdptr->SearchData.InProgress = FALSE;
      if (LangSame ("search", cptr) ||
          LangSame ("search_new", cptr))
      {
         if (SearchPageRequest (rdptr)) return;
      }
   }

   if (rdptr->PublicWildcard)
   {
      /*******************/
      /* wildcard public */
      /*******************/

      CGIVARNULL (cptr, "FORM_FOLDER_LIST_CHANGE");
      if (cptr && *cptr == 't')
      {
         PublicFolderRequest (rdptr);
         return;
      }

      CGIVARNULL (cptr, "FORM_MAIN_BTN");
      if (cptr && *cptr)
      {
         rdptr->SearchData.InProgress = FALSE;
         if (LangSame ("open", cptr))
         {
            PublicFolderRequest (rdptr);
            return;
         }
      }
   }

   /****************************/
   /* previous/at/next message */
   /****************************/

   CGIVARNULL (cptr, "FORM_MSG_PREV");
   if (cptr)
   {
      rdptr->MessageId = sdptr->MessageId;
      if (rdptr->MessageId > 1)
         rdptr->MessageId--;
      else
         StatusMessage (FI_LI, 1, LangFor("no_more_messages"));
      rdptr->MessageHash = 0;
      PublicMessagePage (rdptr);
      return;
   }

   CGIVARNULL (cptr, "FORM_MSG_FOLDER_AT");
   if (cptr)
   {
      rdptr->RangeIdCount = uoptr->MessagesPerPage;
      for (rdptr->RangeIdStart = sdptr->FolderMessageCount;
           rdptr->RangeIdStart >= sdptr->MessageId;
           rdptr->RangeIdStart -= rdptr->RangeIdCount);
      rdptr->RangeIdStart++;
      if (rdptr->RangeIdStart < 1) rdptr->RangeIdStart = 1;
      PublicFolderPage (rdptr);
      return;
   }

   CGIVARNULL (cptr, "FORM_MSG_NEXT");
   if (cptr)
   {
      rdptr->MessageId = sdptr->MessageId;
      if (rdptr->MessageId < sdptr->FolderMessageCount)
         rdptr->MessageId++;
      else
         StatusMessage (FI_LI, 1, LangFor("no_more_messages"));
      rdptr->MessageHash = 0;
      PublicMessagePage (rdptr);
      return;
   }

   /********************/
   /* specific message */
   /********************/

   CGIVARNULL (cptr, "FORM_MSG_ID_HASH");
   if (cptr)
   {
      rdptr->MessageId = atol(cptr);
      while (*cptr && *cptr != '.') cptr++;
      if (*cptr) cptr++;
      if (!*cptr) ErrorExit (SS$_BUGCHECK, FI_LI);;
      rdptr->MessageHash = atol(cptr);
   }

   /*****************/
   /* message parts */
   /*****************/

   CGIVARNULL (cptr, "FORM_PART_BTN");
   if (cptr)
   {
      zptr = (sptr = rdptr->AttachmentName) + sizeof(rdptr->AttachmentName)-1;
      while (*cptr && sptr < zptr) *sptr++ = *cptr++;
      *sptr = '\0';
      /* if the attachment is successfully accessed then just finish up */
      if (MessagePart (rdptr)) return;
      PublicMessagePage (rdptr);
      return;
   }

   /************************/
   /* message read buttons */
   /************************/

   CGIVARNULL (cptr, "FORM_MSG_PRINT");
   if (!cptr) CGIVARNULL (cptr, "FORM_MSG_PRINT_POPUP");
   if (cptr)
   {
      if (MessagePrintView (rdptr)) return;
      PublicMessagePage (rdptr);
      return;
   }

   CGIVARNULL (cptr, "FORM_MSG_RAW");
   if (!cptr) CGIVARNULL (cptr, "FORM_MSG_RAW_POPUP");
   if (cptr)
   {
      if (MessageRawView (rdptr)) return;
      PublicMessagePage (rdptr);
      return;
   }

   CGIVARNULL (cptr, "FORM_MSG_HDR");
   if (!cptr) CGIVARNULL (cptr, "FORM_MSG_HDR_POPUP");
   if (cptr)
   {
      if (MessageHdrView (rdptr)) return;
      PublicMessagePage (rdptr);
      return;
   }

   /**************/
   /* HTML/plain */
   /**************/

   CGIVARNULL (cptr, "FORM_MSG_READ_PREF");
   if (cptr)
   {
      /* one is on, minus one is off, zero is not set! */
      if (LangSame ("message_read_html", cptr))
         rdptr->MessageReadPreference = OPTIONS_READ_PLAIN2_HTML1;
      if (LangSame ("message_read_plain", cptr))
         rdptr->MessageReadPreference = OPTIONS_READ_PLAIN1_HTML2;
      PublicMessagePage (rdptr);
      return;
   }

   /****************/
   /* message wrap */
   /****************/

   CGIVARNULL (cptr, "FORM_MSG_WRAP");
   if (cptr)
   {
      while (*cptr && !isdigit(*cptr)) cptr++;
      rdptr->MassageMessage = atoi(cptr);
      /* use the read preference from the previous request */
      rdptr->MessageReadPreference = sdptr->MessageReadPreference;
      PublicMessagePage (rdptr);
      return;
   }

   /*********************/
   /* message ID in URL */
   /*********************/

   PublicMessagePage (rdptr);
}

/*****************************************************************************/
/*
Generate the HTML for a public page (folder message list or message display).
*/

void PublicPageBegin
(
REQUEST_DATA *rdptr,
int ThisPageIdent
)
{
   static char  OperaChild0 [] = 
"<input type=\"hidden\" name=\"opera_child\" id=\"opera_child\" value=\"0\">\n",
                OperaChild1 [] =
"<input type=\"hidden\" name=\"opera_child\" id=\"opera_child\" value=\"1\">\n";

   char  *cptr,
         *OperaChildPtr,
         *UserNamePtr;
   USER_OPTIONS  *uoptr;
   REQUEST_DATA  *sdptr;
   VMS_MAIL_MSG  *vmptr;
   VMS_MAIL_USER  *muptr;

   /*********/
   /* begin */
   /*********/

   if (WatchEnabled) WatchThis (FI_LI, "PublicPageBegin()");

   uoptr = &rdptr->UserOptions;
   muptr = &VmsMailUser;
   vmptr = &muptr->VmsMailMsg;
   sdptr = (REQUEST_DATA*)rdptr->StateDataPtr;

   if (!rdptr->ThisPageIdent) rdptr->ThisPageIdent = ThisPageIdent;

   if (rdptr->CharSetPtr) CgiLibResponseSetCharset (rdptr->CharSetPtr);

   if (rdptr->PublicAuthorized)
      CgiLibResponseHeader (200, "text/html", "%s", rdptr->LoginSetCookiePtr);
   else
      CgiLibResponseHeader (200, "text/html");

   fprintf (stdout,
"%s\n\
<html>\n\
<head>\n\
%s\
<meta name=\"generator\" content=\"%s\">\n\
<meta name=\"environment\" content=\"%s\">\n\
<meta name=\"copyright\" content=\"%s - Apache-2.0 licensed\">\n\
<meta name=\"language\" content=\"%s %s\">\n",
            DocType,
            CgiLibXUACompatible(NULL),
            SoftwareEnv,
            CgiEnvironmentPtr,
            SoftwareCopy,
            LangFor("lang_name"),
            LangFor("lang_author"));

   /* used to support some of the enhanced functionality */
   SoyMailJavaScriptStuff (rdptr);

   SoyMailStyleStuff (rdptr, uoptr->Theme);

   OperaChildPtr = "";
   if (rdptr->UserAgent == SOY_USER_AGENT_OPERA)
   {
      OperaChildPtr = OperaChild0;
      if (!strcmp (rdptr->CgiRequestMethodPtr, "POST"))
      {
         CGIVARNULL (cptr, "FORM_OPERA_CHILD");
         if (!cptr || *cptr == '0') OperaChildPtr = OperaChild1;
      }
   }

   fprintf (stdout,
"<title>%s</title>\n\
</head>\n\
\n\
<body onload=\"refreshClock();\" \
onunload=\"clearWorking();\" \
onfocus=\"refreshSoyMailForm();\" onblur=\"refreshSoyMailForm();\">\n\
<form \
name=\"soymail_form\" \
id=\"soymail_form\" \
action=\"%s\" \
method=\"POST\" \
accept-charset=\"%s\" \
enctype=\"multipart/form-data\">\n\
%s\
\n\
<table width=\"100%%\" cellpadding=\"0\" cellspacing=\"5\" align=\"center\">\n\
<tr><td align=\"center\">\n\n",
            SoyMailPageTitle(rdptr),
            rdptr->FormAction,
            uoptr->ComposeCharSets[0] ? uoptr->ComposeCharSets : "utf-8",
            OperaChildPtr);
}

/*****************************************************************************/
/*
*/

void PublicPageEnd (REQUEST_DATA *rdptr)

{
   /*********/
   /* begin */
   /*********/

   if (WatchEnabled) WatchThis (FI_LI, "PublicPageEnd()");

   fprintf (stdout, "</td></tr>\n</table>\n\n");

   RequestPublicStateSave (rdptr);

   fputs ("</form>\n", stdout);
   StatTimer (TRUE);
   fputs ("</body>\n</html>\n", stdout);
}

/*****************************************************************************/
/*
Equvalent to the main menu panel in private access soyMAIL.
*/

void PublicPageTitle (REQUEST_DATA *rdptr)

{
   char  *cptr,
         *Title1Ptr,
         *Title2Ptr;

   /*********/
   /* begin */
   /*********/

   if (WatchEnabled) WatchThis (FI_LI, "PublicPageTitle()");

   fprintf (stdout,
"<!-- public title begin -->\n\
<table width=\"100%%\" cellpadding=\"1\" cellspacing=\"0\" \
align=\"center\" class=\"css_panel_1\">\n\
<tr><td>\n\
<table class=\"css_panel_2\" width=\"100%%\" align=\"center\" \
cellpadding=\"4\" cellspacing=\"2\">\n");

   fprintf (stdout,
"<tr>\n\
<td nowrap align=\"left\" valign=\"middle\" width=\"10%%\">&nbsp;&nbsp;");

   SoyMailLogo (rdptr);

   fprintf (stdout, "&nbsp;&nbsp;</td>\n");

   if (rdptr->PublicWildcard || SoyMailConfig.SearchEnabled)
      fprintf (stdout, "<td nowrap align=\"left\" valign=\"middle\">\n\n");

   if (rdptr->PublicWildcard)
   {
      FolderListInit (rdptr);
      FolderOpenSelect (rdptr);
   }

   if (SoyMailConfig.SearchEnabled)
      fprintf (stdout,
"<input class=\"css_button_panel_2\" type=\"submit\" \
name=\"main_btn\" value=\"%s\">&nbsp;\n",
              LangFor("search"));

   fprintf (stdout,
"<script language=\"JavaScript\">\
if (childWindow()) \
document.write(\'<input class=\"css_button_panel_2\" \
type=\"submit\" name=\"main_btn\" value=\"%s\" \
onclick=\"window.close()\">&nbsp;\\n\');\
</script>\n",
           LangFor("close"));

   if (rdptr->PublicAuthorized &&
       SoyMailConfig.LoginSecret)
   {
      if (SoyMailConfig.LogoutDisabled)
         fprintf (stdout,
"<input class=\"css_button_panel_2\" style=\"font-style:italic;\" \
type=\"submit\" id=\"main_btn_logout\" name=\"main_btn\" value=\"%s\" \
onclick=\"return false\">&nbsp;\n",
                  LangFor("logout"));
       else
         fprintf (stdout,
"<input class=\"css_button_panel_2\" \
type=\"submit\" name=\"main_btn\" value=\"%s\" \
onclick=\"return confirm(\'%s\')\">&nbsp;\n",
                  LangFor("logout"),
                  LANG_FOR_CONFIRM("login_confirm_logout"));
   }

   if (rdptr->PublicWildcard || SoyMailConfig.SearchEnabled)
      fprintf (stdout, "</td>\n");

   Title2Ptr = NULL;
   if (SoyMailConfig.PageTitle1)
   {
      Title1Ptr = SoyMailConfig.PageTitle1;
      if (rdptr->PublicAccessTitle[0])
         Title2Ptr = rdptr->PublicAccessTitle;
      else
      if (SoyMailConfig.PageTitle2)
         Title2Ptr = SoyMailConfig.PageTitle2;
   }
   else
   if (rdptr->PublicAccessTitle[0])
      Title1Ptr = rdptr->PublicAccessTitle;
   else
      Title1Ptr = rdptr->CgiPathInfoPtr;

   if (Title1Ptr && Title2Ptr)
      fprintf (stdout,
"<td align=\"middle\" width=\"90%%\" style=\"font-size:120%%;\">%s&nbsp;</td>\
<td align=\"right\" width=\"10%%\" style=\"font-size:120%%;\">%s&nbsp;</td>",
               Title1Ptr,
               Title2Ptr);
   else
      fprintf (stdout,
"<td align=\"right\" width=\"100%%\" style=\"font-size:120%%;\">%s&nbsp;</td>",
               Title1Ptr);

   fprintf (stdout,
"\n\
</tr>\n\
</table>\n\
</td></tr>\n\
</table>\n\
<!-- public title end -->\n\n");

}

/*****************************************************************************/
/*
Display the basic message folder and message list page.
*/

void PublicMessageFolderList (REQUEST_DATA *rdptr)

{
   int  cnt, idx, status;

   char  *cptr, *sptr, *zptr;
   char  FromBuffer [256],
         SubjBuffer [256];
   USER_OPTIONS  *uoptr;
   VMS_MAIL_MSG  *vmptr;
   VMS_MAIL_USER  *muptr;

   /*********/
   /* begin */
   /*********/

   if (WatchEnabled) WatchThis (FI_LI, "PublicMessageFolderList()");

   muptr = &VmsMailUser;
   uoptr = &rdptr->UserOptions;
   vmptr = &muptr->VmsMailMsg;

   fprintf (stdout,
"<p class=\"css_p06\">\
<table width=\"100%%\" cellpadding=\"1\" cellspacing=\"5\" \
align=\"center\" class=\"css_panel_1\">\n\
<tr>\n");

   /******************/
   /* message ranges */
   /******************/

   MessageRangeSelect (rdptr);

   if (!vmptr->MessageSelectedCount)
   {
      /****************/
      /* empty folder */
      /****************/

      rdptr->RangeIdStart = rdptr->RangeIdCount = 0;

      fprintf (stdout, "<td></td></tr></table>\n");

      MessageListFooter ();

      fprintf (stdout,
"</td></tr>\n\
</table>\n\
<!-- public message list end -->\n\n");

      return;
   }

   /********************/
   /* list of messages */
   /********************/

   fprintf (stdout,
"<tr><td colspan=\"2\">\n\
<table cellpadding=\"0\" cellspacing=\"5\" border=\"0\">\n\
<tr class=\"css_bu\">\
<script language=\"JavaScript\">\
function targetPopup (pop) {\n\
   document.getElementById(\"msg_btn_popup\").value = pop;\n\
   if (pop) targetBlank();\n\
}\n\
</script>\n\
<input type=\"hidden\" name=\"msg_btn_popup\" id=\"msg_btn_popup\" value=\"\">\n\
<input type=\"hidden\" name=\"msg_range_list\" id=\"msg_range_list\" value=\"%s\">\n\
<td></td><td></td>\
<td class=\"css_nwtal\">%s</td>\
<td class=\"css_nwtal\">%s</td>\
<td class=\"css_nwtal\">%s</td>\
</tr>\n",
            rdptr->MsgIdListPtr,
            LangFor("received"),
            LangFor("from"),
            LangFor("subject"));

   if (uoptr->MessageOrder < 0)
   {
      /* find the last entry in the list */
      for (vmptr = muptr->MessageList;
           vmptr && vmptr->NextPtr;
           vmptr = vmptr->NextPtr);
   }
   else
      vmptr = muptr->MessageList;
   
   while (vmptr)
   {
      if (Debug)
         fprintf (stdout,
"%%X%08.08X id:%d size:%d hash:%d\n|%s|\n|%s|\n|%s|\n|%s|\n|%s|\n\n",
                  muptr->MailVmsStatus,
                  vmptr->CurrentId, vmptr->SizeInRecords, vmptr->MessageHash,
                  vmptr->Date, vmptr->From, vmptr->Subject,
                  vmptr->To, vmptr->Cc);

      zptr = (sptr = FromBuffer) + sizeof(FromBuffer)-1;
      for (cptr = vmptr->From; *cptr && sptr < zptr; *sptr++ = *cptr++);
      *sptr = '\0';
      MimeDecIsoString (FromBuffer);
      FromBuffer[40] = ']';
      FromBuffer[41] = '\0';

      zptr = (sptr = SubjBuffer) + sizeof(SubjBuffer)-1;
      for (cptr = vmptr->Subject; *cptr && sptr < zptr; *sptr++ = *cptr++);
      *sptr = '\0';
      MimeDecIsoString (SubjBuffer);
      SubjBuffer[60] = ']';
      SubjBuffer[61] = '\0';

      /* this mix of styles to get both Mozilla and MSIE to look right! */
      fprintf (stdout,
"<tr class=\"css_nw\">\
<td>\
<input class=\"css_button_panel_1\" \
type=\"submit\" name=\"msg_btn\" value=\"%04d\" \
onclick=\"targetPopup(0);\">\
<script language=\"JavaScript\">\
document.write(\'<input class=\"css_button_panel_1\" \
style=\"border-left-width:0px;\" \
type=\"submit\" name=\"msg_btn_%d\" value=\"^\" \
onclick=\"targetPopup(%d);\">\');\
</script>\
</td>\
<td>&nbsp;</td>\
<td class=\"css_nwtar\">%17.17s</td>\
<td class=\"css_nwtal\">%s</td>\
<td class=\"css_nwtal\">%s</td>\
</tr>\n",
         vmptr->CurrentId,
         vmptr->CurrentId,
         vmptr->CurrentId,
         InetMailRfcVmsDate(vmptr->Date),
         HTML_ADDR(FromBuffer),
         vmptr->Subject[0] ? HTML_TEXT(SubjBuffer) : LangFor("(none)"));

      if (uoptr->MessageOrder < 0)
         vmptr = vmptr->PrevPtr;
      else
         vmptr = vmptr->NextPtr;
   }

   fprintf (stdout,
"</table>\n\
</td></tr>\n\
</table>\n\
<!-- public message list end -->\n\n");

   MessageListFooter ();
}

/*****************************************************************************/
/*
Display the basic public message list page.
*/

void PublicFolderPage (REQUEST_DATA *rdptr)

{
   USER_OPTIONS  *uoptr;
   REQUEST_DATA  *sdptr;
   VMS_MAIL_MSG  *vmptr;
   VMS_MAIL_USER  *muptr;

   /*********/
   /* begin */
   /*********/

   if (WatchEnabled) WatchThis (FI_LI, "PublicFolderPage()");

   muptr = &VmsMailUser;
   uoptr = &rdptr->UserOptions;
   vmptr = &muptr->VmsMailMsg;
   sdptr = (REQUEST_DATA*)rdptr->StateDataPtr;

   if (!rdptr->RangeIdStart)
   {
      rdptr->RangeIdStart = sdptr->RangeIdStart;
      rdptr->RangeIdCount = sdptr->RangeIdCount;
      if (!rdptr->RangeIdStart)
      {
         /* no previous range to fall back on */
         rdptr->RangeIdStart = 1;
         rdptr->RangeIdCount = RANGE_MOST_RECENT;
      }
   }
   if (!rdptr->RangeIdCount)
      rdptr->RangeIdCount = RANGE_MOST_RECENT;

   muptr->MailVmsStatus = SS$_NORMAL;

   MessageListInit (rdptr);

   PublicPageBegin (rdptr, PAGE_FOLDER);

   PublicPageTitle (rdptr);

   StatusInfoPanel (rdptr);

   PublicMessageFolderList (rdptr);

   PublicFooter (rdptr);

   PublicPageEnd (rdptr);
}

/*****************************************************************************/
/*
Display the public format message header and body page.
*/

void PublicMessagePage (REQUEST_DATA *rdptr)

{
   int  status;
   REQUEST_DATA  *sdptr;
   USER_OPTIONS  *uoptr;
   VMS_MAIL_MSG  *vmptr;
   VMS_MAIL_USER  *muptr;
   VMS_MAIL_USER  UserData;

   /*********/
   /* begin */
   /*********/

   if (WatchEnabled) WatchThis (FI_LI, "PublicMessagePage()");

   muptr = &VmsMailUser;
   uoptr = &rdptr->UserOptions;
   vmptr = &muptr->VmsMailMsg;
   sdptr = (REQUEST_DATA*)rdptr->StateDataPtr;

   rdptr->FolderMessageCount = sdptr->FolderMessageCount;

   vmptr->MessageId = rdptr->MessageId;
   vmptr->ConfirmHash = rdptr->MessageHash;

   CallMailMessageGet (muptr, NULL);

   /* in case a message hash was not supplied use the one just generated */
   rdptr->MessageHash = vmptr->MessageHash;

   if (VMSnok (muptr->MailVmsStatus))
   {
      if (muptr->MailVmsStatus == MAIL$_OPENIN)
      {
         /* error opening external message file */
         StatusMessage (FI_LI, 1, "MAIL: %s %s",
                        SysGetMsg(MAIL$_OPENIN), vmptr->ExtId);
      }
      else
      {
         if (muptr->MailVmsStatus == SS$_BADCHECKSUM ||
             muptr->MailVmsStatus == MAIL$_NOMOREMSG)
            StatusMessage (FI_LI, 1, "%s", LangFor("message_checksum"));
         else
            StatusMessage (FI_LI, 1, "MAIL: %s.",
                           SysGetMsg(muptr->MailVmsStatus));
      }
      PublicFolderPage (rdptr);
      return;
   }

   MessageContentIdentify (rdptr);

   PublicPageBegin (rdptr, PAGE_MESSAGE);

   PublicPageTitle (rdptr);

   StatusInfoPanel (rdptr);

   PublicMessageButtons (rdptr);

   MessageHeader (rdptr);

   MessageBodyText (rdptr);

   MessageAttachments (rdptr);

   PublicPageEnd (rdptr);
}

/*****************************************************************************/
/*
Display the buttons associated with the message.
*/

void PublicMessageButtons (REQUEST_DATA *rdptr)

{
   int  value;
   USER_OPTIONS  *uoptr;
   VMS_MAIL_MSG  *vmptr;
   VMS_MAIL_USER  *muptr;

   /*********/
   /* begin */
   /*********/

   if (WatchEnabled) WatchThis (FI_LI, "PublicMessageButtons()");

   muptr = &VmsMailUser;
   uoptr = &rdptr->UserOptions;
   vmptr = &muptr->VmsMailMsg;

   fprintf (stdout,
"<!-- header buttons begin -->\n\
<p class=\"css_p06\">\
<table width=\"100%%\" cellpadding=\"1\" cellspacing=\"5\" \
align=\"center\" class=\"css_panel_1\">\n\
<tr><td class=\"css_left\">\n\
\
<input class=\"css_button_panel_1\" type=\"submit\" \
name=\"msg_print\" value=\"%s\">\
<script language=\"JavaScript\">\
document.write(\'<input class=\"css_button_panel_1\" \
style=\"border-left-width:0px;\" \
type=\"submit\" name=\"msg_print_popup\" value=\"^\" \
onclick=\"targetBlank();\">\');\
</script> \n\
\
<input class=\"css_button_panel_1\" type=\"submit\" \
name=\"msg_raw\" value=\"%s\"%s>\
<script language=\"JavaScript\">\
document.write(\'<input class=\"css_button_panel_1\" \
style=\"border-left-width:0px;\" \
type=\"submit\" name=\"msg_raw_popup\" value=\"^\"%s>\');\
</script> \n\
\
<input class=\"css_button_panel_1\" type=\"submit\" \
name=\"msg_hdr\" value=\"%s\"%s>\
<script language=\"JavaScript\">\
document.write(\'<input class=\"css_button_panel_1\" \
style=\"border-left-width:0px;\" \
type=\"submit\" name=\"msg_hdr_popup\" value=\"^\"%s>\');\
</script> \n\
\
<input class=\"css_button_panel_1\" type=\"submit\" \
name=\"msg_prev\" value=\"%s\"%s> \n\
<input class=\"css_button_panel_1\" type=\"submit\" \
name=\"msg_folder_at\" value=\"%s\"%s> \n\
<input class=\"css_button_panel_1\" type=\"submit\" \
name=\"msg_next\" value=\"%s\"%s> \n",
            LangFor("print"),
            LangFor("raw"),
            vmptr->LooksLikeRfc ? "" : "onclick=\"return notApplicable();\"",
            vmptr->LooksLikeRfc ? "onclick=\"targetBlank();\"" :
                                  "onclick=\"return notApplicable();\"",
            LangFor("header"),
            vmptr->LooksLikeRfc ? "" : "onclick=\"return notApplicable();\"",
            vmptr->LooksLikeRfc ? "onclick=\"targetBlank();\"" :
                                  "onclick=\"return notApplicable();\"",
            LangFor("prev"),
            CLICK_NOMORE(vmptr->MessageId == 1),
            LangFor("folder_at"),
            CLICK_STARTWORKING,
            LangFor("next"),
            CLICK_NOMORE(vmptr->MessageId == rdptr->FolderMessageCount));

   if (rdptr->ReadPlainText && rdptr->HtmlTextIsPresent)
   {
      fprintf (stdout,
"<input class=\"css_button_panel_1\" type=\"submit\" \
name=\"msg_read_pref\" value=\"%s\"> \n",
               LangFor("message_read_html"));
   }
   else
   if (rdptr->ReadHtmlText && rdptr->PlainTextIsPresent)
   {
      fprintf (stdout,
"<input class=\"css_button_panel_1\" type=\"submit\"  \
name=\"msg_read_pref\" value=\"%s\"> \n",
               LangFor("message_read_plain"));
   }

   if (rdptr->ReadPlainText)
   {
      value = ComposeWrapAt (rdptr->MassageMessage, uoptr);
      if (value < 0) value = ComposeWrapAt (value, uoptr);
      if (value)
         fprintf (stdout,
"<input class=\"css_button_panel_1\" type=\"submit\" \
name=\"msg_wrap\" value=\"%s %d\">\n", LangFor("message_massage_on"), value);
      else
         fprintf (stdout,
"<input class=\"css_button_panel_1\" type=\"submit\" \
name=\"msg_wrap\" value=\"%s\">\n", LangFor("message_massage_off"));
   }

   fprintf (stdout,
"</td></tr>\n\
</table>\n\
<!-- header buttons end -->\n\n");

}

/*****************************************************************************/
/*
*/

void PublicFooter (REQUEST_DATA *rdptr)

{
   /*********/
   /* begin */
   /*********/

   if (!SoyMailConfig.PublicFooter) return;

   fprintf (stdout,
"<!-- public footer begin -->\n\
<p class=\"css_p06\">\n\
<table width=\"100%%\" cellpadding=\"1\" cellspacing=\"5\" \
class=\"css_panel_1\">\n\
<tr><td align=\"left\" valign=\"top\" style=\"white-space:normal;\">\
%s\n\
</td></tr>\n\
</table>\n\
<!-- public footer end -->\n\n",
            SoyMailConfig.PublicFooter);
}

/****************************************************************************/

