/*
 * WvCompos.c
 *
 * Common window handling for post/mail windows
 * DefComposeWndProc is not used as a callback - but as a default handler for
 * messages sent to WinVnMailWndProc and WinVnPostWndProc 
 *
 * john s. cooper (jcooper@netcom.com)
 * 9/24/94
 *
 * $Id: wvcompos.c 1.16 1996/08/31 06:59:18 dumoulin Exp $
 */
#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#include "sha1.h"		//cancel-key, cancel-lock
#include "sha256.h"		//cancel-key, cancel-lock

#pragma hdrstop
#include <ctype.h>                              // for isspace()
#include <assert.h>
#include <stdlib.h>
#ifdef USE_3D_CONTROLS
#include "ctl3d.h"
#endif

#ifdef COMMCTRL
#include <commctrl.h>
//#define RICHEDIT
#endif

#ifdef RICHEDIT
#include "richedit.h"
#endif

#ifdef _WIN32
#if defined(_WIN64)
#define WINVN_ARCHITECTURE "(x86 64bit)"
#elif defined(_X86_)
#define WINVN_ARCHITECTURE "(x86 32bit)"
#elif defined(_ALPHA_)
#define WINVN_ARCHITECTURE "(alpha 32bit)"
#elif defined(_MIPS_)
#define WINVN_ARCHITECTURE "(mips 32bit)"
#elif defined(_PPC_)
#define WINVN_ARCHITECTURE "(ppc 32bit)"
#endif
#else
#define WINVN_ARCHITECTURE "(16bit)"
#endif

extern char attachmentID[MAXINTERNALLINE];
extern INT_PTR CALLBACK WinVnAttachesDlg(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam);

/*
 * Forward declarations
 */
TypAttachment *PrepNewAttachment (WndEdit * compWnd);
void AskForNewAttachment (WndEdit * compWnd);
void DeleteAttachment (WndEdit * compWnd, int num);
void SetWordWrap (WndEdit * compWnd, BOOL enable);
void BrowseMail (WndEdit * editWnd, int button);
BOOL PrepareComposition (WndEdit * compWnd);
BOOL ChangeShowHeaderControls (WndEdit * compWnd);
HWND GetNextHeaderWnd (WndEdit * compWnd, HWND hCur, BOOL next);
void ShowComposeControls (WndEdit * compWnd);
void PrepareControlMenu (WndEdit * compWnd, HWND hControl, BOOL isAttach);
int DoEditCommands (HWND hWndEdit, WPARAM wParam, LPARAM lParam);
BOOL DoEditClose (HWND hWnd, int dirty);


BOOL EditHeaderFlag = FALSE;    //shimomai

/* External function */
DEF void EditHeaders (WndEdit * editWnd);
DEF BOOL SearchLineTextBlock (TypTextBlock * textBlock, char *prefix);
DEF unsigned long iSearchLineTextBlock (TypTextBlock * textBlock, char *prefix);
DEF BOOL ReconstructTextBlock (HWND hParentWnd, TypTextBlock **textBlock);
DEF BOOL GetHeaderLineTextBlock (char *content, TypTextBlock * textBlock, char *prefix, BOOL bZot = TRUE);

#if 0

BOOL TestReferencesHeader(WndEdit *compWnd)
{
  WVString mybuf;
  unsigned long i

  if (compWnd->extraHeaders == NULL) {
    return TRUE;
  }
  i = iSearchLineTextBlock(compWnd->extraHeaders, "References:");
  int broken = 0;
  if (i < compWnd->extraHeader->numLines) {
    const char *p = (const char *)TextBlockLine(compWnd->extraHeaders, i);
    int state = 0; // 0.out 1-. in
    int ch;
#define ref_fail       { broken = 1; break; }
#define ref_assert(x)  if (!(x)) ref_fail
    while (NIL != (ch = *p ++)) {
      if (ch == '<') {
        // mesid isn't include <
        ref_assert(state == 0);
        state = 1;
      } else
        if (ch == '>') {
          // blank isn't include '>' | mesid isn't '<>'
          ref_assert(state > 2);
          state = 0;
        } else
        if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') {
            // msgid isn't include LWSP/CRLF
            ref_assert(state == 0);
        } else
        if (ch < 0x20 || ch >= 0x7f) {
          // references: isn't iclude controls or 8bit
          ref_fail;
        }
        if (state) {
         ++ state;
        }
      }
#undef ref_fail
#undef ref_assert
  }
  if (broken) {
    return FALSE;
  }
  return TRUE;
}

#endif

LRESULT CALLBACK WinVnComposeWndProc (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam)
{
	HMENU hMenu, hSubMenu;
	HWND hControl;
	WndEdit *compWnd;
	RECT cRect;
	int mstatus;
	BOOL enable, down;
	BOOL endless;
	int actualwidth;
	char *t1;
	char *t2;
	register int i;
	int imes = 0;         // shimomai

	compWnd = GetComposeWnd (hWnd);

	if (message == uMSH_MOUSEWHEEL) message = WM_MYMOUSEWHEEL;

	switch (message) 
	{

		case WM_SYSCOMMAND:
			return (DefWindowProc (hWnd, message, wParam, lParam));

		case WM_CREATE:
			{
				compWnd = (WndEdit *)((LPCREATESTRUCT)lParam)->lpCreateParams;
				compWnd->hWnd = hWnd;
				compWnd->headerControls = (TypHeaderControls *) NULL;
				compWnd->numAttachments = 0;
				compWnd->busy = FALSE;
				compWnd->nextBatchIndex = 0;
       
				//SetHandleBkBrush (hWnd, (HBRUSH) GetStockObject (LTGRAY_BRUSH));
				SetHandleBkBrush (hWnd, (HBRUSH) GetSysColorBrush(COLOR_BTNFACE));
				 
				//set some tab stops
				UINT tStop[] = {8,16,24,32,40,48,56,64,72,80,88,96,104,112,120};

				for (int i = 0; i < sizeof(tStop)/sizeof(tStop[0]); i++)
					tStop[i] = ::MulDiv(tStop[i], 4, LOWORD(::GetDialogBaseUnits()));

				Edit_SetTabStops(hWnd, sizeof(tStop)/sizeof(tStop[0]), &tStop);

				if (CreateComposeControls (compWnd) == FAIL)
					break;

				hMenu = GetMenu (hWnd);
				ModifyMenu (hMenu, 0, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT) GetSubMenu (hMenu, 0),
						(LPCSTR) (compWnd->composeType != DOCTYPE_MAIL) ? "&Post" : "&Mail");
				if (compWnd->composeType == DOCTYPE_POSTING ||compWnd->composeType ==  DOCTYPE_SUPERSEDE) 
				{
					NumPostWnds++;
				}
				else 
				{
					NumMailWnds++;
				}
				compWnd->dirty = DT_CLEAN;
				if (PrepareComposition (compWnd) != SUCCESS) 
				{
					DestroyWindow (hWnd);
				}
				else 
				{
					ShowWindow (hWnd, SW_SHOWNORMAL);
				}
				EnableSendComposition (compWnd, TRUE);
				EditHeaderFlag = FALSE;         //shimomai
			}
			break;

		case WM_CTLCOLORSTATIC:
			if ((HWND) lParam != compWnd->hWndEdit)
			{

				SetBkColor ((HDC) wParam, GetSysColor(COLOR_BTNFACE));
				SetTextColor ((HDC) wParam, BLACK_COLOR);
				return (LRESULT) GetSysColorBrush(COLOR_BTNFACE);
			}
			//fall through
		case WM_CTLCOLOREDIT:
		case WM_CTLCOLORMSGBOX:
		case WM_CTLCOLORLISTBOX:
			if ((HWND) lParam == compWnd->hWndEdit)
			{
				HDC hDC = (HDC) wParam;
				if (g_hPalette)
				{
					SelectPalette (hDC, g_hPalette, TRUE) ;
					RealizePalette (hDC) ;				
				}
				
				
				
				SetTextColor ((HDC) wParam, ArticleTextColor);
				SetBkColor ((HDC) wParam, ArticleBackgroundColor);
              /*
			   // Properly originate the background brush. This is
               // of use if the brush is a pattern instead of a
               // solid color.
               UnrealizeObject(hArticleBackgroundBrush);
               SetBrushOrgEx ((HDC)  wParam, 0, 0, NULL);

               // Return a handle to the background brush for the edit
               // control.
               */
			   return (LRESULT)hArticleBackgroundBrush;
			}

			//fall through					
		//case WM_CTLCOLORLISTBOX:
			SetBkColor ((HDC) wParam, GetSysColor(COLOR_WINDOW));
			return (LRESULT)GetSysColorBrush(COLOR_WINDOW);
		case WM_CTLCOLOR:
			{
				HDC hDC = (HDC) wParam;
				if (g_hPalette)
				{
					SelectPalette (hDC, g_hPalette, TRUE) ;
					RealizePalette (hDC) ;				
				}

			}
			
			SetBkColor ((HDC) wParam, ArticleBackgroundColor);
			return (LRESULT)hArticleBackgroundBrush;
			break;
			{
				{

#ifdef RICHEDIT
					if (compWnd->richedit)
					{
						CHARFORMAT cf;
						ZeroMemory( &cf, sizeof(CHARFORMAT));
						cf.cbSize = sizeof(CHARFORMAT);
						cf.dwMask = CFM_COLOR;
						cf.crTextColor = ArticleTextColor;
						SendMessage( compWnd->hWndEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cf);
						SendMessage( compWnd->hWndEdit, EM_SETCHARFORMAT, 0, (LPARAM) &cf);
					}
#endif						

					SetTextColor ((HDC) wParam, ArticleTextColor);
					if (imes == 1) 
					{        // shimomai
						SetBkColor ((HDC) wParam, ArticleBackgroundColor);
						return (LRESULT)hArticleBackgroundBrush;
					} 
					else 
					{
						SetTextColor ((HDC) wParam, BLACK_COLOR);
						SetBkColor ((HDC) wParam, GRAY_COLOR);
						//          return (LRESULT)hArticleBackgroundBrush;
						// Return handle to background brush for the edit control
							return (LRESULT) GetStockObject (LTGRAY_BRUSH);
					}
				}
			}
			break;

		case WM_SIZE:   
			ResizeComposeControls (compWnd, LOWORD (lParam), HIWORD (lParam));
			break;

		case WM_ACTIVATE:
			/* Switch back to the last control which had the focus */
			if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) 
			{
				SetFocus (compWnd->hLastFocusWnd);
			}
			break;

		/*******************************************************/
		/*** This code handles the Microsoft Intellimouse    ***/
		/*** wheel rotation.                                 ***/
		/*******************************************************/
		case WM_MYMOUSEWHEEL:
		case WM_MOUSEWHEEL:
		{
			int   zDelta;

			if (message == WM_MOUSEWHEEL) 
			{
				zDelta = (short) HIWORD(wParam);
			} 
			else 
			{
				zDelta = (int) wParam;
			}

			CTotalDelta += zDelta;
			if ((CScrollMode != WHEELSCROLL_DONT)  && (abs(CTotalDelta) >= WHEEL_DELTA)) 
			{
				CTotalDelta = 0;
				if ( zDelta > 0 )
				{
					if ((CScrollMode == WHEELSCROLL_SCROLL) && (MiddleButton_Is_Down)) 
					{
						if ((CPosScrollByWheel > 0) && (CScrollByWheel[CPosScrollByWheel-1]))
							CPosScrollByWheel--;
					} 
					else 
					{
						for (i = 0 ; i < CScrollByWheel[CPosScrollByWheel] ; i++) 
						{
							//ScrollIt (ThisDoc, (WPARAM) SB_LINEUP, lParam);
							SendMessage (compWnd->hWndEdit, WM_VSCROLL, (WPARAM)SB_LINEUP , (LPARAM)0); 
							InvalidateRect (compWnd->hWndEdit, NULL, TRUE);
						}
					}
				}
				else
				{
					if ((CScrollMode == WHEELSCROLL_SCROLL) && (MiddleButton_Is_Down)) 
					{
						if ((CPosScrollByWheel < (MAX_WHEEL_ENTRIES-1)) && (CScrollByWheel[CPosScrollByWheel+1]))
							CPosScrollByWheel++;
					} 
					else 
					{ 
						for (i = 0 ; i < CScrollByWheel[CPosScrollByWheel] ; i++ )
							//ScrollIt (ThisDoc, (WPARAM) SB_LINEDOWN, lParam);
							SendMessage (compWnd->hWndEdit, WM_VSCROLL, (WPARAM)SB_LINEDOWN , (LPARAM)0); 
						InvalidateRect (compWnd->hWndEdit, NULL, TRUE);
					}
				}
			}
		}
		break;

		case WM_MBUTTONDOWN:
			MiddleButton_Is_Down = TRUE;
			if (CScrollMode == WHEELSCROLL_CLICK) 
			{
				endless = FALSE; /* first loop assuemd as save */
				do 
				{
					CPosScrollByWheel++;
					if ( CPosScrollByWheel >= MAX_WHEEL_ENTRIES ) 
					{
						CPosScrollByWheel = 0;
						if (endless) break; /* prevent a endless loop in case this occures twice */
							endless = TRUE; /* remember first loop just encountered, now it could be endless */
					}
				} while (CScrollByWheel[CPosScrollByWheel] == 0);
			}
			break;

			case WM_MBUTTONUP:
				MiddleButton_Is_Down = FALSE;
				break;

			case WM_KEYDOWN:

			switch (wParam) 
			{
				case 'L':  //ctrl+L
					if (GetFocus () == compWnd->hWndEdit && GetKeyState(VK_CONTROL) < 0 )
					{
						SendMessage (compWnd->hWndEdit, EM_REPLACESEL, 0, (LPARAM)(LPCSTR)"\f");        // Thancks to TANAKA
						InvalidateRect (compWnd->hWndEdit, NULL, TRUE);
						return 0L;
					}
					break; 
				case 'I': //ctrl+I
				case 'T':  //ctrl+T
					if (GetFocus () == compWnd->hWndEdit && GetKeyState(VK_CONTROL) < 0)
					{
						SendMessage (compWnd->hWndEdit, EM_REPLACESEL, 0, (LPARAM)(LPCSTR)"\t");        // Thancks to TANAKA
						InvalidateRect (compWnd->hWndEdit, NULL, TRUE);
						return 0L;
					}
					break;

				case VK_F6:
					NextWindow (compWnd->hWnd, compWnd->composeType);
					break;

				case VK_TAB:
					if (GetFocus () == compWnd->hWndEdit && GetKeyState (VK_SHIFT) >=0 && GetKeyState(VK_CONTROL) >= 0)
					{
						SendMessage (compWnd->hWndEdit, EM_REPLACESEL, 0, (LPARAM)(LPCSTR)"\t");        // Thancks to TANAKA
						InvalidateRect (compWnd->hWndEdit, NULL, TRUE);
						return 0L;

					}
				case VK_RETURN:
				case VK_UP:
				case VK_DOWN:
					if (GetFocus () != compWnd->hWndEdit) 
					{
						if (wParam == VK_TAB) 
						{
							down = (GetKeyState (VK_SHIFT) >= 0);
						} 
						else if (wParam == VK_UP) 
						{
							down = FALSE;
						}
						else 
						{
							down = TRUE;                  // down arrow or enter
						}
						SetFocus (GetNextHeaderWnd (compWnd, GetFocus (), down));
						return 0L;
					}
					break;

				case VK_DELETE:
					if (GetFocus () == compWnd->headerControls->UI[HDR_ATTACH]) 
					{
						i = 1 + (int) SendMessage (compWnd->headerControls->UI[HDR_ATTACH],
																   LB_GETCURSEL, 0, 0L);
						if (i > 0 && i < compWnd->numAttachments) 
						{
							DeleteAttachment (compWnd, i);
						}
						return 0L;
					}
					break;
				case VK_INSERT:
					if (GetFocus () == compWnd->headerControls->UI[HDR_ATTACH]) 
					{
						AskForNewAttachment (compWnd);
						return 0L;
					}
					break;
			}
			return (DefWindowProc (hWnd, message, wParam, lParam)); /* handle it please */
			break;

			case WM_CHAR:
			case WM_KEYUP:
			switch (wParam) 
			{
				case VK_RETURN:
				case VK_TAB:
				case VK_F6:
				case VK_UP:
				case VK_DOWN:
					if (GetFocus () != compWnd->hWndEdit) 
					{
						return 0L;
					}
					break;

				case VK_INSERT:
				case VK_DELETE:
					if (GetFocus () == compWnd->headerControls->UI[HDR_ATTACH]) 
					{
						return 0L;
					}
					break;

				default:
				return (DefWindowProc (hWnd, message, wParam, lParam)); /* handle it please */
			}
			break;


		case WM_INITMENU:
			// set menu for whichever control has the focus 
			hControl = GetFocus ();
			PrepareControlMenu (compWnd, hControl,
							 (hControl == compWnd->headerControls->UI[HDR_ATTACH]));

			/* disable send if comm is busy */
			hMenu = GetMenu (hWnd);
			if (compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) 
			{
				enable = !CommBusy;
			}
			else 
			{
				enable = !SendingMail;
			}
			EnableMenuItem (GetSubMenu (hMenu, 0), IDM_SEND, enable ? ENABLE_MENU : DISABLE_MENU);

			break;

		case WM_HELP:
			DoHelp (hWnd, HELP_CONTEXT, (DWORD) 412);
			break;
		
		case WM_GETMINMAXINFO:
		    {
				LPMINMAXINFO pMinMax = (LPMINMAXINFO) lParam;
				if (compWnd &&  compWnd->bRestrictWidth)
				{
					pMinMax->ptMaxSize.x = compWnd->nFixedWidth;
					pMinMax->ptMaxTrackSize.x = compWnd->nFixedWidth;
					return 0L;
				}
			}
			break;


		case WM_COMMAND:
		/* Child control notifications -- edit wnd, buttons, attach listbox */
		if ((HWND) (UINT) lParam == compWnd->hWndEdit) 
		{
			if (GET_WM_COMMAND_CMD (wParam, lParam) == EN_CHANGE) 
			{
				compWnd->dirty = DT_DIRTY;
			}
			if (GET_WM_COMMAND_CMD (wParam, lParam) == EN_ERRSPACE) 
			{
				WVMessageBox(hWnd, IDS_COMPOS_LOWMEM, IDS_COMPOS_LOWTITLE, MB_OK | MB_ICONSTOP); 
				if (compWnd->dirty == DT_CLEAN)
					compWnd->dirty = DT_DIRTY; //flag to sender insuf. mem
					// MessageBox(hWnd, "Not enough space in edit buffer for this operation.\nTry making an attachment instead.", "Low Memory In Edit Buffer", MB_OK | MB_ICONSTOP);
			}
			return (0L);
		}
		else if (compWnd->headerControls->button[BTN_TO] &&
		(HWND) (UINT) lParam == compWnd->headerControls->button[BTN_TO]) 
		{
			if (GET_WM_COMMAND_CMD (wParam, lParam) == BN_CLICKED) 
			{
				BrowseMail (compWnd, HDR_TO);
			}
			return (0L);
		}
		else if (compWnd->headerControls->button[BTN_CC] &&
		(HWND) (UINT) lParam == compWnd->headerControls->button[BTN_CC]) 
		{
			if (GET_WM_COMMAND_CMD (wParam, lParam) == BN_CLICKED) 
			{
				BrowseMail (compWnd, HDR_CC);
			}
			return (0L);
		}
		else if ((HWND) (UINT) lParam == compWnd->headerControls->UI[HDR_ATTACH]) 
		{
			hControl = compWnd->headerControls->UI[HDR_ATTACH];
			if (GET_WM_COMMAND_CMD (wParam, lParam) == LBN_DBLCLK) 
			{
				
				//start of a new attach dlg
				if (DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_ATTACH), compWnd->hWnd,
					   &WinVnAttachesDlg, (LPARAM) (&compWnd->attachment)) > 0) 
				{
					int nCount = 0;
					SendMessage (compWnd->headerControls->UI[HDR_ATTACH],
								 LB_RESETCONTENT, 0L, 0L);

					for (int n = 1; n < MAX_NUM_ATTACHMENTS; n++)
					{
						if (compWnd->attachment[n])
						{
							SendMessage (compWnd->headerControls->UI[HDR_ATTACH],
										 LB_ADDSTRING, (WPARAM) 0,
										 (LPARAM) (LPCSTR) compWnd->attachment[n]->fileName);
							nCount++;
						}
					}
					compWnd->numAttachments = nCount+1;//main body is attach #0
				}

