#include "stdafx.h"
#include "ksign.h"
                         
#ifdef VERSERV
extern "C" {
#include<vs.h>
}
#include "getver.h"
#endif // VERSERV                         
                         
CKsignApp NEAR theApp;   

/* this is the unofficial, wrong OID */
static gss_OID_desc ksign_krb5_old_mech_oid =  {5, "\053\005\001\005\002"};


void Upgrade(States *current)
{
	*current = (States) ((int) *current + 1);
	switch (*current)
	{
		case UNINITIALIZED : TRACE("state now UNITIALIZED\n"); break;
		case ORDERAUTHSPOOLING : TRACE("state now ORDERAUTHSPOOLING\n"); break;
		case ORDERAUTHCOMPLETE : TRACE("state now ORDERAUTHCOMPLETE\n"); break;
		case ORDERREQUESTED : TRACE("state now ORDERREQUESTED\n"); break;
		case ORDERSPOOLING : TRACE("state now ORDERSPOOLING\n"); break;
		case WAITONUSER : TRACE("state now WAITONUSER\n"); break;
		case SIGNAUTHSPOOLING : TRACE("state now SIGNAUTHSPOOLING\n"); break;
		case SIGNAUTHCOMPLETE : TRACE("state now SIGNAUTHCOMPLETE\n"); break;
		case SIGNPRESSED : TRACE("state now SIGNPRESSED\n"); break;
		case SIGNREQUESTED : TRACE("state now SIGNREQUESTED\n"); break;
		case SIGNSPOOLING : TRACE("state now SIGNSPOOLING\n"); break;
		case SIGNDONE : TRACE("state now SIGNDONE\n"); break;
	}
}	
		 
BOOL CKsignApp::InitInstance()
{
	m_dialog.DoModal(); // returns when Exit button clicked
	return FALSE;
}
				
/////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CKsignDialog, CDialog)
	//{{AFX_MSG_MAP(CKsignDialog)
	ON_WM_CREATE()
	// should we have create send a message at the end which would trigger other
	// initialization?
	// ON_MESSAGE( WM_USER_START_WS, OnStartWsInit)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_ABOUT, OnAbout)
	ON_BN_CLICKED(IDC_SIGN, OnCompute)
	ON_BN_CLICKED(IDC_CANCEL, OnCancel)
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_USER_STREAM, OnStream)    
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////
CKsignDialog::CKsignDialog() : CDialog(CKsignDialog::IDD)
{
	//{{AFX_DATA_INIT(CKsignDialog)
	m_strText = "";
	//}}AFX_DATA_INIT
}

/////////////////////////////////////////////////////////////////////////
void CKsignDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CKsignDialog)
	DDX_Control(pDX, IDC_EDIT4, m_ctrlEdit);
	DDX_Text(pDX, IDC_EDIT4, m_strText);
	//}}AFX_DATA_MAP
}

/////////////////////////////////////////////////////////////////////////
void CKsignDialog::OnCompute()
{
	if (m_nState != WAITONUSER)
		MessageBox("You must wait until seeing the order.", "Ksign", MB_OK );
	else
	{     
		if (m_pStream == NULL);
		{
			// create stream AGAIN
			m_pStream = new CStreamSocket(this, WM_USER_STREAM);
			if (m_pStream->CreateSocket() != CWINSOCK_NOERROR)
			{
				TRACE("stream creation failed\n");   
				TRACE("last error %d\n", m_pStream->LastError());
				delete m_pStream;
				m_pStream = NULL;
				return;
			}               
			TRACE("stream created AGAIN\n");
		}       
			
		TRACE("about to connect to %s at port %ld\n",m_szHostname, m_nPort);                                                               
		if (m_pStream->Connect(m_szHostname, (int) m_nPort) != CWINSOCK_NOERROR)
		{
			TRACE("stream connect failed\n");
			delete m_pStream;
			m_pStream = NULL;
			return;
		}
		TRACE("stream connect succeeded\n");
	}               
}

int CKsignDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	CRect dlgRect;
	int screenWidth, screenHeight;
	int x, y;
	int CheckRet;

	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;

	// Centers the dialog on the screen
	this->GetWindowRect(&dlgRect);
	screenWidth = GetSystemMetrics( SM_CXSCREEN );
	screenHeight = GetSystemMetrics( SM_CYSCREEN );
	x = (screenWidth - dlgRect.Width()) / 2;
	y = (screenHeight - dlgRect.Height()) / 2;
	this->SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
	
	m_nState = UNINITIALIZED; // initial state

	                                               
	// read in file info
	TRACE("in dialog create, filename is %s\n", theApp.m_lpCmdLine);
	
	#ifdef VERSERV
	// Use the version server to give us some control on distribution and usage
	// We're going to test track as well
	TRACE("starting in the version server section of OnCreate");
	
	{                
	
		VS_Request vrequest;
		VS_Status  vstatus;
		BOOL ok_to_continue; 
		char vstr[24];
		char inifilename[64];
		char exefilename[64];
		char vAppName[24];

		// #define APP_TITLE "KSign"
		// #define APP_VER "1.0"
		// #define KSIGN_INI "ksign.ini"

		CWinApp* App  = AfxGetApp();

		strcpy(inifilename, App->m_pszProfileName);
		strcpy(exefilename, App->m_pszExeName);
		// strcat(exefilename, ".EXE");

		// HWND hWnd	     = App->m_pMainWnd->m_hWnd;

		GetVerName(vstr, vAppName);

		if(vAppName != NULL){
			strcpy(exefilename, vAppName);
		}

		
		SetCursor(LoadCursor(NULL, IDC_WAIT));

		vrequest = VSFormRequest(  vAppName , // APP_TITLE,
					   vstr ,	 // APP_VER,
					   inifilename,  // KSIGN_INI,
					   NULL,
					   NULL,
					   V_CHECK_AND_LOG );

		SetCursor(LoadCursor(NULL, IDC_ARROW));						                      
								                      
		if( (ok_to_continue = ( ReqStatus(vrequest) != V_E_CANCEL ) ) &&
		     v_complain( (vstatus = VSProcessRequest(vrequest) ), inifilename ) ){
		                  
		                  WinVSReportRequest( vrequest,
		                  					  NULL,
		                  					  "Version Server Status Report");
		                  					  
		}                 					  
		

		if( ok_to_continue && vstatus  == V_REQUIRED ){
		
			ok_to_continue = FALSE;
			TRACE( "The version server is reporting that the application MUST be updated before being used." );
			SetCursor(LoadCursor(NULL, IDC_WAIT));
			VSDestroyRequest(vrequest);
			return( -1 );
			
		}
		VSDestroyRequest(vrequest);
        
    }   
    #endif // VERSERV
    
	TRY
	{
		m_pInput = new CFile(theApp.m_lpCmdLine, CFile::modeRead );
	}
	CATCH( CFileException, e )
	{
		delete m_pInput;
		TRACE("difficulty in finding file\n");
		MessageBox("Your WWW browser appears to be misconfigured.","Ksign", 
			MB_OK | MB_ICONSTOP);
		OnConfig();	
		return -1;
	}
	END_CATCH
    
	ASSERT(m_pInput != NULL);
	if (m_pInput->Read(m_szReceiveBuffer, (RCVBUFFERLEN-1)) > 0)
	{
		TRACE("we have read the file successfully\n");
		m_pInput->Close(); // reset file stuff immediately
		delete m_pInput;
		m_pInput = NULL;
		    
		if (sscanf(m_szReceiveBuffer,"%s %ld %s %[^\t] %s",
			m_szHostname, &m_nPort, m_szServiceNo, m_szSecurity, m_szOrderNo) == 4)
			TRACE("we have 4 params <%s> <%ld> <%s> <%s>\n", m_szHostname, m_nPort, 
				m_szServiceNo, m_szOrderNo);
		else
			TRACE("no matchup on the params line\n");
	}
	else
	{
		TRACE("could not read file for some reason\n");
		MessageBox("Your WWW browser appears to be misconfigured.","Ksign", 
			MB_OK | MB_ICONSTOP);
		return -1;
	}       
	    
