aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Application/ConfigurationLoader.cs16
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs2
-rw-r--r--OpenSim/Region/ClientStack/RegionApplicationBase.cs16
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs21
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs61
-rw-r--r--OpenSim/Region/CoreModules/World/Region/RestartModule.cs19
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs8
-rw-r--r--OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs5
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs122
-rw-r--r--OpenSim/Region/OptionalModules/Resources/OptionalModules.addin.xml1
-rw-r--r--OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs929
-rw-r--r--OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs126
16 files changed, 1296 insertions, 44 deletions
diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs
index 40ab765..2d81ea8 100644
--- a/OpenSim/Region/Application/ConfigurationLoader.cs
+++ b/OpenSim/Region/Application/ConfigurationLoader.cs
@@ -372,21 +372,7 @@ namespace OpenSim
372 = startupConfig.GetString("clientstack_plugin", "OpenSim.Region.ClientStack.LindenUDP.dll"); 372 = startupConfig.GetString("clientstack_plugin", "OpenSim.Region.ClientStack.LindenUDP.dll");
373 } 373 }
374 374
375 IConfig standaloneConfig = m_config.Source.Configs["StandAlone"];
376 if (standaloneConfig != null)
377 {
378 m_configSettings.StandaloneAuthenticate = standaloneConfig.GetBoolean("accounts_authenticate", true);
379 m_configSettings.StandaloneWelcomeMessage = standaloneConfig.GetString("welcome_message");
380
381 m_configSettings.StandaloneInventoryPlugin = standaloneConfig.GetString("inventory_plugin");
382 m_configSettings.StandaloneInventorySource = standaloneConfig.GetString("inventory_source");
383 m_configSettings.StandaloneUserPlugin = standaloneConfig.GetString("userDatabase_plugin");
384 m_configSettings.StandaloneUserSource = standaloneConfig.GetString("user_source");
385
386 m_configSettings.LibrariesXMLFile = standaloneConfig.GetString("LibrariesXMLFile");
387 }
388
389 m_networkServersInfo.loadFromConfiguration(m_config.Source); 375 m_networkServersInfo.loadFromConfiguration(m_config.Source);
390 } 376 }
391 } 377 }
392} 378} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 43903ce..025c6e6 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -5982,7 +5982,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5982 AvatarWearingArgs wearingArgs = new AvatarWearingArgs(); 5982 AvatarWearingArgs wearingArgs = new AvatarWearingArgs();
5983 for (int i = 0; i < nowWearing.WearableData.Length; i++) 5983 for (int i = 0; i < nowWearing.WearableData.Length; i++)
5984 { 5984 {
5985 m_log.DebugFormat("[XXX]: Wearable type {0} item {1}", nowWearing.WearableData[i].WearableType, nowWearing.WearableData[i].ItemID); 5985 //m_log.DebugFormat("[XXX]: Wearable type {0} item {1}", nowWearing.WearableData[i].WearableType, nowWearing.WearableData[i].ItemID);
5986 AvatarWearingArgs.Wearable wearable = 5986 AvatarWearingArgs.Wearable wearable =
5987 new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID, 5987 new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID,
5988 nowWearing.WearableData[i].WearableType); 5988 nowWearing.WearableData[i].WearableType);
diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
index ea1317a..6e3a58e 100644
--- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs
+++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
@@ -96,6 +96,22 @@ namespace OpenSim.Region.ClientStack
96 96
97 MainServer.Instance = m_httpServer; 97 MainServer.Instance = m_httpServer;
98 98
99 // "OOB" Server
100 if (m_networkServersInfo.ssl_listener)
101 {
102 BaseHttpServer server = null;
103 server = new BaseHttpServer(
104 m_networkServersInfo.https_port, m_networkServersInfo.ssl_listener, m_networkServersInfo.cert_path,
105 m_networkServersInfo.cert_pass);
106 // Add the server to m_Servers
107 if(server != null)
108 {
109 m_log.InfoFormat("[REGION SERVER]: Starting HTTPS server on port {0}", server.Port);
110 MainServer.AddHttpServer(server);
111 server.Start();
112 }
113 }
114
99 base.StartupSpecific(); 115 base.StartupSpecific();
100 } 116 }
101 117
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index 08ac624..e92f072 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -76,7 +76,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
76 } 76 }
77 77
78 if (m_scene == null) 78 if (m_scene == null)
79 m_scene = scene; 79 m_scene = scene;
80 } 80 }
81 81
82 public void PostInitialise() 82 public void PostInitialise()
@@ -162,12 +162,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
162 // one and we're done otherwise, ask for a rebake 162 // one and we're done otherwise, ask for a rebake
163 if (checkonly) return false; 163 if (checkonly) return false;
164 164
165 m_log.InfoFormat("[AVFACTORY] missing baked texture {0}, request rebake",face.TextureID); 165 m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake",face.TextureID);
166 client.SendRebakeAvatarTextures(face.TextureID); 166 client.SendRebakeAvatarTextures(face.TextureID);
167 } 167 }
168 } 168 }
169 169
170 m_log.DebugFormat("[AVFACTORY]: complete texture check for {0}", client.AgentId); 170 m_log.DebugFormat("[AVFACTORY]: completed texture check for {0}", client.AgentId);
171 171
172 // If we only found default textures, then the appearance is not cached 172 // If we only found default textures, then the appearance is not cached
173 return (defonly ? false : true); 173 return (defonly ? false : true);
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
index 111d808..eb776fe 100644
--- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
@@ -66,8 +66,8 @@ namespace OpenSim.Region.CoreModules.Framework
66 m_scene = scene; 66 m_scene = scene;
67 m_scene.RegisterModuleInterface<ICapabilitiesModule>(this); 67 m_scene.RegisterModuleInterface<ICapabilitiesModule>(this);
68 MainConsole.Instance.Commands.AddCommand("Capabilities", false, "show caps", 68 MainConsole.Instance.Commands.AddCommand("Capabilities", false, "show caps",
69 "show capabilities", 69 "show caps",
70 "Shows all registered capabilities", CapabilitiesCommand); 70 "Shows all registered capabilities", CapabilitiesCommand);
71 } 71 }
72 72
73 public void RegionLoaded(Scene scene) 73 public void RegionLoaded(Scene scene)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index 73f07ba..da3a541 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -892,6 +892,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
892 if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) 892 if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent))
893 { 893 {
894 // region doesn't take it 894 // region doesn't take it
895 ReInstantiateScripts(agent);
895 ResetFromTransit(agent.UUID); 896 ResetFromTransit(agent.UUID);
896 return agent; 897 return agent;
897 } 898 }
@@ -1761,14 +1762,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1761 protected void ReInstantiateScripts(ScenePresence sp) 1762 protected void ReInstantiateScripts(ScenePresence sp)
1762 { 1763 {
1763 int i = 0; 1764 int i = 0;
1764 sp.Attachments.ForEach(delegate(SceneObjectGroup sog) 1765 if (sp.InTransitScriptStates.Count > 0)
1765 { 1766 {
1766 sog.SetState(sp.InTransitScriptStates[i++], sp.Scene); 1767 sp.Attachments.ForEach(delegate(SceneObjectGroup sog)
1767 sog.CreateScriptInstances(0, false, sp.Scene.DefaultScriptEngine, 0); 1768 {
1768 sog.ResumeScripts(); 1769 if (i < sp.InTransitScriptStates.Count)
1769 }); 1770 {
1771 sog.SetState(sp.InTransitScriptStates[i++], sp.Scene);
1772 sog.CreateScriptInstances(0, false, sp.Scene.DefaultScriptEngine, 0);
1773 sog.ResumeScripts();
1774 }
1775 else
1776 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: InTransitScriptStates.Count={0} smaller than Attachments.Count={1}", sp.InTransitScriptStates.Count, sp.Attachments.Count);
1777 });
1770 1778
1771 sp.InTransitScriptStates.Clear(); 1779 sp.InTransitScriptStates.Clear();
1780 }
1772 } 1781 }
1773 #endregion 1782 #endregion
1774 1783
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index 9b565ed..a552a28 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -78,7 +78,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
78 78
79 private int m_TotalUrls = 100; 79 private int m_TotalUrls = 100;
80 80
81 private uint https_port = 0;
81 private IHttpServer m_HttpServer = null; 82 private IHttpServer m_HttpServer = null;
83 private IHttpServer m_HttpsServer = null;
82 84
83 private string m_ExternalHostNameForLSL = ""; 85 private string m_ExternalHostNameForLSL = "";
84 86
@@ -100,6 +102,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
100 public void Initialise(IConfigSource config) 102 public void Initialise(IConfigSource config)
101 { 103 {
102 m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName); 104 m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName);
105 bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener",false);
106 if (ssl_enabled)
107 {
108 https_port = (uint) config.Configs["Network"].GetInt("https_port",0);
109 }
103 } 110 }
104 111
105 public void PostInitialise() 112 public void PostInitialise()
@@ -113,6 +120,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
113 // There can only be one 120 // There can only be one
114 // 121 //
115 m_HttpServer = MainServer.Instance; 122 m_HttpServer = MainServer.Instance;
123 //
124 // We can use the https if it is enabled
125 if (https_port > 0)
126 {
127 m_HttpsServer = MainServer.GetHttpServer(https_port);
128 }
116 } 129 }
117 130
118 scene.RegisterModuleInterface<IUrlModule>(this); 131 scene.RegisterModuleInterface<IUrlModule>(this);
@@ -171,7 +184,40 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
171 { 184 {
172 UUID urlcode = UUID.Random(); 185 UUID urlcode = UUID.Random();
173 186
174 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); 187 if (m_HttpsServer == null)
188 {
189 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
190 return urlcode;
191 }
192
193 lock (m_UrlMap)
194 {
195 if (m_UrlMap.Count >= m_TotalUrls)
196 {
197 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
198 return urlcode;
199 }
200 string url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + "/lslhttps/" + urlcode.ToString() + "/";
201
202 UrlData urlData = new UrlData();
203 urlData.hostID = host.UUID;
204 urlData.itemID = itemID;
205 urlData.engine = engine;
206 urlData.url = url;
207 urlData.urlcode = urlcode;
208 urlData.requests = new Dictionary<UUID, RequestData>();
209
210
211 m_UrlMap[url] = urlData;
212
213 string uri = "/lslhttps/" + urlcode.ToString() + "/";
214
215 m_HttpsServer.AddPollServiceHTTPHandler(uri,HandleHttpPoll,
216 new PollServiceEventArgs(HttpRequestHandler,HasEvents, GetEvents, NoEvents,
217 urlcode));
218
219 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_GRANTED", url });
220 }
175 221
176 return urlcode; 222 return urlcode;
177 } 223 }
@@ -345,7 +391,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
345 } 391 }
346 private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) 392 private Hashtable GetEvents(UUID requestID, UUID sessionID, string request)
347 { 393 {
348 UrlData url = null; 394 UrlData url = null;
349 RequestData requestData = null; 395 RequestData requestData = null;
350 396
351 lock (m_RequestMap) 397 lock (m_RequestMap)
@@ -391,11 +437,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
391 lock (request) 437 lock (request)
392 { 438 {
393 string uri = request["uri"].ToString(); 439 string uri = request["uri"].ToString();
394 440 bool is_ssl = uri.Contains("lslhttps");
441
395 try 442 try
396 { 443 {
397 Hashtable headers = (Hashtable)request["headers"]; 444 Hashtable headers = (Hashtable)request["headers"];
398 445
399// string uri_full = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/"; 446// string uri_full = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/";
400 447
401 int pos1 = uri.IndexOf("/");// /lslhttp 448 int pos1 = uri.IndexOf("/");// /lslhttp
@@ -409,7 +456,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
409 456
410 pathInfo = uri.Substring(pos3); 457 pathInfo = uri.Substring(pos3);
411 458
412 UrlData url = m_UrlMap["http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp]; 459 UrlData url = null;
460 if (!is_ssl)
461 url = m_UrlMap["http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp];
462 else
463 url = m_UrlMap["https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp];
413 464
414 //for llGetHttpHeader support we need to store original URI here 465 //for llGetHttpHeader support we need to store original URI here
415 //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers 466 //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers
diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
index ab6a598..e983239 100644
--- a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
+++ b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
@@ -64,19 +64,26 @@ namespace OpenSim.Region.CoreModules.World.Region
64 public void AddRegion(Scene scene) 64 public void AddRegion(Scene scene)
65 { 65 {
66 m_Scene = scene; 66 m_Scene = scene;
67
67 scene.RegisterModuleInterface<IRestartModule>(this); 68 scene.RegisterModuleInterface<IRestartModule>(this);
68 MainConsole.Instance.Commands.AddCommand("RestartModule", 69 MainConsole.Instance.Commands.AddCommand("RestartModule",
69 false, "region restart bluebox", 70 false, "region restart bluebox",
70 "region restart bluebox <message> <time> ...", 71 "region restart bluebox <message> <delta seconds>+",
71 "Restart the region", HandleRegionRestart); 72 "Schedule a region restart",
73 "Schedule a region restart after a given number of seconds. If one delta is given then the region is restarted in delta seconds time. A time to restart is sent to users in the region as a transient notice. If multiple deltas are given then a notice is sent when we reach each delta.",
74 HandleRegionRestart);
75
72 MainConsole.Instance.Commands.AddCommand("RestartModule", 76 MainConsole.Instance.Commands.AddCommand("RestartModule",
73 false, "region restart notice", 77 false, "region restart notice",
74 "region restart notice <message> <time> ...", 78 "region restart notice <message> <delta seconds>+",
75 "Restart the region", HandleRegionRestart); 79 "Schedule a region restart",
80 "Schedule a region restart after a given number of seconds. If one delta is given then the region is restarted in delta seconds time. A time to restart is sent to users in the region as a dismissable bluebox notice. If multiple deltas are given then a notice is sent when we reach each delta.",
81 HandleRegionRestart);
82
76 MainConsole.Instance.Commands.AddCommand("RestartModule", 83 MainConsole.Instance.Commands.AddCommand("RestartModule",
77 false, "region restart abort", 84 false, "region restart abort",
78 "region restart abort [<message>]", 85 "region restart abort [<message>]",
79 "Restart the region", HandleRegionRestart); 86 "Abort a region restart", HandleRegionRestart);
80 } 87 }
81 88
82 public void RegionLoaded(Scene scene) 89 public void RegionLoaded(Scene scene)
@@ -245,7 +252,7 @@ namespace OpenSim.Region.CoreModules.World.Region
245 } 252 }
246 } 253 }
247 254
248 MainConsole.Instance.Output("Error: restart region <mode> <name> <time> ..."); 255 MainConsole.Instance.Output("Error: restart region <mode> <name> <delta seconds>+");
249 return; 256 return;
250 } 257 }
251 258
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index b0f0de6..cd01a05 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -713,7 +713,7 @@ namespace OpenSim.Region.Framework.Scenes
713 newName = item.Name; 713 newName = item.Name;
714 } 714 }
715 715
716 if (remoteClient.AgentId == oldAgentID) 716 if (remoteClient.AgentId == oldAgentID || (LibraryService != null && LibraryService.LibraryRootFolder != null && oldAgentID == LibraryService.LibraryRootFolder.Owner))
717 { 717 {
718 CreateNewInventoryItem( 718 CreateNewInventoryItem(
719 remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Flags, callbackID, asset, (sbyte)item.InvType, 719 remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Flags, callbackID, asset, (sbyte)item.InvType,
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index b537381..49fbe33 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -775,6 +775,8 @@ namespace OpenSim.Region.Framework.Scenes
775 m_regInfo = regInfo; 775 m_regInfo = regInfo;
776 m_eventManager = new EventManager(); 776 m_eventManager = new EventManager();
777 777
778 m_permissions = new ScenePermissions(this);
779
778 m_lastUpdate = Util.EnvironmentTickCount(); 780 m_lastUpdate = Util.EnvironmentTickCount();
779 } 781 }
780 782
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 631c91b..f6295b1 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -2430,8 +2430,12 @@ namespace OpenSim.Region.Framework.Scenes
2430 float speed = Velocity.Length(); 2430 float speed = Velocity.Length();
2431 float velocidyDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity); 2431 float velocidyDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity);
2432 2432
2433 // assuming 5 ms. worst case precision for timer, use 2x that
2434 // for distance error threshold
2435 float distanceErrorThreshold = speed * 0.01f;
2436
2433 if (speed < 0.01f // allow rotation updates if avatar position is unchanged 2437 if (speed < 0.01f // allow rotation updates if avatar position is unchanged
2434 || Math.Abs(distanceError) > 0.25f // arbitrary distance error threshold 2438 || Math.Abs(distanceError) > distanceErrorThreshold
2435 || velocidyDiff > 0.01f) // did velocity change from last update? 2439 || velocidyDiff > 0.01f) // did velocity change from last update?
2436 { 2440 {
2437 m_perfMonMS = currentTick; 2441 m_perfMonMS = currentTick;
@@ -3151,7 +3155,7 @@ namespace OpenSim.Region.Framework.Scenes
3151 { 3155 {
3152 cAgent.AttachmentObjects = new List<ISceneObject>(); 3156 cAgent.AttachmentObjects = new List<ISceneObject>();
3153 cAgent.AttachmentObjectStates = new List<string>(); 3157 cAgent.AttachmentObjectStates = new List<string>();
3154 IScriptModule se = m_scene.RequestModuleInterface<IScriptModule>(); 3158// IScriptModule se = m_scene.RequestModuleInterface<IScriptModule>();
3155 m_InTransitScriptStates.Clear(); 3159 m_InTransitScriptStates.Clear();
3156 foreach (SceneObjectGroup sog in m_attachments) 3160 foreach (SceneObjectGroup sog in m_attachments)
3157 { 3161 {
diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
index db17d8f..8f8124e 100644
--- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
@@ -107,11 +107,10 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
107 107
108 scene.AddCommand( 108 scene.AddCommand(
109 this, "emergency-monitoring", 109 this, "emergency-monitoring",
110 "Go on/off emergency monitoring mode", 110 "emergency-monitoring",
111 "Go on/off emergency monitoring mode", 111 "Go on/off emergency monitoring mode",
112 "Go on/off emergency monitoring mode", 112 "Go on/off emergency monitoring mode",
113 EmergencyMonitoring); 113 EmergencyMonitoring);
114
115 } 114 }
116 115
117 public void RemoveRegion(Scene scene) 116 public void RemoveRegion(Scene scene)
@@ -190,7 +189,7 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
190 int maxNameLength = 18; 189 int maxNameLength = 18;
191 int maxRegionNameLength = 14; 190 int maxRegionNameLength = 14;
192 int maxTypeLength = 4; 191 int maxTypeLength = 4;
193 int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding; 192// int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding;
194 193
195 report.Append(GetColumnEntry("User", maxNameLength, columnPadding)); 194 report.Append(GetColumnEntry("User", maxNameLength, columnPadding));
196 report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding)); 195 report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding));
diff --git a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
new file mode 100644
index 0000000..8589901
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
@@ -0,0 +1,122 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Text;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Framework.Console;
38using OpenSim.Framework.Statistics;
39using OpenSim.Region.ClientStack.LindenUDP;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42
43namespace OpenSim.Region.OptionalModules.Avatar.Appearance
44{
45 /// <summary>
46 /// A module that just holds commands for inspecting avatar appearance.
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AppearanceInfoModule")]
49 public class AppearanceInfoModule : ISharedRegionModule
50 {
51// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 protected Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
54 protected IAvatarFactory m_avatarFactory;
55
56 public string Name { get { return "Appearance Information Module"; } }
57
58 public Type ReplaceableInterface { get { return null; } }
59
60 public void Initialise(IConfigSource source)
61 {
62// m_log.DebugFormat("[APPEARANCE INFO MODULE]: INITIALIZED MODULE");
63 }
64
65 public void PostInitialise()
66 {
67// m_log.DebugFormat("[APPEARANCE INFO MODULE]: POST INITIALIZED MODULE");
68 }
69
70 public void Close()
71 {
72// m_log.DebugFormat("[APPEARANCE INFO MODULE]: CLOSED MODULE");
73 }
74
75 public void AddRegion(Scene scene)
76 {
77// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
78 }
79
80 public void RemoveRegion(Scene scene)
81 {
82// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
83
84 lock (m_scenes)
85 m_scenes.Remove(scene.RegionInfo.RegionID);
86 }
87
88 public void RegionLoaded(Scene scene)
89 {
90// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
91
92 lock (m_scenes)
93 m_scenes[scene.RegionInfo.RegionID] = scene;
94
95 scene.AddCommand(
96 this, "appearance show",
97 "appearance show",
98 "Show appearance information for each avatar in the simulator. At the moment, ",
99 ShowAppearanceInfo);
100 }
101
102 protected void ShowAppearanceInfo(string module, string[] cmd)
103 {
104 lock (m_scenes)
105 {
106 foreach (Scene scene in m_scenes.Values)
107 {
108 scene.ForEachClient(
109 delegate(IClientAPI client)
110 {
111 if (client is LLClientView && !((LLClientView)client).ChildAgentStatus())
112 {
113 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(client);
114 MainConsole.Instance.OutputFormat(
115 "{0} baked apperance texture is {1}", client.Name, bakedTextureValid ? "OK" : "corrupt");
116 }
117 });
118 }
119 }
120 }
121 }
122} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Resources/OptionalModules.addin.xml b/OpenSim/Region/OptionalModules/Resources/OptionalModules.addin.xml
index 5eea286..8691343 100644
--- a/OpenSim/Region/OptionalModules/Resources/OptionalModules.addin.xml
+++ b/OpenSim/Region/OptionalModules/Resources/OptionalModules.addin.xml
@@ -13,5 +13,6 @@
13 <RegionModule id="Concierge" type="OpenSim.Region.OptionalModules.Avatar.Concierge.ConciergeModule" /> 13 <RegionModule id="Concierge" type="OpenSim.Region.OptionalModules.Avatar.Concierge.ConciergeModule" />
14 <RegionModule id="VivoxVoice" type="OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice.VivoxVoiceModule" /> 14 <RegionModule id="VivoxVoice" type="OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice.VivoxVoiceModule" />
15 <RegionModule id="WorldViewModule" type="OpenSim.Region.OptionalModules.World.WorldView.WorldViewModule" /> 15 <RegionModule id="WorldViewModule" type="OpenSim.Region.OptionalModules.World.WorldView.WorldViewModule" />
16 <RegionModule id="AutoBackupModule" type="OpenSim.Region.OptionalModules.World.AutoBackup.AutoBackupModule" />
16 </Extension> 17 </Extension>
17</Addin> 18</Addin>
diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
new file mode 100644
index 0000000..ce9a448
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
@@ -0,0 +1,929 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31using System.IO;
32using System.Reflection;
33using System.Timers;
34using System.Text.RegularExpressions;
35using log4net;
36using Nini.Config;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40
41namespace OpenSim.Region.OptionalModules.World.AutoBackup
42{
43 /// <summary>
44 /// Choose between ways of naming the backup files that are generated.
45 /// </summary>
46 /// <remarks>Time: OARs are named by a timestamp.
47 /// Sequential: OARs are named by counting (Region_1.oar, Region_2.oar, etc.)
48 /// Overwrite: Only one file per region is created; it's overwritten each time a backup is made.</remarks>
49 public enum NamingType
50 {
51 Time,
52 Sequential,
53 Overwrite
54 }
55
56 ///<summary>
57 /// AutoBackupModule: save OAR region backups to disk periodically
58 /// </summary>
59 /// <remarks>
60 /// Config Settings Documentation.
61 /// At the TOP LEVEL, e.g. in OpenSim.ini, we have the following options:
62 /// EACH REGION, in OpenSim.ini, can have the following settings under the [AutoBackupModule] section.
63 /// IMPORTANT: You may optionally specify the key name as follows for a per-region key: [Region Name].[Key Name]
64 /// Example: My region is named Foo.
65 /// If I wanted to specify the "AutoBackupInterval" key just for this region, I would name my key "Foo.AutoBackupInterval", under the [AutoBackupModule] section of OpenSim.ini.
66 /// Instead of specifying them on a per-region basis, you can also omit the region name to specify the default setting for all regions.
67 /// Region-specific settings take precedence.
68 ///
69 /// AutoBackupModuleEnabled: True/False. Default: False. If True, use the auto backup module. This setting does not support per-region basis.
70 /// All other settings under [AutoBackupModule] are ignored if AutoBackupModuleEnabled is false, even per-region settings!
71 /// AutoBackup: True/False. Default: False. If True, activate auto backup functionality.
72 /// This is the only required option for enabling auto-backup; the other options have sane defaults.
73 /// If False for a particular region, the auto-backup module becomes a no-op for the region, and all other AutoBackup* settings are ignored.
74 /// If False globally (the default), only regions that specifically override this with "FooRegion.AutoBackup = true" will get AutoBackup functionality.
75 /// AutoBackupInterval: Double, non-negative value. Default: 720 (12 hours).
76 /// The number of minutes between each backup attempt.
77 /// If a negative or zero value is given, it is equivalent to setting AutoBackup = False.
78 /// AutoBackupBusyCheck: True/False. Default: True.
79 /// If True, we will only take an auto-backup if a set of conditions are met.
80 /// These conditions are heuristics to try and avoid taking a backup when the sim is busy.
81 /// AutoBackupScript: String. Default: not specified (disabled).
82 /// File path to an executable script or binary to run when an automatic backup is taken.
83 /// The file should really be (Windows) an .exe or .bat, or (Linux/Mac) a shell script or binary.
84 /// Trying to "run" directories, or things with weird file associations on Win32, might cause unexpected results!
85 /// argv[1] of the executed file/script will be the file name of the generated OAR.
86 /// If the process can't be spawned for some reason (file not found, no execute permission, etc), write a warning to the console.
87 /// AutoBackupNaming: string. Default: Time.
88 /// One of three strings (case insensitive):
89 /// "Time": Current timestamp is appended to file name. An existing file will never be overwritten.
90 /// "Sequential": A number is appended to the file name. So if RegionName_x.oar exists, we'll save to RegionName_{x+1}.oar next. An existing file will never be overwritten.
91 /// "Overwrite": Always save to file named "${AutoBackupDir}/RegionName.oar", even if we have to overwrite an existing file.
92 /// AutoBackupDir: String. Default: "." (the current directory).
93 /// A directory (absolute or relative) where backups should be saved.
94 /// AutoBackupDilationThreshold: float. Default: 0.5. Lower bound on time dilation required for BusyCheck heuristics to pass.
95 /// If the time dilation is below this value, don't take a backup right now.
96 /// AutoBackupAgentThreshold: int. Default: 10. Upper bound on # of agents in region required for BusyCheck heuristics to pass.
97 /// If the number of agents is greater than this value, don't take a backup right now
98 /// Save memory by setting low initial capacities. Minimizes impact in common cases of all regions using same interval, and instances hosting 1 ~ 4 regions.
99 /// Also helps if you don't want AutoBackup at all.
100 /// </remarks>
101 public class AutoBackupModule : ISharedRegionModule
102 {
103 private static readonly ILog m_log =
104 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
105 private readonly Dictionary<Guid, IScene> m_pendingSaves = new Dictionary<Guid, IScene>(1);
106 private readonly AutoBackupModuleState m_defaultState = new AutoBackupModuleState();
107 private readonly Dictionary<IScene, AutoBackupModuleState> m_states =
108 new Dictionary<IScene, AutoBackupModuleState>(1);
109 private readonly Dictionary<Timer, List<IScene>> m_timerMap =
110 new Dictionary<Timer, List<IScene>>(1);
111 private readonly Dictionary<double, Timer> m_timers = new Dictionary<double, Timer>(1);
112
113 private delegate T DefaultGetter<T>(string settingName, T defaultValue);
114 private bool m_enabled;
115
116 /// <summary>
117 /// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState!
118 /// </summary>
119 private bool m_closed;
120
121 private IConfigSource m_configSource;
122
123 /// <summary>
124 /// Required by framework.
125 /// </summary>
126 public bool IsSharedModule
127 {
128 get { return true; }
129 }
130
131 #region ISharedRegionModule Members
132
133 /// <summary>
134 /// Identifies the module to the system.
135 /// </summary>
136 string IRegionModuleBase.Name
137 {
138 get { return "AutoBackupModule"; }
139 }
140
141 /// <summary>
142 /// We don't implement an interface, this is a single-use module.
143 /// </summary>
144 Type IRegionModuleBase.ReplaceableInterface
145 {
146 get { return null; }
147 }
148
149 /// <summary>
150 /// Called once in the lifetime of the module at startup.
151 /// </summary>
152 /// <param name="source">The input config source for OpenSim.ini.</param>
153 void IRegionModuleBase.Initialise(IConfigSource source)
154 {
155 // Determine if we have been enabled at all in OpenSim.ini -- this is part and parcel of being an optional module
156 this.m_configSource = source;
157 IConfig moduleConfig = source.Configs["AutoBackupModule"];
158 if (moduleConfig == null)
159 {
160 this.m_enabled = false;
161 return;
162 }
163 else
164 {
165 this.m_enabled = moduleConfig.GetBoolean("AutoBackupModuleEnabled", false);
166 if (this.m_enabled)
167 {
168 m_log.Info("[AUTO BACKUP]: AutoBackupModule enabled");
169 }
170 else
171 {
172 return;
173 }
174 }
175
176 Timer defTimer = new Timer(43200000);
177 this.m_defaultState.Timer = defTimer;
178 this.m_timers.Add(43200000, defTimer);
179 defTimer.Elapsed += this.HandleElapsed;
180 defTimer.AutoReset = true;
181 defTimer.Start();
182
183 AutoBackupModuleState abms = this.ParseConfig(null, true);
184 m_log.Debug("[AUTO BACKUP]: Here is the default config:");
185 m_log.Debug(abms.ToString());
186 }
187
188 /// <summary>
189 /// Called once at de-init (sim shutting down).
190 /// </summary>
191 void IRegionModuleBase.Close()
192 {
193 if (!this.m_enabled)
194 {
195 return;
196 }
197
198 // We don't want any timers firing while the sim's coming down; strange things may happen.
199 this.StopAllTimers();
200 }
201
202 /// <summary>
203 /// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded.
204 /// </summary>
205 /// <param name="scene"></param>
206 void IRegionModuleBase.AddRegion(Scene scene)
207 {
208 }
209
210 /// <summary>
211 /// Here we just clean up some resources and stop the OAR backup (if any) for the given scene.
212 /// </summary>
213 /// <param name="scene">The scene (region) to stop performing AutoBackup on.</param>
214 void IRegionModuleBase.RemoveRegion(Scene scene)
215 {
216 if (!this.m_enabled)
217 {
218 return;
219 }
220
221 if (this.m_states.ContainsKey(scene))
222 {
223 AutoBackupModuleState abms = this.m_states[scene];
224
225 // Remove this scene out of the timer map list
226 Timer timer = abms.Timer;
227 List<IScene> list = this.m_timerMap[timer];
228 list.Remove(scene);
229
230 // Shut down the timer if this was the last scene for the timer
231 if (list.Count == 0)
232 {
233 this.m_timerMap.Remove(timer);
234 this.m_timers.Remove(timer.Interval);
235 timer.Close();
236 }
237 this.m_states.Remove(scene);
238 }
239 }
240
241 /// <summary>
242 /// Most interesting/complex code paths in AutoBackup begin here.
243 /// We read lots of Nini config, maybe set a timer, add members to state tracking Dictionaries, etc.
244 /// </summary>
245 /// <param name="scene">The scene to (possibly) perform AutoBackup on.</param>
246 void IRegionModuleBase.RegionLoaded(Scene scene)
247 {
248 if (!this.m_enabled)
249 {
250 return;
251 }
252
253 // This really ought not to happen, but just in case, let's pretend it didn't...
254 if (scene == null)
255 {
256 return;
257 }
258
259 AutoBackupModuleState abms = this.ParseConfig(scene, false);
260 m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName);
261 m_log.Debug((abms == null ? "DEFAULT" : abms.ToString()));
262 }
263
264 /// <summary>
265 /// Currently a no-op.
266 /// </summary>
267 void ISharedRegionModule.PostInitialise()
268 {
269 }
270
271 #endregion
272
273 /// <summary>
274 /// Set up internal state for a given scene. Fairly complex code.
275 /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene.
276 /// </summary>
277 /// <param name="scene">The scene to look at.</param>
278 /// <param name="parseDefault">Whether this call is intended to figure out what we consider the "default" config (applied to all regions unless overridden by per-region settings).</param>
279 /// <returns>An AutoBackupModuleState contains most information you should need to know relevant to auto-backup, as applicable to a single region.</returns>
280 private AutoBackupModuleState ParseConfig(IScene scene, bool parseDefault)
281 {
282 string sRegionName;
283 string sRegionLabel;
284 string prepend;
285 AutoBackupModuleState state;
286
287 if (parseDefault)
288 {
289 sRegionName = null;
290 sRegionLabel = "DEFAULT";
291 prepend = "";
292 state = this.m_defaultState;
293 }
294 else
295 {
296 sRegionName = scene.RegionInfo.RegionName;
297 sRegionLabel = sRegionName;
298 prepend = sRegionName + ".";
299 state = null;
300 }
301
302 // Read the config settings and set variables.
303 IConfig regionConfig = (scene != null ? scene.Config.Configs[sRegionName] : null);
304 IConfig config = this.m_configSource.Configs["AutoBackupModule"];
305 if (config == null)
306 {
307 // defaultState would be disabled too if the section doesn't exist.
308 state = this.m_defaultState;
309 return state;
310 }
311
312 bool tmpEnabled = ResolveBoolean("AutoBackup", this.m_defaultState.Enabled, config, regionConfig);
313 if (state == null && tmpEnabled != this.m_defaultState.Enabled)
314 //Varies from default state
315 {
316 state = new AutoBackupModuleState();
317 }
318
319 if (state != null)
320 {
321 state.Enabled = tmpEnabled;
322 }
323
324 // If you don't want AutoBackup, we stop.
325 if ((state == null && !this.m_defaultState.Enabled) || (state != null && !state.Enabled))
326 {
327 return state;
328 }
329 else
330 {
331 m_log.Info("[AUTO BACKUP]: Region " + sRegionLabel + " is AutoBackup ENABLED.");
332 }
333
334 // Borrow an existing timer if one exists for the same interval; otherwise, make a new one.
335 double interval =
336 this.ResolveDouble("AutoBackupInterval", this.m_defaultState.IntervalMinutes,
337 config, regionConfig) * 60000.0;
338 if (state == null && interval != this.m_defaultState.IntervalMinutes*60000.0)
339 {
340 state = new AutoBackupModuleState();
341 }
342
343 if (this.m_timers.ContainsKey(interval))
344 {
345 if (state != null)
346 {
347 state.Timer = this.m_timers[interval];
348 }
349 m_log.Debug("[AUTO BACKUP]: Reusing timer for " + interval + " msec for region " +
350 sRegionLabel);
351 }
352 else
353 {
354 // 0 or negative interval == do nothing.
355 if (interval <= 0.0 && state != null)
356 {
357 state.Enabled = false;
358 return state;
359 }
360 if (state == null)
361 {
362 state = new AutoBackupModuleState();
363 }
364 Timer tim = new Timer(interval);
365 state.Timer = tim;
366 //Milliseconds -> minutes
367 this.m_timers.Add(interval, tim);
368 tim.Elapsed += this.HandleElapsed;
369 tim.AutoReset = true;
370 tim.Start();
371 }
372
373 // Add the current region to the list of regions tied to this timer.
374 if (scene != null)
375 {
376 if (state != null)
377 {
378 if (this.m_timerMap.ContainsKey(state.Timer))
379 {
380 this.m_timerMap[state.Timer].Add(scene);
381 }
382 else
383 {
384 List<IScene> scns = new List<IScene>(1);
385 scns.Add(scene);
386 this.m_timerMap.Add(state.Timer, scns);
387 }
388 }
389 else
390 {
391 if (this.m_timerMap.ContainsKey(this.m_defaultState.Timer))
392 {
393 this.m_timerMap[this.m_defaultState.Timer].Add(scene);
394 }
395 else
396 {
397 List<IScene> scns = new List<IScene>(1);
398 scns.Add(scene);
399 this.m_timerMap.Add(this.m_defaultState.Timer, scns);
400 }
401 }
402 }
403
404 bool tmpBusyCheck = ResolveBoolean("AutoBackupBusyCheck",
405 this.m_defaultState.BusyCheck, config, regionConfig);
406 if (state == null && tmpBusyCheck != this.m_defaultState.BusyCheck)
407 {
408 state = new AutoBackupModuleState();
409 }
410
411 if (state != null)
412 {
413 state.BusyCheck = tmpBusyCheck;
414 }
415
416 // Set file naming algorithm
417 string stmpNamingType = ResolveString("AutoBackupNaming",
418 this.m_defaultState.NamingType.ToString(), config, regionConfig);
419 NamingType tmpNamingType;
420 if (stmpNamingType.Equals("Time", StringComparison.CurrentCultureIgnoreCase))
421 {
422 tmpNamingType = NamingType.Time;
423 }
424 else if (stmpNamingType.Equals("Sequential", StringComparison.CurrentCultureIgnoreCase))
425 {
426 tmpNamingType = NamingType.Sequential;
427 }
428 else if (stmpNamingType.Equals("Overwrite", StringComparison.CurrentCultureIgnoreCase))
429 {
430 tmpNamingType = NamingType.Overwrite;
431 }
432 else
433 {
434 m_log.Warn("Unknown naming type specified for region " + sRegionLabel + ": " +
435 stmpNamingType);
436 tmpNamingType = NamingType.Time;
437 }
438
439 if (state == null && tmpNamingType != this.m_defaultState.NamingType)
440 {
441 state = new AutoBackupModuleState();
442 }
443
444 if (state != null)
445 {
446 state.NamingType = tmpNamingType;
447 }
448
449 string tmpScript = ResolveString("AutoBackupScript",
450 this.m_defaultState.Script, config, regionConfig);
451 if (state == null && tmpScript != this.m_defaultState.Script)
452 {
453 state = new AutoBackupModuleState();
454 }
455
456 if (state != null)
457 {
458 state.Script = tmpScript;
459 }
460
461 string tmpBackupDir = ResolveString("AutoBackupDir", ".", config, regionConfig);
462 if (state == null && tmpBackupDir != this.m_defaultState.BackupDir)
463 {
464 state = new AutoBackupModuleState();
465 }
466
467 if (state != null)
468 {
469 state.BackupDir = tmpBackupDir;
470 // Let's give the user some convenience and auto-mkdir
471 if (state.BackupDir != ".")
472 {
473 try
474 {
475 DirectoryInfo dirinfo = new DirectoryInfo(state.BackupDir);
476 if (!dirinfo.Exists)
477 {
478 dirinfo.Create();
479 }
480 }
481 catch (Exception e)
482 {
483 m_log.Warn(
484 "BAD NEWS. You won't be able to save backups to directory " +
485 state.BackupDir +
486 " because it doesn't exist or there's a permissions issue with it. Here's the exception.",
487 e);
488 }
489 }
490 }
491
492 return state;
493 }
494
495 /// <summary>
496 /// Helper function for ParseConfig.
497 /// </summary>
498 /// <param name="settingName"></param>
499 /// <param name="defaultValue"></param>
500 /// <param name="global"></param>
501 /// <param name="local"></param>
502 /// <returns></returns>
503 private bool ResolveBoolean(string settingName, bool defaultValue, IConfig global, IConfig local)
504 {
505 if(local != null)
506 {
507 return local.GetBoolean(settingName, global.GetBoolean(settingName, defaultValue));
508 }
509 else
510 {
511 return global.GetBoolean(settingName, defaultValue);
512 }
513 }
514
515 /// <summary>
516 /// Helper function for ParseConfig.
517 /// </summary>
518 /// <param name="settingName"></param>
519 /// <param name="defaultValue"></param>
520 /// <param name="global"></param>
521 /// <param name="local"></param>
522 /// <returns></returns>
523 private double ResolveDouble(string settingName, double defaultValue, IConfig global, IConfig local)
524 {
525 if (local != null)
526 {
527 return local.GetDouble(settingName, global.GetDouble(settingName, defaultValue));
528 }
529 else
530 {
531 return global.GetDouble(settingName, defaultValue);
532 }
533 }
534
535 /// <summary>
536 /// Helper function for ParseConfig.
537 /// </summary>
538 /// <param name="settingName"></param>
539 /// <param name="defaultValue"></param>
540 /// <param name="global"></param>
541 /// <param name="local"></param>
542 /// <returns></returns>
543 private int ResolveInt(string settingName, int defaultValue, IConfig global, IConfig local)
544 {
545 if (local != null)
546 {
547 return local.GetInt(settingName, global.GetInt(settingName, defaultValue));
548 }
549 else
550 {
551 return global.GetInt(settingName, defaultValue);
552 }
553 }
554
555 /// <summary>
556 /// Helper function for ParseConfig.
557 /// </summary>
558 /// <param name="settingName"></param>
559 /// <param name="defaultValue"></param>
560 /// <param name="global"></param>
561 /// <param name="local"></param>
562 /// <returns></returns>
563 private string ResolveString(string settingName, string defaultValue, IConfig global, IConfig local)
564 {
565 if (local != null)
566 {
567 return local.GetString(settingName, global.GetString(settingName, defaultValue));
568 }
569 else
570 {
571 return global.GetString(settingName, defaultValue);
572 }
573 }
574
575 /// <summary>
576 /// Called when any auto-backup timer expires. This starts the code path for actually performing a backup.
577 /// </summary>
578 /// <param name="sender"></param>
579 /// <param name="e"></param>
580 private void HandleElapsed(object sender, ElapsedEventArgs e)
581 {
582 // TODO: heuristic thresholds are per-region, so we should probably run heuristics once per region
583 // XXX: Running heuristics once per region could add undue performance penalty for something that's supposed to
584 // check whether the region is too busy! Especially on sims with LOTS of regions.
585 // Alternative: make heuristics thresholds global to the module rather than per-region. Less flexible,
586 // but would allow us to be semantically correct while being easier on perf.
587 // Alternative 2: Run heuristics once per unique set of heuristics threshold parameters! Ay yi yi...
588 // Alternative 3: Don't support per-region heuristics at all; just accept them as a global only parameter.
589 // Since this is pretty experimental, I haven't decided which alternative makes the most sense.
590 if (this.m_closed)
591 {
592 return;
593 }
594 bool heuristicsRun = false;
595 bool heuristicsPassed = false;
596 if (!this.m_timerMap.ContainsKey((Timer) sender))
597 {
598 m_log.Debug("Code-up error: timerMap doesn't contain timer " + sender);
599 }
600
601 List<IScene> tmap = this.m_timerMap[(Timer) sender];
602 if (tmap != null && tmap.Count > 0)
603 {
604 foreach (IScene scene in tmap)
605 {
606 AutoBackupModuleState state = this.m_states[scene];
607 bool heuristics = state.BusyCheck;
608
609 // Fast path: heuristics are on; already ran em; and sim is fine; OR, no heuristics for the region.
610 if ((heuristics && heuristicsRun && heuristicsPassed) || !heuristics)
611 {
612 this.DoRegionBackup(scene);
613 // Heuristics are on; ran but we're too busy -- keep going. Maybe another region will have heuristics off!
614 }
615 else if (heuristicsRun)
616 {
617 m_log.Info("[AUTO BACKUP]: Heuristics: too busy to backup " +
618 scene.RegionInfo.RegionName + " right now.");
619 continue;
620 // Logical Deduction: heuristics are on but haven't been run
621 }
622 else
623 {
624 heuristicsPassed = this.RunHeuristics(scene);
625 heuristicsRun = true;
626 if (!heuristicsPassed)
627 {
628 m_log.Info("[AUTO BACKUP]: Heuristics: too busy to backup " +
629 scene.RegionInfo.RegionName + " right now.");
630 continue;
631 }
632 this.DoRegionBackup(scene);
633 }
634 }
635 }
636 }
637
638 /// <summary>
639 /// Save an OAR, register for the callback for when it's done, then call the AutoBackupScript (if applicable).
640 /// </summary>
641 /// <param name="scene"></param>
642 private void DoRegionBackup(IScene scene)
643 {
644 if (scene.RegionStatus != RegionStatus.Up)
645 {
646 // We won't backup a region that isn't operating normally.
647 m_log.Warn("[AUTO BACKUP]: Not backing up region " + scene.RegionInfo.RegionName +
648 " because its status is " + scene.RegionStatus);
649 return;
650 }
651
652 AutoBackupModuleState state = this.m_states[scene];
653 IRegionArchiverModule iram = scene.RequestModuleInterface<IRegionArchiverModule>();
654 string savePath = BuildOarPath(scene.RegionInfo.RegionName,
655 state.BackupDir,
656 state.NamingType);
657 if (savePath == null)
658 {
659 m_log.Warn("[AUTO BACKUP]: savePath is null in HandleElapsed");
660 return;
661 }
662 Guid guid = Guid.NewGuid();
663 m_pendingSaves.Add(guid, scene);
664 state.LiveRequests.Add(guid, savePath);
665 ((Scene) scene).EventManager.OnOarFileSaved += new EventManager.OarFileSaved(EventManager_OnOarFileSaved);
666 iram.ArchiveRegion(savePath, guid, null);
667 }
668
669 /// <summary>
670 /// Called by the Event Manager when the OnOarFileSaved event is fired.
671 /// </summary>
672 /// <param name="guid"></param>
673 /// <param name="message"></param>
674 void EventManager_OnOarFileSaved(Guid guid, string message)
675 {
676 // Ignore if the OAR save is being done by some other part of the system
677 if (m_pendingSaves.ContainsKey(guid))
678 {
679 AutoBackupModuleState abms = m_states[(m_pendingSaves[guid])];
680 ExecuteScript(abms.Script, abms.LiveRequests[guid]);
681 m_pendingSaves.Remove(guid);
682 abms.LiveRequests.Remove(guid);
683 }
684 }
685
686 /// <summary>This format may turn out to be too unwieldy to keep...
687 /// Besides, that's what ctimes are for. But then how do I name each file uniquely without using a GUID?
688 /// Sequential numbers, right? We support those, too!</summary>
689 private static string GetTimeString()
690 {
691 StringWriter sw = new StringWriter();
692 sw.Write("_");
693 DateTime now = DateTime.Now;
694 sw.Write(now.Year);
695 sw.Write("y_");
696 sw.Write(now.Month);
697 sw.Write("M_");
698 sw.Write(now.Day);
699 sw.Write("d_");
700 sw.Write(now.Hour);
701 sw.Write("h_");
702 sw.Write(now.Minute);
703 sw.Write("m_");
704 sw.Write(now.Second);
705 sw.Write("s");
706 sw.Flush();
707 string output = sw.ToString();
708 sw.Close();
709 return output;
710 }
711
712 /// <summary>Return value of true ==> not too busy; false ==> too busy to backup an OAR right now, or error.</summary>
713 private bool RunHeuristics(IScene region)
714 {
715 try
716 {
717 return this.RunTimeDilationHeuristic(region) && this.RunAgentLimitHeuristic(region);
718 }
719 catch (Exception e)
720 {
721 m_log.Warn("[AUTO BACKUP]: Exception in RunHeuristics", e);
722 return false;
723 }
724 }
725
726 /// <summary>
727 /// If the time dilation right at this instant is less than the threshold specified in AutoBackupDilationThreshold (default 0.5),
728 /// then we return false and trip the busy heuristic's "too busy" path (i.e. don't save an OAR).
729 /// AutoBackupDilationThreshold is a _LOWER BOUND_. Lower Time Dilation is bad, so if you go lower than our threshold, it's "too busy".
730 /// </summary>
731 /// <param name="region"></param>
732 /// <returns>Returns true if we're not too busy; false means we've got worse time dilation than the threshold.</returns>
733 private bool RunTimeDilationHeuristic(IScene region)
734 {
735 string regionName = region.RegionInfo.RegionName;
736 return region.TimeDilation >=
737 this.m_configSource.Configs["AutoBackupModule"].GetFloat(
738 regionName + ".AutoBackupDilationThreshold", 0.5f);
739 }
740
741 /// <summary>
742 /// If the root agent count right at this instant is less than the threshold specified in AutoBackupAgentThreshold (default 10),
743 /// then we return false and trip the busy heuristic's "too busy" path (i.e., don't save an OAR).
744 /// AutoBackupAgentThreshold is an _UPPER BOUND_. Higher Agent Count is bad, so if you go higher than our threshold, it's "too busy".
745 /// </summary>
746 /// <param name="region"></param>
747 /// <returns>Returns true if we're not too busy; false means we've got more agents on the sim than the threshold.</returns>
748 private bool RunAgentLimitHeuristic(IScene region)
749 {
750 string regionName = region.RegionInfo.RegionName;
751 try
752 {
753 Scene scene = (Scene) region;
754 // TODO: Why isn't GetRootAgentCount() a method in the IScene interface? Seems generally useful...
755 return scene.GetRootAgentCount() <=
756 this.m_configSource.Configs["AutoBackupModule"].GetInt(
757 regionName + ".AutoBackupAgentThreshold", 10);
758 }
759 catch (InvalidCastException ice)
760 {
761 m_log.Debug(
762 "[AUTO BACKUP]: I NEED MAINTENANCE: IScene is not a Scene; can't get root agent count!",
763 ice);
764 return true;
765 // Non-obstructionist safest answer...
766 }
767 }
768
769 /// <summary>
770 /// Run the script or executable specified by the "AutoBackupScript" config setting.
771 /// Of course this is a security risk if you let anyone modify OpenSim.ini and they want to run some nasty bash script.
772 /// But there are plenty of other nasty things that can be done with an untrusted OpenSim.ini, such as running high threat level scripting functions.
773 /// </summary>
774 /// <param name="scriptName"></param>
775 /// <param name="savePath"></param>
776 private static void ExecuteScript(string scriptName, string savePath)
777 {
778 // Do nothing if there's no script.
779 if (scriptName == null || scriptName.Length <= 0)
780 {
781 return;
782 }
783
784 try
785 {
786 FileInfo fi = new FileInfo(scriptName);
787 if (fi.Exists)
788 {
789 ProcessStartInfo psi = new ProcessStartInfo(scriptName);
790 psi.Arguments = savePath;
791 psi.CreateNoWindow = true;
792 Process proc = Process.Start(psi);
793 proc.ErrorDataReceived += HandleProcErrorDataReceived;
794 }
795 }
796 catch (Exception e)
797 {
798 m_log.Warn(
799 "Exception encountered when trying to run script for oar backup " + savePath, e);
800 }
801 }
802
803 /// <summary>
804 /// Called if a running script process writes to stderr.
805 /// </summary>
806 /// <param name="sender"></param>
807 /// <param name="e"></param>
808 private static void HandleProcErrorDataReceived(object sender, DataReceivedEventArgs e)
809 {
810 m_log.Warn("ExecuteScript hook " + ((Process) sender).ProcessName +
811 " is yacking on stderr: " + e.Data);
812 }
813
814 /// <summary>
815 /// Quickly stop all timers from firing.
816 /// </summary>
817 private void StopAllTimers()
818 {
819 foreach (Timer t in this.m_timerMap.Keys)
820 {
821 t.Close();
822 }
823 this.m_closed = true;
824 }
825
826 /// <summary>
827 /// Determine the next unique filename by number, for "Sequential" AutoBackupNamingType.
828 /// </summary>
829 /// <param name="dirName"></param>
830 /// <param name="regionName"></param>
831 /// <returns></returns>
832 private static string GetNextFile(string dirName, string regionName)
833 {
834 FileInfo uniqueFile = null;
835 long biggestExistingFile = GetNextOarFileNumber(dirName, regionName);
836 biggestExistingFile++;
837 // We don't want to overwrite the biggest existing file; we want to write to the NEXT biggest.
838 uniqueFile =
839 new FileInfo(dirName + Path.DirectorySeparatorChar + regionName + "_" +
840 biggestExistingFile + ".oar");
841 return uniqueFile.FullName;
842 }
843
844 /// <summary>
845 /// Top-level method for creating an absolute path to an OAR backup file based on what naming scheme the user wants.
846 /// </summary>
847 /// <param name="regionName">Name of the region to save.</param>
848 /// <param name="baseDir">Absolute or relative path to the directory where the file should reside.</param>
849 /// <param name="naming">The naming scheme for the file name.</param>
850 /// <returns></returns>
851 private static string BuildOarPath(string regionName, string baseDir, NamingType naming)
852 {
853 FileInfo path = null;
854 switch (naming)
855 {
856 case NamingType.Overwrite:
857 path = new FileInfo(baseDir + Path.DirectorySeparatorChar + regionName + ".oar");
858 return path.FullName;
859 case NamingType.Time:
860 path =
861 new FileInfo(baseDir + Path.DirectorySeparatorChar + regionName +
862 GetTimeString() + ".oar");
863 return path.FullName;
864 case NamingType.Sequential:
865 // All codepaths in GetNextFile should return a file name ending in .oar
866 path = new FileInfo(GetNextFile(baseDir, regionName));
867 return path.FullName;
868 default:
869 m_log.Warn("VERY BAD: Unhandled case element " + naming);
870 break;
871 }
872
873 return null;
874 }
875
876 /// <summary>
877 /// Helper function for Sequential file naming type (see BuildOarPath and GetNextFile).
878 /// </summary>
879 /// <param name="dirName"></param>
880 /// <param name="regionName"></param>
881 /// <returns></returns>
882 private static long GetNextOarFileNumber(string dirName, string regionName)
883 {
884 long retval = 1;
885
886 DirectoryInfo di = new DirectoryInfo(dirName);
887 FileInfo[] fi = di.GetFiles(regionName, SearchOption.TopDirectoryOnly);
888 Array.Sort(fi, (f1, f2) => StringComparer.CurrentCultureIgnoreCase.Compare(f1.Name, f2.Name));
889
890 if (fi.LongLength > 0)
891 {
892 long subtract = 1L;
893 bool worked = false;
894 Regex reg = new Regex(regionName + "_([0-9])+" + ".oar");
895
896 while (!worked && subtract <= fi.LongLength)
897 {
898 // Pick the file with the last natural ordering
899 string biggestFileName = fi[fi.LongLength - subtract].Name;
900 MatchCollection matches = reg.Matches(biggestFileName);
901 long l = 1;
902 if (matches.Count > 0 && matches[0].Groups.Count > 0)
903 {
904 try
905 {
906 long.TryParse(matches[0].Groups[1].Value, out l);
907 retval = l;
908 worked = true;
909 }
910 catch (FormatException fe)
911 {
912 m_log.Warn(
913 "[AUTO BACKUP]: Error: Can't parse long value from file name to determine next OAR backup file number!",
914 fe);
915 subtract++;
916 }
917 }
918 else
919 {
920 subtract++;
921 }
922 }
923 }
924 return retval;
925 }
926 }
927}
928
929
diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs
new file mode 100644
index 0000000..2db718c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs
@@ -0,0 +1,126 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31
32namespace OpenSim.Region.OptionalModules.World.AutoBackup
33{
34 /// <summary>AutoBackupModuleState: Auto-Backup state for one region (scene).
35 /// If you use this class in any way outside of AutoBackupModule, you should treat the class as opaque.
36 /// Since it is not part of the framework, you really should not rely upon it outside of the AutoBackupModule implementation.
37 /// </summary>
38 ///
39 public class AutoBackupModuleState
40 {
41 private Dictionary<Guid, string> m_liveRequests = null;
42
43 public AutoBackupModuleState()
44 {
45 this.Enabled = false;
46 this.BackupDir = ".";
47 this.BusyCheck = true;
48 this.Timer = null;
49 this.NamingType = NamingType.Time;
50 this.Script = null;
51 }
52
53 public Dictionary<Guid, string> LiveRequests
54 {
55 get {
56 return this.m_liveRequests ??
57 (this.m_liveRequests = new Dictionary<Guid, string>(1));
58 }
59 }
60
61 public bool Enabled
62 {
63 get;
64 set;
65 }
66
67 public System.Timers.Timer Timer
68 {
69 get;
70 set;
71 }
72
73 public double IntervalMinutes
74 {
75 get
76 {
77 if (this.Timer == null)
78 {
79 return -1.0;
80 }
81 else
82 {
83 return this.Timer.Interval / 60000.0;
84 }
85 }
86 }
87
88 public bool BusyCheck
89 {
90 get;
91 set;
92 }
93
94 public string Script
95 {
96 get;
97 set;
98 }
99
100 public string BackupDir
101 {
102 get;
103 set;
104 }
105
106 public NamingType NamingType
107 {
108 get;
109 set;
110 }
111
112 public new string ToString()
113 {
114 string retval = "";
115
116 retval += "[AUTO BACKUP]: AutoBackup: " + (Enabled ? "ENABLED" : "DISABLED") + "\n";
117 retval += "[AUTO BACKUP]: Interval: " + IntervalMinutes + " minutes" + "\n";
118 retval += "[AUTO BACKUP]: Do Busy Check: " + (BusyCheck ? "Yes" : "No") + "\n";
119 retval += "[AUTO BACKUP]: Naming Type: " + NamingType.ToString() + "\n";
120 retval += "[AUTO BACKUP]: Backup Dir: " + BackupDir + "\n";
121 retval += "[AUTO BACKUP]: Script: " + Script + "\n";
122 return retval;
123 }
124 }
125}
126