int CExtImpl::EncryptSignMessage(HWND hwnd,
								 IMessage *pmsg,
								 RECIPIENTDIALOGSTRUCT *prds,
								 PGPOptionListRef *pSignOptions)
{
	IStream *pstrmBody = 0;
	STATSTG StreamStats;
	DWORD dwInSize;
	UINT nOutSize;
	BOOL bExchangeUser = FALSE;
	char *pInput;
	char *pOutput = NULL;
	LPMAPITABLE ptableAttach = 0;
	SizedSPropTagArray(1, tagaTable) = {
			1, {PR_ATTACH_NUM}};
	SRowSet *prAttach = 0;
	PGPError nError = kPGPError_NoErr;
	HRESULT hr;
	char szName[256];
	char szFile[256];

	UIGetString(szName, sizeof(szName), IDS_LOGNAME);
	UIGetString(szFile, sizeof(szFile), IDS_DLL);

	pmsg->GetAttachmentTable(0, &ptableAttach);
	HrQueryAllRows(ptableAttach, (SPropTagArray *)&tagaTable, 
					NULL, NULL, 0, &prAttach);

	hr = pmsg->OpenProperty(PR_BODY, &IID_IStream, STGM_READ, 
			0, (IUnknown**)&pstrmBody);
	if (FAILED(hr))
	{
		UIDisplayStringID(hwnd, IDS_E_NOBODY);
		ptableAttach->Release();
		return kPGPError_ItemNotFound;
	}
		
	pstrmBody->Stat(&StreamStats, STATFLAG_NONAME);
	dwInSize = StreamStats.cbSize.LowPart;
		
	pInput = (char *) calloc(dwInSize+1, sizeof(char));
	if (!pInput)
	{
		UIDisplayStringID(hwnd, IDS_E_NOMEMORY);
		pstrmBody->Release();
		ptableAttach->Release();
		return kPGPError_OutOfMemory;
	}
	pstrmBody->Read(pInput, dwInSize, &dwInSize);
	pstrmBody->Release();

	pInput[dwInSize] = 0;

	nError = EncryptSignBuffer(UIGetInstance(), hwnd, _pgpContext, 
				_tlsContext, szName, szFile, pInput, 
				dwInSize, prds, NULL, pSignOptions, (VOID ** )&pOutput, 
				&nOutSize, _bEncrypt, _bSign, FALSE);

	if ((dwInSize > 0) && IsntPGPError(nError))
	{
		LARGE_INTEGER li = {0,0};
		ULARGE_INTEGER uli = {1,0};
		BOOL fPartied;

		pmsg->OpenProperty(PR_BODY, &IID_IStream, STGM_READWRITE, 
				MAPI_MODIFY, (IUnknown**)&pstrmBody);
		
		pstrmBody->Seek(li, STREAM_SEEK_SET, NULL);
		pstrmBody->Write("\0", 1, NULL);
		pstrmBody->SetSize(uli);
		pstrmBody->Commit(STGC_DEFAULT);
		pstrmBody->Release();
		RTFSync(pmsg, RTF_SYNC_BODY_CHANGED, &fPartied);

		pmsg->OpenProperty(PR_BODY, &IID_IStream, STGM_READWRITE, 
			MAPI_MODIFY, (IUnknown**)&pstrmBody);
	}

	if (IsntPGPError(nError))
	{
		LARGE_INTEGER li = {0,0};
		ULARGE_INTEGER uli = {nOutSize + prAttach->cRows, 0};
		BOOL fPartied;

		pstrmBody->Seek(li, STREAM_SEEK_SET, NULL);
		pstrmBody->Write(pOutput, nOutSize, NULL);
		pstrmBody->SetSize(uli);
		pstrmBody->Commit(STGC_DEFAULT);
		pstrmBody->Release();
		RTFSync(pmsg, RTF_SYNC_BODY_CHANGED, &fPartied);
		PGPFreeData(pOutput);
	}
		
	free(pInput);

	if (IsntPGPError(nError))
	{
		hr = pmsg->OpenProperty(PR_BODY_HTML, &IID_IStream, STGM_READWRITE, 
				MAPI_MODIFY, (IUnknown**)&pstrmBody);
		
		if (FAILED(hr))
			goto NoBodyHTML;
		else
		{
			LARGE_INTEGER li = {0,0};
			ULARGE_INTEGER uli = {1,0};
			BOOL fPartied;
			
			pstrmBody->Seek(li, STREAM_SEEK_SET, NULL);
			pstrmBody->Write("\0", 1, NULL);
			pstrmBody->SetSize(uli);
			pstrmBody->Commit(STGC_DEFAULT);
			pstrmBody->Release();
			RTFSync(pmsg, RTF_SYNC_BODY_CHANGED, &fPartied);
		}
	}

NoBodyHTML:
	if (prAttach->cRows && IsntPGPError(nError))
		nError = EncryptSignAttachment(hwnd, pmsg, nOutSize,
					prAttach, prds, pSignOptions);

	ptableAttach->Release();
	return nError;
}
BOOL 
EncryptSignRichEditText(char** ppBuffer, 
						long* pLength, 
						BOOL bEncrypt, 
						BOOL bSign, 
						char** pAddresses, 
						long NumAddresses,
						char* pAttachments,
						char** ppOutAttachments)
{
	BOOL ReturnValue = FALSE;
	void* pOutput = NULL;
	long outSize = 0;
	PGPError error = kPGPError_NoErr;
	PGPOptionListRef userOptions = NULL;
	PGPclRecipientDialogStruct *prds = NULL;	
	char szExe[256];
	char szDll[256];

	LoadString(g_hinst, IDS_EXE, szExe, sizeof(szExe));
	LoadString(g_hinst, IDS_DLL, szDll, sizeof(szDll));

	// allocate a recipient dialog structure
	prds = (PGPclRecipientDialogStruct *) 
			calloc(sizeof(PGPclRecipientDialogStruct), 1);

	if (!prds)
	{
		PGPclErrorBox(g_hwndEudoraMainWindow, kPGPError_OutOfMemory);
		return FALSE;
	}

	error =	PGPclOpenDefaultKeyrings(g_pgpContext, 
				kPGPOpenKeyDBFileOptions_Mutable, &(prds->keydbOriginal));

	if (IsPGPError(error))
		error =	PGPclOpenDefaultKeyrings(g_pgpContext, 
					kPGPOpenKeyDBFileOptions_None, &(prds->keydbOriginal));

	if (IsPGPError(error))
	{
		char szTitle[255];
		char szBuffer[1024];
		
		LoadString(g_hinst, IDS_DLL, szTitle, 254);
		LoadString(g_hinst, IDS_Q_NOKEYRINGS, szBuffer, 1023);
		
		if (MessageBox(g_hwndEudoraMainWindow, szBuffer, szTitle, MB_YESNO))
		{
			char szPath[MAX_PATH];
			
			PGPclGetPath(kPGPclPGPkeysExeFile, szPath, MAX_PATH-1);
			PGPclExecute(szPath, SW_SHOW);
		}
		
		return S_FALSE;
	}

	if(prds && bEncrypt)
	{
		char szTitle[256]		= {0x00};	// title for recipient dialog
		UINT recipientReturn	= FALSE;	// recipient dialog result

		LoadString(GetModuleHandle("PGPplugin.dll"), 
			IDS_TITLE_RECIPIENTDIALOG, szTitle, sizeof(szTitle));

		if( IsntPGPError(error) )
		{
			prds->context			= g_pgpContext;
			prds->tlsContext		= g_tlsContext;
			prds->Version			= kPGPCurrentRecipVersion;
			prds->hwndParent		= g_hwndEudoraMainWindow;
			prds->szTitle			= szTitle;
			prds->dwOptions			= kPGPclASCIIArmor;	

			prds->dwDisableFlags	= kPGPclDisableWipeOriginal |
									  kPGPclDisableASCIIArmor |
									  kPGPclDisableSelfDecryptingArchive |
									  kPGPclDisableInputIsText;

			prds->dwNumRecipients	= NumAddresses;	
			prds->szRecipientArray	= pAddresses;

			// If shift is pressed, force the dialog to pop.
			if (GetAsyncKeyState( VK_CONTROL) & 0x8000)
				prds->dwDisableFlags |= kPGPclDisableAutoMode;

			// See who we wish to encrypt this to
			recipientReturn = PGPclRecipientDialog( prds );
		}

		if (prds->keydbAdded != NULL)
		{
			PGPUInt32 numKeys;
			PGPKeySetRef keySet;

			PGPNewKeySet(prds->keydbAdded, &keySet);
			PGPCountKeys(keySet, &numKeys);
			if (numKeys > 0)
				PGPclImportKeys(g_pgpContext, g_tlsContext, prds->hwndParent,
					keySet, prds->keydbOriginal, 
					kPGPclNoDialogForValidSingletons);

			PGPFreeKeySet(keySet);
			PGPFreeKeyDB(prds->keydbAdded);
			prds->keydbAdded = NULL;
		}

		if (!recipientReturn)
		{
			if (prds->keydbSelected != NULL)
				PGPFreeKeyDB(prds->keydbSelected);

			PGPFreeKeyDB(prds->keydbOriginal);
			free(prds);
			return FALSE;
		}
	}

	if( IsntPGPError(error) )
	{
		error = EncryptSignBuffer(g_hinst, g_hwndEudoraMainWindow,
					g_pgpContext, g_tlsContext, szExe, szDll,
					*ppBuffer, *pLength, prds, NULL, &userOptions, &pOutput,
					&outSize, bEncrypt, bSign, FALSE, FALSE);
	}
	else
	{
		PGPclEncDecErrorBox(g_hwndEudoraMainWindow, error);
	}

	*pLength = outSize;

	if( IsntPGPError(error) )
	{
		if( pOutput )
		{
			*ppBuffer = (char*)HeapReAlloc(	GetProcessHeap(), 
											HEAP_ZERO_MEMORY, 
											*ppBuffer, 
											*pLength + 1);

			if(*ppBuffer)
			{
				ReturnValue = TRUE;
				memcpy(*ppBuffer, (char*)pOutput, *pLength);
				*(*ppBuffer + *pLength) = 0x00; // NULL terminate the string
				memset(pOutput, 0x00, *pLength);
			}
			else 
			{
				error = kPGPError_OutOfMemory;
			}

			PGPFreeData(pOutput);
		}
	}
	
	// are there attachments?
	if(IsntPGPError(error) && pAttachments && *pAttachments) 
	{
		error = EncryptAttachments(	pAttachments, 
									ppOutAttachments,
									prds,
									userOptions,
									bEncrypt,
									bSign);

	}

	if(userOptions != NULL)
	{
		PGPFreeOptionList(userOptions);
	}

	if (prds)
	{
		if (prds->keydbSelected != NULL)
			PGPFreeKeyDB(prds->keydbSelected);

		PGPFreeKeyDB(prds->keydbOriginal);
		free(prds);
	}

	return ReturnValue;
}