/*

	// startup winsock stuff     
	m_pWinSock = NULL;
	m_pStream = NULL;
		
	m_pWinSock = new CWinSock;
	if (m_pWinSock->Startup() != CWINSOCK_NOERROR)
	{
		TRACE("winsock error %ld\n", (long) m_pWinSock->LastError());
		delete m_pWinSock;
		m_pWinSock = NULL;
		   
		return -1;
	}    
	TRACE("yes!  winsock object launched!\n");

	// create stream
	m_pStream = new CStreamSocket(this, WM_USER_STREAM);
	if (m_pStream->CreateSocket() != CWINSOCK_NOERROR)
	{
		TRACE("stream creation failed\n");   
		TRACE("last error %d\n", m_pStream->LastError());
		delete m_pStream;
		m_pStream = NULL;
		return -1;
	}               
	TRACE("stream created\n");
									       
	TRACE("about to connect to %s at port %ld\n",m_szHostname, m_nPort);
	CheckRet = m_pStream->Connect(m_szHostname, (int) m_nPort);
	if ( CheckRet != CWINSOCK_NOERROR)
	{
		TRACE("stream connect failed\n");

		{
		    char testbuf[256];
		    wsprintf( testbuf, "Connect returned %d, the arguments were \n m_szHostname = %s, \n m_nPort = %d ",
					CheckRet, m_szHostname, m_nPort );

		    MessageBox( testbuf, "Ksign", MB_OK );

		}
		MessageBox("The vendor's transaction daemon \n"
			   "does not appear to be available.\n"
			   "Call for service. This application will terminate." , "Ksign", MB_OK );

		delete m_pStream;
		m_pStream = NULL;

		return -1;
	}
	TRACE("stream connected\n");

*/ 
	// PostMessage( WM_USER_START_WS, 0, 0);		
	OnStartWsInit();
	return 0;
}


int CKsignDialog::OnStartWsInit(){

	int CheckRet;


	// MessageBox( "In OnStartWsInit()", MB_OK );


	// startup winsock stuff     
	m_pWinSock = NULL;
	m_pStream = NULL;
		
	m_pWinSock = new CWinSock;
	if (m_pWinSock->Startup() != CWINSOCK_NOERROR)
	{
		TRACE("winsock error %ld\n", (long) m_pWinSock->LastError());
		delete m_pWinSock;
		m_pWinSock = NULL;
		   
		return -1;
	}    
	TRACE("yes!  winsock object launched!\n");

	// create stream
	m_pStream = new CStreamSocket(this, WM_USER_STREAM);
	if (m_pStream->CreateSocket() != CWINSOCK_NOERROR)
	{
		TRACE("stream creation failed\n");   
		TRACE("last error %d\n", m_pStream->LastError());
		delete m_pStream;
		m_pStream = NULL;
		return -1;
	}               
	TRACE("stream created\n");
									       
	TRACE("about to connect to %s at port %ld\n",m_szHostname, m_nPort);
	CheckRet = m_pStream->Connect(m_szHostname, (int) m_nPort);
	if ( CheckRet != CWINSOCK_NOERROR)
	{
		TRACE("stream connect failed\n");

		{
		    char testbuf[256];
		    wsprintf( testbuf, "Connect returned %d, the arguments were \n m_szHostname = %s, \n m_nPort = %d ",
					CheckRet, m_szHostname, m_nPort );

		    MessageBox( testbuf, "Ksign", MB_OK );

		}
		MessageBox("The vendor's transaction daemon \n"
			   "does not appear to be available.\n"
			   "Call for service. This application will terminate." , "Ksign", MB_OK );

		delete m_pStream;
		m_pStream = NULL;

		return -1;
	}
	TRACE("stream connected\n");

	return(0);

}

void CKsignDialog::OnDestroy()
{
	CDialog::OnDestroy();
	      
	TRACE("closing stuff down in OnDestroy()\n");      
	// shut down any stray socket stuff
	if (m_pStream)
	{
		m_pStream->DestroySocket();
		delete m_pStream;
		m_pStream = NULL;
	}       
			 
	if (m_pWinSock)
	{
		m_pWinSock->Shutdown(); 
		delete m_pWinSock;
		m_pWinSock = NULL;
	}             
}