/*				
				// don't forget attachment number 0 is the main art body
				i = 1 + (int) SendMessage (hControl, LB_GETCURSEL, 0, 0L);
				if (i > 0 && i < compWnd->numAttachments) 
				{
					if (DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_WINVNATTACH), compWnd->hWnd,
						   lpfnWinVnAttachDlg, (LPARAM) (compWnd->attachment[i]))) 
					{
						SendMessage (compWnd->headerControls->UI[HDR_ATTACH],
										 LB_DELETESTRING, (WPARAM) i - 1, 0L);
						SendMessage (compWnd->headerControls->UI[HDR_ATTACH],
										 LB_INSERTSTRING, (WPARAM) i - 1,
										 (LPARAM) (LPCSTR) compWnd->attachment[i]->fileName);
					}
				}
*/
			}
		}

		switch (GET_WM_COMMAND_ID(wParam, lParam)) 
		{

			case IDM_CANCEL:
			case IDV_EXIT:
				DoEditClose (compWnd->hWnd, compWnd->dirty);
				break;

			case IDM_PRINT:
				PrintFile (compWnd->hWndEdit);
				break;

			case IDM_ATTACH:
				AskForNewAttachment (compWnd);
				break;

			case IDM_READ_FILE:
			{
				char *fileName;

				if ((fileName = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXFILENAME * sizeof (char))) == NULL) 
				{
					WVMessageBox (hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONERROR);
					break;
				}
				if (AskForExistingFileName (hWnd, fileName, "Select Text File To Read") == SUCCESS) 
				{
					ReadTextFileIntoEditWnd (compWnd->hWndEdit, fileName);
					compWnd->dirty = DT_DIRTY;
				}
				GlobalFreePtr(fileName);
			}
			break;

			case IDM_COMPOSE_PREFS:
				DialogBox (hInst, MAKEINTRESOURCE(IDD_WINVNCOMPOSEPREFS), hWnd, lpfnWinVnComposePrefsDlg);
				break;

			case IDM_ATTACH_PREFS:
				DialogBox (hInst, MAKEINTRESOURCE(IDD_WINVNATTACHPREFS), hWnd, lpfnWinVnAttachPrefsDlg);
				break;

			case IDM_WORDWRAP:
				hMenu = GetMenu (hWnd);
				hSubMenu = GetSubMenu (hMenu, 1);
				WordWrap = !WordWrap;
				SetWordWrap (compWnd, WordWrap);
				break;

			case IDM_HEADER_EDIT:   //shimomai
				EditHeaderFlag = TRUE;
				EditHeaders (compWnd);
				EditHeaderFlag = FALSE;
				break;
			case IDM_LOCK_SCREENWIDTH:
				compWnd->bRestrictWidth = !compWnd->bRestrictWidth;
				if (compWnd->bRestrictWidth)
				{
					//maybe force resize?
				}
				return 0L;
				break;

			case IDM_SEND:
				if (((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) ||
					(compWnd->composeType == DOCTYPE_CANCEL)) &&
					TestCommBusy (compWnd->hWnd, IDS_TEST_CANT_SEND)) 
				{
					break;
				}

				GetClientRect(compWnd->hWnd,&cRect);
				if ((actualwidth=((RectWidth (cRect) - SideSpace - ::GetSystemMetrics(SM_CXVSCROLL) )/ CompositionCharWidth)) > DEFAULTPOSTWIDTH ) 
				{
					if ((t1 = (char *) GlobalAllocPtr (GMEM_MOVEABLE, TEMPBUFSIZE * sizeof (char))) == NULL) 
					{
						WVMessageBox (hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONERROR);
						break;
					}
					if ((t2 = (char *) GlobalAllocPtr (GMEM_MOVEABLE, TEMPBUFSIZE * sizeof (char))) == NULL) 
					{
						WVMessageBox (hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONERROR);
						break;
					}

					_snprintf( t1, TEMPBUFSIZE,"%d",actualwidth);
					_snprintf( t2, TEMPBUFSIZE,"%d",DEFAULTPOSTWIDTH);

					mstatus = WVArgXMessageBox(hWnd, IDS_COMPOS_SCREENW, IDS_COMPOS_SREENWTITLE,
															  MB_YESNO | MB_ICONEXCLAMATION, t1, t2);
					GlobalFreePtr(t2);
					GlobalFreePtr(t1);
					if (mstatus == IDYES)
					{
						GetWindowRect(compWnd->hWnd, &cRect);
						cRect.right = cRect.left + SideSpace + ::GetSystemMetrics(SM_CXVSCROLL) + 8  
									  + (DEFAULTPOSTWIDTH * CompositionCharWidth);

						MoveWindow(compWnd->hWnd, cRect.left, cRect.top, RectWidth(cRect), RectHeight(cRect), TRUE);
						return 0L;
					}
				}
				if (compWnd->numAttachments > 1)
				{
					int nType = -1;
					TypAttachment *thisAttach;
					bool bUsesYENC = false;
					bool bUsesB64 = false;

					for (int i = 1; i < compWnd->numAttachments; i++)
					{
						thisAttach = compWnd->attachment[i];
						eEncodingType curType = thisAttach->encodingType;

						if (curType)
						{
							if (curType == CODE_YENC)
								bUsesYENC = true;
							if (curType == CODE_BASE64)
								bUsesB64 = true;

							if (nType < 0)
								nType = curType;
							else if (nType != curType)
							{
								//can't have mixed encodings
								
								WVMessageBox(hWnd, IDS_COMPOS_MIXEDENCODING, IDS_COMPOSE_MIXEDENCODING_TITLE,
															  MB_OK | MB_ICONEXCLAMATION);
								return 0L;								
								
							}
						}
					}


					if (bUsesYENC)
					{
						if  (MailCtrl.MailType == MT_SMTP && 
							(compWnd->composeType == DOCTYPE_MAIL ||
							 compWnd->composeType == DOCTYPE_FORWARD ||
							 (compWnd->composeType == DOCTYPE_POSTING && *CcAddress)))
						{
						
							if (WVMessageBox(hWnd, IDS_COMPOSE_NOMAILYENC, IDS_COMPOSE_NOMAILYENC_TITLE,
										 MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
								return 0L;
							
						}

					}
					//gotta have MIME for B64
					if (bUsesB64 &&  !GenerateMIME)
						GenerateMIME = TRUE;

					//no MIME for yenc
					if (bUsesYENC && GenerateMIME)
						GenerateMIME = FALSE;


				}



				// destroys window if successful
				SendComposition (compWnd);
				break;

			default:
				DoEditCommands (GetFocus (), wParam, lParam);
				break;
		}
		break;

		case WM_DESTROY:
			compWnd->hWnd = (HWND) NULL;
			compWnd->hWndEdit = (HWND) NULL;

			for (i = 0; i < MAX_NUM_ATTACHMENTS; i++) 
			{
				if (compWnd->attachment[i]) 
				{
					GlobalFreePtr (compWnd->attachment[i]);
					compWnd->attachment[i] = (TypAttachment *) NULL;
				}
			}
			compWnd->numAttachments = 0;

			if (compWnd->headerControls) 
			{
				GlobalFreePtr (compWnd->headerControls);
				compWnd->headerControls = (TypHeaderControls *) NULL;
			}

			if (compWnd->extraHeaders) 
			{
				FreeTextBlock(compWnd->extraHeaders);
				compWnd->extraHeaders = (TypTextBlock *)NULL;
			}
			if (compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE)
				NumPostWnds--;
			else
				NumMailWnds--;
			break;

		case WM_CLOSE:
			if (compWnd->busy)
				WVMessageBox (hWnd, IDS_COMPOS_WAIT, IDS_COMPOS_WAITTITLE, MB_OK | MB_ICONSTOP);
			else
				DoEditClose (compWnd->hWnd, compWnd->dirty);
			break;

		default:
			return (DefWindowProc (hWnd, message, wParam, lParam));
	}
	return (0L);
}


