aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
diff options
context:
space:
mode:
authorAdam Frisby2008-04-30 21:16:36 +0000
committerAdam Frisby2008-04-30 21:16:36 +0000
commitf5c312bc3c2567449c7268a54a08a54119f58d53 (patch)
tree424668a4bbec6873ebc5b8256f3671db102f5e9c /OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
parent* Adds the AuthbuyerID field to sqlite and makes use of it. (diff)
downloadopensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.zip
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.gz
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.bz2
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.xz
* Refactored Environment/Modules directory - modules now reside in their own directory with any associated module-specific classes.
* Each module directory is currently inside one of the following category folders: Agent (Anything relating to do with Client<->Server communications.), Avatar (Anything to do with the avatar or presence inworld), Framework (Classes modules can use), Grid (Grid traffic, new OGS2 grid comms), Scripting (Scripting functions, etc), World (The enrivonment/scene, IE Sun/Tree modules.) * This should be moved into a seperate project file.
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs285
1 files changed, 285 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
new file mode 100644
index 0000000..0d7de78
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
@@ -0,0 +1,285 @@
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
28using System;
29using System.Collections;
30using System.Reflection;
31using libsecondlife;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenSim.Framework;
36using OpenSim.Framework.Communications.Cache;
37using OpenSim.Framework.Servers;
38using OpenSim.Region.Capabilities;
39using OpenSim.Region.Environment.Interfaces;
40using OpenSim.Region.Environment.Scenes;
41using Caps=OpenSim.Region.Capabilities.Caps;
42
43namespace OpenSim.Region.Environment.Modules.Avatar.Voice.AsterixVoice
44{
45 public class AsteriskVoiceModule : IRegionModule
46 {
47 private static readonly ILog m_log =
48 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private Scene m_scene;
51 private IConfig m_config;
52 private string m_asterisk;
53 private string m_asterisk_password;
54 private string m_asterisk_salt;
55 private int m_asterisk_timeout;
56 private string m_sipDomain;
57 private string m_confDomain;
58
59 private static readonly string m_parcelVoiceInfoRequestPath = "0007/";
60 private static readonly string m_provisionVoiceAccountRequestPath = "0008/";
61
62 public void Initialise(Scene scene, IConfigSource config)
63 {
64 m_scene = scene;
65 m_config = config.Configs["AsteriskVoice"];
66
67 if (null == m_config)
68 {
69 m_log.Info("[ASTERISKVOICE] no config found, plugin disabled");
70 return;
71 }
72
73 if (!m_config.GetBoolean("enabled", false))
74 {
75 m_log.Info("[ASTERISKVOICE] plugin disabled by configuration");
76 return;
77 }
78 m_log.Info("[ASTERISKVOICE] plugin enabled");
79
80 try {
81 m_sipDomain = m_config.GetString("sip_domain", String.Empty);
82 m_log.InfoFormat("[ASTERISKVOICE] using SIP domain {0}", m_sipDomain);
83
84 m_confDomain = m_config.GetString("conf_domain", String.Empty);
85 m_log.InfoFormat("[ASTERISKVOICE] using conf domain {0}", m_confDomain);
86
87 m_asterisk = m_config.GetString("asterisk_frontend", String.Empty);
88 m_asterisk_password = m_config.GetString("asterisk_password", String.Empty);
89 m_asterisk_timeout = m_config.GetInt("asterisk_timeout", 3000);
90 m_asterisk_salt = m_config.GetString("asterisk_salt", "Wuffwuff");
91 if (String.IsNullOrEmpty(m_asterisk)) throw new Exception("missing asterisk_frontend config parameter");
92 if (String.IsNullOrEmpty(m_asterisk_password)) throw new Exception("missing asterisk_password config parameter");
93 m_log.InfoFormat("[ASTERISKVOICE] using asterisk front end {0}", m_asterisk);
94
95 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
96 }
97 catch (Exception e)
98 {
99 m_log.ErrorFormat("[ASTERISKVOICE] plugin initialization failed: {0}", e.Message);
100 m_log.DebugFormat("[ASTERISKVOICE] plugin initialization failed: {0}", e.ToString());
101 return;
102 }
103 }
104
105 public void PostInitialise()
106 {
107 }
108
109 public void Close()
110 {
111 }
112
113 public string Name
114 {
115 get { return "AsteriskVoiceModule"; }
116 }
117
118 public bool IsSharedModule
119 {
120 get { return false; }
121 }
122
123 public void OnRegisterCaps(LLUUID agentID, Caps caps)
124 {
125 m_log.DebugFormat("[ASTERISKVOICE] OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
126 string capsBase = "/CAPS/" + caps.CapsObjectPath;
127 caps.RegisterHandler("ParcelVoiceInfoRequest",
128 new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath,
129 delegate(string request, string path, string param)
130 {
131 return ParcelVoiceInfoRequest(request, path, param,
132 agentID, caps);
133 }));
134 caps.RegisterHandler("ProvisionVoiceAccountRequest",
135 new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath,
136 delegate(string request, string path, string param)
137 {
138 return ProvisionVoiceAccountRequest(request, path, param,
139 agentID, caps);
140 }));
141 }
142
143 /// <summary>
144 /// Callback for a client request for ParcelVoiceInfo
145 /// </summary>
146 /// <param name="request"></param>
147 /// <param name="path"></param>
148 /// <param name="param"></param>
149 /// <param name="agentID"></param>
150 /// <param name="caps"></param>
151 /// <returns></returns>
152 public string ParcelVoiceInfoRequest(string request, string path, string param,
153 LLUUID agentID, Caps caps)
154 {
155 // we need to do:
156 // - send channel_uri: as "sip:regionID@m_sipDomain"
157 try
158 {
159 m_log.DebugFormat("[ASTERISKVOICE][PARCELVOICE]: request: {0}, path: {1}, param: {2}",
160 request, path, param);
161
162
163 // setup response to client
164 Hashtable creds = new Hashtable();
165 creds["channel_uri"] = String.Format("sip:{0}@{1}",
166 m_scene.RegionInfo.RegionID, m_sipDomain);
167
168 string regionName = m_scene.RegionInfo.RegionName;
169 ScenePresence avatar = m_scene.GetScenePresence(agentID);
170 if (null == m_scene.LandChannel) throw new Exception("land data not yet available");
171 LandData land = m_scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
172
173 LLSDParcelVoiceInfoResponse parcelVoiceInfo =
174 new LLSDParcelVoiceInfoResponse(regionName, land.localID, creds);
175
176 string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo);
177
178
179 // update region on asterisk-opensim frontend
180 Hashtable requestData = new Hashtable();
181 requestData["admin_password"] = m_asterisk_password;
182 requestData["region"] = m_scene.RegionInfo.RegionID.ToString();
183 if (!String.IsNullOrEmpty(m_confDomain))
184 {
185 requestData["region"] += String.Format("@{0}", m_confDomain);
186 }
187
188 ArrayList SendParams = new ArrayList();
189 SendParams.Add(requestData);
190 XmlRpcRequest updateAccountRequest = new XmlRpcRequest("region_update", SendParams);
191 XmlRpcResponse updateAccountResponse = updateAccountRequest.Send(m_asterisk, m_asterisk_timeout);
192 Hashtable responseData = (Hashtable)updateAccountResponse.Value;
193
194 if (!responseData.ContainsKey("success")) throw new Exception("region_update call failed");
195
196 bool success = Convert.ToBoolean((string)responseData["success"]);
197 if (!success) throw new Exception("region_update failed");
198
199
200 m_log.DebugFormat("[ASTERISKVOICE][PARCELVOICE]: {0}", r);
201 return r;
202 }
203 catch (Exception e)
204 {
205 m_log.ErrorFormat("[ASTERISKVOICE][CAPS][PARCELVOICE]: {0}, retry later", e.Message);
206 m_log.DebugFormat("[ASTERISKVOICE][CAPS][PARCELVOICE]: {0} failed", e.ToString());
207
208 return "<llsd>undef</llsd>";
209 }
210 }
211
212 /// <summary>
213 /// Callback for a client request for Voice Account Details
214 /// </summary>
215 /// <param name="request"></param>
216 /// <param name="path"></param>
217 /// <param name="param"></param>
218 /// <param name="agentID"></param>
219 /// <param name="caps"></param>
220 /// <returns></returns>
221 public string ProvisionVoiceAccountRequest(string request, string path, string param,
222 LLUUID agentID, Caps caps)
223 {
224 // we need to
225 // - get user data from UserProfileCacheService
226 // - generate nonce for user voice account password
227 // - issue XmlRpc request to asterisk opensim front end:
228 // + user: base 64 encoded user name (otherwise SL
229 // client is unhappy)
230 // + password: nonce
231 // - the XmlRpc call to asteris-opensim was successful:
232 // send account details back to client
233 try
234 {
235 m_log.DebugFormat("[ASTERISKVOICE][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}",
236 request, path, param);
237
238 // get user data & prepare voice account response
239 string voiceUser = "x" + Convert.ToBase64String(agentID.GetBytes());
240 voiceUser = voiceUser.Replace('+', '-').Replace('/', '_');
241
242 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
243 if (null == userInfo) throw new Exception("cannot get user details");
244
245 // we generate a nonce everytime
246 string voicePassword = "$1$" + Util.Md5Hash(DateTime.UtcNow.ToLongTimeString() + m_asterisk_salt);
247 LLSDVoiceAccountResponse voiceAccountResponse =
248 new LLSDVoiceAccountResponse(voiceUser, voicePassword);
249 string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse);
250 m_log.DebugFormat("[CAPS][PROVISIONVOICE]: {0}", r);
251
252
253 // update user account on asterisk frontend
254 Hashtable requestData = new Hashtable();
255 requestData["admin_password"] = m_asterisk_password;
256 requestData["username"] = voiceUser;
257 if (!String.IsNullOrEmpty(m_sipDomain))
258 {
259 requestData["username"] += String.Format("@{0}", m_sipDomain);
260 }
261 requestData["password"] = voicePassword;
262
263 ArrayList SendParams = new ArrayList();
264 SendParams.Add(requestData);
265 XmlRpcRequest updateAccountRequest = new XmlRpcRequest("account_update", SendParams);
266 XmlRpcResponse updateAccountResponse = updateAccountRequest.Send(m_asterisk, m_asterisk_timeout);
267 Hashtable responseData = (Hashtable)updateAccountResponse.Value;
268
269 if (!responseData.ContainsKey("success")) throw new Exception("account_update call failed");
270
271 bool success = Convert.ToBoolean((string)responseData["success"]);
272 if (!success) throw new Exception("account_update failed");
273
274 return r;
275 }
276 catch (Exception e)
277 {
278 m_log.ErrorFormat("[ASTERISKVOICE][CAPS][PROVISIONVOICE]: {0}, retry later", e.Message);
279 m_log.DebugFormat("[ASTERISKVOICE][CAPS][PROVISIONVOICE]: {0} failed", e.ToString());
280
281 return "<llsd>undef</llsd>";
282 }
283 }
284 }
285} \ No newline at end of file