/// <summary> /// Create a new KCD ANP command message having the minor version and /// type specified and a unique ID. The workspace ID is inserted as the /// first element of the command. /// </summary> public AnpMsg NewKcdCmd(UInt32 type) { AnpMsg msg = Wm.NewKcdCmd(Kcd.MinorVersion, type); msg.AddUInt64(Cd.Credentials.ExternalID); return(msg); }
/// <summary> /// Import a workspace list from the XML document specified. /// </summary> public static void ImportKwsListFromXmlDoc(XmlDocument doc) { UInt32 version = UInt32.Parse(doc.DocumentElement.GetAttribute("version")); if (version > 1) { throw new Exception("unsupported KwsExport version ('" + version + "')"); } // Import all nodes. foreach (XmlNode node in doc.DocumentElement.ChildNodes) { XmlElement el = node as XmlElement; if (el == null) { throw new Exception("Corrupted document (Node is not an XmlElement)."); } else if (el.Name == "Kws") { ImportKws(XmlToKwsCredentials(el)); } else if (el.Name == "KwsBrowser") { ImportFolderList(XmlToFolderList(el)); } else { throw new Exception("Corrupted document (unknown node '" + el.Name + "'."); } } // Serialize the WM since we may have created workspaces. Wm.Serialize(); }
/// <summary> /// This method is called when the workspace manager has stopped. /// The WM is serialized and the application is told to quit. /// </summary> private static void HandlePostStop() { KLogging.Log("WmSm: " + KwmStrings.Kwm + " has stopped."); Wm.MainStatus = WmMainStatus.Stopped; Wm.Serialize(); Program.RequestAppExit(); }
/// <summary> /// Export the given KWS to the specified path. Set kwsID to 0 /// to export all the workspaces. /// </summary> public static void ExportKws(String path, UInt64 kwsID) { XmlDocument doc = new XmlDocument(); XmlNode node = doc.CreateNode(XmlNodeType.XmlDeclaration, "", ""); doc.AppendChild(node); XmlElement ke = doc.CreateElement("TeamboxExport"); ke.SetAttribute("version", "1"); doc.AppendChild(ke); if (kwsID == 0) { // Export all workspaces. foreach (Workspace kws in Wm.KwsTree.Values) { KwsCredentialsToXml(kws.Cd.Credentials, doc, ke); } // Export all folders. FolderListToXml(Wm.Cd.KwsFolderList, doc, ke); } else { // Export only the specified workspace. Workspace kws = Wm.GetKwsByInternalID(kwsID); KwsCredentialsToXml(kws.Cd.Credentials, doc, ke); } using (Stream s = File.Open(path, FileMode.Create)) doc.Save(s); }
/// <summary> /// Create a new workspace having the credentials specified and insert /// it in the workspace manager, with the current task Stop. /// </summary> public static Workspace CreateWorkspace(KwsCredentials creds) { try { // Clear the public flag if we already have a public workspace. if (Cd.PublicKwsID != 0) { creds.PublicFlag = false; } // Get a new internal ID. UInt64 internalID = Cd.NextKwsInternalID++; // Register the worskpace in the workspace manager. KwsCoreData kwsCd = new KwsCoreData(); kwsCd.Credentials = creds; Workspace kws = new Workspace(); kws.Relink(internalID, kwsCd); AdjustPublicKwsID(); // Insert the workspace in the workpace list in the database. LocalDbBroker.AddKwsToKwsList(kws.InternalID, kws.Cd.Credentials.KwsName); // The WM state has changed. Wm.OnStateChange(WmStateChange.Permanent); return(kws); } catch (Exception ex) { KBase.HandleException(ex, true); return(null); } }
/// <summary> /// Complete the operation if we are ready to. /// </summary> private void CompleteIfNeeded() { if (DoneFlag || m_step != OpStep.LoggingIn || Kws.Cd.KcdState.LoginStatus != KwsLoginStatus.LoggedIn || Kws.Cd.MainStatus != KwsMainStatus.NotYetSpawned || Kws.Cd.CurrentTask != KwsTask.Spawn) { return; } // Update the main status of the workspace. Kws.Cd.MainStatus = KwsMainStatus.Good; Kws.OnStateChange(WmStateChange.Permanent); // Ask the state machine to work online. Kws.Sm.RequestTaskSwitch(KwsTask.WorkOnline); // Serialize the KWM so we don't lose the workspace if the KWM // crashes. Wm.Serialize(); // We're done. Complete(); }
/// <summary> /// Called when the KMOD ticket query results are available. /// </summary> private void OnKmodTicketResult(WmLoginTicketQuery query) { if (m_kmodQuery != query) { return; } m_kmodQuery = null; Debug.Assert(m_step == OpStep.TicketReply); try { // Update the registry information. query.UpdateRegistry(); // Generic failure. if (query.Res != WmLoginTicketQueryRes.OK) { throw new Exception(query.OutDesc); } // We cannot create a workspace. if (!KwmCfg.Cur.CanCreateKws()) { throw new EAnpExInvalidKpsConfig(); } // Update the credentials. Creds.Ticket = query.Ticket.BinaryTicket; Creds.UserName = query.Ticket.AnpTicket.Elements[0].String; Creds.UserEmailAddress = query.Ticket.AnpTicket.Elements[1].String; // Set the KCD address. if (KwmCfg.Cur.CustomKcdFlag) { Creds.KcdAddress = KwmCfg.Cur.CustomKcdAddress; } else { Creds.KcdAddress = KwmCfg.Cur.KpsKcdAddr; } if (Creds.KcdAddress == "") { throw new Exception("invalid KCD address"); } // Create the workspace object. Kws = Wm.CreateWorkspace(Creds); RegisterToKws(); // Start the spawn operation and wait for the connection. m_step = OpStep.Connecting; Kws.Sm.RequestTaskSwitch(KwsTask.Spawn); SendCreateKwsCmdIfNeeded(); } catch (Exception ex) { HandleFailure(ex); } }
/// <summary> /// Post a KCD command. /// </summary> public KcdQuery PostKcdCmd(AnpMsg cmd, KcdQueryDelegate callback) { KcdQuery query = new KcdQuery(cmd, callback, Kcd, this); Wm.PostKcdQuery(query); return(query); }
public override void Start() { try { // Register to the workspace, if possible. Kws = Wm.GetKwsByInternalIDOrThrow(KwsID); RegisterToKws(); Kws.KcdLoginHandler.OnSetLoginPwdRefused += OnLoginPwdRefused; // The password was "accepted" without being tried. if (!Kws.KcdLoginHandler.SetLoginPwd(Pwd)) { Complete(); return; } // Wait to be notified. Either we will be told that the // password was refused or the login status will change. } catch (Exception ex) { HandleFailure(ex); } }
public override void Start() { try { // Get the workspace, if possible. Kws = Wm.GetKwsByInternalIDOrThrow(KwsID); // If the task is delete remotely, start a delete remotely // operation. if (Task == KwsTask.DeleteRemotely) { m_deleteRemotelyOp = new KwsCoreOpDeleteKwsRemotely(); m_deleteRemotelyOp.Kws = Kws; m_deleteRemotelyOp.OnCompletion += OnDeleteRemotelyCompletion; m_deleteRemotelyOp.Start(); } // Perform the task switch right away. else { Kws.Sm.RequestTaskSwitch(Task); } } catch (Exception ex) { HandleFailure(ex); } }
private void SaveLocation(Point loc) { if (loc.Equals(Wm.Cd.VncOverlayLoc)) { return; } Wm.Cd.VncOverlayLoc = loc; Wm.OnStateChange(WmStateChange.Internal); }
/// <summary> /// Process one workspace to remove. /// </summary> private static void ProcessOneKwsToRemove(Workspace kws) { // We can remove the workspace now. if (kws.Sm.ReadyToRemove()) { // Remove the workspace from the manager. Wm.RemoveWorkspace(kws); // Request a run of the state machine in case we want to stop. RequestRun("removed " + KwmStrings.Kws); } }
/// <summary> /// Create a VNC session. /// </summary> private void HandleVncCreateSession(AnpMsg cmd, AnpMsg res) { int i = 0; UInt64 kwsID = cmd.Elements[i++].UInt64; bool supportFlag = cmd.Elements[i++].UInt32 > 0; String subject = cmd.Elements[i++].String; Workspace kws = Wm.GetKwsByInternalIDOrThrow(kwsID); byte[] sessionUuid = kws.Vnc.StartServerSession(supportFlag, 0, subject); res.Type = (uint)EAnpRes.VncSession; res.AddBin(sessionUuid); }
/// <summary> /// Join a VNC session. /// </summary> private void HandleVncJoinSession(AnpMsg cmd, AnpMsg res) { int i = 0; UInt64 kwsID = cmd.Elements[i++].UInt64; UInt64 sessionID = cmd.Elements[i++].UInt64; String subject = cmd.Elements[i++].String; Workspace kws = Wm.GetKwsByInternalIDOrThrow(kwsID); byte[] sessionUuid = kws.Vnc.StartClientSession(sessionID, subject); res.Type = (uint)EAnpRes.VncSession; res.AddBin(sessionUuid); }
/// <summary> /// Serialize the WM if it is time to do so. /// </summary> private static void SerializeWmIfNeeded() { DateTime now = DateTime.Now; if (m_lastSerializationDate.AddSeconds(WmSerializationDelay) < now) { m_lastSerializationDate = now; Wm.Serialize(); } ScheduleRun("WM serialization", m_lastSerializationDate.AddSeconds(WmSerializationDelay)); }
/// <summary> /// Import or join a workspace that does not exist in the KWM. /// </summary> private static void ImportNewKws(KwsCredentials creds) { KLogging.Log("Importing new workspace " + creds.KwsName + "."); // Create the workspace. Workspace kws = Wm.CreateWorkspace(creds); // Set its main status. kws.Cd.MainStatus = KwsMainStatus.Good; // Make the workspace work online. kws.Sm.RequestTaskSwitch(KwsTask.WorkOnline); }
/// <summary> /// Import the workspace specified. /// </summary> public static void ImportKws(KwsCredentials creds) { Workspace kws = Wm.GetKwsByExternalID(creds.KcdID, creds.ExternalID); if (kws != null) { ImportExistingKws(kws, creds); } else { ImportNewKws(creds); } }
/// <summary> /// Create an EAnp event having the parameters specified. /// </summary> private AnpMsg MakeEAnpEvent(EAnpEvt type, UInt64 date, UInt32 userID, UInt64 freshness) { AnpMsg m = new AnpMsg(); m.Minor = 1; m.Type = (UInt32)type; m.AddUInt64(InternalID); m.AddUInt64(date); m.AddUInt32(userID); m.AddUInt64(freshness); m.AddBin(Wm.MakeUuid()); return(m); }
public void Relink(UInt64 internalID, KwsCoreData cd) { InternalID = internalID; Cd = cd; Cd.Relink(); Wm.KwsTree[InternalID] = this; Kcd = Wm.GetOrCreateKcd(Cd.Credentials.KcdID); Kcd.KwsTree[InternalID] = this; Sm.Relink(this); KcdEventHandler.Relink(this); KcdLoginHandler.Relink(this); Chat.Relink(this); Pb.Relink(this); Vnc.Relink(this); Kfs.Relink(this); }
/// <summary> /// Called when the create workspace command reply is received. /// </summary> private void HandleCreateKwsCmdResult(KcdQuery query) { if (m_kcdQuery != query) { return; } m_kcdQuery = null; Debug.Assert(m_step == OpStep.CreateReply); try { AnpMsg res = query.Res; // Failure. if (res.Type != KAnp.KANP_RES_MGT_KWS_CREATED) { throw EAnpException.FromKAnpReply(res); } // Parse the reply. UInt64 externalID = res.Elements[0].UInt64; String emailID = res.Elements[1].String; // Validate that the KCD is not screwing with us. This can // happen if the KCD state has been reverted. if (Wm.GetKwsByExternalID(Kws.Kcd.KcdID, externalID) != null) { throw new Exception("duplicate " + KwmStrings.Kws + " external ID"); } // Update the workspace credentials. Creds.ExternalID = externalID; Creds.EmailID = emailID; // Wait for login. m_step = OpStep.LoggingIn; Kws.Sm.SetLoginType(KwsLoginType.Cached); Kws.Sm.SetSpawnStep(KwsSpawnTaskStep.Login); } catch (Exception ex) { HandleFailure(ex); } }
/// <summary> /// Remove the workspace object from the workspace manager. Used by the /// WM state machine. /// </summary> public static void RemoveWorkspace(Workspace kws) { try { WmKcd kcd = kws.Kcd; // Make sure the state is valid. Debug.Assert(KwsTree.ContainsKey(kws.InternalID)); if (kcd != null) { Debug.Assert(kcd.KwsTree.ContainsKey(kws.InternalID)); Debug.Assert(!kcd.KwsConnectTree.ContainsKey(kws.InternalID)); } // Unregister the workspace from the workspace manager. KwsTree.Remove(kws.InternalID); if (KwsRemoveTree.ContainsKey(kws.InternalID)) { KwsRemoveTree.Remove(kws.InternalID); } if (kcd != null) { kcd.CancelKwsKcdQuery(kws); kcd.KwsTree.Remove(kws.InternalID); RemoveKcdIfNoRef(kcd); } AdjustPublicKwsID(); // Delete the workspace data. kws.PrepareToRemove(); foreach (KwsApp app in kws.AppTree.Values) { app.PrepareToRemove(); } // The WM state has changed. Wm.OnStateChange(WmStateChange.Permanent); } catch (Exception ex) { KBase.HandleException(ex, true); } }
/// <summary> /// Update and return the freshness time. /// </summary> public UInt64 UpdateFreshnessTime() { DateTime now = DateTime.Now; Int64 offset = (Int64)(now - FreshnessDate).TotalMilliseconds; Int64 maxOffset = 24 * 60 * 60 * 1000; if (offset < 0) { offset = 0; } else if (offset > maxOffset) { offset = maxOffset; } FreshnessDate = now; FreshnessTime += (UInt64)offset; Wm.OnStateChange(WmStateChange.Internal); return(FreshnessTime); }
/// <summary> /// Send the workspace creation command if we are ready to. /// </summary> private void SendCreateKwsCmdIfNeeded() { if (DoneFlag || m_step != OpStep.Connecting || Kws.Kcd.ConnStatus != KcdConnStatus.Connected) { return; } m_step = OpStep.CreateReply; AnpMsg cmd = Wm.NewKcdCmd(Kws.Kcd.MinorVersion, KAnp.KANP_CMD_MGT_CREATE_KWS); cmd.AddString(Creds.KwsName); cmd.AddBin(Creds.Ticket); cmd.AddUInt32(Convert.ToUInt32(Creds.PublicFlag)); cmd.AddUInt32(Convert.ToUInt32(Creds.SecureFlag)); if (cmd.Minor >= 4) { cmd.AddUInt32(Convert.ToUInt32(Creds.ThinKfsFlag)); } m_kcdQuery = Kws.PostKcdCmd(cmd, HandleCreateKwsCmdResult); }
/// <summary> /// Process a KCD disconnection notice. /// </summary> private static void ProcessKcdDisconnectionNotice(KcdDisconnectionNotice notice) { Debug.Assert(Wm.KcdTree.ContainsKey(notice.KcdID)); WmKcd kcd = Wm.KcdTree[notice.KcdID]; Debug.Assert(kcd.ConnStatus != KcdConnStatus.Disconnected); // The KCD died unexpectedly. if (kcd.ConnStatus != KcdConnStatus.Disconnecting) { // Handle the offense. if (notice.Ex != null) { // Increase the failed connection attempt count if were // connecting. AssignErrorToKcd(kcd, (kcd.ConnStatus == KcdConnStatus.Connecting)); } } // The KCD is now disconnected. kcd.ConnStatus = KcdConnStatus.Disconnected; // Clear the command-reply mappings associated to the KCD. kcd.QueryMap.Clear(); // Notify every workspace that the KCD is disconnected. foreach (Workspace kws in kcd.KwsTree.Values) { kws.Sm.HandleKcdConnStatusChange(KcdConnStatus.Disconnected, notice.Ex); } // Remove the KCD if we no longer need it. Wm.RemoveKcdIfNoRef(kcd); // Re-run the state machine, in case we want to reconnect to the KCD // or stop. RequestRun("KCD disconnected"); }
/// <summary> /// Import the workspace folder list specified. /// </summary> public static void ImportFolderList(List <WmKwsFolder> folderList) { // Import the missing folders. Update the ET blob of existing folders. foreach (WmKwsFolder f in folderList) { bool foundFlag = false; foreach (WmKwsFolder g in Wm.Cd.KwsFolderList) { if (g.FullPath == f.FullPath) { foundFlag = true; g.EtBlob = f.EtBlob; break; } } if (!foundFlag) { Wm.Cd.KwsFolderList.Add(f); } } // The WM state has changed. Wm.OnStateChange(WmStateChange.Permanent); }
/// <summary> /// Enter the main mode of the KWM. Return true if the application /// must continue. /// </summary> private static bool EnterMainMode() { // Perform early linking. Wm.LocalDbBroker.Relink(Wm.LocalDb); // FIXME. #if true // Open a temporary console. ConsoleWindow foo = new ConsoleWindow(); foo.Show(); foo.OnConsoleClosing += delegate(Object sender, EventArgs args) { WmSm.RequestStop(); }; // Create an empty database. Wm.LocalDb.DeleteDb(); Wm.LocalDb.OpenOrCreateDb(KwmPath.GetKwmDbPath()); Wm.LocalDbBroker.InitDb(); WmDeserializer ds = new WmDeserializer(); ds.Deserialize(); Debug.Assert(ds.Ex == null); #else // Open or create the database. Wm.LocalDb.OpenOrCreateDb(KwmPath.GetKwmDbPath()); Wm.LocalDbBroker.InitDb(); // Try to deserialize. WmDeserializer ds = new WmDeserializer(); ds.Deserialize(); // The deserialization failed. if (ds.Ex != null) { // If the user doesn't want to recover, bail out. if (!TellUserAboutDsrFailure()) { return(false); } // Backup, delete and recreate a database. BackupDb(); Wm.LocalDb.DeleteDb(); Wm.LocalDb.OpenOrCreateDb(KwmPath.GetKwmDbPath()); Wm.LocalDbBroker.InitDb(); // Retry to deserialize. ds = new WmDeserializer(); ds.Deserialize(); if (ds.Ex != null) { throw ds.Ex; } // Set the next internal workspace ID to a high value based on // the date to avoid conflicts with old KFS directories. ds.WmCd.NextKwsInternalID = (UInt64)(DateTime.Now - new DateTime(2010, 1, 1)).TotalSeconds; } #endif // Relink the workspace manager object graphs. Wm.Relink(ds); // Open the lingering database transaction. Wm.LocalDb.BeginTransaction(); // Serialize the WM state that has changed. Wm.Serialize(); // Export the workspaces, then exit. if (ExportKwsPath != "") { WmKwsImportExport.ExportKws(ExportKwsPath, 0); return(false); } // Set the handle to the message window. SetKwmHandle(MsgWindow.Handle); // Pass the hand to the WM state machine. WmSm.RequestStart(); return(true); }
protected override void PrepareStart() { Kws = Wm.GetKwsByInternalIDOrThrow(KwsId); }
/// <summary> /// Process workspace rebuild if required. /// </summary> private void ProcessKwsRebuildIfNeeded() { Debug.Assert(m_rebuildStep == KwsRebuildTaskStep.None); if (m_cd.CurrentTask != KwsTask.Rebuild) { return; } // Sanity check. if (m_cd.MainStatus != KwsMainStatus.RebuildRequired) { KLogging.Log("cannot execute rebuild task, " + KwmStrings.Kws + " status is not RebuildRequired"); RequestTaskSwitch(KwsTask.Stop); return; } // We cannot rebuild until the applications are stopped and we're // logged out. if (m_cd.AppStatus != KwsAppStatus.Stopped || m_ks.LoginStatus != KwsLoginStatus.LoggedOut) { return; } // Protect against spurious state changes. m_rebuildStep = KwsRebuildTaskStep.InProgress; try { // Ask the workspace to prepare for rebuild. m_kws.PrepareToRebuild(); if (m_rebuildStep != KwsRebuildTaskStep.InProgress) { return; } // Tell the applications to prepare for rebuild. foreach (KwsApp app in m_kws.AppTree.Values) { app.PrepareToRebuild(); if (m_rebuildStep != KwsRebuildTaskStep.InProgress) { return; } } } catch (Exception ex) { HandleMiscFailure(ex); return; } // We have "rebuilt" the workspace. Update the state. m_rebuildStep = KwsRebuildTaskStep.None; m_cd.MainStatus = KwsMainStatus.Good; m_cd.RebuildFlags = 0; m_cd.Uuid = Wm.MakeUuid(); SetLoginType(KwsLoginType.All); m_kws.OnStateChange(WmStateChange.Permanent); // Switch to the user task. SwitchToUserTask(); }