using System;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Security.Principal;
using System.Threading;
using System.Timers;
using IndianHealthService.BMXNet.Net;
using IndianHealthService.BMXNet.Services;
using IndianHealthService.BMXNet.Model;
using System.Windows.Forms;
namespace IndianHealthService.BMXNet
{
///
/// BMXNetSessionConnection implements low-level connectivity to RPMS databases.
///
[DnsPermission(SecurityAction.Assert, Unrestricted = true)]
internal abstract class BMXNetSessionConnection
{
public BMXNetSessionConnection(BMXNetBroker aBroker)
{
this.Broker = aBroker;
m_sWKID = "BMX";
m_sWINH = "";
m_sPRCH = "";
m_sWISH = "";
m_cHDR = ADEBHDR(m_sWKID, m_sWINH, m_sPRCH, m_sWISH);
}
protected BMXNetBroker _broker=null;
public BMXNetBroker Broker
{
get { return _broker; }
set { _broker=value;}
}
protected EncryptionProvider EncryptionProvider
{
get
{
return this.Broker.EncryptionProvider;
}
}
#region RPX Fields
private string m_sWKID;
private string m_sWISH;
private string m_sPRCH;
private string m_sWINH;
private string m_cHDR;
protected string m_cAppContext;
private string m_cDUZ;
#endregion RPX Fields
#region RPX Functions
///
/// Given strInput = "13" builds "013" if nLength = 3. Default for nLength is 3.
///
///
///
protected string ADEBLDPadString(string strInput)
{
return ADEBLDPadString(strInput, 3);
}
///
/// Given strInput = "13" builds "013" if nLength = 3 Default for nLength is 3.
///
///
/// Default = 3
///
protected string ADEBLDPadString(string strInput, int nLength /*=3*/)
{
return strInput.PadLeft(nLength, '0');
}
///
/// Concatenates zero-padded length of sInput to sInput
/// Given "Hello" returns "004Hello"
/// If nSize = 5, returns "00004Hello"
/// Default for nSize is 3.
///
///
///
protected string ADEBLDB(string sInput)
{
return ADEBLDB(sInput, 3);
}
///
/// Concatenates zero-padded length of sInput to sInput
/// Given "Hello" returns "004Hello"
/// If nSize = 5, returns "00004Hello"
/// Default for nSize is 3.
///
///
///
///
protected string ADEBLDB(string sInput, int nSize /*=3*/)
{
int nLen = sInput.Length;
string sLen = this.ADEBLDPadString(nLen.ToString(), nSize);
return sLen + sInput;
}
///
/// Build protocol header
///
///
///
///
///
///
protected string ADEBHDR(string sWKID, string sWINH, string sPRCH, string sWISH)
{
string strResult;
strResult = sWKID + ";" + sWINH + ";" + sPRCH + ";" + sWISH + ";";
strResult = ADEBLDB(strResult);
return strResult;
}
protected string ADEBLDMsg(string cHDR, string cRPC, string cParam)
{
string sMult = "";
return ADEBLDMsg(cHDR, cRPC, cParam, ref sMult);
}
protected string ADEBLDPadString(int anInteger)
{
return ADEBLDPadString(anInteger.ToString(), 3);
}
protected string ADEBLDPadString(int anInteger, int nLength /*=3*/)
{
return this.ADEBLDPadString(anInteger.ToString(), nLength);
}
protected string ADEBLDMsg(string cHDR, string cRPC, string cParam, ref string cMult)
{
//Builds RPC message
//Automatically splits parameters longer than 200 into subscripted array
String body;
cMult = "";
if (cParam == "")
{
body = "0" + cRPC;
}
else
{
StringBuilder parametersBuilder = new StringBuilder((int)(cParam.Length * 1.2));
int parameterCount = M.PieceLength(cParam, "^");
int maxChunkLength = 400;
for (int j = 1; j <= parameterCount; j++)
{
String piece = M.Piece(cParam, "^", j);
if (piece.Length > maxChunkLength)
{
if (j == parameterCount)
{
//Place holder for the long parameter
String prefix = ".x";
parametersBuilder.Append(ADEBLDPadString(prefix.Length + 1) + "2" + prefix);
StringBuilder encodedMultiPart = new StringBuilder((int)(piece.Length * 1.2));
int subscript = 1;
int startChunk = 0;
do
{
int chunkLength = Math.Min(piece.Length - startChunk, maxChunkLength);
String chunk = piece.Substring(startChunk, chunkLength);
String subscriptString = subscript.ToString();
encodedMultiPart.Append(ADEBLDPadString(subscriptString.Length));
encodedMultiPart.Append(subscriptString);
encodedMultiPart.Append(ADEBLDPadString(chunk.Length));
encodedMultiPart.Append(chunk);
subscript++;
startChunk += chunkLength;
} while (startChunk < piece.Length);
cMult = encodedMultiPart.ToString();
}
else
{
throw new BMXNetException("RPC parameter exceeds " + maxChunkLength.ToString() + ". Lone long parameter must be last.");
}
}
else
{
parametersBuilder.Append(ADEBLDPadString(piece.Length + 1) + "0" + piece);
}
}
String parameters = parametersBuilder.ToString();
body = (cMult.Length > 0 ? "1" : "0") + cRPC + "^" + ADEBLDPadString(parameters.Length, 5) + parameters;
}
return cHDR + ADEBLDB(body, 5);
}
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;
}
///
/// Returns index of first instance of sSubString in sString.
/// If sSubString not found, returns -1.
///
///
///
///
public static int FindSubString(string sString, string sSubString)
{
int nFound = -1;
int nLimit = sString.Length - sSubString.Length + 1;
if (nLimit < 0)
return -1;
int nSubLength = sSubString.Length;
for (int j = 0; j < nLimit; j++)
{
if (sString.Substring(j, nSubLength) == sSubString)
{
nFound = j;
break;
}
}
return nFound;
}
protected StreamWriter m_LogWriter;
bool m_bLogging = false;
public void StartLog()
{
try
{
if (m_bLogging)
{
throw new Exception("Already logging.");
}
string sFile = "BMXLog " + DateTime.Now.DayOfYear.ToString() + " " +
DateTime.Now.Hour.ToString() + " " + DateTime.Now.Minute.ToString()
+ " " + DateTime.Now.Second.ToString() + ".log";
StartLog(sFile);
return;
}
catch (Exception ex)
{
throw ex;
}
}
public void StartLog(string LogFileName)
{
try
{
if (m_bLogging)
{
throw new Exception("Already logging.");
}
m_LogWriter = File.AppendText(LogFileName);
m_bLogging = true;
return;
}
catch (Exception ex)
{
throw ex;
}
}
public void StopLog()
{
try
{
//Close the writer and underlying file.
if (m_bLogging == false)
{
return;
}
m_LogWriter.Close();
m_bLogging = false;
return;
}
catch (Exception ex)
{
throw ex;
}
}
private static void Log(String logMessage, TextWriter w)
{
w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
w.WriteLine(" :");
w.WriteLine(" :{0}", logMessage);
w.WriteLine("-------------------------------");
// Update the underlying file.
w.Flush();
}
public bool Lock(string Variable)
{
return Lock(Variable, "", "");
}
public bool Lock(string Variable, string Increment)
{
return Lock(Variable, Increment, "");
}
///
/// Lock a local or global M variable
/// Returns true if lock is obtained during TimeOut seconds
/// Use + to increment, - to decrement lock.
///
///
///
///
///
public bool Lock(string Variable, string Increment, string TimeOut)
{
try
{
Variable = Variable.Replace("^", "~");
string sParam = Variable + "^" + Increment + "^" + TimeOut;
string sRet = TransmitRPC("BMX LOCK", sParam);
return (sRet == "1");
}
catch (Exception ex)
{
string sMsg = ex.Message;
return false;
}
}
static ReaderWriterLock m_rwl = new ReaderWriterLock();
///
/// Returns a reference to the internal ReaderWriterLock member.
///
public ReaderWriterLock BMXRWL
{
get
{
return m_rwl;
}
}
public abstract bool IsConnected { get; }
public abstract void Close();
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;
}
protected string DecodeReceiveString(String aString)
{
return aString;
}
protected String SendReceiveString(String sendString)
{
return this.SendReceiveString(sendString, "");
}
private String _createContextRpc = "BMX CREATE CONTEXT";
protected String CreateContextRpc
{
get { return _createContextRpc; }
set { _createContextRpc = value; }
}
protected abstract String SendReceiveString(String sendString, String multi);
public abstract int ReceiveTimeout { get; set; }
public abstract int SendTimeout { get; set; }
///
/// AppContext is managed an client and server with c/s calls to change
/// appContext on the server. There is no use for AppContext on the client
/// so recommend integrated AppContext into BMX Protocol so always passing
/// it and managing switching it on the server.
///
public string TransmitRPC(string anRpc, string rpcParameter)
{
this.AssertConnected();
if (rpcParameter.Length > 32600)
{
throw new Exception("RPC parameter length exceeds maximum allowable size.");
}
try
{
string sMult = "";
string sSend = ADEBLDMsg(m_cHDR, anRpc, rpcParameter, ref sMult);
return this.SendReceiveString(sSend, sMult);
}
catch (ApplicationException exception)
{
// The writer lock request timed out.
//TODO: Remark: to writer lock for Transmit RPC
Debug.Write("TransmitRPC writer lock request timed out.\n");
throw exception;
}
catch (Exception problem)
{
throw problem;
}
}
public abstract string GetLoginFacility(String aDuz);
#endregion RPX Functions
protected void AssertConnected()
{
if (!this.IsConnected)
{
throw new BMXNetException("BMXNetBroker.TransmitRPC failed because BMXNetBroker is not connected to RPMS.");
}
}
private String _job = "";
public String Job
{
get { return _job; }
set { _job = value; }
}
///
/// Gets/sets the Kernel Application context
/// Throws an exception if unable to set the context.
///
public string AppContext
{
get
{
return m_cAppContext;
}
set
{
if (m_cAppContext == value)
return;
//Send the changed context to RPMS
if ((value != null) && (value != ""))
{
string encryptedContext = this.EncryptionProvider.Encrypt(value);
string sAuthentication = this.TransmitRPC("BMX CREATE CONTEXT", encryptedContext);
if (BMXNetBroker.FindSubString(sAuthentication, "does not have access to option") > -1)
{
throw new BMXNetException(sAuthentication);
}
if (BMXNetBroker.FindSubString(sAuthentication, "is not registered with port") > -1)
{
throw new BMXNetException(sAuthentication);
}
m_cAppContext = value;
}
}
}
public string DUZ
{
get
{
return m_cDUZ;
}
set { this.m_cDUZ = value; }
}
private EncryptionKeyProvider _keyProvider = null;
public EncryptionKeyProvider KeyProvider
{
get { return _keyProvider; }
set { _keyProvider = value; }
}
protected string RemoveADEEncryp(string sInput)
{
//Encrypt a string
string strResult = null;
string strPercent = null;
string strAssoc = null;
string strIdix = null;
int nPercent = 0;
int nAssocix = 0;
int nIdix = 0;
Debug.Assert(sInput != "");
System.Random rRand = new Random(DateTime.Now.Second);
nPercent = rRand.Next(0, 10000);
nPercent += 72439;
nAssocix = nPercent % 20;
nAssocix++;
Debug.Assert(nAssocix < 21);
strPercent = nPercent.ToString();
strPercent = strPercent.Substring(1, 2);
nIdix = Convert.ToInt32(strPercent);
nIdix = nIdix % 20;
nIdix++;
Debug.Assert(nIdix < 21);
Debug.Assert(strAssoc.Length == 94);
Debug.Assert(strIdix.Length == 94);
string sEncrypted = "";
foreach (char c in sInput)
{
string d = c.ToString();
int nFindChar = strIdix.IndexOf(c);
if (nFindChar > -1)
{
d = strAssoc.Substring(nFindChar, 1);
}
sEncrypted += d;
}
strResult = (char)(nIdix + 31) + sEncrypted + (char)(nAssocix + 31);
return strResult;
}
protected string RemoveLoadKey(int nID)
{
nID -= 102;
Debug.Assert(nID < 20);
return this.KeyProvider.Keys[nID];
}
internal string RemoveADEDecryp(string sInput)
{
//Encrypt a string
string strAssoc = null;
string strIdix = null;
int nAssocix;
int nIdix;
Debug.Assert(sInput != "");
//get associator string index
char cAssocix = sInput[sInput.Length - 1];
nAssocix = (int)cAssocix;
nAssocix -= 31;
Debug.Assert(nAssocix < 21);
//get identifier string index
char cIdix = sInput[0];
nIdix = (int)cIdix;
nIdix -= 31;
Debug.Assert(nIdix < 21);
//get associator string
Debug.Assert(strAssoc.Length == 94);
Debug.Assert(strIdix.Length == 94);
//translated result
string sDecrypted = "";
sInput = sInput.Substring(1, sInput.Length - 2);
foreach (char c in sInput)
{
string d = c.ToString();
int nFindChar = strAssoc.IndexOf(c);
if (nFindChar > -1)
{
d = strIdix.Substring(nFindChar, 1);
}
sDecrypted += d;
}
return sDecrypted;
}
internal string RemoveBMXEncrypt(string sInput)
{
ASCIIEncoding textConverter = new ASCIIEncoding();
RijndaelManaged myRijndael = new RijndaelManaged();
byte[] encrypted;
byte[] toEncrypt;
byte[] key;
byte[] IV;
string sKey = "pouphfoz sfdbqjuvmbwft qizmphfoz";
string sIV = "Gichin Funakoshi";
key = textConverter.GetBytes(sKey);
IV = textConverter.GetBytes(sIV);
//Get an encryptor.
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
//Encrypt the data.
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
//Convert the input data to a byte array.
toEncrypt = textConverter.GetBytes(sInput);
//Write all data to the crypto stream and flush it.
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
//Get encrypted array of bytes.
encrypted = msEncrypt.ToArray();
//Convert to string to send to RPMS
string sEncrypted = "";
byte bTmp;
string sTmp;
for (int j = 0; j < encrypted.Length; j++)
{
bTmp = encrypted[j];
sTmp = bTmp.ToString();
sEncrypted += sTmp;
if (j < (encrypted.Length - 1))
sEncrypted += "~";
}
return sEncrypted;
}
internal string BMXDecrypt(string sInput)
{
try
{
byte[] fromEncrypt;
ASCIIEncoding textConverter = new ASCIIEncoding();
RijndaelManaged myRijndael = new RijndaelManaged();
string sRPMSEncrypted = sInput;
string sBar = "~";
char[] cBar = sBar.ToCharArray();
string[] sArray;
sArray = sRPMSEncrypted.Split(cBar);
byte[] bRPMSEncrypted = new byte[sArray.GetLength(0)];
byte[] key;
byte[] IV;
//Convert the RPMS-stored string to a byte array
for (int j = 0; j < sArray.GetLength(0); j++)
{
bRPMSEncrypted[j] = Byte.Parse(sArray[j]);
}
//Get a decryptor that uses the same key and IV as the encryptor.
string sKey = "pouphfoz sfdbqjuvmbwft qizmphfoz";
string sIV = "Gichin Funakoshi";
key = textConverter.GetBytes(sKey);
IV = textConverter.GetBytes(sIV);
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
MemoryStream msDecrypt = new MemoryStream(bRPMSEncrypted);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
fromEncrypt = new byte[bRPMSEncrypted.Length - 2];
//Read the data out of the crypto stream.
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
int nZ = FindChar(fromEncrypt, (char)0);
//Convert the byte array back into a string.
string sResult;
if (nZ < 0)
{
sResult = textConverter.GetString(fromEncrypt);
}
else
{
sResult = textConverter.GetString(fromEncrypt, 0, nZ);
}
return sResult;
}
catch (Exception ex)
{
Debug.Write(ex.Message);
return "";
}
}
private String _userName = null;
public String UserName
{
get {
if (_userName == null)
{
this._userName = this.TransmitRPC("BMX USER", this.DUZ);
}
return _userName; }
set { _userName = value; }
}
}
}