diff options
author | Justin Clarke Casey | 2008-04-03 15:44:20 +0000 |
---|---|---|
committer | Justin Clarke Casey | 2008-04-03 15:44:20 +0000 |
commit | 042cd57e948f6e3695d1d5b2b2a473ee77a1e9c4 (patch) | |
tree | 347f7abdb075b4acba5ece213d667c7c562c99fb | |
parent | * Minor: fix doc glitch (diff) | |
download | opensim-SC_OLD-042cd57e948f6e3695d1d5b2b2a473ee77a1e9c4.zip opensim-SC_OLD-042cd57e948f6e3695d1d5b2b2a473ee77a1e9c4.tar.gz opensim-SC_OLD-042cd57e948f6e3695d1d5b2b2a473ee77a1e9c4.tar.bz2 opensim-SC_OLD-042cd57e948f6e3695d1d5b2b2a473ee77a1e9c4.tar.xz |
* From: Dr Scofield <hud@zurich.ibm.com>
* This patch removes voice code into a region module. This required the implementation of events and other code to allow region modules to register their own caps handlers, and should allow different voice module implementations.
* CAVEAT: This does not provide complete voice support, it merely provides the hooks so that it can be plugged in.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/Communications/Capabilities/Caps.cs | 189 | ||||
-rwxr-xr-x | OpenSim/Framework/Communications/Capabilities/CapsHandlers.cs | 144 | ||||
-rw-r--r-- | OpenSim/Framework/Communications/Capabilities/LLSDCapsDetails.cs | 52 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Modules/VoiceModule.cs | 196 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Scenes/Scene.cs | 6 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Scenes/SceneEvents.cs | 34 | ||||
-rw-r--r-- | bin/OpenSim.ini.example | 2 |
7 files changed, 427 insertions, 196 deletions
diff --git a/OpenSim/Framework/Communications/Capabilities/Caps.cs b/OpenSim/Framework/Communications/Capabilities/Caps.cs index 53cad66..886ca49 100644 --- a/OpenSim/Framework/Communications/Capabilities/Caps.cs +++ b/OpenSim/Framework/Communications/Capabilities/Caps.cs | |||
@@ -55,25 +55,22 @@ namespace OpenSim.Region.Capabilities | |||
55 | public delegate List<InventoryItemBase> FetchInventoryDescendentsCAPS(LLUUID agentID, LLUUID folderID, LLUUID ownerID, | 55 | public delegate List<InventoryItemBase> FetchInventoryDescendentsCAPS(LLUUID agentID, LLUUID folderID, LLUUID ownerID, |
56 | bool fetchFolders, bool fetchItems, int sortOrder); | 56 | bool fetchFolders, bool fetchItems, int sortOrder); |
57 | 57 | ||
58 | /// <summary> | ||
59 | /// FIXME This is a temporary delegate, and should disappear once the voice code is fleshed out and moved into its | ||
60 | /// own region module. | ||
61 | /// </summary> | ||
62 | public delegate CachedUserInfo GetUserDetailsCAPS(LLUUID agentID); | ||
63 | |||
64 | public class Caps | 58 | public class Caps |
65 | { | 59 | { |
66 | private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 60 | private static readonly log4net.ILog m_log = |
67 | 61 | log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | |
62 | |||
68 | private string m_httpListenerHostName; | 63 | private string m_httpListenerHostName; |
69 | private uint m_httpListenPort; | 64 | private uint m_httpListenPort; |
70 | 65 | ||
71 | /// <summary> | 66 | /// <summary> |
72 | /// This is the uuid portion of every CAPS path. It is used to make capability urls private to the requester. | 67 | /// This is the uuid portion of every CAPS path. It is used to make capability urls private to the requester. |
73 | /// </summary> | 68 | /// </summary> |
74 | private string m_capsObjectPath; | 69 | private string m_capsObjectPath; |
75 | public string CapsObjectPath { get { return m_capsObjectPath; } } | 70 | public string CapsObjectPath { get { return m_capsObjectPath; } } |
76 | 71 | ||
72 | private CapsHandlers m_capsHandlers; | ||
73 | |||
77 | private static readonly string m_requestPath = "0000/"; | 74 | private static readonly string m_requestPath = "0000/"; |
78 | private static readonly string m_mapLayerPath = "0001/"; | 75 | private static readonly string m_mapLayerPath = "0001/"; |
79 | private static readonly string m_newInventory = "0002/"; | 76 | private static readonly string m_newInventory = "0002/"; |
@@ -99,7 +96,6 @@ namespace OpenSim.Region.Capabilities | |||
99 | public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null; | 96 | public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null; |
100 | // | 97 | // |
101 | public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null; | 98 | public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null; |
102 | public GetUserDetailsCAPS CAPSGetUserDetails = null; | ||
103 | 99 | ||
104 | public Caps(AssetCache assetCache, BaseHttpServer httpServer, string httpListen, uint httpPort, string capsPath, | 100 | public Caps(AssetCache assetCache, BaseHttpServer httpServer, string httpListen, uint httpPort, string capsPath, |
105 | LLUUID agent, bool dumpAssetsToFile) | 101 | LLUUID agent, bool dumpAssetsToFile) |
@@ -111,6 +107,7 @@ namespace OpenSim.Region.Capabilities | |||
111 | m_httpListenPort = httpPort; | 107 | m_httpListenPort = httpPort; |
112 | m_agentID = agent; | 108 | m_agentID = agent; |
113 | m_dumpAssetsToFile = dumpAssetsToFile; | 109 | m_dumpAssetsToFile = dumpAssetsToFile; |
110 | m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort); | ||
114 | } | 111 | } |
115 | 112 | ||
116 | /// <summary> | 113 | /// <summary> |
@@ -123,27 +120,31 @@ namespace OpenSim.Region.Capabilities | |||
123 | string capsBase = "/CAPS/" + m_capsObjectPath; | 120 | string capsBase = "/CAPS/" + m_capsObjectPath; |
124 | 121 | ||
125 | try | 122 | try |
126 | { | 123 | { |
127 | m_httpListener.AddStreamHandler( | 124 | // the root of all evil |
128 | new LLSDStreamhandler<LLSDMapRequest, LLSDMapLayerResponse>("POST", capsBase + m_mapLayerPath, GetMapLayer)); | 125 | m_capsHandlers["SEED"] = new RestStreamHandler("POST", capsBase + m_requestPath, CapsRequest); |
129 | m_httpListener.AddStreamHandler( | 126 | m_capsHandlers["MapLayer"] = |
127 | new LLSDStreamhandler<LLSDMapRequest, LLSDMapLayerResponse>("POST", | ||
128 | capsBase + m_mapLayerPath, | ||
129 | GetMapLayer); | ||
130 | m_capsHandlers["NewFileAgentInventory"] = | ||
130 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>("POST", | 131 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>("POST", |
131 | capsBase + m_newInventory, | 132 | capsBase + m_newInventory, |
132 | NewAgentInventoryRequest)); | 133 | NewAgentInventoryRequest); |
133 | 134 | m_capsHandlers["UpdateNotecardAgentInventory"] = | |
134 | // m_httpListener.AddStreamHandler( | 135 | new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory); |
135 | // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST", | 136 | m_capsHandlers["UpdateScriptAgentInventory"] = m_capsHandlers["UpdateNotecardAgentInventory"]; |
136 | // capsBase + m_fetchInventory, | 137 | m_capsHandlers["UpdateScriptTaskInventory"] = |
137 | // FetchInventory)); | 138 | new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory); |
138 | 139 | m_capsHandlers["FetchInventoryDescendents"] = | |
139 | 140 | new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest); | |
140 | AddLegacyCapsHandler(m_httpListener, m_requestPath, CapsRequest); | 141 | // m_capsHandlers["FetchInventoryDescendents"] = |
141 | //AddLegacyCapsHandler(m_httpListener, m_requestTexture , RequestTexture); | 142 | // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST", |
142 | AddLegacyCapsHandler(m_httpListener, m_parcelVoiceInfoRequestPath, ParcelVoiceInfoRequest); | 143 | // capsBase + m_fetchInventory, |
143 | AddLegacyCapsHandler(m_httpListener, m_provisionVoiceAccountRequestPath, ProvisionVoiceAccountRequest); | 144 | // FetchInventory)); |
144 | AddLegacyCapsHandler(m_httpListener, m_notecardUpdatePath, NoteCardAgentInventory); | 145 | // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST", |
145 | AddLegacyCapsHandler(m_httpListener, m_notecardTaskUpdatePath, ScriptTaskInventory); | 146 | // capsBase + m_requestTexture, |
146 | AddLegacyCapsHandler(m_httpListener, m_fetchInventoryPath, FetchInventoryRequest); | 147 | // RequestTexture); |
147 | } | 148 | } |
148 | catch (Exception e) | 149 | catch (Exception e) |
149 | { | 150 | { |
@@ -152,35 +153,29 @@ namespace OpenSim.Region.Capabilities | |||
152 | } | 153 | } |
153 | 154 | ||
154 | /// <summary> | 155 | /// <summary> |
156 | /// Register a handler. This allows modules to register handlers. | ||
157 | /// </summary> | ||
158 | /// <param name="capName"></param> | ||
159 | /// <param name="handler"></param> | ||
160 | public void RegisterHandler(string capName, IRequestHandler handler) | ||
161 | { | ||
162 | m_capsHandlers[capName] = handler; | ||
163 | m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path); | ||
164 | } | ||
165 | |||
166 | /// <summary> | ||
155 | /// Remove all CAPS service handlers. | 167 | /// Remove all CAPS service handlers. |
156 | /// | 168 | /// |
157 | /// FIXME: Would be much nicer to remove and all paths to a single list. However, this is a little awkward | ||
158 | /// than it could be as we set up some handlers differently (legacy and non-legacy) | ||
159 | /// </summary> | 169 | /// </summary> |
160 | /// <param name="httpListener"></param> | 170 | /// <param name="httpListener"></param> |
161 | /// <param name="path"></param> | 171 | /// <param name="path"></param> |
162 | /// <param name="restMethod"></param> | 172 | /// <param name="restMethod"></param> |
163 | public void DeregisterHandlers() | 173 | public void DeregisterHandlers() |
164 | { | 174 | { |
165 | string capsBase = "/CAPS/" + m_capsObjectPath; | 175 | foreach(string capsName in m_capsHandlers.Caps) |
166 | 176 | { | |
167 | m_httpListener.RemoveStreamHandler("POST", capsBase + m_mapLayerPath); | 177 | m_capsHandlers.Remove(capsName); |
168 | m_httpListener.RemoveStreamHandler("POST", capsBase + m_newInventory); | 178 | } |
169 | m_httpListener.RemoveStreamHandler("POST", capsBase + m_requestPath); | ||
170 | m_httpListener.RemoveStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath); | ||
171 | m_httpListener.RemoveStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath); | ||
172 | m_httpListener.RemoveStreamHandler("POST", capsBase + m_notecardUpdatePath); | ||
173 | m_httpListener.RemoveStreamHandler("POST", capsBase + m_notecardTaskUpdatePath); | ||
174 | m_httpListener.RemoveStreamHandler("POST", capsBase + m_fetchInventoryPath); | ||
175 | } | ||
176 | |||
177 | //[Obsolete("Use BaseHttpServer.AddStreamHandler(new LLSDStreamHandler( LLSDMethod delegate )) instead.")] | ||
178 | //Commented out the obsolete as at this time the first caps request can not use the new Caps method | ||
179 | //as the sent type is a array and not a map and the deserialising doesn't deal properly with arrays. | ||
180 | private void AddLegacyCapsHandler(BaseHttpServer httpListener, string path, RestMethod restMethod) | ||
181 | { | ||
182 | string capsBase = "/CAPS/" + m_capsObjectPath; | ||
183 | httpListener.AddStreamHandler(new RestStreamHandler("POST", capsBase + path, restMethod)); | ||
184 | } | 179 | } |
185 | 180 | ||
186 | /// <summary> | 181 | /// <summary> |
@@ -193,31 +188,12 @@ namespace OpenSim.Region.Capabilities | |||
193 | public string CapsRequest(string request, string path, string param) | 188 | public string CapsRequest(string request, string path, string param) |
194 | { | 189 | { |
195 | //Console.WriteLine("caps request " + request); | 190 | //Console.WriteLine("caps request " + request); |
196 | string result = LLSDHelpers.SerialiseLLSDReply(GetCapabilities()); | 191 | string result = LLSDHelpers.SerialiseLLSDReply(m_capsHandlers.CapsDetails); |
197 | return result; | 192 | return result; |
198 | } | 193 | } |
199 | 194 | ||
200 | /// <summary> | 195 | // FIXME: these all should probably go into the respective region |
201 | /// Return an LLSDCapsDetails listing all the capabilities this server can provide | 196 | // modules |
202 | /// </summary> | ||
203 | /// <returns></returns> | ||
204 | protected LLSDCapsDetails GetCapabilities() | ||
205 | { | ||
206 | LLSDCapsDetails caps = new LLSDCapsDetails(); | ||
207 | string capsBaseUrl = "http://" + m_httpListenerHostName + ":" + m_httpListenPort.ToString() + "/CAPS/" + | ||
208 | m_capsObjectPath; | ||
209 | caps.MapLayer = capsBaseUrl + m_mapLayerPath; | ||
210 | // caps.RequestTextureDownload = capsBaseUrl + m_requestTexture; | ||
211 | caps.NewFileAgentInventory = capsBaseUrl + m_newInventory; | ||
212 | caps.UpdateNotecardAgentInventory = capsBaseUrl + m_notecardUpdatePath; | ||
213 | caps.UpdateScriptAgentInventory = capsBaseUrl + m_notecardUpdatePath; | ||
214 | caps.UpdateScriptTaskInventory = capsBaseUrl + m_notecardTaskUpdatePath; | ||
215 | caps.FetchInventoryDescendents = capsBaseUrl + m_fetchInventoryPath; | ||
216 | caps.ParcelVoiceInfoRequest = capsBaseUrl + m_parcelVoiceInfoRequestPath; | ||
217 | caps.ProvisionVoiceAccountRequest = capsBaseUrl + m_provisionVoiceAccountRequestPath; | ||
218 | |||
219 | return caps; | ||
220 | } | ||
221 | 197 | ||
222 | public string FetchInventoryRequest(string request, string path, string param) | 198 | public string FetchInventoryRequest(string request, string path, string param) |
223 | { | 199 | { |
@@ -443,75 +419,6 @@ namespace OpenSim.Region.Capabilities | |||
443 | return null; | 419 | return null; |
444 | } | 420 | } |
445 | 421 | ||
446 | /// <summary> | ||
447 | /// Callback for a client request for ParcelVoiceInfo | ||
448 | /// </summary> | ||
449 | /// <param name="request"></param> | ||
450 | /// <param name="path"></param> | ||
451 | /// <param name="param"></param> | ||
452 | /// <returns></returns> | ||
453 | public string ParcelVoiceInfoRequest(string request, string path, string param) { | ||
454 | try | ||
455 | { | ||
456 | m_log.DebugFormat("[CAPS][PARCELVOICE]: request: {0}, path: {1}, param: {2}", request, path, param); | ||
457 | |||
458 | // XXX brutal hack, we need to get channel_uri, region | ||
459 | // name, and parcel_local_id from somewhere | ||
460 | Hashtable creds = new Hashtable(); | ||
461 | |||
462 | creds["channel_uri"] = "sip:testroom@testserver.com"; | ||
463 | |||
464 | LLSDParcelVoiceInfoResponse parcelVoiceInfo = | ||
465 | new LLSDParcelVoiceInfoResponse("OpenSim Test", 1, creds); | ||
466 | |||
467 | // XXX for debugging purposes: | ||
468 | string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo); | ||
469 | m_log.DebugFormat("[CAPS][PARCELVOICE]: {0}", r); | ||
470 | |||
471 | return r; | ||
472 | } | ||
473 | catch (Exception e) | ||
474 | { | ||
475 | m_log.Error("[CAPS]: " + e.ToString()); | ||
476 | } | ||
477 | |||
478 | return null; | ||
479 | } | ||
480 | |||
481 | /// <summary> | ||
482 | /// Callback for a client request for Voice Account Details | ||
483 | /// </summary> | ||
484 | /// <param name="request"></param> | ||
485 | /// <param name="path"></param> | ||
486 | /// <param name="param"></param> | ||
487 | /// <returns></returns> | ||
488 | public string ProvisionVoiceAccountRequest(string request, string path, string param) { | ||
489 | try | ||
490 | { | ||
491 | m_log.DebugFormat("[CAPS][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}", request, path, param); | ||
492 | |||
493 | if (null == CAPSGetUserDetails) throw new Exception("CAPSGetUserDetails null"); | ||
494 | |||
495 | string voiceUser = "x" + Convert.ToBase64String(m_agentID.GetBytes()); | ||
496 | voiceUser = voiceUser.Replace('+', '-').Replace('/', '_'); | ||
497 | |||
498 | CachedUserInfo userInfo = CAPSGetUserDetails(m_agentID); | ||
499 | if (null == userInfo) throw new Exception("CAPSGetUserDetails returned null"); | ||
500 | |||
501 | LLSDVoiceAccountResponse voiceAccountResponse = | ||
502 | new LLSDVoiceAccountResponse(voiceUser, "$1$" + userInfo.UserProfile.passwordHash); | ||
503 | string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse); | ||
504 | m_log.DebugFormat("[CAPS][PROVISIONVOICE]: {0}", r); | ||
505 | return r; | ||
506 | } | ||
507 | catch (Exception e) | ||
508 | { | ||
509 | m_log.Error("[CAPS][PROVISIONVOICE]: " + e.ToString()); | ||
510 | } | ||
511 | |||
512 | return null; | ||
513 | } | ||
514 | |||
515 | /// <summary> | 422 | /// <summary> |
516 | /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset. | 423 | /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset. |
517 | /// </summary> | 424 | /// </summary> |
diff --git a/OpenSim/Framework/Communications/Capabilities/CapsHandlers.cs b/OpenSim/Framework/Communications/Capabilities/CapsHandlers.cs new file mode 100755 index 0000000..a3d6b71 --- /dev/null +++ b/OpenSim/Framework/Communications/Capabilities/CapsHandlers.cs | |||
@@ -0,0 +1,144 @@ | |||
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 OpenSim 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using libsecondlife; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Framework.Communications.Cache; | ||
35 | using OpenSim.Framework.Console; | ||
36 | using OpenSim.Framework.Servers; | ||
37 | |||
38 | namespace OpenSim.Region.Capabilities | ||
39 | { | ||
40 | /// <summary> | ||
41 | /// CapsHandlers is a cap handler container but also takes | ||
42 | /// care of adding and removing cap handlers to and from the | ||
43 | /// supplied BaseHttpServer. | ||
44 | /// </summary> | ||
45 | public class CapsHandlers | ||
46 | { | ||
47 | private Dictionary <string, IRequestHandler> m_capsHandlers = new Dictionary<string, IRequestHandler>(); | ||
48 | private BaseHttpServer m_httpListener; | ||
49 | private string m_httpListenerHostName; | ||
50 | private uint m_httpListenerPort; | ||
51 | |||
52 | /// <summary></summary> | ||
53 | /// <param name="httpListener">base HTTP server</param> | ||
54 | /// <param name="httpListenerHostname">host name of the HTTP | ||
55 | /// server</param> | ||
56 | /// <param name="httpListenerPort">HTTP port</param> | ||
57 | public CapsHandlers(BaseHttpServer httpListener, string httpListenerHostname, uint httpListenerPort) | ||
58 | { | ||
59 | m_httpListener = httpListener; | ||
60 | m_httpListenerHostName = httpListenerHostname; | ||
61 | m_httpListenerPort = httpListenerPort; | ||
62 | } | ||
63 | |||
64 | /// <summary> | ||
65 | /// Remove the cap handler for a capability. | ||
66 | /// </summary> | ||
67 | /// <param name="capsName">name of the capability of the cap | ||
68 | /// handler to be removed</param> | ||
69 | public void Remove(string capsName) | ||
70 | { | ||
71 | m_capsHandlers.Remove(capsName); | ||
72 | } | ||
73 | |||
74 | public bool ContainsCap(string cap) | ||
75 | { | ||
76 | return m_capsHandlers.ContainsKey(cap); | ||
77 | } | ||
78 | |||
79 | /// <summary> | ||
80 | /// The indexer allows us to treat the CapsHandlers object | ||
81 | /// in an intuitive dictionary like way. | ||
82 | /// </summary> | ||
83 | /// <Remarks> | ||
84 | /// The indexer will throw an exception when you try to | ||
85 | /// retrieve a cap handler for a cap that is not contained in | ||
86 | /// CapsHandlers. | ||
87 | /// </Remarks> | ||
88 | public IRequestHandler this[string idx] | ||
89 | { | ||
90 | get | ||
91 | { | ||
92 | return m_capsHandlers[idx]; | ||
93 | } | ||
94 | |||
95 | set | ||
96 | { | ||
97 | if (m_capsHandlers.ContainsKey(idx)) | ||
98 | { | ||
99 | m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[idx].Path); | ||
100 | m_capsHandlers.Remove(idx); | ||
101 | } | ||
102 | |||
103 | if (null == value) return; | ||
104 | |||
105 | m_capsHandlers[idx] = value; | ||
106 | m_httpListener.AddStreamHandler(value); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /// <summary> | ||
111 | /// Return the list of cap names for which this CapsHandlers | ||
112 | /// object contains cap handlers. | ||
113 | /// </summary> | ||
114 | public string[] Caps | ||
115 | { | ||
116 | get | ||
117 | { | ||
118 | string[] __keys = new string[m_capsHandlers.Keys.Count]; | ||
119 | m_capsHandlers.Keys.CopyTo(__keys, 0); | ||
120 | return __keys; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | /// <summary> | ||
125 | /// Return an LLSD-serializable Hashtable describing the | ||
126 | /// capabilities and their handler details. | ||
127 | /// </summary> | ||
128 | public Hashtable CapsDetails | ||
129 | { | ||
130 | get | ||
131 | { | ||
132 | Hashtable caps = new Hashtable(); | ||
133 | string baseUrl = "http://" + m_httpListenerHostName + ":" + m_httpListenerPort.ToString(); | ||
134 | foreach (string capsName in m_capsHandlers.Keys) | ||
135 | { | ||
136 | // skip SEED cap | ||
137 | if ("SEED" == capsName) continue; | ||
138 | caps[capsName] = baseUrl + m_capsHandlers[capsName].Path; | ||
139 | } | ||
140 | return caps; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | } | ||
diff --git a/OpenSim/Framework/Communications/Capabilities/LLSDCapsDetails.cs b/OpenSim/Framework/Communications/Capabilities/LLSDCapsDetails.cs deleted file mode 100644 index bd1c9da..0000000 --- a/OpenSim/Framework/Communications/Capabilities/LLSDCapsDetails.cs +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
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 OpenSim 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 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.Capabilities | ||
31 | { | ||
32 | [LLSDType("MAP")] | ||
33 | public class LLSDCapsDetails | ||
34 | { | ||
35 | public string MapLayer = String.Empty; | ||
36 | public string NewFileAgentInventory = String.Empty; | ||
37 | //public string EventQueueGet = String.Empty; | ||
38 | // public string RequestTextureDownload = String.Empty; | ||
39 | // public string ChatSessionRequest = String.Empty; | ||
40 | public string UpdateNotecardAgentInventory = String.Empty; | ||
41 | public string UpdateScriptAgentInventory = String.Empty; | ||
42 | public string UpdateScriptTaskInventory = String.Empty; | ||
43 | public string ParcelVoiceInfoRequest = String.Empty; | ||
44 | public string FetchInventoryDescendents = String.Empty; | ||
45 | public string ProvisionVoiceAccountRequest = String.Empty; | ||
46 | |||
47 | |||
48 | public LLSDCapsDetails() | ||
49 | { | ||
50 | } | ||
51 | } | ||
52 | } | ||
diff --git a/OpenSim/Region/Environment/Modules/VoiceModule.cs b/OpenSim/Region/Environment/Modules/VoiceModule.cs new file mode 100644 index 0000000..b254507 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/VoiceModule.cs | |||
@@ -0,0 +1,196 @@ | |||
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 OpenSim 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using libsecondlife; | ||
32 | using Nini.Config; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Framework.Communications.Cache; | ||
35 | using OpenSim.Framework.Servers; | ||
36 | using OpenSim.Region.Capabilities; | ||
37 | using Caps = OpenSim.Region.Capabilities.Caps; | ||
38 | using OpenSim.Region.Environment.Interfaces; | ||
39 | using OpenSim.Region.Environment.Scenes; | ||
40 | |||
41 | namespace OpenSim.Region.Environment.Modules | ||
42 | { | ||
43 | public class VoiceModule : IRegionModule | ||
44 | { | ||
45 | private static readonly log4net.ILog m_log = | ||
46 | log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | private Scene m_scene; | ||
49 | private IConfig m_config; | ||
50 | private string m_sipDomain; | ||
51 | |||
52 | private static readonly string m_parcelVoiceInfoRequestPath = "0007/"; | ||
53 | private static readonly string m_provisionVoiceAccountRequestPath = "0008/"; | ||
54 | |||
55 | public void Initialise(Scene scene, IConfigSource config) | ||
56 | { | ||
57 | m_scene = scene; | ||
58 | m_config = config.Configs["Voice"]; | ||
59 | |||
60 | if (null == m_config || !m_config.GetBoolean("enabled", false)) | ||
61 | { | ||
62 | m_log.Info("[VOICE] plugin disabled"); | ||
63 | return; | ||
64 | } | ||
65 | m_log.Info("[VOICE] plugin enabled"); | ||
66 | |||
67 | m_sipDomain = m_config.GetString("sip_domain", String.Empty); | ||
68 | if (String.IsNullOrEmpty(m_sipDomain)) | ||
69 | { | ||
70 | m_log.Error("[VOICE] plugin mis-configured: missing sip_domain configuration"); | ||
71 | m_log.Info("[VOICE] plugin disabled"); | ||
72 | return; | ||
73 | } | ||
74 | m_log.InfoFormat("[VOICE] using SIP domain {0}", m_sipDomain); | ||
75 | |||
76 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
77 | } | ||
78 | |||
79 | public void PostInitialise() | ||
80 | { | ||
81 | } | ||
82 | |||
83 | public void Close() | ||
84 | { | ||
85 | } | ||
86 | |||
87 | public string Name | ||
88 | { | ||
89 | get { return "VoiceModule"; } | ||
90 | } | ||
91 | |||
92 | public bool IsSharedModule | ||
93 | { | ||
94 | get { return false; } | ||
95 | } | ||
96 | |||
97 | public void OnRegisterCaps(LLUUID agentID, Caps caps) | ||
98 | { | ||
99 | m_log.DebugFormat("[VOICE] OnRegisterCaps: agentID {0} caps {1}", agentID, caps); | ||
100 | string capsBase = "/CAPS/" + caps.CapsObjectPath; | ||
101 | caps.RegisterHandler("ParcelVoiceInfoRequest", | ||
102 | new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath, | ||
103 | delegate(string request, string path, string param) | ||
104 | { | ||
105 | return ParcelVoiceInfoRequest(request, path, param, | ||
106 | agentID, caps); | ||
107 | })); | ||
108 | caps.RegisterHandler("ProvisionVoiceAccountRequest", | ||
109 | new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath, | ||
110 | delegate(string request, string path, string param) | ||
111 | { | ||
112 | return ProvisionVoiceAccountRequest(request, path, param, | ||
113 | agentID, caps); | ||
114 | })); | ||
115 | } | ||
116 | |||
117 | /// <summary> | ||
118 | /// Callback for a client request for ParcelVoiceInfo | ||
119 | /// </summary> | ||
120 | /// <param name="request"></param> | ||
121 | /// <param name="path"></param> | ||
122 | /// <param name="param"></param> | ||
123 | /// <param name="agentID"></param> | ||
124 | /// <param name="caps"></param> | ||
125 | /// <returns></returns> | ||
126 | public string ParcelVoiceInfoRequest(string request, string path, string param, | ||
127 | LLUUID agentID, Caps caps) | ||
128 | { | ||
129 | try | ||
130 | { | ||
131 | m_log.DebugFormat("[VOICE][PARCELVOICE]: request: {0}, path: {1}, param: {2}", request, path, param); | ||
132 | |||
133 | // FIXME: get the creds from region file or from config | ||
134 | Hashtable creds = new Hashtable(); | ||
135 | |||
136 | creds["channel_uri"] = String.Format("sip:{0}@{1}", agentID.ToString(), m_sipDomain); | ||
137 | |||
138 | string regionName = m_scene.RegionInfo.RegionName; | ||
139 | ScenePresence avatar = m_scene.GetScenePresence(agentID); | ||
140 | if (null == m_scene.LandChannel) throw new Exception("land data not yet available"); | ||
141 | LandData land = m_scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); | ||
142 | |||
143 | LLSDParcelVoiceInfoResponse parcelVoiceInfo = | ||
144 | new LLSDParcelVoiceInfoResponse(regionName, land.localID, creds); | ||
145 | |||
146 | string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo); | ||
147 | m_log.DebugFormat("[VOICE][PARCELVOICE]: {0}", r); | ||
148 | |||
149 | return r; | ||
150 | } | ||
151 | catch (Exception e) | ||
152 | { | ||
153 | m_log.ErrorFormat("[CAPS]: {0}, try again later", e.ToString()); | ||
154 | } | ||
155 | |||
156 | return null; | ||
157 | } | ||
158 | |||
159 | /// <summary> | ||
160 | /// Callback for a client request for Voice Account Details | ||
161 | /// </summary> | ||
162 | /// <param name="request"></param> | ||
163 | /// <param name="path"></param> | ||
164 | /// <param name="param"></param> | ||
165 | /// <param name="agentID"></param> | ||
166 | /// <param name="caps"></param> | ||
167 | /// <returns></returns> | ||
168 | public string ProvisionVoiceAccountRequest(string request, string path, string param, | ||
169 | LLUUID agentID, Caps caps) | ||
170 | { | ||
171 | try | ||
172 | { | ||
173 | m_log.DebugFormat("[VOICE][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}", | ||
174 | request, path, param); | ||
175 | |||
176 | string voiceUser = "x" + Convert.ToBase64String(agentID.GetBytes()); | ||
177 | voiceUser = voiceUser.Replace('+', '-').Replace('/', '_'); | ||
178 | |||
179 | CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID); | ||
180 | if (null == userInfo) throw new Exception("cannot get user details"); | ||
181 | |||
182 | LLSDVoiceAccountResponse voiceAccountResponse = | ||
183 | new LLSDVoiceAccountResponse(voiceUser, "$1$" + userInfo.UserProfile.passwordHash); | ||
184 | string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse); | ||
185 | m_log.DebugFormat("[CAPS][PROVISIONVOICE]: {0}", r); | ||
186 | return r; | ||
187 | } | ||
188 | catch (Exception e) | ||
189 | { | ||
190 | m_log.ErrorFormat("[CAPS][PROVISIONVOICE]: {0}, retry later", e.Message); | ||
191 | } | ||
192 | |||
193 | return null; | ||
194 | } | ||
195 | } | ||
196 | } | ||
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 2237922..64c443d 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs | |||
@@ -1737,14 +1737,14 @@ namespace OpenSim.Region.Environment.Scenes | |||
1737 | Caps cap = | 1737 | Caps cap = |
1738 | new Caps(AssetCache, m_httpListener, m_regInfo.ExternalHostName, m_httpListener.Port, | 1738 | new Caps(AssetCache, m_httpListener, m_regInfo.ExternalHostName, m_httpListener.Port, |
1739 | capsObjectPath, agentId, m_dumpAssetsToFile); | 1739 | capsObjectPath, agentId, m_dumpAssetsToFile); |
1740 | |||
1741 | cap.RegisterHandlers(); | 1740 | cap.RegisterHandlers(); |
1741 | |||
1742 | EventManager.TriggerOnRegisterCaps(agentId, cap); | ||
1742 | 1743 | ||
1743 | cap.AddNewInventoryItem = AddInventoryItem; | 1744 | cap.AddNewInventoryItem = AddInventoryItem; |
1744 | cap.ItemUpdatedCall = CapsUpdateInventoryItemAsset; | 1745 | cap.ItemUpdatedCall = CapsUpdateInventoryItemAsset; |
1745 | cap.TaskScriptUpdatedCall = CapsUpdateTaskInventoryScriptAsset; | 1746 | cap.TaskScriptUpdatedCall = CapsUpdateTaskInventoryScriptAsset; |
1746 | cap.CAPSFetchInventoryDescendents = CommsManager.UserProfileCacheService.HandleFetchInventoryDescendentsCAPS; | 1747 | cap.CAPSFetchInventoryDescendents = CommsManager.UserProfileCacheService.HandleFetchInventoryDescendentsCAPS; |
1747 | cap.CAPSGetUserDetails = CommsManager.UserProfileCacheService.GetUserDetails; | ||
1748 | 1748 | ||
1749 | m_capsHandlers[agentId] = cap; | 1749 | m_capsHandlers[agentId] = cap; |
1750 | } | 1750 | } |
@@ -1764,6 +1764,8 @@ namespace OpenSim.Region.Environment.Scenes | |||
1764 | agentId, RegionInfo.RegionName); | 1764 | agentId, RegionInfo.RegionName); |
1765 | 1765 | ||
1766 | m_capsHandlers[agentId].DeregisterHandlers(); | 1766 | m_capsHandlers[agentId].DeregisterHandlers(); |
1767 | EventManager.TriggerOnDeregisterCaps(agentId, m_capsHandlers[agentId]); | ||
1768 | |||
1767 | m_capsHandlers.Remove(agentId); | 1769 | m_capsHandlers.Remove(agentId); |
1768 | } | 1770 | } |
1769 | else | 1771 | else |
diff --git a/OpenSim/Region/Environment/Scenes/SceneEvents.cs b/OpenSim/Region/Environment/Scenes/SceneEvents.cs index 809507c..c916009 100644 --- a/OpenSim/Region/Environment/Scenes/SceneEvents.cs +++ b/OpenSim/Region/Environment/Scenes/SceneEvents.cs | |||
@@ -29,6 +29,7 @@ using libsecondlife; | |||
29 | using System; | 29 | using System; |
30 | using OpenSim.Framework; | 30 | using OpenSim.Framework; |
31 | using OpenSim.Region.Environment.Interfaces; | 31 | using OpenSim.Region.Environment.Interfaces; |
32 | using Caps = OpenSim.Region.Capabilities.Caps; | ||
32 | 33 | ||
33 | namespace OpenSim.Region.Environment.Scenes | 34 | namespace OpenSim.Region.Environment.Scenes |
34 | { | 35 | { |
@@ -136,6 +137,19 @@ namespace OpenSim.Region.Environment.Scenes | |||
136 | 137 | ||
137 | public event OnNewPresenceDelegate OnMakeChildAgent; | 138 | public event OnNewPresenceDelegate OnMakeChildAgent; |
138 | 139 | ||
140 | /// <summary> | ||
141 | /// RegisterCapsEvent is called by Scene after the Caps object | ||
142 | /// has been instantiated and before it is return to the | ||
143 | /// client and provides region modules to add their caps. | ||
144 | /// </summary> | ||
145 | public delegate void RegisterCapsEvent(LLUUID agentID, Caps caps); | ||
146 | public event RegisterCapsEvent OnRegisterCaps; | ||
147 | /// <summary> | ||
148 | /// DeregisterCapsEvent is called by Scene when the caps | ||
149 | /// handler for an agent are removed. | ||
150 | /// </summary> | ||
151 | public delegate void DeregisterCapsEvent(LLUUID agentID, Caps caps); | ||
152 | public event DeregisterCapsEvent OnDeregisterCaps; | ||
139 | 153 | ||
140 | public class MoneyTransferArgs : System.EventArgs | 154 | public class MoneyTransferArgs : System.EventArgs |
141 | { | 155 | { |
@@ -191,6 +205,8 @@ namespace OpenSim.Region.Environment.Scenes | |||
191 | private ClientClosed handlerClientClosed = null; //OnClientClosed; | 205 | private ClientClosed handlerClientClosed = null; //OnClientClosed; |
192 | private OnNewPresenceDelegate handlerMakeChildAgent = null; //OnMakeChildAgent; | 206 | private OnNewPresenceDelegate handlerMakeChildAgent = null; //OnMakeChildAgent; |
193 | private OnTerrainTickDelegate handlerTerrainTick = null; // OnTerainTick; | 207 | private OnTerrainTickDelegate handlerTerrainTick = null; // OnTerainTick; |
208 | private RegisterCapsEvent handlerRegisterCaps = null; // OnRegisterCaps; | ||
209 | private DeregisterCapsEvent handlerDeregisterCaps = null; // OnDeregisterCaps; | ||
194 | 210 | ||
195 | public void TriggerOnScriptChangedEvent(uint localID, uint change) | 211 | public void TriggerOnScriptChangedEvent(uint localID, uint change) |
196 | { | 212 | { |
@@ -428,5 +444,23 @@ namespace OpenSim.Region.Environment.Scenes | |||
428 | handlerMakeChildAgent(presence); | 444 | handlerMakeChildAgent(presence); |
429 | } | 445 | } |
430 | } | 446 | } |
447 | |||
448 | public void TriggerOnRegisterCaps(LLUUID agentID, Caps caps) | ||
449 | { | ||
450 | handlerRegisterCaps = OnRegisterCaps; | ||
451 | if (handlerRegisterCaps != null) | ||
452 | { | ||
453 | handlerRegisterCaps(agentID, caps); | ||
454 | } | ||
455 | } | ||
456 | |||
457 | public void TriggerOnDeregisterCaps(LLUUID agentID, Caps caps) | ||
458 | { | ||
459 | handlerDeregisterCaps = OnDeregisterCaps; | ||
460 | if (handlerDeregisterCaps != null) | ||
461 | { | ||
462 | handlerDeregisterCaps(agentID, caps); | ||
463 | } | ||
464 | } | ||
431 | } | 465 | } |
432 | } | 466 | } |
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 5a6ef06..bf8a48f 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example | |||
@@ -164,7 +164,7 @@ enabled = false | |||
164 | ; changed in future. :-) | 164 | ; changed in future. :-) |
165 | account_management_server = https://www.bhr.vivox.com/api2 | 165 | account_management_server = https://www.bhr.vivox.com/api2 |
166 | ; Global SIP Server for conference calls | 166 | ; Global SIP Server for conference calls |
167 | sip_uri = sip:testroom@testserver.com | 167 | sip_domain = testserver.com |
168 | 168 | ||
169 | ; Uncomment the following to control the progression of daytime | 169 | ; Uncomment the following to control the progression of daytime |
170 | ; in the Sim. The defaults are what is shown below | 170 | ; in the Sim. The defaults are what is shown below |