aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Scripting
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Scripting')
-rw-r--r--OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs332
-rw-r--r--OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs288
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs437
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs229
-rw-r--r--OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs515
-rw-r--r--OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs726
-rw-r--r--OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs726
7 files changed, 3253 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
new file mode 100644
index 0000000..e6a12a4
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
@@ -0,0 +1,332 @@
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.Generic;
30using System.Drawing;
31using System.Drawing.Imaging;
32using OpenMetaverse;
33using OpenMetaverse.Imaging;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
40{
41 public class DynamicTextureModule : IRegionModule, IDynamicTextureManager
42 {
43 private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>();
44
45 private Dictionary<string, IDynamicTextureRender> RenderPlugins =
46 new Dictionary<string, IDynamicTextureRender>();
47
48 private Dictionary<UUID, DynamicTextureUpdater> Updaters = new Dictionary<UUID, DynamicTextureUpdater>();
49
50 #region IDynamicTextureManager Members
51
52 public void RegisterRender(string handleType, IDynamicTextureRender render)
53 {
54 if (!RenderPlugins.ContainsKey(handleType))
55 {
56 RenderPlugins.Add(handleType, render);
57 }
58 }
59
60 /// <summary>
61 /// Called by code which actually renders the dynamic texture to supply texture data.
62 /// </summary>
63 /// <param name="id"></param>
64 /// <param name="data"></param>
65 public void ReturnData(UUID id, byte[] data)
66 {
67 if (Updaters.ContainsKey(id))
68 {
69 DynamicTextureUpdater updater = Updaters[id];
70 if (RegisteredScenes.ContainsKey(updater.SimUUID))
71 {
72 Scene scene = RegisteredScenes[updater.SimUUID];
73 updater.DataReceived(data, scene);
74 }
75 }
76 }
77
78 public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url,
79 string extraParams, int updateTimer)
80 {
81 return AddDynamicTextureURL(simID, primID, contentType, url, extraParams, updateTimer, false, 255);
82 }
83
84 public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url,
85 string extraParams, int updateTimer, bool SetBlending, byte AlphaValue)
86 {
87 if (RenderPlugins.ContainsKey(contentType))
88 {
89 //Console.WriteLine("dynamic texture being created: " + url + " of type " + contentType);
90
91 DynamicTextureUpdater updater = new DynamicTextureUpdater();
92 updater.SimUUID = simID;
93 updater.PrimID = primID;
94 updater.ContentType = contentType;
95 updater.Url = url;
96 updater.UpdateTimer = updateTimer;
97 updater.UpdaterID = UUID.Random();
98 updater.Params = extraParams;
99 updater.BlendWithOldTexture = SetBlending;
100 updater.FrontAlpha = AlphaValue;
101
102 if (!Updaters.ContainsKey(updater.UpdaterID))
103 {
104 Updaters.Add(updater.UpdaterID, updater);
105 }
106
107 RenderPlugins[contentType].AsyncConvertUrl(updater.UpdaterID, url, extraParams);
108 return updater.UpdaterID;
109 }
110 return UUID.Zero;
111 }
112
113 public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data,
114 string extraParams, int updateTimer)
115 {
116 return AddDynamicTextureData(simID, primID, contentType, data, extraParams, updateTimer, false, 255);
117 }
118
119 public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data,
120 string extraParams, int updateTimer, bool SetBlending, byte AlphaValue)
121 {
122 if (RenderPlugins.ContainsKey(contentType))
123 {
124 DynamicTextureUpdater updater = new DynamicTextureUpdater();
125 updater.SimUUID = simID;
126 updater.PrimID = primID;
127 updater.ContentType = contentType;
128 updater.BodyData = data;
129 updater.UpdateTimer = updateTimer;
130 updater.UpdaterID = UUID.Random();
131 updater.Params = extraParams;
132 updater.BlendWithOldTexture = SetBlending;
133 updater.FrontAlpha = AlphaValue;
134
135 if (!Updaters.ContainsKey(updater.UpdaterID))
136 {
137 Updaters.Add(updater.UpdaterID, updater);
138 }
139
140 RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams);
141 return updater.UpdaterID;
142 }
143 return UUID.Zero;
144 }
145
146 #endregion
147
148 #region IRegionModule Members
149
150 public void Initialise(Scene scene, IConfigSource config)
151 {
152 if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
153 {
154 RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
155 scene.RegisterModuleInterface<IDynamicTextureManager>(this);
156 }
157 }
158
159 public void PostInitialise()
160 {
161 }
162
163 public void Close()
164 {
165 }
166
167 public string Name
168 {
169 get { return "DynamicTextureModule"; }
170 }
171
172 public bool IsSharedModule
173 {
174 get { return true; }
175 }
176
177 #endregion
178
179 #region Nested type: DynamicTextureUpdater
180
181 public class DynamicTextureUpdater
182 {
183 public bool BlendWithOldTexture = false;
184 public string BodyData;
185 public string ContentType;
186 public byte FrontAlpha = 255;
187 public UUID LastAssetID;
188 public string Params;
189 public UUID PrimID;
190 public bool SetNewFrontAlpha = false;
191 public UUID SimUUID;
192 public UUID UpdaterID;
193 public int UpdateTimer;
194 public string Url;
195
196 public DynamicTextureUpdater()
197 {
198 LastAssetID = UUID.Zero;
199 UpdateTimer = 0;
200 BodyData = null;
201 }
202
203 /// <summary>
204 /// Called once new texture data has been received for this updater.
205 /// </summary>
206 public void DataReceived(byte[] data, Scene scene)
207 {
208 SceneObjectPart part = scene.GetSceneObjectPart(PrimID);
209 byte[] assetData;
210 AssetBase oldAsset = null;
211
212 if (BlendWithOldTexture)
213 {
214 UUID lastTextureID = part.Shape.Textures.DefaultTexture.TextureID;
215 oldAsset = scene.AssetCache.GetAsset(lastTextureID, true);
216 if (oldAsset != null)
217 {
218 assetData = BlendTextures(data, oldAsset.Data, SetNewFrontAlpha, FrontAlpha);
219 }
220 else
221 {
222 assetData = new byte[data.Length];
223 Array.Copy(data, assetData, data.Length);
224 }
225 }
226 else
227 {
228 assetData = new byte[data.Length];
229 Array.Copy(data, assetData, data.Length);
230 }
231
232 // Create a new asset for user
233 AssetBase asset = new AssetBase();
234 asset.Metadata.FullID = UUID.Random();
235 asset.Data = assetData;
236 asset.Metadata.Name = "DynamicImage" + Util.RandomClass.Next(1, 10000);
237 asset.Metadata.Type = 0;
238 asset.Metadata.Description = "dynamic image";
239 asset.Metadata.Local = false;
240 asset.Metadata.Temporary = true;
241 scene.AssetCache.AddAsset(asset);
242
243 LastAssetID = asset.Metadata.FullID;
244
245 IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>();
246 if (cacheLayerDecode != null)
247 {
248 cacheLayerDecode.syncdecode(asset.Metadata.FullID, asset.Data);
249 }
250 cacheLayerDecode = null;
251
252 // mostly keep the values from before
253 Primitive.TextureEntry tmptex = part.Shape.Textures;
254
255 // remove the old asset from the cache
256 UUID oldID = tmptex.DefaultTexture.TextureID;
257 scene.AssetCache.ExpireAsset(oldID);
258
259 tmptex.DefaultTexture.TextureID = asset.Metadata.FullID;
260 // I'm pretty sure we always want to force this to true
261 tmptex.DefaultTexture.Fullbright = true;
262
263 part.Shape.Textures = tmptex;
264 part.ScheduleFullUpdate();
265 }
266
267 private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha)
268 {
269 ManagedImage managedImage;
270 Image image;
271
272 if (OpenJPEG.DecodeToImage(frontImage, out managedImage, out image))
273 {
274 Bitmap image1 = new Bitmap(image);
275
276 if (OpenJPEG.DecodeToImage(backImage, out managedImage, out image))
277 {
278 Bitmap image2 = new Bitmap(image);
279
280 if (setNewAlpha)
281 SetAlpha(ref image1, newAlpha);
282
283 Bitmap joint = MergeBitMaps(image1, image2);
284
285 byte[] result = new byte[0];
286
287 try
288 {
289 result = OpenJPEG.EncodeFromImage(joint, true);
290 }
291 catch (Exception)
292 {
293 Console.WriteLine(
294 "[DYNAMICTEXTUREMODULE]: OpenJpeg Encode Failed. Empty byte data returned!");
295 }
296
297 return result;
298 }
299 }
300
301 return null;
302 }
303
304 public Bitmap MergeBitMaps(Bitmap front, Bitmap back)
305 {
306 Bitmap joint;
307 Graphics jG;
308
309 joint = new Bitmap(back.Width, back.Height, PixelFormat.Format32bppArgb);
310 jG = Graphics.FromImage(joint);
311
312 jG.DrawImage(back, 0, 0, back.Width, back.Height);
313 jG.DrawImage(front, 0, 0, back.Width, back.Height);
314
315 return joint;
316 }
317
318 private void SetAlpha(ref Bitmap b, byte alpha)
319 {
320 for (int w = 0; w < b.Width; w++)
321 {
322 for (int h = 0; h < b.Height; h++)
323 {
324 b.SetPixel(w, h, Color.FromArgb(alpha, b.GetPixel(w, h)));
325 }
326 }
327 }
328 }
329
330 #endregion
331 }
332}
diff --git a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs
new file mode 100644
index 0000000..c23ff1e
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs
@@ -0,0 +1,288 @@
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.Reflection;
30using System.Collections.Generic;
31using System.Text.RegularExpressions;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36using log4net;
37using Nini.Config;
38using DotNetOpenMail;
39using DotNetOpenMail.SmtpAuth;
40
41namespace OpenSim.Region.CoreModules.Scripting.EmailModules
42{
43 public class EmailModule : IEmailModule
44 {
45 //
46 // Log
47 //
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 //
51 // Module vars
52 //
53 private IConfigSource m_Config;
54 private string m_HostName = string.Empty;
55 //private string m_RegionName = string.Empty;
56 private string SMTP_SERVER_HOSTNAME = string.Empty;
57 private int SMTP_SERVER_PORT = 25;
58 private string SMTP_SERVER_LOGIN = string.Empty;
59 private string SMTP_SERVER_PASSWORD = string.Empty;
60
61 // Scenes by Region Handle
62 private Dictionary<ulong, Scene> m_Scenes =
63 new Dictionary<ulong, Scene>();
64
65 private bool m_Enabled = false;
66
67 public void Initialise(Scene scene, IConfigSource config)
68 {
69 m_Config = config;
70 IConfig SMTPConfig;
71
72 //FIXME: RegionName is correct??
73 //m_RegionName = scene.RegionInfo.RegionName;
74
75 IConfig startupConfig = m_Config.Configs["Startup"];
76
77 m_Enabled = (startupConfig.GetString("emailmodule", "DefaultEmailModule") == "DefaultEmailModule");
78
79 //Load SMTP SERVER config
80 try
81 {
82 if ((SMTPConfig = m_Config.Configs["SMTP"]) == null)
83 {
84 m_log.InfoFormat("[SMTP] SMTP server not configured");
85 m_Enabled = false;
86 return;
87 }
88
89 if (!SMTPConfig.GetBoolean("enabled", false))
90 {
91 m_log.InfoFormat("[SMTP] module disabled in configuration");
92 m_Enabled = false;
93 return;
94 }
95
96 m_HostName = SMTPConfig.GetString("host_domain_header_from", m_HostName);
97 SMTP_SERVER_HOSTNAME = SMTPConfig.GetString("SMTP_SERVER_HOSTNAME",SMTP_SERVER_HOSTNAME);
98 SMTP_SERVER_PORT = SMTPConfig.GetInt("SMTP_SERVER_PORT", SMTP_SERVER_PORT);
99 SMTP_SERVER_LOGIN = SMTPConfig.GetString("SMTP_SERVER_LOGIN", SMTP_SERVER_LOGIN);
100 SMTP_SERVER_PASSWORD = SMTPConfig.GetString("SMTP_SERVER_PASSWORD", SMTP_SERVER_PASSWORD);
101 }
102 catch (Exception e)
103 {
104 m_log.Error("[EMAIL] DefaultEmailModule not configured: "+ e.Message);
105 m_Enabled = false;
106 return;
107 }
108
109 // It's a go!
110 if (m_Enabled)
111 {
112 lock (m_Scenes)
113 {
114 // Claim the interface slot
115 scene.RegisterModuleInterface<IEmailModule>(this);
116
117 // Add to scene list
118 if (m_Scenes.ContainsKey(scene.RegionInfo.RegionHandle))
119 {
120 m_Scenes[scene.RegionInfo.RegionHandle] = scene;
121 }
122 else
123 {
124 m_Scenes.Add(scene.RegionInfo.RegionHandle, scene);
125 }
126 }
127
128 m_log.Info("[EMAIL] Activated DefaultEmailModule");
129 }
130 }
131
132 public void PostInitialise()
133 {
134 }
135
136 public void Close()
137 {
138 }
139
140 public string Name
141 {
142 get { return "DefaultEmailModule"; }
143 }
144
145 public bool IsSharedModule
146 {
147 get { return true; }
148 }
149
150 /// <summary>
151 ///
152 /// </summary>
153 /// <param name="seconds"></param>
154 private void DelayInSeconds(int seconds)
155 {
156 TimeSpan DiffDelay = new TimeSpan(0, 0, seconds);
157 DateTime EndDelay = DateTime.Now.Add(DiffDelay);
158 while (DateTime.Now < EndDelay)
159 {
160 ;//Do nothing!!
161 }
162 }
163
164 private SceneObjectPart findPrim(UUID objectID, out string ObjectRegionName)
165 {
166 lock (m_Scenes)
167 {
168 foreach (Scene s in m_Scenes.Values)
169 {
170 SceneObjectPart part = s.GetSceneObjectPart(objectID);
171 if (part != null)
172 {
173 ObjectRegionName = s.RegionInfo.RegionName;
174 return part;
175 }
176 }
177 }
178 ObjectRegionName = string.Empty;
179 return null;
180 }
181
182 private void resolveNamePositionRegionName(UUID objectID, out string ObjectName, out string ObjectAbsolutePosition, out string ObjectRegionName)
183 {
184 string m_ObjectRegionName;
185 SceneObjectPart part = findPrim(objectID, out m_ObjectRegionName);
186 if (part != null)
187 {
188 ObjectAbsolutePosition = part.AbsolutePosition.ToString();
189 ObjectName = part.Name;
190 ObjectRegionName = m_ObjectRegionName;
191 return;
192 }
193 ObjectAbsolutePosition = part.AbsolutePosition.ToString();
194 ObjectName = part.Name;
195 ObjectRegionName = m_ObjectRegionName;
196 return;
197 }
198
199 /// <summary>
200 /// SendMail function utilized by llEMail
201 /// </summary>
202 /// <param name="objectID"></param>
203 /// <param name="address"></param>
204 /// <param name="subject"></param>
205 /// <param name="body"></param>
206 public void SendEmail(UUID objectID, string address, string subject, string body)
207 {
208 //Check if address is empty
209 if (address == string.Empty)
210 return;
211
212 //FIXED:Check the email is correct form in REGEX
213 string EMailpatternStrict = @"^(([^<>()[\]\\.,;:\s@\""]+"
214 + @"(\.[^<>()[\]\\.,;:\s@\""]+)*)|(\"".+\""))@"
215 + @"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
216 + @"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+"
217 + @"[a-zA-Z]{2,}))$";
218 Regex EMailreStrict = new Regex(EMailpatternStrict);
219 bool isEMailStrictMatch = EMailreStrict.IsMatch(address);
220 if (!isEMailStrictMatch)
221 {
222 m_log.Error("[EMAIL] REGEX Problem in EMail Address: "+address);
223 return;
224 }
225 //FIXME:Check if subject + body = 4096 Byte
226 if ((subject.Length + body.Length) > 1024)
227 {
228 m_log.Error("[EMAIL] subject + body > 1024 Byte");
229 return;
230 }
231
232 try
233 {
234 string LastObjectName = string.Empty;
235 string LastObjectPosition = string.Empty;
236 string LastObjectRegionName = string.Empty;
237 //DONE: Message as Second Life style
238 //20 second delay - AntiSpam System - for now only 10 seconds
239 DelayInSeconds(10);
240 //Creation EmailMessage
241 EmailMessage emailMessage = new EmailMessage();
242 //From
243 emailMessage.FromAddress = new EmailAddress(objectID.ToString()+"@"+m_HostName);
244 //To - Only One
245 emailMessage.AddToAddress(new EmailAddress(address));
246 //Subject
247 emailMessage.Subject = subject;
248 //TEXT Body
249 resolveNamePositionRegionName(objectID, out LastObjectName, out LastObjectPosition, out LastObjectRegionName);
250 emailMessage.TextPart = new TextAttachment("Object-Name: " + LastObjectName +
251 "\r\nRegion: " + LastObjectRegionName + "\r\nLocal-Position: " +
252 LastObjectPosition+"\r\n\r\n\r\n" + body);
253 //HTML Body
254 emailMessage.HtmlPart = new HtmlAttachment("<html><body><p>" +
255 "<BR>Object-Name: " + LastObjectName +
256 "<BR>Region: " + LastObjectRegionName +
257 "<BR>Local-Position: " + LastObjectPosition + "<BR><BR><BR>"
258 +body+"\r\n</p></body><html>");
259
260 //Set SMTP SERVER config
261 SmtpServer smtpServer=new SmtpServer(SMTP_SERVER_HOSTNAME,SMTP_SERVER_PORT);
262 //Authentication
263 smtpServer.SmtpAuthToken=new SmtpAuthToken(SMTP_SERVER_LOGIN, SMTP_SERVER_PASSWORD);
264 //Send Email Message
265 emailMessage.Send(smtpServer);
266 //Log
267 m_log.Info("[EMAIL] EMail sent to: " + address + " from object: " + objectID.ToString());
268 }
269 catch (Exception e)
270 {
271 m_log.Error("[EMAIL] DefaultEmailModule Exception: "+e.Message);
272 return;
273 }
274 }
275
276 /// <summary>
277 ///
278 /// </summary>
279 /// <param name="objectID"></param>
280 /// <param name="sender"></param>
281 /// <param name="subject"></param>
282 /// <returns></returns>
283 public Email GetNextEmail(UUID objectID, string sender, string subject)
284 {
285 return null;
286 }
287 }
288}
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
new file mode 100644
index 0000000..9f3bd09
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -0,0 +1,437 @@
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.Generic;
30using System.IO;
31using System.Net;
32using System.Text;
33using System.Threading;
34using OpenMetaverse;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using System.Collections;
41
42/*****************************************************
43 *
44 * ScriptsHttpRequests
45 *
46 * Implements the llHttpRequest and http_response
47 * callback.
48 *
49 * Some stuff was already in LSLLongCmdHandler, and then
50 * there was this file with a stub class in it. So,
51 * I am moving some of the objects and functions out of
52 * LSLLongCmdHandler, such as the HttpRequestClass, the
53 * start and stop methods, and setting up pending and
54 * completed queues. These are processed in the
55 * LSLLongCmdHandler polling loop. Similiar to the
56 * XMLRPCModule, since that seems to work.
57 *
58 * //TODO
59 *
60 * This probably needs some throttling mechanism but
61 * it's wide open right now. This applies to both
62 * number of requests and data volume.
63 *
64 * Linden puts all kinds of header fields in the requests.
65 * Not doing any of that:
66 * User-Agent
67 * X-SecondLife-Shard
68 * X-SecondLife-Object-Name
69 * X-SecondLife-Object-Key
70 * X-SecondLife-Region
71 * X-SecondLife-Local-Position
72 * X-SecondLife-Local-Velocity
73 * X-SecondLife-Local-Rotation
74 * X-SecondLife-Owner-Name
75 * X-SecondLife-Owner-Key
76 *
77 * HTTPS support
78 *
79 * Configurable timeout?
80 * Configurable max response size?
81 * Configurable
82 *
83 * **************************************************/
84
85namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
86{
87 public class HttpRequestModule : IRegionModule, IHttpRequestModule
88 {
89 private object HttpListLock = new object();
90 private int httpTimeout = 30000;
91 private string m_name = "HttpScriptRequests";
92
93 private string m_proxyurl = "";
94 private string m_proxyexcepts = "";
95
96 // <request id, HttpRequestClass>
97 private Dictionary<UUID, HttpRequestClass> m_pendingRequests;
98 private Scene m_scene;
99 // private Queue<HttpRequestClass> rpcQueue = new Queue<HttpRequestClass>();
100
101 public HttpRequestModule()
102 {
103 }
104
105 #region IHttpRequestModule Members
106
107 public UUID MakeHttpRequest(string url, string parameters, string body)
108 {
109 return UUID.Zero;
110 }
111
112 public UUID StartHttpRequest(uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body)
113 {
114 UUID reqID = UUID.Random();
115 HttpRequestClass htc = new HttpRequestClass();
116
117 // Partial implementation: support for parameter flags needed
118 // see http://wiki.secondlife.com/wiki/LlHTTPRequest
119 //
120 // Parameters are expected in {key, value, ... , key, value}
121 if (parameters != null)
122 {
123 string[] parms = parameters.ToArray();
124 for (int i = 0; i < parms.Length; i += 2)
125 {
126 switch (Int32.Parse(parms[i]))
127 {
128 case (int)HttpRequestConstants.HTTP_METHOD:
129
130 htc.HttpMethod = parms[i + 1];
131 break;
132
133 case (int)HttpRequestConstants.HTTP_MIMETYPE:
134
135 htc.HttpMIMEType = parms[i + 1];
136 break;
137
138 case (int)HttpRequestConstants.HTTP_BODY_MAXLENGTH:
139
140 // TODO implement me
141 break;
142
143 case (int)HttpRequestConstants.HTTP_VERIFY_CERT:
144
145 // TODO implement me
146 break;
147 }
148 }
149 }
150
151 htc.LocalID = localID;
152 htc.ItemID = itemID;
153 htc.Url = url;
154 htc.ReqID = reqID;
155 htc.HttpTimeout = httpTimeout;
156 htc.OutboundBody = body;
157 htc.ResponseHeaders = headers;
158 htc.proxyurl = m_proxyurl;
159 htc.proxyexcepts = m_proxyexcepts;
160
161 lock (HttpListLock)
162 {
163 m_pendingRequests.Add(reqID, htc);
164 }
165
166 htc.Process();
167
168 return reqID;
169 }
170
171 public void StopHttpRequest(uint m_localID, UUID m_itemID)
172 {
173 if (m_pendingRequests != null)
174 {
175 lock (HttpListLock)
176 {
177 HttpRequestClass tmpReq;
178 if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq))
179 {
180 tmpReq.Stop();
181 m_pendingRequests.Remove(m_itemID);
182 }
183 }
184 }
185 }
186
187 /*
188 * TODO
189 * Not sure how important ordering is is here - the next first
190 * one completed in the list is returned, based soley on its list
191 * position, not the order in which the request was started or
192 * finsihed. I thought about setting up a queue for this, but
193 * it will need some refactoring and this works 'enough' right now
194 */
195
196 public IServiceRequest GetNextCompletedRequest()
197 {
198 lock (HttpListLock)
199 {
200 foreach (UUID luid in m_pendingRequests.Keys)
201 {
202 HttpRequestClass tmpReq;
203
204 if (m_pendingRequests.TryGetValue(luid, out tmpReq))
205 {
206 if (tmpReq.Finished)
207 {
208 return tmpReq;
209 }
210 }
211 }
212 }
213 return null;
214 }
215
216 public void RemoveCompletedRequest(UUID id)
217 {
218 lock (HttpListLock)
219 {
220 HttpRequestClass tmpReq;
221 if (m_pendingRequests.TryGetValue(id, out tmpReq))
222 {
223 tmpReq.Stop();
224 tmpReq = null;
225 m_pendingRequests.Remove(id);
226 }
227 }
228 }
229
230 #endregion
231
232 #region IRegionModule Members
233
234 public void Initialise(Scene scene, IConfigSource config)
235 {
236 m_scene = scene;
237
238 m_scene.RegisterModuleInterface<IHttpRequestModule>(this);
239
240 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy");
241 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions");
242
243 m_pendingRequests = new Dictionary<UUID, HttpRequestClass>();
244 }
245
246 public void PostInitialise()
247 {
248 }
249
250 public void Close()
251 {
252 }
253
254 public string Name
255 {
256 get { return m_name; }
257 }
258
259 public bool IsSharedModule
260 {
261 get { return true; }
262 }
263
264 #endregion
265 }
266
267 public class HttpRequestClass: IServiceRequest
268 {
269 // Constants for parameters
270 // public const int HTTP_BODY_MAXLENGTH = 2;
271 // public const int HTTP_METHOD = 0;
272 // public const int HTTP_MIMETYPE = 1;
273 // public const int HTTP_VERIFY_CERT = 3;
274 private bool _finished;
275 public bool Finished
276 {
277 get { return _finished; }
278 }
279 // public int HttpBodyMaxLen = 2048; // not implemented
280
281 // Parameter members and default values
282 public string HttpMethod = "GET";
283 public string HttpMIMEType = "text/plain;charset=utf-8";
284 public int HttpTimeout;
285 // public bool HttpVerifyCert = true; // not implemented
286 private Thread httpThread;
287
288 // Request info
289 private UUID _itemID;
290 public UUID ItemID
291 {
292 get { return _itemID; }
293 set { _itemID = value; }
294 }
295 private uint _localID;
296 public uint LocalID
297 {
298 get { return _localID; }
299 set { _localID = value; }
300 }
301 public DateTime Next;
302 public string proxyurl;
303 public string proxyexcepts;
304 public string OutboundBody;
305 private UUID _reqID;
306 public UUID ReqID
307 {
308 get { return _reqID; }
309 set { _reqID = value; }
310 }
311 public HttpWebRequest Request;
312 public string ResponseBody;
313 public List<string> ResponseMetadata;
314 public Dictionary<string, string> ResponseHeaders;
315 public int Status;
316 public string Url;
317
318 public void Process()
319 {
320 httpThread = new Thread(SendRequest);
321 httpThread.Name = "HttpRequestThread";
322 httpThread.Priority = ThreadPriority.BelowNormal;
323 httpThread.IsBackground = true;
324 _finished = false;
325 httpThread.Start();
326 ThreadTracker.Add(httpThread);
327 }
328
329 /*
330 * TODO: More work on the response codes. Right now
331 * returning 200 for success or 499 for exception
332 */
333
334 public void SendRequest()
335 {
336 HttpWebResponse response = null;
337 StringBuilder sb = new StringBuilder();
338 byte[] buf = new byte[8192];
339 string tempString = null;
340 int count = 0;
341
342 try
343 {
344 Request = (HttpWebRequest) WebRequest.Create(Url);
345 Request.Method = HttpMethod;
346 Request.ContentType = HttpMIMEType;
347
348 if (proxyurl != null && proxyurl.Length > 0)
349 {
350 if (proxyexcepts != null && proxyexcepts.Length > 0)
351 {
352 string[] elist = proxyexcepts.Split(';');
353 Request.Proxy = new WebProxy(proxyurl, true, elist);
354 }
355 else
356 {
357 Request.Proxy = new WebProxy(proxyurl, true);
358 }
359 }
360
361 foreach (KeyValuePair<string, string> entry in ResponseHeaders)
362 Request.Headers[entry.Key] = entry.Value;
363
364 // Encode outbound data
365 if (OutboundBody.Length > 0)
366 {
367 byte[] data = Encoding.UTF8.GetBytes(OutboundBody);
368
369 Request.ContentLength = data.Length;
370 Stream bstream = Request.GetRequestStream();
371 bstream.Write(data, 0, data.Length);
372 bstream.Close();
373 }
374
375 Request.Timeout = HttpTimeout;
376 // execute the request
377 response = (HttpWebResponse) Request.GetResponse();
378
379 Stream resStream = response.GetResponseStream();
380
381 do
382 {
383 // fill the buffer with data
384 count = resStream.Read(buf, 0, buf.Length);
385
386 // make sure we read some data
387 if (count != 0)
388 {
389 // translate from bytes to ASCII text
390 tempString = Encoding.UTF8.GetString(buf, 0, count);
391
392 // continue building the string
393 sb.Append(tempString);
394 }
395 } while (count > 0); // any more data to read?
396
397 ResponseBody = sb.ToString();
398 }
399 catch (Exception e)
400 {
401 if (e is WebException && ((WebException)e).Status == WebExceptionStatus.ProtocolError)
402 {
403 HttpWebResponse webRsp = (HttpWebResponse)((WebException)e).Response;
404 Status = (int)webRsp.StatusCode;
405 ResponseBody = webRsp.StatusDescription;
406 }
407 else
408 {
409 Status = (int)OSHttpStatusCode.ClientErrorJoker;
410 ResponseBody = e.Message;
411 }
412
413 _finished = true;
414 return;
415 }
416 finally
417 {
418 if (response != null)
419 response.Close();
420 }
421
422 Status = (int)OSHttpStatusCode.SuccessOk;
423 _finished = true;
424 }
425
426 public void Stop()
427 {
428 try
429 {
430 httpThread.Abort();
431 }
432 catch (Exception)
433 {
434 }
435 }
436 }
437}
diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
new file mode 100644
index 0000000..afcaff1
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
@@ -0,0 +1,229 @@
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.Drawing;
30using System.IO;
31using System.Net;
32using OpenMetaverse;
33using OpenMetaverse.Imaging;
34using Nini.Config;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
39{
40 public class LoadImageURLModule : IRegionModule, IDynamicTextureRender
41 {
42 private string m_name = "LoadImageURL";
43 private Scene m_scene;
44 private IDynamicTextureManager m_textureManager;
45
46 private string m_proxyurl = "";
47 private string m_proxyexcepts = "";
48
49 #region IDynamicTextureRender Members
50
51 public string GetName()
52 {
53 return m_name;
54 }
55
56 public string GetContentType()
57 {
58 return ("image");
59 }
60
61 public bool SupportsAsynchronous()
62 {
63 return true;
64 }
65
66 public byte[] ConvertUrl(string url, string extraParams)
67 {
68 return null;
69 }
70
71 public byte[] ConvertStream(Stream data, string extraParams)
72 {
73 return null;
74 }
75
76 public bool AsyncConvertUrl(UUID id, string url, string extraParams)
77 {
78 MakeHttpRequest(url, id);
79 return true;
80 }
81
82 public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
83 {
84 return false;
85 }
86
87 #endregion
88
89 #region IRegionModule Members
90
91 public void Initialise(Scene scene, IConfigSource config)
92 {
93 if (m_scene == null)
94 {
95 m_scene = scene;
96 }
97
98 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy");
99 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions");
100 }
101
102 public void PostInitialise()
103 {
104 m_textureManager = m_scene.RequestModuleInterface<IDynamicTextureManager>();
105 if (m_textureManager != null)
106 {
107 m_textureManager.RegisterRender(GetContentType(), this);
108 }
109 }
110
111 public void Close()
112 {
113 }
114
115 public string Name
116 {
117 get { return m_name; }
118 }
119
120 public bool IsSharedModule
121 {
122 get { return true; }
123 }
124
125 #endregion
126
127 private void MakeHttpRequest(string url, UUID requestID)
128 {
129 WebRequest request = HttpWebRequest.Create(url);
130
131 if (m_proxyurl != null && m_proxyurl.Length > 0)
132 {
133 if (m_proxyexcepts != null && m_proxyexcepts.Length > 0)
134 {
135 string[] elist = m_proxyexcepts.Split(';');
136 request.Proxy = new WebProxy(m_proxyurl, true, elist);
137 }
138 else
139 {
140 request.Proxy = new WebProxy(m_proxyurl, true);
141 }
142 }
143
144 RequestState state = new RequestState((HttpWebRequest) request, requestID);
145 // IAsyncResult result = request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state);
146 request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state);
147
148 TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
149 state.TimeOfRequest = (int) t.TotalSeconds;
150 }
151
152 private void HttpRequestReturn(IAsyncResult result)
153 {
154 RequestState state = (RequestState) result.AsyncState;
155 WebRequest request = (WebRequest) state.Request;
156 try
157 {
158 HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
159 if (response.StatusCode == HttpStatusCode.OK)
160 {
161 Bitmap image = new Bitmap(response.GetResponseStream());
162 Size newsize;
163
164 // TODO: make this a bit less hard coded
165 if ((image.Height < 64) && (image.Width < 64))
166 {
167 newsize = new Size(32, 32);
168 }
169 else if ((image.Height < 128) && (image.Width < 128))
170 {
171 newsize = new Size(64, 64);
172 }
173 else if ((image.Height < 256) && (image.Width < 256))
174 {
175 newsize = new Size(128, 128);
176 }
177 else if ((image.Height < 512 && image.Width < 512))
178 {
179 newsize = new Size(256, 256);
180 }
181 else if ((image.Height < 1024 && image.Width < 1024))
182 {
183 newsize = new Size(512, 512);
184 }
185 else
186 {
187 newsize = new Size(1024, 1024);
188 }
189
190 Bitmap resize = new Bitmap(image, newsize);
191 byte[] imageJ2000 = new byte[0];
192
193 try
194 {
195 imageJ2000 = OpenJPEG.EncodeFromImage(resize, true);
196 }
197 catch (Exception)
198 {
199 Console.WriteLine(
200 "[LOADIMAGEURLMODULE]: OpenJpeg Encode Failed. Empty byte data returned!");
201 }
202
203 m_textureManager.ReturnData(state.RequestID, imageJ2000);
204 }
205 }
206 catch (WebException)
207 {
208
209 }
210 }
211
212 #region Nested type: RequestState
213
214 public class RequestState
215 {
216 public HttpWebRequest Request = null;
217 public UUID RequestID = UUID.Zero;
218 public int TimeOfRequest = 0;
219
220 public RequestState(HttpWebRequest request, UUID requestID)
221 {
222 Request = request;
223 RequestID = requestID;
224 }
225 }
226
227 #endregion
228 }
229}
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
new file mode 100644
index 0000000..0c709b5
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
@@ -0,0 +1,515 @@
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.Drawing;
30using System.Drawing.Imaging;
31using System.Globalization;
32using System.IO;
33using System.Net;
34using OpenMetaverse;
35using OpenMetaverse.Imaging;
36using Nini.Config;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39
40//using Cairo;
41
42namespace OpenSim.Region.CoreModules.Scripting.VectorRender
43{
44 public class VectorRenderModule : IRegionModule, IDynamicTextureRender
45 {
46 private string m_name = "VectorRenderModule";
47 private Scene m_scene;
48 private IDynamicTextureManager m_textureManager;
49
50 public VectorRenderModule()
51 {
52 }
53
54 #region IDynamicTextureRender Members
55
56 public string GetContentType()
57 {
58 return ("vector");
59 }
60
61 public string GetName()
62 {
63 return m_name;
64 }
65
66 public bool SupportsAsynchronous()
67 {
68 return true;
69 }
70
71 public byte[] ConvertUrl(string url, string extraParams)
72 {
73 return null;
74 }
75
76 public byte[] ConvertStream(Stream data, string extraParams)
77 {
78 return null;
79 }
80
81 public bool AsyncConvertUrl(UUID id, string url, string extraParams)
82 {
83 return false;
84 }
85
86 public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
87 {
88 Draw(bodyData, id, extraParams);
89 return true;
90 }
91
92 #endregion
93
94 #region IRegionModule Members
95
96 public void Initialise(Scene scene, IConfigSource config)
97 {
98 if (m_scene == null)
99 {
100 m_scene = scene;
101 }
102 }
103
104 public void PostInitialise()
105 {
106 m_textureManager = m_scene.RequestModuleInterface<IDynamicTextureManager>();
107 if (m_textureManager != null)
108 {
109 m_textureManager.RegisterRender(GetContentType(), this);
110 }
111 }
112
113 public void Close()
114 {
115 }
116
117 public string Name
118 {
119 get { return m_name; }
120 }
121
122 public bool IsSharedModule
123 {
124 get { return true; }
125 }
126
127 #endregion
128
129 private void Draw(string data, UUID id, string extraParams)
130 {
131 // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha
132 // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255
133 int width = 256;
134 int height = 256;
135 int alpha = 255; // 0 is transparent
136
137 char[] paramDelimiter = { ',' };
138 char[] nvpDelimiter = { ':' };
139
140 extraParams = extraParams.Trim();
141 extraParams = extraParams.ToLower();
142
143 string[] nvps = extraParams.Split(paramDelimiter);
144
145 int temp = -1;
146 foreach (string pair in nvps)
147 {
148 string[] nvp = pair.Split(nvpDelimiter);
149 string name = "";
150 string value = "";
151
152 if (nvp[0] != null)
153 {
154 name = nvp[0].Trim();
155 }
156
157 if (nvp.Length == 2)
158 {
159 value = nvp[1].Trim();
160 }
161
162 switch (name)
163 {
164 case "width":
165 temp = parseIntParam(value);
166 if (temp != -1)
167 {
168 if (temp < 1)
169 {
170 width = 1;
171 }
172 else if (temp > 2048)
173 {
174 width = 2048;
175 }
176 else
177 {
178 width = temp;
179 }
180 }
181 break;
182 case "height":
183 temp = parseIntParam(value);
184 if (temp != -1)
185 {
186 if (temp < 1)
187 {
188 height = 1;
189 }
190 else if (temp > 2048)
191 {
192 height = 2048;
193 }
194 else
195 {
196 height = temp;
197 }
198 }
199 break;
200 case "alpha":
201 temp = parseIntParam(value);
202 if (temp != -1)
203 {
204 if (temp < 0)
205 {
206 alpha = 0;
207 }
208 else if (temp > 255)
209 {
210 alpha = 255;
211 }
212 else
213 {
214 alpha = temp;
215 }
216 }
217 break;
218 case "":
219 // blank string has been passed do nothing just use defaults
220 break;
221 default: // this is all for backwards compat, all a bit ugly hopfully can be removed in future
222 // could be either set alpha or just an int
223 if (name == "setalpha")
224 {
225 alpha = 0; // set the texture to have transparent background (maintains backwards compat)
226 }
227 else
228 {
229 // this function used to accept an int on its own that represented both
230 // width and height, this is to maintain backwards compat, could be removed
231 // but would break existing scripts
232 temp = parseIntParam(name);
233 if (temp != -1)
234 {
235 if (temp > 1024)
236 temp = 1024;
237
238 if (temp < 128)
239 temp = 128;
240
241 width = temp;
242 height = temp;
243 }
244 }
245 break;
246 }
247
248 }
249
250 Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
251
252 Graphics graph = Graphics.FromImage(bitmap);
253
254 // this is really just to save people filling the
255 // background white in their scripts, only do when fully opaque
256 if (alpha == 255)
257 {
258 graph.FillRectangle(new SolidBrush(Color.White), 0, 0, width, height);
259 }
260
261 for (int w = 0; w < bitmap.Width; w++)
262 {
263 for (int h = 0; h < bitmap.Height; h++)
264 {
265 bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h)));
266 }
267 }
268
269
270 GDIDraw(data, graph);
271
272 byte[] imageJ2000 = new byte[0];
273
274 try
275 {
276 imageJ2000 = OpenJPEG.EncodeFromImage(bitmap, true);
277 }
278 catch (Exception)
279 {
280 Console.WriteLine(
281 "[VECTORRENDERMODULE]: OpenJpeg Encode Failed. Empty byte data returned!");
282 }
283 m_textureManager.ReturnData(id, imageJ2000);
284 }
285
286 private int parseIntParam(string strInt)
287 {
288 int parsed;
289 try
290 {
291 parsed = Convert.ToInt32(strInt);
292 }
293 catch (Exception)
294 {
295 //Ckrinke: Add a WriteLine to remove the warning about 'e' defined but not used
296 // Console.WriteLine("Problem with Draw. Please verify parameters." + e.ToString());
297 parsed = -1;
298 }
299
300 return parsed;
301
302 }
303
304
305/*
306 private void CairoDraw(string data, System.Drawing.Graphics graph)
307 {
308 using (Win32Surface draw = new Win32Surface(graph.GetHdc()))
309 {
310 Context contex = new Context(draw);
311
312 contex.Antialias = Antialias.None; //fastest method but low quality
313 contex.LineWidth = 7;
314 char[] lineDelimiter = { ';' };
315 char[] partsDelimiter = { ',' };
316 string[] lines = data.Split(lineDelimiter);
317
318 foreach (string line in lines)
319 {
320 string nextLine = line.Trim();
321
322 if (nextLine.StartsWith("MoveTO"))
323 {
324 float x = 0;
325 float y = 0;
326 GetParams(partsDelimiter, ref nextLine, ref x, ref y);
327 contex.MoveTo(x, y);
328 }
329 else if (nextLine.StartsWith("LineTo"))
330 {
331 float x = 0;
332 float y = 0;
333 GetParams(partsDelimiter, ref nextLine, ref x, ref y);
334 contex.LineTo(x, y);
335 contex.Stroke();
336 }
337 }
338 }
339 graph.ReleaseHdc();
340 }
341*/
342
343 private void GDIDraw(string data, Graphics graph)
344 {
345 Point startPoint = new Point(0, 0);
346 Point endPoint = new Point(0, 0);
347 Pen drawPen = new Pen(Color.Black, 7);
348 string fontName = "Arial";
349 float fontSize = 14;
350 Font myFont = new Font(fontName, fontSize);
351 SolidBrush myBrush = new SolidBrush(Color.Black);
352 char[] lineDelimiter = {';'};
353 char[] partsDelimiter = {','};
354 string[] lines = data.Split(lineDelimiter);
355
356 foreach (string line in lines)
357 {
358 string nextLine = line.Trim();
359 //replace with switch, or even better, do some proper parsing
360 if (nextLine.StartsWith("MoveTo"))
361 {
362 float x = 0;
363 float y = 0;
364 GetParams(partsDelimiter, ref nextLine, 6, ref x, ref y);
365 startPoint.X = (int) x;
366 startPoint.Y = (int) y;
367 }
368 else if (nextLine.StartsWith("LineTo"))
369 {
370 float x = 0;
371 float y = 0;
372 GetParams(partsDelimiter, ref nextLine, 6, ref x, ref y);
373 endPoint.X = (int) x;
374 endPoint.Y = (int) y;
375 graph.DrawLine(drawPen, startPoint, endPoint);
376 startPoint.X = endPoint.X;
377 startPoint.Y = endPoint.Y;
378 }
379 else if (nextLine.StartsWith("Text"))
380 {
381 nextLine = nextLine.Remove(0, 4);
382 nextLine = nextLine.Trim();
383 graph.DrawString(nextLine, myFont, myBrush, startPoint);
384 }
385 else if (nextLine.StartsWith("Image"))
386 {
387 float x = 0;
388 float y = 0;
389 GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y);
390 endPoint.X = (int) x;
391 endPoint.Y = (int) y;
392 Image image = ImageHttpRequest(nextLine);
393 graph.DrawImage(image, (float) startPoint.X, (float) startPoint.Y, x, y);
394 startPoint.X += endPoint.X;
395 startPoint.Y += endPoint.Y;
396 }
397 else if (nextLine.StartsWith("Rectangle"))
398 {
399 float x = 0;
400 float y = 0;
401 GetParams(partsDelimiter, ref nextLine, 9, ref x, ref y);
402 endPoint.X = (int) x;
403 endPoint.Y = (int) y;
404 graph.DrawRectangle(drawPen, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
405 startPoint.X += endPoint.X;
406 startPoint.Y += endPoint.Y;
407 }
408 else if (nextLine.StartsWith("FillRectangle"))
409 {
410 float x = 0;
411 float y = 0;
412 GetParams(partsDelimiter, ref nextLine, 13, ref x, ref y);
413 endPoint.X = (int) x;
414 endPoint.Y = (int) y;
415 graph.FillRectangle(myBrush, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
416 startPoint.X += endPoint.X;
417 startPoint.Y += endPoint.Y;
418 }
419 else if (nextLine.StartsWith("Ellipse"))
420 {
421 float x = 0;
422 float y = 0;
423 GetParams(partsDelimiter, ref nextLine, 7, ref x, ref y);
424 endPoint.X = (int) x;
425 endPoint.Y = (int) y;
426 graph.DrawEllipse(drawPen, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
427 startPoint.X += endPoint.X;
428 startPoint.Y += endPoint.Y;
429 }
430 else if (nextLine.StartsWith("FontSize"))
431 {
432 nextLine = nextLine.Remove(0, 8);
433 nextLine = nextLine.Trim();
434 fontSize = Convert.ToSingle(nextLine, CultureInfo.InvariantCulture);
435 myFont = new Font(fontName, fontSize);
436 }
437 else if (nextLine.StartsWith("FontName"))
438 {
439 nextLine = nextLine.Remove(0, 8);
440 fontName = nextLine.Trim();
441 myFont = new Font(fontName, fontSize);
442 }
443 else if (nextLine.StartsWith("PenSize"))
444 {
445 nextLine = nextLine.Remove(0, 7);
446 nextLine = nextLine.Trim();
447 float size = Convert.ToSingle(nextLine, CultureInfo.InvariantCulture);
448 drawPen.Width = size;
449 }
450 else if (nextLine.StartsWith("PenColour"))
451 {
452 nextLine = nextLine.Remove(0, 9);
453 nextLine = nextLine.Trim();
454 int hex = 0;
455
456 Color newColour;
457 if (Int32.TryParse(nextLine, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hex))
458 {
459 newColour = Color.FromArgb(hex);
460 }
461 else
462 {
463 // this doesn't fail, it just returns black if nothing is found
464 newColour = Color.FromName(nextLine);
465 }
466
467 myBrush.Color = newColour;
468 drawPen.Color = newColour;
469 }
470 }
471 }
472
473 private static void GetParams(char[] partsDelimiter, ref string line, int startLength, ref float x, ref float y)
474 {
475 line = line.Remove(0, startLength);
476 string[] parts = line.Split(partsDelimiter);
477 if (parts.Length == 2)
478 {
479 string xVal = parts[0].Trim();
480 string yVal = parts[1].Trim();
481 x = Convert.ToSingle(xVal, CultureInfo.InvariantCulture);
482 y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
483 }
484 else if (parts.Length > 2)
485 {
486 string xVal = parts[0].Trim();
487 string yVal = parts[1].Trim();
488 x = Convert.ToSingle(xVal, CultureInfo.InvariantCulture);
489 y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
490
491 line = "";
492 for (int i = 2; i < parts.Length; i++)
493 {
494 line = line + parts[i].Trim();
495 line = line + " ";
496 }
497 }
498 }
499
500 private Bitmap ImageHttpRequest(string url)
501 {
502 WebRequest request = HttpWebRequest.Create(url);
503//Ckrinke: Comment out for now as 'str' is unused. Bring it back into play later when it is used.
504//Ckrinke Stream str = null;
505 HttpWebResponse response = (HttpWebResponse) (request).GetResponse();
506 if (response.StatusCode == HttpStatusCode.OK)
507 {
508 Bitmap image = new Bitmap(response.GetResponseStream());
509 return image;
510 }
511
512 return null;
513 }
514 }
515}
diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
new file mode 100644
index 0000000..c363940
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
@@ -0,0 +1,726 @@
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.Collections.Generic;
31using OpenMetaverse;
32using Nini.Config;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36
37// using log4net;
38// using System.Reflection;
39
40
41/*****************************************************
42 *
43 * WorldCommModule
44 *
45 *
46 * Holding place for world comms - basically llListen
47 * function implementation.
48 *
49 * lLListen(integer channel, string name, key id, string msg)
50 * The name, id, and msg arguments specify the filtering
51 * criteria. You can pass the empty string
52 * (or NULL_KEY for id) for these to set a completely
53 * open filter; this causes the listen() event handler to be
54 * invoked for all chat on the channel. To listen only
55 * for chat spoken by a specific object or avatar,
56 * specify the name and/or id arguments. To listen
57 * only for a specific command, specify the
58 * (case-sensitive) msg argument. If msg is not empty,
59 * listener will only hear strings which are exactly equal
60 * to msg. You can also use all the arguments to establish
61 * the most restrictive filtering criteria.
62 *
63 * It might be useful for each listener to maintain a message
64 * digest, with a list of recent messages by UUID. This can
65 * be used to prevent in-world repeater loops. However, the
66 * linden functions do not have this capability, so for now
67 * thats the way it works.
68 * Instead it blocks messages originating from the same prim.
69 * (not Object!)
70 *
71 * For LSL compliance, note the following:
72 * (Tested again 1.21.1 on May 2, 2008)
73 * 1. 'id' has to be parsed into a UUID. None-UUID keys are
74 * to be replaced by the ZeroID key. (Well, TryParse does
75 * that for us.
76 * 2. Setting up an listen event from the same script, with the
77 * same filter settings (including step 1), returns the same
78 * handle as the original filter.
79 * 3. (TODO) handles should be script-local. Starting from 1.
80 * Might be actually easier to map the global handle into
81 * script-local handle in the ScriptEngine. Not sure if its
82 * worth the effort tho.
83 *
84 * **************************************************/
85
86namespace OpenSim.Region.CoreModules.Scripting.WorldComm
87{
88 public class WorldCommModule : IRegionModule, IWorldComm
89 {
90 // private static readonly ILog m_log =
91 // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
92
93 private ListenerManager m_listenerManager;
94 private Queue m_pending;
95 private Queue m_pendingQ;
96 private Scene m_scene;
97 private int m_whisperdistance = 10;
98 private int m_saydistance = 30;
99 private int m_shoutdistance = 100;
100
101 #region IRegionModule Members
102
103 public void Initialise(Scene scene, IConfigSource config)
104 {
105 // wrap this in a try block so that defaults will work if
106 // the config file doesn't specify otherwise.
107 int maxlisteners = 1000;
108 int maxhandles = 64;
109 try
110 {
111 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance);
112 m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance);
113 m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance);
114 maxlisteners = config.Configs["Chat"].GetInt("max_listens_per_region", maxlisteners);
115 maxhandles = config.Configs["Chat"].GetInt("max_listens_per_script", maxhandles);
116 }
117 catch (Exception)
118 {
119 }
120 if (maxlisteners < 1) maxlisteners = int.MaxValue;
121 if (maxhandles < 1) maxhandles = int.MaxValue;
122
123 m_scene = scene;
124 m_scene.RegisterModuleInterface<IWorldComm>(this);
125 m_listenerManager = new ListenerManager(maxlisteners, maxhandles);
126 m_scene.EventManager.OnChatFromClient += DeliverClientMessage;
127 m_scene.EventManager.OnChatBroadcast += DeliverClientMessage;
128 m_pendingQ = new Queue();
129 m_pending = Queue.Synchronized(m_pendingQ);
130 }
131
132 public void PostInitialise()
133 {
134 }
135
136 public void Close()
137 {
138 }
139
140 public string Name
141 {
142 get { return "WorldCommModule"; }
143 }
144
145 public bool IsSharedModule
146 {
147 get { return false; }
148 }
149
150 #endregion
151
152 #region IWorldComm Members
153
154 /// <summary>
155 /// Create a listen event callback with the specified filters.
156 /// The parameters localID,itemID are needed to uniquely identify
157 /// the script during 'peek' time. Parameter hostID is needed to
158 /// determine the position of the script.
159 /// </summary>
160 /// <param name="localID">localID of the script engine</param>
161 /// <param name="itemID">UUID of the script engine</param>
162 /// <param name="hostID">UUID of the SceneObjectPart</param>
163 /// <param name="channel">channel to listen on</param>
164 /// <param name="name">name to filter on</param>
165 /// <param name="id">key to filter on (user given, could be totally faked)</param>
166 /// <param name="msg">msg to filter on</param>
167 /// <returns>number of the scripts handle</returns>
168 public int Listen(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg)
169 {
170 return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg);
171 }
172
173 /// <summary>
174 /// Sets the listen event with handle as active (active = TRUE) or inactive (active = FALSE).
175 /// The handle used is returned from Listen()
176 /// </summary>
177 /// <param name="itemID">UUID of the script engine</param>
178 /// <param name="handle">handle returned by Listen()</param>
179 /// <param name="active">temp. activate or deactivate the Listen()</param>
180 public void ListenControl(UUID itemID, int handle, int active)
181 {
182 if (active == 1)
183 m_listenerManager.Activate(itemID, handle);
184 else if (active == 0)
185 m_listenerManager.Dectivate(itemID, handle);
186 }
187
188 /// <summary>
189 /// Removes the listen event callback with handle
190 /// </summary>
191 /// <param name="itemID">UUID of the script engine</param>
192 /// <param name="handle">handle returned by Listen()</param>
193 public void ListenRemove(UUID itemID, int handle)
194 {
195 m_listenerManager.Remove(itemID, handle);
196 }
197
198 /// <summary>
199 /// Removes all listen event callbacks for the given itemID
200 /// (script engine)
201 /// </summary>
202 /// <param name="itemID">UUID of the script engine</param>
203 public void DeleteListener(UUID itemID)
204 {
205 m_listenerManager.DeleteListener(itemID);
206 }
207
208
209 protected static Vector3 CenterOfRegion = new Vector3(128, 128, 20);
210
211 public void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg)
212 {
213 Vector3 position;
214 SceneObjectPart source;
215 ScenePresence avatar;
216
217 if ((source = m_scene.GetSceneObjectPart(id)) != null)
218 position = source.AbsolutePosition;
219 else if ((avatar = m_scene.GetScenePresence(id)) != null)
220 position = avatar.AbsolutePosition;
221 else if (ChatTypeEnum.Region == type)
222 position = CenterOfRegion;
223 else
224 return;
225
226 DeliverMessage(type, channel, name, id, msg, position);
227 }
228
229 /// <summary>
230 /// This method scans over the objects which registered an interest in listen callbacks.
231 /// For everyone it finds, it checks if it fits the given filter. If it does, then
232 /// enqueue the message for delivery to the objects listen event handler.
233 /// The enqueued ListenerInfo no longer has filter values, but the actually trigged values.
234 /// Objects that do an llSay have their messages delivered here and for nearby avatars,
235 /// the OnChatFromClient event is used.
236 /// </summary>
237 /// <param name="type">type of delvery (whisper,say,shout or regionwide)</param>
238 /// <param name="channel">channel to sent on</param>
239 /// <param name="name">name of sender (object or avatar)</param>
240 /// <param name="id">key of sender (object or avatar)</param>
241 /// <param name="msg">msg to sent</param>
242 public void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg, Vector3 position)
243 {
244 // m_log.DebugFormat("[WorldComm] got[2] type {0}, channel {1}, name {2}, id {3}, msg {4}",
245 // type, channel, name, id, msg);
246
247 // Determine which listen event filters match the given set of arguments, this results
248 // in a limited set of listeners, each belonging a host. If the host is in range, add them
249 // to the pending queue.
250 foreach (ListenerInfo li in m_listenerManager.GetListeners(UUID.Zero, channel, name, id, msg))
251 {
252 // Dont process if this message is from yourself!
253 if (li.GetHostID().Equals(id))
254 continue;
255
256 SceneObjectPart sPart = m_scene.GetSceneObjectPart(li.GetHostID());
257 if (sPart == null)
258 continue;
259
260 double dis = Util.GetDistanceTo(sPart.AbsolutePosition, position);
261 switch (type)
262 {
263 case ChatTypeEnum.Whisper:
264 if (dis < m_whisperdistance)
265 {
266 lock (m_pending.SyncRoot)
267 {
268 m_pending.Enqueue(new ListenerInfo(li,name,id,msg));
269 }
270 }
271 break;
272
273 case ChatTypeEnum.Say:
274 if (dis < m_saydistance)
275 {
276 lock (m_pending.SyncRoot)
277 {
278 m_pending.Enqueue(new ListenerInfo(li,name,id,msg));
279 }
280 }
281 break;
282
283 case ChatTypeEnum.Shout:
284 if (dis < m_shoutdistance)
285 {
286 lock (m_pending.SyncRoot)
287 {
288 m_pending.Enqueue(new ListenerInfo(li,name,id,msg));
289 }
290 }
291 break;
292
293 case ChatTypeEnum.Region:
294 lock (m_pending.SyncRoot)
295 {
296 m_pending.Enqueue(new ListenerInfo(li,name,id,msg));
297 }
298 break;
299 }
300 }
301 }
302
303 /// <summary>
304 /// Are there any listen events ready to be dispatched?
305 /// </summary>
306 /// <returns>boolean indication</returns>
307 public bool HasMessages()
308 {
309 return (m_pending.Count > 0);
310 }
311
312 /// <summary>
313 /// Pop the first availlable listen event from the queue
314 /// </summary>
315 /// <returns>ListenerInfo with filter filled in</returns>
316 public IWorldCommListenerInfo GetNextMessage()
317 {
318 ListenerInfo li = null;
319
320 lock (m_pending.SyncRoot)
321 {
322 li = (ListenerInfo) m_pending.Dequeue();
323 }
324
325 return li;
326 }
327
328 #endregion
329
330 /********************************************************************
331 *
332 * Listener Stuff
333 *
334 * *****************************************************************/
335
336 private void DeliverClientMessage(Object sender, OSChatMessage e)
337 {
338 if (null != e.Sender)
339 DeliverMessage(e.Type, e.Channel, e.Sender.Name, e.Sender.AgentId, e.Message, e.Position);
340 else
341 DeliverMessage(e.Type, e.Channel, e.From, UUID.Zero, e.Message, e.Position);
342 }
343
344 public Object[] GetSerializationData(UUID itemID)
345 {
346 return m_listenerManager.GetSerializationData(itemID);
347 }
348
349 public void CreateFromData(uint localID, UUID itemID, UUID hostID,
350 Object[] data)
351 {
352 m_listenerManager.AddFromData(localID, itemID, hostID, data);
353 }
354 }
355
356 public class ListenerManager
357 {
358 private Dictionary<int, List<ListenerInfo>> m_listeners = new Dictionary<int, List<ListenerInfo>>();
359 private int m_maxlisteners;
360 private int m_maxhandles;
361 private int m_curlisteners;
362
363 public ListenerManager(int maxlisteners, int maxhandles)
364 {
365 m_maxlisteners = maxlisteners;
366 m_maxhandles = maxhandles;
367 m_curlisteners = 0;
368 }
369
370 public int AddListener(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg)
371 {
372 // do we already have a match on this particular filter event?
373 List<ListenerInfo> coll = GetListeners(itemID, channel, name, id, msg);
374
375 if (coll.Count > 0)
376 {
377 // special case, called with same filter settings, return same handle
378 // (2008-05-02, tested on 1.21.1 server, still holds)
379 return coll[0].GetHandle();
380 }
381
382 if (m_curlisteners < m_maxlisteners)
383 {
384 int newHandle = GetNewHandle(itemID);
385
386 if (newHandle > 0)
387 {
388 ListenerInfo li = new ListenerInfo(newHandle, localID, itemID, hostID, channel, name, id, msg);
389
390 lock (m_listeners)
391 {
392 List<ListenerInfo> listeners;
393 if (!m_listeners.TryGetValue(channel,out listeners))
394 {
395 listeners = new List<ListenerInfo>();
396 m_listeners.Add(channel, listeners);
397 }
398 listeners.Add(li);
399 m_curlisteners++;
400 }
401
402 return newHandle;
403 }
404 }
405 return -1;
406 }
407
408 public void Remove(UUID itemID, int handle)
409 {
410 lock (m_listeners)
411 {
412 foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners)
413 {
414 foreach (ListenerInfo li in lis.Value)
415 {
416 if (li.GetItemID().Equals(itemID) && li.GetHandle().Equals(handle))
417 {
418 lis.Value.Remove(li);
419 if (lis.Value.Count == 0)
420 {
421 m_listeners.Remove(lis.Key);
422 m_curlisteners--;
423 }
424 // there should be only one, so we bail out early
425 return;
426 }
427 }
428 }
429 }
430 }
431
432 public void DeleteListener(UUID itemID)
433 {
434 List<int> emptyChannels = new List<int>();
435 List<ListenerInfo> removedListeners = new List<ListenerInfo>();
436
437 lock (m_listeners)
438 {
439 foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners)
440 {
441 foreach (ListenerInfo li in lis.Value)
442 {
443 if (li.GetItemID().Equals(itemID))
444 {
445 // store them first, else the enumerated bails on us
446 removedListeners.Add(li);
447 }
448 }
449 foreach (ListenerInfo li in removedListeners)
450 {
451 lis.Value.Remove(li);
452 m_curlisteners--;
453 }
454 removedListeners.Clear();
455 if (lis.Value.Count == 0)
456 {
457 // again, store first, remove later
458 emptyChannels.Add(lis.Key);
459 }
460 }
461 foreach (int channel in emptyChannels)
462 {
463 m_listeners.Remove(channel);
464 }
465 }
466 }
467
468 public void Activate(UUID itemID, int handle)
469 {
470 lock (m_listeners)
471 {
472 foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners)
473 {
474 foreach (ListenerInfo li in lis.Value)
475 {
476 if (li.GetItemID().Equals(itemID) && li.GetHandle() == handle)
477 {
478 li.Activate();
479 // only one, bail out
480 return;
481 }
482 }
483 }
484 }
485 }
486
487 public void Dectivate(UUID itemID, int handle)
488 {
489 lock (m_listeners)
490 {
491 foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners)
492 {
493 foreach (ListenerInfo li in lis.Value)
494 {
495 if (li.GetItemID().Equals(itemID) && li.GetHandle() == handle)
496 {
497 li.Deactivate();
498 // only one, bail out
499 return;
500 }
501 }
502 }
503 }
504 }
505
506 // non-locked access, since its always called in the context of the lock
507 private int GetNewHandle(UUID itemID)
508 {
509 List<int> handles = new List<int>();
510
511 // build a list of used keys for this specific itemID...
512 foreach (KeyValuePair<int,List<ListenerInfo>> lis in m_listeners)
513 {
514 foreach (ListenerInfo li in lis.Value)
515 {
516 if (li.GetItemID().Equals(itemID))
517 handles.Add(li.GetHandle());
518 }
519 }
520
521 // Note: 0 is NOT a valid handle for llListen() to return
522 for (int i = 1; i <= m_maxhandles; i++)
523 {
524 if (!handles.Contains(i))
525 return i;
526 }
527
528 return -1;
529 }
530
531 // Theres probably a more clever and efficient way to
532 // do this, maybe with regex.
533 // PM2008: Ha, one could even be smart and define a specialized Enumerator.
534 public List<ListenerInfo> GetListeners(UUID itemID, int channel, string name, UUID id, string msg)
535 {
536 List<ListenerInfo> collection = new List<ListenerInfo>();
537
538 lock (m_listeners)
539 {
540 List<ListenerInfo> listeners;
541 if (!m_listeners.TryGetValue(channel,out listeners))
542 {
543 return collection;
544 }
545
546 foreach (ListenerInfo li in listeners)
547 {
548 if (!li.IsActive())
549 {
550 continue;
551 }
552 if (!itemID.Equals(UUID.Zero) && !li.GetItemID().Equals(itemID))
553 {
554 continue;
555 }
556 if (li.GetName().Length > 0 && !li.GetName().Equals(name))
557 {
558 continue;
559 }
560 if (!li.GetID().Equals(UUID.Zero) && !li.GetID().Equals(id))
561 {
562 continue;
563 }
564 if (li.GetMessage().Length > 0 && !li.GetMessage().Equals(msg))
565 {
566 continue;
567 }
568 collection.Add(li);
569 }
570 }
571 return collection;
572 }
573
574 public Object[] GetSerializationData(UUID itemID)
575 {
576 List<Object> data = new List<Object>();
577
578 foreach (List<ListenerInfo> list in m_listeners.Values)
579 {
580 foreach (ListenerInfo l in list)
581 {
582 if (l.GetItemID() == itemID)
583 data.AddRange(l.GetSerializationData());
584 }
585 }
586 return (Object[])data.ToArray();
587 }
588
589 public void AddFromData(uint localID, UUID itemID, UUID hostID,
590 Object[] data)
591 {
592 int idx = 0;
593 Object[] item = new Object[6];
594
595 while (idx < data.Length)
596 {
597 Array.Copy(data, idx, item, 0, 6);
598
599 ListenerInfo info =
600 ListenerInfo.FromData(localID, itemID, hostID, item);
601
602 if (!m_listeners.ContainsKey((int)item[2]))
603 m_listeners.Add((int)item[2], new List<ListenerInfo>());
604 m_listeners[(int)item[2]].Add(info);
605
606 idx+=6;
607 }
608 }
609 }
610
611 public class ListenerInfo: IWorldCommListenerInfo
612 {
613 private bool m_active; // Listener is active or not
614 private int m_handle; // Assigned handle of this listener
615 private uint m_localID; // Local ID from script engine
616 private UUID m_itemID; // ID of the host script engine
617 private UUID m_hostID; // ID of the host/scene part
618 private int m_channel; // Channel
619 private UUID m_id; // ID to filter messages from
620 private string m_name; // Object name to filter messages from
621 private string m_message; // The message
622
623 public ListenerInfo(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message)
624 {
625 Initialise(handle, localID, ItemID, hostID, channel, name, id, message);
626 }
627
628 public ListenerInfo(ListenerInfo li, string name, UUID id, string message)
629 {
630 Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message);
631 }
632
633 private void Initialise(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name,
634 UUID id, string message)
635 {
636 m_active = true;
637 m_handle = handle;
638 m_localID = localID;
639 m_itemID = ItemID;
640 m_hostID = hostID;
641 m_channel = channel;
642 m_name = name;
643 m_id = id;
644 m_message = message;
645 }
646
647 public Object[] GetSerializationData()
648 {
649 Object[] data = new Object[6];
650
651 data[0] = m_active;
652 data[1] = m_handle;
653 data[2] = m_channel;
654 data[3] = m_name;
655 data[4] = m_id;
656 data[5] = m_message;
657
658 return data;
659 }
660
661 public static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data)
662 {
663 ListenerInfo linfo = new ListenerInfo((int)data[1], localID,
664 ItemID, hostID, (int)data[2], (string)data[3],
665 (UUID)data[4], (string)data[5]);
666 linfo.m_active=(bool)data[0];
667
668 return linfo;
669 }
670
671 public UUID GetItemID()
672 {
673 return m_itemID;
674 }
675
676 public UUID GetHostID()
677 {
678 return m_hostID;
679 }
680
681 public int GetChannel()
682 {
683 return m_channel;
684 }
685
686 public uint GetLocalID()
687 {
688 return m_localID;
689 }
690
691 public int GetHandle()
692 {
693 return m_handle;
694 }
695
696 public string GetMessage()
697 {
698 return m_message;
699 }
700
701 public string GetName()
702 {
703 return m_name;
704 }
705
706 public bool IsActive()
707 {
708 return m_active;
709 }
710
711 public void Deactivate()
712 {
713 m_active = false;
714 }
715
716 public void Activate()
717 {
718 m_active = true;
719 }
720
721 public UUID GetID()
722 {
723 return m_id;
724 }
725 }
726}
diff --git a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
new file mode 100644
index 0000000..942c130
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
@@ -0,0 +1,726 @@
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.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Threading;
34using OpenMetaverse;
35using log4net;
36using Nini.Config;
37using Nwc.XmlRpc;
38using OpenSim.Framework;
39using OpenSim.Framework.Servers;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42
43/*****************************************************
44 *
45 * XMLRPCModule
46 *
47 * Module for accepting incoming communications from
48 * external XMLRPC client and calling a remote data
49 * procedure for a registered data channel/prim.
50 *
51 *
52 * 1. On module load, open a listener port
53 * 2. Attach an XMLRPC handler
54 * 3. When a request is received:
55 * 3.1 Parse into components: channel key, int, string
56 * 3.2 Look up registered channel listeners
57 * 3.3 Call the channel (prim) remote data method
58 * 3.4 Capture the response (llRemoteDataReply)
59 * 3.5 Return response to client caller
60 * 3.6 If no response from llRemoteDataReply within
61 * RemoteReplyScriptTimeout, generate script timeout fault
62 *
63 * Prims in script must:
64 * 1. Open a remote data channel
65 * 1.1 Generate a channel ID
66 * 1.2 Register primid,channelid pair with module
67 * 2. Implement the remote data procedure handler
68 *
69 * llOpenRemoteDataChannel
70 * llRemoteDataReply
71 * remote_data(integer type, key channel, key messageid, string sender, integer ival, string sval)
72 * llCloseRemoteDataChannel
73 *
74 * **************************************************/
75
76namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
77{
78 public class XMLRPCModule : IRegionModule, IXMLRPC
79 {
80 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
81
82 private string m_name = "XMLRPCModule";
83
84 // <channel id, RPCChannelInfo>
85 private Dictionary<UUID, RPCChannelInfo> m_openChannels;
86 private Dictionary<UUID, SendRemoteDataRequest> m_pendingSRDResponses;
87 private int m_remoteDataPort = 0;
88
89 private Dictionary<UUID, RPCRequestInfo> m_rpcPending;
90 private Dictionary<UUID, RPCRequestInfo> m_rpcPendingResponses;
91 private List<Scene> m_scenes = new List<Scene>();
92 private int RemoteReplyScriptTimeout = 9000;
93 private int RemoteReplyScriptWait = 300;
94 private object XMLRPCListLock = new object();
95
96 #region IRegionModule Members
97
98 public void Initialise(Scene scene, IConfigSource config)
99 {
100 // We need to create these early because the scripts might be calling
101 // But since this gets called for every region, we need to make sure they
102 // get called only one time (or we lose any open channels)
103 if (null == m_openChannels)
104 {
105 m_openChannels = new Dictionary<UUID, RPCChannelInfo>();
106 m_rpcPending = new Dictionary<UUID, RPCRequestInfo>();
107 m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>();
108 m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>();
109
110 try
111 {
112 m_remoteDataPort = config.Configs["Network"].GetInt("remoteDataPort", m_remoteDataPort);
113 }
114 catch (Exception)
115 {
116 }
117 }
118
119 if (!m_scenes.Contains(scene))
120 {
121 m_scenes.Add(scene);
122
123 scene.RegisterModuleInterface<IXMLRPC>(this);
124 }
125 }
126
127 public void PostInitialise()
128 {
129 if (IsEnabled())
130 {
131 // Start http server
132 // Attach xmlrpc handlers
133 m_log.Info("[REMOTE_DATA]: " +
134 "Starting XMLRPC Server on port " + m_remoteDataPort + " for llRemoteData commands.");
135 BaseHttpServer httpServer = new BaseHttpServer((uint) m_remoteDataPort);
136 httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData);
137 httpServer.Start();
138 }
139 }
140
141 public void Close()
142 {
143 }
144
145 public string Name
146 {
147 get { return m_name; }
148 }
149
150 public bool IsSharedModule
151 {
152 get { return true; }
153 }
154
155 #endregion
156
157 #region IXMLRPC Members
158
159 public bool IsEnabled()
160 {
161 return (m_remoteDataPort > 0);
162 }
163
164 /**********************************************
165 * OpenXMLRPCChannel
166 *
167 * Generate a UUID channel key and add it and
168 * the prim id to dictionary <channelUUID, primUUID>
169 *
170 * A custom channel key can be proposed.
171 * Otherwise, passing UUID.Zero will generate
172 * and return a random channel
173 *
174 * First check if there is a channel assigned for
175 * this itemID. If there is, then someone called
176 * llOpenRemoteDataChannel twice. Just return the
177 * original channel. Other option is to delete the
178 * current channel and assign a new one.
179 *
180 * ********************************************/
181
182 public UUID OpenXMLRPCChannel(uint localID, UUID itemID, UUID channelID)
183 {
184 UUID newChannel = UUID.Zero;
185
186 // This should no longer happen, but the check is reasonable anyway
187 if (null == m_openChannels)
188 {
189 m_log.Warn("[RemoteDataReply] Attempt to open channel before initialization is complete");
190 return newChannel;
191 }
192
193 //Is a dupe?
194 foreach (RPCChannelInfo ci in m_openChannels.Values)
195 {
196 if (ci.GetItemID().Equals(itemID))
197 {
198 // return the original channel ID for this item
199 newChannel = ci.GetChannelID();
200 break;
201 }
202 }
203
204 if (newChannel == UUID.Zero)
205 {
206 newChannel = (channelID == UUID.Zero) ? UUID.Random() : channelID;
207 RPCChannelInfo rpcChanInfo = new RPCChannelInfo(localID, itemID, newChannel);
208 lock (XMLRPCListLock)
209 {
210 m_openChannels.Add(newChannel, rpcChanInfo);
211 }
212 }
213
214 return newChannel;
215 }
216
217 // Delete channels based on itemID
218 // for when a script is deleted
219 public void DeleteChannels(UUID itemID)
220 {
221 if (m_openChannels != null)
222 {
223 ArrayList tmp = new ArrayList();
224
225 lock (XMLRPCListLock)
226 {
227 foreach (RPCChannelInfo li in m_openChannels.Values)
228 {
229 if (li.GetItemID().Equals(itemID))
230 {
231 tmp.Add(itemID);
232 }
233 }
234
235 IEnumerator tmpEnumerator = tmp.GetEnumerator();
236 while (tmpEnumerator.MoveNext())
237 m_openChannels.Remove((UUID) tmpEnumerator.Current);
238 }
239 }
240 }
241
242 /**********************************************
243 * Remote Data Reply
244 *
245 * Response to RPC message
246 *
247 *********************************************/
248
249 public void RemoteDataReply(string channel, string message_id, string sdata, int idata)
250 {
251 UUID message_key = new UUID(message_id);
252 UUID channel_key = new UUID(channel);
253
254 RPCRequestInfo rpcInfo = null;
255
256 if (message_key == UUID.Zero)
257 {
258 foreach (RPCRequestInfo oneRpcInfo in m_rpcPendingResponses.Values)
259 if (oneRpcInfo.GetChannelKey() == channel_key)
260 rpcInfo = oneRpcInfo;
261 }
262 else
263 {
264 m_rpcPendingResponses.TryGetValue(message_key, out rpcInfo);
265 }
266
267 if (rpcInfo != null)
268 {
269 rpcInfo.SetStrRetval(sdata);
270 rpcInfo.SetIntRetval(idata);
271 rpcInfo.SetProcessed(true);
272 m_rpcPendingResponses.Remove(message_key);
273 }
274 else
275 {
276 m_log.Warn("[RemoteDataReply]: Channel or message_id not found");
277 }
278 }
279
280 /**********************************************
281 * CloseXMLRPCChannel
282 *
283 * Remove channel from dictionary
284 *
285 *********************************************/
286
287 public void CloseXMLRPCChannel(UUID channelKey)
288 {
289 if (m_openChannels.ContainsKey(channelKey))
290 m_openChannels.Remove(channelKey);
291 }
292
293
294 public bool hasRequests()
295 {
296 lock (XMLRPCListLock)
297 {
298 if (m_rpcPending != null)
299 return (m_rpcPending.Count > 0);
300 else
301 return false;
302 }
303 }
304
305 public IXmlRpcRequestInfo GetNextCompletedRequest()
306 {
307 if (m_rpcPending != null)
308 {
309 lock (XMLRPCListLock)
310 {
311 foreach (UUID luid in m_rpcPending.Keys)
312 {
313 RPCRequestInfo tmpReq;
314
315 if (m_rpcPending.TryGetValue(luid, out tmpReq))
316 {
317 if (!tmpReq.IsProcessed()) return tmpReq;
318 }
319 }
320 }
321 }
322 return null;
323 }
324
325 public void RemoveCompletedRequest(UUID id)
326 {
327 lock (XMLRPCListLock)
328 {
329 RPCRequestInfo tmp;
330 if (m_rpcPending.TryGetValue(id, out tmp))
331 {
332 m_rpcPending.Remove(id);
333 m_rpcPendingResponses.Add(id, tmp);
334 }
335 else
336 {
337 Console.WriteLine("UNABLE TO REMOVE COMPLETED REQUEST");
338 }
339 }
340 }
341
342 public UUID SendRemoteData(uint localID, UUID itemID, string channel, string dest, int idata, string sdata)
343 {
344 SendRemoteDataRequest req = new SendRemoteDataRequest(
345 localID, itemID, channel, dest, idata, sdata
346 );
347 m_pendingSRDResponses.Add(req.GetReqID(), req);
348 req.Process();
349 return req.ReqID;
350 }
351
352 public IServiceRequest GetNextCompletedSRDRequest()
353 {
354 if (m_pendingSRDResponses != null)
355 {
356 lock (XMLRPCListLock)
357 {
358 foreach (UUID luid in m_pendingSRDResponses.Keys)
359 {
360 SendRemoteDataRequest tmpReq;
361
362 if (m_pendingSRDResponses.TryGetValue(luid, out tmpReq))
363 {
364 if (tmpReq.Finished)
365 return tmpReq;
366 }
367 }
368 }
369 }
370 return null;
371 }
372
373 public void RemoveCompletedSRDRequest(UUID id)
374 {
375 lock (XMLRPCListLock)
376 {
377 SendRemoteDataRequest tmpReq;
378 if (m_pendingSRDResponses.TryGetValue(id, out tmpReq))
379 {
380 m_pendingSRDResponses.Remove(id);
381 }
382 }
383 }
384
385 public void CancelSRDRequests(UUID itemID)
386 {
387 if (m_pendingSRDResponses != null)
388 {
389 lock (XMLRPCListLock)
390 {
391 foreach (SendRemoteDataRequest li in m_pendingSRDResponses.Values)
392 {
393 if (li.ItemID.Equals(itemID))
394 m_pendingSRDResponses.Remove(li.GetReqID());
395 }
396 }
397 }
398 }
399
400 #endregion
401
402 public XmlRpcResponse XmlRpcRemoteData(XmlRpcRequest request)
403 {
404 XmlRpcResponse response = new XmlRpcResponse();
405
406 Hashtable requestData = (Hashtable) request.Params[0];
407 bool GoodXML = (requestData.Contains("Channel") && requestData.Contains("IntValue") &&
408 requestData.Contains("StringValue"));
409
410 if (GoodXML)
411 {
412 UUID channel = new UUID((string) requestData["Channel"]);
413 RPCChannelInfo rpcChanInfo;
414 if (m_openChannels.TryGetValue(channel, out rpcChanInfo))
415 {
416 string intVal = Convert.ToInt32(requestData["IntValue"]).ToString();
417 string strVal = (string) requestData["StringValue"];
418
419 RPCRequestInfo rpcInfo;
420
421 lock (XMLRPCListLock)
422 {
423 rpcInfo =
424 new RPCRequestInfo(rpcChanInfo.GetLocalID(), rpcChanInfo.GetItemID(), channel, strVal,
425 intVal);
426 m_rpcPending.Add(rpcInfo.GetMessageID(), rpcInfo);
427 }
428
429 int timeoutCtr = 0;
430
431 while (!rpcInfo.IsProcessed() && (timeoutCtr < RemoteReplyScriptTimeout))
432 {
433 Thread.Sleep(RemoteReplyScriptWait);
434 timeoutCtr += RemoteReplyScriptWait;
435 }
436 if (rpcInfo.IsProcessed())
437 {
438 Hashtable param = new Hashtable();
439 param["StringValue"] = rpcInfo.GetStrRetval();
440 param["IntValue"] = rpcInfo.GetIntRetval();
441
442 ArrayList parameters = new ArrayList();
443 parameters.Add(param);
444
445 response.Value = parameters;
446 rpcInfo = null;
447 }
448 else
449 {
450 response.SetFault(-1, "Script timeout");
451 rpcInfo = null;
452 }
453 }
454 else
455 {
456 response.SetFault(-1, "Invalid channel");
457 }
458 }
459
460 return response;
461 }
462 }
463
464 public class RPCRequestInfo: IXmlRpcRequestInfo
465 {
466 private UUID m_ChannelKey;
467 private string m_IntVal;
468 private UUID m_ItemID;
469 private uint m_localID;
470 private UUID m_MessageID;
471 private bool m_processed;
472 private int m_respInt;
473 private string m_respStr;
474 private string m_StrVal;
475
476 public RPCRequestInfo(uint localID, UUID itemID, UUID channelKey, string strVal, string intVal)
477 {
478 m_localID = localID;
479 m_StrVal = strVal;
480 m_IntVal = intVal;
481 m_ItemID = itemID;
482 m_ChannelKey = channelKey;
483 m_MessageID = UUID.Random();
484 m_processed = false;
485 m_respStr = String.Empty;
486 m_respInt = 0;
487 }
488
489 public bool IsProcessed()
490 {
491 return m_processed;
492 }
493
494 public UUID GetChannelKey()
495 {
496 return m_ChannelKey;
497 }
498
499 public void SetProcessed(bool processed)
500 {
501 m_processed = processed;
502 }
503
504 public void SetStrRetval(string resp)
505 {
506 m_respStr = resp;
507 }
508
509 public string GetStrRetval()
510 {
511 return m_respStr;
512 }
513
514 public void SetIntRetval(int resp)
515 {
516 m_respInt = resp;
517 }
518
519 public int GetIntRetval()
520 {
521 return m_respInt;
522 }
523
524 public uint GetLocalID()
525 {
526 return m_localID;
527 }
528
529 public UUID GetItemID()
530 {
531 return m_ItemID;
532 }
533
534 public string GetStrVal()
535 {
536 return m_StrVal;
537 }
538
539 public int GetIntValue()
540 {
541 return int.Parse(m_IntVal);
542 }
543
544 public UUID GetMessageID()
545 {
546 return m_MessageID;
547 }
548 }
549
550 public class RPCChannelInfo
551 {
552 private UUID m_ChannelKey;
553 private UUID m_itemID;
554 private uint m_localID;
555
556 public RPCChannelInfo(uint localID, UUID itemID, UUID channelID)
557 {
558 m_ChannelKey = channelID;
559 m_localID = localID;
560 m_itemID = itemID;
561 }
562
563 public UUID GetItemID()
564 {
565 return m_itemID;
566 }
567
568 public UUID GetChannelID()
569 {
570 return m_ChannelKey;
571 }
572
573 public uint GetLocalID()
574 {
575 return m_localID;
576 }
577 }
578
579 public class SendRemoteDataRequest: IServiceRequest
580 {
581 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
582
583 public string Channel;
584 public string DestURL;
585 private bool _finished;
586 public bool Finished
587 {
588 get { return _finished; }
589 set { _finished = value; }
590 }
591 private Thread httpThread;
592 public int Idata;
593 private UUID _itemID;
594 public UUID ItemID
595 {
596 get { return _itemID; }
597 set { _itemID = value; }
598 }
599 private uint _localID;
600 public uint LocalID
601 {
602 get { return _localID; }
603 set { _localID = value; }
604 }
605 private UUID _reqID;
606 public UUID ReqID
607 {
608 get { return _reqID; }
609 set { _reqID = value; }
610 }
611 public XmlRpcRequest Request;
612 public int ResponseIdata;
613 public string ResponseSdata;
614 public string Sdata;
615
616 public SendRemoteDataRequest(uint localID, UUID itemID, string channel, string dest, int idata, string sdata)
617 {
618 this.Channel = channel;
619 DestURL = dest;
620 this.Idata = idata;
621 this.Sdata = sdata;
622 ItemID = itemID;
623 LocalID = localID;
624
625 ReqID = UUID.Random();
626 }
627
628 public void Process()
629 {
630 httpThread = new Thread(SendRequest);
631 httpThread.Name = "HttpRequestThread";
632 httpThread.Priority = ThreadPriority.BelowNormal;
633 httpThread.IsBackground = true;
634 _finished = false;
635 httpThread.Start();
636 ThreadTracker.Add(httpThread);
637 }
638
639 /*
640 * TODO: More work on the response codes. Right now
641 * returning 200 for success or 499 for exception
642 */
643
644 public void SendRequest()
645 {
646 Hashtable param = new Hashtable();
647
648 // Check if channel is an UUID
649 // if not, use as method name
650 UUID parseUID;
651 string mName = "llRemoteData";
652 if ((Channel != null) && (Channel != ""))
653 if (!UUID.TryParse(Channel, out parseUID))
654 mName = Channel;
655 else
656 param["Channel"] = Channel;
657
658 param["StringValue"] = Sdata;
659 param["IntValue"] = Convert.ToString(Idata);
660
661 ArrayList parameters = new ArrayList();
662 parameters.Add(param);
663 XmlRpcRequest req = new XmlRpcRequest(mName, parameters);
664 try
665 {
666 XmlRpcResponse resp = req.Send(DestURL, 30000);
667 if (resp != null)
668 {
669 Hashtable respParms;
670 if (resp.Value.GetType().Equals(typeof(System.Collections.Hashtable)))
671 {
672 respParms = (Hashtable) resp.Value;
673 }
674 else
675 {
676 ArrayList respData = (ArrayList) resp.Value;
677 respParms = (Hashtable) respData[0];
678 }
679 if (respParms != null)
680 {
681 if (respParms.Contains("StringValue"))
682 {
683 Sdata = (string) respParms["StringValue"];
684 }
685 if (respParms.Contains("IntValue"))
686 {
687 Idata = Convert.ToInt32((string) respParms["IntValue"]);
688 }
689 if (respParms.Contains("faultString"))
690 {
691 Sdata = (string) respParms["faultString"];
692 }
693 if (respParms.Contains("faultCode"))
694 {
695 Idata = Convert.ToInt32(respParms["faultCode"]);
696 }
697 }
698 }
699 }
700 catch (Exception we)
701 {
702 Sdata = we.Message;
703 m_log.Warn("[SendRemoteDataRequest]: Request failed");
704 m_log.Warn(we.StackTrace);
705 }
706
707 _finished = true;
708 }
709
710 public void Stop()
711 {
712 try
713 {
714 httpThread.Abort();
715 }
716 catch (Exception)
717 {
718 }
719 }
720
721 public UUID GetReqID()
722 {
723 return ReqID;
724 }
725 }
726}