/* Interface to GENSOCK module */
/* $Id: wvsckgen.c 1.29 1996/08/13 04:55:55 dumoulin Exp $ */

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#include "intgensock.h"



#pragma hdrstop
#include <stdlib.h>
#include <stdio.h>				/* for sprintf */
#include <stdarg.h>				/* for varargs stuff */
#include <ctype.h>				/* for isspace */
#define MAXSENDLEN 32767
//#define COMMBUFSIZE	1600

/* generic socket DLL support */
//#include "gensock\\gensock.h"

//char CommBuff[COMMBUFSIZE];
//int CommBuffIdx = COMMBUFSIZE + 1;
//int CharsInCommBuff = 0;

socktag NNTPSock = 0;
socktag SMTPSock = 0;
char my_hostname[256];

			

/* functions the rest of winvn expects to see */
BOOL PutCommLine (char *line);
BOOL PutCommData (char *data, unsigned int length);

int MRRReadComm (void);
void MRRCloseComm (void);
int MRRInitComm (void);
BOOL MRRInitZStream(int nType);

/* internal to this file */
int open_smtp_socket (void);
void smtp_error (char *message, HWND hWnd = NULL);
int finish_smtp_message (void);
int get_smtp_line (char* buf = NULL, int* pLen = NULL);
int put_smtp_line (socktag sock, char far * line, unsigned int nchars);

HINSTANCE gensock_lib = 0;
static BOOL NoChkConn = FALSE;   //S.Yoshida

int (FAR PASCAL * pgensock_connect) (char FAR * hostname, char FAR * service, socktag FAR * pst, char UseSSL, int ipfamily);
int (FAR PASCAL * pgensock_getchar) (socktag st, int wait, char FAR * ch);
int (FAR PASCAL * pgensock_put_data) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL * pgensock_close) (socktag st);
int (FAR PASCAL * pgensock_gethostname) (char FAR * name, int namelen);
int (FAR PASCAL * pgensock_put_data_buffered) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL * pgensock_put_data_flush) (socktag st);
int (FAR PASCAL * pgensock_starttls) ( socktag st);
int (FAR PASCAL * pgensock_description) (socktag st, char* desc, int nLen);
int (FAR PASCAL * pgensock_startZstream) (socktag st, int nType);
int (FAR PASCAL * pgensock_endZstream) (socktag st);



/*-- function MRRReadComm ---------------------------------------
 *
 *  Reads characters from the NNTP Socket
 */

#define ERROR_BUFFER_SIZE 1024

void complain (int err, char *function, char *fmt,...)
{
	va_list marker;
	char message[ERROR_BUFFER_SIZE];
	char message1[100];
	static int messageOnScreen = FALSE; /* avoid cascading errors --> stack crash */
    
	int SaveCommState = CommState;
    CommState = ST_WAIT_COMM;
	
	/* Write text to a string and output the string. */
	if (!messageOnScreen) 
	{
		va_start (marker, fmt);
		_vsnprintf (message, ERROR_BUFFER_SIZE, fmt, marker);
		va_end (marker);
	if (err >=0)
		wsprintf (message1, "Error %d - Function '%s'",err,function);
	else
		wsprintf (message1, "WinVN Function '%s'",function);
		messageOnScreen = TRUE;
		WVMessageBox (NetDoc.hDocWnd, message, message1, MB_OK  | MB_ICONERROR);
		messageOnScreen = FALSE;

		/*
		//need to test -MDS			
		char error_string[1024];
		strcpy(error_string, message);

		strcat(	error_string, "\r\nClose in 90 seconds...");
		WVTimedMessageBox(NULL, error_string, "Winsock Error" ,MB_OK|MB_ICONHAND);	
		*/	

	}
    CommState = SaveCommState;

}

void gensock_error (char *function, int retval)
{
	char error_string[512];
	int len;

	len = LoadString (hInst, retval, error_string, sizeof (error_string));
		complain (retval,function,"%s",
		len == 0 ? "[couldn't get error string]" : error_string);
}

BOOL MRRInitZStream(int nType)
{

	return (*pgensock_startZstream) (NNTPSock, nType);
}