LONG CKsignDialog::OnStream(WPARAM wParam, LPARAM lParam)
{
	LPCSTR pDataRead; // pointer to incoming message
	int nLen; // length of incoming message
	static UINT nSummaryLen; // how big the entire message is
	static gss_buffer_desc readbuffer;
	gss_OID secoid;



	TRACE("OnStream: ");
	
	switch (wParam)
	{
      case CWINSOCK_YOU_ARE_CONNECTED:
         TRACE("we're connected\n");
         // our entry could be UNITIALIZED or WAITONUSER
		    
			// Kerberos initialization
			send_tok.value = m_szServiceNo;
			send_tok.length = strlen(m_szServiceNo) + 1;

			maj_stat = gss_import_name(&min_stat, &send_tok, 
				(gss_OID) &ksign_nt_service_name, &target_name);
			if (maj_stat != GSS_S_COMPLETE)
			{
				TRACE("error number %d parsing gss_import_name()\n",maj_stat);
				MessageBox("Unable to verify tickets.\nCannot get import name","Ksign", MB_OK | MB_ICONEXCLAMATION);
				EndDialog(0);

				return -1;
			}
			TRACE("gss_import_name() succeeded\n");
	   
	 		token_ptr = GSS_C_NO_BUFFER; // "default behavior is requested" ?
			context = GSS_C_NO_CONTEXT; // for first call only      

			
			// Waiting on library to have the gss_str_to_oid() function 

			
			send_tok.value = m_szSecurity;
			send_tok.length = strlen(m_szSecurity) + 1;
			maj_stat = gss_str_to_oid(&min_stat, &send_tok, &secoid);
			if (maj_stat != GSS_S_COMPLETE)
			{
				TRACE("gss_str_to_oid() failed\n");
				return -1;          // TODO notify user
			}
			TRACE("gss_str_to_oid() succeeded\n");


	   
			maj_stat = gss_init_sec_context(&min_stat,
			   GSS_C_NO_CREDENTIAL, &context, target_name,
			   &ksign_krb5_old_mech_oid,
			   // GSS_C_NULL_OID,
			   GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
			   0, NULL, token_ptr, NULL, &send_tok, NULL, NULL);

			TRACE("gss_init_sec_context succeeded\n");
			

			if (token_ptr != GSS_C_NO_BUFFER)
				gss_release_buffer(&ignore, &recv_tok);
			if ((maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) 
				|| (context == GSS_C_NO_CONTEXT))
			{
				TRACE("could not establish context\n");   
				// some debugging information
				display_status( "gss_init_sec_context",
								maj_stat,
								min_stat );

				MessageBox("Unable to establish Kerberos context.\nYou may not be authenticated.\n\nCannot continue: exiting Ksign.","Ksign", MB_OK | MB_ICONEXCLAMATION);
				// EndDialog(0);
				// return -1;
			}
			if (maj_stat == GSS_S_COMPLETE)
			{
				Upgrade(&m_nState); // to SPOOLING
				Upgrade(&m_nState); // to COMPLETE
				gss_release_name(&ignore, &target_name);
				ASSERT(send_tok.length == 0); // this should be the case
			}    	
			else // GSS_S_CONTINUE_NEEDED
			{
				Upgrade(&m_nState); // to SPOOLING
			}    	
			        
			if (send_tok.length > 0)            
			{            
				recv_tok.length = 0; //initialize before read
				nSummaryLen = 0;
				        	
				ASSERT(send_tok.length < TOKENBUFFERSIZE);
				rqst2.nLen = htonl(send_tok.length);
				memcpy((void *) rqst2.strMessage, send_tok.value, 
					send_tok.length);

			if (m_pStream->Write(sizeof(long) + send_tok.length, 
				&rqst2) != CWINSOCK_NOERROR)
			{
				TRACE("Error sending request\n");
				m_pStream->DestroySocket();
				delete m_pStream;
				m_pStream = NULL;
				gss_release_buffer(&ignore, &send_tok);
				gss_release_name(&ignore, &target_name);
				MessageBox("Unable to send information.\nNetwork problems?","Ksign", MB_OK | MB_ICONEXCLAMATION);
				EndDialog(0);
				return -1;
			}
			TRACE("returned from WINSOCK_CONNECTED write()\n");
		}
			
		break;               

		case CWINSOCK_DONE_WRITING:
			nSummaryLen = 0;

		    TRACE("done writing\n");
			if (readbuffer.length != 0)
				gss_release_buffer(&ignore, &readbuffer);
			if ((m_nState == SIGNAUTHCOMPLETE) || (m_nState == SIGNAUTHSPOOLING) || 
				(m_nState == ORDERAUTHCOMPLETE) || (m_nState == ORDERAUTHSPOOLING))	
				gss_release_buffer(&ignore, &send_tok);
			break;
					
		case CWINSOCK_ERROR_WRITING:  
			nSummaryLen = 0;
			TRACE("Last error %d\n",m_pStream->LastError());  
			CWinSockErrorBox(m_pStream->LastError());
			if ((m_nState == SIGNAUTHCOMPLETE) || (m_nState == SIGNAUTHSPOOLING) || 
				(m_nState == ORDERAUTHCOMPLETE) || (m_nState == ORDERAUTHSPOOLING))
			{
				gss_release_buffer(&ignore, &send_tok);
				gss_release_name(&ignore, &target_name);	
			}	
				  		
			MessageBox("Unable to send information.\nNetwork problems?","Ksign", MB_OK | MB_ICONEXCLAMATION);
			EndDialog(0);
			return -1;
			break;
					
		case CWINSOCK_DONE_READING:
			pDataRead = (LPCSTR)m_pStream->Read(&nLen);
			TRACE("WinSock read %u bytes\n",nLen);
			                       
			if (readbuffer.length == 0) // first (only?) packet
			{
				// storing total expected length
				readbuffer.length = ntohl(*(unsigned long *)pDataRead); 
				TRACE("We're expecting %d bytes, says the first packet.\n",
					readbuffer.length);
				nLen -= sizeof(long);
				nSummaryLen = nLen;
				TRACE("We've got %d bytes now.\n", nSummaryLen);
				if ((readbuffer.value = malloc(readbuffer.length)) == NULL)
					TRACE("error getting memory for readbuffer\n");;
				
				if (nLen > sizeof(long))
					memcpy(readbuffer.value,(char *)pDataRead + sizeof(long), nLen);
				free((void *)pDataRead);
			}	
			else // continuation
			{
				memcpy((char *)readbuffer.value + nSummaryLen, pDataRead, nLen); 
				nSummaryLen += nLen;
				free((void *)pDataRead);
			}
				
			if (nSummaryLen == readbuffer.length)
			switch (m_nState)
			{           
				case ORDERAUTHSPOOLING:
				case SIGNAUTHSPOOLING:
				case ORDERAUTHCOMPLETE:
				case SIGNAUTHCOMPLETE:
					ProcessToken(&readbuffer);
					break;
					
				case SIGNPRESSED:
				case SIGNREQUESTED:
				case SIGNSPOOLING:
					Upgrade(&m_nState);
					ProcessSignature(&readbuffer);
					break;
					
				case ORDERREQUESTED:
				case ORDERSPOOLING:
					Upgrade(&m_nState);
					ProcessOrder(&readbuffer);
					gss_release_buffer(&ignore, &readbuffer);
					break;
			}
			break;
		
		case CWINSOCK_ERROR_READING:
			MessageBox("Error reading information.\nNetwork problems?","Ksign", MB_OK | MB_ICONEXCLAMATION);
			EndDialog(0);
			return -1;
			TRACE("error reading\n");
			break;
		
		case CWINSOCK_LOST_CONNECTION:
			TRACE("lost connection\n");
			m_pStream->DestroySocket();
			delete m_pStream;
			m_pStream = NULL;
			break;
		
		default:
			TRACE("different wParam message %d\n",(int) wParam);
			break;
	}       

	
	return 1;           
}

