/******************************************************************************
 GMessageEditDir.cc

	BASE CLASS = GMManagedDirector

	Copyright © 1997 by Glenn Bach. All rights reserved.

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

#include "GMessageEditDir.h"
#include <SMTPMessage.h>
#include <GMessageEditor.h>
#include "JXGetPasswordDialog.h"
#include "gMailUtils.h"
#include <GMApp.h>
#include <GPrefsMgr.h>
#include <GHelpText.h>
#include "GMDirectorManager.h"
#include "GMDirectorMenu.h"

#include "filenew.xpm"
#include "filefloppy.xpm"
#include "fileprint.xpm"
#include "fileopen.xpm"
#include "envelopes.xpm"

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

#include "lock.xpm"
#include "send.xpm"
#include "signature.xpm"


#include <JXToolBar.h>

#include <JXStaticText.h>
#include <JXInputField.h>
#include <JXScrollbarSet.h>
#include <JXScrollbar.h>
#include <JXChooseSaveFile.h>
#include <JXColormap.h>
#include <JXApplication.h>
#include <JXTextButton.h>
#include <JXWindow.h>
#include <JXMenuBar.h>
#include <JXTextMenu.h>
#include <JXHelpManager.h>
#include <JXEngravedRect.h>
#include <JXImage.h>

#include <JUNIXDirEntry.h>
#include <JUserNotification.h>
#include <JString.h>
#include <JColormap.h>
#include <JInPipeStream.h>
#include <JOutPipeStream.h>

#include <GMGlobals.h>

#include <jXCSFIcons.h>

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

#include <iostream.h>
#include <fstream.h>
#include <strstream.h>
#include <stdlib.h>
#include <unistd.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 \"Open::Arrow\""
	"%l|Send message  %k Meta-Shift-S %i \"Send::Arrow\""
	"| Save message %k Meta-S  %i \"Save::Arrow\""
	"| Save message as... %i \"SaveAs::Arrow\""
	"%l|Discard and close %i \"Discard&Clase::Arrow\""
	"|Quit %k Meta-Q %i \"Quit::Arrow\"";

enum
{	
	kNewCmd = 1,
	kNewMBox,
	kOpenCmd,
	kSendCmd,
	kSaveCmd,
	kSaveAsCmd,
	kDiscardCmd,
	kQuitCmd
};

// Message menu

static const JCharacter* kMessageMenuTitleStr = "Message";
static const JCharacter* kMessageMenuStr = 
	"Insert quoted %k Meta-I %i \"InsertQuoted::Arrow\""
	"| Insert unquoted %i \"InsertUnQuoted::Arrow\""
	"| Insert signature %k Meta-Shift-G %i \"InsertSig::Arrow\""
	"|Insert text file %i \"InsertTextFile::Arrow\""
	"%l|Encrypt %i \"Encrypt::Arrow\""
	"%l|Show Reply-To %b %i \"ShowReplyTo::Arrow\""
	"| Show Cc %b %k Meta-Shift-C %i \"ShowCC::Arrow\""
	"| Show Bcc %b %i \"ShowBCC::Arrow\"";

enum
{
	kQuoteCmd = 1,
	kUnquoteCmd,
	kSigCmd,
	kInsertTextCmd,
	kEncryptCmd,
	kShowRepToCmd,
	kShowCcCmd,
	kShowBccCmd
};

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
};

static const JCharacter* kDefaultReplyString = "On $d, $f wrote:";
static const JCharacter* kDefaultMark = ">";

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

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

GMessageEditDir::GMessageEditDir
	(
	JXDirector* supervisor
	)
	:
	GMManagedDirector(supervisor)
{
	itsPasswdDialog	= NULL;
	itsMessage 		= NULL;
	BuildWindow();
	
	itsReplyString = 		new JString(kDefaultReplyString);
	assert(itsReplyString != NULL);
	
	itsReplyMark = 			new JString(kDefaultMark);
	assert(itsReplyMark != NULL);
	
	itsSentFrom = 			new JString();
	assert(itsSentFrom != NULL);
	
	itsSentDate = 			new JString();
	assert(itsSentDate != NULL);
	
	itsSentTextFileName = 	new JString();
	assert(itsSentTextFileName != NULL);
	
	itsShowReplyTo 	= kFalse;
	itsShowCC		= kFalse;
	itsShowBCC		= kFalse;

	JString replyto = GGetPrefsMgr()->GetReplyTo();
	if (!replyto.IsEmpty())
		{
		itsShowReplyTo = kTrue;
		itsReplyToInput->SetText(replyto);
		}

	itsShowReplyString = GGetPrefsMgr()->ShowingSenderString();
	if (itsShowReplyString)
		{
		*itsReplyString = GGetPrefsMgr()->GetSenderString();
		}
	
	AdjustInputFields();

	GMGetApplication()->AppendNewMessage(this);

	GGetDirMgr()->DirectorCreated(this);
}

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

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

GMessageEditDir::~GMessageEditDir()
{
	delete itsReplyString;
	delete itsReplyMark;
	delete itsSentFrom;
	delete itsSentDate;
	if (JFileExists(*itsSentTextFileName))
		{
		JRemoveFile(*itsSentTextFileName);
		}
	delete itsSentTextFileName;
	delete itsMenuIcon;

	GGetDirMgr()->DirectorDeleted(this);
}

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

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

void
GMessageEditDir::BuildWindow()
{
	JSize w 				= 510;
	JSize h 				= 400;
	const JSize inputAdjust	= 260;
	const JSize kSendBuffer	= 130;
	
	JString title;
	JString path;
	JXWindow* window = new JXWindow(this, w,h, "New Message");
	assert( window != NULL );
	SetWindow(window);

	window->SetMinSize(w, 250);
	window->SetFocusWhenShow(kTrue);

	window->SetWMClass(GMGetWMClassInstance(), GMGetEditorWindowClass());
	GGetPrefsMgr()->GetEditorWindowSize(window);

	JSize origW	= w;
	w 			= window->GetFrameWidth();
	h 			= window->GetFrameHeight();

	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);

	itsMessageMenu->SetItemImage(kEncryptCmd, lock_xpm);
	itsMessageMenu->SetItemImage(kSigCmd, signature_xpm);
	itsMessageMenu->SetItemImage(kInsertTextCmd, JXGetPlainFileIcon());
	
	itsToolBar = 
		new JXToolBar(GGetPrefsMgr(), kGEditToolBarID,
			menuBar, origW, 250, window,
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0, kJXStdMenuBarHeight, w, h - kJXStdMenuBarHeight);
	assert(itsToolBar != NULL);

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

	JXEngravedRect* uprect = 
		new JXEngravedRect(itsToolBar->GetWidgetEnclosure(), 
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0,0, 
			w ,newHeight);
	assert(uprect != NULL);

	itsToLabel =
		new JXStaticText("To:", itsToolBar->GetWidgetEnclosure(),
			JXWidget::kFixedLeft, JXWidget::kFixedTop, 
			60,13,30,17);
	assert(itsToLabel != NULL);
	
	itsToInput =
		new JXInputField(itsToolBar->GetWidgetEnclosure(),
			JXWidget::kHElastic, JXWidget::kFixedTop, 
			100,10,w - inputAdjust,20);
	assert(itsToInput != NULL);
	ListenTo(itsToInput);
	itsToInput->SetDefaultFont(GGetPrefsMgr()->GetDefaultMonoFont(), kJDefaultFontSize);
	
	itsReplyToLabel =
		new JXStaticText("Reply-To:", itsToolBar->GetWidgetEnclosure(),
			JXWidget::kFixedLeft, JXWidget::kFixedTop, 
			20,43,70,17);
	assert(itsReplyToLabel != NULL);
	
	itsReplyToInput =
		new JXInputField(itsToolBar->GetWidgetEnclosure(),
			JXWidget::kFixedLeft, JXWidget::kFixedTop, 
			100,40,w - inputAdjust,20);
	assert(itsReplyToInput != NULL);
	itsReplyToInput->SetDefaultFont(GGetPrefsMgr()->GetDefaultMonoFont(), kJDefaultFontSize);
	
	itsCCLabel =
		new JXStaticText("Cc:", itsToolBar->GetWidgetEnclosure(),
			JXWidget::kFixedLeft, JXWidget::kFixedTop, 
			58,73,30,17);
	assert(itsCCLabel != NULL);
	
	itsCCInput =
		new JXInputField(itsToolBar->GetWidgetEnclosure(),
			JXWidget::kHElastic, JXWidget::kFixedTop, 
			100,70,w - inputAdjust,20);
	assert(itsCCInput != NULL);
	itsCCInput->SetDefaultFont(GGetPrefsMgr()->GetDefaultMonoFont(), kJDefaultFontSize);

	itsBCCLabel =
		new JXStaticText("Bcc:", itsToolBar->GetWidgetEnclosure(),
			JXWidget::kFixedLeft, JXWidget::kFixedTop, 
			52,103,40,17);
	assert(itsBCCLabel != NULL);
	
	itsBCCInput =
		new JXInputField(itsToolBar->GetWidgetEnclosure(),
			JXWidget::kHElastic, JXWidget::kFixedTop, 
			100,100,w - inputAdjust,20);
	assert(itsBCCInput != NULL);
	itsBCCInput->SetDefaultFont(GGetPrefsMgr()->GetDefaultMonoFont(), kJDefaultFontSize);
	
	itsSubjectLabel =
		new JXStaticText("Subject:", itsToolBar->GetWidgetEnclosure(),
			JXWidget::kFixedLeft, JXWidget::kFixedTop, 
			32,133,60,17);
	assert(itsSubjectLabel != NULL);
	
	itsSubjectInput =
		new JXInputField(itsToolBar->GetWidgetEnclosure(),
			JXWidget::kHElastic, JXWidget::kFixedTop, 
			100,130,w - inputAdjust,20);
	assert(itsSubjectInput != NULL);
	ListenTo(itsSubjectInput);
	itsSubjectInput->SetDefaultFont(GGetPrefsMgr()->GetDefaultMonoFont(), kJDefaultFontSize);

	itsEditorSet = 
		new JXScrollbarSet(itsToolBar->GetWidgetEnclosure(),
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0,160,w,newHeight - 160);
	assert(itsEditorSet != NULL);
	
	itsEditor = 
		new GMessageEditor(menuBar, 
			itsEditorSet, itsEditorSet->GetScrollEnclosure(),
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0,0,w,newHeight - 160);
	assert (itsEditor != NULL);
	itsEditor->SetBackColor(GetColormap()->GetWhiteColor());

	itsToInput->ShareEditMenu(itsEditor, kFalse, kFalse);
	itsToInput->ShouldAllowDragAndDrop(kTrue);

	itsReplyToInput->ShareEditMenu(itsEditor, kFalse, kFalse);
	itsReplyToInput->ShouldAllowDragAndDrop(kTrue);

	itsCCInput->ShareEditMenu(itsEditor, kFalse, kFalse);
	itsCCInput->ShouldAllowDragAndDrop(kTrue);

	itsBCCInput->ShareEditMenu(itsEditor, kFalse, kFalse);
	itsBCCInput->ShouldAllowDragAndDrop(kTrue);

	itsSubjectInput->ShareEditMenu(itsEditor, kFalse, kFalse);
	itsSubjectInput->ShouldAllowDragAndDrop(kTrue);

	itsSendButton = 
		new JXTextButton("Send", itsToolBar->GetWidgetEnclosure(),
			JXWidget::kFixedRight, JXWidget::kFixedTop, 
			w - kSendBuffer,10,70,20);
	assert(itsSubjectInput != NULL);
//	itsSendButton->SetShortcuts("#s");
	ListenTo(itsSendButton);

	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(kSendCmd, send_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, kSendCmd);
		itsToolBar->AppendButton(itsFileMenu, kSaveCmd);
		}

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

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

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

void
GMessageEditDir::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 == itsMessageMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleMessageMenu(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 == itsMessageMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateMessageMenu();
		}
	else if (sender == itsSendButton && message.Is(JXButton::kPushed))
		{
		HandleFileMenu(kSendCmd);
		}
	else if (sender == itsToInput && message.Is(JXWidget::kLostFocus))
		{
		JString text = itsToInput->GetText();
		if (!text.IsEmpty())
			{
			AdjustWindowTitle();
			}
		}
	else if (sender == itsSubjectInput && message.Is(JXWidget::kLostFocus))
		{
		JString text = itsSubjectInput->GetText();
		if (!text.IsEmpty())
			{
			AdjustWindowTitle();
			}
		}
	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();
			JPtrArray<JString> names;
			GParseNameLists(itsToInput->GetText(), itsCCInput->GetText(), 
							itsBCCInput->GetText(), names);

			JString buffer;
			JBoolean ok = 
				GEncryptPGP2_6_2(itsEditor->GetText(), passwd, &names, &buffer);
			if (ok && !buffer.IsEmpty())
				{
				itsEditor->SelectAll();
				itsEditor->Paste(buffer);
				}
			}
		itsPasswdDialog = NULL;
		}
	else if (sender == itsMessage)
		{
		if (message.Is(SMTPMessage::kMessageSent))
			{
			Close();
			itsMessage = NULL;
			}
		else if (message.Is(SMTPMessage::kSendFailure))
			{
			GetWindow()->Show();
			itsMessage = NULL;
			}
		}
	else
		{
		GMManagedDirector::Receive(sender, message);
		}

}

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


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

void
GMessageEditDir::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 == kSendCmd)
		{
		Send();
		}
	else if (index == kSaveCmd)
		{
		if (itsFileName.IsEmpty())
			{
			JXGetChooseSaveFile()->SaveFile("Save text as:","", "",  &itsFileName);
			}
		if (!itsFileName.IsEmpty())
			{
			ofstream os(itsFileName);
			if (os.good())
				{
				itsEditor->GetText().Print(os);
				JString path;
				JString name;
				JSplitPathAndName(itsFileName, &path, &name);
				JString menuName = "Save message (" + name + ")";
				itsFileMenu->SetItemText(kSaveCmd, menuName);
				}
			else
				{
				JString notice = "Unable to open file " + itsFileName;
				JGetUserNotification()->ReportError(notice);
				}
			}
		}
	else if (index == kSaveAsCmd)
		{
		JXGetChooseSaveFile()->SaveFile("Save text as:","", "",  &itsFileName);
		if (!itsFileName.IsEmpty())
			{
			ofstream os(itsFileName);
			if (os.good())
				{
				itsEditor->GetText().Print(os);
				JString path;
				JString name;
				JSplitPathAndName(itsFileName, &path, &name);
				JString menuName = "Save message (" + name + ")";
				itsFileMenu->SetItemText(kSaveCmd, menuName);
				}
			else
				{
				JString notice = "Unable to open file " + itsFileName;
				JGetUserNotification()->ReportError(notice);
				}
			}
		}
	else if (index == kDiscardCmd)
		{
		Close();
		}
	else if (index == kQuitCmd)
		{
		JXGetApplication()->Quit();
		}
}

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


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

void
GMessageEditDir::UpdateMessageMenu()
{
	itsMessageMenu->EnableItem(kSigCmd);
	if (itsSentTextFileName->IsEmpty())
		{
		itsMessageMenu->DisableItem(kQuoteCmd);
		itsMessageMenu->DisableItem(kUnquoteCmd);
		}
	else
		{
		itsMessageMenu->EnableItem(kQuoteCmd);
		itsMessageMenu->EnableItem(kUnquoteCmd);
		}
	if (GEncryptionEnabled())
		{
		itsMessageMenu->EnableItem(kEncryptCmd);
		}
	else
		{
		itsMessageMenu->DisableItem(kEncryptCmd);
		}
	if (itsShowReplyTo)
		{
		itsMessageMenu->CheckItem(kShowRepToCmd);
		}
	if (itsShowCC)
		{
		itsMessageMenu->CheckItem(kShowCcCmd);
		}
	if (itsShowBCC)
		{
		itsMessageMenu->CheckItem(kShowBccCmd);
		}
}

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


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

void
GMessageEditDir::HandleMessageMenu
	(
	const JIndex index
	)
{
	if (index == kQuoteCmd)
		{
		InsertText(kTrue);
		}
	else if (index == kUnquoteCmd)
		{
		InsertText(kFalse);
		}
	else if (index == kSigCmd)
		{
		JString homeDir;
		if (JGetHomeDirectory(&homeDir))
			{
			JAppendDirSeparator(&homeDir);
			JString sigFile = homeDir + ".signature";
			if (JFileExists(sigFile))
				{
				ifstream is(sigFile);
				if (is.good())
					{
					JString sig;
					JReadFile(is, &sig);
					itsEditor->Paste(sig);
					}
				}
			else
				{
				JGetUserNotification()->ReportError("Can't find signature file.");
				}
			}
		else
			{
			JGetUserNotification()->ReportError("Can't find home directory.");
			}
		}
	else if (index == kInsertTextCmd)
		{
		JString filename;
		if (JXGetChooseSaveFile()->ChooseFile("Text file","",&filename))
			{
			JString buffer;
			JReadFile(filename, &buffer);
			JBoolean ok = kTrue;
			if (itsEditor->ContainsIllegalChars(buffer))
				{
				ok = JGetUserNotification()->AskUserYes("This file contains illegal characters. It is probably a binary file. Are you sure you want to insert it?");
				}
			if (ok)
				{
				itsEditor->Paste(buffer);
				}
			}
		}
	else if (index == kEncryptCmd)
		{
		if (itsToInput->GetText().IsEmpty())
			{
			JGetUserNotification()->ReportError("You must specify a recipient.");
			}
		else
			{
			if (GGetPrefsMgr()->GetEncryptionType() == GPrefsMgr::kPGP2_6)
				{
				assert(itsPasswdDialog == NULL);
				itsPasswdDialog = new JXGetPasswordDialog(this);
				assert(itsPasswdDialog != NULL);
				ListenTo(itsPasswdDialog);
				itsPasswdDialog->BeginDialog();
				}
			else
				{
				JPtrArray<JString> names;
				GParseNameLists(itsToInput->GetText(), itsCCInput->GetText(), 
								itsBCCInput->GetText(), names);

				JString buffer;
				JBoolean ok = 
					GEncryptGPG1_0(itsEditor->GetText(), &names, &buffer);
				if (ok && !buffer.IsEmpty())
					{
					itsEditor->SelectAll();
					itsEditor->Paste(buffer);
					}
				}
			}
		}
	else if (index == kShowRepToCmd)
		{
		itsShowReplyTo = JNegate(itsShowReplyTo);
		AdjustInputFields();
		if (itsShowReplyTo)
			{
			itsReplyToInput->Focus();
			}
		}
	else if (index == kShowCcCmd)
		{
		itsShowCC = JNegate(itsShowCC);
		AdjustInputFields();
		if (itsShowCC)
			{
			itsCCInput->Focus();
			}
		}
	else if (index == kShowBccCmd)
		{
		itsShowBCC = JNegate(itsShowBCC);
		AdjustInputFields();
		if (itsShowBCC)
			{
			itsBCCInput->Focus();
			}
		}
}

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


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

void
GMessageEditDir::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()->SaveEditorWindowSize(GetWindow());
		}

}

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


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

void
GMessageEditDir::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(kSendHelpName);
		}
	else if (index == kChangesCmd)
		{
		(JXGetHelpManager())->ShowSection(kChangeLogName);
		}
	else if (index == kCreditsCmd)
		{
		(JXGetHelpManager())->ShowSection(kCreditsName);
		}
}

/******************************************************************************
 Send

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

void
GMessageEditDir::Send()
{
	if (itsToInput->GetText().IsEmpty())
		{
		JGetUserNotification()->ReportError("You must specify a recipient.");
		itsToInput->Focus();
		return;
		}

	GetWindow()->Hide();
	JXGetApplication()->DisplayBusyCursor();
	itsMessage = new SMTPMessage();
	assert(itsMessage != NULL);
	ListenTo(itsMessage);
	itsMessage->SetTo(itsToInput->GetText());
	JString username = GGetPrefsMgr()->GetSMTPUser();
	itsMessage->SetFrom(username);
	itsMessage->SetSubject(itsSubjectInput->GetText());
	itsMessage->SetCC(itsCCInput->GetText());
	itsMessage->SetBCC(itsBCCInput->GetText());
	itsMessage->SetReplyTo(itsReplyToInput->GetText());
	itsMessage->SetData(itsEditor->GetText());
	itsMessage->Send();
}

/******************************************************************************
 Close

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

JBoolean
GMessageEditDir::Close()
{
	return GMManagedDirector::Close();
}

/******************************************************************************
 SetTo

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

void
GMessageEditDir::SetTo
	(
	const JString& to
	)
{
	JString temp = to;
	temp.TrimWhitespace();
	GCompressWhitespace(&temp);
	itsToInput->SetText(temp);
	AdjustWindowTitle();
	itsEditor->Focus();
}

/******************************************************************************
 SetCC

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

void
GMessageEditDir::SetCC
	(
	const JString& cc
	)
{
	JString temp(cc);
	temp.TrimWhitespace();
	GCompressWhitespace(&temp);
	if (!temp.IsEmpty())
		{
		itsCCInput->SetText(temp);
		itsShowCC = kTrue;
		AdjustInputFields();
		}
}

/******************************************************************************
 SetSubject

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

void
GMessageEditDir::SetSubject
	(
	const JString& subject
	)
{
	itsSubjectInput->SetText(subject);
	AdjustWindowTitle();
}

/******************************************************************************
 SetSentFrom

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

void
GMessageEditDir::SetSentFrom
	(
	const JString& sentfrom
	)
{
	*itsSentFrom = sentfrom;
	itsSentFrom->TrimWhitespace();
}

/******************************************************************************
 SetSentDate

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

void
GMessageEditDir::SetSentDate
	(
	const JString& sentdate
	)
{
	*itsSentDate = sentdate;
}

/******************************************************************************
 SetText

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

void
GMessageEditDir::SetText
	(
	const JString& filename
	)
{
	*itsSentTextFileName = filename;
}

/******************************************************************************
 InsertText

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

void
GMessageEditDir::InsertText
	(
	const JBoolean marked
	)
{
	JString text;
	ifstream is(*itsSentTextFileName);
	JReadAll(is, &text);
	JIndex startIndex;
	itsEditor->GetCaretLocation(&startIndex);

	if (!marked)
		{
		itsEditor->Paste(text);
		}
	else
		{
		if (itsShowReplyString)
			{
			JString replystring(*itsReplyString);
			JIndex findindex;
			if (replystring.LocateSubstring("$d", &findindex))
				{
				replystring.ReplaceSubstring(findindex, findindex+1, *itsSentDate);
				}
			if (replystring.LocateSubstring("$f", &findindex))
				{
				replystring.ReplaceSubstring(findindex, findindex+1, *itsSentFrom);
				}
			if (replystring.GetLastCharacter() != '\n')
				{
				replystring.Append("\n");
				}

			replystring.Append("\n");
			text.Prepend(replystring);
			}
		GQuoteString(&text, JNegate(itsShowReplyString));
		itsEditor->Paste(text);
		}
	itsEditor->SelectLine(itsEditor->GetLineForChar(startIndex));
	itsEditor->TEScrollToSelection(kFalse);
	itsEditor->SetCaretLocation(startIndex);
}

/******************************************************************************
 AdjustInputFields

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

void
GMessageEditDir::AdjustInputFields()
{
	JSize inputcount = 0;
	if (itsShowReplyTo)
		{
		itsReplyToInput->Place(100,40);
		itsReplyToLabel->Place(20,43);
		inputcount++;
		itsReplyToInput->Show();
		itsReplyToLabel->Show();
		}
	else
		{
		itsReplyToInput->Hide();
		itsReplyToLabel->Hide();
		}
	if (itsShowCC)
		{
		itsCCInput->Place(100,40 + inputcount*30);
		itsCCLabel->Place(58,43 + inputcount*30);
		inputcount++;
		itsCCInput->Show();
		itsCCLabel->Show();
		}
	else
		{
		itsCCInput->Hide();
		itsCCLabel->Hide();
		}
	if (itsShowBCC)
		{
		itsBCCInput->Place(100,40 + inputcount*30);
		itsBCCLabel->Place(52,43 + inputcount*30);
		inputcount++;
		itsBCCInput->Show();
		itsBCCLabel->Show();
		}
	else
		{
		itsBCCInput->Hide();
		itsBCCLabel->Hide();
		}
	itsSubjectInput->Place(100, 40 + inputcount*30);
	itsSubjectLabel->Place(32, 43 + inputcount*30);
	inputcount++;
	
	JSize currentheight = itsEditorSet->GetFrameHeight();
	JRect frame = itsEditorSet->GetFrame();
	JCoordinate newpos = 40 + inputcount*30;
	JCoordinate oldpos = frame.top;
	itsEditorSet->Move(0, newpos - oldpos);
	itsEditorSet->AdjustSize(0, oldpos - newpos);
//	GetWindow()->AdjustSize(0, newpos-oldpos);
}

/******************************************************************************
 AdjustWindowTitle

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

void
GMessageEditDir::AdjustWindowTitle()
{
	JString title;
	if (!(itsToInput->GetText().IsEmpty()))
		{
		title = itsToInput->GetText();
		JIndex findindex;
		if (title.LocateSubstring("@", &findindex))
			{
			title.RemoveSubstring(findindex, title.GetLength());
			}
		}
	if (!(itsSubjectInput->GetText().IsEmpty()))
		{
		if (!title.IsEmpty())
			{
			title.Append(":");
			}
		JString sub = itsSubjectInput->GetText();
		const JSize kMaxSubjectWidth = 10;
		if (sub.GetLength() > kMaxSubjectWidth)
			{
			sub.RemoveSubstring(10, sub.GetLength());
			}
		title.Append(sub);
		}
	GetWindow()->SetTitle(title);
	GGetDirMgr()->DirectorChanged(this);
}

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


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

void
GMessageEditDir::SaveState
	(
	ostream& os
	)
{
	os << itsToInput->GetText();
	os << itsReplyToInput->GetText();
	os << itsCCInput->GetText();
	os << itsBCCInput->GetText();
	os << itsSubjectInput->GetText();

	os << itsShowReplyTo << " ";
	os << itsShowCC << " ";
	os << itsShowBCC << " ";

	os << *itsReplyString;
	os << *itsReplyMark;
	os << *itsSentFrom;
	os << *itsSentDate;

	os << itsEditor->GetText();

	JString buffer;
	if (JFileExists(*itsSentTextFileName))
		{
		JReadFile(*itsSentTextFileName, &buffer);
		}
	os << buffer;

	GetWindow()->WriteGeometry(os);

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

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


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

void
GMessageEditDir::ReadState
	(
	istream& is
	)
{
	JString buffer;
	is >> buffer;
	itsToInput->SetText(buffer);
	is >> buffer;
	itsReplyToInput->SetText(buffer);
	is >> buffer;
	itsCCInput->SetText(buffer);
	is >> buffer;
	itsBCCInput->SetText(buffer);
	is >> buffer;
	itsSubjectInput->SetText(buffer);

	JBoolean visible;
	is >> visible;
	itsShowReplyTo = visible;
	is >> visible;
	itsShowCC = visible;
	is >> visible;
	itsShowBCC = visible;
	
	is >> *itsReplyString;
	is >> *itsReplyMark;
	is >> *itsSentFrom;
	is >> *itsSentDate;

	is >> buffer;
	itsEditor->SetText(buffer);

	is >> buffer;
	if (!buffer.IsEmpty())
		{
		*itsSentTextFileName = JGetTempFileName("/tmp/");
		ofstream os(*itsSentTextFileName);
		buffer.Print(os);
		}

	GetWindow()->ReadGeometry(is);
	JCoordinate hval, vval;
	is >> hval;
	is >> vval;
	JXScrollbar* hsb = itsEditorSet->GetHScrollbar();
	JXScrollbar* vsb = itsEditorSet->GetVScrollbar();
	hsb->SetValue(hval);
	vsb->SetValue(vval);

	AdjustInputFields();
}

/******************************************************************************
 QuoteLineRange

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

void
GMessageEditDir::QuoteLineRange
	(
	const JIndex linestart,
	const JIndex lineend
	)
{
	for (JSize i = linestart+1; i <= lineend; i++)
		{
		itsEditor->SelectLine(i-1);
		JString test;
		itsEditor->GetSelection(&test);
		test.TrimWhitespace();
		if ((test == "\n") || test.IsEmpty())
			{
			itsEditor->SelectLine(i);
			itsEditor->GetSelection(&test);
			test.TrimWhitespace();
			JString mark;
			if (test.BeginsWith(">"))
				{
				mark = ">";
				}
			else if (!test.IsEmpty())
				{
				mark = "> ";
				}
			itsEditor->GoToLine(i);
			itsEditor->Paste(mark);
			}
		}
}


/******************************************************************************
 CheckForPendingMessage

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

void
GMessageEditDir::CheckForPendingMessage()
{
	if (itsMessage != NULL)
		{
		itsMessage->BlockUntilOkOrFail();
		}
}
