From 24fdfe7f5e20ed34f431b46cdb595d6b85d194bd Mon Sep 17 00:00:00 2001 From: Jim Norman Date: Tue, 29 Aug 2006 18:26:30 +0000 Subject: [PATCH] Feature added: Allow user to change the persistence location --- CASA/gui/CASAManager.csproj | 5 + CASA/gui/CasaMain.cs | 106 ++- CASA/gui/Common.cs | 13 + CASA/gui/DbgFileChooser.cs | 78 +++ CASA/gui/FileChooser.cs | 60 +- CASA/gui/images/casa.glade | 647 +++++++++++++++++- CASA/micasad/cache/SecretStore.cs | 97 ++- CASA/micasad/common/SessionManager.cs | 34 +- CASA/micasad/lib/Novell.CASA.Common.csproj | 5 + .../micasad/lib/common/ChangePersistentDir.cs | 42 ++ .../lib/communication/MiCasaRequestReply.cs | 1 + CASA/micasad/micasad.csproj | 5 + CASA/micasad/verbs/ObjectSerialization.cs | 36 +- .../windows/vs_solutions/CASAInstall/CASA.ncb | Bin 642048 -> 642048 bytes .../windows/vs_solutions/CASAInstall/CASA.suo | Bin 52224 -> 55296 bytes .../vs_solutions/CASAInstall/CASA.vdproj | 73 +- CASA/policy/PolicyImpl.cs | 26 +- 17 files changed, 1111 insertions(+), 117 deletions(-) create mode 100644 CASA/gui/DbgFileChooser.cs create mode 100644 CASA/micasad/lib/common/ChangePersistentDir.cs diff --git a/CASA/gui/CASAManager.csproj b/CASA/gui/CASAManager.csproj index 88df2db2..ad8001fb 100644 --- a/CASA/gui/CASAManager.csproj +++ b/CASA/gui/CASAManager.csproj @@ -185,6 +185,11 @@ SubType = "Code" BuildAction = "Compile" /> + + /// ******************************************************************** + /// Import/export handlers + /// ******************************************************************** + /// public void on_exportSecrets_activate(object obj, EventArgs args) { @@ -2099,6 +2129,61 @@ namespace Novell.CASA.GUI } + public void on_buttonChooseDirectory_clicked(object obj, EventArgs args) + { + //Choose directory for persistent storage + FileChooser fc = new FileChooser(FileChooser.ACTION_CHOOSE_DIR); + string sDirectory = fc.GetFile(entryStorageDirectory.Text, null); + + // show the user the directory choosen + if (sDirectory != null) + { + if (Directory.Exists(sDirectory)) + { + entryStorageDirectory.Text = sDirectory; + } + else + { + CommonGUI.DisplayMessage(Gtk.MessageType.Error, "Directory does not exist\r\n" + sDirectory); + } + } + } + + private bool MoveMiCASAFiles(string sOldDirectory, string sNewDirectory) + { + if ((sOldDirectory != null) && (sNewDirectory != null)) + { + if (!sOldDirectory.Equals(sNewDirectory)) + { + // get file list for .miCASAFiles + string[] files = Directory.GetFiles(sOldDirectory, ".miCASA*"); + if (files != null) + { + // first copy them to the new location + foreach ( string file in files) + { + string sFileName = file.Substring(file.LastIndexOf("\\") + 1); + File.Copy(file, sNewDirectory + sFileName, true); + } + + // TODO: tell our daemon/service we changed the location + ChangePersistentDir cpd = new ChangePersistentDir(sOldDirectory, sNewDirectory); + cpd = (ChangePersistentDir)MiCasaRequestReply.Send(MiCasaRequestReply.VERB_CHANGE_PERSIST_DIR, cpd); + + // now delete them from the old directory + foreach (string file in files) + { + File.Delete(file); + } + + return true; + } + } + } + + return false; + } + /// /// ******************************************************************** /// private void HandleQuit() @@ -2153,7 +2238,12 @@ namespace Novell.CASA.GUI Logger.DbgLog("GUI:CasaMain.OnWindowMainDeleted() - END"); } - + + public void on_debug_file_chooser_activate(object obj, EventArgs args) + { + DbgFileChooser dbf = new DbgFileChooser(); + dbf.Run(); + } } } diff --git a/CASA/gui/Common.cs b/CASA/gui/Common.cs index 0a3e1c1d..69965e73 100644 --- a/CASA/gui/Common.cs +++ b/CASA/gui/Common.cs @@ -138,8 +138,11 @@ public class Common public static string ARG_SHOW_TRAY_ICON = "-tray"; public static string ARG_DEBUG = "-debug"; + // config settings public static string CONFIG_RUN_IN_TRAY = "RunInTray"; public static string DISPLAY_CASA_MANAGER = "DisplayCasaManagerOnClick"; + public static string CONFIG_PERSISTENT_DIRECTORY = "PersistentDirectory"; + ///############################################################# @@ -439,6 +442,16 @@ public class Common return Environment.GetEnvironmentVariable("USERPROFILE"); } + internal static string GetUserPersistentDir(Config config) + { + return (config.GetConfigSetting(CONFIG_PERSISTENT_DIRECTORY, GetUserHomeDir())); + } + + internal static void SetUserPersistentDir(Config config, string sNewDirectory) + { + config.SetConfigSetting(CONFIG_PERSISTENT_DIRECTORY, sNewDirectory); + config.WriteConfig(); + } } } diff --git a/CASA/gui/DbgFileChooser.cs b/CASA/gui/DbgFileChooser.cs new file mode 100644 index 00000000..a0e3c873 --- /dev/null +++ b/CASA/gui/DbgFileChooser.cs @@ -0,0 +1,78 @@ +using System; + +namespace Novell.CASA.GUI +{ + /// + /// Summary description for DbgFileChooser. + /// + public class DbgFileChooser + { + #region widgets + [Glade.Widget] + Gtk.Dialog dialogDebugFileChooser; + + [Glade.Widget] + Gtk.Entry entrySaveFile, + entryOpenFile, + entryChooseDirectory; + + + #endregion + + public DbgFileChooser() + { + + } + + public void Run() + { + Glade.XML gxmlTemp = new Glade.XML (Common.GladeFile, "dialogDebugFileChooser", null); + gxmlTemp.Autoconnect (this); + //dialogDebugFileChooser.TransientFor = windowMain; + } + + public void on_buttonSaveFile_clicked(object obj, EventArgs args) + { + FileChooser fc = new FileChooser(FileChooser.ACTION_SAVE); + string sFile = fc.GetFile(null, null); + if (sFile != null) + { + entrySaveFile.Text = sFile; + } + else + { + entrySaveFile.Text = "Null"; + } + + } + + public void on_buttonOpenFile_clicked(object obj, EventArgs args) + { + FileChooser fc = new FileChooser(FileChooser.ACTION_OPEN); + string sFile = fc.GetFile(null, null); + if (sFile != null) + { + entryOpenFile.Text = sFile; + } + else + { + entryOpenFile.Text = "Null"; + } + } + public void on_buttonChooseDirectory_clicked(object obj, EventArgs args) + { + FileChooser fc = new FileChooser(FileChooser.ACTION_CHOOSE_DIR); + string sFile = fc.GetFile(null, null); + if (sFile != null) + { + entryChooseDirectory.Text = sFile; + } + else + { + entryChooseDirectory.Text = "Null"; + } + } + + + } +} diff --git a/CASA/gui/FileChooser.cs b/CASA/gui/FileChooser.cs index 2ba65b3e..8a4b7821 100644 --- a/CASA/gui/FileChooser.cs +++ b/CASA/gui/FileChooser.cs @@ -25,6 +25,7 @@ namespace Novell.CASA.GUI private int m_iAction = 1; public const int ACTION_OPEN = 1; public const int ACTION_SAVE = 2; + public const int ACTION_CHOOSE_DIR = 3; Thread tChooserThread = null; @@ -72,6 +73,8 @@ namespace Novell.CASA.GUI else m_currentDirectory = dir; + if (!m_currentDirectory.EndsWith(m_pathSeparator)) + m_currentDirectory = m_currentDirectory + m_pathSeparator; //if (m_currentDirectory.EndsWith(m_pathSeparator)) // m_currentDirectory = m_currentDirectory.Substring(0, m_currentDirectory.Length - 1); @@ -92,16 +95,18 @@ namespace Novell.CASA.GUI m_hintFile = sHintFile; } - DoWork(); + DisplayChooser(); if (m_sFileSelected != null) - return m_currentDirectory + m_pathSeparator + m_sFileSelected; + { + return m_currentDirectory + m_sFileSelected; + } else return null; } - private void DoWork() + private void DisplayChooser() { // display chooser @@ -140,7 +145,13 @@ namespace Novell.CASA.GUI Glade.XML gxmlTemp = new Glade.XML(Common.GladeFile, "dialogFileChooser", null); gxmlTemp.Autoconnect(this); - if (m_iAction == ACTION_OPEN) + if (m_iAction == ACTION_CHOOSE_DIR) + { + entrySelectedFile.Visible = false; + dialogFileChooser.Title = "Select a directory"; + + } + else if (m_iAction == ACTION_OPEN) { buttonNewFolder.Visible = false; entrySelectedFile.Sensitive = false; @@ -208,11 +219,14 @@ namespace Novell.CASA.GUI ts.AppendValues(new Gdk.Pixbuf (Common.IMAGE_PATH + "folder.png"), dirs[i].Name, "", "File folder"); } - FileInfo[] files = dirInfo.GetFiles(); - for (int i=0; i 0)) + m_sFileSelected = entrySelectedFile.Text + m_pathSeparator; + else + m_sFileSelected = ""; + + // destroy dialog + dialogFileChooser.Destroy(); + m_bFileChoosing = false; + } + else + { + ProcessSelection(); + } } diff --git a/CASA/gui/images/casa.glade b/CASA/gui/images/casa.glade index 5b45180d..46f69153 100644 --- a/CASA/gui/images/casa.glade +++ b/CASA/gui/images/casa.glade @@ -56,7 +56,7 @@ True - + True gtk-new 1 @@ -78,7 +78,7 @@ - + True gtk-new 1 @@ -99,7 +99,7 @@ - + True gtk-new 1 @@ -125,7 +125,7 @@ - + True gtk-refresh 1 @@ -152,7 +152,7 @@ - + True gtk-dialog-authentication 1 @@ -173,7 +173,7 @@ - + True gtk-open 1 @@ -194,7 +194,7 @@ - + True gtk-delete 1 @@ -221,7 +221,7 @@ - + True gtk-floppy 1 @@ -242,7 +242,7 @@ - + True gtk-open 1 @@ -270,7 +270,7 @@ - + True gtk-quit 1 @@ -306,7 +306,7 @@ - + True gtk-zoom-fit 1 @@ -327,7 +327,7 @@ - + True gtk-jump-to 1 @@ -348,7 +348,7 @@ - + True gtk-copy 1 @@ -376,7 +376,7 @@ - + True gtk-delete 1 @@ -410,7 +410,7 @@ True - + True gtk-execute 1 @@ -432,7 +432,7 @@ - + True gtk-execute 1 @@ -453,7 +453,7 @@ - + True gtk-execute 1 @@ -474,7 +474,7 @@ - + True gtk-execute 1 @@ -495,7 +495,7 @@ - + True gtk-execute 1 @@ -520,7 +520,7 @@ - + True gtk-revert-to-saved 1 @@ -547,7 +547,7 @@ - + True gtk-preferences 1 @@ -581,7 +581,7 @@ - + True gtk-add 1 @@ -602,7 +602,7 @@ - + True gtk-remove 1 @@ -621,6 +621,21 @@ + + + True + Debug File Chooser + True + + + + + + + True + + + True @@ -653,7 +668,7 @@ - + True gtk-help 1 @@ -680,7 +695,7 @@ - + True gtk-dialog-info 1 @@ -4729,7 +4744,140 @@ prompted for the Master Password at startup. 0 - True + False + True + + + + + + 6 + True + 0 + 0.5 + GTK_SHADOW_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + 4 + True + False + 0 + + + + True + False + 0 + + + + True + False + 0 + + + + True + True + True + True + 0 + + True + * + False + + + 3 + True + True + + + + + + True + True + GTK_RELIEF_NORMAL + False + + + + + True + gtk-find + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + + + True + <b> miCASA Storage Location </b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False True @@ -4858,7 +5006,7 @@ prompted for the Master Password at startup. 0 - True + False True @@ -12999,4 +13147,449 @@ to encrypt this file + + True + CASA - Debug File chooser + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + True + True + True + CASAicons.ico + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-help + True + GTK_RELIEF_NONE + True + -11 + + + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + -7 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 0 + + + + True + False + 0 + + + + True + False + 0 + + + + True + gtk-dialog-authentication + 6 + 0.5 + 0.5 + 0 + 0 + + + 4 + False + True + + + + + 4 + True + True + + + + + + True + False + 0 + + + + True + <b>Debug file Chooser</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 4 + False + False + + + + + + True + This will be removed + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 4 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + 6 + True + 0 + 0.5 + GTK_SHADOW_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + 3 + 3 + False + 0 + 0 + + + + True + Save File + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + Open File + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + Choose Directory + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 1 + 2 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 2 + 3 + + + + + + + True + True + Save As... + True + GTK_RELIEF_NORMAL + True + + + + 2 + 3 + 0 + 1 + fill + + + + + + + True + True + Open file + True + GTK_RELIEF_NORMAL + True + + + + 2 + 3 + 1 + 2 + fill + + + + + + + True + True + Choose Dir + True + GTK_RELIEF_NORMAL + True + + + + 2 + 3 + 2 + 3 + fill + + + + + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + diff --git a/CASA/micasad/cache/SecretStore.cs b/CASA/micasad/cache/SecretStore.cs index 0b35f64e..65bcb96b 100644 --- a/CASA/micasad/cache/SecretStore.cs +++ b/CASA/micasad/cache/SecretStore.cs @@ -34,6 +34,8 @@ using sscs.constants; using sscs.lss; using sscs.crypto; +using Novell.CASA.CASAPolicy; + namespace sscs.cache { class SecretStore @@ -54,6 +56,7 @@ namespace sscs.cache private LocalStorage lss = null; bool bIsStorePersistent = false; + string m_persistenceDirectory = null; private MPFileWatcher mpWatcher = null; @@ -86,17 +89,18 @@ namespace sscs.cache ssMutex = new Mutex(); + + // start a MPFileWatcher if necessary if (mpWatcher == null) { - // make sure HomeDirectory exists - String sHomeDir = GetUserHomeDirectory(); - if (sHomeDir != null && sHomeDir.Length > 0) + // make sure Persistence Directory exists + String sPersistentDir = GetPersistenceDirectory(); + if (sPersistentDir != null && sPersistentDir.Length > 0) { - mpWatcher = new MPFileWatcher(GetUserHomeDirectory(), ConstStrings.MICASA_PASSCODE_BY_MASTERPASSWD_FILE); + mpWatcher = new MPFileWatcher(GetPersistenceDirectory(), ConstStrings.MICASA_PASSCODE_BY_MASTERPASSWD_FILE); } } - } internal bool IsStorePersistent() @@ -177,17 +181,19 @@ namespace sscs.cache { CSSSLogger.DbgLog("StartPersistenceByDesktopPasswd - Called"); - // make sure we have a user home directory - if (GetUserHomeDirectory() == null || GetUserHomeDirectory().Length < 1) + // make sure we have a Persistence Directory + if (GetPersistenceDirectory() == null || GetPersistenceDirectory().Length < 1) { - CSSSLogger.DbgLog("StartPersistenceByDesktopPasswd - No Home directory yet"); + CSSSLogger.DbgLog("StartPersistenceByDesktopPasswd - No Peristence directory yet"); + CSSSLogger.DbgLog("Directory: [" + GetPersistenceDirectory() + "]"); return false; } else { - if (!Directory.Exists(GetUserHomeDirectory())) + if (!Directory.Exists(GetPersistenceDirectory())) { - CSSSLogger.DbgLog("StartPersistenceByDesktopPasswd - Home directory is not created yet"); + CSSSLogger.DbgLog("StartPersistenceByDesktopPasswd - Peristence directory is not created yet"); + CSSSLogger.DbgLog("Directory: " + GetPersistenceDirectory() + "]"); return false; } } @@ -777,33 +783,82 @@ namespace sscs.cache return user.GetUserHomeDir(); } + internal string GetPersistenceDirectory() + { + if (m_persistenceDirectory != null) + { + if (Directory.Exists(m_persistenceDirectory)) + return m_persistenceDirectory; + else + return null; + } + else + { + // the user might have set a different one + // load the policy file and check. + UIPol uiPolicy = (UIPol)ICASAPol.GetPolicy(CASAPolType.UI_POL, GetUserHomeDirectory()); + string sDir = uiPolicy.GetConfigSetting("PersistentDirectory"); + if ((sDir != null) && (sDir.Length > 0)) + { + m_persistenceDirectory = sDir; + return m_persistenceDirectory; + } + } + + return GetUserHomeDirectory(); + } + + internal bool SetPeristenceDirectory(string sNewDirectory) + { + if (Directory.Exists(sNewDirectory)) + { + // reset the FileWatcher + if (mpWatcher != null) + { + mpWatcher.pauseWatcher(); + mpWatcher = new MPFileWatcher(sNewDirectory, ConstStrings.MICASA_PASSCODE_BY_MASTERPASSWD_FILE); + mpWatcher.resumeWatcher(); + } + + m_persistenceDirectory = sNewDirectory; + return true; + } + + return false; + + } + internal string GetKeyFilePath() { - string homeDir = GetUserHomeDirectory(); - return homeDir + ConstStrings.MICASA_KEY_FILE; + string persistDir = GetPersistenceDirectory(); + return persistDir + ConstStrings.MICASA_KEY_FILE; } internal string GetPasscodeByDesktopFilePath() { - string homeDir = GetUserHomeDirectory(); - return homeDir + ConstStrings.MICASA_PASSCODE_BY_DESKTOP_FILE; + string persistDir = GetPersistenceDirectory(); + return persistDir + ConstStrings.MICASA_PASSCODE_BY_DESKTOP_FILE; } internal string GetPasscodeByMasterPasswdFilePath() { - string homeDir = GetUserHomeDirectory(); - return homeDir + ConstStrings.MICASA_PASSCODE_BY_MASTERPASSWD_FILE; + string persistDir = GetPersistenceDirectory(); + return persistDir + ConstStrings.MICASA_PASSCODE_BY_MASTERPASSWD_FILE; } internal string GetPersistenceFilePath() { - string homeDir = GetUserHomeDirectory(); - return homeDir + ConstStrings.MICASA_PERSISTENCE_FILE; + string persistDir = GetPersistenceDirectory(); + return persistDir + ConstStrings.MICASA_PERSISTENCE_FILE; } internal string GetValidationFilePath() { - string homeDir = GetUserHomeDirectory(); - return homeDir + ConstStrings.MICASA_VALIDATION_FILE; + string persistDir = GetPersistenceDirectory(); + return persistDir + ConstStrings.MICASA_VALIDATION_FILE; } + + + + internal byte[] GetSecrets(string sEncryptionString) { if (lss != null) @@ -848,5 +903,7 @@ namespace sscs.cache lss.AddXMLSecretsToStore(doc); } } + + } } diff --git a/CASA/micasad/common/SessionManager.cs b/CASA/micasad/common/SessionManager.cs index a72239d3..14494a7d 100644 --- a/CASA/micasad/common/SessionManager.cs +++ b/CASA/micasad/common/SessionManager.cs @@ -101,20 +101,26 @@ namespace sscs.common try { mutex.WaitOne(); - SecretStore ss = GetUserSecretStore(userId); - ss.DecrRefCount(); - - // We must keep the cache alive, and destroy it on - // a logout event - - //if( 0 == ss.refCount ) - if (destroySession) + try { - CSSSLogger.DbgLog("Removing the user session of " + userId.GetUID()); - ss.CommitStore(); - sessionTable.Remove(userId); - } + SecretStore ss = GetUserSecretStore(userId); + ss.DecrRefCount(); + // We must keep the cache alive, and destroy it on + // a logout event + + //if( 0 == ss.refCount ) + if (destroySession) + { + CSSSLogger.DbgLog("Removing the user session of " + userId.GetUID()); + ss.CommitStore(); + sessionTable.Remove(userId); + } + } + catch (Exception e) + { + CSSSLogger.DbgLog(e.ToString()); + } mutex.ReleaseMutex(); return true; } @@ -193,7 +199,9 @@ namespace sscs.common internal static void ListActiveUserSessions() { CSSSLogger.ExecutionTrace(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + CSSSLogger.DbgLog("List Active Sessions"); mutex.WaitOne(); + CSSSLogger.DbgLog("List Active Sessions2"); IDictionaryEnumerator etor = sessionTable.GetEnumerator(); int i = 0; @@ -206,7 +214,9 @@ namespace sscs.common Console.WriteLine((((SecretStore)(etor.Value)).secretStoreName + ":" + ((SecretStore)(etor.Value)).refCount); */ } + CSSSLogger.DbgLog("List Active Sessions3"); mutex.ReleaseMutex(); + CSSSLogger.DbgLog("List Active Sessions4"); } diff --git a/CASA/micasad/lib/Novell.CASA.Common.csproj b/CASA/micasad/lib/Novell.CASA.Common.csproj index c849869c..f8b4257a 100644 --- a/CASA/micasad/lib/Novell.CASA.Common.csproj +++ b/CASA/micasad/lib/Novell.CASA.Common.csproj @@ -98,6 +98,11 @@ SubType = "Code" BuildAction = "Compile" /> + + /// Summary description for ChangePersistentDir. + /// + /// + [Serializable] + public class ChangePersistentDir + { + private string m_sOldDirectory; + private string m_sNewDirectory; + private string m_sErrorMessage = ""; + + public ChangePersistentDir(string sOldDirectory, string sNewDirectory) + { + m_sOldDirectory = sOldDirectory; + m_sNewDirectory = sNewDirectory; + } + + public string GetOldDirectory() + { + return m_sOldDirectory; + } + + public string GetNewDirectory() + { + return m_sNewDirectory; + } + + public void SetErrorMessage(string sMessage) + { + m_sErrorMessage = sMessage; + } + + public string GetErrorMessage() + { + return m_sErrorMessage; + } + } +} diff --git a/CASA/micasad/lib/communication/MiCasaRequestReply.cs b/CASA/micasad/lib/communication/MiCasaRequestReply.cs index 4d5e1bd0..8659b241 100644 --- a/CASA/micasad/lib/communication/MiCasaRequestReply.cs +++ b/CASA/micasad/lib/communication/MiCasaRequestReply.cs @@ -58,6 +58,7 @@ namespace Novell.CASA.MiCasa.Communication public const int VERB_VALIDATE_DESKTOP_PWD = 20; public const int VERB_EXPORT_SECRETS = 21; public const int VERB_ADD_XML_SECRETS = 22; + public const int VERB_CHANGE_PERSIST_DIR = 23; public const int VERB_DUMP_LINKED_KEYS = 96; public const int VERB_CREATE_TEST_SECRETS = 97; diff --git a/CASA/micasad/micasad.csproj b/CASA/micasad/micasad.csproj index f055a87c..1b2013c8 100644 --- a/CASA/micasad/micasad.csproj +++ b/CASA/micasad/micasad.csproj @@ -129,6 +129,11 @@ Project = "{57CD94A2-5B4A-40C3-8189-CB760FB78357}" Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}" /> + diff --git a/CASA/micasad/verbs/ObjectSerialization.cs b/CASA/micasad/verbs/ObjectSerialization.cs index 0b6f54c9..d6da5f62 100644 --- a/CASA/micasad/verbs/ObjectSerialization.cs +++ b/CASA/micasad/verbs/ObjectSerialization.cs @@ -227,6 +227,10 @@ namespace sscs.verbs { return DoMergeXMLSecrets(ssStore, wo); } + case MiCasaRequestReply.VERB_CHANGE_PERSIST_DIR: + { + return DoChangePersistentDir(ssStore, wo); + } default: { @@ -239,11 +243,33 @@ namespace sscs.verbs { wo.SetError(constants.RetCodes.FAILURE, e.ToString()); } - - ssStore.ResumeFileWatcher(); + finally + { + ssStore.ResumeFileWatcher(); + } + return wo; } + + private WrappedObject DoChangePersistentDir(SecretStore ssStore, WrappedObject wo) + { + ChangePersistentDir cpd = (ChangePersistentDir)wo.GetObject(); + string sOldDir = cpd.GetOldDirectory(); + string sNewDir = cpd.GetNewDirectory(); + + if (ssStore.SetPeristenceDirectory(sNewDir)) + { + cpd.SetErrorMessage("Success"); + } + else + { + cpd.SetErrorMessage("Error: Changing directory failed"); + } + + return wo; + } + private WrappedObject DoMergeXMLSecrets(SecretStore ssStore, WrappedObject wo) { ImportXMLSecrets addSecrets = (ImportXMLSecrets)wo.GetObject(); @@ -262,7 +288,7 @@ namespace sscs.verbs int iBytes = fs.Read(baXMLSecrets, 0, (int)fs.Length); fs.Flush(); - fs.Close(); + fs.Close(); } } catch (Exception e) @@ -287,6 +313,10 @@ namespace sscs.verbs // do the merge now. ssStore.MergeXMLSecrets(baXMLSecrets); } + + // persist em + ssStore.CommitStore(); + addSecrets.SetStatus("Success"); wo.SetError(constants.RetCodes.SUCCESS, ""); } diff --git a/CASA/package/windows/vs_solutions/CASAInstall/CASA.ncb b/CASA/package/windows/vs_solutions/CASAInstall/CASA.ncb index a416619d002dcc4a4d8a77b18b7845e530e9531e..49b6ecc206d6a51eabd39590ddafed1babae3d5f 100644 GIT binary patch delta 9341 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 C!?1z? delta 9258 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 V4);awj4t+O^sqal9A?xL{%;+|6u$rf diff --git a/CASA/package/windows/vs_solutions/CASAInstall/CASA.suo b/CASA/package/windows/vs_solutions/CASAInstall/CASA.suo index 6ef739793594ae0b0ce17980728b75a726b37044..da15791bda500983fc735e2687282de8e5c56a8f 100644 GIT binary patch delta 4124 zcmb7HeNa@_6@T~bE-bhpyURB#tO^K-xO^D3L0tnPC_$nmjY6z^2`DVEEDHFw>P&_> z3<@W0NQ|jM(iqwb<)!VUI1U}{)Ty=sW7EuZ#u1yOo#{uM4*8>PM*BODWnJ9Vw(rev z?|Jv0d%o_u=iYS>XxyWk(Rx{YlN#jmMbAl+lnvwnYk&e^HSjdBmZs%|V|kz+;#q;V z6xak50h@sbJb-5l=&e98@GMXQYy+}@3Sc|111JMt0C-LW+MOPH7us@w<-O!->(TC! zq-3cQL={jC)Bv@>UZ4)x4Kx7z=s8V7-=5rlZIf>J^?$u~gPhu126ij}V0AR5O{59E zmO6CTbyMgxDVqZJ3oWap_X7*Hlj!T$UlW1KFZ4%6hzRve^iH-f(TZ;B3_cW)kDfHZ&JS-=wZmU5GfL( zLOhyO6K6up^o711u7#zBcu&WiEsMT|j`0}$;L%AYNeD@51brMZlQGO3WC4`|Nc=_a zusvd&ro${^iXMc0BXTGVBWy@DjBNuru;Wx>jFm5>(ZjGPI&O@_i~(a7X528wFCK~p zM+uxg0H+%9W=MISxso)M3_V}$i?LLLp$Ts@JcdBlk_V@E0GsKdag!kkJ?sTP?5~bl zzM@Xk7RobcibeFLsf4a-Glh}b%_WoiY($8V^LQ%Awr8j&c8WLG!wgx@=TfJiYwEr`aLEnGjYYC3t?dfutMU+ z{V19;PsG6Ep+ANv-5OcCbn{O>n?ACvswrn9MkU3a=GKwjwoVMuQCp;T9IHsJ7tOl; z7@VR}TYSU^oIbt*hOB5hav%;<9@?y_>UbMMU$5qjizjj@su8P7Ol(1fInh6&>xF4z zNXgEO(C7&ruL4w>^NIMFrUJ}#KTscii}`@tz;A)O!0!O6SY?g52VxrFJpTjQPl3;X z&w0nt-Bnh)xGH_@sX~q3fZn-aDXz6W@}N^5TR)@GaU^S%e{9^UHE=O7&EqTR5o1O9 zGHHvyBKy_}sw$4A=x6^#S6q?Qb0C!5xQsPh)oL30Oy!bK}j=Bcr)>3Wk|x{~R8hjytkojh#nKjfzE9kJv( zyjLx8zy5xX>5D5ryu(G#3}NYjK^4z6iSuFB9VSwMY#y^L&`44|z=7pwP71=`OuIW1 zl?R6ng4~^2TJOxKjD#%V!rRta*xeVckOl!Xjp8c*j|H@7Yb{(a@XyF<|S)(rZ~ zkyvscxfGO%ld}LP=qlF|j`Rn~crEN|g!zmVULMm^) zF)Vv?vuCW=CBzMCKYdKxq%TizqkOYX{D#`k9Mf^cwIurT$fng(e&1yp{I*50ocdIZ zy>(9$bQZ(>oTbe7qLe#B`GW4dvCrTUR}c1x+en%|_gA{)+UFhZLoXsGacl96_9_MM zgv#pV)1F~&6L?tcqN$*yMZTv(g}2^U;LygwM?ZJ3RBZ2tiT{zfVcBGgJgPpc&-eqFeV)Kcc^Wi*){prrTQ78E^@qNMbHqNA+U$==?<0h#1= zSyZqsk?yVwP%3iY#=6z0oMNyG_dD<tc+1Kb@so%h;D|N zsP$4ZO*Ds^eTKlG9_UnZ`K2YRo|2>}DMH&dt1HQ07yWc}({i19rBknE^Y|nD`IWqp z7e%Vq`Y3;nN7mz#Po*Q{)Vtph!!~gi@kQexmdyn>>Oni%&Xu!vdZk7`S*jgUf4P{m z)CFI8Q}Hr6p@Hc($me9L@ri&}a*V%Z<=D7Qq(Alqk(GMJm54b{*oS7k>W=w3 zeR2NM=*Hy<`t#2^9tF|j&*ZBznN`NsV2jszL-@Gjo%q8PC3)S9f3n19IDkvJ*s$Sq zMXp5+;=E!3mnt8HCgI6abJfMRIYQ%D>Z6^)OXS_DkXSz7R_l|c7JH=X>59V=(Sj6W zJN;x@=lQ?bUnV77`4tzFnAu{&wUggQtX`dZQQ}OTHO-p~OZ>(7E=wtCdeG zEc2i2>%+%_wyaR=3pux>lWYvfpRsUJLBbfplv-k1itLoUH8QRev7e1U*HQ=G+1ibY bOvRVWRja+hOYv8%BwQ&Fr0LrzOVYmq|1>_O delta 3709 zcmeHJZBUfg6~6b~50;N53oNLB%cnv><1RuYRmmbCD4((0DJohF0%Cw&VNurAu-X~N z7)oT1wVml06pfuBjR9WU{wR%9$>7*X#Kf3iir9R#Gqsrs%`};g+vmP~twZBXf4A?> zv-jR}&pqe7=RW7&*VC`^{6f{gN8(GVLE66bvCrpQ%^1rBvVo1j^T1jlmmWxQ78`nb zz)Bz=C;*CpLO`tEgmyDf3`7E@WC@4~%s}slz~k;0V{|*v*$Gg4Ky0_I(W`FK^f$!* ze27}qw?j;r&;l^!qj7aI4eQj@uDPxWgYcwWpnaLENi4n`P()t_sJ*%ou9e@@y~6b@ z6mp?9x7M1d<{okdxwRz_=a}SggWi|um^D0Q18ZS+c7V0ATJ#E7J9DDfjBx|xqOD>z z%uYW2h@MAbvEJYARH#iSoQOvW()mn9NXU%FtZ-=+1iv)k508e0FwUnFYR6bbVTOpn zx6%9E+-MtmF9YY4x#cP(8YmGXjSup4T5qV~59ypCmb>U(!}p_9!g>=zu3@_n@-DU; zV>g9{MN6(Ux?)&FDR+#p;ik&446J!A%p|!Nlf@XpcablwfbwI^8ezjmuJFy2mykvO z3@@f@;T9fFZ4qU9uEwPDnlo=2CH5FH)OCMAFHDeUI4T=oN? zkhLL7=u&_&HOwXGRR+EN$ay1vvd1{ZwWlC$*3-eLO?obLN5^FI?m>n<8C;S^jy(>n*0k`(v==iaFk> z%(r3(_JBsM02a!tEs-kS1iB(+RFU~f!k;jB9~hevet`BCFb>=X?$Wq6f~vCOmp#Bp zESp685co6jDexKaIq(JWSU#8aE0r!8-MK6|vpXe{1~RCwJeej2v~pGd1wNQFrP4r) zG5MR^Vs(fp@Ni&$)y7WFry2Q~#8@a86QpqPEoi+5Sd=|H*GSY+1i9ob6YQj1X zU{FSvp>+pPY>K*I*yLLLyGdtBLn*nzjBM;l9y80n!UBo%i-*ozH*-2!s-wQm23lP5 zMek*G?-t2hYL%@vNt5nSDt0f7z$uFct?VFG3#ebq;&D(lC@xwt$EdWF2DjyLg)h$S zHeDWsvu{gN+i!)46H5rhBMMlastQrj@Omp*tA}OJD;`dsa*wxW*jr%@5T#Yi*3uvP zHpwUZ)^N)BUK$O)Sw^?j@$y8ymU9h_JJZSe(`vb;p-ZBPws<+drIPEv*|a>Lj+Ca5!KR}FH;s@aQh#&E%s7@D zTi5YSMPuT82wmK|&D(r~=O}`qW*yYbP&bnOW-N^~Zy@VFD{1YX-gOdfdG!)CJ0}Bs z5QHE{4;^W(r;NIAIeh;kPKk~^^vGT*3Jm3g5~guiBt1H)rLIE;jo5*s^o^sCJo}80 zhR@7I(bZLE{q(t7h3al)Kc?6AWzjvmf!;Wz^&ae`f4TO0-5ymdYoc=Zv*bN!D-ce^ zu`iyRZ)Jx6{oS|kiOejO7?`L$$Jc%xe0JT}!NPH%$S9LoGIt|13(H*)ADwpZrF$-& zh)V7{l*p;ekr=_)YPJS9+hLpt`Pk5xSexuy`$tZb4aa2D(Me9e>pJQ`jkF!VNT++x zrj)_YEV1%X+jjh>FO28F+(zZhZAEeHD2SmgzcI`wB z$yXO<(v_KJXBYkY=uX*lrk|q|M4nC?wVdlB!ZZtYPe1K*S{4RC>@E!5`yTjv>#6ppJ!W z{&SjBza#y*@Zp@fsYRUgqZQz)6LB}-4zI^Mw6Y&5{oRQ30JEX*WQ{wq`wJEGl;flY zbInlNhy{(fPsQiKLfs<8sL+}|cFGV$6LdwY;%T5hiTdl!a?Yu%oL;dEyM5rpWw;;0#oPx