void BrowseMail (WndEdit * editWnd, int button)
{
	HWND control;
	char *temp;

	if (button == BTN_TO) 
	{
		control = editWnd->headerControls->UI[HDR_TO];
	}
	else 
	{
		control = editWnd->headerControls->UI[HDR_CC];
	}
	if ((temp = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXHEADERLINE * sizeof (char))) == NULL) 
	{
		WVMessageBox ((HWND)editWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONERROR);
		return;
	}
	SendMessage (control, WM_GETTEXT, (WPARAM) MAXHEADERLINE, (LPARAM) (LPCSTR) temp);

	if (DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_WINVNMAIL), editWnd->hWnd, lpfnWinVnMailDlg, (LPARAM) temp)) 
	{
		SendMessage (control, WM_SETTEXT, 0, (LPARAM) (LPCSTR) DialogString);
	}
	GlobalFreePtr(temp);
}

/* ------------------------------------------------------------------------
 * To maximize amount of data allowable in posting, allocate a new
 * data segment for this posting from the Global heap, and set the
 * window hInstance to this segment
 * Don't forget you can't use EM_GET/SETHANDLE on an edit buf with
 * a global mem segment
 */
BOOL CreateEditWnd (WndEdit * compWnd)
{
  RECT cRect;
  DWORD wrapOptions = 0;
  HINSTANCE editInst;

	editInst = hInst;

	if (!WordWrap)
		wrapOptions = WS_HSCROLL | ES_AUTOHSCROLL;

	GetClientRect (compWnd->hWnd, &cRect);

#if defined (WIN32)	&& defined (RICHEDIT)
	LoadLibrary("RICHED32.DLL");
	compWnd->hWndEdit = CreateWindow ((LPCSTR) "RICHEDIT" , "",
						  WS_TABSTOP | WS_CHILD | WS_VSCROLL | WS_BORDER |
						  ES_LEFT | ES_MULTILINE | ES_WANTRETURN | 
						  ES_AUTOVSCROLL | wrapOptions,
						  0, compWnd->headerControls->yEdge, RectWidth (cRect), 
						  cRect.bottom - (compWnd->headerControls->yEdge + 1),
						  compWnd->hWnd, (HMENU) EDITID, (HINSTANCE) editInst, NULL);

	compWnd->richedit = 1;
	if (!compWnd->hWndEdit)
	{
		compWnd->richedit = 0;
		compWnd->hWndEdit = CreateWindow ((LPCSTR) "edit", (LPCSTR) NULL,
			WS_TABSTOP | WS_CHILD | WS_VSCROLL | WS_BORDER |
			ES_LEFT | ES_MULTILINE | ES_WANTRETURN | 
			ES_AUTOVSCROLL | wrapOptions,
			0, compWnd->headerControls->yEdge, RectWidth (cRect), 
			cRect.bottom - (compWnd->headerControls->yEdge + 1),
			compWnd->hWnd, (HMENU) EDITID, (HINSTANCE) editInst, NULL);

	}
#else
	compWnd->hWndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, (LPCSTR) "edit", (LPCSTR) NULL,
		WS_TABSTOP | WS_CHILD | WS_VSCROLL | WS_BORDER |
		ES_LEFT | ES_MULTILINE | ES_WANTRETURN | 
		ES_AUTOVSCROLL | wrapOptions,
		0, compWnd->headerControls->yEdge, RectWidth (cRect), 
		cRect.bottom - (compWnd->headerControls->yEdge + 1),
		compWnd->hWnd, (HMENU) EDITID, (HINSTANCE) editInst, NULL);
#endif
	if (!compWnd->hWndEdit) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_CREATEFAIL , IDS_COMPOS_EDIT_BUFFER, MB_OK | MB_ICONERROR);
		return (FAIL);
	}
	SendMessage (compWnd->hWndEdit, EM_LIMITTEXT, 0, 0L);
	SetHandleBkBrush (compWnd->hWndEdit, hArticleBackgroundBrush);
	//  SetHandleBkBrush (compWnd->hWndEdit, (HBRUSH) GetStockObject (LTGRAY_BRUSH));
	SendMessage (compWnd->hWndEdit, WM_SETFONT, (WPARAM) hCompositionFont, FALSE);
	compWnd->dirty = DT_CLEAN;

#ifdef RICHEDIT
	{
		CHARFORMAT cf;
		if (compWnd->richedit)
		{
			SendMessage(compWnd->hWndEdit,EM_SETBKGNDCOLOR, 0,ArticleBackgroundColor);
			SendMessage(compWnd->hWndEdit,EM_SETLIMITTEXT, 0x001FFFFF, 0); //2Meg 
			SendMessage(compWnd->hWndEdit,EM_SETSEL, 0, (LPARAM) -1);  

			ZeroMemory( &cf, sizeof(CHARFORMAT));
			cf.cbSize = sizeof(CHARFORMAT);
			cf.dwMask = CFM_COLOR;
			cf.crTextColor = ArticleTextColor;

			SendMessage( compWnd->hWndEdit, EM_SETCHARFORMAT, 0, (LPARAM) &cf);
			SendMessage( compWnd->hWndEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cf);
		}		
	}

#endif

	/* Subclass the edit window to pass accelerators to parent */
	SetWindowLongPtr (compWnd->hWndEdit, GWLP_WNDPROC, (LONG_PTR) lpfnWinVnControlSubclass);

	return (SUCCESS);
}

/*----------------------------------------------------------------------------
 * Create the all controls necessary for header entry
 * jsc 9/22/94
 */

#define XBASE                   13
#define YBASE                   11
#define XSPACING                5
#define YSPACING                2

#define IDC_HEADER_UI   1100

void ResizeComposeControls (WndEdit * compWnd, int cx, int cy)
{
	register int n;
	int x, ySize, hdrLine, b, titleWidth, editWidth, buttonWidth;
	RECT rect;
	SIZE size;
	HDC hDC;
	HFONT hOldFont;

	if (!cx && !cy) 
	{
		GetClientRect (compWnd->hWnd, &rect);
		cx = RectWidth (rect);
		cy = RectHeight (rect);
	}
	ChangeShowHeaderControls (compWnd);

	/* floatingpt ySize yuck.  only way to avoid loss of accuracy in small font sizes */
	ySize = (int) (1.6 * (float) WinVnLineHeight);

	/* get estimated width of the longest title in the current font 
	* Use subject static control as a temporary DC in which to do work
	*/
	hDC = GetDC (compWnd->headerControls->title[HDR_SUBJECT]);
	hOldFont = (HFONT) SelectObject (hDC, hWinVnFont);
	if (compWnd->headerControls->title[HDR_ORG]) 
	{
		GetTextExtentPoint (hDC, " Organization: ", 15, &size);
	}
	else 
	{
		GetTextExtentPoint (hDC, " Attachments: ", 14, &size);
	}
	titleWidth = size.cx;

	GetTextExtentPoint (hDC, " Browse ", 8, &size);
	buttonWidth = size.cx;

	SelectObject (hDC, hOldFont);
	ReleaseDC (compWnd->headerControls->title[HDR_SUBJECT], hDC);

	//  titleWidth = 15 * WinVnCharWidth;   /* space for word " Organization: " */
	//  buttonWidth = 9 * WinVnCharWidth;   /* space for word " Browse " */

	x = XBASE + titleWidth + XSPACING;
	editWidth = max (buttonWidth + 50, cx - x - 15);

	for (n = 0, hdrLine = 0; n < HDR_NUM_CONTROLS; n++) 
	{
		//   if ((n != HDR_GROUPS) || (compWnd->composeType != DOCTYPE_CANCEL)){
		if (compWnd->headerControls->UI[n]) 
		{
			MoveWindow (compWnd->headerControls->title[n],
				XBASE, YBASE + 3 + hdrLine * (ySize + YSPACING),
				titleWidth, ySize, TRUE);

			MoveWindow (compWnd->headerControls->UI[n],
				x, YBASE + hdrLine * (ySize + YSPACING),
				(n == HDR_TO || n == HDR_CC) ? editWidth - XSPACING - buttonWidth : editWidth,
				(n == HDR_ATTACH) ? (2 * ySize) : ySize, TRUE);
			SendMessage (compWnd->headerControls->title[n], WM_SETFONT, (WPARAM) hWinVnFont, 0);
			SendMessage (compWnd->headerControls->UI[n], WM_SETFONT, (WPARAM) hWinVnFont, 0);

			if (n == HDR_TO || n == HDR_CC) 
			{
				b = (n == HDR_TO) ? BTN_TO : BTN_CC;
				MoveWindow (compWnd->headerControls->button[b],
					x + editWidth - buttonWidth,
					YBASE + hdrLine * (ySize + YSPACING),
					buttonWidth, ySize, TRUE);
				SendMessage (compWnd->headerControls->button[b], WM_SETFONT, (WPARAM) hWinVnFont, TRUE);
			}

			hdrLine++;
		}

	}
	compWnd->headerControls->yEdge = (hdrLine - 1) * (ySize + YSPACING) + 3 * ySize + YSPACING;
	SendMessage (compWnd->hWndEdit, WM_SETFONT, (WPARAM) hCompositionFont, TRUE);
	MoveWindow (compWnd->hWndEdit, 0, compWnd->headerControls->yEdge,
		cx, cy - compWnd->headerControls->yEdge, TRUE);
	InvalidateRect (compWnd->hWnd, NULL, TRUE);
}

/* 
 * CreateWindow helpers
 * return true on success 
 */
BOOL CreateHeaderTitle (WndEdit * compWnd, int n, char *title)
{
	compWnd->headerControls->title[n] =
		CreateWindow ("STATIC", title,
			WS_CHILD | SS_RIGHT,
			0, 0, 0, 0,
			compWnd->hWnd, (HMENU) NULL, hInst, NULL);

  return (compWnd->headerControls->title[n] != (HWND) NULL);
}

