using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using IndianHealthService.BMXNet.WinForm.Forms; using IndianHealthService.BMXNet.Net; using IndianHealthService.BMXNet.WinForm.Configuration; using System.Security.Cryptography; using System.Security.Permissions; using System.Security.Principal; using System.Net.Sockets; using System.Net; using System.Threading; namespace IndianHealthService.BMXNet.WinForm.Forms { public partial class VerifyCodeUpdateDialog : Form { /// /// Private variable that takes framework as parameter /// private WinFramework _framework = null; /// /// Login process, not sure if this is needed /// private LoginProcess mylogin; private RpmsConnectionSpec _connectionSpec = null; /// /// The active ConnectionSpec being used to login. With care, the property can be changed or the instance can be modified during the AttemptingLogin and LoginAttempted events /// with care. /// public RpmsConnectionSpec ConnectionSpec { get { return _connectionSpec; } set { _connectionSpec = value; } } private string _accessCode; internal protected WinFramework Framework { get { return _framework; } set { _framework = value; } } private bool isUpdateSuccessful; public VerifyCodeUpdateDialog(WinFramework framework, RpmsConnectionSpec connspec, string accesscode) { this.Framework = framework; this._accessCode = accesscode; this.ConnectionSpec = connspec; mylogin = new LoginProcess(framework); InitializeComponent(); } private bool _isSwitchServerModeEnabled = false; public bool IsSwitchServerModeEnabled { get { return _isSwitchServerModeEnabled; } set { _isSwitchServerModeEnabled = value; } } private void VerifyCodeUpdateDialog_Load(object sender, EventArgs e) { this.currentVerifyCodeEntry.Focus(); } public void ShowView(IWin32Window anOwner) { this.ShowDialog(anOwner); } public VerifyCodeUpdateResult ShowVerifyChangeDialog(IWin32Window anOwner) { DialogResult dr = new DialogResult(); if (anOwner != null) { dr = this.ShowDialog(anOwner); } else { dr = this.ShowDialog(); } VerifyCodeUpdateResult vr = new VerifyCodeUpdateResult(); vr.DialogResult = dr; vr.WasVerifyCodeUpdatedSuccessfully = this.IsUpdateSuccessful; return vr; } public IWin32Window UiOwner { get { return this.Owner; } } #region RpmsLoginView Members public string Title { set { this.Text = value; } } public bool IsUpdateSuccessful { set { this.isUpdateSuccessful = value; } get { return this.isUpdateSuccessful; } } public string CurrentVerifyCode { get { return this.currentVerifyCodeEntry.Text; } } public string AccessCode { set { this._accessCode = value; } get { return this._accessCode; } } private string _updateMessage; public string UpdateMessage { set { this._updateMessage = value; } get { return this._updateMessage; } } public string NewVerifyCode { get { return this.NewVerifyCodeEntry.Text; } } public string RepeatNewVerifyCode { get { return this.RepeatVerifyCodeEntry.Text; } } public event EventHandler Ok; public event EventHandler Cancel; #endregion public void CloseView() { this.Close(); } private void okButton_Click(object sender, EventArgs e) { //make sure all fields were filled with values if ((this.currentVerifyCodeEntry.Text.Length == 0) || (this.NewVerifyCodeEntry.Text.Length == 0) || (this.RepeatVerifyCodeEntry.Text.Length == 0) ) { string message = "Please fill all blank fields"; string caption = "Verify Code Update"; MessageBoxButtons buttons = MessageBoxButtons.OK; DialogResult result; // Displays the MessageBox. result = MessageBox.Show(message, caption, buttons); } else if (this.currentVerifyCodeEntry.Text.Contains("^") || this.NewVerifyCodeEntry.Text.Contains("^") || this.RepeatVerifyCodeEntry.Text.Contains("^")) { string message = "The character '^' is not allowed in any of the verify code entry fields."; string caption = "Verify Code Update"; MessageBoxButtons buttons = MessageBoxButtons.OK; DialogResult result; //Display the MessageBox result = MessageBox.Show(message, caption, buttons); ResetVerifyCodeEntries(); } else if (this.NewVerifyCodeEntry.Text != this.RepeatVerifyCodeEntry.Text) { string message = "Please key in the same verify code twice."; string caption = "Verify Code Update"; MessageBoxButtons buttons = MessageBoxButtons.OK; DialogResult result; // Displays the MessageBox. result = MessageBox.Show(message, caption, buttons); } else { //get all the values and ready to udpate string currentVCode = this.currentVerifyCodeEntry.Text; string newVCode = this.NewVerifyCodeEntry.Text; string repeatVCode = this.RepeatVerifyCodeEntry.Text; this.IsUpdateSuccessful = SendSecurityRequest(EncryptAccessVerifyCode(this.AccessCode,currentVCode,newVCode)); if (!this.IsUpdateSuccessful) { ResetVerifyCodeEntries(); } } } private void cancelButton_Click(object sender, EventArgs e) { if (this.Cancel != null) { this.Cancel(this, new EventArgs()); } } public void ResetVerifyCodeEntries() { this.currentVerifyCodeEntry.Clear(); this.RepeatVerifyCodeEntry.Clear(); this.NewVerifyCodeEntry.Clear(); this.currentVerifyCodeEntry.Select(); } public void ShowWait() { this.Cursor = Cursors.WaitCursor; } public void HideWait() { this.Cursor = Cursors.Default; } public String EncryptAccessVerifyCode(string anAccessCode, string aCurrentVerifyCode, string aNewVerifyCode) { BMXNetBroker broker = this.Framework.SocketBroker; string accessVerifyPair = anAccessCode.ToUpper() + ";" + aNewVerifyCode.ToUpper() + ";" + aCurrentVerifyCode.ToUpper(); return broker.EncryptionProvider.Encrypt(accessVerifyPair); } private bool SendSecurityRequest(string encryptedAccessVerifyCode) { BMXNetSocketBroker broker = (BMXNetSocketBroker)this.Framework.SocketBroker; string strReceive = ""; string cMSG; string m_sWKID = "BMX"; string m_sWINH = ""; string m_sPRCH = ""; string m_sWISH = ""; string m_cHDR = broker.ADEBHDR(m_sWKID,m_sWINH,m_sPRCH,m_sWISH); //open a TCP sockry TcpClient mySocket = this.OpenConnectionCommon(); cMSG = broker.ADEBLDMsg(m_cHDR, "BMX CVC", encryptedAccessVerifyCode); SendString(mySocket, cMSG, ""); strReceive = ReceiveString(mySocket); //"2VERIFY CODE must be a mix of alpha and numerics." //"3This code is the same as the current one." //"4This has been used previously as the VERIFY CODE." //"5VERIFY CODE must be different than the ACCESS CODE." List rspMessages = new List(); // List of received messages rspMessages.Add("Sorry that isn't the correct current code"); rspMessages.Add("Enter 8-20 characters mixed alphanumeric and punctuation (except '^', ';', ':')."); rspMessages.Add("VERIFY CODE must be a mix of alpha and numerics and punctuation."); // String element 2 rspMessages.Add("This code is the same as the current one."); // 3 rspMessages.Add("This has been used previously as the VERIFY CODE."); // 4 rspMessages.Add("VERIFY CODE must be different than the ACCESS CODE."); // 5 if (strReceive.StartsWith("M ERROR=")) { string caption = "Verify Code Update"; MessageBoxButtons buttons = MessageBoxButtons.OK; DialogResult result; // Displays the MessageBox. result = MessageBox.Show(strReceive, caption, buttons); return false; } else { foreach (string errorMsg in rspMessages) { if (strReceive.Contains(errorMsg)) { this.UpdateMessage = errorMsg; string caption = "Verify Code Update"; MessageBoxButtons buttons = MessageBoxButtons.OK; DialogResult result; // Displays the MessageBox. result = MessageBox.Show(errorMsg, caption, buttons); return false; } } //if the code runs here, it means the update is successful if (strReceive.Contains("0")) { string message = "Verify code has been successfully updated. "; MessageBoxButtons msgButtons = MessageBoxButtons.OK; // Displays the MessageBox. MessageBox.Show(message, "Verify Code Update", msgButtons); return true; } else { this.UpdateMessage = strReceive; string caption = "Verify Code Update"; MessageBoxButtons buttons = MessageBoxButtons.OK; DialogResult result; // Displays the MessageBox. result = MessageBox.Show(strReceive, caption, buttons); return false; } } } protected void SendString(TcpClient tcpClient, string cSendString, string cMult) { String encodedString = this.EncodeSendString(cSendString, cMult); NetworkStream ns = tcpClient.GetStream(); ns.WriteTimeout = 20000; byte[] sendBytes = Encoding.ASCII.GetBytes(encodedString); ns.Write(sendBytes,0,sendBytes.Length); return; } protected string EncodeSendString(String cSendString, String cMulti) { String encoded = null; int nLen = cSendString.Length; string sLen = nLen.ToString(); sLen = sLen.PadLeft(5, '0'); encoded = sLen + cSendString; nLen += 15; sLen = nLen.ToString(); sLen = sLen.PadLeft(5, '0'); encoded = "{BMX}" + sLen + encoded; encoded = encoded + cMulti; return encoded; } private string ReceiveString(TcpClient tcpClient) { NetworkStream ns = tcpClient.GetStream(); ns.ReadTimeout = 40000; //TAE: This following is suspect. NetworkSTream Read and ReadTimeout provide //the same behavior. Look at removing in the futuer. For now, this works. int cyclePause = 25; int cycles = 0; DateTime start = DateTime.Now; while (ns.DataAvailable == false) { if (cycles++ > 999) break; if ((DateTime.Now-start).TotalMilliseconds > 40000) break; Thread.Sleep(cyclePause); } if (!ns.DataAvailable) { this.Close(); throw new Exception("BMXNetBroker.ReceiveString timeout. Connection Closed."); } byte[] bReadBuffer = new byte[1024]; string sReadBuffer = ""; StringBuilder sbAll = new StringBuilder("", 1024); int numberOfBytesRead = 0; // Incoming message may be larger than the buffer size. bool bFinished = false; bool bStarted = false; int lpBuf = 0; string sError = ""; string sAppError = ""; do { numberOfBytesRead = ns.Read(bReadBuffer, 0, bReadBuffer.Length); if ((numberOfBytesRead == 1)&&(bStarted == false)) { //TAE: This following is suspect. If Read is blocking then this sleep is extra. //This is rarely called Thread.Sleep(15); numberOfBytesRead += ns.Read(bReadBuffer,1, bReadBuffer.Length-1); } if (bStarted == false) { //Process error info at beginning of returned string int nErrLen = bReadBuffer[0]; int nAppLen = bReadBuffer[bReadBuffer[0]+1]; if ((bReadBuffer[2] == 0)&&(bReadBuffer[3] == 0)) { //special case: M error trap invoked in SND^XWBTCPC lpBuf += 2; } sError = Encoding.ASCII.GetString(bReadBuffer, lpBuf + 1, nErrLen); if (sError != "") { sAppError = Encoding.ASCII.GetString(bReadBuffer, lpBuf + 1 + nErrLen + 1, nAppLen); throw new BMXNetException(sError); } sAppError = Encoding.ASCII.GetString(bReadBuffer, lpBuf+1+nErrLen+1, nAppLen); lpBuf += (nErrLen + nAppLen + 2); numberOfBytesRead -= (nErrLen + nAppLen + 2); bStarted = true; } bFinished = FindChar(bReadBuffer, (char)4) > -1; sReadBuffer = Encoding.ASCII.GetString(bReadBuffer, lpBuf, numberOfBytesRead); lpBuf = 0; if (bFinished) { sbAll.Append(sReadBuffer, 0, numberOfBytesRead -1); } else { sbAll.Append(sReadBuffer); } } while(!bFinished); String decodedReceiveString = sbAll.ToString(); return decodedReceiveString; } public static int FindChar(byte[] c, char y) { int n = 0; int nRet = -1; for (n = 0; n < c.Length; n++) { if (y == (char)c[n]) { nRet = n; break; } } return nRet; } public static int FindChar(string s, char y) { int n = 0; int nRet = -1; foreach (char c in s) { if (y == c) { nRet = n; break; } n++; } return nRet; } protected TcpClient OpenConnectionCommon() { try { TcpClient connector = null; try { BMXNetSocketBroker broker = (BMXNetSocketBroker)this.Framework.SocketBroker; BMXNetSocketConnectionSpec ConnectionSpec = broker.ConnectionSpec; connector = new TcpClient(); connector.SendTimeout = ConnectionSpec.SendTimeout; connector.ReceiveTimeout = ConnectionSpec.ReceiveTimeout; connector.Connect(ConnectionSpec.Server, ConnectionSpec.Port); } catch (SocketException exSocket) { string s = exSocket.Message + exSocket.StackTrace; throw new BMXNetException(s); } //Prepare & send the connect message string cSend = "TCPconnect^" + "" + "^^"; int nLen = cSend.Length; string sLen = nLen.ToString(); sLen = sLen.PadLeft(5, '0'); cSend = "{BMX}" + sLen + cSend; NetworkStream ns = connector.GetStream(); byte[] sendBytes = Encoding.ASCII.GetBytes(cSend); ns.Write(sendBytes,0,sendBytes.Length); return connector; } catch (BMXNetException bmxEx) { throw bmxEx; } catch (Exception ex) { string s = ex.Message + ex.StackTrace; throw new BMXNetException(s); } }//End OpenConnectionCommon } /// /// Class for passing result of AttemptChangeVerifyCode to calling routine /// public class VerifyCodeUpdateResult { //Members private DialogResult dr = new DialogResult(); private bool bVerifyCodeWasSucessfullyChanged; //Properties public DialogResult DialogResult { set { this.dr = value; } get { return this.dr; } } public bool WasVerifyCodeUpdatedSuccessfully { set { this.bVerifyCodeWasSucessfullyChanged = value; } get { return this.bVerifyCodeWasSucessfullyChanged; } } } }