int MRRReadComm ()
{
	int retval;
	unsigned char ch;

	/* we set wait = 1, sortof non-blocking */
	if (!NNTPSock)
		return (-1);

	if ( (retval = (*pgensock_getchar) (NNTPSock, 1, (char FAR *)&ch))) 
	{
		switch (retval) 
		{
			case WAIT_A_BIT:
			case ERR_BUSY:
				break;
			case ERR_NOT_CONNECTED:
				if (Initializing == INIT_ESTAB_CONN && Reconnecting == 1 && Autoconnect == 1 && UseSSL)
				{
					//aborted SSL connect on 1st read?  Try again
					//complain (-1,"MRRReadComm","NNTP server has closed the connection");
					MRRInitComm ();
					break;
				}
				else if ( Initializing == INIT_ESTAB_CONN && UseSSL)
				{
					//aborted on 1st connection
					Initializing = INIT_NOT_CONNECTED;
					MRRCloseComm ();
					SetConnectMenuItems (&NetDoc, ENABLE);
					UpdateWindow (NetDoc.hDocWnd);
					return(-1);

				}

				Initializing = INIT_NOT_CONNECTED;
				PostMessage (NetDoc.hDocWnd, (UINT) WM_COMMAND,
							(WPARAM) IDM_DISCONNECTED, (LPARAM) 0);
				Initializing = INIT_NOT_CONNECTED;
				//Disconnect ();
				//complain (-1,"MRRReadComm","NNTP server has closed the connection");
				return (-1);
				break;
			case ERR_DECOMPRESS:
				return (-2);
				break;
			default:
				gensock_error ("gensock_getchar", retval);
		}
		return (-1);
	}
	else 
		return ((int) ch);
}

int	putline_internal (socktag sock, char *line, unsigned int nchars)
{
	int retval;

	if (sock && (retval = (*pgensock_put_data) (sock, (char FAR *) line,
		 (unsigned long) nchars))) 
	{
		switch (retval) 
		{
			case ERR_NOT_CONNECTED:
				Initializing = INIT_NOT_CONNECTED;
				SendMessage (NetDoc.hDocWnd, (UINT) WM_COMMAND,
						    (WPARAM) IDM_DISCONNECTED, (LPARAM) 0);

				//Disconnect ();
				//complain (-1,"PutLine_Internal","NNTP server has closed the connection");
				return (-1);
			break;

			default:
				gensock_error ("gensock_put_data", retval);
		}
		return (-1);
	}
	else if (!sock)
		return -1;

	return (0);
}

/* PutCommLine takes a string, sends it, followed by
 * \r\n.  All one-line sends in winvn should use this.
 */

BOOL PutCommLine (char *line)
{
	if (putline_internal (NNTPSock, line, lstrlen (line)) < 0 ||
		putline_internal (NNTPSock, "\r\n", 2) < 0)
		return FALSE;

	//we've sent something
	TimeoutCounter = CommTimeout * 1000 / COMM_TIMER_INTERVAL;

	return TRUE;
}

/* Use this function for sending larger chunks of data.
 * the text data from an Edit class window can be sent
 * using this function
 */

BOOL PutCommData (char *data, unsigned int length)
{
	//we've sent something
	TimeoutCounter = CommTimeout * 1000 / COMM_TIMER_INTERVAL;
	
	return (putline_internal (NNTPSock, data, length)) == 0;
}

/*-- function MRRCloseComm -----------------------------------------
 *
 *  Close the communications port, serial or TCP.
 */
void MRRCloseComm ()
{
	if (NNTPSock) 
	{
		(*pgensock_close) (NNTPSock);
		NNTPSock = (socktag) 0;
	}
	if (!SMTPSock && gensock_lib) 
	{
		if (gensock_lib > (HINSTANCE)1)
			FreeLibrary (gensock_lib);
		gensock_lib = 0;
		pgensock_connect =NULL;
		pgensock_getchar = NULL;
		pgensock_put_data =NULL;
		pgensock_close = NULL;
		pgensock_gethostname = NULL; 
		pgensock_put_data_buffered = NULL;
		pgensock_put_data_flush = NULL;
		pgensock_starttls = NULL;
		pgensock_description = NULL;
		pgensock_startZstream = NULL;
		pgensock_endZstream = NULL;


	}
	CommState = ST_CLOSED_COMM;
	SetStatbarText (NetDoc.hWndFrame, "", &NetDoc, TRUE, TRUE);
	SetConnectionText (NetDoc.hWndFrame, "", &NetDoc, TRUE, TRUE);
	InvalidateRect (NetDoc.hDocWnd, NULL, TRUE);
}