BOOL CreateHeaderEdit (WndEdit * compWnd, int n)
{

	compWnd->headerControls->UI[n] =
	CreateWindowEx (WS_EX_CLIENTEDGE, "EDIT", (LPCSTR) NULL,
	WS_TABSTOP | WS_CHILD | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL,
	0, 0, 0, 0,
	compWnd->hWnd, (HMENU) (IDC_HEADER_UI + n), hInst, NULL);

	if (compWnd->headerControls->UI[n]) 
	{
		SendMessage (compWnd->headerControls->UI[n], EM_LIMITTEXT, (WPARAM)MAXHEADERLINE, 0);
		/* Subclass the edit window to pass acceleratprs to parent */
		SetWindowLongPtr (compWnd->headerControls->UI[n], GWLP_WNDPROC, (LONG_PTR) lpfnWinVnControlSubclass);
#ifdef USE_3D_CONTROLS
		Ctl3dSubclassCtl (compWnd->headerControls->UI[n]);
#endif
	}
	return (compWnd->headerControls->UI[n] != (HWND) NULL);
}

BOOL CreateHeaderListBox (WndEdit * compWnd, int n)
{
	compWnd->headerControls->UI[n] =
		CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", (LPCSTR) NULL,
			WS_TABSTOP | WS_CHILD | WS_BORDER | WS_VSCROLL | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,
			0, 0, 0, 0,
			compWnd->hWnd, (HMENU) (IDC_HEADER_UI + n), hInst, NULL);

		if (compWnd->headerControls->UI[n]) 
		{
			SetWindowLongPtr (compWnd->headerControls->UI[n], GWLP_WNDPROC, (LONG_PTR) lpfnWinVnControlSubclass);
#ifdef USE_3D_CONTROLS
		Ctl3dSubclassCtl (compWnd->headerControls->UI[n]);
#endif
	}
	return (compWnd->headerControls->UI[n] != (HWND) NULL);
}

BOOL CreateButton (WndEdit * compWnd, int n)
{
	compWnd->headerControls->button[n] =
		CreateWindow ("BUTTON", (LPCSTR) "Browse",
			WS_CHILD | BS_PUSHBUTTON, // | WS_TABSTOP 
			0, 0, 0, 0,
			compWnd->hWnd, (HMENU) ID_BROWSE, hInst, NULL);

	return (compWnd->headerControls->button[n] != (HWND) NULL);
}

BOOL CreateHeaderControls (WndEdit * compWnd, int n, char *title)
{
  return (CreateHeaderTitle (compWnd, n, title) &&
		 CreateHeaderEdit (compWnd, n));
}

void DestroyHeaderControls (WndEdit * compWnd, int n)
{
	char *title;
	char *contents;
	char *buf;

	if ((title = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXDIALOGSTRING * sizeof (char))) == NULL) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONSTOP);
		return;
	}
	if ((contents = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXHEADERLINE * sizeof (char))) == NULL) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONSTOP);
		return;
	}
	if ((buf = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXHEADERLINE * sizeof (char))) == NULL) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONSTOP);
		return;
	}

//shimomai
	if (compWnd->headerControls->UI[n] || compWnd->headerControls->title[n]) 
	{
		SendMessage (compWnd->headerControls->title[n], WM_GETTEXT,
		(WPARAM) MAXDIALOGSTRING, (LPARAM) (LPCSTR) title);
		if (SendMessage (compWnd->headerControls->UI[n], WM_GETTEXT,
						(WPARAM) MAXHEADERLINE, (LPARAM) (LPCSTR) contents) > 0) 
		{
			_snprintf(buf, MAXHEADERLINE, "%s %s\r\n", title, contents);
			if (!compWnd->extraHeaders)
				compWnd->extraHeaders = InitTextBlock (compWnd->hWnd);
			AddLineToTextBlock (compWnd->extraHeaders, buf);
		}
	}
	if (compWnd->headerControls->UI[n]) 
	{
		DestroyWindow (compWnd->headerControls->UI[n]);
		compWnd->headerControls->UI[n] = (HWND) NULL;
	}
	if (compWnd->headerControls->title[n]) 
	{
		DestroyWindow (compWnd->headerControls->title[n]);
		compWnd->headerControls->title[n] = (HWND) NULL;
	}
	GlobalFreePtr(buf);
	GlobalFreePtr(contents);
	GlobalFreePtr(title);
}

/*
 * Main entry point for creating the controls 
 * returns FAIL or SUCCESS 
 */