void CKsignDialog::OnAbout()
{
	CAboutDlg aboutDlg(this);
	TRACE("about box ready to be launched\n");
	aboutDlg.DoModal();
	TRACE("just came back from about box\n");
}     
   
void CKsignDialog::OnConfig()
{
	CConfigDlg configDlg(this);
	TRACE("config box ready to be launched\n");
	configDlg.DoModal();
	TRACE("just came back from config box\n");
}   
   
void CKsignDialog::OnCancel()
{
#ifndef _DEBUG
	if (MessageBox("Are you sure you want to cancel\nyour order authorization?",
		  "Ksign",MB_YESNO | MB_ICONQUESTION) == IDYES)
	{
		MessageBox("Your order authorization has been cancelled.\nPress OK to return to your current order form.",
			"Ksign",MB_OK);
		EndDialog(0);
	}
#else 
   EndDialog(0);
#endif   	
}



void CKsignDialog::ProcessToken(gss_buffer_desc *recv_tok)
{
	gss_buffer_desc cleartext, encrypted;

	// phase 1: "kick off another round of gss_init if necessary"
	if ((m_nState == ORDERAUTHSPOOLING) || (m_nState == SIGNAUTHSPOOLING))
	{
		maj_stat = gss_init_sec_context(&min_stat, 
	      GSS_C_NO_CREDENTIAL, &context, target_name,
		  &ksign_krb5_old_mech_oid,
	      // GSS_C_NULL_OID, 
		  GSS_C_MUTUAL_FLAG | 
	      GSS_C_REPLAY_FLAG, 0, NULL, recv_tok, NULL, 
	      &send_tok, NULL, NULL);

      if (recv_tok->length != 0)
			gss_release_buffer(&ignore, recv_tok);

		// if (recv_tok != GSS_C_NO_BUFFER)
		// 	return; // skipping the gss_release_buffer() 'cause not responsible
		if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
		{
		   TRACE("could not establish context\n");
  			MessageBox("Unable to use tickets.\nCheck your Kerberos status.","Ksign", MB_OK | MB_ICONEXCLAMATION);
			EndDialog(0);

			return;
		}
		if (maj_stat == GSS_S_COMPLETE)
		{
			Upgrade(&m_nState); // on to next state
			ASSERT(send_tok.length == 0); // this should be the case
			gss_release_name(&ignore, &target_name);
		}
				                    
		if (send_tok.length > 0)
		{
			ASSERT(send_tok.length < TOKENBUFFERSIZE);
			rqst2.nLen = htonl(send_tok.length);
			memcpy((void *)rqst2.strMessage, send_tok.value, send_tok.length);

			if (m_pStream->Write(sizeof(long) + send_tok.length, &rqst2) != 
				CWINSOCK_NOERROR)
			{
				TRACE("Error sending request\n");
				m_pStream->DestroySocket();
				delete m_pStream;
				m_pStream = NULL;
				gss_release_buffer(&ignore, &send_tok);
				gss_release_name(&ignore, &target_name);
				MessageBox("Unable to send ticket information.\nNetwork problems?","Ksign", MB_OK | MB_ICONEXCLAMATION);
				EndDialog(0);
			}

			return;
		}
	}	

	// phase 2: "if completed context, kick off order or signature"
	if ((m_nState == SIGNAUTHCOMPLETE) || (m_nState == ORDERAUTHCOMPLETE))
	{
		Upgrade(&m_nState);
					
		// construct request
		rqst.nType = (m_nState == ORDERREQUESTED) ? 
			htonl(1L) : htonl(2L); // get order text or sign
		strcpy(rqst.strMessage, m_szOrderNo);
									
		// kerberize outgoing write
		cleartext.length = lstrlen(rqst.strMessage) +1 + 
			sizeof(long); // used to be 2 * sizeof(long)
		cleartext.value = (char *)&rqst + sizeof(long); // used to not offset
					
		// if (encrypted.length > 0)
		// 	gss_release_buffer(&ignore, &encrypted);			
		maj_stat = gss_seal(&min_stat, context, 1,
			GSS_C_QOP_DEFAULT, &cleartext, &conf_state, 
			&encrypted);
			
		if (maj_stat != GSS_S_COMPLETE)	
		{
			TRACE("Error in sealing order request\n");
			MessageBox("Unable to decode encrypted information\nKerberos problem?","Ksign", MB_OK | MB_ICONEXCLAMATION);
			return;
		}
					                                       
		rqst2.nLen = htonl(encrypted.length);
		ASSERT(encrypted.length < TOKENBUFFERSIZE);
		memcpy((void *)rqst2.strMessage, (void *)encrypted.value, 
			encrypted.length);
	
		gss_release_buffer(&ignore, &encrypted);				
		if (m_pStream->Write(ntohl(rqst2.nLen) + sizeof(long),
			&rqst2) != CWINSOCK_NOERROR)
		{
			TRACE("Error sending request\n");
			m_pStream->DestroySocket();
			delete m_pStream;
			m_pStream = NULL;
			MessageBox("Unable to send ticket information.\nNetwork problems?","Ksign", MB_OK | MB_ICONEXCLAMATION);
			EndDialog(0);
		}
					
		return;
	}
}	