int	load_gensock ()
{

//MDS always use internal one for now
//	if ((gensock_lib = LoadLibrary (GenSockDLL)) == NULL) 
	{

	/*
		char message[256];
		wsprintf (message, "Couldn't load '%s'", GenSockDLL);
		complain (-1,"Load_Gensock",message);
		gensock_lib = 0;
	 */

	/* use internal one */
	pgensock_connect =&gensock_connect;
	pgensock_getchar = &gensock_getchar;
	pgensock_put_data =gensock_put_data;
	pgensock_close = &gensock_close;
	pgensock_gethostname = &gensock_gethostname; 
	pgensock_put_data_buffered = &gensock_put_data_buffered;
	pgensock_put_data_flush = &gensock_put_data_flush;
	pgensock_starttls = &gensock_starttls;
	pgensock_description = &gensock_description;
	pgensock_startZstream = &gensock_startZstream;
	pgensock_endZstream = &gensock_endZstream;


	gensock_lib =  (HINSTANCE) 1;
	return (0);
	//return (-1);

		
	}
#if 0
	if (!result && (pgensock_connect =
		  (int (FAR PASCAL *) (char FAR *, char FAR *, socktag FAR *, char ))
				  GetProcAddress (gensock_lib, "gensock_connect")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_connect");
		result = -1;
	}

	if (!result && (pgensock_getchar =
		  (int (FAR PASCAL *) (socktag, int, char FAR *))
				  GetProcAddress (gensock_lib, "gensock_getchar")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_getchar");
		result = -1;
	}

	if (!result && (pgensock_put_data =
		(int (FAR PASCAL *) (socktag, char FAR *, unsigned long))
			GetProcAddress (gensock_lib, "gensock_put_data")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_put_data");
		result = -1;
	}

	if (!result && (pgensock_close =
		(int (FAR PASCAL *) (socktag))
			GetProcAddress (gensock_lib, "gensock_close")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_close");
		result = -1;
	}

	if (!result && (pgensock_gethostname =
		(int (FAR PASCAL *) (char FAR *, int))
			 GetProcAddress (gensock_lib, "gensock_gethostname")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_gethostname");
		result = -1;
	}

	if (!result && (pgensock_put_data_buffered =
		(int (FAR PASCAL *) (socktag, char FAR *, unsigned long))
			GetProcAddress (gensock_lib, "gensock_put_data_buffered")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_put_data_buffered");
		result = -1;
	}

	if (!result && (pgensock_put_data_flush =
	  (int (FAR PASCAL *) (socktag))
		  GetProcAddress (gensock_lib, "gensock_put_data_flush")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_put_data_flush");
		result = -1;
	}
	if (!result && (pgensock_starttls =
		(int (FAR PASCAL *) (socktag))
		  GetProcAddress (gensock_lib, "gensock_starttls")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_starttls");
		result = -1;
	}
	if (!result && (pgensock_description =
		(int (FAR PASCAL *) (socktag st, char* desc, int nLen))
		  GetProcAddress (gensock_lib, "gensock_description")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_description");
		result = -1;
	}

		if (!result && (pgensock_startZstream =
		  (int (FAR PASCAL *) (socktag, int))
				  GetProcAddress (gensock_lib, "gensock_startZstream")) == NULL) 
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_startZstream");
		//result = -1;
	}


	if (!result && (pgensock_endZstream =
		  (int (FAR PASCAL *) (socktag))
				  GetProcAddress (gensock_lib, "gensock_endZstream")) == NULL)
	{
		complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_endZstream");
		//result = -1;
	}
				   


	


	if (result) 
	{
		FreeLibrary (gensock_lib);
		gensock_lib = 0;
	}
	return (result);
#endif
}

int	MRRInitComm ()
{
	int retval;
	DWORD dwTries = 1;

	if (NNTPSock) 
	{
		(*pgensock_close) (NNTPSock);
		NNTPSock = (socktag) 0;
		SetConnectionText (NetDoc.hWndFrame, "", &NetDoc, TRUE, TRUE);


	}
	{
		if ( (bool)NetDoc.nStatBarCommPanel ^ (bool)UseSSL )
		{
			NetDoc.nStatBarCommPanel = UseSSL;
			InvalidateRect(NetDoc.hWndFrame, NULL, TRUE);

		}

	}	
	
	/* load the library if it's not loaded */
	if (!gensock_lib) 
	{
		if ((retval = load_gensock ())) 
		{
			return (retval);
		}
	}

	/* to keep our sanity, we will quietly try '119' in case it fails */
	NoChkConn = TRUE;
	while (1)
	{
		
		if ((retval = (*pgensock_connect) ((LPSTR) NNTPHost,
									 (LPSTR) NNTPService,
									 &NNTPSock, (char) UseSSL, (int) ip_family))) 
		{
			if (retval == ERR_CANT_RESOLVE_SERVICE) 
			{
				//Dont retry the same port numbers that just failed
				if (strcmp(NNTPService, "563") && strcmp(NNTPService, "119"))
				{ 
					if ((retval = (*pgensock_connect) ((LPSTR) NNTPHost,
													 UseSSL ? (LPSTR) "563" : (LPSTR) "119",
													 &NNTPSock, UseSSL, ip_family))) 
					{
						gensock_error ("gensock_connect", retval);
						return (-1);
					}
					else
					{
						break;
					}
				}
				else
				{
					gensock_error ("gensock_connect", retval);
					return (-1);				
				}
			}
			/* error other than can't resolve service */
			else 
			{
				if (Reconnecting == 1)
				{
					
					char error_string[512];
					char title[256];
					int len;

					wsprintf(title, "Restablish connection attempt %d...", dwTries);

					len = LoadString (hInst, retval, error_string, sizeof (error_string));
					strcat(	error_string, "\r\nRetrying in 30 seconds...");
					UINT uRet = WVTimedMessageBox(NetDoc.hDocWnd, len ? error_string : " Unknown Error", title ,MB_OKCANCEL);	
					if ( uRet != IDOK)
					{
						return (-1);
						break;
					}
					else
					{
						dwTries++;
						continue;
					}
				}
				else
					gensock_error ("gensock_connect", retval);
				return (-1);
			}
		}
		else
		{

			 break;
		}
	}
	NoChkConn = FALSE;
	IgnoreCommCh = '\r';
	EOLCommCh = '\n';

	CommLinePtr = CommLineIn;
	CommState = ST_ESTABLISH_COMM;
	CommBusy = FALSE;
	

	if (pgensock_description)
	{
		
		char msg[256];

		(*pgensock_description) (NNTPSock, msg, 255);
		if (*msg)
			SetConnectionText (NetDoc.hWndFrame, msg, &NetDoc, TRUE, TRUE);

		WVSetStatbarText (NetDoc.hWndFrame, CommState, &NetDoc, TRUE, TRUE);

	}


	return (0);
}

/* ---------------------------------------------------------------------------
 * open/close SMTP socket
 */

void abort_mail_socket ()
{
	/* in case we're _not_ connected to a NNTP server, and
	* we just used SMTP mail only, then we probably want to
	* close the library...
	*/
	//S.Yoshida	 "(PATCH) GenSock.DLL Unload error when processing RASAPI."
	SMTPSock = 0;
	if (!NNTPSock && gensock_lib && !NoChkConn) 
	{
		if (gensock_lib > (HINSTANCE)1)
			FreeLibrary (gensock_lib);
		gensock_lib = 0;
	}
}

int open_smtp_socket ()
{
	int retval;

	if (gensock_lib && SMTPSock)	// already open
		return 0;

	/* load the library if it's not loaded */
	if (!gensock_lib) 
	{
		if ((retval = load_gensock ())) 
		{
			return (retval);
		}
	}

	if ((retval = (*pgensock_connect) ((LPSTR) SMTPHost, (LPSTR) SMTPService,&SMTPSock, SMTPUseSSL, SMTPIP_Family))) 
	{
		if (retval == ERR_CANT_RESOLVE_SERVICE ||
			retval == ERR_NO_ERROR_CODE)  		/* Chameleon is bad, it fails but sets no error code. */
		{
			if ((retval = (*pgensock_connect) ((LPSTR) SMTPHost,
					(LPSTR) "25",
					&SMTPSock, SMTPUseSSL, SMTPIP_Family))) 
			{
				gensock_error ("gensock_connect", retval);
				abort_mail_socket ();
				return (-1);
			}
		}
		/* error other than can't resolve service */
		else 
		{
			gensock_error ("gensock_connect", retval);
			abort_mail_socket ();
			return (-1);
		}
	}

	/* we wait to do this until here because WINSOCK is
	* guaranteed to be already initialized at this point.
	*/

	/* get the local hostname (needed by SMTP) */
	if ((retval = (*pgensock_gethostname) (my_hostname, sizeof (my_hostname)))) 
	{
		/* This is failing very often, I hope no smtp server complains too loudly */
		strcpy (my_hostname, "idunnomyownname");
	}
	return 0;
}

int close_smtp_socket ()
{
	int retval = 0;

	if (SMTPSock) 
	{
		if ((retval = (*pgensock_close) (SMTPSock))) 
		{
			gensock_error ("gensock_close", retval);
		}
	}
	abort_mail_socket ();

	return (retval);
}

/* ---------------------------------------------------------------------------
 * internal SMTP functions
 */

int get_smtp_line (char *line /*=NULL*/, int* pLen /*=NULL*/)
{
	char ch = '.';
	char local_buf[MAXCOMMLINE];
	char *in_data = local_buf;
	char *index;
	int retval = 0;
	int nMax = MAXCOMMLINE;
	
	if (line && pLen)
	{
		in_data = line;
		nMax = *pLen;
	}

	index = in_data;

	while (ch != '\n' && (index - in_data) < nMax) 
	{   //Buffer overrun on some servers MDS 2000/01/25
		if ((retval = (*pgensock_getchar) (SMTPSock, 0, &ch))) 
		{
			gensock_error ("gensock_getchar", retval);
			return (-1);
		}
		else 
		{
			*index = ch;
			index++;
		}
	}
	if (line && pLen)  //we want single line
	{
		*pLen = index - in_data;
		*index = '\0';
		return atoi (in_data);
	}

	/* this is to support multi-line responses, common with */
	/* servers that speak ESMTP */

	/* I know, I know, it's a hack 8^) */
	if (in_data[3] == '-')
		return (get_smtp_line ());
	else
		return (atoi (in_data));
}

int put_smtp_line (socktag sock, char far * line, unsigned int nchars)
{
	int retval = -1;

	if (!sock || (retval = (*pgensock_put_data) (sock, line, (unsigned long) nchars))) 
	{
		gensock_error ("gensock_put_data", retval);
		return (-1);
	}
	return (0);
}

int finish_smtp_message ()
{
	int retval;

	if ((retval = (*pgensock_put_data_flush) (SMTPSock))) 
	{
		return (retval);
	}
	put_smtp_line (SMTPSock, "QUIT\r\n", 6);
	if ((retval = (*pgensock_put_data_flush) (SMTPSock)))
		return (retval);

	return (-1);
}

void smtp_error (char *message, HWND hWnd)
{
	if (!hWnd)
		hWnd = NetDoc.hDocWnd; 
	WVMessageBox (hWnd, message, "WinVN", MB_OK);
	put_smtp_line (SMTPSock, "QUIT\r\n", 6);
	close_smtp_socket ();
}

/* ---------------------------------------------------------------------------
 * The following are entry points
 * all return 0 on success or non-zero on fail
 */

int	end_post ()
{
	int retval;

	if ((retval = (*pgensock_put_data_buffered) (NNTPSock, ".\r\n", 3))) 
	{
		return (retval);
	}
	if ((retval = (*pgensock_put_data_flush) (NNTPSock))) 
	{
		return (retval);
	}
  // DEBUG_BREAK; // verify this as proper return value...
  return 0;
}

int end_send_smtp (HWND hWnd)
{
	int retval;

	if ((retval = (*pgensock_put_data_buffered) (SMTPSock, ".\r\n", 3))) 
	{
		return (retval);
	}

	if ((retval = (*pgensock_put_data_flush) (SMTPSock))) 
	{
		return (retval);
	}
	char strMsg[1024] = {0};
	int nLen = 1023, msgLen = 0;
	LoadString(hInst, IDS_ERR_SMTP_REJ, strMsg, nLen);
	msgLen = strlen(strMsg);
	nLen -= msgLen;
	retval = get_smtp_line (strMsg+msgLen, &nLen);
	if (retval != 250 && retval != 251) 
	{
		smtp_error (strMsg, hWnd);
		return -1;
	}

	finish_smtp_message ();
	close_smtp_socket ();

	return 0;
}


int	send_smtp_line (char *str, unsigned long len)
{
	int retval;

	if (*str == '.' &&			/* if line starts with dot, send two dots */
	  (retval = (*pgensock_put_data_buffered) (SMTPSock, str, 1))) 
	{
		return (retval);
	}
	return ((*pgensock_put_data_buffered) (SMTPSock, str, len));
}

int	post_line (char *str, unsigned long len)
{
	int retval;

	if (*str == '.' &&			/* if line starts with dot, send two dots */
	  (retval = (*pgensock_put_data_buffered) (NNTPSock, str, 1))) 
	{
		return (retval);
	}
	return ((*pgensock_put_data_buffered) (NNTPSock, str, len));
}

/* prepare_smtp_message
 * headers is a textblock containing the header lines for this mail
 * grab the From, To and any Cc from here to generate From: and RCPT:
 * SMTP commands
 */
int	prepare_smtp_message (TypTextBlock * headers, HWND hWnd)
{
	char out_data[MAXOUTLINE], address[MAXHEADERLINE], in_data[MAXCOMMLINE];;
	char *ptr, *line;
	int len, startLen, result;
	unsigned long i;
	bool bDoAuth = false;
	bool bStarttls = false;

	if (open_smtp_socket ())
		return (-1);

	if (get_smtp_line () != 220) 
	{
		smtp_error ("SMTP server error", hWnd);
		return (-1);
	}
//original HELO 
  /*
  sprintf (out_data, "HELO %s\r\n", my_hostname);
  put_smtp_line (SMTPSock, out_data, strlen (out_data));
  */

	// Changed to EHLO processing 27 Feb 2001 Craig Morrison
	sprintf( out_data, "EHLO %s\r\n", my_hostname);
	if ( 0 != put_smtp_line( SMTPSock, out_data, strlen (out_data) ) ) 
	{
		return(-1);
	}
	
	len = MAXCOMMLINE;
	if ( (result = get_smtp_line(in_data, &len )) != 250 ) 
	{
		sprintf( out_data, "HELO %s\r\n", my_hostname);

		// end of changes of EHLO
		if (get_smtp_line () != 250) 
		{
			smtp_error ("SMTP server error", hWnd);
			return (-1);
		}
	}
	else do
	{
		//look for possible AUTH
		if (!bDoAuth && !strnicmp(in_data+4, "AUTH", 4))
		{
			bDoAuth = stristr(in_data, "LOGIN") != NULL;
		}
		if (!bStarttls && stristr(in_data+4, "STARTTLS"))
			bStarttls = true;
		
		if (in_data[3] == '-')
		{
			len = MAXCOMMLINE;
			result = get_smtp_line(in_data, &len );
		}
		else
		{ 
			result = 0;
		}

	} while (result == 250 && in_data[3] == '-');

	if (bStarttls)
	{
		
		put_smtp_line (SMTPSock, "STARTTLS\r\n", 10);
		if (get_smtp_line () == 220) 
		{

		
			result = pgensock_starttls(SMTPSock);
			if (result)
			{
				smtp_error ("Error negotiating secure channel", hWnd);
				return (-1);

			}	
		}
		else
		{
			smtp_error ("Couldn't use STARTTLS command to begin secure transfer ", hWnd);
			return -1;

		}

		//login again after negotiating secure connection
		sprintf( out_data, "EHLO %s\r\n", my_hostname);
		if ( 0 != put_smtp_line( SMTPSock, out_data, strlen (out_data) ) ) 
		{
			return(-1);
		}
		
		len = MAXCOMMLINE;
		if ( (result = get_smtp_line(in_data, &len )) != 250 ) 
		{
			sprintf( out_data, "HELO %s\r\n", my_hostname);

			// end of changes of EHLO
			if (get_smtp_line () != 250) 
			{
				smtp_error ("SMTP server error", hWnd);
				return (-1);
			}
		}
		else do
		{
			//look for possible AUTH
			if (!bDoAuth && !strnicmp(in_data+4, "AUTH", 4))
			{
				bDoAuth = stristr(in_data, "LOGIN") != NULL;
			}
			
			if (in_data[3] == '-')
			{
				len = MAXCOMMLINE;
				result = get_smtp_line(in_data, &len );
			}
			else
			{ 
				result = 0;
			}

		} while (result == 250 && in_data[3] == '-');


	}

	if ( strlen (SMTPPasswordEncrypted) || strlen(SMTPUserName) )
	{
		if (!bDoAuth)
		{
			TRACE("mail server doesn't report being able to do authentication\r\n");
			bDoAuth = TRUE;
		}

	}

smtpdoauth:
	MRRDecrypt (SMTPPasswordEncrypted, (unsigned char *) address, MAXHEADERLINE);

	if (bDoAuth && strlen(SMTPUserName) && !strlen(address))
	{
		bDoAuth = FALSE;
		if ( (DialogBoxParam (hInst, MAKEINTRESOURCE(IDD_WINVNSMTP), hWnd, lpfnWinVnSMTPDlg, 1L) != IDOK) ||
			!strlen(SMTPPasswordEncrypted) )
		{
			smtp_error("Mail Canceled", hWnd);
			return -1;
		}
	}

	if (bDoAuth)
	{
		//send AUTH LOGIN
		//wait 334 (username)
		//send B64(username)
		//wait 334 (password)
		//send B64(password)
		//wait 235 successful
		//else report error	
		result = 0;



		int login_state = 0;
		char *pMsg = "";


		while(result == 0)
		{
			switch(login_state)
			{
				case 0:
					put_smtp_line (SMTPSock, "AUTH LOGIN\r\n", 12);
					if (get_smtp_line () != 334) 
					{
						pMsg = "Login authentication denied. Are you sure it is necessary?";
						result = -1;
					}
					else
					{
						login_state++;
					}
					break;
				case 1:
					len = Encode64( (unsigned char *)SMTPUserName, strlen(SMTPUserName), out_data, MAXOUTLINE);
					strcpy(out_data+len, "\r\n");
					put_smtp_line (SMTPSock, out_data, len+2);
					if (get_smtp_line () != 334) 
					{
						pMsg = "Login username denied";
						result = -1;
					}
					else
					{
						login_state++;
					}
					break;
					
				case 2:
					

					MRRDecrypt (SMTPPasswordEncrypted, (unsigned char *) address, MAXHEADERLINE);
					len = Encode64((unsigned char *) address, strlen(address), out_data, MAXOUTLINE);
					strcpy(out_data+len, "\r\n");
					put_smtp_line (SMTPSock, out_data, len+2);
					len = MAXCOMMLINE;
					result = get_smtp_line(in_data, &len );
					if (result != 235 ) 
					{
						strcpy(out_data, "Login failed:\r\n");
						strcat(out_data, in_data);
						pMsg = out_data;
						result = -1;
					}
					else
					{
						result = 1;
						login_state++;
					}
					break;
				default:
					pMsg = "unkown error in Authentication";
					result = -1;
					break;
			}
			if (result == -1)
			{
				smtp_error ( pMsg, hWnd);
				return -1;

			}

		}

		//we're authenticated


	}


	for (i = 0; i < headers->numLines; i++) 
	{
		line = TextBlockLine (headers, i);
		if (!_strnicmp (line, "from: ", 6))
			break;
	}
	if (i < headers->numLines)
		ParseAddress (&line[6], address, MAXHEADERLINE, str, MAXINTERNALLINE);
	else
		strcpy (address, MailAddress);

	ptr = &address[strlen (address) - 1];
	while (isspace ((unsigned char)*ptr))
		*ptr-- = '\0';				/* strip trailing space */
	sprintf (out_data, "MAIL From:<%s>\r\n", address);
	put_smtp_line (SMTPSock, out_data, strlen (out_data));

	result = get_smtp_line ();
	if (result == 530)
	{
		if (!bDoAuth)
		{
			bDoAuth = true;
			goto smtpdoauth;
		}
		else
		{
			smtp_error ("The mail server doesn't like the login name", hWnd);
			return (-1);

		}

	}

	if ( result != 250) 
	{
		smtp_error ("The mail server doesn't like the sender name, "
		"have you set your mail address correctly?", hWnd);
		return (-1);
	}

	/* do a series of RCPT lines for all To: addresses and Cc: address */
	for (i = 0; i < headers->numLines; i++) 
	{
		line = TextBlockLine (headers, i);

		if (!_strnicmp (line, "to: ", 4) || !_strnicmp (line, "cc: ", 4)) 
		{
			ptr = strcpy (address, &line[4]);
			while (*ptr) 
			{
				// if there's only one token left, then len will = startLen,
				// and we'll iterate once only
				startLen = strlen (ptr);
				if ((len = strcspn (ptr, " ,\n\t\r")) != startLen) 
				{
					ptr[len++] = '\0';	// replace delim with NULL char

					while (isspace ((unsigned char)ptr[len]) || ptr[len] == ',')		// eat white space
						ptr[len++] = '\0';
				}

				sprintf (out_data, "RCPT To: <%s>\r\n", ptr);
				putline_internal (SMTPSock, out_data, strlen (out_data));

				result = get_smtp_line ();
				if (result != 250 && result != 251) 
				{
					sprintf (str, "The mail server doesn't like the name %s.  "
					"Have you set the 'To: ' field correctly?", ptr);
					smtp_error (str, hWnd);
					return (-1);
				}

				if (len == startLen)	// last token, we're done
					break;

				ptr += len;
			}							/* RCPT loop */
		}							/* if To: or Cc: */
	}								/* for header lines */

	sprintf (out_data, "DATA\r\n");
	put_smtp_line (SMTPSock, out_data, strlen (out_data));

	if (get_smtp_line () != 354) 
	{
		smtp_error ("Mail server error accepting message data", hWnd);
		return (-1);
	}

	return (0);

}

/* prepare_cc_smtp_message
 * destination is the address(es) to forward to
 * headers is a textblock containing the header lines for mail to be forwarded
 */
int prepare_cc_smtp_message (char *destination, TypTextBlock * headers)
{
	register unsigned long i;
	char toLine[MAXOUTLINE];
	char DateLine[MAXHEADERLINE];
	char contents[MAXHEADERLINE];
	char  *fromLine;
	TypTextBlock *tempHeader;
	int retval;

	/* create temporary header block containing only a To: and a From: 
	* to make prepare_smtp_message happy
	*/
	if ((tempHeader = InitTextBlock (NetDoc.hDocWnd)) == NULL)
		return 1;
	_snprintf (toLine, MAXOUTLINE, "To: %s\r\n", destination);
	retval = AddLineToTextBlock (tempHeader, toLine);

	if (!retval) 
	{
		/* copy From: line from real headers */
		for (i = 0; i < headers->numLines; i++) 
		{
			fromLine = TextBlockLine (headers, i);
			if (!_strnicmp (TextBlockLine (headers, i), "from: ", 6))
				break;
		}
		if (i < headers->numLines) 
		{
			retval = AddLineToTextBlock (tempHeader, fromLine);
		}
	}
	if ( (!retval)  && GetDate (contents, MAXHEADERLINE)) 
	{
		_snprintf (DateLine, MAXHEADERLINE, "Date: %s\r\n", contents);
		retval = AddLineToTextBlock (tempHeader, DateLine);//Heirich 19960729 
		/* adding is not needed yet, but keep headerblocks current for defensive 
		programming */
	}
	retval = retval ||
		prepare_smtp_message (tempHeader) ||
		put_smtp_line (SMTPSock, toLine, lstrlen (toLine)) ||
		put_smtp_line (SMTPSock, DateLine, lstrlen (DateLine));

	FreeTextBlock (tempHeader);
	return (retval);
}