BOOL CreateComposeControls (WndEdit * compWnd)
{
	RECT cRect;

	if ((compWnd->headerControls = (TypHeaderControls *)
		GlobalAllocPtr (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (TypHeaderControls))) == NULL) 
	{
		return FAIL;
	}

	if ((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) ||
		(compWnd->composeType == DOCTYPE_CANCEL)) 
	{
		if (!CreateHeaderControls (compWnd, HDR_GROUPS, "Newsgroups:"))
			return FAIL;
	}
	else if ((!CreateHeaderControls (compWnd, HDR_TO, "To:")) ||
			 (!CreateButton (compWnd, BTN_TO)))
		return FAIL;

	if (!CreateHeaderControls (compWnd, HDR_SUBJECT, "Subject:"))
		return FAIL;

	if ((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
		!CreateHeaderControls (compWnd, HDR_FOLLOWTO, "Followup-to:"))
		return FAIL;

	/* cc-by-mail when posting is only available if SMTP */
	if (compWnd->composeType != DOCTYPE_CANCEL)
	{
		if (MailCtrl.enableMail == MF_ENABLED && MailCtrl.MailType == MT_SMTP &&
			!CreateHeaderControls (compWnd, HDR_CC, (compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) ? "Cc-By-Mail:" : "Cc:"))
			return FAIL;

	if (!CreateButton (compWnd, BTN_CC))
		return FAIL;
	}

	if ((compWnd->composeType != DOCTYPE_CANCEL) &&
		(!CreateHeaderTitle (compWnd, HDR_ATTACH, "Attachments:") ||
		 !CreateHeaderListBox (compWnd, HDR_ATTACH)))
		return FAIL;

	/* all optional headers will be created by ChangeShowHeaderControls */
	if (CreateEditWnd (compWnd) == FAIL)
		return FAIL;

	if (compWnd->composeType != DOCTYPE_CANCEL) 
	{
		GetClientRect (compWnd->hWnd, &cRect);
		ResizeComposeControls (compWnd, RectWidth (cRect), RectHeight (cRect));
		ShowComposeControls (compWnd);
	}

	if (compWnd->Doc)
		compWnd->hLastFocusWnd = compWnd->hWndEdit;
	else if (compWnd->composeType == DOCTYPE_CANCEL)
		compWnd->hLastFocusWnd = compWnd->headerControls->UI[HDR_SUBJECT];
	else if (compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE)
		compWnd->hLastFocusWnd = compWnd->headerControls->UI[HDR_GROUPS];
	else
		compWnd->hLastFocusWnd = compWnd->headerControls->UI[HDR_TO];
	return SUCCESS;
}

void ShowComposeControls (WndEdit * compWnd)
{
	register int i;
	for (i = 0; i < HDR_NUM_CONTROLS; i++) 
	{
		if (compWnd->headerControls->title[i])
			ShowWindow (compWnd->headerControls->title[i], SW_SHOWNORMAL);
		if (compWnd->headerControls->UI[i])
			ShowWindow (compWnd->headerControls->UI[i], SW_SHOWNORMAL);
	}
	for (i = 0; i < HDR_NUM_BUTTONS; i++) 
	{
		if (compWnd->headerControls->button[i])
			ShowWindow (compWnd->headerControls->button[i], SW_SHOWNORMAL);
	}
	if (compWnd->hWndEdit)
	ShowWindow (compWnd->hWndEdit, SW_SHOWNORMAL);
}

BOOL ChangeShowHeaderControls (WndEdit * compWnd)
{
	char *temp;

	if ((temp = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXHEADERLINE * sizeof (char))) == NULL) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONSTOP);
		return FAIL;
	}

	if (ShowFromHdr && !(compWnd->headerControls->title[HDR_FROM])) 
	{
		if (!CreateHeaderControls (compWnd, HDR_FROM, "From:")) 
		{
			GlobalFreePtr(temp);
			return FAIL;
		}
		//shimomai
		if (GetHeaderLineTextBlock(temp, compWnd->extraHeaders, "From:") == TRUE ||
			GetFromAddress (temp, MAXHEADERLINE, compWnd->Doc) == TRUE) 
		{
				SendMessage (compWnd->headerControls->UI[HDR_FROM], WM_SETTEXT,
							0, (LPARAM) (LPCSTR) temp);
		}
	}
	if (!ShowFromHdr && compWnd->headerControls->title[HDR_FROM]) 
	{
		DestroyHeaderControls (compWnd, HDR_FROM);
	}

	if (ShowOrgHdr && !(compWnd->headerControls->title[HDR_ORG])) 
	{
		if (!CreateHeaderControls (compWnd, HDR_ORG, "Organization:")) 
		{
			GlobalFreePtr(temp);
			return FAIL;
		}
		//shimomai
		if (GetHeaderLineTextBlock(temp, compWnd->extraHeaders, "Organization:") == TRUE ||
			strcpy(temp, Organization)) 
		{
			SendMessage (compWnd->headerControls->UI[HDR_ORG], WM_SETTEXT,
						0, (LPARAM) (LPCSTR) temp);
		}
	}
	if (!ShowOrgHdr && compWnd->headerControls->title[HDR_ORG]) 
	{
		DestroyHeaderControls (compWnd, HDR_ORG);
	}

	if (ShowReplyToHdr && !(compWnd->headerControls->title[HDR_REPLYTO])) 
	{
		if (!CreateHeaderControls (compWnd, HDR_REPLYTO, "Reply-To:")) 
		{
			GlobalFreePtr(temp);
			return FAIL;
		}
		//shimomai
		if (GetHeaderLineTextBlock(temp, compWnd->extraHeaders, "Reply-To:") == TRUE ||
			strcpy(temp, ReplyTo)) 
		{
			SendMessage (compWnd->headerControls->UI[HDR_REPLYTO], WM_SETTEXT,
						0, (LPARAM) (LPCSTR) temp);
		}
	}
	if (!ShowReplyToHdr && compWnd->headerControls->title[HDR_REPLYTO]) 
	{
		DestroyHeaderControls (compWnd, HDR_REPLYTO);
	}

	if (ShowKeywordsHdr && !(compWnd->headerControls->title[HDR_KEYWORDS])) 
	{
		if (!CreateHeaderControls (compWnd, HDR_KEYWORDS, "Keywords:")) 
		{
			GlobalFreePtr(temp);
			return FAIL;
		}
		//shimomai
		if (GetHeaderLineTextBlock(temp, compWnd->extraHeaders, "Keywords:") == TRUE) 
		{
			SendMessage (compWnd->headerControls->UI[HDR_KEYWORDS], WM_SETTEXT,
						0, (LPARAM) (LPCSTR) temp);
		}
	}
	if (!ShowKeywordsHdr && compWnd->headerControls->title[HDR_KEYWORDS]) 
	{
		DestroyHeaderControls (compWnd, HDR_KEYWORDS);
	}

	if ((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
	ShowSummaryHdr && !(compWnd->headerControls->title[HDR_SUMMARY])) 
	{
		if (!CreateHeaderControls (compWnd, HDR_SUMMARY, "Summary:")) 
		{
			GlobalFreePtr(temp);
			return FAIL;
		}
		//shimomai
		if (GetHeaderLineTextBlock(temp, compWnd->extraHeaders, "Summary:") == TRUE) 
		{
			SendMessage (compWnd->headerControls->UI[HDR_SUMMARY], WM_SETTEXT,
						0, (LPARAM) (LPCSTR) temp);
		}
	}
	if ((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
		!ShowSummaryHdr && compWnd->headerControls->title[HDR_SUMMARY]) 
	{
		DestroyHeaderControls (compWnd, HDR_SUMMARY);
	}

	if ((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
		ShowDistributionHdr && !(compWnd->headerControls->title[HDR_DIST])) 
	{
		if (!CreateHeaderControls (compWnd, HDR_DIST, "Distribution:")) 
		{
			GlobalFreePtr(temp);
			return FAIL;
		}
		//shimomai
		if (GetHeaderLineTextBlock(temp, compWnd->extraHeaders, "Distribution:") == TRUE) 
		{
			SendMessage (compWnd->headerControls->UI[HDR_DIST], WM_SETTEXT,
				0, (LPARAM) (LPCSTR) temp);
		}
	}
	if ( (compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
		!ShowDistributionHdr && compWnd->headerControls->title[HDR_DIST]) 
	{
		DestroyHeaderControls (compWnd, HDR_DIST);
	}

	if ( (compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
		ShowFollowupToHdr && !(compWnd->headerControls->title[HDR_FOLLOWTO])) 
	{
		if (!CreateHeaderControls (compWnd, HDR_FOLLOWTO, "Followup-To:")) 
		{
			GlobalFreePtr(temp);
			return FAIL;
		}

		//shimomai
		if (GetHeaderLineTextBlock(temp, compWnd->extraHeaders, "Followup-To:") == TRUE) 
		{
			SendMessage (compWnd->headerControls->UI[HDR_FOLLOWTO], WM_SETTEXT,
				0, (LPARAM) (LPCSTR) temp);
		}
	}
	if (( compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
		!ShowFollowupToHdr && compWnd->headerControls->title[HDR_FOLLOWTO]) 
	{
		DestroyHeaderControls (compWnd, HDR_FOLLOWTO);
	}
	ShowComposeControls (compWnd);
	ReconstructTextBlock (compWnd->hWnd, &(compWnd->extraHeaders));

	GlobalFreePtr(temp);
	return SUCCESS;
}

HWND GetNextHeaderWnd (WndEdit * compWnd, HWND hCur, BOOL next)
{
	register int n;

	for (n = 0; n < HDR_NUM_CONTROLS; n++) 
	{
		if (compWnd->headerControls->UI[n] == hCur)
			break;
	}

	/* n is now set to current control */
	do 
	{
		if (next) 
		{
			n++;
			if (n == HDR_NUM_CONTROLS) 
			{
				return compWnd->hWndEdit;
			}
		}
		else 
		{
			n = n - 1;
			if (n < 0) 
			{
				return compWnd->hWndEdit;
			}
		}
	} while (!compWnd->headerControls->UI[n]);
	return compWnd->headerControls->UI[n];
}

void EnableSendComposition (WndEdit * compWnd, BOOL enable)
{
	HMENU hMenu = GetMenu (compWnd->hWnd);
	HMENU hSubMenu = GetSubMenu (hMenu, 0);

	//  Send menu is handled by WM_INITMENU
	if (compWnd->composeType == DOCTYPE_CANCEL)
	{ 
		EnableMenuItem (hSubMenu, IDM_READ_FILE, DISABLE_MENU);
		EnableMenuItem (hSubMenu, IDM_ATTACH, DISABLE_MENU);
		EnableMenuItem (hSubMenu, IDM_COMPOSE_PREFS,DISABLE_MENU);
		EnableMenuItem (hSubMenu, IDM_ATTACH_PREFS,DISABLE_MENU);
	}
	else 
	{
		EnableMenuItem (hSubMenu, IDM_READ_FILE, enable ? ENABLE_MENU : DISABLE_MENU);
		EnableMenuItem (hSubMenu, IDM_ATTACH, enable ? ENABLE_MENU : DISABLE_MENU);
		EnableMenuItem (hSubMenu, IDM_CANCEL, enable ? ENABLE_MENU : DISABLE_MENU);

		hSubMenu = GetSubMenu (hMenu, 1);
		EnableMenuItem (hSubMenu, IDM_ROT13, enable ? ENABLE_MENU : DISABLE_MENU);
		EnableMenuItem (hSubMenu, IDM_WORDWRAP, enable ? ENABLE_MENU : DISABLE_MENU);
	}
}

/*------------ WinVnControlIntercept ---------------------------- 
 *
 * The subclassed WindowProc for the compose controls
 *
 * Capture key messages and pass them to parent
 * as may contain accelerator information
 *
 *--------------------------------------------------------------*/
INT_PTR CALLBACK WinVnControlIntercept (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	WndEdit *compWnd;
	HWND hParentWnd = GetParent (hWnd);

	if ( msg == uMSH_MOUSEWHEEL ) 
		msg = WM_MYMOUSEWHEEL;

	switch (msg) 
	{
		case WM_SETFOCUS:
		/* remember that this control had the focus last */
			compWnd = GetComposeWnd(hParentWnd);
			if (compWnd) 
			{
				compWnd->hLastFocusWnd = hWnd;
			}
		break;

		case WM_KILLFOCUS:
			// scroll edit text back to start when losing focus
			compWnd = GetComposeWnd (hParentWnd);
			if (hWnd != compWnd->headerControls->UI[HDR_ATTACH] && 
				hWnd != compWnd->hWndEdit) 
			{

				SendMessage (hWnd, EM_SETSEL, (WPARAM) (INT) 0, (LPARAM) (INT) 0);
				SendMessage (hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);

			}
			break;


		case WM_CHAR:
			// Process this message to avoid message beeps.
			if (wParam == VK_RETURN || wParam == VK_TAB) 
			{
				compWnd = GetComposeWnd (hParentWnd);
				if (hWnd != compWnd->hWndEdit) 
				{
					return 0;
				}
			}
			break;

	case WM_KEYDOWN:   //restored this code to handle tab between fields MDS 2000/01/19
	case WM_KEYUP: 
		// big kludge - arrows only seem to work if SendMsg 
		// but accelerators only seem to work if PostMsg
		switch (wParam) 
		{
			case VK_TAB: 
			case VK_RETURN:
			default:
				SendMessage(hParentWnd, msg, wParam, lParam);
				break;
		}

	case WM_COMMAND:
    /* DoEditcommands if any */
		if (DoEditCommands(hWnd,wParam, lParam))
			return 0L;
		break;

		case WM_GETDLGCODE:
			// we want to handle tabs/arrows/return 
			return DLGC_WANTALLKEYS | (BOOL) CallWindowProc((WNDPROC)GetClassLongPtr(hWnd, GCLP_WNDPROC),
						hWnd, msg, (WPARAM) wParam , (LPARAM) lParam);
		break;
	}               
	/* and always let the edit control do its thing  */
	return CallWindowProc((WNDPROC)GetClassLongPtr(hWnd, GCLP_WNDPROC), hWnd, msg, wParam , lParam);
}

/* --------------- PrepareControlMenu -----------------
 * Prepare &Edit menu based on current composition control
 * 
 */
void PrepareControlMenu (WndEdit * compWnd, HWND hControl, BOOL isAttach)
{
	DWORD dwResult;
	UINT action;
	HMENU hMenu = GetMenu (compWnd->hWnd);

	dwResult = SendMessage (hControl, EM_GETSEL, 0, 0L);

	/* cannot cut, add quotation, remove quotation , delete or rot13 unless there is a selection */
	action = (isAttach || HIWORD (dwResult) == LOWORD (dwResult)) ? DISABLE_MENU : ENABLE_MENU;

	EnableMenuItem (hMenu, IDM_ROT13, action);
	EnableMenuItem (hMenu, IDM_COPY, action);
	EnableMenuItem (hMenu, IDM_CUT, action);
	EnableMenuItem (hMenu, IDM_QUOTE_EXTERN, action);
	EnableMenuItem (hMenu, IDM_QUOTE_ADD, action);
	EnableMenuItem (hMenu, IDM_QUOTE_REMOVE, action);

	/* Delete and Select all are always available unless this is the 
	* attachment listbox
	*/
	action = isAttach ? DISABLE_MENU : ENABLE_MENU;
	EnableMenuItem (hMenu, IDM_DEL, action);
	EnableMenuItem (hMenu, IDM_SELECT_ALL, action);

	/* if clipboard contains text, can paste or paste as quotation */
	action = (isAttach || !IsClipboardFormatAvailable (CF_TEXT)) ? DISABLE_MENU : ENABLE_MENU;
	EnableMenuItem (hMenu, IDM_PASTE, action);
	EnableMenuItem (hMenu, IDM_PASTE_TEXT, action);

	/* if Undo Buffer is empty, cannot Undo changes */
	action = (isAttach || !SendMessage (hControl, EM_CANUNDO, 0, 0L)) ?
		DISABLE_MENU : ENABLE_MENU;
	EnableMenuItem (hMenu, IDM_UNDO, action);

	action = (isAttach && compWnd->numAttachments > 1) ?
		ENABLE_MENU : DISABLE_MENU;

	//  EnableMenuItem(hMenu, IDM_DELETE_ATTACHMENT, action);

	CheckMenuItem (hMenu, IDM_WORDWRAP, MF_BYCOMMAND | (WordWrap ? MF_CHECKED : MF_UNCHECKED));
	CheckMenuItem (hMenu, IDM_LOCK_SCREENWIDTH, MF_BYCOMMAND | (compWnd->bRestrictWidth ? MF_CHECKED : MF_UNCHECKED) );

}




/* ---------------- function DoEditCommands -------------
 *  edit commands for composition window
 */
int DoEditCommands (HWND hWndEdit, WPARAM wParam, LPARAM lParam)
{
  
	BOOL bRichEdit = FALSE;
	WndEdit *compWnd = GetComposeWnd (GetParent(hWndEdit));

	if (compWnd && compWnd->richedit)
	bRichEdit = TRUE;

	switch (LOWORD (wParam)) 
	{
		case IDM_UNDO:
			if ( HIWORD(wParam) == 0 || !bRichEdit)
				SendMessage (hWndEdit, WM_UNDO, 0, 0L);
			break;

		case IDM_CUT:
			if ( HIWORD(wParam) == 0 || !bRichEdit)
				SendMessage (hWndEdit, WM_CUT, 0, 0L);
				break;

		case IDM_COPY:
			if ( HIWORD(wParam) == 0 || !bRichEdit)
				SendMessage (hWndEdit, WM_COPY, 0, 0L);
				break;

		case IDM_PASTE:
			if ( HIWORD(wParam) == 0 || !bRichEdit) 
				SendMessage (hWndEdit, WM_PASTE, 0, 0L);
				break;

		case IDM_PASTE_TEXT:
		{
			WORD		wStart,length;
			char		*editptr;
			char		*src;
			char		*dst,*newText;
			char		lastch = '\0';

			SendMessage (hWndEdit, WM_CLEAR, 0, 0L); /* remove a selection if any, because paste will replace it */

			editptr = GetEditText(hWndEdit);
			length = strlen(editptr);
			GlobalFreePtr(editptr);

			wStart = LOWORD (SendMessage (hWndEdit, EM_GETSEL, (WPARAM) 0, (LPARAM) (0L)));
			SendMessage (hWndEdit, WM_PASTE, 0, 0L);

			editptr = GetEditText (hWndEdit);

			length = strlen(editptr) - length;

			src = editptr;

			if ((dst = newText = (char *) GlobalAllocPtr (GMEM_MOVEABLE, 2 * (1+length) * sizeof (char))) == NULL) 
			{
				/* assume for each pasted char a quote, quicker than counting the real size :-) */
				/* space for the first quote and terminating NUL must be also added */
				WVMessageBox (hWndEdit, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_EDIT_TEXT, MB_OK | MB_ICONSTOP);
				GlobalFreePtr(editptr); /* free memory allocated by GetEditText */
				break;
			}

			src = editptr + wStart;
			while ( (src < (editptr + wStart + length)) && ((*src == ' ') || (*src == '\t')) ) 
			{
				src++;
			}
			while ( src < (editptr + wStart + length) ) 
			{
				if (*src >= ' ')
					*dst++ = lastch = *src;
				if (*src == '\t')
					*dst++ = lastch = ' ';
				if (*src == '\r') 
				{
					if (strncmp(src,"\r\n\r\n",4) == 0) 
					{
						while ((*src == '\r') || (*src == '\n'))
							*dst++ = *src++;
						src--;
						lastch = ' '; /* hard-CR is good like a blank to separate words */
					}
				}
				if (*src == '\n') 
				{
					if (lastch != ' ') 
					{
						*dst++ = ' ';
					}
					src++;
					while ( (src < (editptr + wStart + length)) && ((*src == ' ') || (*src == '\t')) ) 
					{
						src++;
					}
				} 
				else 
				{
					src++;
				}
			}
			*dst = '\0';

			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart, (LPARAM) wStart + length);
			SendMessage (hWndEdit, EM_REPLACESEL, (WPARAM) TRUE, (LPARAM) newText);

			GlobalFreePtr(newText);
			GlobalFreePtr(editptr);

			//SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart + length, (LPARAM) wStart + length );
		}
		break;
		case IDM_SEND:
		{
			SendMessage (compWnd->hWnd, WM_COMMAND, (WPARAM) IDM_SEND, (LPARAM) (compWnd->hWnd));
		}
			break;
		case IDM_DEL:
			SendMessage (hWndEdit, WM_CLEAR, 0, 0L);
			break;

		case IDM_DEL_LINE:
		{
			WORD		wStart,wEnd =0;
			char		*editptr;
			char		*src;

			wStart = (WORD) SendMessage (hWndEdit, EM_LINEINDEX, (WPARAM) -1, (LPARAM) (0L));
			editptr = GetEditText(hWndEdit);

			src = editptr + wStart;
			while (*src) 
			{
				if (*src == '\n') 
				{
					wEnd = 1 + src - editptr;
					break;
				}
				src++;
			}

			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart, (LPARAM) wEnd);
			SendMessage (hWndEdit, WM_CLEAR, (WPARAM) 0, (LPARAM) 0L);
			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart, (LPARAM) wStart );

			GlobalFreePtr(editptr);
		}
		break;

		case IDM_SELECT_ALL:
			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) (INT) 0, (LPARAM) (INT) - 1);
			break;

		case IDM_QUOTE_EXTERN:
        {
			DWORD dwResult;
			WORD wStart, wEnd;
			char *editptr;
			char *newText;
			char *dst,*src,*pStart,*pEnd;
			unsigned int size;
			unsigned int delta;

			dwResult = SendMessage (hWndEdit, EM_GETSEL, 0, 0L);
			wStart = LOWORD (dwResult);
			wEnd = HIWORD (dwResult);

			editptr = GetEditText (hWndEdit);

			pStart = editptr + wStart;
			while ((pStart >= editptr) && (*pStart != '\n') && (*pStart !='\r')) 
			{
				pStart--;
			}
			do 
			{
				pStart++;
			} while ((*pStart == '\r') || (*pStart == '\n'));

			wStart = (pStart - editptr);

			pEnd = editptr + wEnd;

			size = (pEnd - pStart) + 1 + 1; /* +1 for trailing \0  +1 for first QuoteLineInd */

			src = pStart;
			while (src < pEnd) 
			{
				if (*src == '\n') size++; /* length of ExternLineInd = 1 */
				src++;
			}

			if ((dst = newText = (char *) GlobalAllocPtr (GMEM_MOVEABLE, size * sizeof (char))) == NULL) 
			{
				WVMessageBox (hWndEdit, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_EDIT_TEXT, MB_OK | MB_ICONSTOP);
				GlobalFreePtr(editptr); /* free memory allocated by GetEditText */
				break;
			}

			src = pStart;
			*dst++ = ExternLineInd;
			delta = 1;
			while ( src < pEnd ) 
			{
				*dst++ = *src;
				if (*src == '\n') 
				{
					*dst++ = ExternLineInd;
					delta++;
				}
				src++;
			}
			*dst = '\0';


			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart, (LPARAM) wEnd);
			SendMessage (hWndEdit, EM_REPLACESEL, (WPARAM) TRUE, (LPARAM) newText);
			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart, (LPARAM) wEnd+delta );

         
			GlobalFreePtr (editptr); /* free memory allocated by GetEditText */
			GlobalFreePtr (newText);
			InvalidateRect (hWndEdit, NULL, TRUE);
        }
        break;

		case IDM_QUOTE_ADD:
        {
			DWORD dwResult;
			WORD wStart, wEnd;
			char *editptr;
			char *newText;
			char *dst,*src,*pStart,*pEnd;
			unsigned int size;
			unsigned int delta;

			dwResult = SendMessage (hWndEdit, EM_GETSEL, 0, 0L);
			wStart = LOWORD (dwResult);
			wEnd = HIWORD (dwResult);

			editptr = GetEditText (hWndEdit);

			pStart = editptr + wStart;
			while ((pStart >= editptr) && (*pStart != '\n') && (*pStart !='\r')) 
			{
				pStart--;
			}
			do 
			{
				pStart++;
			} while ((*pStart == '\r') || (*pStart == '\n'));

			wStart = (pStart - editptr);

			pEnd = editptr + wEnd;

			size = (pEnd - pStart) + 1 + 1; /* +1 for trailing \0  +1 for first QuoteLineInd */

			src = pStart;
			while (src < pEnd) 
			{
				if (*src == '\n') size++; /* length of QuoteLineInd = 1 */
					src++;
			}

			if ((dst = newText = (char *) GlobalAllocPtr (GMEM_MOVEABLE, size * sizeof (char))) == NULL) 
			{
				WVMessageBox (hWndEdit, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_EDIT_TEXT, MB_OK | MB_ICONSTOP);
				GlobalFreePtr(editptr); /* free memory allocated by GetEditText */
				break;
			}

			src = pStart;
			*dst++ = QuoteLineInd;
			delta = 1;
			while ( src < pEnd ) 
			{
				*dst++ = *src;
				if (*src == '\n') 
				{
					*dst++ = QuoteLineInd;
					delta++;
				}
				src++;
			}
			*dst = '\0';

			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart, (LPARAM) wEnd);
			SendMessage (hWndEdit, EM_REPLACESEL, (WPARAM) TRUE, (LPARAM) newText);
			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart, (LPARAM) wEnd+delta );

			GlobalFreePtr (editptr); /* free memory allocated by GetEditText */
			GlobalFreePtr (newText);
			InvalidateRect (hWndEdit, NULL, TRUE);
		}
		break;

		case IDM_QUOTE_REMOVE:
        {
			DWORD dwResult;
			WORD wStart, wEnd;
			char *editptr;
			char *dst,*src,*pStart,*pEnd;
			unsigned int delta;

			dwResult = SendMessage (hWndEdit, EM_GETSEL, 0, 0L);
			wStart = LOWORD (dwResult);
			wEnd = HIWORD (dwResult);

			editptr = GetEditText (hWndEdit);

			pStart = editptr + wStart;
			while ((pStart >= editptr) && (*pStart != '\n')) 
			{
				pStart--;
			}
			do 
			{
				pStart++;
			} while ((*pStart == '\r') || (*pStart == '\n'));

			wStart = (pStart - editptr);

			pEnd = editptr + wEnd;

			dst = src = pStart;
			src++;
			delta = 1;
			while (src < pEnd ) 
			{
				*dst++ = *src;
				if (*src == '\n') 
				{
					src++;
					delta++;
				}
				src++;
			}
			*dst = '\0';

			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart, (LPARAM) wEnd);
			SendMessage (hWndEdit, EM_REPLACESEL, (WPARAM) TRUE, (LPARAM) pStart);
			SendMessage (hWndEdit, EM_SETSEL, (WPARAM) wStart, (LPARAM) wEnd - delta);


			GlobalFreePtr (editptr);
			InvalidateRect (hWndEdit, NULL, TRUE);
		}
        break;

		case IDM_ROT13:
		{
			DWORD dwResult;
			WORD wStart, wEnd;
			char *editptr;

			dwResult = SendMessage (hWndEdit, EM_GETSEL, 0, 0L);
			wStart = LOWORD (dwResult);
			wEnd = HIWORD (dwResult);

			editptr = GetEditText (hWndEdit);
			strnROT13 (editptr + wStart, wEnd - wStart);

			*(editptr + wEnd) = '\0';
			SendMessage (hWndEdit, EM_REPLACESEL, (WPARAM) TRUE, (LPARAM) editptr + wStart);

			/* SetEditText (hWndEdit, editptr); changes current carret position :-( */

			GlobalFreePtr (editptr);
			InvalidateRect (hWndEdit, NULL, TRUE);
		}
        break;

		default:
			return (0);                                     // signnify no action 

	}
	return (1);                                   // signify actions completed 

}

