Initial Commit

This commit is contained in:
2016-07-27 00:32:34 -04:00
commit 8d162b2035
701 changed files with 188672 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
namespace Pluto.Api {
using System;
using RemObjects.SDK;
using RemObjects.SDK.Types;
using RemObjects.SDK.Server;
using RemObjects.SDK.Server.ClassFactories;
using PlutoServer.MSL;
using System.Collections.Generic;
using PlutoServer.MSL.Connectors;
[RemObjects.SDK.Server.ClassFactories.StandardClassFactory()]
[RemObjects.SDK.Server.Service(Name = "Authentication", InvokerClass = typeof(Authentication_Invoker), ActivatorClass = typeof(Authentication_Activator))]
public class Authentication : RemObjects.SDK.Server.Service, IAuthentication {
private System.ComponentModel.Container components = null;
public Authentication() :
base() {
this.InitializeComponent();
}
private void InitializeComponent() {
}
protected override void Dispose(bool aDisposing) {
if(aDisposing) {
if((this.components != null)) {
this.components.Dispose();
}
}
base.Dispose(aDisposing);
}
public virtual UserInfo1 Login1(string apiKey, PracticeInfo1 practiceInfo, string userId, string password)
{
if(ProductType.IsKeyLytec(apiKey))
{
UserInfo1 info = LytecConnector.AuthenticateUserLogin(apiKey, userId, password);
if (info == null)
MSLSpecific.Logger.Error("Lytec Authentication Failed for User:{0} into Practice:{1}", userId, practiceInfo.Name);
return info;
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
UserInfo1 info = MedisoftConnector.AuthenticateUserLogin(apiKey, userId, password);
if (info == null)
MSLSpecific.Logger.Error("Medisoft Authentication Failed for User:{0} into Practice:{1}", userId, practiceInfo.Name);
return info;
}
MSLSpecific.Logger.Error("Invalid Product");
return null;
}
#region IAuthentication Members
public PracticeInfo1[] GetPracticeList1(string apiKey)
{
MSLSpecific.Logger.Error("GetPracticeList1 is not implemented, shouldn't never be called");
return null;
}
public virtual bool CreatePin1(string apiKey, PracticeInfo1 practiceInfo, string userId, string fourdigitpin)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.CreatePin(apiKey, userId, fourdigitpin);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.CreatePin(apiKey, userId, fourdigitpin);
}
MSLSpecific.Logger.Error("Invalid Product");
return false;
}
public virtual UserInfo1 ValidatePin1(string apiKey, PracticeInfo1 practiceInfo, string userId, string pin)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.AuthenticateUserPIN(apiKey, userId, pin);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.AuthenticateUserPIN(apiKey, userId, pin);
}
MSLSpecific.Logger.Error("Invalid Product");
return null;
}
public virtual bool PinIsSet1(string apiKey, PracticeInfo1 practiceInfo, string userId)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.PinIsSet(apiKey, userId);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.PinIsSet(apiKey, userId);
}
MSLSpecific.Logger.Error("Invalid Product");
return false;
}
public virtual string GetAPIVersion()
{
Version LocalVersion = Yaulw.Assembly.AssemblyW.GetAssemblyVersion(Yaulw.Assembly.AssemblyW.AssemblyST.Entry);
return LocalVersion.ToString();
}
public virtual bool IsAPIOutOfDate()
{
bool bRetVal = AutoUpdate.IsLocalServiceVersionOutOfDate();
if (bRetVal)
MSLSpecific.Logger.Info("Local Service is out of Date");
return bRetVal;
}
#endregion
}
}

View File

@@ -0,0 +1,316 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Yaulw.File;
using System.IO;
using Yaulw.Thread;
using System.Diagnostics;
namespace PlutoServer.MSL
{
internal static class AutoUpdate
{
#region Private Statics
/// <summary>
/// Check every 2.5 hours
/// </summary>
private const int AUTO_CHECK_INTERVAL_IN_MINUTES = 150;
/// <summary>
/// Keep track when last update occured
/// </summary>
private static ISReadWrite s_ISReadWrite = new ISReadWrite("update");
/// <summary>
/// Auto-Update Thread
/// </summary>
private static SingleThreadTimer timer = null;
/// <summary>
/// Online Version of the Service
/// </summary>
private static Version OnlineVersion = null;
/// <summary>
/// Retrieve the LocalFileNameNPath for SetupMini File (TEMP FOLDER)
/// </summary>
/// <returns></returns>
private static string MiniSetupFileNameNPath
{
get
{
string LocalFileNameNPath = Yaulw.Tools.PathNaming.PathEndsWithSlash(Path.GetTempPath()) + "SetupMini.exe";
return LocalFileNameNPath;
}
}
#endregion
#region Construction
static AutoUpdate()
{
}
#endregion
#region internal Methods
/// <summary>
/// Try to update the Service, if needed
/// </summary>
internal static void TryToUpdateIfNeeded(int nDelay, bool bCheckDTStamp)
{
// Default Auto Update with 15 sec delay
if (nDelay < 0)
nDelay = 15;
PlutoService.AppLogInfo(String.Format("TryToUpdateIfNeeded called at {0} with delay {1} and CheckDT {2}", DateTime.Now.ToLongTimeString(), nDelay.ToString(), bCheckDTStamp));
if (bCheckDTStamp)
{
DateTime dtLastUpdated = GetLastUpdated();
TimeSpan ts = DateTime.Now - dtLastUpdated;
if (ts.TotalDays >= 1.0)
{
PlutoService.AppLogInfo(String.Format("LaunchUpdateThread called with Delay {0}", nDelay));
LaunchUpdateThread(nDelay);
}
}
else
{
PlutoService.AppLogInfo(String.Format("LaunchUpdateThread called with Delay {0}", nDelay));
LaunchUpdateThread(nDelay);
}
}
/// <summary>
/// Main Entry Point - Service Calls into here upon Start-Up
/// </summary>
internal static void StartAutoTimer_ServiceStarted()
{
// Important Sanity Clean-up, this way we know that the service
// always downloads the latest setup and runs the latest setup
if (File.Exists(MiniSetupFileNameNPath))
File.Delete(MiniSetupFileNameNPath);
// Right at Service Startup Check if we have tried to update
// within the last day, if we have not, try to update.
// NOTE: Don't do this if we just got installed for the very first time
// the service seems to hang when doing that during the install of
// lytec/medisoft. (not known what the root cause is), but let's
// just avoid it alltogether. (We could potentially add a timeout here
// and just check way way later), not sure what the best course of action
// is at this point.
DateTime dt = Yaulw.Registry.RegKey.GetKey<DateTime>(Yaulw.Registry.HKEYRoot.LocalMachine, PlutoService.LOCAL_MACHINE_SUBKEY, PlutoService.LOCAL_MACHINE_INITIALSETUPDT, DateTime.MinValue);
TimeSpan ts = DateTime.Now - dt;
// If the ts is < 10 Minutes we must have just gotten installed, hence, we shouldn't
// try to update the service and just let it start (let the autoUpdate Handler below or Diagnose Mobile handle the initial updating).
if (ts.TotalMinutes > 10)
TryToUpdateIfNeeded(0, false);
// Additionally, we want to start a Timer Thread,
// that Randomly checks for new updates, once every few hours, but only
// in specific circumstances will it actually perform the update. ( check every 2.5 hours )
timer = new SingleThreadTimer(AutoUpdateHandler, (uint)TimeSpan.FromMinutes(AUTO_CHECK_INTERVAL_IN_MINUTES).TotalMilliseconds, true);
// * for debugging *:
//SingleThreadTimer timer = new SingleThreadTimer(STElapsedEventHandler, (uint)TimeSpan.FromSeconds(30).TotalMilliseconds, true);
}
/// <summary>
/// Main Entry Point - Service Calls into here upon Stop
/// </summary>
internal static void StopAutoTimer_ServiceStopped()
{
if (timer != null)
{
timer.Stop();
timer = null;
}
}
/// <summary>
/// Fetch the Latest Version that is Online
/// </summary>
/// <returns>valid version object or null if error occured</returns>
internal static Version FetchOnlineVerion()
{
string fetchVersion = Yaulw.Net.WCHelper.ScreenScrapeFromURL(Configuration.CHECK_VERSION_URL);
if (!String.IsNullOrEmpty(fetchVersion))
{
fetchVersion = fetchVersion.Replace("\n", "");
fetchVersion = fetchVersion.Replace("\r", "");
fetchVersion = fetchVersion.Trim();
try
{
Version version = new Version(fetchVersion);
return version;
}
catch (Exception e)
{
PlutoService.AppLogError(String.Format("The url:{0} to check the Mobile version could not be parsed: {1}", Configuration.CHECK_VERSION_URL, e.Message));
}
}
else
{
PlutoService.AppLogError(String.Format("The url:{0} to check the Mobile version could not be accessed", Configuration.CHECK_VERSION_URL));
}
return null;
}
/// <summary>
/// Quick Check to see if the Local Service is out of date
/// </summary>
/// <returns></returns>
internal static bool IsLocalServiceVersionOutOfDate()
{
OnlineVersion = FetchOnlineVerion();
Version LocalVersion = Yaulw.Assembly.AssemblyW.GetAssemblyVersion(Yaulw.Assembly.AssemblyW.AssemblyST.Entry);
if (OnlineVersion != null && LocalVersion != null)
{
if (OnlineVersion.Major == LocalVersion.Major && OnlineVersion > LocalVersion)
{
PlutoService.AppLogInfo("Newer Mobile Api Service Found Online");
return true;
}
else
{
PlutoService.AppLogInfo("Mobile Api Service is already up to date");
return false;
}
}
return false;
}
#endregion
#region Private Methods / Helpers
/// <summary>
/// Called Randomly every 2.5 Hours, will call Update only if called in the hours of 2 am - 6am AND
/// the TimeSpan of the last update has been over a day
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void AutoUpdateHandler(object sender, Yaulw.Thread.SingleThreadTimer.STElapsedEventArgs e)
{
DateTime dt = e.SignalTime.ToLocalTime();
TimeSpan ts = dt.TimeOfDay;
bool bIsBetween2amAnd6am = (ts.TotalHours >= 2.0) && (ts.TotalHours <= 6.0);
// Only Check between the hours of 2am to 6am
// And if we haven't updated today yet
if (bIsBetween2amAnd6am)
{
// Launch update without a thread, already inside a thread
TryToUpdateIfNeeded(0, true);
}
}
/// <summary>
/// Get the LastUpdated() DT or DateTime.Min if none
/// </summary>
/// <returns></returns>
private static DateTime GetLastUpdated()
{
string s = s_ISReadWrite.ReadFromIS();
DateTime dt = DateTime.MinValue;
if (!String.IsNullOrEmpty(s) && DateTime.TryParse(s, out dt))
return dt;
else
return DateTime.MinValue;
}
/// <summary>
/// Set the LastUpdated() DT
/// </summary>
/// <param name="dt"></param>
private static void SetLastUpdated(DateTime dt)
{
if (dt != null)
{
s_ISReadWrite.WriteToIS(dt.ToString());
}
}
/// <summary>
/// Add A Delay variable to the Update Thread
/// </summary>
private class UpdateThreadParams
{
public int nDelay = 0;
}
/// <summary>
/// Check for Updates and update the service if needed
/// </summary>
private static void CheckForUpdatesAndUpdate(object o)
{
int nSleepInMiliseconds = 0;
if (o != null)
{
UpdateThreadParams p = (UpdateThreadParams)o;
nSleepInMiliseconds = p.nDelay;
}
PlutoService.AppLogInfo(string.Format("CheckForUpdatesAndUpdate called with nDelay {0}", nSleepInMiliseconds));
if(nSleepInMiliseconds > 0)
System.Threading.Thread.Sleep(nSleepInMiliseconds);
// Update this service, if Online Version is bigger than Local Version
if (IsLocalServiceVersionOutOfDate())
{
if (Yaulw.Net.WCHelper.DownloadFileFromURL(Configuration.DOWNLOAD_MINISETUP_URL, MiniSetupFileNameNPath, true))
{
// * Important * sanity check. Kumar/Jeff found this. State can happen that we can reach the
// version url but don't actually download the file which then causes the service to crash when
// calling PSetupSpwan (might as well also make sure that the new file is equal to the file we expect)
if (File.Exists(MiniSetupFileNameNPath))
{
// The Setup will also try to auto-close this service, so first update the dt then spawn the setup.exe
SetLastUpdated(DateTime.Now);
PlutoService.AppLogInfo(String.Format("Updating to newer Mobile Api Service '{0}' via '{1}'", OnlineVersion.ToString(), MiniSetupFileNameNPath));
//No longer needed - ServiceStartVersionSent (handled in PlutoService.MSL.cs) will take care of this for us
//RegistrationWrapper.ServerHasBeenUpdated(OnlineVersion.ToString());
// The auto-update is also forcing a close (however we will also try to committ suicide)
Yaulw.Installer.Common.PSetupSpwan(MiniSetupFileNameNPath, "", false);
// * Double Knock-out * Force the Service to close here a kill itself here as well, don't know if this even get's called
// but might as well make sure and double punch
//PlutoService.StopNow();
//PlutoService.KillCurrentProccess();
}
else
{
PlutoService.AppLogInfo(String.Format("Failed to download the file to update the service, please download and install manually: '{0}'", Configuration.DOWNLOAD_MINISETUP_URL));
}
}
}
}
/// <summary>
/// Launch the Update within a Thread() with specified Delay,
/// Thread only launched if Delay > 0, otherwise just calls CheckForUpdatesAndUpdate() directly
/// </summary>
/// <param name="nDelay"></param>
internal static void LaunchUpdateThread(int nDelayInSeconds)
{
if (nDelayInSeconds > 0)
{
UpdateThreadParams p = new UpdateThreadParams() { nDelay = (int)TimeSpan.FromSeconds(nDelayInSeconds).TotalMilliseconds };
Yaulw.Thread.TStarter.StartParameterizedThread(CheckForUpdatesAndUpdate, p, "CheckForUpdate_Thread", System.Threading.ApartmentState.MTA, true, System.Threading.ThreadPriority.Normal);
}
else
{
CheckForUpdatesAndUpdate(null);
}
}
#endregion
}
}

View File

@@ -0,0 +1,174 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.269
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Pluto.Api
{
using System;
using RemObjects.SDK;
using RemObjects.SDK.Types;
using RemObjects.SDK.Server;
using RemObjects.SDK.Server.ClassFactories;
using PlutoServer.MSL.Connectors;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
[RemObjects.SDK.Server.ClassFactories.StandardClassFactory()]
[RemObjects.SDK.Server.Service(Name = "Billing", InvokerClass = typeof(Billing_Invoker), ActivatorClass = typeof(Billing_Activator))]
public class Billing : RemObjects.SDK.Server.Service, IBilling
{
private System.ComponentModel.Container components = null;
public Billing() :
base()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
}
protected override void Dispose(bool aDisposing)
{
if (aDisposing)
{
if ((this.components != null))
{
this.components.Dispose();
}
}
base.Dispose(aDisposing);
}
public virtual bool PostBilling(string apiKey, string User, BillingPost1 billingInfo)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.PostBilling(apiKey, User, billingInfo);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.PostBilling(apiKey, User, billingInfo);
}
MSLSpecific.Logger.Error("Invalid Product");
return false;
}
#region Superbill Templates
/// <summary>
/// Load a specified superbill for the specified practice
/// </summary>
/// <param name="apiKey"></param>
/// <param name="Name"></param>
/// <returns></returns>
public virtual System.Xml.XmlNode LoadSuperBill(string apiKey, string Name)
{
try
{
if (!String.IsNullOrEmpty(Name))
{
string strPath = ProductType.GetProductSpecificSuperBillDirectoryPath(apiKey);
string file = strPath + "\\" + Name + "." + ProductType.MOBILE_SB_FILE_TYPE;
if (System.IO.File.Exists(file))
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(file);
return xmlDocument;
}
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("LoadSuperBill", e);
}
return null;
}
/// <summary>
/// Save a specified superbill for a specified practice
/// </summary>
/// <param name="apiKey"></param>
/// <param name="Name"></param>
/// <param name="Data"></param>
public virtual void SaveSuperBill(string apiKey, string Name, System.Xml.XmlNode Data)
{
try
{
if (Data != null && !String.IsNullOrEmpty(Name))
{
string strPath = ProductType.GetProductSpecificSuperBillDirectoryPath(apiKey);
XmlDocument xmlDocument = new XmlDocument();
XmlNode oNode = xmlDocument.ImportNode(Data, true);
xmlDocument.AppendChild(oNode);
xmlDocument.Save(strPath + "\\" + Name + "." + ProductType.MOBILE_SB_FILE_TYPE);
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("SaveSuperBill", e);
}
}
/// <summary>
/// Retrieve a list of available superbills for a specified practice
/// </summary>
/// <param name="apiKey"></param>
/// <returns></returns>
public virtual string[] GetListOfAvailableSuperBills(string apiKey)
{
try
{
string strPath = ProductType.GetProductSpecificSuperBillDirectoryPath(apiKey);
string[] files = Directory.GetFiles(strPath, "*." + ProductType.MOBILE_SB_FILE_TYPE, SearchOption.TopDirectoryOnly);
List<string> FileNames = new List<string>();
foreach (string file in files)
FileNames.Add(Path.GetFileNameWithoutExtension(file));
return FileNames.ToArray();
}
catch (Exception e)
{
MSLSpecific.Logger.Error("GetListOfAvailableSuperBills", e);
}
return null;
}
/// <summary>
/// Delete a specified superbill for a specified practice
/// </summary>
/// <param name="apiKey"></param>
/// <param name="Name"></param>
public virtual void DeleteSuperbill(string apiKey, string Name)
{
try
{
string strPath = ProductType.GetProductSpecificSuperBillDirectoryPath(apiKey);
string[] files = Directory.GetFiles(strPath, "*." + ProductType.MOBILE_SB_FILE_TYPE, SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
var fileName = Path.GetFileNameWithoutExtension(file);
if (fileName.Equals(Name))
{
File.Delete(file);
}
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("Deleting Superbill", e);
}
}
#endregion
}
}

