/******************************************************************************
 GMessageViewDir.cc

	BASE CLASS = GMManagedDirector

	Copyright © 1997 by Glenn Bach. All rights reserved.

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

#include "GMessageViewDir.h"
#include "GMessageView.h"
#include "GMessageEditor.h"
#include "GMessageHeader.h"
#include "GMessageTableDir.h"
#include "GMessageTable.h"
#include "GMessageEditDir.h"
#include "GMessageHeaderList.h"
#include "JXGetPasswordDialog.h"
#include "gMailUtils.h"
#include <GMApp.h>
#include <GHelpText.h>
#include <GPrefsMgr.h>
#include "GMChooseSaveFile.h"
#include "GMPTPrinter.h"
#include "GMDirectorManager.h"
#include "GMDirectorMenu.h"

#include "filenew.xpm"
#include "filefloppy.xpm"
#include "fileprint.xpm"
#include "fileopen.xpm"
#include "envelopes.xpm"
#include "check_mail.xpm"
#include "mini-left.xpm"
#include "mini-right.xpm"
#include "mini-del-right.xpm"

#include "unlock.xpm"
#include "reply.xpm"
#include "reply_all.xpm"
#include "reply_sender.xpm"
#include "forward.xpm"
#include "redirect.xpm"

#include "address_entry.xpm"
#include "mailbox.xpm"

#include "jx_help_specific.xpm"
#include "jx_help_toc.xpm"

#include <JXToolBar.h>

#include <JXColormap.h>
#include <JXVertPartition.h>
#include <JXTextMenu.h>
#include <JXDownRect.h>
#include <JXTextButton.h>
#include <JXScrollbarSet.h>
#include <JXScrollbar.h>
#include <JXChooseSaveFile.h>
#include <JXApplication.h>
#include <JXWindow.h>
#include <JXMenuBar.h>
#include <JXFontManager.h>
#include <JXHelpManager.h>
#include <JXImage.h>

#include <JUserNotification.h>
#include <JString.h>
#include <JPtrArray.h>
#include <JColormap.h>
#include <JInPipeStream.h>
#include <JOutPipeStream.h>
#include <JRegex.h>
#include <JError.h>

#include <GMGlobals.h>

#include <jXCSFIcons.h>

#include <jStreamUtil.h>
#include <jFileUtil.h>
#include <jProcessUtil.h>
#include <jDirUtil.h>
#include <jMissingProto.h>

#include <iostream.h>
#include <fstream.h>
#include <strstream.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <jAssert.h>

static const JCharacter* kFileMenuTitleStr = "File";
static const JCharacter* kFileMenuStr = 
	"New message %k Meta-N %i \"NewMessage::Arrow\""
	"| New mailbox %k Meta-Shift-N %i \"NewMailbox::Arrow\""
	"|Open mailbox... %k Meta-O %i \"OpenMailbox::Arrow\""
	"%l|Save... %k Meta-S %i \"Save::Arrow\" "
	"|Append... %i \"Append::Arrow\" "
	"%l|Page setup... %i \"PageSetup::Arrow\""
	"| Print... %k Meta-P  %i \"Print::Arrow\""
	"%l|Show next %k Meta-plus %i \"ShowNect::Arrow\""
	"| Show previous %k Meta-minus %i \"ShowPrev::Arrow\""
	"|Delete and show next %k Meta-Shift-D %i \"DelShowNext::Arrow\""
	"%l|Close %k Meta-W %i \"Close::Arrow\""
	"|Close and delete %k Meta-D %i \"CloseDelete::Arrow\""
	"|Quit %k Meta-Q %i \"Quit::Arrow\"";

enum
{	
	kNewCmd = 1,
	kNewMBox,
	kOpenCmd,
	kSaveCmd,
	kAppendCmd,
	kPageSetupCmd,
	kPrintCmd,
	kShowNextCmd,
	kShowPrevCmd,
	kDeleteShowNextCmd,
	kCloseCmd,
	kCloseDeleteCmd,
	kQuitCmd
};

static const JCharacter* kMessageMenuTitleStr = "Message";
static const JCharacter* kMessageMenuStr = 
	"Show full headers %b  %i \"ShowFullHead::Arrow\""
	"| Decrypt %i \"Decrypt::Arrow\""
	"%l|Reply %k Meta-R %i \"Reply::Arrow\""
	"| Reply to sender %i \"ReplySender::Arrow\""
	"|Reply to all %i \"ReplyAll::Arrow\""
	"| Forward %i \"Forward::Arrow\""
	"| Redirect %i \"Redirect::Arrow\"";

enum
{
	kShowHeaderCmd = 1,
	kDecryptCmd,
	kReplyCmd,
	kReplySenderCmd,
	kReplyAllCmd,
	kForwardCmd,
	kRedirectCmd
};

static const JCharacter* kWindowsMenuTitleStr = "Windows";

static const JCharacter* kPrefsMenuTitleStr = "Preferences";
static const JCharacter* kPrefsMenuStr = 
	"Edit mail preferences %i \"Preferences::Arrow\""
	"|Edit URL preferences %i \"URLPreferences::Arrow\""
	"|Edit tool bar... %i \"EditToolBar::Arrow\""
	"|Save window size as default %i \"SaveWindowDefault::Arrow\"";

enum
{	
	kPrefsCmd = 1,
	kURLPrefsCmd,
	kEditToolBarCmd,
	kSaveWindowSizeCmd
};

static const JCharacter* kHelpMenuTitleStr = "Help";
static const JCharacter* kHelpMenuStr = 
	"About"
	"%l|Table of Contents %i \"TOCHelp::Arrow\""
	"|Overview|This window %i \"ThisWindowHelp::Arrow\""
	"%l|Changes|Credits";

enum
{	
	kAboutCmd = 1,
	kTOCCmd,
	kOverviewCmd,
	kThisWindowCmd,
	kChangesCmd,
	kCreditsCmd
};

/******************************************************************************
 Constructor

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

GMessageViewDir::GMessageViewDir
	(
	GMessageTableDir* supervisor,
	const JString& mailfile,
	GMessageHeader* header
	)
	:
	GMManagedDirector(supervisor)
{
	itsPasswdDialog = NULL;

	BuildWindow(mailfile);
	itsDir = supervisor;
	itsShowFullHeaders = kFalse;
	ShowHeader(header);

	GGetDirMgr()->DirectorCreated(this);
}

/******************************************************************************
 Destructor

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

GMessageViewDir::~GMessageViewDir()
{
	delete itsMenuIcon;
	GGetDirMgr()->DirectorDeleted(this);
}

/******************************************************************************
 BuildWindow

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

void
GMessageViewDir::BuildWindow
	(
	const JString& mailfile
	)
{
	JSize w = 500;
	JSize h = 300;
	JXWindow* window = 
		new JXWindow(this, w,h, mailfile);
    assert( window != NULL );
    SetWindow(window);
	window->SetWMClass(GMGetWMClassInstance(), GMGetViewWindowClass());
    GGetPrefsMgr()->GetViewWindowSize(window);
	w = window->GetFrameWidth();
	h = window->GetFrameHeight();
    
    window->SetMinSize(w, 150);
    window->SetFocusWhenShow(kTrue);
	
	JXMenuBar* menuBar = 
		new JXMenuBar(window, 
			JXWidget::kHElastic, JXWidget::kFixedTop,
			0, 0, w, kJXStdMenuBarHeight);
	assert(menuBar != NULL);

	itsFileMenu = menuBar->AppendTextMenu(kFileMenuTitleStr);
	itsFileMenu->SetMenuItems(kFileMenuStr);
	itsFileMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsFileMenu);
	
	itsMessageMenu = menuBar->AppendTextMenu(kMessageMenuTitleStr);
	itsMessageMenu->SetMenuItems(kMessageMenuStr);
	itsMessageMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsMessageMenu);

	itsToolBar = 
		new JXToolBar(GGetPrefsMgr(), kGViewToolBarID,
			menuBar, w, 150, window,
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0, kJXStdMenuBarHeight, w, h - kJXStdMenuBarHeight);
	assert(itsToolBar != NULL);

	const JSize newHeight	= itsToolBar->GetWidgetEnclosure()->GetBoundsHeight();

	const JFontManager* fm 	= window->GetFontManager();
	JSize lineHeight = 
		fm->GetLineHeight(GGetPrefsMgr()->GetDefaultMonoFont(),
						  GGetPrefsMgr()->GetDefaultFontSize(),
						  JFontStyle());
													
	
	const JCoordinate headerheight  = (lineHeight * 4) + (lineHeight/2); //58;

	JArray<JCoordinate> sizes;
	JArray<JCoordinate> minSizes;
	
	sizes.AppendElement(headerheight);
	minSizes.AppendElement(20);
	sizes.AppendElement(w - headerheight);
	minSizes.AppendElement(50);
	JIndex elasticIndex = 2;

	itsPart = 
		new JXVertPartition(sizes, elasticIndex, 
			minSizes, itsToolBar->GetWidgetEnclosure(), 
			JXWidget::kHElastic, JXWidget::kVElastic,
			0, 0, 
			w, newHeight);
	assert(itsPart != NULL);

	itsSBSet = 
		new JXScrollbarSet(itsPart->GetCompartment(2),
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0,0,
			100,100);
	assert(itsSBSet != NULL);
	itsSBSet->FitToEnclosure(kTrue, kTrue);
	
	itsView = 
		new GMessageView(menuBar, itsSBSet, itsSBSet->GetScrollEnclosure(),
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0,0,10,10);
	assert (itsView != NULL);
	itsView->FitToEnclosure(kTrue, kTrue);
	itsView->SetPTPrinter(GMGetAltPTPrinter());

	JXScrollbarSet* sbs = 
		new JXScrollbarSet(itsPart->GetCompartment(1),
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0,0,
			100,50);
	assert(sbs != NULL);
	sbs->FitToEnclosure(kTrue, kTrue);

	itsHeader = 
		new GMessageView(sbs, sbs->GetScrollEnclosure(),
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0,0,10,10);
	assert (itsHeader != NULL);
	itsHeader->FitToEnclosure(kTrue, kTrue);

	itsHeader->ShareEditMenu(itsView, kFalse, kFalse);
	itsHeader->ShareSearchMenu(itsView);

	GMDirectorMenu* menu = 
		new GMDirectorMenu(kWindowsMenuTitleStr, menuBar,
			JXWidget::kFixedLeft, JXWidget::kVElastic, 0,0, 10,10);
	assert(menu != NULL);
	menuBar->AppendMenu(menu);

	itsPrefsMenu = menuBar->AppendTextMenu(kPrefsMenuTitleStr);
	itsPrefsMenu->SetMenuItems(kPrefsMenuStr);
	itsPrefsMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsPrefsMenu);

	itsHelpMenu = menuBar->AppendTextMenu(kHelpMenuTitleStr);
	itsHelpMenu->SetMenuItems(kHelpMenuStr);
	itsHelpMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsHelpMenu);

	itsFileMenu->SetItemImage(kNewCmd, filenew);
	itsFileMenu->SetItemImage(kNewMBox, envelopes);
	itsFileMenu->SetItemImage(kOpenCmd, fileopen);
	itsFileMenu->SetItemImage(kSaveCmd, filefloppy);
	itsFileMenu->SetItemImage(kPrintCmd, fileprint);
	itsFileMenu->SetItemImage(kShowNextCmd, mini_right);
	itsFileMenu->SetItemImage(kDeleteShowNextCmd, mini_del_right);
	itsFileMenu->SetItemImage(kShowPrevCmd, mini_left);

//	itsMessageMenu->SetItemImage(kDeleteCmd, mini_cross);
	itsMessageMenu->SetItemImage(kDecryptCmd, unlock_xpm);
	itsMessageMenu->SetItemImage(kReplyCmd, reply_xpm);
	itsMessageMenu->SetItemImage(kReplySenderCmd, reply_sender_xpm);
	itsMessageMenu->SetItemImage(kReplyAllCmd, reply_all_xpm);
	itsMessageMenu->SetItemImage(kForwardCmd, forward_xpm);
	itsMessageMenu->SetItemImage(kRedirectCmd, redirect_xpm);
	
	itsHelpMenu->SetItemImage(kTOCCmd, jx_help_toc);
	itsHelpMenu->SetItemImage(kThisWindowCmd, JXPM(jx_help_specific));

	itsToolBar->LoadPrefs();

	if (itsToolBar->IsEmpty())
		{
		itsToolBar->AppendButton(itsFileMenu, kNewCmd);
		itsToolBar->AppendButton(itsFileMenu, kOpenCmd);
		itsToolBar->NewGroup();

		itsToolBar->AppendButton(itsFileMenu, kSaveCmd);
		itsToolBar->NewGroup();

		itsToolBar->AppendButton(itsFileMenu, kPrintCmd);
		itsToolBar->NewGroup();

		itsToolBar->AppendButton(itsFileMenu, kShowNextCmd);
		itsToolBar->AppendButton(itsFileMenu, kShowPrevCmd);
		itsToolBar->AppendButton(itsFileMenu, kDeleteShowNextCmd);
		itsToolBar->NewGroup();

		itsToolBar->AppendButton(itsMessageMenu, kReplyCmd);
		itsToolBar->AppendButton(itsMessageMenu, kReplySenderCmd);
		itsToolBar->AppendButton(itsMessageMenu, kReplyAllCmd);
		itsToolBar->AppendButton(itsMessageMenu, kForwardCmd);
		itsToolBar->AppendButton(itsMessageMenu, kRedirectCmd);
		}

	itsMenuIcon = new JXImage(window->GetDisplay(), window->GetColormap(), JXGetPlainFileIcon());
	assert(itsMenuIcon != NULL);
	itsMenuIcon->ConvertToRemoteStorage();
}

/******************************************************************************
 Receive

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

void
GMessageViewDir::Receive
	(
	JBroadcaster* sender,
	const JBroadcaster::Message& message
	)
{
	if (sender == itsFileMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleFileMenu(selection->GetIndex());
		}
	else if (sender == itsHelpMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleHelpMenu(selection->GetIndex());
		}
	else if (sender == itsPrefsMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandlePrefsMenu(selection->GetIndex());
		}
	else if (sender == itsFileMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateFileMenu();
		}
	else if (sender == itsMessageMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleMessageMenu(selection->GetIndex());
		}
	else if (sender == itsMessageMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateMessageMenu();
		}
	else if (sender == itsPasswdDialog && message.Is(JXDialogDirector::kDeactivated))
		{
		const JXDialogDirector::Deactivated* info =
			dynamic_cast(const JXDialogDirector::Deactivated*, &message);
		assert( info != NULL );
		if (info->Successful())
			{
			JString passwd = itsPasswdDialog->GetPassword();
			JString buffer;
			JBoolean ok;
			if (GGetPrefsMgr()->GetEncryptionType() == GPrefsMgr::kPGP2_6)
				{
				ok = GDecryptPGP2_6_2(itsView->GetText(), passwd, &buffer);
				}
			else
				{
				ok = GDecryptGPG1_0(itsView->GetText(), passwd, &buffer);
				}
			if (ok && !buffer.IsEmpty())
				{
				itsView->SelectAll();
				itsView->Paste(buffer);
				}
			}
		itsPasswdDialog = NULL;
		}
	else if (sender == GMGetAltPTPrinter() && message.Is(GMPTPrinter::kPrintStarting))
		{
		JBoolean headers = GMGetAltPTPrinter()->WillPrintHeader();
		if (headers)
			{
			itsShowFullHeaders = kTrue;
			itsView->SetText(itsFullHeader + itsBody);
			}
		}
	else
		{
		GMManagedDirector::Receive(sender, message);
		}
}

/******************************************************************************
 HandleFileMenu 


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

void
GMessageViewDir::HandleFileMenu
	(
	const JIndex index
	)
{
	if (index == kNewCmd)
		{
		GMessageEditDir* dir = new GMessageEditDir(JXGetApplication());
		assert(dir != NULL);
		dir->Activate();
		}
	else if (index == kNewMBox)
		{
		JString mbox;
		if (JXGetChooseSaveFile()->SaveFile("Name of new mailbox:", "", "",  &mbox))
			{
			GMGetApplication()->NewMailbox(mbox);
			}
		}
	else if (index == kOpenCmd)
		{
		GMGetApplication()->OpenMailbox();
		}
	else if (index == kSaveCmd)
		{
		JString name;
		if (GMGetAltChooseSaveFile()->SaveFile("Choose file name:", "", "",  &name))
			{
			JBoolean headers = GMGetAltChooseSaveFile()->IsSavingHeaders();
			if (!headers)
				{
				itsView->WritePlainText(name, JTextEditor::kUNIXText);			
				}
			else
				{
				if (itsShowFullHeaders)
					{
					itsView->WritePlainText(name, JTextEditor::kUNIXText);
					}
				else
					{
					itsView->SetText(itsFullHeader + itsBody);
					itsView->WritePlainText(name, JTextEditor::kUNIXText);
					itsView->SetText(itsBody);				
					}
				}
			}
		}
	else if (index == kAppendCmd)
		{
		AppendMessagesToFile(kFalse);
		}
	else if (index == kPageSetupCmd)
		{
		GMGetAltPTPrinter()->BeginUserPageSetup();
		}
	else if (index == kPrintCmd)
		{
		itsView->PrintPT();
		ListenTo(GMGetAltPTPrinter());
		}
	else if (index == kCloseCmd)
		{
		Close();
		}
	else if (index == kCloseDeleteCmd)
		{
		itsDir->GetTable().DeleteHeader(itsMessageHeader);
		Close();
		}
	else if (index == kDeleteShowNextCmd)
		{
		itsDir->GetTable().DeleteHeader(itsMessageHeader);
		GMessageHeader* header = itsMessageHeader;
		ShowNext();
		if (header == itsMessageHeader)
			{
			Close();
			}
		}
	else if (index == kShowNextCmd)
		{
		ShowNext();
		}
	else if (index == kShowPrevCmd)
		{
		ShowPrev();
		}
	else if (index == kQuitCmd)
		{
		JXGetApplication()->Quit();
		}
}

/******************************************************************************
 UpdateFileMenu 


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

void
GMessageViewDir::UpdateFileMenu()
{
	GMessageHeaderList& list = itsDir->GetHeaderList();
	JIndex findex;
	list.Find(itsMessageHeader, &findex);

	if (findex > 1)
		{
		itsFileMenu->EnableItem(kShowPrevCmd);
		}
	else
		{
		itsFileMenu->DisableItem(kShowPrevCmd);
		}
	if (findex < list.GetElementCount())
		{
		itsFileMenu->EnableItem(kShowNextCmd);
		}
	else
		{
		itsFileMenu->DisableItem(kShowNextCmd);
		}
}

/******************************************************************************
 UpdateMessageMenu 


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

void
GMessageViewDir::UpdateMessageMenu()
{
	if (itsShowFullHeaders)
		{
		itsMessageMenu->CheckItem(kShowHeaderCmd);
		}
}

/******************************************************************************
 HandleMessageMenu 


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

void
GMessageViewDir::HandleMessageMenu
	(
	const JIndex index
	)
{
	if (index == kShowHeaderCmd)
		{
		itsShowFullHeaders = JNegate(itsShowFullHeaders);
		if (itsShowFullHeaders)
			{
			itsView->SetText(itsFullHeader + itsBody);
			}
		else
			{
			itsView->SetText(itsBody);
			}
		}
	else if (index == kDecryptCmd)
		{
		assert(itsPasswdDialog == NULL);
		itsPasswdDialog = new JXGetPasswordDialog(this);
		assert(itsPasswdDialog != NULL);
		ListenTo(itsPasswdDialog);
		itsPasswdDialog->BeginDialog();
		}
	else if (index == kReplyCmd)
		{
		itsDir->GetTable().Reply(itsMessageHeader);
		}
	else if (index == kReplySenderCmd)
		{
		itsDir->GetTable().ReplySender(itsMessageHeader);
		}
	else if (index == kReplyAllCmd)
		{
		itsDir->GetTable().ReplyAll(itsMessageHeader);
		}
	else if (index == kForwardCmd)
		{
		itsDir->GetTable().Forward(itsMessageHeader);
		}
	else if (index == kRedirectCmd)
		{
		itsDir->GetTable().Redirect(itsMessageHeader);
		}
}

/******************************************************************************
 HandlePrefsMenu 


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

void
GMessageViewDir::HandlePrefsMenu
	(
	const JIndex index
	)
{
	if (index == kPrefsCmd)
		{
		GGetPrefsMgr()->EditPrefs();
		}
	else if (index == kURLPrefsCmd)
		{
		JXGetHelpManager()->EditPrefs();
		}
	else if (index == kEditToolBarCmd)
		{
		itsToolBar->Edit();
		}
	else if (index == kSaveWindowSizeCmd)
		{
		GGetPrefsMgr()->SaveViewWindowSize(GetWindow());
		}


}

/******************************************************************************
 HandleHelpMenu 


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

void
GMessageViewDir::HandleHelpMenu
	(
	const JIndex index
	)
{
	if (index == kAboutCmd)
		{
		GMGetApplication()->DisplayAbout();
		}
	else if (index == kTOCCmd)
		{
		(JXGetHelpManager())->ShowSection(kTOCHelpName);
		}
	else if (index == kOverviewCmd)
		{
		(JXGetHelpManager())->ShowSection(kOverviewHelpName);
		}
	else if (index == kThisWindowCmd)
		{
		(JXGetHelpManager())->ShowSection(kViewHelpName);
		}
	else if (index == kChangesCmd)
		{
		(JXGetHelpManager())->ShowSection(kChangeLogName);
		}
	else if (index == kCreditsCmd)
		{
		(JXGetHelpManager())->ShowSection(kCreditsName);
		}
}

/******************************************************************************
 ShowNext 


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

void
GMessageViewDir::ShowNext()
{
		GMessageHeaderList& list = itsDir->GetHeaderList();
		JIndex findex;
		list.Find(itsMessageHeader, &findex);
		if (findex < list.GetElementCount())
			{
			JBoolean found = kFalse;
			JIndex i = findex + 1;
			GMessageHeader* header;
			while (!found && i <= list.GetElementCount())
				{
				header = list.NthElement(i);
				if (header->GetMessageStatus() != GMessageHeader::kDelete)
					{
					found = kTrue;
					}
				i++;
				}
			if (found)
				{
				itsDir->GetTable().UnSelectHeader(itsMessageHeader);
				ShowHeader(header);
				itsDir->GetTable().SelectHeader(header);
				itsDir->GetTable().ShowMessageRead(header);
				GGetDirMgr()->DirectorChanged(this);
				}
			}
}

/******************************************************************************
 ShowPrev 


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

void
GMessageViewDir::ShowPrev()
{
		GMessageHeaderList& list = itsDir->GetHeaderList();
		JIndex findex;
		list.Find(itsMessageHeader, &findex);
		if (findex > 1)
			{
			JBoolean found = kFalse;
			JIndex i = findex - 1;
			GMessageHeader* header;
			while (!found && i > 0)
				{
				header = list.NthElement(i);
				if (header->GetMessageStatus() != GMessageHeader::kDelete)
					{
					found = kTrue;
					}
				i--;
				}
			if (found)
				{
				itsDir->GetTable().UnSelectHeader(itsMessageHeader);
				ShowHeader(header);
				itsDir->GetTable().SelectHeader(header);
				itsDir->GetTable().ShowMessageRead(header);
				GGetDirMgr()->DirectorChanged(this);
				}
			}
}

/******************************************************************************
 ShowHeader 


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

void
GMessageViewDir::ShowHeader
	(
	GMessageHeader* header
	)
{
	itsMessageHeader = header;

	mode_t perms;
	JError err = JGetPermissions(itsDir->GetMailFile(), &perms);
	if (!err.OK())
		{
		perms = 0600;
		}

	fstream is(itsDir->GetMailFile(), ios::in|ios::out, perms);
	assert(is.good());
	
	is.seekp(header->GetHeaderStart());
	itsFullHeader = JRead(is, header->GetHeaderEnd() - header->GetHeaderStart());
	
	itsFrom = header->GetFrom();
	itsTo = header->GetTo();
	itsDate = header->GetDate();
	itsSubject = header->GetSubject();
	itsReplyTo = header->GetReplyTo();
	itsCC = header->GetCC();
	JString head = "From: " + itsFrom;
	if (!itsSubject.IsEmpty())
		{
		if (head.GetLastCharacter() != '\n')
			{
			head += "\n";
			}	
		head += "Subject: " + itsSubject;
		}
	if (head.GetLastCharacter() != '\n')
		{
		head += "\n";
		}
	head += "Date: " + itsDate;
	if (!itsTo.IsEmpty())
		{
		if (head.GetLastCharacter() != '\n')
			{
			head += "\n";
			}
		head += "To: " + itsTo;
		}
	if (!itsReplyTo.IsEmpty())
		{
		if (head.GetLastCharacter() != '\n')
			{
			head += "\n";
			}
		head += "Reply-To: " + itsReplyTo;
		}
	if (!itsCC.IsEmpty())
		{
		if (head.GetLastCharacter() != '\n')
			{
			head += "\n";
			}
		head += "Cc: " + itsCC;
		}
	head.TrimWhitespace();
	itsHeader->SetText(head);

	itsBody = JRead(is, header->GetMessageEnd() - header->GetHeaderEnd());
	
	if (itsShowFullHeaders)
		{
		itsView->SetText(itsFullHeader + itsBody);
		}
	else
		{
		itsView->SetText(itsBody);
		}
	is.close();
	JString title = itsFrom;
	JIndex findindex;
	if (title.LocateSubstring("@", &findindex))
		{
		title.RemoveSubstring(findindex, title.GetLength());
		}
	JString sub = ":" + itsSubject;
	if (sub.GetLength() > 11)
		{
		sub.RemoveSubstring(10, sub.GetLength());
		}
	title.Append(sub);
	GetWindow()->SetTitle(title);
}

/******************************************************************************
 FixHeaderForReply 


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

void
GMessageViewDir::FixHeaderForReply
	(
	JString* sub
	)
{
	JRegex regex;
	JError err = regex.SetPattern("^[rR][eE][.:]");
	assert(err.OK());
	JBoolean matched;
	JArray<JIndexRange>* subList = new JArray<JIndexRange>;
	assert(subList != NULL);
	matched = regex.Match(*sub, subList);
	if (!matched)
		{
		sub->Prepend("Re: ");
		}
}

/******************************************************************************
 SaveState 


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

void
GMessageViewDir::SaveState
	(
	ostream& os
	)
{
	os << itsMessageHeader->GetHeader() << " ";
	GetWindow()->WriteGeometry(os);

	JXScrollbar* hsb = itsSBSet->GetHScrollbar();
	JXScrollbar* vsb = itsSBSet->GetVScrollbar();
	os << hsb->GetValue() << " ";
	os << vsb->GetValue() << " ";

	const JArray<JCoordinate>& sizes = itsPart->GetCompartmentSizes();
	JSize count = 2;
	for (JSize i = 1; i <= 2; i++)
		{
		os << sizes.GetElement(i) << " ";
		}
}

/******************************************************************************
 ReadState 

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

void
GMessageViewDir::ReadState
	(
	istream& is
	)
{
	GetWindow()->ReadGeometry(is);
	JCoordinate hval, vval;
	is >> hval;
	is >> vval;
	JXScrollbar* hsb = itsSBSet->GetHScrollbar();
	JXScrollbar* vsb = itsSBSet->GetVScrollbar();
	hsb->SetValue(hval);
	vsb->SetValue(vval);

	JArray<JCoordinate> sizes;
	JCoordinate value;
	is >> value;
	sizes.AppendElement(value);
	is >> value;
	sizes.AppendElement(value);
	itsPart->JPartition::SetCompartmentSizes(sizes);
}

/******************************************************************************
 AppendMessagesToFile (private) 

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

void
GMessageViewDir::AppendMessagesToFile
	(
	const JBoolean headers
	)
{
	JString filename;
	if (GMGetAltChooseSaveFile()->ChooseFile("Choose file:", "", &filename))
		{
		mode_t perms;
		JError err = JGetPermissions(filename, &perms);
		if (!err.OK())
			{
			perms = 0600;
			}
		fstream is(filename, ios::in|ios::out, perms);
		JString tempname = filename + ".tmp";
		ofstream os(tempname);
		JBoolean ok = JConvertToBoolean(os.good());
		if (!ok)
			{
			tempname = JGetTempFileName();
			os.close();
			os.open(tempname);
			}
		JSize size;
		err = JGetFileLength(filename, &size);
		if (!err.OK())
			{
			JGetUserNotification()->ReportError("There was an unknown problem saving the file.");
			return;
			}
		JString temp;
		temp.Read(is, size);
		if ((size != 0) && !temp.EndsWith("\n\n"))
			{
			temp.Append("\n\n");
			}
		temp.Print(os);
		JBoolean saveHeaders = GMGetAltChooseSaveFile()->IsSavingHeaders();
		if (saveHeaders)
			{
			itsFullHeader.Print(os);
			}
		itsBody.Print(os);
		
		is.close();
		os.close();

		GMReplaceFileWithTemp(tempname, filename);
		}
}