/*
 *  function DoEditClose
 *  close down the edit window only if clean to close 
 *  or user agrees to lose information 
 *
 */
BOOL DoEditClose (HWND hWnd, int dirty)
{
	if (dirty == DT_DIRTY) 
	{
		if (WVMessageBox (hWnd, IDS_COMPOS_EXIT, IDS_COMPOS_EXIT_T,  MB_ICONQUESTION | MB_OKCANCEL) == IDOK) 
		{
			DestroyWindow (hWnd);
		}
		else
		{
			return TRUE;
		}
	}
	else 
	{
		DestroyWindow (hWnd);
	}
	return FALSE;
}

/* -----------------------------------------------------------------
 * New and Delete attachment
 * manage list of attachments via the attach listbox
 */
TypAttachment *	PrepNewAttachment (WndEdit * compWnd)
{
	TypAttachment *thisAttach;

	if (compWnd->numAttachments + 1 > MAX_NUM_ATTACHMENTS) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_MAXATTACH, IDS_COMPOS_ATTACHABORT, MB_OK | MB_ICONSTOP);
		return NULL;
	}

	thisAttach = (TypAttachment *) GlobalAllocPtr (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (TypAttachment));
	if (thisAttach == NULL) 
	{
		WVMessageBox(compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ATTACHABORT,  MB_OK | MB_ICONSTOP);
	}
	else 
	{
		thisAttach->attachInNewArt = DefaultAttachInNewArt;
		thisAttach->encodingType = DefaultEncodingType;
	}
	return thisAttach;
}

void AskForNewAttachment (WndEdit * compWnd)
{
	/*
	TypAttachment *thisAttach;

	if ((thisAttach = PrepNewAttachment (compWnd)) == NULL)
		return;

	if (DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_WINVNATTACH), compWnd->hWnd, lpfnWinVnAttachDlg, (LPARAM) thisAttach)) 
	{
		compWnd->attachment[compWnd->numAttachments] = thisAttach;
		compWnd->numAttachments++;
		if (thisAttach->encodingType == CODE_YENC)
		{
			GenerateMIME = 0;
		}
		SendMessage (compWnd->headerControls->UI[HDR_ATTACH],
			LB_ADDSTRING, 0, (LPARAM) (LPCSTR) thisAttach->fileName);
	}
	else 
	{
		GlobalFreePtr (thisAttach);
	}
	*/

	//start of a new attach dlg
	if (DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_ATTACH), compWnd->hWnd,
		   &WinVnAttachesDlg, (LPARAM) (&compWnd->attachment)) > 0) 
	{
		int nCount = 0;
		SendMessage (compWnd->headerControls->UI[HDR_ATTACH],
					 LB_RESETCONTENT, 0L, 0L);

		for (int n = 1; n < MAX_NUM_ATTACHMENTS; n++)
		{
			if (compWnd->attachment[n])
			{
				SendMessage (compWnd->headerControls->UI[HDR_ATTACH],
							 LB_ADDSTRING, (WPARAM) 0,
							 (LPARAM) (LPCSTR) compWnd->attachment[n]->fileName);
				nCount++;
			}
		}
		compWnd->numAttachments = nCount+1;//main body is attach #0
	}

}

void DeleteAttachment (WndEdit * compWnd, int num)
{
	register int i;

	assert (num >= 0 && num < compWnd->numAttachments);

	SendMessage (compWnd->headerControls->UI[HDR_ATTACH],
				LB_DELETESTRING, (WPARAM) (num - 1), 0);

	GlobalFreePtr (compWnd->attachment[num]);
	for (i = num; i < compWnd->numAttachments - 1; i++)
		compWnd->attachment[i] = compWnd->attachment[i + 1];

	compWnd->attachment[i] = (TypAttachment *) NULL;
	(compWnd->numAttachments)--;
}

/*------------------------------------------------------------------------
 * SetWordWrap - actually destroys the window and recreates it.
 * (I've tried messing with classword/etc.  doesn't look like you can change
 * wordwrap on the fly)
 * jsc 10/3/94
 */
void SetWordWrap (WndEdit * compWnd, BOOL enable)
{
	char *editBuf;
	editBuf = GetEditText (compWnd->hWndEdit);
	if (editBuf == NULL)
		return;

	DestroyWindow (compWnd->hWndEdit);
	CreateEditWnd (compWnd);
	SetEditText (compWnd->hWndEdit, editBuf);
	GlobalFreePtr (editBuf);
	ShowWindow (compWnd->hWndEdit, SW_NORMAL);
	SetFocus (compWnd->hWndEdit);
}

/*------------------------------------------------- 
 * PrepareComposition
 * fills composition controls with inital values (possibly based on a ref doc)
 * if refDoc is non-NULL, this is a doc which we are replying to
 *
 * based loosely on old CreatePostingText/ExtractPostingText
 * jsc 9/28/94
 */