View File

@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using Yaulw.Assembly;
using Yaulw.Tools;
namespace PlutoServer.MSL
{
public static class Configuration
{
private const string DEFAULT_REGISTRATION_HOST_N_PORT_URL = "http://services.ndchealthvar.com/mobile1/REGURL.htm";
private const string DEFAULT_REGISTRATION_HOST_URL = "services.ndchealthvar.com";
private const int DEFAULT_REGISTRATION_CHANNEL_PORT = 443;
private const string DEFAULT_CHECK_VERSION_URL = "http://services.ndchealthvar.com/mobile1/PUBLISH.htm";
private const string DEFAULT_DOWNLOAD_SETUP_URL = "http://services.ndchealthvar.com/mobile1/Setup.exe";
private const string DEFAULT_DOWNLOAD_MINISETUP_URL = "http://services.ndchealthvar.com/mobile1/SetupMini.exe";
private const string DEFAULT_DETERMINE_EXTERNAL_IP_ADDRESS_URL = "http://services.ndchealthvar.com/GetIP/default.aspx";
private static System.Configuration.Configuration _Configuration = null;
/// <summary>
/// Load the PlutoServer.MSL.Exe configuration (writing Configuration class this way) allows
/// DiagnoseMobile.exe (RegistrationAPI_Tester to reuse this code/link this class) and is therefore
/// more generic way of retrieving the settings
/// </summary>
/// <returns></returns>
public static bool Load(bool bReload)
{
try
{
if (_Configuration == null || bReload)
{
string curPath = AssemblyW.SpecializedAssemblyInfo.GetAssemblyPath(AssemblyW.AssemblyST.Executing);
string ConfigNameNPath = PathNaming.PathEndsWithSlash(curPath) + "PlutoServer.MSL.exe";
_Configuration = ConfigurationManager.OpenExeConfiguration(ConfigNameNPath);
return (_Configuration != null);
}
}
catch (Exception) { /* ignore */}
return false;
}
#region Setting Getters
/// <summary>
/// Returns true if passed in object is valid and is not empty
/// </summary>
/// <param name="oToValidate">an object to validate</param>
/// <returns>true if valid, false otherwise</returns>
private static bool IsNotNullAndNotEmpty(object oToValidate)
{
if ((oToValidate != null) && (oToValidate.ToString() != String.Empty))
return true;
else
return false;
}
/// <summary>
/// Check to make sure the configuration is set and that there is a setting that is not blank
/// </summary>
/// <param name="setting"></param>
/// <returns></returns>
private static bool IsValidSetting(string setting)
{
if (_Configuration != null && !String.IsNullOrEmpty(setting) && IsNotNullAndNotEmpty(_Configuration.AppSettings.Settings[setting]))
{
var v = _Configuration.AppSettings.Settings[setting];
return IsNotNullAndNotEmpty(v.Value);
}
return false;
}
/// <summary>
/// Retrieves a setting or "" if setting is not valid/not found/not configured
/// </summary>
/// <param name="setting"></param>
/// <returns></returns>
private static string RetrieveSetting(string setting)
{
if (IsValidSetting(setting))
{
var v = _Configuration.AppSettings.Settings[setting];
return v.Value.ToString();
}
return String.Empty;
}
#endregion
/// <summary>
/// Default Registration URL to determine what Registration server to use (allows us to be more dynamic)
/// </summary>
public static string REGISTRATION_HOST_N_PORT_URL
{
get
{
if (IsValidSetting("REGISTRATION_HOST_N_PORT_URL"))
return RetrieveSetting("REGISTRATION_HOST_N_PORT_URL");
else
return DEFAULT_REGISTRATION_HOST_N_PORT_URL;
}
}
/// <summary>
/// Default Registration HOST URL To Use (can be configured via App.Config)
/// </summary>
public static string REGISTRATION_HOST_URL
{
get
{
if (IsValidSetting("REGISTRATION_HOST_URL"))
return RetrieveSetting("REGISTRATION_HOST_URL");
else
return DEFAULT_REGISTRATION_HOST_URL;
}
}
/// <summary>
/// Default Registration Port To Use (can be configured via App.Config)
/// </summary>
public static int REGISTRATION_CHANNEL_PORT
{
get
{
if (IsValidSetting("REGISTRATION_CHANNEL_PORT"))
{
int nPort = 0;
if (int.TryParse(RetrieveSetting("REGISTRATION_CHANNEL_PORT"), out nPort) && nPort > 0)
return nPort;
}
return DEFAULT_REGISTRATION_CHANNEL_PORT;
}
}
/// <summary>
/// Default CHECK_VERSION_URL To Use (can be configured via App.Config)
/// </summary>
public static string CHECK_VERSION_URL
{
get
{
if (IsValidSetting("CHECK_VERSION_URL"))
return RetrieveSetting("CHECK_VERSION_URL");
else
return DEFAULT_CHECK_VERSION_URL;
}
}
/// <summary>
/// Default DOWNLOAD_SETUP_URL To Use (can be configured via App.Config)
/// </summary>
public static string DOWNLOAD_SETUP_URL
{
get
{
if (IsValidSetting("DOWNLOAD_SETUP_URL"))
return RetrieveSetting("DOWNLOAD_SETUP_URL");
else
return DEFAULT_DOWNLOAD_SETUP_URL;
}
}
/// <summary>
/// Default DOWNLOAD_MINISETUP_URL To Use (can be configured via App.Config)
/// </summary>
public static string DOWNLOAD_MINISETUP_URL
{
get
{
if (IsValidSetting("DOWNLOAD_MINISETUP_URL"))
return RetrieveSetting("DOWNLOAD_MINISETUP_URL");
else
return DEFAULT_DOWNLOAD_MINISETUP_URL;
}
}
/// <summary>
/// Default DETERMINE_EXTERNAL_IP_ADDRESS_URL to use (can be configured via App.Config)
/// </summary>
public static string DETERMINE_EXTERNAL_IP_ADDRESS_URL
{
get
{
if (IsValidSetting("DETERMINE_EXTERNAL_IP_ADDRESS_URL"))
return RetrieveSetting("DETERMINE_EXTERNAL_IP_ADDRESS_URL");
else
return DEFAULT_DOWNLOAD_MINISETUP_URL;
}
}
}
}

View File