void CKsignDialog::ProcessSignature(gss_buffer_desc *encrypted)
{
	unsigned long len;
	LPCSTR ptr;
	CString m_strConfirmation;
	// CString m_strThanks = "\r\n\r\nPress OK to return to your current order form.";
	
	gss_buffer_desc cleartext;
	maj_stat = gss_unseal(&min_stat, context,
		encrypted, &cleartext, NULL, NULL);
	if (maj_stat != GSS_S_COMPLETE)
	{
		TRACE("unable to unseal received message\n");
		MessageBox("Unable to use ticket to receive information.\nKerberos problems?","Ksign", MB_OK | MB_ICONEXCLAMATION);
		EndDialog(0);

		return;
	}

   // okay, we've got the data to plug into the display

	ptr = (char *)cleartext.value + sizeof(long);
	len = cleartext.length - sizeof(long);
	perr = *(long *)cleartext.value;

	while (len > 0)
	{
		if (*ptr != '\r')
		{
			if (*ptr == '\n')
				m_strConfirmation += "\r\n";
			else
				m_strConfirmation += *ptr;
		}
		len--;
		ptr++;
	}

	// m_strConfirmation += m_strThanks; 
	// TODO: Press OK to return to your current order form.

	gss_release_buffer(&ignore, &cleartext);
	while (m_nState != SIGNDONE)
		Upgrade(&m_nState);
	MessageBox(m_strConfirmation, "Ksign", MB_OK );
	EndDialog(0);
}