BOOL PrepareComposition (WndEdit * compWnd)
{
	char *contents, *buf;
	BOOL result = SUCCESS;
	char *editBuf;
	int SaveDT = 0;

	if ((contents = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXREFERENCELINE * sizeof (char))) == NULL) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONSTOP);
		return FALSE;
	}

	if ((buf = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXREFERENCELINE * sizeof (char))) == NULL) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONSTOP);
		return FALSE;
	}

	/* init the 1st attachment which is the body */
	if ((compWnd->attachment[0] = PrepNewAttachment (compWnd)) == NULL) 
	{
		GlobalFreePtr(buf);
		GlobalFreePtr(contents);
		return FALSE;
	}
	compWnd->attachment[0]->encodingType = CODE_NONE;
	strcpy (compWnd->attachment[0]->contentType, "Text/Plain");
	strcpy (compWnd->attachment[0]->fileName, "text");
	compWnd->attachment[0]->attachInNewArt = FALSE;
	compWnd->numAttachments = 1;

	compWnd->extraHeaders = InitTextBlock(compWnd->hWnd);

	/* leave To address blank if forwarding */
	if ((compWnd->composeType == DOCTYPE_MAIL &&
		GetToAddress (buf, MAXREFERENCELINE, compWnd->Doc, compWnd->hWnd) == TRUE)) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_TO], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}

	/* Get Newsgroups line but handle special cases to use Followup-to Header
	if exists, unless we are Canceling */    
	if ((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) ||
		(compWnd->composeType == DOCTYPE_CANCEL)) 
	{

		if (compWnd->composeType == DOCTYPE_CANCEL) 
		{
			SaveDT = compWnd->composeType;
			compWnd->Doc->DocType = DOCTYPE_CANCEL;
		} 
		if (GetNewsgroups (buf, MAXREFERENCELINE, compWnd->Doc) == TRUE)
			SendMessage (compWnd->headerControls->UI[HDR_GROUPS], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
		if (compWnd->composeType == DOCTYPE_CANCEL)
			compWnd->Doc->DocType = SaveDT; 
	}

	if (ShowFromHdr && GetFromAddress (buf, MAXREFERENCELINE, compWnd->Doc) == TRUE) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_FROM], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}

	if (compWnd->composeType == DOCTYPE_CANCEL) 
	{
		GetHeaderLine (compWnd->Doc, "Message-ID:", contents, MAXREFERENCELINE); 
		_snprintf (buf, MAXREFERENCELINE, "Cancel %s",contents+12); 
		SendMessage (compWnd->headerControls->UI[HDR_SUBJECT], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}
	else if (GetSubject (buf, MAXREFERENCELINE, compWnd->Doc, compWnd->composeType) == TRUE) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_SUBJECT], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}

	if (ShowOrgHdr && GetOrganization (buf, MAXREFERENCELINE, compWnd->Doc) == TRUE) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_ORG], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}

	if (ShowReplyToHdr && GetReplyToAddress (buf, MAXREFERENCELINE, compWnd->Doc) == TRUE) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_REPLYTO], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}

	if (ShowFollowupToHdr && (compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
		GetFollowupTo (buf, MAXREFERENCELINE, compWnd->Doc) == TRUE) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_FOLLOWTO], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}

	if ((compWnd->composeType == DOCTYPE_POSTING) && PrefillCcAddress &&
		(GetToAddress (buf, MAXREFERENCELINE, compWnd->Doc, compWnd->hWnd) == TRUE) &&
		(compWnd->headerControls->UI[HDR_CC] != NULL)) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_CC], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	
	}  // following obtains Cc in mail replies... 
	else if (compWnd->composeType == DOCTYPE_MAIL &&
			(GetCcAddress(buf, MAXREFERENCELINE, compWnd->Doc) == TRUE) &&
			(compWnd->headerControls->UI[HDR_CC] != NULL)) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_CC], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}

	if (compWnd->composeType != DOCTYPE_CANCEL) 
	{
		if (ShowKeywordsHdr && GetHeaderContents (buf, MAXREFERENCELINE, compWnd->Doc, "Keywords:") == TRUE) 
		{
			SendMessage (compWnd->headerControls->UI[HDR_KEYWORDS], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
		}
	}

	if ((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
		ShowSummaryHdr && GetHeaderContents (buf, MAXREFERENCELINE, compWnd->Doc, "Summary:") == TRUE) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_SUMMARY], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}

	if (((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) ||
		(compWnd->composeType == DOCTYPE_CANCEL)) &&
		ShowDistributionHdr && GetHeaderContents (buf, MAXREFERENCELINE, compWnd->Doc, "Distribution:") == TRUE) 
	{
		SendMessage (compWnd->headerControls->UI[HDR_DIST], WM_SETTEXT, 0, (LPARAM) (LPCSTR) buf);
	}

	// The following are headers we need now but are not shown in the window
	// we need to capture these now, in case the refDoc gets discarded

	//Distribution
	if (((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) || 
		(compWnd->composeType == DOCTYPE_CANCEL)) &&
		!compWnd->headerControls->UI[HDR_DIST] &&
		GetHeaderContents (contents, MAXREFERENCELINE, compWnd->Doc, "Distribution:")) 
	{
		_snprintf (buf, MAXREFERENCELINE, "Distribution: %s\r\n", contents);
		result = AddLineToTextBlock (compWnd->extraHeaders, buf);
	}
	
	//Keywords
	if (result == SUCCESS && !compWnd->headerControls->UI[HDR_KEYWORDS] &&
		GetHeaderContents (contents, MAXREFERENCELINE, compWnd->Doc, "Keywords:")) 
	{
		_snprintf (buf, MAXREFERENCELINE, "Keywords: %s\r\n", contents);
		result = AddLineToTextBlock (compWnd->extraHeaders, buf);
	}

	//In-Reply-To
	if (result == SUCCESS && compWnd->composeType == DOCTYPE_MAIL &&
		GetInReplyTo (contents, MAXREFERENCELINE, compWnd->Doc)) 
	{
		_snprintf (buf, MAXREFERENCELINE, "In-Reply-To: %s\r\n", contents);
		result = AddLineToTextBlock (compWnd->extraHeaders, buf);
	}

	//Message-ID for supersedes
	if (compWnd->composeType == DOCTYPE_SUPERSEDE)
	{
		//set supersedes header, copy message ID for possible cancel-key
		GetHeaderLine (compWnd->Doc, "Message-ID:", contents, MAXREFERENCELINE);
		_snprintf (buf, MAXREFERENCELINE, "Supersedes: %s\r\n",contents+12);
		result = AddLineToTextBlock (compWnd->extraHeaders, buf);
		
		//is cancel-key needed?
		if (GetSameHeaderLines(compWnd->Doc, "Cancel-Lock:", buf, MAXHEADERLINE) )
		{
			char *p = contents+12, *end;
			while (*p && isspace((unsigned char)*p))
				p++;
			end = p;
			while (*end && !isspace((unsigned char)*end))
				end++;
			*end = '\0';

			//cancel-key needs to match original ID
			char * key = sha_key(CancelKey, strlen(CancelKey), p, strlen(p));
			if (key)
			{  
				_snprintf (buf, MAXHEADERLINE, "Cancel-Key: %s\r\n", key);	
				free(key);
				result = AddLineToTextBlock (compWnd->extraHeaders, buf);
			}
		}
	}
	//References:
	if (result == SUCCESS && GetReferences (contents, MAXREFERENCELINE, compWnd->Doc)) 
	{
		_snprintf (buf, MAXREFERENCELINE, "References: %s\r\n", contents);
		result = AddLineToTextBlock (compWnd->extraHeaders, buf);
	}


	GlobalFreePtr(buf);
	GlobalFreePtr(contents);

	if (MakeBody (&editBuf, compWnd->Doc, compWnd->composeType, compWnd->hWnd, compWnd->hWndEdit, FALSE) != SUCCESS) 
	{
		return FAIL;
	}
	if (editBuf != (char *) NULL) 
	{
		SetWindowText (compWnd->hWndEdit, editBuf);
		GlobalFreePtr (editBuf);
		if (compWnd->dirty == DT_DIRTY)
		{

			//insert failed... one more time without message body

			if (MakeBody (&editBuf, compWnd->Doc, compWnd->composeType, compWnd->hWnd, compWnd->hWndEdit, TRUE) != SUCCESS)
				return FAIL;
			if (editBuf != (char *) NULL) 
			{
				SetWindowText (compWnd->hWndEdit, editBuf);
				GlobalFreePtr (editBuf);
			}

		}
	}
	return SUCCESS;
}

//When message-ID changes, cancel-lock needs to change
void UpdateCancelLock (TypTextBlock * textBlock)
{
	//Cancel-Lock:
	if (UseCancelKey)
	{
		char NewLock[MAXHEADERLINE];
		char MessageID[MAXHEADERLINE];

		NewLock[0] = '\0';

		//make sure cancel-lock matches any modified message id
		if (!GetHeaderLineTextBlock(MessageID, textBlock, "Message-ID:", FALSE) )
			_snprintf (MessageID, MAXHEADERLINE, "<%s>", attachmentID);

		char * lock = sha_lock(CancelKey, strlen(CancelKey), MessageID, strlen(MessageID));
		if (lock)
		{  
			_snprintf (NewLock, MAXHEADERLINE, "Cancel-Lock: %s\r\n", lock);	
			free(lock);

			/* find message-id line in headers to replace */
			
			int num = iSearchLineTextBlock (textBlock, "Cancel-Lock:");
	
			if (num < textBlock->numLines)
				ReplaceLineInTextBlock (textBlock, num, NewLock);
			else
				AddLineToTextBlock (textBlock, NewLock);
		}
	}

}


/*------------------------------------------------- 
 * GenerateHeadersForSend
 * generate headers textblock based on entries in header controls
 *
 * called by SendComposition (located in wvattach.c)
 * jsc 9/28/94
 */