@@ -0,0 +1,407 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sdaleo;
using System.Net;
using Yaulw.Xml;
using Yaulw.File;
using CrossProduct.Core;
using System.Data;
using Sdaleo.Systems.SQLServer;
using Sdaleo.Systems.Advantage;
using Sdaleo.Systems;
using Pluto.Api;
namespace PlutoServer.MSL.Connectors
{
/// <summary>
/// Responsible for cachine SystemAPIKeys to physical Databases/Connections
/// Since we are now seperated from the instance, the practice needs to be looked up
/// in the practice list table. The Practice List Table will contain UserApiKeys that we
/// have to convert to SystemApiKeys. This cache will save us a lookup, as well as do the work for us
/// </summary>
public static class DBCache
{
private static Dictionary<string, SQLServerCredential> _LytecConnetions = new Dictionary<string, SQLServerCredential>();
private static Dictionary<string, AdvantageCredential> _MedisoftConnections = new Dictionary<string, AdvantageCredential>();
// Static Instance of the Current Configuration Data
private static DBCacheDataStore s_DBCredentialCacheDataStore = new DBCacheDataStore();
private static XSerializer s_xmlserializer = new XSerializer();
private static ISReadWrite s_ISReadWrite = new ISReadWrite("DBCache.enc");
#region Construction
static DBCache()
{
}
#endregion
#region Mobile Test Settings
/// <summary>
/// Is this computer a computer used for mobile testing?
/// </summary>
public static bool IsMachine_Used_ForTesting = false;
/// <summary>
/// Used for Unit Testing Purposes
/// </summary>
public static SQLServerCredential TestLytecUserDBCredential = null;
/// <summary>
/// Used for Unit Testing Purposes
/// </summary>
public static AdvantageCredential TestMedisoftDBCredential = null;
#endregion
#region AddSharedDataConnections (Public for Test Framework)
/// <summary>
/// Add a new SQL Server Credential to the datastore if it doesn't already exist
/// </summary>
/// <param name="bSaveToFile">true to save to the DataStore File</param>
public static void AddSharedDataConnectionToDataStore(SQLServerCredential credential, bool bSaveToFile)
{
// Check if exists
DBCacheDataStore.Credential[] existing_creds = s_DBCredentialCacheDataStore.SQLServerCredentials.Credentials;
foreach (DBCacheDataStore.Credential existing_cred in existing_creds)
{
if (String.Compare(credential.Server, existing_cred.SqlServer, true) == 0 &&
String.Compare(credential.Instance, existing_cred.SqlInstance, true) == 0)
return;
}
// else Add to persisten store
DBCacheDataStore.Credential cred = new DBCacheDataStore.Credential();
cred.SqlServer = credential.Server;
cred.SqlInstance = credential.Instance;
cred.SqlUser = credential.User;
cred.SqlPassword = ConnStr.RetrieveValue("PASSWORD", credential.ConnectionString);
s_DBCredentialCacheDataStore.SQLServerCredentials.AddCredential(cred);
// Log this
MSLSpecific.Logger.Info("Adding a new SQL Server Credential to the Datastore for Server:{0} Instance:{1}", cred.SqlServer, cred.SqlInstance);
// Save to File
if (bSaveToFile)
SaveDataStore();
// Load all User Api Keys for new Connection
IterateSharedConnectionAndLoadUserApiKeyConnections(credential);
}
/// <summary>
/// Add a new Advantage Credential * Shared Credential * to the datastore if it doesn't already exist
/// </summary>
/// <param name="bSaveToFile">true to save to the DataStore File</param>
public static void AddSharedDataConnectionToDataStore(AdvantageCredential credential, bool bSaveToFile)
{
// Check if exists
DBCacheDataStore.Credential[] existing_creds = s_DBCredentialCacheDataStore.AdvantageCredentials.Credentials;
foreach (DBCacheDataStore.Credential existing_cred in existing_creds)
{
if (String.Compare(credential.DataSource, existing_cred.AdvDataSource, true) == 0)
return;
}
// else Add to persisten store
DBCacheDataStore.Credential cred = new DBCacheDataStore.Credential();
cred.AdvDataSource = credential.DataSource;
cred.AdvIsRemote = (ConnStr.RetrieveValue("SERVERTYPE", credential.ConnectionString) == "REMOTE");
s_DBCredentialCacheDataStore.AdvantageCredentials.AddCredential(cred);
// Log this
MSLSpecific.Logger.Info("Adding a new Advantage Credential to the Datastore DataSource:{0} Remote:{1}", cred.AdvDataSource, cred.AdvIsRemote);
// Save to File
if (bSaveToFile)
SaveDataStore();
// Load all User Api Keys for new Connection
IterateSharedConnectionAndLoadUserApiKeyConnections(credential);
}
#endregion
#region Persistent DBCache File Store (Internal)
/// <summary>
/// Read from the DataStore into user connections * Reads in all credentials from a file into SQLServer & Medisoft Connections *
/// Additionally, pulls out UserApiKeys from the Practice List of the corresponding Databases
/// </summary>
/// <returns>true if file doesn't exist or if successfull read occured, false otherwise</returns>
internal static bool ReadInDataStore()
{
try
{
string ISFileContent = s_ISReadWrite.ReadFromIS();
if (!String.IsNullOrEmpty(ISFileContent))
{
// Ran into the issue that the data in the DBCache is total nonsense after decrypting,
// not sure yet how to doeal with yet * however if that is the case * what else can we
// do but ignore the input?
try
{
ISFileContent = Encryption.DecryptText(ISFileContent);
s_DBCredentialCacheDataStore = s_xmlserializer.ReadFromString<DBCacheDataStore>(ISFileContent);
}
catch (Exception e)
{
// error occured parsing the file, ignore the read!
PlutoService.AppLogError(String.Format("DBCache File is invalid. Ignoring and erasing the cache: {0}", e.Message));
s_ISReadWrite.WriteToIS(String.Empty);
return true;
}
// Test to see if a single successful read occured
bool bASuccessFullLytecReadOccured = false;
// Iterate thru all the SQL Connections
_LytecConnetions.Clear();
bool bLytecConnectionsFound = false;
int nLytecCount = 0;
foreach (DBCacheDataStore.Credential credential in s_DBCredentialCacheDataStore.SQLServerCredentials.Credentials)
{
if (credential != null)
{
bLytecConnectionsFound = true;
SQLServerCredential tempCred = new SQLServerCredential(credential.SqlServer, credential.SqlInstance, "Lytec SharedData", credential.SqlUser, credential.SqlPassword);
bool bSuccess = IterateSharedConnectionAndLoadUserApiKeyConnections(tempCred);
if (bSuccess)
{
bASuccessFullLytecReadOccured = true;
nLytecCount++;
}
}
}
if (bLytecConnectionsFound && !bASuccessFullLytecReadOccured)
PlutoService.AppLogInfo("Not one valid Lytec Connection was found in the DataStore");
if(nLytecCount > 0)
PlutoService.AppLogInfo(String.Format("Loaded {0} Lytec Shared Connection",nLytecCount));
// Test to see if a single successful read occured
bool bASuccessFullMedisoftReadOccured = false;
// Iterate thru all the Advantage Connections
_MedisoftConnections.Clear();
bool bMedisoftConnectionsFound = false;
int nMedisoftCount = 0;
foreach (DBCacheDataStore.Credential credential in s_DBCredentialCacheDataStore.AdvantageCredentials.Credentials)
{
if (credential != null)
{
bMedisoftConnectionsFound = true;
AdvantageCredential tempCred = new AdvantageCredential(credential.AdvDataSource, "SharedDataUser", "AndPassword", credential.AdvIsRemote ? AdvantageCredential.ServerType.REMOTE : AdvantageCredential.ServerType.LOCAL);
bool bSuccess = IterateSharedConnectionAndLoadUserApiKeyConnections(tempCred);
if (bSuccess)
{
bASuccessFullMedisoftReadOccured = true;
nMedisoftCount++;
}
}
}
if (bMedisoftConnectionsFound && !bASuccessFullMedisoftReadOccured)
PlutoService.AppLogInfo("Not one valid Medisoft Connection was found in the DataStore");
if (nMedisoftCount > 0)
PlutoService.AppLogInfo(String.Format("Loaded {0} Medisoft Shared Connection", nMedisoftCount));
return (bASuccessFullLytecReadOccured || bASuccessFullMedisoftReadOccured);
}
}
catch (Exception e)
{
PlutoService.AppLogError(String.Format("Error thrown reading DataStore: {0}", e.Message));
return false;
}
// No File exists, always return true
return true;
}
/// <summary>
/// Save user connnections to the DataStore any existing connections * Writes in all SQLServer & Medisoft Connectios to a file *
/// Note: UserApiKeys are never saved only the paths/credentials of the Connection
/// </summary>
internal static void SaveDataStore()
{
string ISFileContent = s_xmlserializer.WriteToString<DBCacheDataStore>(s_DBCredentialCacheDataStore);
ISFileContent = Encryption.EncryptText(ISFileContent);
s_ISReadWrite.WriteToIS(ISFileContent);
}
/// <summary>
/// Load all SQL Server User Credentials from a Shared Connection
/// </summary>
/// <param name="credential"></param>
internal static bool IterateSharedConnectionAndLoadUserApiKeyConnections(SQLServerCredential credential)
{
bool bSuccess = false;
if (credential != null)
{
DBRetVal retVal = LytecConnector.GetPracticeList(credential);
if (retVal.IsValid)
{
bSuccess = true;
foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
{
string UserApiKey = DataRet.Retrieve(row["UserAPIKey"]);
if (!String.IsNullOrEmpty(UserApiKey))
{
SystemAccessVerifier verifier = new SystemAccessVerifier(UserApiKey);
if (!String.IsNullOrEmpty(verifier.SystemApiKey))
{
string UserDB = DataRet.Retrieve(row["Database Name"]);
string Password = ConnStr.RetrieveValue("PASSWORD", credential.ConnectionString);
// We must ensure uniqueness. Somehow both Medisoft & Lytec can create scenarios
// where they are not unique amongst themselves! strange, but true
// Don't overwrite connections that are already loaded (invalid state)
if (!_LytecConnetions.ContainsKey(verifier.SystemApiKey))
{
MSLSpecific.Logger.Info("Loading ApiKey Connection for DataBase:{0}", UserDB);
_LytecConnetions[verifier.SystemApiKey] = new SQLServerCredential(credential.Server, credential.Instance, UserDB, credential.User, Password);
}
}
}
}
}
}
return bSuccess;
}
/// <summary>
/// Load all Advantage User Credentials from a Shared Connection
/// </summary>
/// <param name="credential"></param>
internal static bool IterateSharedConnectionAndLoadUserApiKeyConnections(AdvantageCredential credential)
{
bool bSuccess = false;
if (credential != null)
{
DBRetVal retVal = MedisoftConnector.GetPracticeList(credential);
if (retVal.IsValid)
{
bSuccess = true;
foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
{
string UserApiKey = DataRet.Retrieve(row["UserAPIKey"]);
if (!String.IsNullOrEmpty(UserApiKey))
{
SystemAccessVerifier verifier = new SystemAccessVerifier(UserApiKey);
if (!String.IsNullOrEmpty(verifier.SystemApiKey))
{
string UserDB = DataRet.Retrieve(row["Data Path"]);
bool bIsRemote = (ConnStr.RetrieveValue("SERVERTYPE", credential.ConnectionString) == "REMOTE");
// We must ensure uniqueness. Somehow both Medisoft & Lytec can create scenarios
// where they are not unique amongst themselves! strange, but true
// Don't overwrite connections that are already loaded (invalid state)
if(!_MedisoftConnections.ContainsKey(verifier.SystemApiKey))
{
MSLSpecific.Logger.Info("Loading ApiKey Connection for DataBase:{0}", UserDB);
_MedisoftConnections[verifier.SystemApiKey] = new AdvantageCredential(UserDB + "\\mwddf.add", "user", "password", bIsRemote ? AdvantageCredential.ServerType.REMOTE : AdvantageCredential.ServerType.LOCAL);
}
}
}
}
}
}
return bSuccess;
}
#endregion
#region Get Specific Connection
internal static SQLServerCredential GetSQLServerConnection(string SystemApiKey)
{
IConnectDb connection = GetConnectionForSystemApiKey(SystemApiKey);
if (connection is SQLServerCredential)
return (SQLServerCredential)connection;
else
return null;
}
internal static AdvantageCredential GetAdvantageConnection(string SystemApiKey)
{
IConnectDb connection = GetConnectionForSystemApiKey(SystemApiKey);
if (connection is AdvantageCredential)
return (AdvantageCredential)connection;
else
return null;
}
internal static AdvantageCredential GetAdvantageConnection(string SystemApiKey, string User)
{
AdvantageCredential credentialSystem = GetAdvantageConnection(SystemApiKey);
if (credentialSystem != null && !String.IsNullOrEmpty(User))
{
// First Retrieve the Password for that user
string SQL = String.Format("SELECT [Password] FROM [mwSEC] WHERE upper([Code]) = '{0}'", User.Replace("'", "''").ToUpper());
DB db = DB.Create(credentialSystem);
DBRetVal retVal = db.ExecuteScalar(SQL);
if (retVal.IsValid)
{
// Now Create a new Connection with the User and Password for Advantage
// ~Medisoft attaches 'mwmw' to the username for DB Connections
string pwd = retVal.GetScalarRetVal().Trim();
AdvantageCredential credentialUser = new AdvantageCredential(credentialSystem.DataSource, (User + "mwmw").ToUpper(), pwd.ToUpper(), credentialSystem.Type);
return credentialUser;
}
}
// Something Failed
return null;
}
#endregion
#region Get General Connection
/// <summary>
/// Looks up the System string in the Local User DB Connection cache and retrieves it,
/// if found. otherwise throws System not properly installed error for (release builds,
/// of this service). On Test machines it will always return something.
/// </summary>
/// <param name="SystemApiKey">SystemKey to check</param>
/// <returns></returns>
private static IConnectDb GetConnectionForSystemApiKey(string SystemApiKey)
{
if (!String.IsNullOrEmpty(SystemApiKey))
{
if (_LytecConnetions.ContainsKey(SystemApiKey))
return _LytecConnetions[SystemApiKey];
if (_MedisoftConnections.ContainsKey(SystemApiKey))
return _MedisoftConnections[SystemApiKey];
// * Setup Any Debug/Test Connections * Used Internally Only
if (IsMachine_Used_ForTesting)
{
if (ProductType.IsKeyLytec(SystemApiKey) && TestLytecUserDBCredential != null)
return TestLytecUserDBCredential;
else if (ProductType.IsKeyMedisoft(SystemApiKey) && TestMedisoftDBCredential != null)
return TestMedisoftDBCredential;
else
throw new Exception("Failed to retrieve DBCredential for ApiKey. Test Machine not properly configured.");
}
else
{
// not internally recognized, something went wrong or just Lytec / Medisoft
// calling in the wrong order * either way * nothing to return
// returning null will just mean something else blows up, so might as well
// throw an error and let the pluto api return false
PlutoService.AppLogError("Failed to retrieve ApiKey. System not properly configured.");
throw new Exception("Failed to retrieve ApiKey. System not properly configured.");
}
}
return null;
}
#endregion
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Collections;
namespace PlutoServer.MSL.Connectors
{
/// <summary>
/// Serializable Xml Object used to store all Configuration data - place any new class objects in here
/// </summary>
[XmlRoot("configuration", Namespace = "PlutoServerMSL", IsNullable = false)]
public class DBCacheDataStore
{
// Member Tags <>
public SQLServerCredentialsW SQLServerCredentials = null;
public AdvantageCredentialsW AdvantageCredentials = null;
public class SQLServerCredentialsW
{
private ArrayList m_ArrayList;
public SQLServerCredentialsW()
{
m_ArrayList = new ArrayList();
}
[XmlElement("Credential")]
public Credential[] Credentials
{
get
{
Credential[] credentials = new Credential[m_ArrayList.Count];
m_ArrayList.CopyTo(credentials);
return credentials;
}
set
{
if (value == null) return;
Credential[] credentials = (Credential[])value;
m_ArrayList.Clear();
foreach (Credential credential in credentials)
m_ArrayList.Add(credential);
}
}
internal void AddCredential(Credential credential)
{
m_ArrayList.Add(credential);
}
}
public class AdvantageCredentialsW
{
private ArrayList m_ArrayList;
public AdvantageCredentialsW()
{
m_ArrayList = new ArrayList();
}
[XmlElement("Credential")]
public Credential[] Credentials
{
get
{
Credential[] credentials = new Credential[m_ArrayList.Count];
m_ArrayList.CopyTo(credentials);
return credentials;
}
set
{
if (value == null) return;
Credential[] credentials = (Credential[])value;
m_ArrayList.Clear();
foreach (Credential credential in credentials)
m_ArrayList.Add(credential);
}
}
internal void AddCredential(Credential credential)
{
m_ArrayList.Add(credential);
}
}
public class Credential
{
public string SqlServer;
public string SqlInstance;
public string SqlUser;
public string SqlPassword;
public string AdvDataSource;
public bool AdvIsRemote;
}
/// <summary>
/// DBCacheDataStore configuration - Constructor
/// </summary>
public DBCacheDataStore()
{
SQLServerCredentials = new SQLServerCredentialsW();
AdvantageCredentials = new AdvantageCredentialsW();
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Yaulw.Assembly;
using Yaulw.Tools;
using Sdaleo.Systems.SQLServer;
using Sdaleo.Systems.Advantage;
namespace PlutoServer.MSL.Connectors
{
/// <summary>
/// Dummy wrapper class that makes it pretty to figgure out what
/// product we are in. Just do a ProductType.IsKeyLytec() or ProductType.IsKeyMedisoft() etc.
/// </summary>
internal static class ProductType
{
#region consts
/// <summary>
/// Parent folder name where SuperBills are to be stored
/// </summary>
internal const string MOBILE_SB_FILE_FOLDER_NAME = "SuperBills";
/// <summary>
/// The File Extension for the Mobile SB Files
/// </summary>
internal const string MOBILE_SB_FILE_TYPE = "msb";
#endregion
/// <summary>
/// Is System Key of type Lytec
/// </summary>
/// <param name="SystemApiKey"></param>
/// <returns></returns>
internal static bool IsKeyLytec(string SystemApiKey)
{
return (SystemAccessVerifier.GetProductTypeFromSystemApiKey(SystemApiKey) == 'L');
}
/// <summary>
/// Is System Key of type Medisoft
/// </summary>
/// <param name="SystemApiKey"></param>
/// <returns></returns>
internal static bool IsKeyMedisoft(string SystemApiKey)
{
return (SystemAccessVerifier.GetProductTypeFromSystemApiKey(SystemApiKey) == 'M');
}
/// <summary>
/// GetProductName by bool bIsMedisoft, if false returns Lytec
/// </summary>
/// <param name="bIsMedisoft"></param>
/// <returns></returns>
internal static string GetProductName(bool bIsMedisoft)
{
if (bIsMedisoft)
return "Medisoft";
else
return "Lytec";
}
/// <summary>
/// Return the Directory for the superbills, depending on product and DataSet or Database Name.
/// This means that the connection must already be in the DBCache, in order for this function to work.
/// If it is not in the DBCache, it will just default to the default superbill directory.
/// </summary>
/// <param name="SystemApiKey"></param>
/// <returns></returns>
internal static string GetProductSpecificSuperBillDirectoryPath(string SystemApiKey)
{
#if !DEBUG
// Create Default Superbill Directory, if it doesn't exists
string AsmPath = AssemblyW.SpecializedAssemblyInfo.GetAssemblyPath(AssemblyW.AssemblyST.Executing);
string SuperBillsPath = AsmPath + "\\" + MOBILE_SB_FILE_FOLDER_NAME;
if (!Directory.Exists(SuperBillsPath))
Directory.CreateDirectory(SuperBillsPath);
// Figgure out which subdirectory to use, allows us to sub-divide
// Superbills by Practice/DataSet
string subDirectory = "";
if (ProductType.IsKeyLytec(SystemApiKey))
{
// Stripe out all invalid Chars (import for SQL Databases which can have different chars than the file system)
SQLServerCredential credential = DBCache.GetSQLServerConnection(SystemApiKey);
if(credential != null)
subDirectory = PathNaming.MakeDirectoryPathValid(credential.Database);
}
else if (ProductType.IsKeyMedisoft(SystemApiKey))
{
// Retrieve the last Directory Name (DataSet Name from the DataSource)
AdvantageCredential credential = DBCache.GetAdvantageConnection(SystemApiKey);
if (credential != null)
subDirectory = PathNaming.RetrieveLastDirectoryNameInPath(credential.DataSource);
}
// Create the SubDirectory (and if files exist in the main directory)
// then copy those over, make those the default files * allows people to specify the new files to use in a practice *
if (!String.IsNullOrEmpty(subDirectory))
{
if (!Directory.Exists(SuperBillsPath + "\\" + subDirectory))
{
// Create the directory and copy all *.msb files from the main directory into it,
// allows the vars to put it into the main directory to be redistributed automatically
Directory.CreateDirectory(SuperBillsPath + "\\" + subDirectory);
string[] files = Directory.GetFiles(SuperBillsPath, "*." + ProductType.MOBILE_SB_FILE_TYPE, SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
string FileName = Path.GetFileName(file);
File.Copy(SuperBillsPath + "\\" + FileName, SuperBillsPath + "\\" + subDirectory + "\\" + FileName, false);
}
}
return PathNaming.PathEndsWithNoSlash(SuperBillsPath + "\\" + subDirectory);
}
return PathNaming.PathEndsWithNoSlash(SuperBillsPath);
#else
// Temp Path may not be perfect,
// but at least it is a central location not in the Release folder where we
// are building
return PathNaming.PathEndsWithNoSlash(Path.GetTempPath());
#endif
}
}
}

View File

@@ -0,0 +1,280 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PlutoServer.MSL.Connectors
{
/// <summary>
/// This class is copied (Stripped down to it's core, with all unneccessary stuff for this instance removed)
/// from Registration Server's SystemAccessVerifier.
/// All new code should go there. No Pin is generated here. The pin for a userkey
/// should always be generated at the registration server.
/// This class however can be used to convert a SystemApiKey to a UserApiKey, usefull for what we are
/// trying to do in this service
/// </summary>
internal class SystemAccessVerifier
{
#region Consts
const int SYSTEM_API_KEY_LENGTH = 22;
const int USER_API_KEY_LENGTH = 20;
const int PIN_LENGTH = 6;
const string SYSTEM_API_KEY_BEGIN_MARKER = "$";
const string SYSTEM_API_KEY_END_MARKER = "#";
internal static readonly string LETTER_CHARS = "AZXVGLTCIRKPNOMQJSHUFWDEYB";
internal static int GET_LETTER_CHARS_COUNT { get { return LETTER_CHARS.Length; } }
#endregion
#region System Api Key
private string _systemApiKey = String.Empty;
internal string SystemApiKey
{
get
{
return _systemApiKey;
}
set
{
if (ValidateSystemKey(value))
_systemApiKey = value.ToUpper().Trim();
}
}
private static bool ValidateSystemKey(string key)
{
if(!String.IsNullOrEmpty(key))
key = key.ToUpper().Trim();
// $247B2CB4A437EB74C62#M
if (!String.IsNullOrEmpty(key) && key.Length == SYSTEM_API_KEY_LENGTH &&
key[0] == Char.Parse(SYSTEM_API_KEY_BEGIN_MARKER) && key[SYSTEM_API_KEY_LENGTH - 2] == Char.Parse(SYSTEM_API_KEY_END_MARKER) &&
Char.IsLetter(key[SYSTEM_API_KEY_LENGTH - 1]))
{
// AllAreLettersOrDigit?
for (int i = 1; i < SYSTEM_API_KEY_LENGTH - 2; ++i)
{
if (!Char.IsLetterOrDigit(key[i]))
return false;
}
return true;
}
return false;
}
#endregion
#region User Api Key
private string _UserApiKey = String.Empty;
internal string UserApiKey
{
get
{
return _UserApiKey;
}
set
{
if (ValidateUserKey(value))
_UserApiKey = value.ToUpper().Trim();
}
}
private static bool ValidateUserKey(string key)
{
if (!String.IsNullOrEmpty(key))
key = key.ToUpper().Trim();
//247BQCB4A-37EB-4C62M
if (!String.IsNullOrEmpty(key) && key.Length == USER_API_KEY_LENGTH &&
Char.IsLetter(key[USER_API_KEY_LENGTH - 1]) &&
Char.IsLetter(key[4]) && key[9] == '-' && key[14] == '-')
{
// Perform Product Security check
char productType = key[USER_API_KEY_LENGTH - 1];
int v = (int)productType % GET_LETTER_CHARS_COUNT;
if (key[4] == LETTER_CHARS[v])
return true;
}
return false;
}
#endregion
#region Product Type
private char _productType = '\0';
internal char ProductType { get { return Char.ToUpper(_productType); } }
internal bool IsValidProductType { get { return (_productType != '\0'); } }
#endregion
#region Construction
internal SystemAccessVerifier(string userApiKey)
{
if (!String.IsNullOrEmpty(userApiKey))
userApiKey = userApiKey.ToUpper().Trim();
if (ValidateUserKey(userApiKey))
{
UserApiKey = userApiKey;
ConvertUserToSystemApiKey();
_productType = GetProductTypeFromSystemApiKey(SystemApiKey);
}
}
#endregion
#region Private Converters
private void ConvertUserToSystemApiKey()
{
if (ValidateUserKey(UserApiKey))
{
// 247BQCB4A-37EB-4C62M
StringBuilder sb = new StringBuilder(UserApiKey);
char productType = sb[USER_API_KEY_LENGTH - 1];
sb.Remove(USER_API_KEY_LENGTH - 1, 1);
// Add More Randomness into this (nobody will ever know :S)
// Dynamic Calc for 2 - 2, 12 - 4
int a = (int)'A';
int z = (int)'Z';
int ic = (int)sb[2];
if ((ic - 2 >= a) && (ic <= z))
sb[2] = (char)(ic - 2);
ic = sb[12];
if ((ic - 4 >= a) && (ic <= z))
sb[12] = (char)(ic - 4);
//Otherway arround arbitrary swap (just in case)
// Swap 3 to 10, and 5 to 16
char c = sb[3];
sb[3] = sb[10];
sb[10] = c;
c = sb[5];
sb[5] = sb[16];
sb[16] = c;
// Assign '-'
sb[4] = '-';
// How clever :S
string s = ReverseString(sb.ToString());
int n = 0;
sb = new StringBuilder(s);
for (int i = 0; i < s.Length; ++i)
{
if (s[i] == '-')
{
sb[i] = (s[n]);
n++;
}
else
{
sb[i] = (s[i]);
}
}
// $247B2CB4A437EB74C62#M
s = SYSTEM_API_KEY_BEGIN_MARKER + sb.ToString() + SYSTEM_API_KEY_END_MARKER + Char.ToUpper(productType);
SystemApiKey = s;
}
}
#endregion
#region Internal Statics
internal static char GetProductTypeFromSystemApiKey(string systemApiKey)
{
if (ValidateSystemKey(systemApiKey))
return Char.ToUpper(systemApiKey[SYSTEM_API_KEY_LENGTH - 1]);
else
return '\0';
}
#endregion
#region Private static Key Generation Helper Functions
private static string ReverseString(string str)
{
if (!String.IsNullOrEmpty(str))
{
Stack<char> stack = new Stack<char>();
foreach (char c in str)
stack.Push(c);
StringBuilder sb = new StringBuilder();
while (stack.Count > 0)
sb.Append(stack.Pop());
return sb.ToString();
}
return String.Empty;
}
/// <summary>
/// Perform checksum on string
/// </summary>
/// <param name="strAboutToBeChecksummed"></param>
/// <returns>Checksum</returns>
private static int PerformChecksum(string strAboutToBeChecksummed)
{
if (!String.IsNullOrEmpty(strAboutToBeChecksummed))
{
int nChecksum = 0;
for (int i = 0; i < strAboutToBeChecksummed.Length; ++i)
{
if (Char.IsDigit(strAboutToBeChecksummed[i]))
nChecksum = nChecksum + int.Parse(strAboutToBeChecksummed[i].ToString());
}
return nChecksum;
}
return 0;
}
/// <summary>
/// Dash a String every Nth Character
/// </summary>
/// <returns>a dashed string</returns>
private static string MakeIntoDashSeperatedString(string strAboutToBeDashed, int DashEveryNthCharacter)
{
if (!String.IsNullOrEmpty(strAboutToBeDashed))
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < strAboutToBeDashed.Length; i++)
{
if ((i != 0) && ((i % DashEveryNthCharacter) == 0))
sb.Append("-");
sb.Append(strAboutToBeDashed[i]);
}
return sb.ToString();
}
return String.Empty;
}
/// <summary>
/// Undash a String
/// </summary>
/// <returns>a string without dashes</returns>
private static string MakeIntoDashUnseperatedString(string strAboutToBeUndashed)
{
if (!String.IsNullOrEmpty(strAboutToBeUndashed))
return strAboutToBeUndashed.Replace("-", "");
return String.Empty;
}
/// <summary>
/// Check if the passed in string contains only digits
/// </summary>
/// <param name="strToCheckForDigits">string to check for digits for</param>
/// <returns>true, if all digits are numbers</returns>
private static bool ContainsOnlyDigits(string strToCheckForDigits)
{
if (!String.IsNullOrEmpty(strToCheckForDigits))
{
for (int i = 0; i < strToCheckForDigits.Length; ++i)
{
if (!Char.IsDigit(strToCheckForDigits[i]))
return false;
}
return true;
}
return false;
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PlutoServer.MSL {
public static class SessionKeys {
public static readonly string AuthToken = "AUTH_TOKEN";
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pluto.Api;
using Sdaleo.Systems.SQLServer;
using Sdaleo;
using PlutoServer.MSL.Connectors;
using Sdaleo.Systems.Advantage;
using RegistrationAPI;
using Pluto.Registration;
namespace PlutoServer.MSL
{
/// <summary>
/// Only used for Debugging / Testing
/// </summary>
internal static class DEBUGGING_ONLY
{
#region Debug Step Credentials (For Testing)
const string LYTEC_KEY = "$616866C0D12EC1641A5#L";
const string MEDISOFT_KEY = "$616866C0D12EC1641A5#M";
/// <summary>
/// Advantage User Test Credential
/// </summary>
internal static AdvantageCredential AdvantageTestCredential = new AdvantageCredential(@"\\10.97.156.4\Medidata\Tutor\mwddf.add", "user", "password", AdvantageCredential.ServerType.REMOTE);
/// <summary>
/// Advantage Shared Test Credential
/// </summary>
internal static AdvantageCredential AdvantageTestSharedCredential = new AdvantageCredential(@"\\10.97.156.4\Medidata\SharedData.add", "SharedDataUser", "AndPassword", AdvantageCredential.ServerType.REMOTE);
/// <summary>
/// SQLServer User Test Credential
/// </summary>
internal static SQLServerCredential SQLServerTestCredential = new SQLServerCredential("10.97.156.22", "LytecMD", "Lytec Tutorial", "sa", "Clinical$1");
/// <summary>
/// SQLServer Shared Test Credential
/// </summary>
internal static SQLServerCredential SQLServerTestSharedCredential = new SQLServerCredential("10.97.156.22", "LytecMD", "Lytec SharedData", "sa", "Clinical$1");
#endregion
/// <summary>
/// Called in Debug Mode to allow us to step into specific things and
/// easier test them straight thru the service, called before OnStart(),
/// makes it easier to directly test Medisoft/Lytec Connectors
/// </summary>
internal static void DEBUGSTEP_INTO()
{
MSLSpecific.Setup_Test_Logger();
DBCache.IsMachine_Used_ForTesting = true;
DBCache.TestMedisoftDBCredential = AdvantageTestCredential;
DBCache.TestLytecUserDBCredential = SQLServerTestCredential;
//Could you please run the script for IP address thing for orgs with key 2A66B402F-4041-E491M and E2G4Y3777-4F3E-BFEDL
//SystemAccessVerifier v = new SystemAccessVerifier("CC67BA96B-4E85-57BBM");
//SystemAccessVerifier v = new SystemAccessVerifier("930CY6704-42FE-1D1FL");
//SystemAccessVerifier v = new SystemAccessVerifier("2A66B402F-4041-E491M"); // "$194E114069F204446A2#M"
SystemAccessVerifier v = new SystemAccessVerifier("E2G4Y3777-4F3E-BFEDL"); // "$DE3BDE3F4E777F34E2E#L"
//string pin = RegistrationAPI.API.RetrieveUserApiKeyPin("CC67BA96B-4E85-57BBM");
string apikey = v.SystemApiKey;
Pluto.Registration.Host host = RegistrationAPI.API.GetApiMobile(v.SystemApiKey);
string ip = host.host;
int port = host.port;
bool bTest = RegistrationAPI.API.IsApiMobileReachable(v.SystemApiKey);
//RegistrationAPI.API.SetNetworkSettings("172.19.73.26", 443);
RegistrationAPI.API.SetNetworkSettings("ppsmobile.mckesson.com", 443);
//RegistrationAPI.API.SetNetworkSettings("services.ndchealthvar.com", 443);
string strApiKey;
string strPin;
bool bSuccess = RegistrationAPI.API.RegisterNewServerPractice(new Guid("7c18db98-3c34-4382-963c-1175f0d20f44"), "Happy Valley Medical Clinic (Mck)", "10.24.52.25", "", 1945, "Medisoft", out strApiKey, out strPin);
//SuperBillLoadingSavingDebugStep();
}
private static void SuperBillLoadingSavingDebugStep()
{
//string path = Path.GetTempPath();
//string str = "<Name>Default</Name><Sections><SuperbillSection><Title>Office Visit (New)</Title><BgColor><Red>0</Red><Green>0</Green><Blue>0</Blue></BgColor><Sequence>1</Sequence><Row>0</Row><Column>0</Column><Fields><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>1</Sequence><Code>99201</Code><DisplayText>Problem focused</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>2</Sequence><Code>99202</Code><DisplayText>Expanded problem focused</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>3</Sequence><Code>99203</Code><DisplayText>Detailed</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>4</Sequence><Code>99204</Code><DisplayText>Comprehensive</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>5</Sequence><Code>99205</Code><DisplayText>Comprehensive (new patient)</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>6</Sequence><Code>-25</Code><DisplayText>Significant, separate service</DisplayText><Modifiers /><Units>0</Units></SuperbillField></Fields></SuperbillSection><SuperbillSection><Title>Office Visit (Est)</Title><BgColor><Red>0</Red><Green>0</Green><Blue>0</Blue></BgColor><Sequence>2</Sequence><Row>1</Row><Column>0</Column><Fields><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>1</Sequence><Code>99211</Code><DisplayText>Minimal</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>2</Sequence><Code>99212</Code><DisplayText>Expanded problem focused</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>3</Sequence><Code>99213</Code><DisplayText>Detailed</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>4</Sequence><Code>99214</Code><DisplayText>Comprehensive</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>5</Sequence><Code>99215</Code><DisplayText>Comprehensive (new patient)</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>6</Sequence><Code>-25</Code><DisplayText>Significant, separate service</DisplayText><Modifiers /><Units>0</Units></SuperbillField></Fields></SuperbillSection><SuperbillSection><Title>Discharge Instructions</Title><BgColor><Red>0</Red><Green>0</Green><Blue>0</Blue></BgColor><Sequence>3</Sequence><Row>2</Row><Column>0</Column><Fields><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>1</Sequence><Code /><DisplayText>Comeback in 2 weeks</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>1</Sequence><Code /><DisplayText>Comeback in 4 weeks</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>1</Sequence><Code /><DisplayText>Comeback in 6 weeks</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>1</Sequence><Code /><DisplayText>Comeback in 8 weeks</DisplayText><Modifiers /><Units>0</Units></SuperbillField><SuperbillField><FieldType>Diagnosis</FieldType><Sequence>1</Sequence><Code /><DisplayText>Comeback in 6 months</DisplayText><Modifiers /><Units>0</Units></SuperbillField></Fields></SuperbillSection><SuperbillSection><Title>Skin procedures</Title><BgColor><Red>0</Red><Green>0</Green><Blue>0</Blue></BgColor><Sequence>4</Sequence><Row>3</Row><Column>0</Column><Fields /></SuperbillSection><SuperbillSection><Title>Other services</Title><BgColor><Red>0</Red><Green>0</Green><Blue>0</Blue></BgColor><Sequence>5</Sequence><Row>4</Row><Column>0</Column><Fields /></SuperbillSection></Sections>";
//string strPath = ProductType.GetProductSpecificSuperBillDirectoryPath("");
//XmlDocument xmlDocument = new XmlDocument();
//XmlNode Data = xmlDocument.CreateNode(XmlNodeType.Element, "SuperBillTemplate", "SuperBillTemplate");
//Data.InnerXml = str;
//XmlNode oNode = xmlDocument.ImportNode(Data, true);
//xmlDocument.AppendChild(oNode);
//xmlDocument.Save(strPath + "\\" + "Default" + ".msb");
//xmlDocument.Load(strPath + "\\" + "Default" + ".msb");
//XmlNode oNode2 = (XmlNode) xmlDocument;
}
}
}

View File

@@ -0,0 +1,31 @@
namespace PlutoServer.MSL {
partial class Installer {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.ServiceProcess;
namespace PlutoServer.MSL {
[RunInstaller(true)]
public partial class Installer : System.Configuration.Install.Installer {
public Installer() {
InitializeComponent();
ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller();
ServiceInstaller serviceInstaller = new ServiceInstaller();
//# Service Account Information
serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
serviceProcessInstaller.Username = null;
serviceProcessInstaller.Password = null;
//# Service Information
serviceInstaller.ServiceName = "PlutoServer.MSL";
serviceInstaller.DisplayName = "McKesson MSL Mobile Api Server";
serviceInstaller.Description = "Manages data updates and retrieval for McKesson's PPS Mobile App from MSL";
serviceInstaller.StartType = ServiceStartMode.Automatic;
// # Done
this.Installers.Add(serviceProcessInstaller);
this.Installers.Add(serviceInstaller);
}
}
}

View File

@@ -0,0 +1,727 @@
namespace Pluto.Api
{
using System;
using RemObjects.SDK;
using RemObjects.SDK.Types;
using RemObjects.SDK.Server;
using RemObjects.SDK.Server.ClassFactories;
using PlutoServer.MSL.Connectors;
using Yaulw.File;
using Sdaleo;
using Sdaleo.Systems.SQLServer;
using Sdaleo.Systems.Advantage;
using Sdaleo.Systems;
using System.Net;
using PlutoServer.MSL;
using Yaulw.Assembly;
using Yaulw.Tools;
[RemObjects.SDK.Server.ClassFactories.StandardClassFactory()]
[RemObjects.SDK.Server.Service(Name = "MSLSpecific", InvokerClass = typeof(MSLSpecific_Invoker), ActivatorClass = typeof(MSLSpecific_Activator))]
public class MSLSpecific : RemObjects.SDK.Server.Service, IMSLSpecific
{
private System.ComponentModel.Container components = null;
public MSLSpecific() :
base()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
}
protected override void Dispose(bool aDisposing)
{
if (aDisposing)
{
if ((this.components != null))
{
this.components.Dispose();
}
}
base.Dispose(aDisposing);
}
/// <summary>
/// Keep track of the Host GUID
/// </summary>
private static ISReadWrite s_ISReadWrite = new ISReadWrite("host");
#region Logger Functions (public one is for Test Framework)
/// <summary>
/// For Logging to a File
/// </summary>
internal static Logging Logger = null;
/// <summary>
/// Test Log File and Path
/// </summary>
internal static string TestLogFileNameNPath = String.Empty;
/// <summary>
/// Setup the Logger Object, should be done only once at when the application starts
/// </summary>
internal static void Setup_Logger()
{
if (Logger == null)
{
// Is Setup_Test_Logger() Called?
bool bIsTestLogFileSet = !String.IsNullOrEmpty(TestLogFileNameNPath);
// Default Log File Settings
const int LOG_FILE_FILE_SIZE_IN_MB = 4;
const int LOG_FILE_NUM_OF_BACKUPS = 2;
const string FILE_EXTENSION_LOG_DEFAULT = "log";
// Default Log File Name N Path Settings
string LogFileNameNPath = String.Empty;
if (!bIsTestLogFileSet)
{
string Path = AssemblyW.SpecializedAssemblyInfo.GetAssemblyPath(AssemblyW.AssemblyST.Entry);
LogFileNameNPath = PathNaming.PathEndsWithSlash(Path) + AssemblyW.GetAssemblyName(AssemblyW.AssemblyST.Entry) + "." + FILE_EXTENSION_LOG_DEFAULT;
}
else
{
// Allow Unit test framework to set the log file path
LogFileNameNPath = TestLogFileNameNPath;
}
// Log Config
Logging_Configuration config = new Logging_Configuration();
config.LogFileNameNPath = LogFileNameNPath;
config.maxFileSizeInMB = LOG_FILE_FILE_SIZE_IN_MB;
config.numOfBackupLogFiles = LOG_FILE_NUM_OF_BACKUPS;
config.Log4NetDetailPatternLayout = "%date{dd MMM HH:mm:ss,fff} %level - %message%newline";
config.LogCallingFunction = false;
config.LogCallingType = false;
if (PlutoService.IsOnMcKessonNetwork || bIsTestLogFileSet)
config.Detail = Logging_Detail.DEBUG;
else
config.Detail = Logging_Detail.INFO;
config.UseExclusiveFileLock = false;
// Now just create the Logger
if (!bIsTestLogFileSet)
Logger = Logging.AddGlobalLoggerConfiguration(AssemblyW.GetAssemblyName(AssemblyW.AssemblyST.Entry), config);
else
Logger = Logging.AddGlobalLoggerConfiguration("Pluto.MSL.Test", config);
// Make a Debug Message show, if we are on McKesson
if (PlutoService.IsOnMcKessonNetwork)
Logger.Info("**** NOTE **** This is a McKesson Networked Machine. DEBUG Messages will only show when service is run from a McKesson Networked Machine.");
else
Logger.Info("**** NOTE **** This is a Regularly Networked Machine. Only INFO and ERROR Messages will show when service in this Environment.");
Logger.Info("Logger Started at:{0} with Service Version {1}", DateTime.Now.ToString(), AssemblyW.GetAssemblyVersion(AssemblyW.AssemblyST.Entry));
}
}
/// <summary>
/// Setup the Test Logger Object, should be done by the Unit test framework to put the file in c:\\
/// </summary>
public static void Setup_Test_Logger()
{
TestLogFileNameNPath = @"C:\\Pluto.MSL.Test.log";
Setup_Logger();
}
#endregion
#region Internal Static Helper Functions
// Wipes all information known to use, both on the registration server as well as here
// and starts over. logs the information to the user. System is auto-fixing itelf.
// performing an internal re-install. The user may not like it, but that is just what
// happend, we are in a bad state ERROR IT * BOLDLY in the Error log*
internal static void MAJOR_ERROR_INTEGRITY_EVENT_OCCURED_ENTER_REINSTALL_STATE()
{
Logger.Fatal("******** FATAL ******** State occured. Service integrity invalid. All UserApiKeys will get deregistered as well as all hostGuid keys");
Logger.Fatal("******** FATAL ******** Someone must have tried to tamper with the system (registry / files) loosing vital information needed to continue.");
Logger.Fatal("******** FATAL ******** Service is attempting to auto-fix itself. All users must re-open Mobile->Help about and obtain a new user api key.");
}
/// <summary>
/// Retrieve the UserApiKey for a given Practice
/// </summary>
/// <param name="bIsMedisoft"></param>
/// <param name="credential"></param>
/// <param name="DataSetOrDataBaseName"></param>
/// <returns></returns>
internal static string GetUserApiKeyForPractice(bool bIsMedisoft, IConnectDb credential, string DataSetOrDataBaseName, out bool bErrorOccured)
{
string UserApiKey = "";
bErrorOccured = true;
if (!String.IsNullOrEmpty(DataSetOrDataBaseName) && credential != null)
{
if (bIsMedisoft)
{
string retVal = MedisoftConnector.GetUserApiKeyForPractice((AdvantageCredential)credential, DataSetOrDataBaseName, out bErrorOccured);
if (!String.IsNullOrEmpty(retVal))
UserApiKey = retVal;
}
else
{
string retVal = LytecConnector.GetUserApiKeyForPractice((SQLServerCredential)credential, DataSetOrDataBaseName, out bErrorOccured);
if (!String.IsNullOrEmpty(retVal))
UserApiKey = retVal;
}
}
return UserApiKey;
}
/// <summary>
/// Set the UserApiKey for a given Practice
/// </summary>
/// <param name="bIsMedisoft"></param>
/// <param name="credential"></param>
/// <param name="DataSetOrDataBaseName"></param>
/// <returns></returns>
internal static bool SetUserApiKeyForPractice(bool bIsMedisoft, IConnectDb credential, string DataSetOrDataBaseName, string UserApiKey)
{
if (!String.IsNullOrEmpty(DataSetOrDataBaseName) && credential != null)
{
if (bIsMedisoft)
{
bool bSuccess = MedisoftConnector.SetUserApiKeyForPractice((AdvantageCredential)credential, DataSetOrDataBaseName, UserApiKey);
if(!bSuccess)
Logger.Error("Error setting UserApiKey for DataSetorDataBaseName {0}", DataSetOrDataBaseName);
return bSuccess;
}
else
{
bool bSuccess = LytecConnector.SetUserApiKeyForPractice((SQLServerCredential)credential, DataSetOrDataBaseName, UserApiKey);
if (!bSuccess)
Logger.Error("Error setting UserApiKey for DataSetorDataBaseName {0}", DataSetOrDataBaseName);
return bSuccess;
}
}
return false;
}
/// <summary>
/// Retrieve the Host Guid for this instance,k if not exists,
/// create one. Host Guid is stored in isolated storage * why not *
/// </summary>
/// <returns></returns>
internal static Guid GetHostGUID()
{
string s = s_ISReadWrite.ReadFromIS();
if (String.IsNullOrEmpty(s))
{
Guid g = Guid.NewGuid();
Logger.Debug("Creating new Host GUID {0}", g.ToString());
s_ISReadWrite.WriteToIS(g.ToString());
return g;
}
return new Guid(s);
// New Untested Code * Still needs some hashing out *
//string s = s_ISReadWrite.ReadFromIS();
//Guid g = Guid.NewGuid();
//if (String.IsNullOrEmpty(s))
//{
// // Store bck HostGuid in registry to make sure this value is never lost
// Yaulw.Registry.RegKey.SetKey<string>(Yaulw.Registry.HKEYRoot.LocalMachine, PlutoService.LOCAL_MACHINE_SUBKEY, PlutoService.LOCAL_MACHINE_HOSTGUID, g.ToString());
// Logger.Debug("Creating new Host GUID {0}", g.ToString());
// s_ISReadWrite.WriteToIS(g.ToString());
// return g;
//}
//else
//{
// // Read registry and retrieve backup guid first * if empty set it, Upgrade service issues * feature added in 1.0.2.3
// string bckGuid = Yaulw.Registry.RegKey.GetKey<string>(Yaulw.Registry.HKEYRoot.LocalMachine, PlutoService.LOCAL_MACHINE_SUBKEY, PlutoService.LOCAL_MACHINE_HOSTGUID, String.Empty);
// if (String.IsNullOrEmpty(bckGuid.ToString()))
// {
// Yaulw.Registry.RegKey.SetKey<string>(Yaulw.Registry.HKEYRoot.LocalMachine, PlutoService.LOCAL_MACHINE_SUBKEY, PlutoService.LOCAL_MACHINE_HOSTGUID, g.ToString());
// }
// else
// {
// // if not empty compare them (they should always be equal if not, we are kind of in mayor trouble)
// // we will pick the guid that is stored in online, that is our only choice, doubtful that both got
// // stored online (*that state is a major error state and would require wiping the host guid, and wiping
// // all hostkeys online and all userapikeys online. Even maybe the DBCacheFile. basically an internal re-install
// if (String.Compare(s, bckGuid, true) != 0)
// {
// // chech which guid is online, pick that one first
// // else Mayor event occured
// MAJOR_ERROR_INTEGRITY_EVENT_OCCURED_ENTER_REINSTALL_STATE();
// }
// }
//}
//return new Guid(s);
}
/// <summary>
/// Quick check to see if the connection is a Medisoft / Advantage DB Connection
/// </summary>
/// <param name="ConnectionString"></param>
/// <returns></returns>
internal static bool ConnectionContainsAdvServerType(string ConnectionString)
{
if (!String.IsNullOrEmpty(ConnectionString))
return (ConnStr.ContainsKey("Advantage Server Type", ConnectionString) || ConnStr.ContainsKey("ServerType", ConnectionString));
return false;
}
#endregion
#region Private DBCache Related Helper Functions
/// <summary>
/// Shared Database Connection needs to be added
/// </summary>
/// <param name="SharedConnectionDataSource">Connection String of the Shared DB to be added to Cache</param>
/// <param name="bTryToConnect">Will try to connect to the DB, if set to true</param>
/// <param name="bCanConnect">if bTryToConnect is true, it will try to connect and assign out this value</param>
/// <returns>true if it needed to be added and, if TryToConnect is set, and communication is working, false otherwise</returns>
private bool AddConnectionIfNotAlreadyThere(string SharedConnectionDataSource, bool bTryToConnect)
{
if (!String.IsNullOrEmpty(SharedConnectionDataSource))
{
IConnectDb credential = ConvertSharedDataSourceToProperCredential(SharedConnectionDataSource);
if (credential != null)
{
// Is Connection of Type Medisoft
if (ConnectionContainsAdvServerType(SharedConnectionDataSource))
{
DBCache.AddSharedDataConnectionToDataStore((AdvantageCredential)credential, true);
// Test the Connection = see if error occurs calling practice list
if (bTryToConnect)
{
bool bConnect = MedisoftConnector.GetPracticeList((AdvantageCredential)credential).IsValid;
return bConnect;
}
else
return true;
}
else // Or Lytec
{
DBCache.AddSharedDataConnectionToDataStore((SQLServerCredential)credential, true);
// Test the Connection = see if error occurs calling practice list
if (bTryToConnect)
{
bool bConnect = LytecConnector.GetPracticeList((SQLServerCredential)credential).IsValid;
return bConnect;
}
else
return true;
}
}
}
return false;
}
/// <summary>
/// Converts a passed in SharedConnection (from Medisoft/Lytec) into a proper IConnectDb credential
/// we can use to pass arround
/// </summary>
/// <param name="SharedConnectionDataSource"></param>
/// <returns></returns>
private IConnectDb ConvertSharedDataSourceToProperCredential(string SharedConnectionDataSource)
{
if (!String.IsNullOrEmpty(SharedConnectionDataSource))
{
// Is Connection of Type Medisoft
if (ConnectionContainsAdvServerType(SharedConnectionDataSource))
{
string Type = ConnStr.RetrieveValue("Advantage Server Type", SharedConnectionDataSource);
if (String.IsNullOrEmpty(Type))
Type = ConnStr.RetrieveValue("ServerType", SharedConnectionDataSource);
bool bIsRemote = Type.ToUpper().Contains("REMOTE");
AdvantageCredential credential = new AdvantageCredential(Yaulw.Net.IPHostHelper.GetDataSource(SharedConnectionDataSource), "SharedDataUser", "AndPassword", bIsRemote ? AdvantageCredential.ServerType.REMOTE : AdvantageCredential.ServerType.LOCAL);
return credential;
}
else // Or Lytec
{
string Server;
string Instance;
if (SQLServerUtilities.SplitServerOrServerNInstance(Yaulw.Net.IPHostHelper.GetDataSource(SharedConnectionDataSource), out Server, out Instance))
{
string UserID = ConnStr.RetrieveValue("User ID", SharedConnectionDataSource);
string Password = ConnStr.RetrieveValue("Password", SharedConnectionDataSource);
SQLServerCredential credential = new SQLServerCredential(Server, Instance, "Lytec SharedData", UserID, Password);
return credential;
}
}
}
return null;
}
/// <summary>
/// Reload the UserCredentials for a given SharedCredentials in the Cache
/// </summary>
/// <param name="SharedCredential"></param>
/// <param name="bIsMedisoft"></param>
private void ReloadUserDBConnectionForSharedCredential(IConnectDb SharedCredential, bool bIsMedisoft)
{
if (bIsMedisoft)
DBCache.IterateSharedConnectionAndLoadUserApiKeyConnections((AdvantageCredential)SharedCredential);
else
DBCache.IterateSharedConnectionAndLoadUserApiKeyConnections((SQLServerCredential)SharedCredential);
}
#endregion
#region IMSLMobileConnect
/// <summary>
/// Common Tasks to do for all of our MSLSpecific Calls
/// </summary>
/// <param name="SharedConnectionDataSource">Medisoft/Lytec SharedDataConnection</param>
/// <param name="bAddSharedConnection">if true, add the connection to our DataStore</param>
/// <param name="bTryToConnect">if true, trying to connect to the db to test</param>
/// <param name="bIsMedisoft">out is Medisoft</param>
/// <param name="Credential">out Credential</param>
/// <returns>return true when everything is ok, false otherwise</returns>
private bool CommonThingsToDoUponEveryMSLCall(string SharedConnectionDataSource, bool bAddSharedConnection, bool bTryToConnect, out bool bIsMedisoft, out IConnectDb Credential)
{
bIsMedisoft = false;
Credential = null;
if(!String.IsNullOrEmpty(SharedConnectionDataSource))
{
// Is Lytec or Medisoft?
bIsMedisoft = ConnectionContainsAdvServerType(SharedConnectionDataSource);
Credential = ConvertSharedDataSourceToProperCredential(SharedConnectionDataSource);
if (Credential != null)
{
// Local Host name and IP
if(bIsMedisoft)
Logger.Info("Determined DataSource to be Medisoft");
else
Logger.Info("Determined DataSource to be Lytec");
Logger.Info("Determined Host:{0} with Host Guid:'{1}'", Dns.GetHostName(), GetHostGUID());
// Should we add the connection?
if (bAddSharedConnection)
{
// will always return true, unless bTryToConnect is true and it will try to connect and fail
bool bConnect = AddConnectionIfNotAlreadyThere(SharedConnectionDataSource, bTryToConnect);
if (bTryToConnect && bConnect)
Logger.Debug("Successfully connected to SharedDataSource: {0}", SharedConnectionDataSource);
else if(bTryToConnect && !bConnect)
Logger.Error("Failed to Connect to passed in DataSource");
// Ensure that all UserApiKeys are unique - running into issues
// with Lytec and Medisoft somehow
if (bConnect)
{
if (bIsMedisoft)
MedisoftConnector.CleanUpDuplicateUserApiKeyExists((AdvantageCredential)Credential);
else
LytecConnector.CleanUpDuplicateUserApiKeyExists((SQLServerCredential)Credential);
}
return bConnect;
}
}
}
Logger.Debug("Something is wrong with this DataSource {0},", SharedConnectionDataSource);
Logger.Error("Failed to Retrieve the information needed to continue");
return false;
}
/// <summary>
/// Mobile About Dialog got called by Lytec/Medisoft. Here we do the main work of registering everything
/// </summary>
/// <param name="SharedConnectionDataSource"></param>
/// <param name="RegisteredName"></param>
/// <param name="PracticeName"></param>
/// <returns></returns>
public virtual ApiKeyNPin MobileAboutDialogCalled(string SharedConnectionDataSource, string RegisteredName, string PracticeName, string DataBaseNameOrDataSetName)
{
Logger.Debug("called with SharedDataSource: {0}, RegisteredName: {1}, PracticeName: {2}, DataSetOrDBName: {3}", SharedConnectionDataSource, RegisteredName, PracticeName, DataBaseNameOrDataSetName);
ApiKeyNPin apikey = new ApiKeyNPin();
try
{
// Perform this for all MSL Entry Calls * for Sanity *
bool bIsMedisoft = false;
IConnectDb Credential = null;
bool bIsValid = CommonThingsToDoUponEveryMSLCall(SharedConnectionDataSource, true, false, out bIsMedisoft, out Credential);
if (!bIsValid)
return apikey;
// Try To Fetch the UserApikey
bool bErrorOccured = true;
string UserApiKey = GetUserApiKeyForPractice(bIsMedisoft, Credential, DataBaseNameOrDataSetName, out bErrorOccured);
if (bErrorOccured)
{
Logger.Error("Database Error Occured fetching UserApiKey - Mobile About Dialog cannot continue for DataSetorDataBaseName {0}", DataBaseNameOrDataSetName);
return apikey;
}
// To Do: UserApiKey could not match with the current host, if that ever happens,
// we should ideally re-register and not retrieve the PIN, because now the systems are out of sync
// (TBD)
// If there is no UserApiKey already in the System,
// it means we must register this practice as * new *
if (String.IsNullOrEmpty(UserApiKey))
{
string strApiKey;
string strPin;
bool bSuccess = RegistrationWrapper.RegisterNewPractice(PracticeName, bIsMedisoft, out strApiKey, out strPin);
if (bSuccess)
{
Logger.Debug("Retrieved new UserApiKey {0} and Pin {1}", strApiKey, strPin);
// Set the Service State
PlutoService.state = RegistrationWrapper.HostGUIDstate.exists;
// Save the UserApiKey in the DB (if successful save, then continue to reload user DB Connections)
// and only then assign out the api key! ~if it didn't save in the db it shouldn't show on the dialog
if (SetUserApiKeyForPractice(bIsMedisoft, Credential, DataBaseNameOrDataSetName, strApiKey))
{
apikey.UserApiKey = strApiKey;
apikey.UserPin = strPin;
// Reload the UserDB Cache
ReloadUserDBConnectionForSharedCredential(Credential, bIsMedisoft);
}
else
{
Logger.Error("Database Error Occured saving UserApiKey - Mobile About Dialog cannot continue");
}
return apikey;
}
}
else
{
// Practice already registered! So just retrieve the pin for the UserApikey and we are done
string Pin = RegistrationWrapper.RetrievePinForUserApiKey(UserApiKey);
if (!String.IsNullOrEmpty(Pin))
{
apikey.UserApiKey = UserApiKey;
apikey.UserPin = Pin;
Logger.Debug("MobileAboutDialogCalled() Retrieving Pin:{0} for UserApiKey:{1}", Pin, UserApiKey);
}
else
{
Logger.Error("Failed to retrieve Pin - Mobile About Dialog cannot continue");
}
return apikey;
}
}
catch (Exception e) { Logger.Error("MobileAboutDialogCalled() Error", e); }
return apikey;
}
/// <summary>
/// Called upon every lytec/medisoft launch. Currently doesn't do very much. (It was kind of
/// intended for Registration Purposes).
/// </summary>
/// <param name="SharedConnectionDataSource"></param>
/// <param name="RegisteredName"></param>
/// <returns></returns>
public virtual bool ProductSetupCompleted(string SharedConnectionDataSource, string RegisteredName)
{
Logger.Debug("called with SharedDataSource: {0}, RegisteredName: {1}", SharedConnectionDataSource, RegisteredName);
try
{
// Perform this for all MSL Entry Calls * for Sanity *
bool bIsMedisoft = false;
IConnectDb Credential = null;
CommonThingsToDoUponEveryMSLCall(SharedConnectionDataSource, true, true, out bIsMedisoft, out Credential);
// Always return true, Medisoft/Lytec Checking that it can connect to this service expects
// a true back, if it doesn't it will hinder the CheckConnectivity Test at step 1,
// not allowing the real step 2 and step 3 to continue
return true;
}
catch (Exception e) { Logger.Error("ProductSetupCompleted() Error", e); }
return false;
}
/// <summary>
/// Practice Name Change Occured
/// </summary>
/// <param name="SharedConnectionDataSource"></param>
/// <param name="NewPracticeName"></param>
/// <returns></returns>
public virtual bool PracticeNameChangeOccured(string SharedConnectionDataSource, string NewPracticeName, string DataBaseNameOrDataSetName)
{
Logger.Debug("called with SharedDataSource: {0}, NewPracticeName: {1}, DataSetOrDBName: {2}", SharedConnectionDataSource, NewPracticeName, DataBaseNameOrDataSetName);
try
{
// Perform this for all MSL Entry Calls * for Sanity *
bool bIsMedisoft = false;
IConnectDb Credential = null;
bool bIsValid = CommonThingsToDoUponEveryMSLCall(SharedConnectionDataSource, true, false, out bIsMedisoft, out Credential);
if (!bIsValid)
return false;
// Try To Fetch the UserApikey
bool bErrorOccured = true;
string UserApiKey = GetUserApiKeyForPractice(bIsMedisoft, Credential, DataBaseNameOrDataSetName, out bErrorOccured);
if (bErrorOccured)
{
Logger.Error("Database Error Occured fetching UserApiKey - PracticeNameChangeOccured cannot continue for DataSetorDataBaseName {0}", DataBaseNameOrDataSetName);
return false;
}
if (!String.IsNullOrEmpty(UserApiKey))
{
// Auto-Retrieve the Pin
string Pin = RegistrationWrapper.RetrievePinForUserApiKey(UserApiKey);
if (!String.IsNullOrEmpty(Pin))
{
Logger.Debug("Retrieved UserApiKey:{0} Pin:{1} for Practice:{2}", UserApiKey, Pin, NewPracticeName);
// Update the Practice Name
bool bSuccess = RegistrationWrapper.UpdatePracticeName(UserApiKey, Pin, NewPracticeName);
return bSuccess;
}
else
{
Logger.Error("Failed to retrieve Pin - PracticeNameChangeOccured cannot continue");
}
}
return false;
}
catch (Exception e) { Logger.Error("PracticeNameChangeOccured() Error", e); }
return false;
}
/// <summary>
/// Check to see if the external IP can be accessed by the McKesson's Mobile Gateway
/// </summary>
/// <param name="SharedConnectionDataSource"></param>
/// <returns></returns>
public virtual bool IsServerReachableFromTheInternet(string SharedConnectionDataSource)
{
Logger.Debug("called with SharedDataSource: {0}", SharedConnectionDataSource);
try
{
// Perform this for all MSL Entry Calls * for Sanity *
bool bIsMedisoft = false;
IConnectDb Credential = null;
bool bIsValid = CommonThingsToDoUponEveryMSLCall(SharedConnectionDataSource, true, false, out bIsMedisoft, out Credential);
if (!bIsValid)
return false;
// Check to see if this server is reachable from the internet
bool bIsReachable = RegistrationWrapper.IsServerReachable();
return bIsReachable;
}
catch (Exception e) { Logger.Error("IsServerReachableFromTheInternet() Error", e); }
return false;
}
/// <summary>
/// Update the Service if needed
/// </summary>
public virtual void UpdateServiceIfNeeded()
{
PlutoService.AppLogInfo("UpdateServiceIfNeeded() called - Will try to Update the Service, if new Service was found online");
// Callback from MSLConnect, to try to update the service,
// we only need a little delay here, let this call return as quickly as possible
AutoUpdate.TryToUpdateIfNeeded(5, false);
}
#endregion
#region Pluto AddOns
/// <summary>
/// Retrieve the Host GUID for this machine
/// </summary>
/// <returns></returns>
public virtual string GetHostSpecGUID()
{
return GetHostGUID().ToString();
}
/// <summary>
/// Retrieve the External Port Set
/// </summary>
/// <returns>a valid port or -1 for none</returns>
public virtual int GetExternalPort()
{
if (PlutoService.IsExtIPandExtPortSet)
return (int) PlutoService.ExternalPort;
else
return -1;
}
/// <summary>
/// Set and reload the External CHannel on a different port
/// </summary>
/// <param name="Port"></param>
/// <returns></returns>
public virtual bool SetExternalPort(int Port)
{
// never tested (coded), but never tested
// must test ReloadExtIPandPortConfiguration() at some point,
// won't get called by Diagnose mobile at this time
return PlutoService.ReloadExtIPandPortConfiguration(Port);
}
/// <summary>
/// Retrieve the latest external IP
/// </summary>
/// <returns></returns>
public virtual string GetExternalIP()
{
if (PlutoService.IsExtIPandExtPortSet)
return PlutoService.ExternalIP.ToString();
else
return IPAddress.None.ToString();
}
/// <summary>
/// Retrieve the latest Internal IP
/// </summary>
/// <returns></returns>
public virtual string GetLocalIP()
{
return PlutoService.InternalIP.ToString();
}
#endregion
#region Pluto Dev AddOns (To Do)
/// <summary>
/// Go thru all the Shared Database Connections and auto-generate a
/// user api key for all practices * good for testing and debugging *
/// this means lytec/medisoft is not needed to create the userapikeys
/// </summary>
public virtual void GenerateApiKeysForPracticesInLoadedSharedCredentials()
{
// TO DO:
}
/// <summary>
/// Add a custom Shared Database Credential Medisoft or Lytec to the system
/// *good for testing and debugging*
/// </summary>
/// <param name="credential"></param>
/// <returns></returns>
public virtual bool AddSharedCredential(ApiKeyNCredential credential)
{
// TO DO:
return false;
}
/// <summary>
/// Retrieve all currently loaded credentials good for support,
/// dev, qa, etc to see what is going on
/// </summary>
/// <returns></returns>
public virtual ApiKeyNCredential[] GetLoadedCredentials()
{
// TO DO:
return null;
}
#endregion
}
}

View File

@@ -0,0 +1,35 @@
namespace Pluto.Api {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using RemObjects.SDK;
using RemObjects.SDK.Types;
using RemObjects.SDK.Server;
using RemObjects.SDK.Server.ClassFactories;
using PlutoServer.MSL;
[RemObjects.SDK.Server.ClassFactories.StandardClassFactory()]
[RemObjects.SDK.Server.Service(Name = "Medication", InvokerClass = typeof(Medication_Invoker), ActivatorClass = typeof(Medication_Activator))]
public class Medication : RemObjects.SDK.Server.Service, IMedication {
private System.ComponentModel.Container components = null;
public Medication() :
base() {
this.InitializeComponent();
}
private void InitializeComponent() {
}
protected override void Dispose(bool aDisposing) {
if(aDisposing) {
if((this.components != null)) {
this.components.Dispose();
}
}
base.Dispose(aDisposing);
}
public virtual MedicationInfo1[] Search(string apiKey, string searchString)
{
return null;
}
}
}

View File

@@ -0,0 +1 @@
1.0.3.8

View File

@@ -0,0 +1,96 @@
namespace Pluto.Api {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using RemObjects.SDK;
using RemObjects.SDK.Types;
using RemObjects.SDK.Server;
using RemObjects.SDK.Server.ClassFactories;
using PlutoServer.MSL;
using PlutoServer.MSL.Connectors;
[RemObjects.SDK.Server.ClassFactories.StandardClassFactory()]
[RemObjects.SDK.Server.Service(Name = "Patient", InvokerClass = typeof(Patient_Invoker), ActivatorClass = typeof(Patient_Activator))]
public class Patient : RemObjects.SDK.Server.Service, IPatient {
private System.ComponentModel.Container components = null;
public Patient() :
base() {
this.InitializeComponent();
}
private void InitializeComponent() {
}
protected override void Dispose(bool aDisposing) {
if(aDisposing) {
if((this.components != null)) {
this.components.Dispose();
}
}
base.Dispose(aDisposing);
}
#region IPatient Members
public virtual PrescribedMedicationInfo1[] GetMedications(string apiKey, int chartId)
{
return null;
}
public virtual AllergyInfo1[] GetAllergies(string apiKey, int chartId)
{
return null;
}
public virtual ProblemInfo1[] GetProblems(string apiKey, int chartId)
{
return null;
}
public virtual ChartInfo1 GetChart(string apiKey, int patientId, int chartId)
{
return null;
}
public virtual VitalSignInfo1[] GetVitalSigns(string apiKey, int patientId, int chartId)
{
return null;
}
public virtual void AddNote(string apiKey, int patientId, int chartId, PatientNoteInfo1 patientNote)
{
return;
}
public virtual PatientNoteInfo1[] GetNotes(string apiKey, int patientId, int chartId)
{
return null;
}
public virtual ProcedureInfo1[] GetProcedures(string apiKey, int chartId)
{
return null;
}
public virtual PatientDetail1 GetPatientDetail(string apiKey, string chartId)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.GetPatientDetail(apiKey, null, chartId, true);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.GetPatientDetail(apiKey, null, chartId, true);
}
MSLSpecific.Logger.Error("Invalid Product");
return null;
}
public virtual string CreatePatient(string apiKey, PatientInfo1 basicPatientInfo)
{
return String.Empty;
}
#endregion
}
}

View File

@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{36D78B93-9ECC-4BF1-852F-10E18B0EB41C}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PlutoServer.MSL</RootNamespace>
<AssemblyName>PlutoServer.MSL</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Target\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Target\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net">
<HintPath>Components\log4net.dll</HintPath>
</Reference>
<Reference Include="RemObjects.InternetPack, Version=7.0.63.1055, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Components\RemObjects.InternetPack.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="RemObjects.SDK, Version=7.0.63.1055, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Components\RemObjects.SDK.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="RemObjects.SDK.Server, Version=7.0.63.1055, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Components\RemObjects.SDK.Server.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="RemObjects.SDK.ZLib, Version=7.0.63.1055, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Components\RemObjects.SDK.ZLib.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Sdaleo, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\3rdParty\Sdaleo\Sdaleo.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Xml" />
<Reference Include="Yaulw">
<HintPath>..\..\3rdParty\Sdaleo\Yaulw.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\PlutoServer\PlutoApi_Events.cs">
<Link>PlutoApi_Events.cs</Link>
</Compile>
<Compile Include="..\PlutoServer\PlutoApi_Intf.cs">
<Link>PlutoApi_Intf.cs</Link>
</Compile>
<Compile Include="..\PlutoServer\PlutoApi_Invk.cs">
<Link>PlutoApi_Invk.cs</Link>
</Compile>
<Compile Include="Authentication_Impl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="AutoUpdate.cs" />
<Compile Include="Billing_Impl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Configuration.cs" />
<Compile Include="Connectors\DBCache.cs" />
<Compile Include="Connectors\DBCacheDataStore.cs" />
<Compile Include="Connectors\ProductType.cs" />
<Compile Include="Connectors\LytecConnector.cs" />
<Compile Include="Connectors\MedisoftConnector.cs" />
<Compile Include="Constants.cs" />
<Compile Include="DEBUGGING_ONLY.cs" />
<Compile Include="Installer.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Installer.Designer.cs">
<DependentUpon>Installer.cs</DependentUpon>
</Compile>
<Compile Include="Medication_Impl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="MSLSpecific_Impl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Patient_Impl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="PlutoService.MSL.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="PlutoService.MSL.Designer.cs">
<DependentUpon>PlutoService.MSL.cs</DependentUpon>
</Compile>
<Compile Include="Practice_Impl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Provider_Impl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="RegistrationWrapper.cs" />
<Compile Include="Schedule_Impl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Connectors\SystemAccessVerifier.cs" />
<Compile Include="Terminology_Impl.cs">
<SubType>Component</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="PlutoService.MSL.resx">
<DependentUpon>PlutoService.MSL.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Properties\licenses.licx" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CrossProduct.Core\CrossProduct.Core.csproj">
<Project>{D6CC42F0-0F08-457F-84D1-44D0D25715F6}</Project>
<Name>CrossProduct.Core</Name>
<Private>True</Private>
</ProjectReference>
<ProjectReference Include="..\RegistrationAPI\RegistrationAPI.csproj">
<Project>{D8974253-F538-4AA6-B567-48B7CD574888}</Project>
<Name>RegistrationAPI</Name>
<Private>True</Private>
</ProjectReference>
<ProjectReference Include="..\TCMPortMapper\TCMPortMapper.csproj">
<Project>{7D79CD16-563E-470E-8042-58863719544A}</Project>
<Name>TCMPortMapper</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="PUBLISH.htm">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectView>ShowAllFiles</ProjectView>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,102 @@
using System.Configuration;
using System;
namespace PlutoServer.MSL {
partial class PlutoService {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Set the Internal Port to use for the internal Channel
/// </summary>
/// <param name="Port">Port To use</param>
private void SetInternalPort(int Port)
{
if (Port > 0 && this.MSLTcpServerChannelInternal.Port != Port)
{
this.MSLTcpServerChannelInternal.Port = Port;
this.MSLTcpServerChannelInternal.TcpServer.Port = Port;
}
}
/// <summary>
/// Set the External Port to use for the external Channel
/// </summary>
/// <param name="Port">Port To use</param>
private void SetExternalPort(int Port)
{
if (Port > 0 && this.MSLTcpServerChannelExternal.Port != Port)
{
this.MSLTcpServerChannelExternal.Port = Port;
this.MSLTcpServerChannelExternal.TcpServer.Port = Port;
}
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
this.MSLBinMessage = new RemObjects.SDK.BinMessage();
this.MSLTcpServerChannelInternal = new RemObjects.SDK.Server.IpTcpServerChannel(this.components);
this.MSLTcpServerChannelExternal = new RemObjects.SDK.Server.IpTcpServerChannel(this.components);
this.aesEncryptionEnvelope = new RemObjects.SDK.AesEncryptionEnvelope();
((System.ComponentModel.ISupportInitialize)(this.MSLTcpServerChannelInternal)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.MSLTcpServerChannelExternal)).BeginInit();
//
// MSLBinMessage
//
this.MSLBinMessage.ContentType = "application/octet-stream";
this.MSLBinMessage.Envelopes.Add(new RemObjects.SDK.MessageEnvelopeItem(this.aesEncryptionEnvelope));
this.MSLBinMessage.SerializerInstance = null;
//
// MSLTcpServerChannelInternal
//
this.MSLTcpServerChannelInternal.Dispatchers.Add(new RemObjects.SDK.Server.MessageDispatcher("bin", this.MSLBinMessage));
this.MSLTcpServerChannelInternal.Port = 1945;
//
//
//
this.MSLTcpServerChannelInternal.TcpServer.Port = 1945;
//
// MSLTcpServerChannelExternal
//
this.MSLTcpServerChannelExternal.Dispatchers.Add(new RemObjects.SDK.Server.MessageDispatcher("bin", this.MSLBinMessage));
this.MSLTcpServerChannelExternal.Port = 0;
//
// aesEncryptionEnvelope
//
this.aesEncryptionEnvelope.EnvelopeMarker = "AES";
this.aesEncryptionEnvelope.Password = "KxHWkkE5PAp4tuTzmPKQF7RUyylMk7VOV8zfYln2w6NZJMOvT3yrXofIJWxJYRSQwAkm8DysTG9k7";
//
// PlutoService
//
this.ServiceName = "PlutoServer.MSL";
((System.ComponentModel.ISupportInitialize)(this.MSLTcpServerChannelInternal)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.MSLTcpServerChannelExternal)).EndInit();
}
#endregion
private RemObjects.SDK.BinMessage MSLBinMessage;
private RemObjects.SDK.Server.IpTcpServerChannel MSLTcpServerChannelInternal;
private RemObjects.SDK.Server.IpTcpServerChannel MSLTcpServerChannelExternal;
private RemObjects.SDK.AesEncryptionEnvelope aesEncryptionEnvelope;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="MSLBinMessage.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 54</value>
</metadata>
<metadata name="MSLTcpServerChannelInternal.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 91</value>
</metadata>
<metadata name="MSLTcpServerChannelExternal.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>229, 55</value>
</metadata>
<metadata name="aesEncryptionEnvelope.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>218, 91</value>
</metadata>
<metadata name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
</root>

View File

@@ -0,0 +1,105 @@
namespace Pluto.Api {
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PlutoServer.MSL;
using PlutoServer.MSL.Connectors;
[RemObjects.SDK.Server.ClassFactories.StandardClassFactory()]
[RemObjects.SDK.Server.Service(Name = "Practice", InvokerClass = typeof(Practice_Invoker), ActivatorClass = typeof(Practice_Activator))]
public class Practice : RemObjects.SDK.Server.Service, IPractice {
private System.ComponentModel.Container components = null;
public Practice() :
base() {
this.InitializeComponent();
}
private void InitializeComponent() {
}
protected override void Dispose(bool aDisposing) {
if(aDisposing) {
if((this.components != null)) {
this.components.Dispose();
}
}
base.Dispose(aDisposing);
}
public virtual PracticeInfo1[] GetPracticeList1(string apiKey)
{
// Not supported for current SystemApiKey Structure.
// Each ApiKey binds to one specific practice
return null;
}
public virtual ProviderInfo1[] GetProviderList1(string apiKey, PracticeInfo1 practiceInfo)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.GetProviderList(apiKey);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.GetProviderList(apiKey);
}
MSLSpecific.Logger.Error("Invalid Product");
return null;
}
#region IPractice Members
public virtual PatientInfo1[] GetPatientList1(string apiKey, string lastName, string firstName, string dateOfBirth)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.GetPatientList(apiKey, lastName, firstName, dateOfBirth);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.GetPatientList(apiKey, lastName, firstName, dateOfBirth);
}
MSLSpecific.Logger.Error("Invalid Product");
return null;
}
public virtual MessageRecipientInfo1[] GetMessageRecipientList(string apiKey)
{
return null;
}
public virtual FacilityInfo1[] GetFacilitiesList1(string apiKey)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.GetFacilitiesList(apiKey);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.GetFacilitiesList(apiKey);
}
MSLSpecific.Logger.Error("Invalid Product");
return null;
}
public virtual ResourceInfo1[] GetResourcesList1(string apiKey)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.GetResourcesList(apiKey);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.GetResourcesList(apiKey);
}
MSLSpecific.Logger.Error("Invalid Product");
return null;
}
#endregion
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Reflection;
namespace PlutoServer.MSL {
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new PlutoService()
};
#if DEBUG
PlutoService s = (PlutoService)ServicesToRun[0];
s.DebugStart(null);
#else
ServiceBase.Run(ServicesToRun);
#endif
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PlutoServer.MSL")]
[assembly: AssemblyDescription("PlutoServer.MSL Service")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("McKesson")]
[assembly: AssemblyProduct("PlutoServer.MSL")]
[assembly: AssemblyCopyright("MckKesson Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("fb1035bf-62b6-4785-aba3-c9cf04917211")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.3.8")]
[assembly: AssemblyFileVersion("1.0.3.8")]

View File

@@ -0,0 +1,6 @@
RemObjects.SDK.Server.IpTcpServerChannel, RemObjects.SDK.Server, Version=7.0.63.1055, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098
RemObjects.SDK.Server.IpTcpServerChannel, RemObjects.SDK.Server, Version=6.0.57.993, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098
RemObjects.SDK.Server.IpTcpServerChannel, RemObjects.SDK.Server, Version=6.0.61.1033, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098
RemObjects.SDK.Server.OlympiaServerSessionManager, RemObjects.SDK.Server, Version=7.0.63.1055, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098
RemObjects.SDK.Server.OlympiaServerSessionManager, RemObjects.SDK.Server, Version=6.0.57.993, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098
RemObjects.SDK.Server.OlympiaServerSessionManager, RemObjects.SDK.Server, Version=6.0.61.1033, Culture=neutral, PublicKeyToken=3df3cad1b7aa5098

View File

@@ -0,0 +1,53 @@
namespace Pluto.Api {
using System;
using RemObjects.SDK;
using RemObjects.SDK.Types;
using RemObjects.SDK.Server;
using RemObjects.SDK.Server.ClassFactories;
using PlutoServer.MSL;
using System.Linq;
[RemObjects.SDK.Server.ClassFactories.StandardClassFactory()]
[RemObjects.SDK.Server.Service(Name = "Provider", InvokerClass = typeof(Provider_Invoker), ActivatorClass = typeof(Provider_Activator))]
public class Provider : RemObjects.SDK.Server.Service, IProvider {
private System.ComponentModel.Container components = null;
public Provider() :
base() {
this.InitializeComponent();
}
private void InitializeComponent() {
}
protected override void Dispose(bool aDisposing) {
if(aDisposing) {
if((this.components != null)) {
this.components.Dispose();
}
}
base.Dispose(aDisposing);
}
#region IProvider Members
public MailboxFolderInfo1[] GetMailboxFoldersInfo(string apiKey, int providerId)
{
return null;
}
public FolderItemInfo1[] GetMailboxItems(string apiKey, MailboxFolderTypeEnum folderType)
{
return null;
}
public MessageInfo1 GetMessage(string apiKey, long messageId)
{
return null;
}
public void SendMessage(string apiKey, MessageInfo1 message)
{
return;
}
#endregion
}
}

View File

@@ -0,0 +1,537 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pluto.Api;
using System.Net;
using PlutoServer.MSL.Connectors;
namespace PlutoServer.MSL
{
public static class RegistrationWrapper
{
// Allow the Registration wrapper to let the Service enter into a different 'disconnected' state
internal static int HasConnectivityErrorCountInARow = 0;
internal static int HasConnectivityErrorCountMaxBeforeStateChange = 10;
internal static string RegistrationHOST = "";
internal static uint RegistrationPORT = 0;
#region Connectivity
/// <summary>
/// Check to make sure we can communicate with the Registration Service.
/// Check the Server's ip & port for connectivity as well as that this
/// computer has connectivity.
/// This way we won't throw any connectivity errors, which is good.
/// </summary>
/// <returns>true, if successfully can connect, false otherwise</returns>
private static bool HasConnectivity()
{
try
{
bool bCanConnect = false;
bool bUseConfiguration = true;
// Try the overwritten Registration Host and Port first, if exists
if (RegistrationHOST != "" && RegistrationPORT > 0)
{
bCanConnect = Yaulw.Net.IPHostHelper.HasConnectivity(RegistrationHOST, RegistrationPORT, 0);
if (bCanConnect)
bUseConfiguration = false;
}
// Else, fall-back on the configuration, if we couldn't connect
if (!bCanConnect)
{
bCanConnect = Yaulw.Net.IPHostHelper.HasConnectivity(Configuration.REGISTRATION_HOST_URL, (uint)Configuration.REGISTRATION_CHANNEL_PORT, 0);
if (bCanConnect)
bUseConfiguration = true;
}
if (bCanConnect)
{
MSLSpecific.Logger.Info("Network Communication successful with the McKesson's Mobile Gateway bUseConfiguration={0}", bUseConfiguration.ToString());
if (bUseConfiguration)
{
IPAddress ip = Yaulw.Net.IPHostHelper.GetIpForHost(Configuration.REGISTRATION_HOST_URL);
RegistrationAPI.API.SetNetworkSettings(ip.ToString(), (uint)Configuration.REGISTRATION_CHANNEL_PORT);
}
else
{
IPAddress ip = Yaulw.Net.IPHostHelper.GetIpForHost(RegistrationHOST);
RegistrationAPI.API.SetNetworkSettings(ip.ToString(), RegistrationPORT);
}
HasConnectivityErrorCountInARow = 0;
}
else
{
// Try to retrieve the latest Host and Port Setting online
try
{
string HostNPortSetOnline = Yaulw.Net.WCHelper.ScreenScrapeFromURL(Configuration.REGISTRATION_HOST_N_PORT_URL);
if (!String.IsNullOrEmpty(HostNPortSetOnline))
{
RegistrationHOST = HostNPortSetOnline.Split(';')[0];
RegistrationPORT = uint.Parse(HostNPortSetOnline.Split(';')[1]);
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("Retrieving Host and Port Setting from REGISTRATION_HOST_N_PORT_URL failed", e);
}
// Try to connection one more time
if (RegistrationHOST != "" && RegistrationPORT > 0)
bCanConnect = Yaulw.Net.IPHostHelper.HasConnectivity(RegistrationHOST, RegistrationPORT, 0);
// if we can connect, we are Golden
if (bCanConnect)
{
MSLSpecific.Logger.Info("Network Communication successful with the McKesson's Mobile Gateway bUseConfiguration=False");
IPAddress ip = Yaulw.Net.IPHostHelper.GetIpForHost(RegistrationHOST);
RegistrationAPI.API.SetNetworkSettings(ip.ToString(), RegistrationPORT);
HasConnectivityErrorCountInARow = 0;
}
else
{
// Connectivity Errors too plentiful - Change the state of the service to reflect that
if (HasConnectivityErrorCountInARow >= HasConnectivityErrorCountMaxBeforeStateChange)
{
MSLSpecific.Logger.Info("Entering no_Connectivity to McKesson's Mobile Gateway state");
PlutoService.state = HostGUIDstate.no_connectivity;
}
else
{
MSLSpecific.Logger.Error("Network Communication unsuccessful with McKesson's Mobile Gateway");
HasConnectivityErrorCountInARow++;
}
}
}
return bCanConnect;
}
catch (Exception e)
{
MSLSpecific.Logger.Error("HasConnectivity() error thrown", e);
}
return false;
}
#endregion
#region Registration Specifics that don't require network
/// <summary>
/// Get a Practice Name with (MCK) in it (for internal usuage)
/// </summary>
/// <param name="PracticeName"></param>
/// <returns></returns>
public static string GetMCKPractice(string PracticeName)
{
return RegistrationAPI.API.GetMcKInternalizedPracticeName(PracticeName);
}
#endregion
#region Update Server
/// <summary>
/// Update Server Internal / External
/// </summary>
/// <param name="internalIP"></param>
/// <param name="externalIP"></param>
/// <param name="Port"></param>
public static void UpdateServerIntExt(IPAddress internalIP, IPAddress externalIP, uint Port)
{
string LocalIP = "";
if (Yaulw.Net.IPHostHelper.IsValidIPv4Address(internalIP, false))
LocalIP = internalIP.ToString();
string ExternalIP = "";
if (Yaulw.Net.IPHostHelper.IsValidIPv4Address(externalIP, false))
ExternalIP = externalIP.ToString();
if ((!String.IsNullOrEmpty(LocalIP) || !String.IsNullOrEmpty(ExternalIP)) || Port > 0)
UpdateServerIntExt(LocalIP, ExternalIP, Port);
else
MSLSpecific.Logger.Info("UpdateServerIntExt was called with invalid parameters. Registration not updated.");
}
/// <summary>
/// Update Server Internal / External (actually does the work)
/// </summary>
/// <param name="internalIP"></param>
/// <param name="externalIP"></param>
/// <param name="Port"></param>
private static void UpdateServerIntExt(string internalIP, string externalIP, uint Port)
{
try
{
if(HasConnectivity())
{
bool bSuccess = RegistrationAPI.API.UpdateServer(MSLSpecific.GetHostGUID(), internalIP, externalIP, Port);
if (bSuccess)
MSLSpecific.Logger.Info("Updating IP Internal/External information occured successfully for Host:{0} LocalIP:{1}, ExternalIP:{2}, Port:{3}", MSLSpecific.GetHostGUID(), internalIP, externalIP, Port);
else
MSLSpecific.Logger.Error("Updating IP Internal/External information failed for Host:{0} LocalIP:{1}, ExternalIP:{2}, Port:{3}", MSLSpecific.GetHostGUID(), internalIP, externalIP, Port);
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("UdateServerIntExt Error Thrown", e);
}
}
/// <summary>
/// Update Server Internal
/// </summary>
/// <param name="internalIP"></param>
/// <param name="Port"></param>
public static void UpdateServerInternal(IPAddress internalIP)
{
string LocalIP = "";
if (Yaulw.Net.IPHostHelper.IsValidIPv4Address(internalIP, false))
LocalIP = internalIP.ToString();
if (!String.IsNullOrEmpty(LocalIP))
UpdateServerInternal(LocalIP);
else
MSLSpecific.Logger.Info("UpdateServerInternal was called with invalid parameters. Registration not updated.");
}
/// <summary>
/// Update Server Internal (actually does the work)
/// </summary>
/// <param name="bLog"></param>
/// <param name="internalIP"></param>
/// <param name="Port"></param>
private static void UpdateServerInternal(string internalIP)
{
try
{
if (HasConnectivity())
{
bool bSuccess = RegistrationAPI.API.UpdateServer(MSLSpecific.GetHostGUID(), internalIP, String.Empty, PlutoService.INTERNAL_CHANNEL_PORT);
if (bSuccess)
MSLSpecific.Logger.Info("Updating IP Internal information occured successfully for Host:{0} LocalIP:{1}, Port:{2}", MSLSpecific.GetHostGUID(), internalIP, PlutoService.INTERNAL_CHANNEL_PORT);
else
MSLSpecific.Logger.Error("Updating IP Internal information failed for Host:{0} LocalIP:{1}, Port:{2}", MSLSpecific.GetHostGUID(), internalIP, PlutoService.INTERNAL_CHANNEL_PORT);
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("UpdateServerInternal Error Thrown", e);
}
}
#endregion
#region Register Update/New Practice
/// <summary>
/// Register New Practice
/// </summary>
/// <param name="PracticeName">Name of Practice</param>
/// <param name="bIsMedisoft">Is Medisoft</param>
/// <param name="strApiKey">out ApiKey</param>
/// <param name="strPin">out Pin</param>
/// <returns>true, if successful, false otherwise</returns>
public static bool RegisterNewPractice(string PracticeName, bool bIsMedisoft, out string strApiKey, out string strPin)
{
strApiKey = "";
strPin = "";
try
{
if (HasConnectivity())
{
// Set up local IP
string LocalIP = "";
if (Yaulw.Net.IPHostHelper.IsValidIPv4Address(PlutoService.InternalIP, false))
LocalIP = PlutoService.InternalIP.ToString();
// Set up external IP and Port
string ExternalIP = "";
uint Port = 0;
if (PlutoService.IsExtIPandExtPortSet)
{
if (Yaulw.Net.IPHostHelper.IsValidIPv4Address(PlutoService.ExternalIP, false))
ExternalIP = PlutoService.ExternalIP.ToString();
Port = PlutoService.ExternalPort;
}
else
{
Port = PlutoService.INTERNAL_CHANNEL_PORT;
}
// Set up Practice Name
if (PlutoService.IsOnMcKessonNetwork)
PracticeName = GetMCKPractice(PracticeName);
// Set up Product Name
string ProductName = ProductType.GetProductName(bIsMedisoft);
// Make the Registration Call
MSLSpecific.Logger.Info("Registering PracticeName:{0}, LocalIP:{1}, ExternalIP:{2}, Port:{3}, ProductName:{4} for Host:{5}", PracticeName, LocalIP, ExternalIP, Port, ProductName, MSLSpecific.GetHostGUID());
bool bSuccess = RegistrationAPI.API.RegisterNewServerPractice(MSLSpecific.GetHostGUID(), PracticeName, LocalIP, ExternalIP, Port, ProductName, out strApiKey, out strPin);
if (bSuccess)
MSLSpecific.Logger.Info("Registering Practice successfully");
else
MSLSpecific.Logger.Error("Registering Practice failed");
return bSuccess;
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("RegisterNewPractice Error Thrown", e);
}
return false;
}
/// <summary>
/// Update Practice Name
/// </summary>
/// <param name="UserApiKey"></param>
/// <param name="Pin"></param>
/// <param name="NewPracticeName"></param>
/// <returns></returns>
public static bool UpdatePracticeName(string UserApiKey, string Pin, string NewPracticeName)
{
try
{
if (HasConnectivity())
{
// Set up Practice Name
if (PlutoService.IsOnMcKessonNetwork)
NewPracticeName = GetMCKPractice(NewPracticeName);
bool bSuccess = RegistrationAPI.API.UpdatePracticeName(UserApiKey, Pin, NewPracticeName);
if (bSuccess)
MSLSpecific.Logger.Info("Updating Practice Name successfully");
else
MSLSpecific.Logger.Error("Updating Practice Name failed");
return bSuccess;
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("UpdatePracticeName Error Thrown", e);
}
return false;
}
#endregion
#region Other Register Methods
/// <summary>
/// Retrieve Pin for UserApiKey
/// </summary>
/// <param name="UserApiKey"></param>
/// <returns></returns>
public static string RetrievePinForUserApiKey(string UserApiKey)
{
try
{
if (HasConnectivity())
{
if (!String.IsNullOrEmpty(UserApiKey))
{
string Pin = RegistrationAPI.API.RetrieveUserApiKeyPin(UserApiKey);
return Pin;
}
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("RetrievePinForUserApiKey Error Thrown", e);
}
return String.Empty;
}
/// <summary>
/// Is this Server reachable online
/// </summary>
/// <returns></returns>
public static bool IsServerReachable()
{
try
{
if (PlutoService.IsOnMcKessonNetwork)
{
MSLSpecific.Logger.Info("This host/server is in WIFI only mode, due to being on the McKesson Network");
PlutoService.AppLogWarning("This is a host/server is in WIFI only mode, due to being on the McKesson Network");
return false;
}
if (!PlutoService.IsExtIPandExtPortSet)
{
MSLSpecific.Logger.Info("This host/server is in WIFI only mode, external connectivity not configured");
PlutoService.AppLogWarning("This is a host/server is in WIFI only mode, external connectivity not configured");
return false;
}
if (HasConnectivity())
{
bool bSuccess = RegistrationAPI.API.IsServerReachable(PlutoService.ExternalIP.ToString(), PlutoService.ExternalPort);
if (bSuccess)
MSLSpecific.Logger.Info("The server/host was reachable (success) on External IP:{0} and Port:{1}", PlutoService.ExternalIP.ToString(), PlutoService.ExternalPort);
else
MSLSpecific.Logger.Error("The server/host was unreachable (failure) on External IP:{0} and Port:{1}", PlutoService.ExternalIP.ToString(), PlutoService.ExternalPort);
return bSuccess;
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("IsServerReachable Error Thrown", e);
}
return false;
}
/// <summary>
/// Is a specific Server reachable online
/// </summary>
/// <param name="bLog"></param>
/// <param name="externalIP"></param>
/// <param name="Port"></param>
/// <returns></returns>
public static bool IsServerReachable(IPAddress externalIP, uint Port)
{
try
{
// Set up external IP
string ExtIP = "";
if (Yaulw.Net.IPHostHelper.IsValidIPv4Address(externalIP, false))
ExtIP = externalIP.ToString();
if (String.IsNullOrEmpty(ExtIP))
{
MSLSpecific.Logger.Info("Invalid External IP passed in");
return false;
}
// Check Port
if (Port <= 0)
{
MSLSpecific.Logger.Info("Invalid Port passed in");
return false;
}
// Check Connectivity
if (HasConnectivity())
{
bool bSuccess = RegistrationAPI.API.IsServerReachable(ExtIP, Port);
if (bSuccess)
MSLSpecific.Logger.Info("The server/host was reachable (success) on External IP:{0} and Port:{1}", ExtIP, Port);
else
MSLSpecific.Logger.Error("The server/host was unreachable (failure) on External IP:{0} and Port:{1}", ExtIP, Port);
return bSuccess;
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error(String.Format("IsServerReachable Error Thrown with ExtIP={0} and Port={1}", externalIP.ToString(), Port.ToString()), e);
}
return false;
}
/// <summary>
/// Retrieve the HostGUID from a Server/Port if that Server Port is running Pluto
/// </summary>
/// <param name="externalIP"></param>
/// <param name="Port"></param>
/// <returns>HostGUID or "" if none found</returns>
public static string RetrieveHostGUIDForServer(IPAddress externalIP, uint Port)
{
try
{
// Set up external IP
string ExtIP = "";
if (Yaulw.Net.IPHostHelper.IsValidIPv4Address(externalIP, false))
ExtIP = externalIP.ToString();
if (String.IsNullOrEmpty(ExtIP))
{
MSLSpecific.Logger.Info("Invalid External IP passed in");
return String.Empty;
}
// Check Port
if (Port <= 0)
{
MSLSpecific.Logger.Info("Invalid Port passed in");
return String.Empty;
}
if(HasConnectivity())
{
string retVal = RegistrationAPI.API.RetrievePlutoHostGUID(externalIP.ToString(), Port);
return retVal;
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("RetrieveHostGUIDForServer Error Thrown", e);
}
return String.Empty;
}
/// <summary>
/// Connectivity / HOST Guid State * Important for Integrity Checking *
/// </summary>
public enum HostGUIDstate
{
exists,
not_exists,
no_connectivity
}
/// <summary>
/// Quick Check to see if our host guid even exists on the server, if it doesn't
/// then no need to call UpdateServer() in any form
/// </summary>
/// <returns></returns>
public static HostGUIDstate DoesServerHostGuidExist()
{
try
{
if (HasConnectivity())
{
bool bExists = RegistrationAPI.API.DoesServerHostGUIDExist(MSLSpecific.GetHostGUID());
if (bExists)
{
MSLSpecific.Logger.Info("HostGuid found on Mobile Gateway Server. Some Practice(s) are registered online");
return HostGUIDstate.exists;
}
else
{
MSLSpecific.Logger.Info("HostGuid not found on Mobile Gateway Server. No Practice is registered online");
return HostGUIDstate.not_exists;
}
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("DoesServerHostGuidExist Error Thrown", e);
}
return HostGUIDstate.no_connectivity;
}
/// <summary>
/// Let the Registration Service know what we have been updated
/// </summary>
/// <param name="version"></param>
public static void ServerHasBeenUpdated(string version)
{
try
{
if (HasConnectivity())
{
RegistrationAPI.API.ServerHasBeenUpdated(MSLSpecific.GetHostGUID(), version);
}
}
catch (Exception e)
{
MSLSpecific.Logger.Error("ServerHasBeenUpdated Error Thrown", e);
}
}
#endregion
}
}

View File

@@ -0,0 +1,68 @@
namespace Pluto.Api {
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PlutoServer.MSL;
using System;
using PlutoServer.MSL.Connectors;
[RemObjects.SDK.Server.ClassFactories.StandardClassFactory()]
[RemObjects.SDK.Server.Service(Name = "Schedule", InvokerClass = typeof(Schedule_Invoker), ActivatorClass = typeof(Schedule_Activator))]
public class Schedule : RemObjects.SDK.Server.Service, ISchedule {
private System.ComponentModel.Container components = null;
public Schedule() :
base() {
this.InitializeComponent();
}
private void InitializeComponent() {
}
protected override void Dispose(bool aDisposing) {
if(aDisposing) {
if((this.components != null)) {
this.components.Dispose();
}
}
base.Dispose(aDisposing);
}
public virtual AppointmentInfo1[] GetAppointments1(string apiKey, ProviderInfo1[] providerInfo, ResourceInfo1[] resourceInfo, System.DateTime startDate, System.DateTime endDate)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.GetAppointments(apiKey, providerInfo, resourceInfo, startDate, endDate);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.GetAppointments(apiKey, providerInfo, resourceInfo, startDate, endDate);
}
MSLSpecific.Logger.Error("Invalid Product");
return null;
}
public virtual AppointmentDetail1 GetAppointmentDetail1(string apiKey, int ApptID,bool bCalculateBalance)
{
if (ProductType.IsKeyLytec(apiKey))
{
return LytecConnector.GetAppointmentDetail(apiKey, ApptID, bCalculateBalance);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
return MedisoftConnector.GetAppointmentDetail(apiKey, ApptID, bCalculateBalance);
}
MSLSpecific.Logger.Error("Invalid Product");
return null;
}
#region ISchedule Members
public bool AddAppointment1(string apiKey, AppointmentInfo1 appointmentInfo) {
return true;
}
#endregion
}
}

View File

@@ -0,0 +1,59 @@
namespace Pluto.Api {
using System;
using RemObjects.SDK;
using RemObjects.SDK.Types;
using RemObjects.SDK.Server;
using RemObjects.SDK.Server.ClassFactories;
using System.Linq;
using System.Collections.Generic;
using PlutoServer.MSL;
using PlutoServer.MSL.Connectors;
[RemObjects.SDK.Server.ClassFactories.StandardClassFactory()]
[RemObjects.SDK.Server.Service(Name = "Terminology", InvokerClass = typeof(Terminology_Invoker), ActivatorClass = typeof(Terminology_Activator))]
public class Terminology : RemObjects.SDK.Server.Service, ITerminology {
private System.ComponentModel.Container components = null;
public Terminology() :
base() {
this.InitializeComponent();
}
private void InitializeComponent() {
}
protected override void Dispose(bool aDisposing) {
if(aDisposing) {
if((this.components != null)) {
this.components.Dispose();
}
}
base.Dispose(aDisposing);
}
#region ITerminology Members
public TerminologyInfo1[] SearchTerminology(string apiKey, string searchString, TerminologySearchTypeEnum searchType, TerminologyDomainEnum terminologyDomain, string chartID)
{
bool bDoDiagnosisSearch = (terminologyDomain == TerminologyDomainEnum.DiagnosesAll);
bool bDoProceduresSearch = (terminologyDomain == TerminologyDomainEnum.ProceduresAll);
if (ProductType.IsKeyLytec(apiKey))
{
if(bDoDiagnosisSearch)
return LytecConnector.GetDiagnosisList(apiKey, searchString);
if(bDoProceduresSearch)
return LytecConnector.GetProceduresList(apiKey, chartID, searchString);
}
else if (ProductType.IsKeyMedisoft(apiKey))
{
if (bDoDiagnosisSearch)
return MedisoftConnector.GetDiagnosisList(apiKey, searchString);
if (bDoProceduresSearch)
return MedisoftConnector.GetProceduresList(apiKey, chartID, searchString);
}
// Something Failed
return null;
}
#endregion
}
}

View File

@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v2.0.50727"/>
</startup>
<appSettings>
<add key="REGISTRATION_HOST_N_PORT_URL" value="http://ppsmobile.mckesson.com/mobile1/REGURL.htm" />
<add key="REGISTRATION_HOST_URL" value="ppsmobile.mckesson.com" />
<add key="REGISTRATION_CHANNEL_PORT" value="443" />
<add key="CHECK_VERSION_URL" value="http://ppsmobile.mckesson.com/mobile1/PUBLISH.htm" />
<add key="DOWNLOAD_SETUP_URL" value="http://ppsmobile.mckesson.com/mobile1/Setup.exe" />
<add key="DOWNLOAD_MINISETUP_URL" value="http://ppsmobile.mckesson.com/mobile1/SetupMini.exe" />
<add key="DETERMINE_EXTERNAL_IP_ADDRESS_URL" value="http://ppsmobile.mckesson.com/GetIP/default.aspx" />
</appSettings>
</configuration>

View File

@@ -0,0 +1,14 @@
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Debug\ResolveAssemblyReference.cache
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Debug\PlutoServer.MSL.PlutoService.resources
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Debug\ResGen.read.1.tlog
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Debug\ResGen.write.1.tlog
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Debug\PlutoServer.MSL.exe.licenses
C:\Users\Administrator\Projects\Pluto\Server\Target\Debug\MLServer.config
C:\Users\Administrator\Projects\Pluto\Server\Target\Debug\PlutoServer.MSL.exe.config
C:\Users\Administrator\Projects\Pluto\Server\Target\Debug\PlutoServer.MSL.exe
C:\Users\Administrator\Projects\Pluto\Server\Target\Debug\PlutoServer.MSL.pdb
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Debug\PlutoServer.MSL.exe
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Debug\PlutoServer.MSL.pdb
\\192.168.2.7\bin\FTP-Private\Pluto\Server\Target\Debug\PlutoServer.MSL.exe.config
\\192.168.2.7\bin\FTP-Private\Pluto\Server\PlutoServer.MSL\obj\x86\Debug\PlutoServer.MSL.exe
\\192.168.2.7\bin\FTP-Private\Pluto\Server\PlutoServer.MSL\obj\x86\Debug\PlutoServer.MSL.pdb

View File

@@ -0,0 +1,14 @@
C:\Users\Administrator\Projects\Pluto\Server\TargetRelease\PlutoServer.MSL.exe.config
C:\Users\Administrator\Projects\Pluto\Server\TargetRelease\PlutoServer.MSL.exe
C:\Users\Administrator\Projects\Pluto\Server\TargetRelease\PlutoServer.MSL.pdb
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Release\ResolveAssemblyReference.cache
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Release\PlutoServer.MSL.PlutoService.resources
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Release\ResGen.read.1.tlog
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Release\ResGen.write.1.tlog
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Release\PlutoServer.MSL.exe.licenses
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Release\PlutoServer.MSL.exe
C:\Users\Administrator\Projects\Pluto\Server\PlutoServer.MSL\obj\x86\Release\PlutoServer.MSL.pdb
C:\Users\Administrator\Projects\Pluto\Server\Target\Release\PlutoServer.MSL.exe.config
C:\Users\Administrator\Projects\Pluto\Server\Target\Release\PlutoServer.MSL.exe
C:\Users\Administrator\Projects\Pluto\Server\Target\Release\PlutoServer.MSL.pdb
C:\Users\Administrator\Projects\Pluto\Server\Target\Release\MLServer.config