void CKsignDialog::ProcessOrder(gss_buffer_desc *encrypted)
{
	unsigned long len;
	LPCSTR ptr;
	
	gss_buffer_desc cleartext;
	maj_stat = gss_unseal(&min_stat, context,
		encrypted, &cleartext, NULL, NULL);
	if ((maj_stat != GSS_S_COMPLETE) || 
		((encrypted->length > 0) && (cleartext.length == 0)))
	{
		TRACE("unable to unseal received message\n");
		return;
	}

   // okay, we've got the data to plug into the display
	ptr = (char *)cleartext.value + sizeof(long);
	len = (int)cleartext.length - sizeof(long);
	perr = *(long *)cleartext.value;

	UpdateData(TRUE);
	while (len > 0)
	{
		if (*ptr != '\r')
		{
			if (*ptr == '\n')
				m_strText += "\r\n";
			else 
				m_strText += *ptr;
		}
		len--;
		ptr++;
	}
	UpdateData(FALSE);

	gss_release_buffer(&ignore, &cleartext);
	while (m_nState != WAITONUSER)
		Upgrade(&m_nState);
}
  


/////////////////////////////////////////////////////////////////////////
// All the things necessary for the about box
/////////////////////////////////////////////////////////////////////////

CAboutDlg::CAboutDlg(CWnd* pParent) : CDialog(CAboutDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

int CAboutDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   CRect dlgRect;
   int screenWidth, screenHeight;
   int x, y;
   
   if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;
		
   GetWindowRect(&dlgRect);
   screenWidth = GetSystemMetrics( SM_CXSCREEN );
   screenHeight = GetSystemMetrics( SM_CYSCREEN );

   x = (screenWidth - dlgRect.Width()) / 2;
   y = (screenHeight - dlgRect.Height()) / 2;
   this->SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );	
   
   return 0;
}             

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}      


BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
		ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
        
/////////////////////////////////////////////////////////////////////////
// All the things necessary for the config box
/////////////////////////////////////////////////////////////////////////

CConfigDlg::CConfigDlg(CWnd* pParent) : CDialog(CConfigDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

int CConfigDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   CRect dlgRect;
   int screenWidth, screenHeight;
   int x, y;
   
   if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;
		
   GetWindowRect(&dlgRect);
   screenWidth = GetSystemMetrics( SM_CXSCREEN );
   screenHeight = GetSystemMetrics( SM_CYSCREEN );

   x = (screenWidth - dlgRect.Width()) / 2;
   y = (screenHeight - dlgRect.Height()) / 2;
   this->SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );	
   
   return 0;
}             
        
        
void CConfigDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}
     
BEGIN_MESSAGE_MAP(CConfigDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
		ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