/* Ray Dunn:99/11: Added ConfirmXPost parameter */
BOOL GenerateHeadersForSend (WndEdit * compWnd, TypTextBlock * headers, char *saveSubject, int ConfirmXPost)
{
	register int n;
	unsigned long i;
	char *title, *contents;
	char *buf;
	char *dest, *src;
	char *text, *ptr, *endPtr;
	BOOL result = SUCCESS;
	int ForDocType;
	TypDoc * myDoc;
	BOOL found;

	if ((title = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXDIALOGSTRING * sizeof (char))) == NULL) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONSTOP);
		return FAIL;
	}
	if ((contents = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXHEADERLINE * sizeof (char))) == NULL) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONSTOP);
		return FAIL;
	}
	if ((buf = (char *) GlobalAllocPtr (GMEM_MOVEABLE, MAXHEADERLINE * sizeof (char))) == NULL) 
	{
		WVMessageBox (compWnd->hWnd, IDS_COMPOS_ALLOCFAIL, IDS_COMPOS_ERROR, MB_OK | MB_ICONSTOP);
		return FAIL;
	}


	*CcAddress = '\0';

	for (n = 0; n < HDR_NUM_CONTROLS; n++) 
	{
		if (n == HDR_ATTACH)
			continue;

		if (compWnd->headerControls->UI[n]) 
		{
			SendMessage (compWnd->headerControls->title[n], WM_GETTEXT, (WPARAM) MAXDIALOGSTRING, (LPARAM) (LPCSTR) title);
			SendMessage (compWnd->headerControls->UI[n], WM_GETTEXT, (WPARAM) MAXHEADERLINE, (LPARAM) (LPCSTR) contents);

			// following header lines are required 
			if (!EditHeaderFlag) 
			{        
				if (*contents == '\0' && (n == HDR_TO || n == HDR_GROUPS || n == HDR_FROM || n == HDR_SUBJECT)) 
				{
					WVArgMessageBox (compWnd->hWnd, IDS_COMPOS_ENTRY_REQ, IDS_COMPOS_INCOMPLETE,
						MB_OK | MB_ICONSTOP, title);
					result = FAIL;
					
					break;
				}
			}
			// strip spaces in newsgroups
			if (n == HDR_GROUPS)
			{
				// Ray Dunn:99/10: Warn if crossposting 
				int groupcount = 1;
				int gotcomma = 0;

				strcpy (buf, contents);
				for (dest = contents, src = buf; *src; src++)
				{
					if (!isspace ((unsigned char)*src))
					{
						*dest++ = *src;
						if (*src == ',')
							gotcomma = 1;
						else if (gotcomma)
						{
							groupcount++;
							gotcomma = 0;
						}
					}
				}
				*dest = '\0';

				if (ConfirmXPost && groupcount > 1)
				{
					char Mesg[20];
					sprintf (Mesg, "%d", groupcount);
					if (IDYES != WVArgMessageBox (compWnd->hWnd, IDS_COMPOS_CROSSPOST, IDS_COMPOS_TITLEXPOST,
						   MB_YESNO | MB_ICONEXCLAMATION, Mesg) )
					return(FAIL);

				}
				// Ray Dunn:99/10:End 

			}          
			if (*contents) 
			{
				if (saveSubject && n == HDR_SUBJECT) 
				{
					// save subject line if given a saveSubject buffer
					strcpy (saveSubject, contents);
				}
				if (n == HDR_CC && compWnd->composeType == DOCTYPE_POSTING ) 
				{
					// eat cc-by-mail address when posting 
					strntcpy (CcAddress, contents, MAXHEADERLINE-1);
				}
				else if (n == HDR_REPLYTO && !strcmp (MailAddress, contents)) 
				{
					// ignore reply-to if identical to mail address 
				}
				// ignore follow-to if identical to newsgroups or we are canceling
				else if ((n == HDR_FOLLOWTO) && 
					((compWnd->composeType == DOCTYPE_CANCEL) ||
					 (compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) &&
					  GetNewsgroups (buf, MAXHEADERLINE, compWnd->Doc) &&
					(!strcmp (buf, contents))))
				{ 
				}
				else 
				{
					// good header, add it to the header block 
					_snprintf (buf, MAXHEADERLINE, "%s %s\r\n", title, contents);
					if (AddLineToTextBlock (headers, buf) == FAIL) 
					{
						result = FAIL;
						break;
					}
				}
			}
		}
	}

	// deal with headers which are not shown, but we still want 
	
	//From:
	if (result == SUCCESS &&
		!compWnd->headerControls->UI[HDR_FROM] &&
		!SearchLineTextBlock(compWnd->extraHeaders, "From:") &&
		GetFromAddress (contents, MAXHEADERLINE, compWnd->Doc)) 
	{
		_snprintf (buf, MAXHEADERLINE, "From: %s\r\n", contents);
		result = AddLineToTextBlock (headers, buf);
	}

	//Reply-to:
	if (result == SUCCESS &&
		!compWnd->headerControls->UI[HDR_REPLYTO] && *ReplyTo &&
		!SearchLineTextBlock(compWnd->extraHeaders, "Reply-To:")) 
	{
		_snprintf (buf, MAXHEADERLINE, "Reply-To: %s\r\n", ReplyTo);
		result = AddLineToTextBlock (headers, buf);
	}

	//Organization:
	if (result == SUCCESS &&
		!compWnd->headerControls->UI[HDR_ORG] && *Organization &&
		!SearchLineTextBlock(compWnd->extraHeaders, "Organization:")) 
	{
		_snprintf (buf, MAXHEADERLINE, "Organization: %s\r\n", Organization);
		AddLineToTextBlock (headers, buf);
	}
               
	//Control:
	if (result == SUCCESS &&      
		compWnd->composeType == DOCTYPE_CANCEL && 
		!SearchLineTextBlock(compWnd->extraHeaders, "Control:") &&
		GetHeaderLine (compWnd->Doc, "Message-ID:", contents, MAXHEADERLINE)) 
	{ 
		_snprintf (buf, MAXHEADERLINE, "Control: cancel %s\r\n", contents+12);
		result = AddLineToTextBlock (headers, buf);
	}

	//Date:
	if (result == SUCCESS &&      /*compWnd->composeType != DOCTYPE_POSTING && */ //RFC 1036 reqs date field (J. David Bryan )
		!SearchLineTextBlock(compWnd->extraHeaders, "Date:") &&
		GetDate (contents, MAXHEADERLINE)) 
	{
		_snprintf (buf, MAXHEADERLINE, "Date: %s\r\n", contents);
		result = AddLineToTextBlock (headers, buf);
	}

	//Message-ID:
	if (result == SUCCESS && 
		compWnd->composeType != DOCTYPE_CANCEL &&
		!SearchLineTextBlock(compWnd->extraHeaders, "Message-ID:")) 
	{
		//<pan.2006.08.24.15.38.25.268747@emteedee.invalid>
		GenerateMIMEAttachmentID();
		_snprintf (buf, MAXHEADERLINE, "Message-ID: <%s>\r\n", attachmentID);
		result = AddLineToTextBlock (headers, buf);
	}


	// If authentication was required, add header so that people reading it can
	// know who really posted it.  (The From: line may be a lie.)

	if (result == SUCCESS && AuthReqMail &&
		!SearchLineTextBlock(compWnd->extraHeaders, "X-Authenticated-User:")) 
	{
		_snprintf (buf, MAXHEADERLINE, "X-Authenticated-User: %s\r\n", AuthenticatedName);
		result = AddLineToTextBlock (headers, buf);
	}

	if (!EditHeaderFlag) 
	{        
		
		//Cancel-Key: needed for Cancel
		if (result == SUCCESS &&  (compWnd->composeType == DOCTYPE_CANCEL) && 
			GetHeaderLine (compWnd->Doc, "Message-ID:", contents, MAXHEADERLINE) &&
			!SearchLineTextBlock(compWnd->extraHeaders, "Cancel-Key:")) 
		{ 

			char *p = contents+12, *end;
			while (*p && isspace((unsigned char)*p))
				p++;
			end = p;
			while (*end && !isspace((unsigned char)*end))
				end++;
			*end = '\0';


			char * key = sha_key(CancelKey, strlen(CancelKey), p, strlen(p));
			if (key)
			{  
				_snprintf (buf, MAXHEADERLINE, "Cancel-Key: %s\r\n", key);	
				free(key);
				result = AddLineToTextBlock (headers, buf);

			}
		}		
		
		//Cancel-Lock:
		if (UseCancelKey)
		{
			if (result == SUCCESS && compWnd->composeType != DOCTYPE_CANCEL && 
									 compWnd->composeType != DOCTYPE_MAIL )
			{
				//make sure cancel-lock matches any modified message id
				if (!GetHeaderLineTextBlock(buf, headers, "Message-ID:", FALSE) &&
					!GetHeaderLineTextBlock(buf, compWnd->extraHeaders, "Message-ID:", FALSE))
					_snprintf (buf, MAXHEADERLINE, "<%s>", attachmentID);
	
				char * lock = sha_lock(CancelKey, strlen(CancelKey), buf, strlen(buf));
				if (lock)
				{  
					_snprintf (buf, MAXHEADERLINE, "Cancel-Lock: %s\r\n", lock);	
					free(lock);
					
					//if message-id changes, we need to update cancel-lock
					result = AddLineToTextBlock (headers, buf);

				}
			}
		}
		
		
		if (result == SUCCESS && !NoXNewsreader) 
		{
			if ((compWnd->composeType == DOCTYPE_POSTING || compWnd->composeType == DOCTYPE_SUPERSEDE) || 
				(compWnd->composeType == DOCTYPE_CANCEL)) 
			{
				_snprintf (buf, MAXHEADERLINE, "X-Newsreader: %s %s\r\n", WINVN_VERSION, WINVN_ARCHITECTURE);
			}
			else 
			{
				_snprintf (buf, MAXHEADERLINE, "X-Mailer: %s %s\r\n", WINVN_VERSION, WINVN_ARCHITECTURE);
			}
			result = AddLineToTextBlock (headers, buf);
		}
	}     

	if (result == SUCCESS && XNoArchive && !EditHeaderFlag && compWnd->composeType != DOCTYPE_MAIL) 
	{
		_snprintf (buf, MAXHEADERLINE, "X-No-Archive: yes\r\n");
		result = AddLineToTextBlock (headers, buf);
	}

	if (compWnd->composeType == DOCTYPE_CANCEL) 
	{
		compWnd->bodyOffset = 0L;
	}
	else 
	{
		// add any extra headers added in PrepareComposition 
		for (i = 0; result == SUCCESS && i < compWnd->extraHeaders->numLines; i++) 
		{
			result = AddLineToTextBlock (headers, TextBlockLine(compWnd->extraHeaders, i));
		}

		// now scan body text up to a blank line for additional 
		// x- and rfc822 and rfc1036 headers 
		compWnd->bodyOffset = 0L;

		if ((text = GetEditText (compWnd->hWndEdit)) == NULL) 
			result = FAIL;

		if (result == SUCCESS) 
		{
			ptr = text;
			while (*ptr && result == SUCCESS) 
			{
				if ((endPtr = strchr (ptr, '\r')) == NULL) 
				{
					endPtr = ptr + strlen(ptr);   // handle no crlf on last line 
				} 
				else 
				{
					*endPtr = '\0';
					endPtr++;				// move past \r 
					
					// handle soft line break \r\r\n (see EM_FMTLINES) 
					if (*endPtr == '\r') 
						endPtr++;			// move past \n 

					if (*endPtr == '\n') 
						endPtr++;			// move past extra \n (in case of soft line break extra \n 
				}
				if (*ptr == '\0' ||                 // blank line 
					strchr (ptr, ':') == NULL ||    // no colon 
					!IsAdditionalHeader(ptr)) 		// not recognized 
				{             
					break;
				}       
				_snprintf(buf, MAXHEADERLINE, "%s\r\n", ptr);
				result = AddLineToTextBlock (headers, buf);
				ptr = endPtr;
			}
			if (ptr != text) 
			{
				compWnd->bodyOffset = (unsigned long)(ptr - text);
			}
			GlobalFreePtr (text);
		}
	}

	myDoc = compWnd->Doc;
	if (!myDoc) 
	{
		/* perhaps we have started posting from a group window ? */
		/* try to find this. if not available, it's a posting from the mainwindow */
		for (n = 0, found = FALSE; !found && n < MAXGROUPWNDS; n++) 
		{
			if (GroupDocs[n].hWndFrame == compWnd->ParenthWnd) 
			{
				found = TRUE;
				myDoc = &(GroupDocs[n]);
			}
		}
	}

	ResetGroupAddHdr(myDoc);
	while ((result == SUCCESS) && (GetGroupCurrentAddHdr(myDoc,&ForDocType,contents))) 
	{
		if ( (ForDocType & compWnd->composeType) &&
			contents[0] && ((ptr=strchr(contents,':'))!=NULL) &&
			IsAdditionalHeader(contents)) 
		{
			*ptr = '\0';
			strcpy(buf,contents);
			*ptr = ':';
			strcat(buf,":");

			// don't add existing headers 
			if (!SearchLineTextBlock(headers, buf)) 
			{
				_snprintf(buf,MAXHEADERLINE,"%s\r\n",contents);
				result = AddLineToTextBlock(headers,buf);
			}
			if (result != SUCCESS)
				break;
		}
		GroupGoToNextAddHdr(myDoc);
	}

	ResetGlobalAddHdr();
	while ((result == SUCCESS) && (GetGlobalCurrentAddHdr(&ForDocType,contents))) 
	{
		if ( (ForDocType & compWnd->composeType) &&
			contents[0] && ((ptr=strchr(contents,':'))!=NULL) &&
			IsAdditionalHeader(contents)) 
		{
			*ptr = '\0';
			strcpy(buf,contents);
			*ptr = ':';
			strcat(buf,":");
			// don't add existing headers
			if (!SearchLineTextBlock(headers, buf)) 
			{
				_snprintf(buf,MAXHEADERLINE,"%s\r\n",contents);
				result = AddLineToTextBlock(headers,buf);
			}
			if (result != SUCCESS)
				break;
		}
		GlobalGoToNextAddHdr();
	}

	GlobalFreePtr(buf);
	GlobalFreePtr(contents);
	GlobalFreePtr(title);

	return result;
}

/* ------------------------------------------------------------------------
 * Returns true for lines which look like standard header lines
 * A binary search through a list of words would be really smart
 * This is the lazy approach
 */
BOOL IsAdditionalHeader(const char *line)
{
	if (!line)
		return FALSE;

	switch (tolower(line[0]))
	{
		case 'a': 
				return (!_strnicmp(line, "approved: ", 10) ||
						!_strnicmp(line, "author: ",8) ||
						!_strnicmp(line, "archive-name: ", 14) ||
						!strncmp(line, "Article ", 8) );
		case 'b': 
				return (!_strnicmp(line, "bcc: ", 5) ||
						!_strnicmp(line, "bytes: ", 7));
		case 'c': 
				return (!_strnicmp(line, "cancel-key: ", 12) ||
						!_strnicmp(line, "cancel-lock: ", 13) ||
						!_strnicmp(line, "cc: ", 4) ||
						!_strnicmp(line, "control: ", 9) ||
						!_strnicmp(line, "comments: ", 10) ||
						!strncmp(line, "Content-", 8) );
		case 'd': 
				return (!_strnicmp(line, "date: ", 6) ||
						!_strnicmp(line, "distribution: ", 14));
		case 'e': 
				return (!_strnicmp(line, "encrypted: ", 11) ||
						!_strnicmp(line, "expires: ", 9));
		case 'f': 
				return (!_strnicmp(line, "followup-to: ", 13) ||
						!_strnicmp(line, "from: ", 6) ||
						!_strnicmp(line, "face: ", 6));	 //unapproved but inuse header
		case 'g':
				return (!_strnicmp(line, "get-it-from: ", 13) );
		case 'i':
				return (!_strnicmp(line, "in-reply-to: ", 13));
		case 'k':
				return (!_strnicmp(line, "keywords: ", 10));
        
		case 'l':
				return (!_strnicmp(line, "lines: ", 7));
		case 'm':
				return (!_strnicmp(line, "message-id: ", 12) ||
						!_strnicmp(line, "mime-version: ", 14) );
		case 'n':
				return (!_strnicmp(line, "newsgroups: ", 12) ||
						!_strnicmp(line, "nntp-posting-host: ", 19) ||
						!_strnicmp(line, "nntp-posting-date: ", 19) );
		case 'o':
				return (!_strnicmp(line, "organization: ", 14) ||
						!_strnicmp(line, "originator: ", 12) );
		case 'p':
				return (!_strnicmp(line, "path: ", 6) ||
						!_strnicmp(line, "posting-number: ", 16) ||
						!_strnicmp(line, "posting-by: ", 12) );
		case 'r':
				return (!_strnicmp(line, "references: ", 12) ||
						!_strnicmp(line, "resent-", 7) ||
						!_strnicmp(line, "return-path: ", 13) ||
						!_strnicmp(line, "reply-to: ", 10));
		case 's':
				return (!_strnicmp(line, "sender: ", 8) ||
						!_strnicmp(line, "subject: ", 9) ||
						!_strnicmp(line, "summary: ", 9) ||
						!_strnicmp(line, "supersedes: ", 12) || 
						!_strnicmp(line, "status: ", 8 ) ||
						!_strnicmp(line, "sent: ", 6) ||
						!_strnicmp(line, "submitted-by: ", 14) );   
		case 't':
				return (!_strnicmp(line, "to: ", 4));
		case 'u':
				return (!_strnicmp(line, "user-agent: ", 12));
		case 'x':
				return (!_strnicmp(line, "x-", 2) ||
						!_strnicmp(line, "xdisclaimer: ", 13) || 
						!_strnicmp(line, "xref: ", 6) );
		default:
				return (0);
	}
}
