aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/Util.cs3942
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs31
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs290
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs76
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs20
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs26
-rw-r--r--OpenSim/Server/Handlers/Hypergrid/HGFriendServerConnector.cs26
-rw-r--r--OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs159
-rw-r--r--OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs5
-rw-r--r--OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs20
-rw-r--r--OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs67
-rw-r--r--OpenSim/Services/HypergridService/HGFriendsService.cs301
-rw-r--r--OpenSim/Services/Interfaces/IHypergridServices.cs11
-rw-r--r--bin/config-include/StandaloneHypergrid.ini6
14 files changed, 2790 insertions, 2190 deletions
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 9e0f138..0b9e0e7 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1,383 +1,383 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 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 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Data; 31using System.Data;
32using System.Diagnostics; 32using System.Diagnostics;
33using System.Globalization; 33using System.Globalization;
34using System.IO; 34using System.IO;
35using System.IO.Compression; 35using System.IO.Compression;
36using System.Net; 36using System.Net;
37using System.Net.Sockets; 37using System.Net.Sockets;
38using System.Reflection; 38using System.Reflection;
39using System.Runtime.InteropServices; 39using System.Runtime.InteropServices;
40using System.Runtime.Serialization; 40using System.Runtime.Serialization;
41using System.Runtime.Serialization.Formatters.Binary; 41using System.Runtime.Serialization.Formatters.Binary;
42using System.Security.Cryptography; 42using System.Security.Cryptography;
43using System.Text; 43using System.Text;
44using System.Text.RegularExpressions; 44using System.Text.RegularExpressions;
45using System.Xml; 45using System.Xml;
46using System.Threading; 46using System.Threading;
47using log4net; 47using log4net;
48using Nini.Config; 48using Nini.Config;
49using Nwc.XmlRpc; 49using Nwc.XmlRpc;
50using OpenMetaverse; 50using OpenMetaverse;
51using OpenMetaverse.StructuredData; 51using OpenMetaverse.StructuredData;
52using Amib.Threading; 52using Amib.Threading;
53 53
54namespace OpenSim.Framework 54namespace OpenSim.Framework
55{ 55{
56 /// <summary> 56 /// <summary>
57 /// The method used by Util.FireAndForget for asynchronously firing events 57 /// The method used by Util.FireAndForget for asynchronously firing events
58 /// </summary> 58 /// </summary>
59 /// <remarks> 59 /// <remarks>
60 /// None is used to execute the method in the same thread that made the call. It should only be used by regression 60 /// None is used to execute the method in the same thread that made the call. It should only be used by regression
61 /// test code that relies on predictable event ordering. 61 /// test code that relies on predictable event ordering.
62 /// RegressionTest is used by regression tests. It fires the call synchronously and does not catch any exceptions. 62 /// RegressionTest is used by regression tests. It fires the call synchronously and does not catch any exceptions.
63 /// </remarks> 63 /// </remarks>
64 public enum FireAndForgetMethod 64 public enum FireAndForgetMethod
65 { 65 {
66 None, 66 None,
67 RegressionTest, 67 RegressionTest,
68 UnsafeQueueUserWorkItem, 68 UnsafeQueueUserWorkItem,
69 QueueUserWorkItem, 69 QueueUserWorkItem,
70 BeginInvoke, 70 BeginInvoke,
71 SmartThreadPool, 71 SmartThreadPool,
72 Thread, 72 Thread,
73 } 73 }
74 74
75 /// <summary> 75 /// <summary>
76 /// Miscellaneous utility functions 76 /// Miscellaneous utility functions
77 /// </summary> 77 /// </summary>
78 public class Util 78 public class Util
79 { 79 {
80 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 80 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
81 81
82 private static uint nextXferID = 5000; 82 private static uint nextXferID = 5000;
83 private static Random randomClass = new Random(); 83 private static Random randomClass = new Random();
84 84
85 // Get a list of invalid file characters (OS dependent) 85 // Get a list of invalid file characters (OS dependent)
86 private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; 86 private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]";
87 private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; 87 private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]";
88 private static object XferLock = new object(); 88 private static object XferLock = new object();
89 89
90 /// <summary> 90 /// <summary>
91 /// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used 91 /// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used
92 /// </summary> 92 /// </summary>
93 private static SmartThreadPool m_ThreadPool; 93 private static SmartThreadPool m_ThreadPool;
94 94
95 // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. 95 // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC.
96 private static readonly DateTime unixEpoch = 96 private static readonly DateTime unixEpoch =
97 DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); 97 DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime();
98 98
99 private static readonly string rawUUIDPattern 99 private static readonly string rawUUIDPattern
100 = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; 100 = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}";
101 public static readonly Regex PermissiveUUIDPattern = new Regex(rawUUIDPattern); 101 public static readonly Regex PermissiveUUIDPattern = new Regex(rawUUIDPattern);
102 public static readonly Regex UUIDPattern = new Regex(string.Format("^{0}$", rawUUIDPattern)); 102 public static readonly Regex UUIDPattern = new Regex(string.Format("^{0}$", rawUUIDPattern));
103 103
104 public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; 104 public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool;
105 public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; 105 public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod;
106 106
107 /// <summary> 107 /// <summary>
108 /// Gets the name of the directory where the current running executable 108 /// Gets the name of the directory where the current running executable
109 /// is located 109 /// is located
110 /// </summary> 110 /// </summary>
111 /// <returns>Filesystem path to the directory containing the current 111 /// <returns>Filesystem path to the directory containing the current
112 /// executable</returns> 112 /// executable</returns>
113 public static string ExecutingDirectory() 113 public static string ExecutingDirectory()
114 { 114 {
115 return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 115 return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
116 } 116 }
117 117
118 /// <summary> 118 /// <summary>
119 /// Linear interpolates B<->C using percent A 119 /// Linear interpolates B<->C using percent A
120 /// </summary> 120 /// </summary>
121 /// <param name="a"></param> 121 /// <param name="a"></param>
122 /// <param name="b"></param> 122 /// <param name="b"></param>
123 /// <param name="c"></param> 123 /// <param name="c"></param>
124 /// <returns></returns> 124 /// <returns></returns>
125 public static double lerp(double a, double b, double c) 125 public static double lerp(double a, double b, double c)
126 { 126 {
127 return (b*a) + (c*(1 - a)); 127 return (b*a) + (c*(1 - a));
128 } 128 }
129 129
130 /// <summary> 130 /// <summary>
131 /// Bilinear Interpolate, see Lerp but for 2D using 'percents' X & Y. 131 /// Bilinear Interpolate, see Lerp but for 2D using 'percents' X & Y.
132 /// Layout: 132 /// Layout:
133 /// A B 133 /// A B
134 /// C D 134 /// C D
135 /// A<->C = Y 135 /// A<->C = Y
136 /// C<->D = X 136 /// C<->D = X
137 /// </summary> 137 /// </summary>
138 /// <param name="x"></param> 138 /// <param name="x"></param>
139 /// <param name="y"></param> 139 /// <param name="y"></param>
140 /// <param name="a"></param> 140 /// <param name="a"></param>
141 /// <param name="b"></param> 141 /// <param name="b"></param>
142 /// <param name="c"></param> 142 /// <param name="c"></param>
143 /// <param name="d"></param> 143 /// <param name="d"></param>
144 /// <returns></returns> 144 /// <returns></returns>
145 public static double lerp2D(double x, double y, double a, double b, double c, double d) 145 public static double lerp2D(double x, double y, double a, double b, double c, double d)
146 { 146 {
147 return lerp(y, lerp(x, a, b), lerp(x, c, d)); 147 return lerp(y, lerp(x, a, b), lerp(x, c, d));
148 } 148 }
149 149
150 public static Encoding UTF8 = Encoding.UTF8; 150 public static Encoding UTF8 = Encoding.UTF8;
151 151
152 /// <value> 152 /// <value>
153 /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) 153 /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards)
154 /// </value> 154 /// </value>
155 public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); 155 public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f");
156 156
157 #region Vector Equations 157 #region Vector Equations
158 158
159 /// <summary> 159 /// <summary>
160 /// Get the distance between two 3d vectors 160 /// Get the distance between two 3d vectors
161 /// </summary> 161 /// </summary>
162 /// <param name="a">A 3d vector</param> 162 /// <param name="a">A 3d vector</param>
163 /// <param name="b">A 3d vector</param> 163 /// <param name="b">A 3d vector</param>
164 /// <returns>The distance between the two vectors</returns> 164 /// <returns>The distance between the two vectors</returns>
165 public static double GetDistanceTo(Vector3 a, Vector3 b) 165 public static double GetDistanceTo(Vector3 a, Vector3 b)
166 { 166 {
167 float dx = a.X - b.X; 167 float dx = a.X - b.X;
168 float dy = a.Y - b.Y; 168 float dy = a.Y - b.Y;
169 float dz = a.Z - b.Z; 169 float dz = a.Z - b.Z;
170 return Math.Sqrt(dx * dx + dy * dy + dz * dz); 170 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
171 } 171 }
172 172
173 /// <summary> 173 /// <summary>
174 /// Returns true if the distance beween A and B is less than amount. Significantly faster than GetDistanceTo since it eliminates the Sqrt. 174 /// Returns true if the distance beween A and B is less than amount. Significantly faster than GetDistanceTo since it eliminates the Sqrt.
175 /// </summary> 175 /// </summary>
176 /// <param name="a"></param> 176 /// <param name="a"></param>
177 /// <param name="b"></param> 177 /// <param name="b"></param>
178 /// <param name="amount"></param> 178 /// <param name="amount"></param>
179 /// <returns></returns> 179 /// <returns></returns>
180 public static bool DistanceLessThan(Vector3 a, Vector3 b, double amount) 180 public static bool DistanceLessThan(Vector3 a, Vector3 b, double amount)
181 { 181 {
182 float dx = a.X - b.X; 182 float dx = a.X - b.X;
183 float dy = a.Y - b.Y; 183 float dy = a.Y - b.Y;
184 float dz = a.Z - b.Z; 184 float dz = a.Z - b.Z;
185 return (dx*dx + dy*dy + dz*dz) < (amount*amount); 185 return (dx*dx + dy*dy + dz*dz) < (amount*amount);
186 } 186 }
187 187
188 /// <summary> 188 /// <summary>
189 /// Get the magnitude of a 3d vector 189 /// Get the magnitude of a 3d vector
190 /// </summary> 190 /// </summary>
191 /// <param name="a">A 3d vector</param> 191 /// <param name="a">A 3d vector</param>
192 /// <returns>The magnitude of the vector</returns> 192 /// <returns>The magnitude of the vector</returns>
193 public static double GetMagnitude(Vector3 a) 193 public static double GetMagnitude(Vector3 a)
194 { 194 {
195 return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); 195 return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z));
196 } 196 }
197 197
198 /// <summary> 198 /// <summary>
199 /// Get a normalized form of a 3d vector 199 /// Get a normalized form of a 3d vector
200 /// </summary> 200 /// </summary>
201 /// <param name="a">A 3d vector</param> 201 /// <param name="a">A 3d vector</param>
202 /// <returns>A new vector which is normalized form of the vector</returns> 202 /// <returns>A new vector which is normalized form of the vector</returns>
203 /// <remarks>The vector paramater cannot be <0,0,0></remarks> 203 /// <remarks>The vector paramater cannot be <0,0,0></remarks>
204 public static Vector3 GetNormalizedVector(Vector3 a) 204 public static Vector3 GetNormalizedVector(Vector3 a)
205 { 205 {
206 if (IsZeroVector(a)) 206 if (IsZeroVector(a))
207 throw new ArgumentException("Vector paramater cannot be a zero vector."); 207 throw new ArgumentException("Vector paramater cannot be a zero vector.");
208 208
209 float Mag = (float) GetMagnitude(a); 209 float Mag = (float) GetMagnitude(a);
210 return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag); 210 return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag);
211 } 211 }
212 212
213 /// <summary> 213 /// <summary>
214 /// Returns if a vector is a zero vector (has all zero components) 214 /// Returns if a vector is a zero vector (has all zero components)
215 /// </summary> 215 /// </summary>
216 /// <returns></returns> 216 /// <returns></returns>
217 public static bool IsZeroVector(Vector3 v) 217 public static bool IsZeroVector(Vector3 v)
218 { 218 {
219 if (v.X == 0 && v.Y == 0 && v.Z == 0) 219 if (v.X == 0 && v.Y == 0 && v.Z == 0)
220 { 220 {
221 return true; 221 return true;
222 } 222 }
223 223
224 return false; 224 return false;
225 } 225 }
226 226
227 # endregion 227 # endregion
228 228
229 public static Quaternion Axes2Rot(Vector3 fwd, Vector3 left, Vector3 up) 229 public static Quaternion Axes2Rot(Vector3 fwd, Vector3 left, Vector3 up)
230 { 230 {
231 float s; 231 float s;
232 float tr = (float) (fwd.X + left.Y + up.Z + 1.0); 232 float tr = (float) (fwd.X + left.Y + up.Z + 1.0);
233 233
234 if (tr >= 1.0) 234 if (tr >= 1.0)
235 { 235 {
236 s = (float) (0.5 / Math.Sqrt(tr)); 236 s = (float) (0.5 / Math.Sqrt(tr));
237 return new Quaternion( 237 return new Quaternion(
238 (left.Z - up.Y) * s, 238 (left.Z - up.Y) * s,
239 (up.X - fwd.Z) * s, 239 (up.X - fwd.Z) * s,
240 (fwd.Y - left.X) * s, 240 (fwd.Y - left.X) * s,
241 (float) 0.25 / s); 241 (float) 0.25 / s);
242 } 242 }
243 else 243 else
244 { 244 {
245 float max = (left.Y > up.Z) ? left.Y : up.Z; 245 float max = (left.Y > up.Z) ? left.Y : up.Z;
246 246
247 if (max < fwd.X) 247 if (max < fwd.X)
248 { 248 {
249 s = (float) (Math.Sqrt(fwd.X - (left.Y + up.Z) + 1.0)); 249 s = (float) (Math.Sqrt(fwd.X - (left.Y + up.Z) + 1.0));
250 float x = (float) (s * 0.5); 250 float x = (float) (s * 0.5);
251 s = (float) (0.5 / s); 251 s = (float) (0.5 / s);
252 return new Quaternion( 252 return new Quaternion(
253 x, 253 x,
254 (fwd.Y + left.X) * s, 254 (fwd.Y + left.X) * s,
255 (up.X + fwd.Z) * s, 255 (up.X + fwd.Z) * s,
256 (left.Z - up.Y) * s); 256 (left.Z - up.Y) * s);
257 } 257 }
258 else if (max == left.Y) 258 else if (max == left.Y)
259 { 259 {
260 s = (float) (Math.Sqrt(left.Y - (up.Z + fwd.X) + 1.0)); 260 s = (float) (Math.Sqrt(left.Y - (up.Z + fwd.X) + 1.0));
261 float y = (float) (s * 0.5); 261 float y = (float) (s * 0.5);
262 s = (float) (0.5 / s); 262 s = (float) (0.5 / s);
263 return new Quaternion( 263 return new Quaternion(
264 (fwd.Y + left.X) * s, 264 (fwd.Y + left.X) * s,
265 y, 265 y,
266 (left.Z + up.Y) * s, 266 (left.Z + up.Y) * s,
267 (up.X - fwd.Z) * s); 267 (up.X - fwd.Z) * s);
268 } 268 }
269 else 269 else
270 { 270 {
271 s = (float) (Math.Sqrt(up.Z - (fwd.X + left.Y) + 1.0)); 271 s = (float) (Math.Sqrt(up.Z - (fwd.X + left.Y) + 1.0));
272 float z = (float) (s * 0.5); 272 float z = (float) (s * 0.5);
273 s = (float) (0.5 / s); 273 s = (float) (0.5 / s);
274 return new Quaternion( 274 return new Quaternion(
275 (up.X + fwd.Z) * s, 275 (up.X + fwd.Z) * s,
276 (left.Z + up.Y) * s, 276 (left.Z + up.Y) * s,
277 z, 277 z,
278 (fwd.Y - left.X) * s); 278 (fwd.Y - left.X) * s);
279 } 279 }
280 } 280 }
281 } 281 }
282 282
283 public static Random RandomClass 283 public static Random RandomClass
284 { 284 {
285 get { return randomClass; } 285 get { return randomClass; }
286 } 286 }
287 287
288 public static ulong UIntsToLong(uint X, uint Y) 288 public static ulong UIntsToLong(uint X, uint Y)
289 { 289 {
290 return Utils.UIntsToLong(X, Y); 290 return Utils.UIntsToLong(X, Y);
291 } 291 }
292 292
293 public static T Clamp<T>(T x, T min, T max) 293 public static T Clamp<T>(T x, T min, T max)
294 where T : IComparable<T> 294 where T : IComparable<T>
295 { 295 {
296 return x.CompareTo(max) > 0 ? max : 296 return x.CompareTo(max) > 0 ? max :
297 x.CompareTo(min) < 0 ? min : 297 x.CompareTo(min) < 0 ? min :
298 x; 298 x;
299 } 299 }
300 300
301 public static uint GetNextXferID() 301 public static uint GetNextXferID()
302 { 302 {
303 uint id = 0; 303 uint id = 0;
304 lock (XferLock) 304 lock (XferLock)
305 { 305 {
306 id = nextXferID; 306 id = nextXferID;
307 nextXferID++; 307 nextXferID++;
308 } 308 }
309 return id; 309 return id;
310 } 310 }
311 311
312 public static string GetFileName(string file) 312 public static string GetFileName(string file)
313 { 313 {
314 // Return just the filename on UNIX platforms 314 // Return just the filename on UNIX platforms
315 // TODO: this should be customisable with a prefix, but that's something to do later. 315 // TODO: this should be customisable with a prefix, but that's something to do later.
316 if (Environment.OSVersion.Platform == PlatformID.Unix) 316 if (Environment.OSVersion.Platform == PlatformID.Unix)
317 { 317 {
318 return file; 318 return file;
319 } 319 }
320 320
321 // Return %APPDATA%/OpenSim/file for 2K/XP/NT/2K3/VISTA 321 // Return %APPDATA%/OpenSim/file for 2K/XP/NT/2K3/VISTA
322 // TODO: Switch this to System.Enviroment.SpecialFolders.ApplicationData 322 // TODO: Switch this to System.Enviroment.SpecialFolders.ApplicationData
323 if (Environment.OSVersion.Platform == PlatformID.Win32NT) 323 if (Environment.OSVersion.Platform == PlatformID.Win32NT)
324 { 324 {
325 if (!Directory.Exists("%APPDATA%\\OpenSim\\")) 325 if (!Directory.Exists("%APPDATA%\\OpenSim\\"))
326 { 326 {
327 Directory.CreateDirectory("%APPDATA%\\OpenSim"); 327 Directory.CreateDirectory("%APPDATA%\\OpenSim");
328 } 328 }
329 329
330 return "%APPDATA%\\OpenSim\\" + file; 330 return "%APPDATA%\\OpenSim\\" + file;
331 } 331 }
332 332
333 // Catch all - covers older windows versions 333 // Catch all - covers older windows versions
334 // (but those probably wont work anyway) 334 // (but those probably wont work anyway)
335 return file; 335 return file;
336 } 336 }
337 337
338 /// <summary> 338 /// <summary>
339 /// Debug utility function to convert OSD into formatted XML for debugging purposes. 339 /// Debug utility function to convert OSD into formatted XML for debugging purposes.
340 /// </summary> 340 /// </summary>
341 /// <param name="osd"> 341 /// <param name="osd">
342 /// A <see cref="OSD"/> 342 /// A <see cref="OSD"/>
343 /// </param> 343 /// </param>
344 /// <returns> 344 /// <returns>
345 /// A <see cref="System.String"/> 345 /// A <see cref="System.String"/>
346 /// </returns> 346 /// </returns>
347 public static string GetFormattedXml(OSD osd) 347 public static string GetFormattedXml(OSD osd)
348 { 348 {
349 return GetFormattedXml(OSDParser.SerializeLLSDXmlString(osd)); 349 return GetFormattedXml(OSDParser.SerializeLLSDXmlString(osd));
350 } 350 }
351 351
352 /// <summary> 352 /// <summary>
353 /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes. 353 /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes.
354 /// </summary> 354 /// </summary>
355 /// <remarks> 355 /// <remarks>
356 /// Please don't delete me even if I appear currently unused! 356 /// Please don't delete me even if I appear currently unused!
357 /// </remarks> 357 /// </remarks>
358 /// <param name="rawXml"></param> 358 /// <param name="rawXml"></param>
359 /// <returns></returns> 359 /// <returns></returns>
360 public static string GetFormattedXml(string rawXml) 360 public static string GetFormattedXml(string rawXml)
361 { 361 {
362 XmlDocument xd = new XmlDocument(); 362 XmlDocument xd = new XmlDocument();
363 xd.LoadXml(rawXml); 363 xd.LoadXml(rawXml);
364 364
365 StringBuilder sb = new StringBuilder(); 365 StringBuilder sb = new StringBuilder();
366 StringWriter sw = new StringWriter(sb); 366 StringWriter sw = new StringWriter(sb);
367 367
368 XmlTextWriter xtw = new XmlTextWriter(sw); 368 XmlTextWriter xtw = new XmlTextWriter(sw);
369 xtw.Formatting = Formatting.Indented; 369 xtw.Formatting = Formatting.Indented;
370 370
371 try 371 try
372 { 372 {
373 xd.WriteTo(xtw); 373 xd.WriteTo(xtw);
374 } 374 }
375 finally 375 finally
376 { 376 {
377 xtw.Close(); 377 xtw.Close();
378 } 378 }
379 379
380 return sb.ToString(); 380 return sb.ToString();
381 } 381 }
382 382
383 /// <summary> 383 /// <summary>
@@ -392,1118 +392,1118 @@ namespace OpenSim.Framework
392 || platformId == PlatformID.Win32S 392 || platformId == PlatformID.Win32S
393 || platformId == PlatformID.Win32Windows 393 || platformId == PlatformID.Win32Windows
394 || platformId == PlatformID.WinCE); 394 || platformId == PlatformID.WinCE);
395 } 395 }
396 396
397 public static bool LoadArchSpecificWindowsDll(string libraryName) 397 public static bool LoadArchSpecificWindowsDll(string libraryName)
398 { 398 {
399 // We do this so that OpenSimulator on Windows loads the correct native library depending on whether 399 // We do this so that OpenSimulator on Windows loads the correct native library depending on whether
400 // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports 400 // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports
401 // will find it already loaded later on. 401 // will find it already loaded later on.
402 // 402 //
403 // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be 403 // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be
404 // controlled in config files. 404 // controlled in config files.
405 string nativeLibraryPath; 405 string nativeLibraryPath;
406 406
407 if (Util.Is64BitProcess()) 407 if (Util.Is64BitProcess())
408 nativeLibraryPath = "lib64/" + libraryName; 408 nativeLibraryPath = "lib64/" + libraryName;
409 else 409 else
410 nativeLibraryPath = "lib32/" + libraryName; 410 nativeLibraryPath = "lib32/" + libraryName;
411 411
412 m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); 412 m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath);
413 413
414 if (Util.LoadLibrary(nativeLibraryPath) == IntPtr.Zero) 414 if (Util.LoadLibrary(nativeLibraryPath) == IntPtr.Zero)
415 { 415 {
416 m_log.ErrorFormat( 416 m_log.ErrorFormat(
417 "[UTIL]: Couldn't find native Windows library at {0}", nativeLibraryPath); 417 "[UTIL]: Couldn't find native Windows library at {0}", nativeLibraryPath);
418 418
419 return false; 419 return false;
420 } 420 }
421 else 421 else
422 { 422 {
423 return true; 423 return true;
424 } 424 }
425 } 425 }
426 426
427 public static bool IsEnvironmentSupported(ref string reason) 427 public static bool IsEnvironmentSupported(ref string reason)
428 { 428 {
429 // Must have .NET 2.0 (Generics / libsl) 429 // Must have .NET 2.0 (Generics / libsl)
430 if (Environment.Version.Major < 2) 430 if (Environment.Version.Major < 2)
431 { 431 {
432 reason = ".NET 1.0/1.1 lacks components that is used by OpenSim"; 432 reason = ".NET 1.0/1.1 lacks components that is used by OpenSim";
433 return false; 433 return false;
434 } 434 }
435 435
436 // Windows 95/98/ME are unsupported 436 // Windows 95/98/ME are unsupported
437 if (Environment.OSVersion.Platform == PlatformID.Win32Windows && 437 if (Environment.OSVersion.Platform == PlatformID.Win32Windows &&
438 Environment.OSVersion.Platform != PlatformID.Win32NT) 438 Environment.OSVersion.Platform != PlatformID.Win32NT)
439 { 439 {
440 reason = "Windows 95/98/ME will not run OpenSim"; 440 reason = "Windows 95/98/ME will not run OpenSim";
441 return false; 441 return false;
442 } 442 }
443 443
444 // Windows 2000 / Pre-SP2 XP 444 // Windows 2000 / Pre-SP2 XP
445 if (Environment.OSVersion.Version.Major == 5 && 445 if (Environment.OSVersion.Version.Major == 5 &&
446 Environment.OSVersion.Version.Minor == 0) 446 Environment.OSVersion.Version.Minor == 0)
447 { 447 {
448 reason = "Please update to Windows XP Service Pack 2 or Server2003"; 448 reason = "Please update to Windows XP Service Pack 2 or Server2003";
449 return false; 449 return false;
450 } 450 }
451 451
452 return true; 452 return true;
453 } 453 }
454 454
455 public static int UnixTimeSinceEpoch() 455 public static int UnixTimeSinceEpoch()
456 { 456 {
457 return ToUnixTime(DateTime.UtcNow); 457 return ToUnixTime(DateTime.UtcNow);
458 } 458 }
459 459
460 public static int ToUnixTime(DateTime stamp) 460 public static int ToUnixTime(DateTime stamp)
461 { 461 {
462 TimeSpan t = stamp.ToUniversalTime() - unixEpoch; 462 TimeSpan t = stamp.ToUniversalTime() - unixEpoch;
463 return (int) t.TotalSeconds; 463 return (int) t.TotalSeconds;
464 } 464 }
465 465
466 public static DateTime ToDateTime(ulong seconds) 466 public static DateTime ToDateTime(ulong seconds)
467 { 467 {
468 DateTime epoch = unixEpoch; 468 DateTime epoch = unixEpoch;
469 return epoch.AddSeconds(seconds); 469 return epoch.AddSeconds(seconds);
470 } 470 }
471 471
472 public static DateTime ToDateTime(int seconds) 472 public static DateTime ToDateTime(int seconds)
473 { 473 {
474 DateTime epoch = unixEpoch; 474 DateTime epoch = unixEpoch;
475 return epoch.AddSeconds(seconds); 475 return epoch.AddSeconds(seconds);
476 } 476 }
477 477
478 /// <summary> 478 /// <summary>
479 /// Return an md5 hash of the given string 479 /// Return an md5 hash of the given string
480 /// </summary> 480 /// </summary>
481 /// <param name="data"></param> 481 /// <param name="data"></param>
482 /// <returns></returns> 482 /// <returns></returns>
483 public static string Md5Hash(string data) 483 public static string Md5Hash(string data)
484 { 484 {
485 byte[] dataMd5 = ComputeMD5Hash(data); 485 byte[] dataMd5 = ComputeMD5Hash(data);
486 StringBuilder sb = new StringBuilder(); 486 StringBuilder sb = new StringBuilder();
487 for (int i = 0; i < dataMd5.Length; i++) 487 for (int i = 0; i < dataMd5.Length; i++)
488 sb.AppendFormat("{0:x2}", dataMd5[i]); 488 sb.AppendFormat("{0:x2}", dataMd5[i]);
489 return sb.ToString(); 489 return sb.ToString();
490 } 490 }
491 491
492 private static byte[] ComputeMD5Hash(string data) 492 private static byte[] ComputeMD5Hash(string data)
493 { 493 {
494 MD5 md5 = MD5.Create(); 494 MD5 md5 = MD5.Create();
495 return md5.ComputeHash(Encoding.Default.GetBytes(data)); 495 return md5.ComputeHash(Encoding.Default.GetBytes(data));
496 } 496 }
497 497
498 /// <summary> 498 /// <summary>
499 /// Return an SHA1 hash 499 /// Return an SHA1 hash
500 /// </summary> 500 /// </summary>
501 /// <param name="data"></param> 501 /// <param name="data"></param>
502 /// <returns></returns> 502 /// <returns></returns>
503 public static string SHA1Hash(string data) 503 public static string SHA1Hash(string data)
504 { 504 {
505 return SHA1Hash(Encoding.Default.GetBytes(data)); 505 return SHA1Hash(Encoding.Default.GetBytes(data));
506 } 506 }
507 507
508 /// <summary> 508 /// <summary>
509 /// Return an SHA1 hash 509 /// Return an SHA1 hash
510 /// </summary> 510 /// </summary>
511 /// <param name="data"></param> 511 /// <param name="data"></param>
512 /// <returns></returns> 512 /// <returns></returns>
513 public static string SHA1Hash(byte[] data) 513 public static string SHA1Hash(byte[] data)
514 { 514 {
515 byte[] hash = ComputeSHA1Hash(data); 515 byte[] hash = ComputeSHA1Hash(data);
516 return BitConverter.ToString(hash).Replace("-", String.Empty); 516 return BitConverter.ToString(hash).Replace("-", String.Empty);
517 } 517 }
518 518
519 private static byte[] ComputeSHA1Hash(byte[] src) 519 private static byte[] ComputeSHA1Hash(byte[] src)
520 { 520 {
521 SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); 521 SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider();
522 return SHA1.ComputeHash(src); 522 return SHA1.ComputeHash(src);
523 } 523 }
524 524
525 public static int fast_distance2d(int x, int y) 525 public static int fast_distance2d(int x, int y)
526 { 526 {
527 x = Math.Abs(x); 527 x = Math.Abs(x);
528 y = Math.Abs(y); 528 y = Math.Abs(y);
529 529
530 int min = Math.Min(x, y); 530 int min = Math.Min(x, y);
531 531
532 return (x + y - (min >> 1) - (min >> 2) + (min >> 4)); 532 return (x + y - (min >> 1) - (min >> 2) + (min >> 4));
533 } 533 }
534 534
535 /// <summary> 535 /// <summary>
536 /// Are the co-ordinates of the new region visible from the old region? 536 /// Are the co-ordinates of the new region visible from the old region?
537 /// </summary> 537 /// </summary>
538 /// <param name="oldx">Old region x-coord</param> 538 /// <param name="oldx">Old region x-coord</param>
539 /// <param name="newx">New region x-coord</param> 539 /// <param name="newx">New region x-coord</param>
540 /// <param name="oldy">Old region y-coord</param> 540 /// <param name="oldy">Old region y-coord</param>
541 /// <param name="newy">New region y-coord</param> 541 /// <param name="newy">New region y-coord</param>
542 /// <returns></returns> 542 /// <returns></returns>
543 public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy) 543 public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy)
544 { 544 {
545 int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize); 545 int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize);
546 546
547 int startX = (int)oldx - dd; 547 int startX = (int)oldx - dd;
548 int startY = (int)oldy - dd; 548 int startY = (int)oldy - dd;
549 549
550 int endX = (int)oldx + dd; 550 int endX = (int)oldx + dd;
551 int endY = (int)oldy + dd; 551 int endY = (int)oldy + dd;
552 552
553 return (newx < startX || endX < newx || newy < startY || endY < newy); 553 return (newx < startX || endX < newx || newy < startY || endY < newy);
554 } 554 }
555 555
556 public static string FieldToString(byte[] bytes) 556 public static string FieldToString(byte[] bytes)
557 { 557 {
558 return FieldToString(bytes, String.Empty); 558 return FieldToString(bytes, String.Empty);
559 } 559 }
560 560
561 /// <summary> 561 /// <summary>
562 /// Convert a variable length field (byte array) to a string, with a 562 /// Convert a variable length field (byte array) to a string, with a
563 /// field name prepended to each line of the output 563 /// field name prepended to each line of the output
564 /// </summary> 564 /// </summary>
565 /// <remarks>If the byte array has unprintable characters in it, a 565 /// <remarks>If the byte array has unprintable characters in it, a
566 /// hex dump will be put in the string instead</remarks> 566 /// hex dump will be put in the string instead</remarks>
567 /// <param name="bytes">The byte array to convert to a string</param> 567 /// <param name="bytes">The byte array to convert to a string</param>
568 /// <param name="fieldName">A field name to prepend to each line of output</param> 568 /// <param name="fieldName">A field name to prepend to each line of output</param>
569 /// <returns>An ASCII string or a string containing a hex dump, minus 569 /// <returns>An ASCII string or a string containing a hex dump, minus
570 /// the null terminator</returns> 570 /// the null terminator</returns>
571 public static string FieldToString(byte[] bytes, string fieldName) 571 public static string FieldToString(byte[] bytes, string fieldName)
572 { 572 {
573 // Check for a common case 573 // Check for a common case
574 if (bytes.Length == 0) return String.Empty; 574 if (bytes.Length == 0) return String.Empty;
575 575
576 StringBuilder output = new StringBuilder(); 576 StringBuilder output = new StringBuilder();
577 bool printable = true; 577 bool printable = true;
578 578
579 for (int i = 0; i < bytes.Length; ++i) 579 for (int i = 0; i < bytes.Length; ++i)
580 { 580 {
581 // Check if there are any unprintable characters in the array 581 // Check if there are any unprintable characters in the array
582 if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09 582 if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09
583 && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00) 583 && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00)
584 { 584 {
585 printable = false; 585 printable = false;
586 break; 586 break;
587 } 587 }
588 } 588 }
589 589
590 if (printable) 590 if (printable)
591 { 591 {
592 if (fieldName.Length > 0) 592 if (fieldName.Length > 0)
593 { 593 {
594 output.Append(fieldName); 594 output.Append(fieldName);
595 output.Append(": "); 595 output.Append(": ");
596 } 596 }
597 597
598 output.Append(CleanString(Util.UTF8.GetString(bytes, 0, bytes.Length - 1))); 598 output.Append(CleanString(Util.UTF8.GetString(bytes, 0, bytes.Length - 1)));
599 } 599 }
600 else 600 else
601 { 601 {
602 for (int i = 0; i < bytes.Length; i += 16) 602 for (int i = 0; i < bytes.Length; i += 16)
603 { 603 {
604 if (i != 0) 604 if (i != 0)
605 output.Append(Environment.NewLine); 605 output.Append(Environment.NewLine);
606 if (fieldName.Length > 0) 606 if (fieldName.Length > 0)
607 { 607 {
608 output.Append(fieldName); 608 output.Append(fieldName);
609 output.Append(": "); 609 output.Append(": ");
610 } 610 }
611 611
612 for (int j = 0; j < 16; j++) 612 for (int j = 0; j < 16; j++)
613 { 613 {
614 if ((i + j) < bytes.Length) 614 if ((i + j) < bytes.Length)
615 output.Append(String.Format("{0:X2} ", bytes[i + j])); 615 output.Append(String.Format("{0:X2} ", bytes[i + j]));
616 else 616 else
617 output.Append(" "); 617 output.Append(" ");
618 } 618 }
619 619
620 for (int j = 0; j < 16 && (i + j) < bytes.Length; j++) 620 for (int j = 0; j < 16 && (i + j) < bytes.Length; j++)
621 { 621 {
622 if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E) 622 if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E)
623 output.Append((char) bytes[i + j]); 623 output.Append((char) bytes[i + j]);
624 else 624 else
625 output.Append("."); 625 output.Append(".");
626 } 626 }
627 } 627 }
628 } 628 }
629 629
630 return output.ToString(); 630 return output.ToString();
631 } 631 }
632 632
633 /// <summary> 633 /// <summary>
634 /// Converts a URL to a IPAddress 634 /// Converts a URL to a IPAddress
635 /// </summary> 635 /// </summary>
636 /// <param name="url">URL Standard Format</param> 636 /// <param name="url">URL Standard Format</param>
637 /// <returns>A resolved IP Address</returns> 637 /// <returns>A resolved IP Address</returns>
638 public static IPAddress GetHostFromURL(string url) 638 public static IPAddress GetHostFromURL(string url)
639 { 639 {
640 return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]); 640 return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]);
641 } 641 }
642 642
643 /// <summary> 643 /// <summary>
644 /// Returns a IP address from a specified DNS, favouring IPv4 addresses. 644 /// Returns a IP address from a specified DNS, favouring IPv4 addresses.
645 /// </summary> 645 /// </summary>
646 /// <param name="dnsAddress">DNS Hostname</param> 646 /// <param name="dnsAddress">DNS Hostname</param>
647 /// <returns>An IP address, or null</returns> 647 /// <returns>An IP address, or null</returns>
648 public static IPAddress GetHostFromDNS(string dnsAddress) 648 public static IPAddress GetHostFromDNS(string dnsAddress)
649 { 649 {
650 // Is it already a valid IP? No need to look it up. 650 // Is it already a valid IP? No need to look it up.
651 IPAddress ipa; 651 IPAddress ipa;
652 if (IPAddress.TryParse(dnsAddress, out ipa)) 652 if (IPAddress.TryParse(dnsAddress, out ipa))
653 return ipa; 653 return ipa;
654 654
655 IPAddress[] hosts = null; 655 IPAddress[] hosts = null;
656 656
657 // Not an IP, lookup required 657 // Not an IP, lookup required
658 try 658 try
659 { 659 {
660 hosts = Dns.GetHostEntry(dnsAddress).AddressList; 660 hosts = Dns.GetHostEntry(dnsAddress).AddressList;
661 } 661 }
662 catch (Exception e) 662 catch (Exception e)
663 { 663 {
664 m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e); 664 m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e);
665 665
666 // Still going to throw the exception on for now, since this was what was happening in the first place 666 // Still going to throw the exception on for now, since this was what was happening in the first place
667 throw e; 667 throw e;
668 } 668 }
669 669
670 foreach (IPAddress host in hosts) 670 foreach (IPAddress host in hosts)
671 { 671 {
672 if (host.AddressFamily == AddressFamily.InterNetwork) 672 if (host.AddressFamily == AddressFamily.InterNetwork)
673 { 673 {
674 return host; 674 return host;
675 } 675 }
676 } 676 }
677 677
678 if (hosts.Length > 0) 678 if (hosts.Length > 0)
679 return hosts[0]; 679 return hosts[0];
680 680
681 return null; 681 return null;
682 } 682 }
683 683
684 public static Uri GetURI(string protocol, string hostname, int port, string path) 684 public static Uri GetURI(string protocol, string hostname, int port, string path)
685 { 685 {
686 return new UriBuilder(protocol, hostname, port, path).Uri; 686 return new UriBuilder(protocol, hostname, port, path).Uri;
687 } 687 }
688 688
689 /// <summary> 689 /// <summary>
690 /// Gets a list of all local system IP addresses 690 /// Gets a list of all local system IP addresses
691 /// </summary> 691 /// </summary>
692 /// <returns></returns> 692 /// <returns></returns>
693 public static IPAddress[] GetLocalHosts() 693 public static IPAddress[] GetLocalHosts()
694 { 694 {
695 return Dns.GetHostAddresses(Dns.GetHostName()); 695 return Dns.GetHostAddresses(Dns.GetHostName());
696 } 696 }
697 697
698 public static IPAddress GetLocalHost() 698 public static IPAddress GetLocalHost()
699 { 699 {
700 IPAddress[] iplist = GetLocalHosts(); 700 IPAddress[] iplist = GetLocalHosts();
701 701
702 if (iplist.Length == 0) // No accessible external interfaces 702 if (iplist.Length == 0) // No accessible external interfaces
703 { 703 {
704 IPAddress[] loopback = Dns.GetHostAddresses("localhost"); 704 IPAddress[] loopback = Dns.GetHostAddresses("localhost");
705 IPAddress localhost = loopback[0]; 705 IPAddress localhost = loopback[0];
706 706
707 return localhost; 707 return localhost;
708 } 708 }
709 709
710 foreach (IPAddress host in iplist) 710 foreach (IPAddress host in iplist)
711 { 711 {
712 if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork) 712 if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork)
713 { 713 {
714 return host; 714 return host;
715 } 715 }
716 } 716 }
717 717
718 if (iplist.Length > 0) 718 if (iplist.Length > 0)
719 { 719 {
720 foreach (IPAddress host in iplist) 720 foreach (IPAddress host in iplist)
721 { 721 {
722 if (host.AddressFamily == AddressFamily.InterNetwork) 722 if (host.AddressFamily == AddressFamily.InterNetwork)
723 return host; 723 return host;
724 } 724 }
725 // Well all else failed... 725 // Well all else failed...
726 return iplist[0]; 726 return iplist[0];
727 } 727 }
728 728
729 return null; 729 return null;
730 } 730 }
731 731
732 /// <summary> 732 /// <summary>
733 /// Removes all invalid path chars (OS dependent) 733 /// Removes all invalid path chars (OS dependent)
734 /// </summary> 734 /// </summary>
735 /// <param name="path">path</param> 735 /// <param name="path">path</param>
736 /// <returns>safe path</returns> 736 /// <returns>safe path</returns>
737 public static string safePath(string path) 737 public static string safePath(string path)
738 { 738 {
739 return Regex.Replace(path, regexInvalidPathChars, String.Empty); 739 return Regex.Replace(path, regexInvalidPathChars, String.Empty);
740 } 740 }
741 741
742 /// <summary> 742 /// <summary>
743 /// Removes all invalid filename chars (OS dependent) 743 /// Removes all invalid filename chars (OS dependent)
744 /// </summary> 744 /// </summary>
745 /// <param name="path">filename</param> 745 /// <param name="path">filename</param>
746 /// <returns>safe filename</returns> 746 /// <returns>safe filename</returns>
747 public static string safeFileName(string filename) 747 public static string safeFileName(string filename)
748 { 748 {
749 return Regex.Replace(filename, regexInvalidFileChars, String.Empty); 749 return Regex.Replace(filename, regexInvalidFileChars, String.Empty);
750 ; 750 ;
751 } 751 }
752 752
753 // 753 //
754 // directory locations 754 // directory locations
755 // 755 //
756 756
757 public static string homeDir() 757 public static string homeDir()
758 { 758 {
759 string temp; 759 string temp;
760 // string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); 760 // string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
761 // temp = Path.Combine(personal,".OpenSim"); 761 // temp = Path.Combine(personal,".OpenSim");
762 temp = "."; 762 temp = ".";
763 return temp; 763 return temp;
764 } 764 }
765 765
766 public static string assetsDir() 766 public static string assetsDir()
767 { 767 {
768 return Path.Combine(configDir(), "assets"); 768 return Path.Combine(configDir(), "assets");
769 } 769 }
770 770
771 public static string inventoryDir() 771 public static string inventoryDir()
772 { 772 {
773 return Path.Combine(configDir(), "inventory"); 773 return Path.Combine(configDir(), "inventory");
774 } 774 }
775 775
776 public static string configDir() 776 public static string configDir()
777 { 777 {
778 return "."; 778 return ".";
779 } 779 }
780 780
781 public static string dataDir() 781 public static string dataDir()
782 { 782 {
783 return "."; 783 return ".";
784 } 784 }
785 785
786 public static string logDir() 786 public static string logDir()
787 { 787 {
788 return "."; 788 return ".";
789 } 789 }
790 790
791 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html 791 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html
792 public static string GetUniqueFilename(string FileName) 792 public static string GetUniqueFilename(string FileName)
793 { 793 {
794 int count = 0; 794 int count = 0;
795 string Name; 795 string Name;
796 796
797 if (File.Exists(FileName)) 797 if (File.Exists(FileName))
798 { 798 {
799 FileInfo f = new FileInfo(FileName); 799 FileInfo f = new FileInfo(FileName);
800 800
801 if (!String.IsNullOrEmpty(f.Extension)) 801 if (!String.IsNullOrEmpty(f.Extension))
802 { 802 {
803 Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.')); 803 Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.'));
804 } 804 }
805 else 805 else
806 { 806 {
807 Name = f.FullName; 807 Name = f.FullName;
808 } 808 }
809 809
810 while (File.Exists(FileName)) 810 while (File.Exists(FileName))
811 { 811 {
812 count++; 812 count++;
813 FileName = Name + count + f.Extension; 813 FileName = Name + count + f.Extension;
814 } 814 }
815 } 815 }
816 return FileName; 816 return FileName;
817 } 817 }
818 818
819 // Nini (config) related Methods 819 // Nini (config) related Methods
820 public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) 820 public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName)
821 { 821 {
822 if (!File.Exists(fileName)) 822 if (!File.Exists(fileName))
823 { 823 {
824 //create new file 824 //create new file
825 } 825 }
826 XmlConfigSource config = new XmlConfigSource(fileName); 826 XmlConfigSource config = new XmlConfigSource(fileName);
827 AddDataRowToConfig(config, row); 827 AddDataRowToConfig(config, row);
828 config.Save(); 828 config.Save();
829 829
830 return config; 830 return config;
831 } 831 }
832 832
833 public static void AddDataRowToConfig(IConfigSource config, DataRow row) 833 public static void AddDataRowToConfig(IConfigSource config, DataRow row)
834 { 834 {
835 config.Configs.Add((string) row[0]); 835 config.Configs.Add((string) row[0]);
836 for (int i = 0; i < row.Table.Columns.Count; i++) 836 for (int i = 0; i < row.Table.Columns.Count; i++)
837 { 837 {
838 config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); 838 config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]);
839 } 839 }
840 } 840 }
841 841
842 public static float Clip(float x, float min, float max) 842 public static float Clip(float x, float min, float max)
843 { 843 {
844 return Math.Min(Math.Max(x, min), max); 844 return Math.Min(Math.Max(x, min), max);
845 } 845 }
846 846
847 public static int Clip(int x, int min, int max) 847 public static int Clip(int x, int min, int max)
848 { 848 {
849 return Math.Min(Math.Max(x, min), max); 849 return Math.Min(Math.Max(x, min), max);
850 } 850 }
851 851
852 /// <summary> 852 /// <summary>
853 /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens. 853 /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens.
854 /// </summary> 854 /// </summary>
855 /// <param name="UUID"></param> 855 /// <param name="UUID"></param>
856 /// <returns></returns> 856 /// <returns></returns>
857 public static String ToRawUuidString(UUID UUID) 857 public static String ToRawUuidString(UUID UUID)
858 { 858 {
859 return UUID.Guid.ToString("n"); 859 return UUID.Guid.ToString("n");
860 } 860 }
861 861
862 public static string CleanString(string input) 862 public static string CleanString(string input)
863 { 863 {
864 if (input.Length == 0) 864 if (input.Length == 0)
865 return input; 865 return input;
866 866
867 int clip = input.Length; 867 int clip = input.Length;
868 868
869 // Test for ++ string terminator 869 // Test for ++ string terminator
870 int pos = input.IndexOf("\0"); 870 int pos = input.IndexOf("\0");
871 if (pos != -1 && pos < clip) 871 if (pos != -1 && pos < clip)
872 clip = pos; 872 clip = pos;
873 873
874 // Test for CR 874 // Test for CR
875 pos = input.IndexOf("\r"); 875 pos = input.IndexOf("\r");
876 if (pos != -1 && pos < clip) 876 if (pos != -1 && pos < clip)
877 clip = pos; 877 clip = pos;
878 878
879 // Test for LF 879 // Test for LF
880 pos = input.IndexOf("\n"); 880 pos = input.IndexOf("\n");
881 if (pos != -1 && pos < clip) 881 if (pos != -1 && pos < clip)
882 clip = pos; 882 clip = pos;
883 883
884 // Truncate string before first end-of-line character found 884 // Truncate string before first end-of-line character found
885 return input.Substring(0, clip); 885 return input.Substring(0, clip);
886 } 886 }
887 887
888 /// <summary> 888 /// <summary>
889 /// returns the contents of /etc/issue on Unix Systems 889 /// returns the contents of /etc/issue on Unix Systems
890 /// Use this for where it's absolutely necessary to implement platform specific stuff 890 /// Use this for where it's absolutely necessary to implement platform specific stuff
891 /// </summary> 891 /// </summary>
892 /// <returns></returns> 892 /// <returns></returns>
893 public static string ReadEtcIssue() 893 public static string ReadEtcIssue()
894 { 894 {
895 try 895 try
896 { 896 {
897 StreamReader sr = new StreamReader("/etc/issue.net"); 897 StreamReader sr = new StreamReader("/etc/issue.net");
898 string issue = sr.ReadToEnd(); 898 string issue = sr.ReadToEnd();
899 sr.Close(); 899 sr.Close();
900 return issue; 900 return issue;
901 } 901 }
902 catch (Exception) 902 catch (Exception)
903 { 903 {
904 return ""; 904 return "";
905 } 905 }
906 } 906 }
907 907
908 public static void SerializeToFile(string filename, Object obj) 908 public static void SerializeToFile(string filename, Object obj)
909 { 909 {
910 IFormatter formatter = new BinaryFormatter(); 910 IFormatter formatter = new BinaryFormatter();
911 Stream stream = null; 911 Stream stream = null;
912 912
913 try 913 try
914 { 914 {
915 stream = new FileStream( 915 stream = new FileStream(
916 filename, FileMode.Create, 916 filename, FileMode.Create,
917 FileAccess.Write, FileShare.None); 917 FileAccess.Write, FileShare.None);
918 918
919 formatter.Serialize(stream, obj); 919 formatter.Serialize(stream, obj);
920 } 920 }
921 catch (Exception e) 921 catch (Exception e)
922 { 922 {
923 m_log.Error(e.ToString()); 923 m_log.Error(e.ToString());
924 } 924 }
925 finally 925 finally
926 { 926 {
927 if (stream != null) 927 if (stream != null)
928 { 928 {
929 stream.Close(); 929 stream.Close();
930 } 930 }
931 } 931 }
932 } 932 }
933 933
934 public static Object DeserializeFromFile(string filename) 934 public static Object DeserializeFromFile(string filename)
935 { 935 {
936 IFormatter formatter = new BinaryFormatter(); 936 IFormatter formatter = new BinaryFormatter();
937 Stream stream = null; 937 Stream stream = null;
938 Object ret = null; 938 Object ret = null;
939 939
940 try 940 try
941 { 941 {
942 stream = new FileStream( 942 stream = new FileStream(
943 filename, FileMode.Open, 943 filename, FileMode.Open,
944 FileAccess.Read, FileShare.None); 944 FileAccess.Read, FileShare.None);
945 945
946 ret = formatter.Deserialize(stream); 946 ret = formatter.Deserialize(stream);
947 } 947 }
948 catch (Exception e) 948 catch (Exception e)
949 { 949 {
950 m_log.Error(e.ToString()); 950 m_log.Error(e.ToString());
951 } 951 }
952 finally 952 finally
953 { 953 {
954 if (stream != null) 954 if (stream != null)
955 { 955 {
956 stream.Close(); 956 stream.Close();
957 } 957 }
958 } 958 }
959 959
960 return ret; 960 return ret;
961 } 961 }
962 962
963 public static string Compress(string text) 963 public static string Compress(string text)
964 { 964 {
965 byte[] buffer = Util.UTF8.GetBytes(text); 965 byte[] buffer = Util.UTF8.GetBytes(text);
966 MemoryStream memory = new MemoryStream(); 966 MemoryStream memory = new MemoryStream();
967 using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) 967 using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true))
968 { 968 {
969 compressor.Write(buffer, 0, buffer.Length); 969 compressor.Write(buffer, 0, buffer.Length);
970 } 970 }
971 971
972 memory.Position = 0; 972 memory.Position = 0;
973 973
974 byte[] compressed = new byte[memory.Length]; 974 byte[] compressed = new byte[memory.Length];
975 memory.Read(compressed, 0, compressed.Length); 975 memory.Read(compressed, 0, compressed.Length);
976 976
977 byte[] compressedBuffer = new byte[compressed.Length + 4]; 977 byte[] compressedBuffer = new byte[compressed.Length + 4];
978 Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); 978 Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length);
979 Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); 979 Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4);
980 return Convert.ToBase64String(compressedBuffer); 980 return Convert.ToBase64String(compressedBuffer);
981 } 981 }
982 982
983 public static string Decompress(string compressedText) 983 public static string Decompress(string compressedText)
984 { 984 {
985 byte[] compressedBuffer = Convert.FromBase64String(compressedText); 985 byte[] compressedBuffer = Convert.FromBase64String(compressedText);
986 using (MemoryStream memory = new MemoryStream()) 986 using (MemoryStream memory = new MemoryStream())
987 { 987 {
988 int msgLength = BitConverter.ToInt32(compressedBuffer, 0); 988 int msgLength = BitConverter.ToInt32(compressedBuffer, 0);
989 memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4); 989 memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4);
990 990
991 byte[] buffer = new byte[msgLength]; 991 byte[] buffer = new byte[msgLength];
992 992
993 memory.Position = 0; 993 memory.Position = 0;
994 using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress)) 994 using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress))
995 { 995 {
996 decompressor.Read(buffer, 0, buffer.Length); 996 decompressor.Read(buffer, 0, buffer.Length);
997 } 997 }
998 998
999 return Util.UTF8.GetString(buffer); 999 return Util.UTF8.GetString(buffer);
1000 } 1000 }
1001 } 1001 }
1002 1002
1003 public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) 1003 public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args)
1004 { 1004 {
1005 return SendXmlRpcCommand(url, methodName, args); 1005 return SendXmlRpcCommand(url, methodName, args);
1006 } 1006 }
1007 1007
1008 public static XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args) 1008 public static XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args)
1009 { 1009 {
1010 XmlRpcRequest client = new XmlRpcRequest(methodName, args); 1010 XmlRpcRequest client = new XmlRpcRequest(methodName, args);
1011 return client.Send(url, 6000); 1011 return client.Send(url, 6000);
1012 } 1012 }
1013 1013
1014 /// <summary> 1014 /// <summary>
1015 /// Returns an error message that the user could not be found in the database 1015 /// Returns an error message that the user could not be found in the database
1016 /// </summary> 1016 /// </summary>
1017 /// <returns>XML string consisting of a error element containing individual error(s)</returns> 1017 /// <returns>XML string consisting of a error element containing individual error(s)</returns>
1018 public static XmlRpcResponse CreateUnknownUserErrorResponse() 1018 public static XmlRpcResponse CreateUnknownUserErrorResponse()
1019 { 1019 {
1020 XmlRpcResponse response = new XmlRpcResponse(); 1020 XmlRpcResponse response = new XmlRpcResponse();
1021 Hashtable responseData = new Hashtable(); 1021 Hashtable responseData = new Hashtable();
1022 responseData["error_type"] = "unknown_user"; 1022 responseData["error_type"] = "unknown_user";
1023 responseData["error_desc"] = "The user requested is not in the database"; 1023 responseData["error_desc"] = "The user requested is not in the database";
1024 1024
1025 response.Value = responseData; 1025 response.Value = responseData;
1026 return response; 1026 return response;
1027 } 1027 }
1028 1028
1029 /// <summary> 1029 /// <summary>
1030 /// Converts a byte array in big endian order into an ulong. 1030 /// Converts a byte array in big endian order into an ulong.
1031 /// </summary> 1031 /// </summary>
1032 /// <param name="bytes"> 1032 /// <param name="bytes">
1033 /// The array of bytes 1033 /// The array of bytes
1034 /// </param> 1034 /// </param>
1035 /// <returns> 1035 /// <returns>
1036 /// The extracted ulong 1036 /// The extracted ulong
1037 /// </returns> 1037 /// </returns>
1038 public static ulong BytesToUInt64Big(byte[] bytes) 1038 public static ulong BytesToUInt64Big(byte[] bytes)
1039 { 1039 {
1040 if (bytes.Length < 8) return 0; 1040 if (bytes.Length < 8) return 0;
1041 return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) | 1041 return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) |
1042 ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7]; 1042 ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7];
1043 } 1043 }
1044 1044
1045 // used for RemoteParcelRequest (for "About Landmark") 1045 // used for RemoteParcelRequest (for "About Landmark")
1046 public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) 1046 public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y)
1047 { 1047 {
1048 byte[] bytes = 1048 byte[] bytes =
1049 { 1049 {
1050 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), 1050 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1051 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), 1051 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56),
1052 (byte)x, (byte)(x >> 8), 0, 0, 1052 (byte)x, (byte)(x >> 8), 0, 0,
1053 (byte)y, (byte)(y >> 8), 0, 0 }; 1053 (byte)y, (byte)(y >> 8), 0, 0 };
1054 return new UUID(bytes, 0); 1054 return new UUID(bytes, 0);
1055 } 1055 }
1056 1056
1057 public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y, uint z) 1057 public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y, uint z)
1058 { 1058 {
1059 byte[] bytes = 1059 byte[] bytes =
1060 { 1060 {
1061 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), 1061 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1062 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), 1062 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56),
1063 (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), 1063 (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8),
1064 (byte)y, (byte)(y >> 8), 0, 0 }; 1064 (byte)y, (byte)(y >> 8), 0, 0 };
1065 return new UUID(bytes, 0); 1065 return new UUID(bytes, 0);
1066 } 1066 }
1067 1067
1068 public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) 1068 public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y)
1069 { 1069 {
1070 byte[] bytes = parcelID.GetBytes(); 1070 byte[] bytes = parcelID.GetBytes();
1071 regionHandle = Utils.BytesToUInt64(bytes); 1071 regionHandle = Utils.BytesToUInt64(bytes);
1072 x = Utils.BytesToUInt(bytes, 8) & 0xffff; 1072 x = Utils.BytesToUInt(bytes, 8) & 0xffff;
1073 y = Utils.BytesToUInt(bytes, 12) & 0xffff; 1073 y = Utils.BytesToUInt(bytes, 12) & 0xffff;
1074 } 1074 }
1075 1075
1076 public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) 1076 public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z)
1077 { 1077 {
1078 byte[] bytes = parcelID.GetBytes(); 1078 byte[] bytes = parcelID.GetBytes();
1079 regionHandle = Utils.BytesToUInt64(bytes); 1079 regionHandle = Utils.BytesToUInt64(bytes);
1080 x = Utils.BytesToUInt(bytes, 8) & 0xffff; 1080 x = Utils.BytesToUInt(bytes, 8) & 0xffff;
1081 z = (Utils.BytesToUInt(bytes, 8) & 0xffff0000) >> 16; 1081 z = (Utils.BytesToUInt(bytes, 8) & 0xffff0000) >> 16;
1082 y = Utils.BytesToUInt(bytes, 12) & 0xffff; 1082 y = Utils.BytesToUInt(bytes, 12) & 0xffff;
1083 } 1083 }
1084 1084
1085 public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) 1085 public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y)
1086 { 1086 {
1087 ulong regionHandle; 1087 ulong regionHandle;
1088 uint rx, ry; 1088 uint rx, ry;
1089 1089
1090 ParseFakeParcelID(parcelID, out regionHandle, out x, out y); 1090 ParseFakeParcelID(parcelID, out regionHandle, out x, out y);
1091 Utils.LongToUInts(regionHandle, out rx, out ry); 1091 Utils.LongToUInts(regionHandle, out rx, out ry);
1092 1092
1093 x += rx; 1093 x += rx;
1094 y += ry; 1094 y += ry;
1095 } 1095 }
1096 1096
1097 /// <summary> 1097 /// <summary>
1098 /// Get operating system information if available. Returns only the first 45 characters of information 1098 /// Get operating system information if available. Returns only the first 45 characters of information
1099 /// </summary> 1099 /// </summary>
1100 /// <returns> 1100 /// <returns>
1101 /// Operating system information. Returns an empty string if none was available. 1101 /// Operating system information. Returns an empty string if none was available.
1102 /// </returns> 1102 /// </returns>
1103 public static string GetOperatingSystemInformation() 1103 public static string GetOperatingSystemInformation()
1104 { 1104 {
1105 string os = String.Empty; 1105 string os = String.Empty;
1106 1106
1107 if (Environment.OSVersion.Platform != PlatformID.Unix) 1107 if (Environment.OSVersion.Platform != PlatformID.Unix)
1108 { 1108 {
1109 os = Environment.OSVersion.ToString(); 1109 os = Environment.OSVersion.ToString();
1110 } 1110 }
1111 else 1111 else
1112 { 1112 {
1113 os = ReadEtcIssue(); 1113 os = ReadEtcIssue();
1114 } 1114 }
1115 1115
1116 if (os.Length > 45) 1116 if (os.Length > 45)
1117 { 1117 {
1118 os = os.Substring(0, 45); 1118 os = os.Substring(0, 45);
1119 } 1119 }
1120 1120
1121 return os; 1121 return os;
1122 } 1122 }
1123 1123
1124 public static string GetRuntimeInformation() 1124 public static string GetRuntimeInformation()
1125 { 1125 {
1126 string ru = String.Empty; 1126 string ru = String.Empty;
1127 1127
1128 if (Environment.OSVersion.Platform == PlatformID.Unix) 1128 if (Environment.OSVersion.Platform == PlatformID.Unix)
1129 ru = "Unix/Mono"; 1129 ru = "Unix/Mono";
1130 else 1130 else
1131 if (Environment.OSVersion.Platform == PlatformID.MacOSX) 1131 if (Environment.OSVersion.Platform == PlatformID.MacOSX)
1132 ru = "OSX/Mono"; 1132 ru = "OSX/Mono";
1133 else 1133 else
1134 { 1134 {
1135 if (Type.GetType("Mono.Runtime") != null) 1135 if (Type.GetType("Mono.Runtime") != null)
1136 ru = "Win/Mono"; 1136 ru = "Win/Mono";
1137 else 1137 else
1138 ru = "Win/.NET"; 1138 ru = "Win/.NET";
1139 } 1139 }
1140 1140
1141 return ru; 1141 return ru;
1142 } 1142 }
1143 1143
1144 /// <summary> 1144 /// <summary>
1145 /// Is the given string a UUID? 1145 /// Is the given string a UUID?
1146 /// </summary> 1146 /// </summary>
1147 /// <param name="s"></param> 1147 /// <param name="s"></param>
1148 /// <returns></returns> 1148 /// <returns></returns>
1149 public static bool isUUID(string s) 1149 public static bool isUUID(string s)
1150 { 1150 {
1151 return UUIDPattern.IsMatch(s); 1151 return UUIDPattern.IsMatch(s);
1152 } 1152 }
1153 1153
1154 public static string GetDisplayConnectionString(string connectionString) 1154 public static string GetDisplayConnectionString(string connectionString)
1155 { 1155 {
1156 int passPosition = 0; 1156 int passPosition = 0;
1157 int passEndPosition = 0; 1157 int passEndPosition = 0;
1158 string displayConnectionString = null; 1158 string displayConnectionString = null;
1159 1159
1160 // hide the password in the connection string 1160 // hide the password in the connection string
1161 passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); 1161 passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase);
1162 passPosition = connectionString.IndexOf("=", passPosition); 1162 passPosition = connectionString.IndexOf("=", passPosition);
1163 if (passPosition < connectionString.Length) 1163 if (passPosition < connectionString.Length)
1164 passPosition += 1; 1164 passPosition += 1;
1165 passEndPosition = connectionString.IndexOf(";", passPosition); 1165 passEndPosition = connectionString.IndexOf(";", passPosition);
1166 1166
1167 displayConnectionString = connectionString.Substring(0, passPosition); 1167 displayConnectionString = connectionString.Substring(0, passPosition);
1168 displayConnectionString += "***"; 1168 displayConnectionString += "***";
1169 displayConnectionString += connectionString.Substring(passEndPosition, connectionString.Length - passEndPosition); 1169 displayConnectionString += connectionString.Substring(passEndPosition, connectionString.Length - passEndPosition);
1170 1170
1171 return displayConnectionString; 1171 return displayConnectionString;
1172 } 1172 }
1173 1173
1174 public static T ReadSettingsFromIniFile<T>(IConfig config, T settingsClass) 1174 public static T ReadSettingsFromIniFile<T>(IConfig config, T settingsClass)
1175 { 1175 {
1176 Type settingsType = settingsClass.GetType(); 1176 Type settingsType = settingsClass.GetType();
1177 1177
1178 FieldInfo[] fieldInfos = settingsType.GetFields(); 1178 FieldInfo[] fieldInfos = settingsType.GetFields();
1179 foreach (FieldInfo fieldInfo in fieldInfos) 1179 foreach (FieldInfo fieldInfo in fieldInfos)
1180 { 1180 {
1181 if (!fieldInfo.IsStatic) 1181 if (!fieldInfo.IsStatic)
1182 { 1182 {
1183 if (fieldInfo.FieldType == typeof(System.String)) 1183 if (fieldInfo.FieldType == typeof(System.String))
1184 { 1184 {
1185 fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); 1185 fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass)));
1186 } 1186 }
1187 else if (fieldInfo.FieldType == typeof(System.Boolean)) 1187 else if (fieldInfo.FieldType == typeof(System.Boolean))
1188 { 1188 {
1189 fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); 1189 fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass)));
1190 } 1190 }
1191 else if (fieldInfo.FieldType == typeof(System.Int32)) 1191 else if (fieldInfo.FieldType == typeof(System.Int32))
1192 { 1192 {
1193 fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); 1193 fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass)));
1194 } 1194 }
1195 else if (fieldInfo.FieldType == typeof(System.Single)) 1195 else if (fieldInfo.FieldType == typeof(System.Single))
1196 { 1196 {
1197 fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); 1197 fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass)));
1198 } 1198 }
1199 else if (fieldInfo.FieldType == typeof(System.UInt32)) 1199 else if (fieldInfo.FieldType == typeof(System.UInt32))
1200 { 1200 {
1201 fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); 1201 fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString())));
1202 } 1202 }
1203 } 1203 }
1204 } 1204 }
1205 1205
1206 PropertyInfo[] propertyInfos = settingsType.GetProperties(); 1206 PropertyInfo[] propertyInfos = settingsType.GetProperties();
1207 foreach (PropertyInfo propInfo in propertyInfos) 1207 foreach (PropertyInfo propInfo in propertyInfos)
1208 { 1208 {
1209 if ((propInfo.CanRead) && (propInfo.CanWrite)) 1209 if ((propInfo.CanRead) && (propInfo.CanWrite))
1210 { 1210 {
1211 if (propInfo.PropertyType == typeof(System.String)) 1211 if (propInfo.PropertyType == typeof(System.String))
1212 { 1212 {
1213 propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); 1213 propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null);
1214 } 1214 }
1215 else if (propInfo.PropertyType == typeof(System.Boolean)) 1215 else if (propInfo.PropertyType == typeof(System.Boolean))
1216 { 1216 {
1217 propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); 1217 propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null);
1218 } 1218 }
1219 else if (propInfo.PropertyType == typeof(System.Int32)) 1219 else if (propInfo.PropertyType == typeof(System.Int32))
1220 { 1220 {
1221 propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); 1221 propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null);
1222 } 1222 }
1223 else if (propInfo.PropertyType == typeof(System.Single)) 1223 else if (propInfo.PropertyType == typeof(System.Single))
1224 { 1224 {
1225 propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); 1225 propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null);
1226 } 1226 }
1227 if (propInfo.PropertyType == typeof(System.UInt32)) 1227 if (propInfo.PropertyType == typeof(System.UInt32))
1228 { 1228 {
1229 propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); 1229 propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null);
1230 } 1230 }
1231 } 1231 }
1232 } 1232 }
1233 1233
1234 return settingsClass; 1234 return settingsClass;
1235 } 1235 }
1236 1236
1237 public static string Base64ToString(string str) 1237 public static string Base64ToString(string str)
1238 { 1238 {
1239 UTF8Encoding encoder = new UTF8Encoding(); 1239 UTF8Encoding encoder = new UTF8Encoding();
1240 Decoder utf8Decode = encoder.GetDecoder(); 1240 Decoder utf8Decode = encoder.GetDecoder();
1241 1241
1242 byte[] todecode_byte = Convert.FromBase64String(str); 1242 byte[] todecode_byte = Convert.FromBase64String(str);
1243 int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); 1243 int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
1244 char[] decoded_char = new char[charCount]; 1244 char[] decoded_char = new char[charCount];
1245 utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); 1245 utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
1246 string result = new String(decoded_char); 1246 string result = new String(decoded_char);
1247 return result; 1247 return result;
1248 } 1248 }
1249 1249
1250 public static Guid GetHashGuid(string data, string salt) 1250 public static Guid GetHashGuid(string data, string salt)
1251 { 1251 {
1252 byte[] hash = ComputeMD5Hash(data + salt); 1252 byte[] hash = ComputeMD5Hash(data + salt);
1253 1253
1254 //string s = BitConverter.ToString(hash); 1254 //string s = BitConverter.ToString(hash);
1255 1255
1256 Guid guid = new Guid(hash); 1256 Guid guid = new Guid(hash);
1257 1257
1258 return guid; 1258 return guid;
1259 } 1259 }
1260 1260
1261 public static byte ConvertMaturityToAccessLevel(uint maturity) 1261 public static byte ConvertMaturityToAccessLevel(uint maturity)
1262 { 1262 {
1263 byte retVal = 0; 1263 byte retVal = 0;
1264 switch (maturity) 1264 switch (maturity)
1265 { 1265 {
1266 case 0: //PG 1266 case 0: //PG
1267 retVal = 13; 1267 retVal = 13;
1268 break; 1268 break;
1269 case 1: //Mature 1269 case 1: //Mature
1270 retVal = 21; 1270 retVal = 21;
1271 break; 1271 break;
1272 case 2: // Adult 1272 case 2: // Adult
1273 retVal = 42; 1273 retVal = 42;
1274 break; 1274 break;
1275 } 1275 }
1276 1276
1277 return retVal; 1277 return retVal;
1278 1278
1279 } 1279 }
1280 1280
1281 public static uint ConvertAccessLevelToMaturity(byte maturity) 1281 public static uint ConvertAccessLevelToMaturity(byte maturity)
1282 { 1282 {
1283 if (maturity <= 13) 1283 if (maturity <= 13)
1284 return 0; 1284 return 0;
1285 else if (maturity <= 21) 1285 else if (maturity <= 21)
1286 return 1; 1286 return 1;
1287 else 1287 else
1288 return 2; 1288 return 2;
1289 } 1289 }
1290 1290
1291 /// <summary> 1291 /// <summary>
1292 /// Produces an OSDMap from its string representation on a stream 1292 /// Produces an OSDMap from its string representation on a stream
1293 /// </summary> 1293 /// </summary>
1294 /// <param name="data">The stream</param> 1294 /// <param name="data">The stream</param>
1295 /// <param name="length">The size of the data on the stream</param> 1295 /// <param name="length">The size of the data on the stream</param>
1296 /// <returns>The OSDMap or an exception</returns> 1296 /// <returns>The OSDMap or an exception</returns>
1297 public static OSDMap GetOSDMap(Stream stream, int length) 1297 public static OSDMap GetOSDMap(Stream stream, int length)
1298 { 1298 {
1299 byte[] data = new byte[length]; 1299 byte[] data = new byte[length];
1300 stream.Read(data, 0, length); 1300 stream.Read(data, 0, length);
1301 string strdata = Util.UTF8.GetString(data); 1301 string strdata = Util.UTF8.GetString(data);
1302 OSDMap args = null; 1302 OSDMap args = null;
1303 OSD buffer; 1303 OSD buffer;
1304 buffer = OSDParser.DeserializeJson(strdata); 1304 buffer = OSDParser.DeserializeJson(strdata);
1305 if (buffer.Type == OSDType.Map) 1305 if (buffer.Type == OSDType.Map)
1306 { 1306 {
1307 args = (OSDMap)buffer; 1307 args = (OSDMap)buffer;
1308 return args; 1308 return args;
1309 } 1309 }
1310 return null; 1310 return null;
1311 } 1311 }
1312 1312
1313 public static OSDMap GetOSDMap(string data) 1313 public static OSDMap GetOSDMap(string data)
1314 { 1314 {
1315 OSDMap args = null; 1315 OSDMap args = null;
1316 try 1316 try
1317 { 1317 {
1318 OSD buffer; 1318 OSD buffer;
1319 // We should pay attention to the content-type, but let's assume we know it's Json 1319 // We should pay attention to the content-type, but let's assume we know it's Json
1320 buffer = OSDParser.DeserializeJson(data); 1320 buffer = OSDParser.DeserializeJson(data);
1321 if (buffer.Type == OSDType.Map) 1321 if (buffer.Type == OSDType.Map)
1322 { 1322 {
1323 args = (OSDMap)buffer; 1323 args = (OSDMap)buffer;
1324 return args; 1324 return args;
1325 } 1325 }
1326 else 1326 else
1327 { 1327 {
1328 // uh? 1328 // uh?
1329 m_log.Debug(("[UTILS]: Got OSD of unexpected type " + buffer.Type.ToString())); 1329 m_log.Debug(("[UTILS]: Got OSD of unexpected type " + buffer.Type.ToString()));
1330 return null; 1330 return null;
1331 } 1331 }
1332 } 1332 }
1333 catch (Exception ex) 1333 catch (Exception ex)
1334 { 1334 {
1335 m_log.Debug("[UTILS]: exception on GetOSDMap " + ex.Message); 1335 m_log.Debug("[UTILS]: exception on GetOSDMap " + ex.Message);
1336 return null; 1336 return null;
1337 } 1337 }
1338 } 1338 }
1339 1339
1340 public static string[] Glob(string path) 1340 public static string[] Glob(string path)
1341 { 1341 {
1342 string vol=String.Empty; 1342 string vol=String.Empty;
1343 1343
1344 if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar) 1344 if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar)
1345 { 1345 {
1346 string[] vcomps = path.Split(new char[] {Path.VolumeSeparatorChar}, 2, StringSplitOptions.RemoveEmptyEntries); 1346 string[] vcomps = path.Split(new char[] {Path.VolumeSeparatorChar}, 2, StringSplitOptions.RemoveEmptyEntries);
1347 1347
1348 if (vcomps.Length > 1) 1348 if (vcomps.Length > 1)
1349 { 1349 {
1350 path = vcomps[1]; 1350 path = vcomps[1];
1351 vol = vcomps[0]; 1351 vol = vcomps[0];
1352 } 1352 }
1353 } 1353 }
1354 1354
1355 string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries); 1355 string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries);
1356 1356
1357 // Glob 1357 // Glob
1358 1358
1359 path = vol; 1359 path = vol;
1360 if (vol != String.Empty) 1360 if (vol != String.Empty)
1361 path += new String(new char[] {Path.VolumeSeparatorChar, Path.DirectorySeparatorChar}); 1361 path += new String(new char[] {Path.VolumeSeparatorChar, Path.DirectorySeparatorChar});
1362 else 1362 else
1363 path = new String(new char[] {Path.DirectorySeparatorChar}); 1363 path = new String(new char[] {Path.DirectorySeparatorChar});
1364 1364
1365 List<string> paths = new List<string>(); 1365 List<string> paths = new List<string>();
1366 List<string> found = new List<string>(); 1366 List<string> found = new List<string>();
1367 paths.Add(path); 1367 paths.Add(path);
1368 1368
1369 int compIndex = -1; 1369 int compIndex = -1;
1370 foreach (string c in comps) 1370 foreach (string c in comps)
1371 { 1371 {
1372 compIndex++; 1372 compIndex++;
1373 1373
1374 List<string> addpaths = new List<string>(); 1374 List<string> addpaths = new List<string>();
1375 foreach (string p in paths) 1375 foreach (string p in paths)
1376 { 1376 {
1377 string[] dirs = Directory.GetDirectories(p, c); 1377 string[] dirs = Directory.GetDirectories(p, c);
1378 1378
1379 if (dirs.Length != 0) 1379 if (dirs.Length != 0)
1380 { 1380 {
1381 foreach (string dir in dirs) 1381 foreach (string dir in dirs)
1382 addpaths.Add(Path.Combine(path, dir)); 1382 addpaths.Add(Path.Combine(path, dir));
1383 } 1383 }
1384 1384
1385 // Only add files if that is the last path component 1385 // Only add files if that is the last path component
1386 if (compIndex == comps.Length - 1) 1386 if (compIndex == comps.Length - 1)
1387 { 1387 {
1388 string[] files = Directory.GetFiles(p, c); 1388 string[] files = Directory.GetFiles(p, c);
1389 foreach (string f in files) 1389 foreach (string f in files)
1390 found.Add(f); 1390 found.Add(f);
1391 } 1391 }
1392 } 1392 }
1393 paths = addpaths; 1393 paths = addpaths;
1394 } 1394 }
1395 1395
1396 return found.ToArray(); 1396 return found.ToArray();
1397 } 1397 }
1398 1398
1399 public static string ServerURI(string uri) 1399 public static string ServerURI(string uri)
1400 { 1400 {
1401 if (uri == string.Empty) 1401 if (uri == string.Empty)
1402 return string.Empty; 1402 return string.Empty;
1403 1403
1404 // Get rid of eventual slashes at the end 1404 // Get rid of eventual slashes at the end
1405 uri = uri.TrimEnd('/'); 1405 uri = uri.TrimEnd('/');
1406 1406
1407 IPAddress ipaddr1 = null; 1407 IPAddress ipaddr1 = null;
1408 string port1 = ""; 1408 string port1 = "";
1409 try 1409 try
1410 { 1410 {
1411 ipaddr1 = Util.GetHostFromURL(uri); 1411 ipaddr1 = Util.GetHostFromURL(uri);
1412 } 1412 }
1413 catch { } 1413 catch { }
1414 1414
1415 try 1415 try
1416 { 1416 {
1417 port1 = uri.Split(new char[] { ':' })[2]; 1417 port1 = uri.Split(new char[] { ':' })[2];
1418 } 1418 }
1419 catch { } 1419 catch { }
1420 1420
1421 // We tried our best to convert the domain names to IP addresses 1421 // We tried our best to convert the domain names to IP addresses
1422 return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; 1422 return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri;
1423 } 1423 }
1424 1424
1425 /// <summary> 1425 /// <summary>
1426 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. 1426 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary.
1427 /// </summary> 1427 /// </summary>
1428 /// <param name="str"> 1428 /// <param name="str">
1429 /// If null or empty, then an bytes[0] is returned. 1429 /// If null or empty, then an bytes[0] is returned.
1430 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] 1430 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
1431 /// </param> 1431 /// </param>
1432 /// <param name="args"> 1432 /// <param name="args">
1433 /// Arguments to substitute into the string via the {} mechanism. 1433 /// Arguments to substitute into the string via the {} mechanism.
1434 /// </param> 1434 /// </param>
1435 /// <returns></returns> 1435 /// <returns></returns>
1436 public static byte[] StringToBytes256(string str, params object[] args) 1436 public static byte[] StringToBytes256(string str, params object[] args)
1437 { 1437 {
1438 return StringToBytes256(string.Format(str, args)); 1438 return StringToBytes256(string.Format(str, args));
1439 } 1439 }
1440 1440
1441 /// <summary> 1441 /// <summary>
1442 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. 1442 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary.
1443 /// </summary> 1443 /// </summary>
1444 /// <param name="str"> 1444 /// <param name="str">
1445 /// If null or empty, then an bytes[0] is returned. 1445 /// If null or empty, then an bytes[0] is returned.
1446 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] 1446 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
1447 /// </param> 1447 /// </param>
1448 /// <returns></returns> 1448 /// <returns></returns>
1449 public static byte[] StringToBytes256(string str) 1449 public static byte[] StringToBytes256(string str)
1450 { 1450 {
1451 if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } 1451 if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; }
1452 if (str.Length > 254) str = str.Remove(254); 1452 if (str.Length > 254) str = str.Remove(254);
1453 if (!str.EndsWith("\0")) { str += "\0"; } 1453 if (!str.EndsWith("\0")) { str += "\0"; }
1454 1454
1455 // Because this is UTF-8 encoding and not ASCII, it's possible we 1455 // Because this is UTF-8 encoding and not ASCII, it's possible we
1456 // might have gotten an oversized array even after the string trim 1456 // might have gotten an oversized array even after the string trim
1457 byte[] data = UTF8.GetBytes(str); 1457 byte[] data = UTF8.GetBytes(str);
1458 if (data.Length > 256) 1458 if (data.Length > 256)
1459 { 1459 {
1460 Array.Resize<byte>(ref data, 256); 1460 Array.Resize<byte>(ref data, 256);
1461 data[255] = 0; 1461 data[255] = 0;
1462 } 1462 }
1463 1463
1464 return data; 1464 return data;
1465 } 1465 }
1466 1466
1467 /// <summary> 1467 /// <summary>
1468 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. 1468 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary.
1469 /// </summary> 1469 /// </summary>
1470 /// <param name="str"> 1470 /// <param name="str">
1471 /// If null or empty, then an bytes[0] is returned. 1471 /// If null or empty, then an bytes[0] is returned.
1472 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] 1472 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
1473 /// </param> 1473 /// </param>
1474 /// <param name="args"> 1474 /// <param name="args">
1475 /// Arguments to substitute into the string via the {} mechanism. 1475 /// Arguments to substitute into the string via the {} mechanism.
1476 /// </param> 1476 /// </param>
1477 /// <returns></returns> 1477 /// <returns></returns>
1478 public static byte[] StringToBytes1024(string str, params object[] args) 1478 public static byte[] StringToBytes1024(string str, params object[] args)
1479 { 1479 {
1480 return StringToBytes1024(string.Format(str, args)); 1480 return StringToBytes1024(string.Format(str, args));
1481 } 1481 }
1482 1482
1483 /// <summary> 1483 /// <summary>
1484 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. 1484 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary.
1485 /// </summary> 1485 /// </summary>
1486 /// <param name="str"> 1486 /// <param name="str">
1487 /// If null or empty, then an bytes[0] is returned. 1487 /// If null or empty, then an bytes[0] is returned.
1488 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] 1488 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
1489 /// </param> 1489 /// </param>
1490 /// <returns></returns> 1490 /// <returns></returns>
1491 public static byte[] StringToBytes1024(string str) 1491 public static byte[] StringToBytes1024(string str)
1492 { 1492 {
1493 if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } 1493 if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; }
1494 if (str.Length > 1023) str = str.Remove(1023); 1494 if (str.Length > 1023) str = str.Remove(1023);
1495 if (!str.EndsWith("\0")) { str += "\0"; } 1495 if (!str.EndsWith("\0")) { str += "\0"; }
1496 1496
1497 // Because this is UTF-8 encoding and not ASCII, it's possible we 1497 // Because this is UTF-8 encoding and not ASCII, it's possible we
1498 // might have gotten an oversized array even after the string trim 1498 // might have gotten an oversized array even after the string trim
1499 byte[] data = UTF8.GetBytes(str); 1499 byte[] data = UTF8.GetBytes(str);
1500 if (data.Length > 1024) 1500 if (data.Length > 1024)
1501 { 1501 {
1502 Array.Resize<byte>(ref data, 1024); 1502 Array.Resize<byte>(ref data, 1024);
1503 data[1023] = 0; 1503 data[1023] = 0;
1504 } 1504 }
1505 1505
1506 return data; 1506 return data;
1507 } 1507 }
1508 1508
1509 /// <summary> 1509 /// <summary>
@@ -1525,466 +1525,500 @@ namespace OpenSim.Framework
1525 public static bool Is64BitProcess() 1525 public static bool Is64BitProcess()
1526 { 1526 {
1527 return IntPtr.Size == 8; 1527 return IntPtr.Size == 8;
1528 } 1528 }
1529 1529
1530 #region FireAndForget Threading Pattern 1530 #region FireAndForget Threading Pattern
1531 1531
1532 /// <summary> 1532 /// <summary>
1533 /// Created to work around a limitation in Mono with nested delegates 1533 /// Created to work around a limitation in Mono with nested delegates
1534 /// </summary> 1534 /// </summary>
1535 private sealed class FireAndForgetWrapper 1535 private sealed class FireAndForgetWrapper
1536 { 1536 {
1537 private static volatile FireAndForgetWrapper instance; 1537 private static volatile FireAndForgetWrapper instance;
1538 private static object syncRoot = new Object(); 1538 private static object syncRoot = new Object();
1539 1539
1540 public static FireAndForgetWrapper Instance { 1540 public static FireAndForgetWrapper Instance {
1541 get { 1541 get {
1542 1542
1543 if (instance == null) 1543 if (instance == null)
1544 { 1544 {
1545 lock (syncRoot) 1545 lock (syncRoot)
1546 { 1546 {
1547 if (instance == null) 1547 if (instance == null)
1548 { 1548 {
1549 instance = new FireAndForgetWrapper(); 1549 instance = new FireAndForgetWrapper();
1550 } 1550 }
1551 } 1551 }
1552 } 1552 }
1553 1553
1554 return instance; 1554 return instance;
1555 } 1555 }
1556 } 1556 }
1557 1557
1558 public void FireAndForget(System.Threading.WaitCallback callback) 1558 public void FireAndForget(System.Threading.WaitCallback callback)
1559 { 1559 {
1560 callback.BeginInvoke(null, EndFireAndForget, callback); 1560 callback.BeginInvoke(null, EndFireAndForget, callback);
1561 } 1561 }
1562 1562
1563 public void FireAndForget(System.Threading.WaitCallback callback, object obj) 1563 public void FireAndForget(System.Threading.WaitCallback callback, object obj)
1564 { 1564 {
1565 callback.BeginInvoke(obj, EndFireAndForget, callback); 1565 callback.BeginInvoke(obj, EndFireAndForget, callback);
1566 } 1566 }
1567 1567
1568 private static void EndFireAndForget(IAsyncResult ar) 1568 private static void EndFireAndForget(IAsyncResult ar)
1569 { 1569 {
1570 System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; 1570 System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState;
1571 1571
1572 try { callback.EndInvoke(ar); } 1572 try { callback.EndInvoke(ar); }
1573 catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } 1573 catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); }
1574 1574
1575 ar.AsyncWaitHandle.Close(); 1575 ar.AsyncWaitHandle.Close();
1576 } 1576 }
1577 } 1577 }
1578 1578
1579 public static void FireAndForget(System.Threading.WaitCallback callback) 1579 public static void FireAndForget(System.Threading.WaitCallback callback)
1580 { 1580 {
1581 FireAndForget(callback, null); 1581 FireAndForget(callback, null);
1582 } 1582 }
1583 1583
1584 public static void InitThreadPool(int maxThreads) 1584 public static void InitThreadPool(int maxThreads)
1585 { 1585 {
1586 if (maxThreads < 2) 1586 if (maxThreads < 2)
1587 throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); 1587 throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2");
1588 if (m_ThreadPool != null) 1588 if (m_ThreadPool != null)
1589 throw new InvalidOperationException("SmartThreadPool is already initialized"); 1589 throw new InvalidOperationException("SmartThreadPool is already initialized");
1590 1590
1591 m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); 1591 m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2);
1592 } 1592 }
1593 1593
1594 public static int FireAndForgetCount() 1594 public static int FireAndForgetCount()
1595 { 1595 {
1596 const int MAX_SYSTEM_THREADS = 200; 1596 const int MAX_SYSTEM_THREADS = 200;
1597 1597
1598 switch (FireAndForgetMethod) 1598 switch (FireAndForgetMethod)
1599 { 1599 {
1600 case FireAndForgetMethod.UnsafeQueueUserWorkItem: 1600 case FireAndForgetMethod.UnsafeQueueUserWorkItem:
1601 case FireAndForgetMethod.QueueUserWorkItem: 1601 case FireAndForgetMethod.QueueUserWorkItem:
1602 case FireAndForgetMethod.BeginInvoke: 1602 case FireAndForgetMethod.BeginInvoke:
1603 int workerThreads, iocpThreads; 1603 int workerThreads, iocpThreads;
1604 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); 1604 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
1605 return workerThreads; 1605 return workerThreads;
1606 case FireAndForgetMethod.SmartThreadPool: 1606 case FireAndForgetMethod.SmartThreadPool:
1607 return m_ThreadPool.MaxThreads - m_ThreadPool.InUseThreads; 1607 return m_ThreadPool.MaxThreads - m_ThreadPool.InUseThreads;
1608 case FireAndForgetMethod.Thread: 1608 case FireAndForgetMethod.Thread:
1609 return MAX_SYSTEM_THREADS - System.Diagnostics.Process.GetCurrentProcess().Threads.Count; 1609 return MAX_SYSTEM_THREADS - System.Diagnostics.Process.GetCurrentProcess().Threads.Count;
1610 default: 1610 default:
1611 throw new NotImplementedException(); 1611 throw new NotImplementedException();
1612 } 1612 }
1613 } 1613 }
1614 1614
1615 public static void FireAndForget(System.Threading.WaitCallback callback, object obj) 1615 public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
1616 { 1616 {
1617 WaitCallback realCallback; 1617 WaitCallback realCallback;
1618 1618
1619 if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) 1619 if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
1620 { 1620 {
1621 // If we're running regression tests, then we want any exceptions to rise up to the test code. 1621 // If we're running regression tests, then we want any exceptions to rise up to the test code.
1622 realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; 1622 realCallback = o => { Culture.SetCurrentCulture(); callback(o); };
1623 } 1623 }
1624 else 1624 else
1625 { 1625 {
1626 // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture 1626 // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture
1627 // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas 1627 // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas
1628 // for decimals places but is read by a culture that treats commas as number seperators. 1628 // for decimals places but is read by a culture that treats commas as number seperators.
1629 realCallback = o => 1629 realCallback = o =>
1630 { 1630 {
1631 Culture.SetCurrentCulture(); 1631 Culture.SetCurrentCulture();
1632 1632
1633 try 1633 try
1634 { 1634 {
1635 callback(o); 1635 callback(o);
1636 } 1636 }
1637 catch (Exception e) 1637 catch (Exception e)
1638 { 1638 {
1639 m_log.ErrorFormat( 1639 m_log.ErrorFormat(
1640 "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", 1640 "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}",
1641 e.Message, e.StackTrace); 1641 e.Message, e.StackTrace);
1642 } 1642 }
1643 }; 1643 };
1644 } 1644 }
1645 1645
1646 switch (FireAndForgetMethod) 1646 switch (FireAndForgetMethod)
1647 { 1647 {
1648 case FireAndForgetMethod.RegressionTest: 1648 case FireAndForgetMethod.RegressionTest:
1649 case FireAndForgetMethod.None: 1649 case FireAndForgetMethod.None:
1650 realCallback.Invoke(obj); 1650 realCallback.Invoke(obj);
1651 break; 1651 break;
1652 case FireAndForgetMethod.UnsafeQueueUserWorkItem: 1652 case FireAndForgetMethod.UnsafeQueueUserWorkItem:
1653 ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); 1653 ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj);
1654 break; 1654 break;
1655 case FireAndForgetMethod.QueueUserWorkItem: 1655 case FireAndForgetMethod.QueueUserWorkItem:
1656 ThreadPool.QueueUserWorkItem(realCallback, obj); 1656 ThreadPool.QueueUserWorkItem(realCallback, obj);
1657 break; 1657 break;
1658 case FireAndForgetMethod.BeginInvoke: 1658 case FireAndForgetMethod.BeginInvoke:
1659 FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; 1659 FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance;
1660 wrapper.FireAndForget(realCallback, obj); 1660 wrapper.FireAndForget(realCallback, obj);
1661 break; 1661 break;
1662 case FireAndForgetMethod.SmartThreadPool: 1662 case FireAndForgetMethod.SmartThreadPool:
1663 if (m_ThreadPool == null) 1663 if (m_ThreadPool == null)
1664 m_ThreadPool = new SmartThreadPool(2000, 15, 2); 1664 m_ThreadPool = new SmartThreadPool(2000, 15, 2);
1665 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); 1665 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj });
1666 break; 1666 break;
1667 case FireAndForgetMethod.Thread: 1667 case FireAndForgetMethod.Thread:
1668 Thread thread = new Thread(delegate(object o) { realCallback(o); }); 1668 Thread thread = new Thread(delegate(object o) { realCallback(o); });
1669 thread.Start(obj); 1669 thread.Start(obj);
1670 break; 1670 break;
1671 default: 1671 default:
1672 throw new NotImplementedException(); 1672 throw new NotImplementedException();
1673 } 1673 }
1674 } 1674 }
1675 1675
1676 /// <summary> 1676 /// <summary>
1677 /// Get a thread pool report. 1677 /// Get a thread pool report.
1678 /// </summary> 1678 /// </summary>
1679 /// <returns></returns> 1679 /// <returns></returns>
1680 public static string GetThreadPoolReport() 1680 public static string GetThreadPoolReport()
1681 { 1681 {
1682 string threadPoolUsed = null; 1682 string threadPoolUsed = null;
1683 int maxThreads = 0; 1683 int maxThreads = 0;
1684 int minThreads = 0; 1684 int minThreads = 0;
1685 int allocatedThreads = 0; 1685 int allocatedThreads = 0;
1686 int inUseThreads = 0; 1686 int inUseThreads = 0;
1687 int waitingCallbacks = 0; 1687 int waitingCallbacks = 0;
1688 int completionPortThreads = 0; 1688 int completionPortThreads = 0;
1689 1689
1690 StringBuilder sb = new StringBuilder(); 1690 StringBuilder sb = new StringBuilder();
1691 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) 1691 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
1692 { 1692 {
1693 threadPoolUsed = "SmartThreadPool"; 1693 threadPoolUsed = "SmartThreadPool";
1694 maxThreads = m_ThreadPool.MaxThreads; 1694 maxThreads = m_ThreadPool.MaxThreads;
1695 minThreads = m_ThreadPool.MinThreads; 1695 minThreads = m_ThreadPool.MinThreads;
1696 inUseThreads = m_ThreadPool.InUseThreads; 1696 inUseThreads = m_ThreadPool.InUseThreads;
1697 allocatedThreads = m_ThreadPool.ActiveThreads; 1697 allocatedThreads = m_ThreadPool.ActiveThreads;
1698 waitingCallbacks = m_ThreadPool.WaitingCallbacks; 1698 waitingCallbacks = m_ThreadPool.WaitingCallbacks;
1699 } 1699 }
1700 else if ( 1700 else if (
1701 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem 1701 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem
1702 || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) 1702 || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem)
1703 { 1703 {
1704 threadPoolUsed = "BuiltInThreadPool"; 1704 threadPoolUsed = "BuiltInThreadPool";
1705 ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); 1705 ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads);
1706 ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); 1706 ThreadPool.GetMinThreads(out minThreads, out completionPortThreads);
1707 int availableThreads; 1707 int availableThreads;
1708 ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); 1708 ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads);
1709 inUseThreads = maxThreads - availableThreads; 1709 inUseThreads = maxThreads - availableThreads;
1710 allocatedThreads = -1; 1710 allocatedThreads = -1;
1711 waitingCallbacks = -1; 1711 waitingCallbacks = -1;
1712 } 1712 }
1713 1713
1714 if (threadPoolUsed != null) 1714 if (threadPoolUsed != null)
1715 { 1715 {
1716 sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); 1716 sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed);
1717 sb.AppendFormat("Max threads : {0}\n", maxThreads); 1717 sb.AppendFormat("Max threads : {0}\n", maxThreads);
1718 sb.AppendFormat("Min threads : {0}\n", minThreads); 1718 sb.AppendFormat("Min threads : {0}\n", minThreads);
1719 sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); 1719 sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString());
1720 sb.AppendFormat("In use threads : {0}\n", inUseThreads); 1720 sb.AppendFormat("In use threads : {0}\n", inUseThreads);
1721 sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); 1721 sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString());
1722 } 1722 }
1723 else 1723 else
1724 { 1724 {
1725 sb.AppendFormat("Thread pool not used\n"); 1725 sb.AppendFormat("Thread pool not used\n");
1726 } 1726 }
1727 1727
1728 return sb.ToString(); 1728 return sb.ToString();
1729 } 1729 }
1730 1730
1731 private static object SmartThreadPoolCallback(object o) 1731 private static object SmartThreadPoolCallback(object o)
1732 { 1732 {
1733 object[] array = (object[])o; 1733 object[] array = (object[])o;
1734 WaitCallback callback = (WaitCallback)array[0]; 1734 WaitCallback callback = (WaitCallback)array[0];
1735 object obj = array[1]; 1735 object obj = array[1];
1736 1736
1737 callback(obj); 1737 callback(obj);
1738 return null; 1738 return null;
1739 } 1739 }
1740 1740
1741 #endregion FireAndForget Threading Pattern 1741 #endregion FireAndForget Threading Pattern
1742 1742
1743 /// <summary> 1743 /// <summary>
1744 /// Environment.TickCount is an int but it counts all 32 bits so it goes positive 1744 /// Environment.TickCount is an int but it counts all 32 bits so it goes positive
1745 /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap 1745 /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap
1746 /// for the callers. 1746 /// for the callers.
1747 /// This trims it to a 12 day interval so don't let your frame time get too long. 1747 /// This trims it to a 12 day interval so don't let your frame time get too long.
1748 /// </summary> 1748 /// </summary>
1749 /// <returns></returns> 1749 /// <returns></returns>
1750 public static Int32 EnvironmentTickCount() 1750 public static Int32 EnvironmentTickCount()
1751 { 1751 {
1752 return Environment.TickCount & EnvironmentTickCountMask; 1752 return Environment.TickCount & EnvironmentTickCountMask;
1753 } 1753 }
1754 const Int32 EnvironmentTickCountMask = 0x3fffffff; 1754 const Int32 EnvironmentTickCountMask = 0x3fffffff;
1755 1755
1756 /// <summary> 1756 /// <summary>
1757 /// Environment.TickCount is an int but it counts all 32 bits so it goes positive 1757 /// Environment.TickCount is an int but it counts all 32 bits so it goes positive
1758 /// and negative every 24.9 days. Subtracts the passed value (previously fetched by 1758 /// and negative every 24.9 days. Subtracts the passed value (previously fetched by
1759 /// 'EnvironmentTickCount()') and accounts for any wrapping. 1759 /// 'EnvironmentTickCount()') and accounts for any wrapping.
1760 /// </summary> 1760 /// </summary>
1761 /// <returns>subtraction of passed prevValue from current Environment.TickCount</returns> 1761 /// <returns>subtraction of passed prevValue from current Environment.TickCount</returns>
1762 public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) 1762 public static Int32 EnvironmentTickCountSubtract(Int32 prevValue)
1763 { 1763 {
1764 Int32 diff = EnvironmentTickCount() - prevValue; 1764 Int32 diff = EnvironmentTickCount() - prevValue;
1765 return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); 1765 return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1);
1766 } 1766 }
1767 1767
1768 // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount 1768 // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount
1769 // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount(). 1769 // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount().
1770 // A positive return value indicates A occured later than B 1770 // A positive return value indicates A occured later than B
1771 public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB) 1771 public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB)
1772 { 1772 {
1773 // A, B and TC are all between 0 and 0x3fffffff 1773 // A, B and TC are all between 0 and 0x3fffffff
1774 int tc = EnvironmentTickCount(); 1774 int tc = EnvironmentTickCount();
1775 1775
1776 if (tc - tcA >= 0) 1776 if (tc - tcA >= 0)
1777 tcA += EnvironmentTickCountMask + 1; 1777 tcA += EnvironmentTickCountMask + 1;
1778 1778
1779 if (tc - tcB >= 0) 1779 if (tc - tcB >= 0)
1780 tcB += EnvironmentTickCountMask + 1; 1780 tcB += EnvironmentTickCountMask + 1;
1781 1781
1782 return tcA - tcB; 1782 return tcA - tcB;
1783 } 1783 }
1784 1784
1785 /// <summary> 1785 /// <summary>
1786 /// Prints the call stack at any given point. Useful for debugging. 1786 /// Prints the call stack at any given point. Useful for debugging.
1787 /// </summary> 1787 /// </summary>
1788 public static void PrintCallStack() 1788 public static void PrintCallStack()
1789 { 1789 {
1790 StackTrace stackTrace = new StackTrace(true); // get call stack 1790 StackTrace stackTrace = new StackTrace(true); // get call stack
1791 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) 1791 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
1792 1792
1793 // write call stack method names 1793 // write call stack method names
1794 foreach (StackFrame stackFrame in stackFrames) 1794 foreach (StackFrame stackFrame in stackFrames)
1795 { 1795 {
1796 MethodBase mb = stackFrame.GetMethod(); 1796 MethodBase mb = stackFrame.GetMethod();
1797 m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name 1797 m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name
1798 } 1798 }
1799 } 1799 }
1800 1800
1801 /// <summary> 1801 /// <summary>
1802 /// Gets the client IP address 1802 /// Gets the client IP address
1803 /// </summary> 1803 /// </summary>
1804 /// <param name="xff"></param> 1804 /// <param name="xff"></param>
1805 /// <returns></returns> 1805 /// <returns></returns>
1806 public static IPEndPoint GetClientIPFromXFF(string xff) 1806 public static IPEndPoint GetClientIPFromXFF(string xff)
1807 { 1807 {
1808 if (xff == string.Empty) 1808 if (xff == string.Empty)
1809 return null; 1809 return null;
1810 1810
1811 string[] parts = xff.Split(new char[] { ',' }); 1811 string[] parts = xff.Split(new char[] { ',' });
1812 if (parts.Length > 0) 1812 if (parts.Length > 0)
1813 { 1813 {
1814 try 1814 try
1815 { 1815 {
1816 return new IPEndPoint(IPAddress.Parse(parts[0]), 0); 1816 return new IPEndPoint(IPAddress.Parse(parts[0]), 0);
1817 } 1817 }
1818 catch (Exception e) 1818 catch (Exception e)
1819 { 1819 {
1820 m_log.WarnFormat("[UTIL]: Exception parsing XFF header {0}: {1}", xff, e.Message); 1820 m_log.WarnFormat("[UTIL]: Exception parsing XFF header {0}: {1}", xff, e.Message);
1821 } 1821 }
1822 } 1822 }
1823 1823
1824 return null; 1824 return null;
1825 } 1825 }
1826 1826
1827 public static string GetCallerIP(Hashtable req) 1827 public static string GetCallerIP(Hashtable req)
1828 { 1828 {
1829 if (req.ContainsKey("headers")) 1829 if (req.ContainsKey("headers"))
1830 { 1830 {
1831 try 1831 try
1832 { 1832 {
1833 Hashtable headers = (Hashtable)req["headers"]; 1833 Hashtable headers = (Hashtable)req["headers"];
1834 if (headers.ContainsKey("remote_addr") && headers["remote_addr"] != null) 1834 if (headers.ContainsKey("remote_addr") && headers["remote_addr"] != null)
1835 return headers["remote_addr"].ToString(); 1835 return headers["remote_addr"].ToString();
1836 } 1836 }
1837 catch (Exception e) 1837 catch (Exception e)
1838 { 1838 {
1839 m_log.WarnFormat("[UTIL]: exception in GetCallerIP: {0}", e.Message); 1839 m_log.WarnFormat("[UTIL]: exception in GetCallerIP: {0}", e.Message);
1840 } 1840 }
1841 } 1841 }
1842 return string.Empty; 1842 return string.Empty;
1843 } 1843 }
1844 1844
1845 #region Xml Serialization Utilities 1845 #region Xml Serialization Utilities
1846 public static bool ReadBoolean(XmlTextReader reader) 1846 public static bool ReadBoolean(XmlTextReader reader)
1847 { 1847 {
1848 reader.ReadStartElement(); 1848 reader.ReadStartElement();
1849 bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); 1849 bool result = Boolean.Parse(reader.ReadContentAsString().ToLower());
1850 reader.ReadEndElement(); 1850 reader.ReadEndElement();
1851 1851
1852 return result; 1852 return result;
1853 } 1853 }
1854 1854
1855 public static UUID ReadUUID(XmlTextReader reader, string name) 1855 public static UUID ReadUUID(XmlTextReader reader, string name)
1856 { 1856 {
1857 UUID id; 1857 UUID id;
1858 string idStr; 1858 string idStr;
1859 1859
1860 reader.ReadStartElement(name); 1860 reader.ReadStartElement(name);
1861 1861
1862 if (reader.Name == "Guid") 1862 if (reader.Name == "Guid")
1863 idStr = reader.ReadElementString("Guid"); 1863 idStr = reader.ReadElementString("Guid");
1864 else if (reader.Name == "UUID") 1864 else if (reader.Name == "UUID")
1865 idStr = reader.ReadElementString("UUID"); 1865 idStr = reader.ReadElementString("UUID");
1866 else // no leading tag 1866 else // no leading tag
1867 idStr = reader.ReadContentAsString(); 1867 idStr = reader.ReadContentAsString();
1868 UUID.TryParse(idStr, out id); 1868 UUID.TryParse(idStr, out id);
1869 reader.ReadEndElement(); 1869 reader.ReadEndElement();
1870 1870
1871 return id; 1871 return id;
1872 } 1872 }
1873 1873
1874 public static Vector3 ReadVector(XmlTextReader reader, string name) 1874 public static Vector3 ReadVector(XmlTextReader reader, string name)
1875 { 1875 {
1876 Vector3 vec; 1876 Vector3 vec;
1877 1877
1878 reader.ReadStartElement(name); 1878 reader.ReadStartElement(name);
1879 vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x 1879 vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x
1880 vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y 1880 vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y
1881 vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z 1881 vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z
1882 reader.ReadEndElement(); 1882 reader.ReadEndElement();
1883 1883
1884 return vec; 1884 return vec;
1885 } 1885 }
1886 1886
1887 public static Quaternion ReadQuaternion(XmlTextReader reader, string name) 1887 public static Quaternion ReadQuaternion(XmlTextReader reader, string name)
1888 { 1888 {
1889 Quaternion quat = new Quaternion(); 1889 Quaternion quat = new Quaternion();
1890 1890
1891 reader.ReadStartElement(name); 1891 reader.ReadStartElement(name);
1892 while (reader.NodeType != XmlNodeType.EndElement) 1892 while (reader.NodeType != XmlNodeType.EndElement)
1893 { 1893 {
1894 switch (reader.Name.ToLower()) 1894 switch (reader.Name.ToLower())
1895 { 1895 {
1896 case "x": 1896 case "x":
1897 quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); 1897 quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
1898 break; 1898 break;
1899 case "y": 1899 case "y":
1900 quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); 1900 quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
1901 break; 1901 break;
1902 case "z": 1902 case "z":
1903 quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); 1903 quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
1904 break; 1904 break;
1905 case "w": 1905 case "w":
1906 quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty); 1906 quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
1907 break; 1907 break;
1908 } 1908 }
1909 } 1909 }
1910 1910
1911 reader.ReadEndElement(); 1911 reader.ReadEndElement();
1912 1912
1913 return quat; 1913 return quat;
1914 } 1914 }
1915 1915
1916 public static T ReadEnum<T>(XmlTextReader reader, string name) 1916 public static T ReadEnum<T>(XmlTextReader reader, string name)
1917 { 1917 {
1918 string value = reader.ReadElementContentAsString(name, String.Empty); 1918 string value = reader.ReadElementContentAsString(name, String.Empty);
1919 // !!!!! to deal with flags without commas 1919 // !!!!! to deal with flags without commas
1920 if (value.Contains(" ") && !value.Contains(",")) 1920 if (value.Contains(" ") && !value.Contains(","))
1921 value = value.Replace(" ", ", "); 1921 value = value.Replace(" ", ", ");
1922 1922
1923 return (T)Enum.Parse(typeof(T), value); ; 1923 return (T)Enum.Parse(typeof(T), value); ;
1924 } 1924 }
1925 #endregion 1925 #endregion
1926 1926
1927 #region Universal User Identifiers 1927 #region Universal User Identifiers
1928 /// <summary> 1928 /// <summary>
1929 /// </summary> 1929 /// </summary>
1930 /// <param name="value">uuid[;endpoint[;name]]</param> 1930 /// <param name="value">uuid[;endpoint[;first last[;secret]]]</param>
1931 /// <param name="uuid"></param> 1931 /// <param name="uuid">the uuid part</param>
1932 /// <param name="url"></param> 1932 /// <param name="url">the endpoint part (e.g. http://foo.com)</param>
1933 /// <param name="firstname"></param> 1933 /// <param name="firstname">the first name part (e.g. Test)</param>
1934 /// <param name="lastname"></param> 1934 /// <param name="lastname">the last name part (e.g User)</param>
1935 public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) 1935 /// <param name="secret">the secret part</param>
1936 { 1936 public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret)
1937 uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; 1937 {
1938 1938 uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty;
1939 string[] parts = value.Split(';'); 1939
1940 if (parts.Length >= 1) 1940 string[] parts = value.Split(';');
1941 if (!UUID.TryParse(parts[0], out uuid)) 1941 if (parts.Length >= 1)
1942 return false; 1942 if (!UUID.TryParse(parts[0], out uuid))
1943 1943 return false;
1944 if (parts.Length >= 2) 1944
1945 url = parts[1]; 1945 if (parts.Length >= 2)
1946 1946 url = parts[1];
1947 if (parts.Length >= 3) 1947
1948 { 1948 if (parts.Length >= 3)
1949 string[] name = parts[2].Split(); 1949 {
1950 if (name.Length == 2) 1950 string[] name = parts[2].Split();
1951 { 1951 if (name.Length == 2)
1952 firstname = name[0]; 1952 {
1953 lastname = name[1]; 1953 firstname = name[0];
1954 } 1954 lastname = name[1];
1955 } 1955 }
1956 if (parts.Length >= 4) 1956 }
1957 secret = parts[3]; 1957 if (parts.Length >= 4)
1958 1958 secret = parts[3];
1959 return true; 1959
1960 } 1960 return true;
1961 1961 }
1962 /// <summary> 1962
1963 /// 1963 /// <summary>
1964 /// </summary> 1964 /// Produces a universal (HG) system-facing identifier given the information
1965 /// <param name="acircuit"></param> 1965 /// </summary>
1966 /// <returns>uuid[;endpoint[;name]]</returns> 1966 /// <param name="acircuit"></param>
1967 public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit) 1967 /// <returns>uuid[;homeURI[;first last]]</returns>
1968 { 1968 public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit)
1969 if (acircuit.ServiceURLs.ContainsKey("HomeURI")) 1969 {
1970 { 1970 if (acircuit.ServiceURLs.ContainsKey("HomeURI"))
1971 string agentsURI = acircuit.ServiceURLs["HomeURI"].ToString(); 1971 return UniversalIdentifier(acircuit.AgentID, acircuit.firstname, acircuit.lastname, acircuit.ServiceURLs["HomeURI"].ToString());
1972 if (!agentsURI.EndsWith("/")) 1972 else
1973 agentsURI += "/"; 1973 return acircuit.AgentID.ToString();
1974 1974 }
1975 // This is ugly, but there's no other way, given that the name is changed 1975
1976 // in the agent circuit data for foreigners 1976 /// <summary>
1977 if (acircuit.lastname.Contains("@")) 1977 /// Produces a universal (HG) system-facing identifier given the information
1978 { 1978 /// </summary>
1979 string[] parts = acircuit.firstname.Split(new char[] { '.' }); 1979 /// <param name="id">UUID of the user</param>
1980 if (parts.Length == 2) 1980 /// <param name="firstName">first name (e.g Test)</param>
1981 return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; 1981 /// <param name="lastName">last name (e.g. User)</param>
1982 } 1982 /// <param name="homeURI">homeURI (e.g. http://foo.com)</param>
1983 return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + acircuit.firstname + " " + acircuit.lastname; 1983 /// <returns>a string of the form uuid[;homeURI[;first last]]</returns>
1984 } 1984 public static string UniversalIdentifier(UUID id, String firstName, String lastName, String homeURI)
1985 else 1985 {
1986 return acircuit.AgentID.ToString(); 1986 string agentsURI = homeURI;
1987 } 1987 if (!agentsURI.EndsWith("/"))
1988 #endregion 1988 agentsURI += "/";
1989 } 1989
1990} 1990 // This is ugly, but there's no other way, given that the name is changed
1991 // in the agent circuit data for foreigners
1992 if (lastName.Contains("@"))
1993 {
1994 string[] parts = firstName.Split(new char[] { '.' });
1995 if (parts.Length == 2)
1996 return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1];
1997 }
1998 return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName;
1999
2000 }
2001
2002 /// <summary>
2003 /// Produces a universal (HG) user-facing name given the information
2004 /// </summary>
2005 /// <param name="firstName"></param>
2006 /// <param name="lastName"></param>
2007 /// <param name="homeURI"></param>
2008 /// <returns>string of the form first.last @foo.com or first last</returns>
2009 public static string UniversalName(String firstName, String lastName, String homeURI)
2010 {
2011 Uri uri = null;
2012 try
2013 {
2014 uri = new Uri(homeURI);
2015 }
2016 catch (UriFormatException)
2017 {
2018 return firstName + " " + lastName;
2019 }
2020 return firstName + "." + lastName + " " + "@" + uri.Authority;
2021 }
2022 #endregion
2023 }
2024}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index c266fe5..f6a31b5 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -550,7 +550,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
550 UUID principalID = new UUID(im.fromAgentID); 550 UUID principalID = new UUID(im.fromAgentID);
551 UUID friendID = new UUID(im.toAgentID); 551 UUID friendID = new UUID(im.toAgentID);
552 552
553 m_log.DebugFormat("[FRIENDS]: {0} ({1}) offered friendship to {2}", principalID, im.fromAgentName, friendID); 553 m_log.DebugFormat("[FRIENDS]: {0} ({1}) offered friendship to {2} ({3})", principalID, client.FirstName + client.LastName, friendID, im.fromAgentName);
554
555 // Check that the friendship doesn't exist yet
556 FriendInfo[] finfos = GetFriends(principalID);
557 if (finfos != null)
558 {
559 FriendInfo f = GetFriend(finfos, friendID);
560 if (f != null)
561 {
562 client.SendAgentAlertMessage("This person is already your friend. Please delete it first if you want to reestablish the friendship.", false);
563 return;
564 }
565 }
554 566
555 // This user wants to be friends with the other user. 567 // This user wants to be friends with the other user.
556 // Let's add the relation backwards, in case the other is not online 568 // Let's add the relation backwards, in case the other is not online
@@ -561,7 +573,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
561 } 573 }
562 } 574 }
563 575
564 private void ForwardFriendshipOffer(UUID agentID, UUID friendID, GridInstantMessage im) 576 protected virtual bool ForwardFriendshipOffer(UUID agentID, UUID friendID, GridInstantMessage im)
565 { 577 {
566 // !!!!!!!! This is a hack so that we don't have to keep state (transactionID/imSessionID) 578 // !!!!!!!! This is a hack so that we don't have to keep state (transactionID/imSessionID)
567 // We stick this agent's ID as imSession, so that it's directly available on the receiving end 579 // We stick this agent's ID as imSession, so that it's directly available on the receiving end
@@ -570,7 +582,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
570 582
571 // Try the local sim 583 // Try the local sim
572 if (LocalFriendshipOffered(friendID, im)) 584 if (LocalFriendshipOffered(friendID, im))
573 return; 585 {
586 m_log.DebugFormat("[XXX]: LocalFriendshipOffered successes");
587 return true;
588 }
574 589
575 // The prospective friend is not here [as root]. Let's forward. 590 // The prospective friend is not here [as root]. Let's forward.
576 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() }); 591 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
@@ -581,9 +596,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
581 { 596 {
582 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); 597 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
583 m_FriendsSimConnector.FriendshipOffered(region, agentID, friendID, im.message); 598 m_FriendsSimConnector.FriendshipOffered(region, agentID, friendID, im.message);
599 return true;
584 } 600 }
585 } 601 }
586 // If the prospective friend is not online, he'll get the message upon login. 602 // If the prospective friend is not online, he'll get the message upon login.
603 return false;
587 } 604 }
588 605
589 protected virtual string GetFriendshipRequesterName(UUID agentID) 606 protected virtual string GetFriendshipRequesterName(UUID agentID)
@@ -592,7 +609,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
592 return (account == null) ? "Unknown" : account.FirstName + " " + account.LastName; 609 return (account == null) ? "Unknown" : account.FirstName + " " + account.LastName;
593 } 610 }
594 611
595 private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders) 612 protected virtual void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
596 { 613 {
597 m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", client.AgentId, friendID); 614 m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", client.AgentId, friendID);
598 615
@@ -603,7 +620,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
603 { 620 {
604 StoreFriendships(client.AgentId, friendID); 621 StoreFriendships(client.AgentId, friendID);
605 622
606 // Update the local cache 623 // Update the local cache.
607 RecacheFriends(client); 624 RecacheFriends(client);
608 625
609 // 626 //
@@ -756,7 +773,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
756 773
757 #region Local 774 #region Local
758 775
759 public bool LocalFriendshipOffered(UUID toID, GridInstantMessage im) 776 public virtual bool LocalFriendshipOffered(UUID toID, GridInstantMessage im)
760 { 777 {
761 IClientAPI friendClient = LocateClientObject(toID); 778 IClientAPI friendClient = LocateClientObject(toID);
762 if (friendClient != null) 779 if (friendClient != null)
@@ -912,7 +929,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
912 return FriendsService.GetFriends(client.AgentId); 929 return FriendsService.GetFriends(client.AgentId);
913 } 930 }
914 931
915 private void RecacheFriends(IClientAPI client) 932 protected void RecacheFriends(IClientAPI client)
916 { 933 {
917 // FIXME: Ideally, we want to avoid doing this here since it sits the EventManager.OnMakeRootAgent event 934 // FIXME: Ideally, we want to avoid doing this here since it sits the EventManager.OnMakeRootAgent event
918 // is on the critical path for transferring an avatar from one region to another. 935 // is on the critical path for transferring an avatar from one region to another.
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
index 9c53fc4..0fe1134 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
@@ -61,6 +61,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
61 } 61 }
62 } 62 }
63 63
64 protected HGFriendsServicesConnector m_HGFriendsConnector = new HGFriendsServicesConnector();
65
64 #region ISharedRegionModule 66 #region ISharedRegionModule
65 public override string Name 67 public override string Name
66 { 68 {
@@ -94,6 +96,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
94 96
95 #endregion 97 #endregion
96 98
99 protected override void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
100 {
101 // Update the local cache. Yes, we need to do it right here
102 // because the HGFriendsService placed something on the DB
103 // from under the sim
104 base.OnApproveFriendRequest(client, agentID, friendID, callingCardFolders);
105 }
106
97 protected override bool CacheFriends(IClientAPI client) 107 protected override bool CacheFriends(IClientAPI client)
98 { 108 {
99// m_log.DebugFormat("[HGFRIENDS MODULE]: Entered CacheFriends for {0}", client.Name); 109// m_log.DebugFormat("[HGFRIENDS MODULE]: Entered CacheFriends for {0}", client.Name);
@@ -183,91 +193,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
183// m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetOnlineFriends for {0}", userID); 193// m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetOnlineFriends for {0}", userID);
184 } 194 }
185 195
186 //protected override void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online)
187 //{
188 // // Let's single out the UUIs
189 // List<string> localFriends = new List<string>();
190 // List<string> foreignFriends = new List<string>();
191 // string tmp = string.Empty;
192
193 // foreach (string s in friendList)
194 // {
195 // UUID id;
196 // if (UUID.TryParse(s, out id))
197 // localFriends.Add(s);
198 // else if (Util.ParseUniversalUserIdentifier(s, out id, out tmp, out tmp, out tmp, out tmp))
199 // {
200 // foreignFriends.Add(s);
201 // // add it here too, who knows maybe the foreign friends happens to be on this grid
202 // localFriends.Add(id.ToString());
203 // }
204 // }
205
206 // // OK, see who's present on this grid
207 // List<string> toBeRemoved = new List<string>();
208 // PresenceInfo[] presence = PresenceService.GetAgents(localFriends.ToArray());
209 // foreach (PresenceInfo pi in presence)
210 // {
211 // UUID presenceID;
212 // if (UUID.TryParse(pi.UserID, out presenceID))
213 // {
214 // online.Add(presenceID);
215 // foreach (string s in foreignFriends)
216 // if (s.StartsWith(pi.UserID))
217 // toBeRemoved.Add(s);
218 // }
219 // }
220
221 // foreach (string s in toBeRemoved)
222 // foreignFriends.Remove(s);
223
224 // // OK, let's send this up the stack, and leave a closure here
225 // // collecting online friends in other grids
226 // Util.FireAndForget(delegate { CollectOnlineFriendsElsewhere(userID, foreignFriends); });
227
228 //}
229
230 //private void CollectOnlineFriendsElsewhere(UUID userID, List<string> foreignFriends)
231 //{
232 // // let's divide the friends on a per-domain basis
233 // Dictionary<string, List<string>> friendsPerDomain = new Dictionary<string, List<string>>();
234 // foreach (string friend in foreignFriends)
235 // {
236 // UUID friendID;
237 // if (!UUID.TryParse(friend, out friendID))
238 // {
239 // // it's a foreign friend
240 // string url = string.Empty, tmp = string.Empty;
241 // if (Util.ParseUniversalUserIdentifier(friend, out friendID, out url, out tmp, out tmp, out tmp))
242 // {
243 // if (!friendsPerDomain.ContainsKey(url))
244 // friendsPerDomain[url] = new List<string>();
245 // friendsPerDomain[url].Add(friend);
246 // }
247 // }
248 // }
249
250 // // Now, call those worlds
251
252 // foreach (KeyValuePair<string, List<string>> kvp in friendsPerDomain)
253 // {
254 // List<string> ids = new List<string>();
255 // foreach (string f in kvp.Value)
256 // ids.Add(f);
257 // UserAgentServiceConnector uConn = new UserAgentServiceConnector(kvp.Key);
258 // List<UUID> online = uConn.GetOnlineFriends(userID, ids);
259 // // Finally send the notifications to the user
260 // // this whole process may take a while, so let's check at every
261 // // iteration that the user is still here
262 // IClientAPI client = LocateClientObject(userID);
263 // if (client != null)
264 // client.SendAgentOnline(online.ToArray());
265 // else
266 // break;
267 // }
268
269 //}
270
271 protected override void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online) 196 protected override void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
272 { 197 {
273// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID); 198// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID);
@@ -335,12 +260,25 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
335 return true; 260 return true;
336 261
337 // fid is not a UUID... 262 // fid is not a UUID...
338 string url = string.Empty, tmp = string.Empty; 263 string url = string.Empty, tmp = string.Empty, f = string.Empty, l = string.Empty;
339 if (Util.ParseUniversalUserIdentifier(fid, out agentID, out url, out first, out last, out tmp)) 264 m_log.DebugFormat("[YYY]: FID {0}", fid);
265 if (Util.ParseUniversalUserIdentifier(fid, out agentID, out url, out f, out l, out tmp))
340 { 266 {
341 IUserManagement userMan = m_Scenes[0].RequestModuleInterface<IUserManagement>(); 267 m_log.DebugFormat("[YYY]: Adding user {0} {1} {2}", f, l, url);
342 userMan.AddUser(agentID, first, last, url); 268 m_uMan.AddUser(agentID, f, l, url);
343 269
270 string name = m_uMan.GetUserName(agentID);
271 string[] parts = name.Trim().Split(new char[] {' '});
272 if (parts.Length == 2)
273 {
274 first = parts[0];
275 last = parts[1];
276 }
277 else
278 {
279 first = f;
280 last = l;
281 }
344 return true; 282 return true;
345 } 283 }
346 return false; 284 return false;
@@ -348,13 +286,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
348 286
349 protected override string GetFriendshipRequesterName(UUID agentID) 287 protected override string GetFriendshipRequesterName(UUID agentID)
350 { 288 {
351 // For the time being we assume that HG friendship requests can only happen 289 return m_uMan.GetUserName(agentID);
352 // when avies are on the same region.
353 IClientAPI client = LocateClientObject(agentID);
354 if (client != null)
355 return client.FirstName + " " + client.LastName;
356 else
357 return base.GetFriendshipRequesterName(agentID);
358 } 290 }
359 291
360 protected override string FriendshipMessage(string friendID) 292 protected override string FriendshipMessage(string friendID)
@@ -392,10 +324,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
392 AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); 324 AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode);
393 if (agentClientCircuit != null) 325 if (agentClientCircuit != null)
394 { 326 {
395 string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); 327 //[XXX] string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit);
396 328
397 finfos = FriendsService.GetFriends(agentUUI); 329 finfos = FriendsService.GetFriends(client.AgentId.ToString());
398 m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, agentUUI); 330 m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString());
399 } 331 }
400 332
401// m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name); 333// m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name);
@@ -454,16 +386,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
454 friendIsLocal = UserManagementModule.IsLocalGridUser(friendID); 386 friendIsLocal = UserManagementModule.IsLocalGridUser(friendID);
455 } 387 }
456 388
457 // Are they both local users? 389 // Is the requester a local user?
458 if (agentIsLocal && friendIsLocal) 390 if (agentIsLocal)
459 { 391 {
460 // local grid users 392 // local grid users
461 m_log.DebugFormat("[HGFRIENDS MODULE]: Users are both local"); 393 m_log.DebugFormat("[HGFRIENDS MODULE]: Friendship requester is local. Storing backwards.");
394
462 base.StoreBackwards(friendID, agentID); 395 base.StoreBackwards(friendID, agentID);
463 return; 396 return;
464 } 397 }
465 398
466 // no provision for this temporary friendship state 399 // no provision for this temporary friendship state when user is not local
467 //FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 0); 400 //FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 0);
468 } 401 }
469 402
@@ -501,12 +434,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
501 agentClientCircuit = ((Scene)(agentClient.Scene)).AuthenticateHandler.GetAgentCircuitData(agentClient.CircuitCode); 434 agentClientCircuit = ((Scene)(agentClient.Scene)).AuthenticateHandler.GetAgentCircuitData(agentClient.CircuitCode);
502 agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); 435 agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit);
503 agentFriendService = agentClientCircuit.ServiceURLs["FriendsServerURI"].ToString(); 436 agentFriendService = agentClientCircuit.ServiceURLs["FriendsServerURI"].ToString();
437 RecacheFriends(agentClient);
504 } 438 }
505 if (friendClient != null) 439 if (friendClient != null)
506 { 440 {
507 friendClientCircuit = ((Scene)(friendClient.Scene)).AuthenticateHandler.GetAgentCircuitData(friendClient.CircuitCode); 441 friendClientCircuit = ((Scene)(friendClient.Scene)).AuthenticateHandler.GetAgentCircuitData(friendClient.CircuitCode);
508 friendUUI = Util.ProduceUserUniversalIdentifier(friendClientCircuit); 442 friendUUI = Util.ProduceUserUniversalIdentifier(friendClientCircuit);
509 friendFriendService = friendClientCircuit.ServiceURLs["FriendsServerURI"].ToString(); 443 friendFriendService = friendClientCircuit.ServiceURLs["FriendsServerURI"].ToString();
444 RecacheFriends(friendClient);
510 } 445 }
511 446
512 m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}", 447 m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}",
@@ -515,14 +450,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
515 // Generate a random 8-character hex number that will sign this friendship 450 // Generate a random 8-character hex number that will sign this friendship
516 string secret = UUID.Random().ToString().Substring(0, 8); 451 string secret = UUID.Random().ToString().Substring(0, 8);
517 452
453 string theFriendUUID = friendUUI + ";" + secret;
454 string agentUUID = agentUUI + ";" + secret;
455
518 if (agentIsLocal) // agent is local, 'friend' is foreigner 456 if (agentIsLocal) // agent is local, 'friend' is foreigner
519 { 457 {
520 // This may happen when the agent returned home, in which case the friend is not there 458 // This may happen when the agent returned home, in which case the friend is not there
521 // We need to look for its information in the friends list itself 459 // We need to look for its information in the friends list itself
460 FriendInfo[] finfos = null;
522 bool confirming = false; 461 bool confirming = false;
523 if (friendUUI == string.Empty) 462 if (friendUUI == string.Empty)
524 { 463 {
525 FriendInfo[] finfos = GetFriends(agentID); 464 finfos = GetFriends(agentID);
526 foreach (FriendInfo finfo in finfos) 465 foreach (FriendInfo finfo in finfos)
527 { 466 {
528 if (finfo.TheirFlags == -1) 467 if (finfo.TheirFlags == -1)
@@ -530,29 +469,57 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
530 if (finfo.Friend.StartsWith(friendID.ToString())) 469 if (finfo.Friend.StartsWith(friendID.ToString()))
531 { 470 {
532 friendUUI = finfo.Friend; 471 friendUUI = finfo.Friend;
472 theFriendUUID = friendUUI;
473 UUID utmp = UUID.Zero; String url = String.Empty; String first = String.Empty, last = String.Empty, tmp = String.Empty;
474 // If it's confirming the friendship, we already have the full UUI with the secret
475 if (Util.ParseUniversalUserIdentifier(theFriendUUID, out utmp, out url, out first, out last, out secret))
476 {
477 agentUUID = agentUUI + ";" + secret;
478 m_uMan.AddUser(utmp, first, last, url);
479 }
533 confirming = true; 480 confirming = true;
481 break;
534 } 482 }
535 } 483 }
536 } 484 }
537 } 485 if (!confirming)
486 {
487 friendUUI = m_uMan.GetUserUUI(friendID);
488 theFriendUUID = friendUUI + ";" + secret;
489 }
490
491 friendFriendService = m_uMan.GetUserServerURL(friendID, "FriendsServerURI");
538 492
539 // If it's confirming the friendship, we already have the full friendUUI with the secret 493 // m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}",
540 string theFriendUUID = confirming ? friendUUI : friendUUI + ";" + secret; 494 // agentUUI, friendUUI, agentFriendService, friendFriendService);
495
496 }
497
498 // Delete any previous friendship relations
499 DeletePreviousRelations(agentID, friendID);
541 500
542 // store in the local friends service a reference to the foreign friend 501 // store in the local friends service a reference to the foreign friend
543 FriendsService.StoreFriend(agentID.ToString(), theFriendUUID, 1); 502 FriendsService.StoreFriend(agentID.ToString(), theFriendUUID, 1);
544 // and also the converse 503 // and also the converse
545 FriendsService.StoreFriend(theFriendUUID, agentID.ToString(), 1); 504 FriendsService.StoreFriend(theFriendUUID, agentID.ToString(), 1);
546 505
547 if (!confirming && friendClientCircuit != null) 506 //if (!confirming)
548 { 507 //{
549 // store in the foreign friends service a reference to the local agent 508 // store in the foreign friends service a reference to the local agent
550 HGFriendsServicesConnector friendsConn = new HGFriendsServicesConnector(friendFriendService, friendClientCircuit.SessionID, friendClientCircuit.ServiceSessionID); 509 HGFriendsServicesConnector friendsConn = null;
551 friendsConn.NewFriendship(friendID, agentUUI + ";" + secret); 510 if (friendClientCircuit != null) // the friend is here, validate session
552 } 511 friendsConn = new HGFriendsServicesConnector(friendFriendService, friendClientCircuit.SessionID, friendClientCircuit.ServiceSessionID);
512 else // the friend is not here, he initiated the request in his home world
513 friendsConn = new HGFriendsServicesConnector(friendFriendService);
514
515 friendsConn.NewFriendship(friendID, agentUUID);
516 //}
553 } 517 }
554 else if (friendIsLocal) // 'friend' is local, agent is foreigner 518 else if (friendIsLocal) // 'friend' is local, agent is foreigner
555 { 519 {
520 // Delete any previous friendship relations
521 DeletePreviousRelations(agentID, friendID);
522
556 // store in the local friends service a reference to the foreign agent 523 // store in the local friends service a reference to the foreign agent
557 FriendsService.StoreFriend(friendID.ToString(), agentUUI + ";" + secret, 1); 524 FriendsService.StoreFriend(friendID.ToString(), agentUUI + ";" + secret, 1);
558 // and also the converse 525 // and also the converse
@@ -582,6 +549,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
582 // my brain hurts now 549 // my brain hurts now
583 } 550 }
584 551
552 private void DeletePreviousRelations(UUID a1, UUID a2)
553 {
554 // Delete any previous friendship relations
555 FriendInfo[] finfos = null;
556 FriendInfo f = null;
557 finfos = GetFriends(a1);
558 if (finfos != null)
559 {
560 f = GetFriend(finfos, a2);
561 if (f != null)
562 {
563 FriendsService.Delete(a1, f.Friend);
564 // and also the converse
565 FriendsService.Delete(f.Friend, a1.ToString());
566 }
567 }
568
569 finfos = GetFriends(a2);
570 if (finfos != null)
571 {
572 f = GetFriend(finfos, a1);
573 if (f != null)
574 {
575 FriendsService.Delete(a2, f.Friend);
576 // and also the converse
577 FriendsService.Delete(f.Friend, a2.ToString());
578 }
579 }
580 }
581
585 protected override bool DeleteFriendship(UUID agentID, UUID exfriendID) 582 protected override bool DeleteFriendship(UUID agentID, UUID exfriendID)
586 { 583 {
587 Boolean agentIsLocal = true; 584 Boolean agentIsLocal = true;
@@ -684,5 +681,74 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
684 friendConn.DeleteFriendship(foreignUser, localUser, secret); 681 friendConn.DeleteFriendship(foreignUser, localUser, secret);
685 } 682 }
686 } 683 }
684
685 protected override bool ForwardFriendshipOffer(UUID agentID, UUID friendID, GridInstantMessage im)
686 {
687 if (base.ForwardFriendshipOffer(agentID, friendID, im))
688 return true;
689
690 // OK, that didn't work, so let's try to find this user somewhere
691 if (!m_uMan.IsLocalGridUser(friendID))
692 {
693 string friendsURL = m_uMan.GetUserServerURL(friendID, "FriendsServerURI");
694 if (friendsURL != string.Empty)
695 {
696 m_log.DebugFormat("[HGFRIENDS MODULE]: Forwading friendship from {0} to {1} @ {2}", agentID, friendID, friendsURL);
697 GridRegion region = new GridRegion();
698 region.ServerURI = friendsURL;
699
700 string name = im.fromAgentName;
701 if (m_uMan.IsLocalGridUser(agentID))
702 {
703 IClientAPI agentClient = LocateClientObject(agentID);
704 AgentCircuitData agentClientCircuit = ((Scene)(agentClient.Scene)).AuthenticateHandler.GetAgentCircuitData(agentClient.CircuitCode);
705 string agentHomeService = string.Empty;
706 try
707 {
708 agentHomeService = agentClientCircuit.ServiceURLs["HomeURI"].ToString();
709 string lastname = "@" + new Uri(agentHomeService).Authority;
710 string firstname = im.fromAgentName.Replace(" ", ".");
711 name = firstname + lastname;
712 }
713 catch (KeyNotFoundException)
714 {
715 m_log.DebugFormat("[HGFRIENDS MODULE]: Key HomeURI not found for user {0}", agentID);
716 return false;
717 }
718 catch (NullReferenceException)
719 {
720 m_log.DebugFormat("[HGFRIENDS MODULE]: Null HomeUri for local user {0}", agentID);
721 return false;
722 }
723 catch (UriFormatException)
724 {
725 m_log.DebugFormat("[HGFRIENDS MODULE]: Malformed HomeUri {0} for local user {1}", agentHomeService, agentID);
726 return false;
727 }
728 }
729
730 m_HGFriendsConnector.FriendshipOffered(region, agentID, friendID, im.message, name);
731
732 return true;
733 }
734 }
735
736 return false;
737 }
738
739 public override bool LocalFriendshipOffered(UUID toID, GridInstantMessage im)
740 {
741 if (base.LocalFriendshipOffered(toID, im))
742 {
743 if (im.fromAgentName.Contains("@"))
744 {
745 string[] parts = im.fromAgentName.Split(new char[] { '@' });
746 if (parts.Length == 2)
747 m_uMan.AddUser(new UUID(im.fromAgentID), parts[0], "http://" + parts[1]);
748 }
749 return true;
750 }
751 return false;
752 }
687 } 753 }
688} \ No newline at end of file 754} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
index 66de8e4..4eecaa2 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
@@ -71,43 +71,52 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
71 71
72 protected override void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) 72 protected override void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users)
73 { 73 {
74 string[] words = query.Split(new char[] { ' ' }); 74 if (query.Contains("@")) // First.Last@foo.com, maybe?
75
76 for (int i = 0; i < words.Length; i++)
77 { 75 {
78 if (words[i].Length < 3) 76 string[] words = query.Split(new char[] { '@' });
77 if (words.Length != 2)
79 { 78 {
80 if (i != words.Length - 1) 79 m_log.DebugFormat("[USER MANAGEMENT MODULE]: Malformed address {0}", query);
81 Array.Copy(words, i + 1, words, i, words.Length - i - 1); 80 return;
82 Array.Resize(ref words, words.Length - 1);
83 } 81 }
84 }
85 82
86 if (words.Length == 0 || words.Length > 2) 83 words[0] = words[0].Trim(); // it has at least 1
87 return; 84 words[1] = words[1].Trim();
88 85
89 if (words.Length == 2) // First.Last @foo.com, maybe? 86 if (words[0] == String.Empty) // query was @foo.com?
90 { 87 {
91 bool found = false; 88 foreach (UserData d in m_UserCache.Values)
89 {
90 if (d.LastName.ToLower().StartsWith("@" + words[1].ToLower()))
91 users.Add(d);
92 }
93
94 // We're done
95 return;
96 }
97
98 // words.Length == 2 and words[0] != string.empty
99 // first.last@foo.com ?
92 foreach (UserData d in m_UserCache.Values) 100 foreach (UserData d in m_UserCache.Values)
93 { 101 {
94 if (d.LastName.StartsWith("@") && 102 if (d.LastName.StartsWith("@") &&
95 d.FirstName.ToLower().Equals(words[0].ToLower()) && 103 d.FirstName.ToLower().Equals(words[0].ToLower()) &&
96 d.LastName.ToLower().Equals(words[1].ToLower())) 104 d.LastName.ToLower().Equals("@" + words[1].ToLower()))
97 { 105 {
98 users.Add(d); 106 users.Add(d);
99 found = true; 107 // It's cached. We're done
100 break; 108 return;
101 } 109 }
102 } 110 }
103 111
104 if (!found && words[1].StartsWith("@") && words[0].Contains(".")) // This is it! Let's ask the other world 112 // This is it! Let's ask the other world
113 if (words[0].Contains("."))
105 { 114 {
106 string[] names = words[0].Split(new char[] { '.' }); 115 string[] names = words[0].Split(new char[] { '.' });
107 if (names.Length >= 2) 116 if (names.Length >= 2)
108 { 117 {
109 118
110 string uriStr = "http://" + words[1].Substring(1); // remove the @ 119 string uriStr = "http://" + words[1];
111 // Let's check that the last name is a valid address 120 // Let's check that the last name is a valid address
112 try 121 try
113 { 122 {
@@ -115,6 +124,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
115 } 124 }
116 catch (UriFormatException) 125 catch (UriFormatException)
117 { 126 {
127 m_log.DebugFormat("[USER MANAGEMENT MODULE]: Malformed address {0}", uriStr);
118 return; 128 return;
119 } 129 }
120 130
@@ -125,26 +135,26 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
125 UserData ud = new UserData(); 135 UserData ud = new UserData();
126 ud.Id = userID; 136 ud.Id = userID;
127 ud.FirstName = words[0]; 137 ud.FirstName = words[0];
128 ud.LastName = words[1]; 138 ud.LastName = "@" + words[1];
129 users.Add(ud); 139 users.Add(ud);
130 AddUser(userID, ud.FirstName, ud.LastName, uriStr); 140 AddUser(userID, names[0], names[1], uriStr);
131 m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0} {1} found", words[0], words[1]); 141 m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0}@{1} found", words[0], words[1]);
132 } 142 }
133 else 143 else
134 m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0} {1} not found", words[0], words[1]); 144 m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0}@{1} not found", words[0], words[1]);
135 } 145 }
136 } 146 }
137 } 147 }
138 else 148 //else
139 { 149 //{
140 foreach (UserData d in m_UserCache.Values) 150 // foreach (UserData d in m_UserCache.Values)
141 { 151 // {
142 if (d.LastName.StartsWith("@") && 152 // if (d.LastName.StartsWith("@") &&
143 (d.FirstName.ToLower().StartsWith(query.ToLower()) || 153 // (d.FirstName.ToLower().StartsWith(query.ToLower()) ||
144 d.LastName.ToLower().StartsWith(query.ToLower()))) 154 // d.LastName.ToLower().StartsWith(query.ToLower())))
145 users.Add(d); 155 // users.Add(d);
146 } 156 // }
147 } 157 //}
148 } 158 }
149 159
150 } 160 }
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
index cb562a2..0397478 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
@@ -299,7 +299,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
299 299
300 public string GetUserName(UUID uuid) 300 public string GetUserName(UUID uuid)
301 { 301 {
302 //m_log.DebugFormat("[XXX] GetUserName {0}", uuid);
303 string[] names = GetUserNames(uuid); 302 string[] names = GetUserNames(uuid);
304 if (names.Length == 2) 303 if (names.Length == 2)
305 { 304 {
@@ -340,9 +339,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
340 339
341 if (userdata.HomeURL != null && userdata.HomeURL != string.Empty) 340 if (userdata.HomeURL != null && userdata.HomeURL != string.Empty)
342 { 341 {
343 m_log.DebugFormat( 342 //m_log.DebugFormat(
344 "[USER MANAGEMENT MODULE]: Did not find url type {0} so requesting urls from '{1}' for {2}", 343 // "[USER MANAGEMENT MODULE]: Did not find url type {0} so requesting urls from '{1}' for {2}",
345 serverType, userdata.HomeURL, userID); 344 // serverType, userdata.HomeURL, userID);
346 345
347 UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL); 346 UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL);
348 userdata.ServerURLs = uConn.GetServerURLs(userID); 347 userdata.ServerURLs = uConn.GetServerURLs(userID);
@@ -401,11 +400,15 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
401 400
402 public void AddUser(UUID uuid, string first, string last, string homeURL) 401 public void AddUser(UUID uuid, string first, string last, string homeURL)
403 { 402 {
403 // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
404
404 AddUser(uuid, homeURL + ";" + first + " " + last); 405 AddUser(uuid, homeURL + ";" + first + " " + last);
405 } 406 }
406 407
407 public void AddUser (UUID id, string creatorData) 408 public void AddUser (UUID id, string creatorData)
408 { 409 {
410 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData);
411
409 UserData oldUser; 412 UserData oldUser;
410 //lock the whole block - prevent concurrent update 413 //lock the whole block - prevent concurrent update
411 lock (m_UserCache) 414 lock (m_UserCache)
@@ -431,9 +434,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
431 return; 434 return;
432 } 435 }
433 } 436 }
434// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData);
435 437
436 UserAccount account = m_Scenes [0].UserAccountService.GetUserAccount (m_Scenes [0].RegionInfo.ScopeID, id); 438 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount (m_Scenes [0].RegionInfo.ScopeID, id);
437 439
438 if (account != null) 440 if (account != null)
439 { 441 {
@@ -482,9 +484,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
482 lock (m_UserCache) 484 lock (m_UserCache)
483 m_UserCache[user.Id] = user; 485 m_UserCache[user.Id] = user;
484 486
485// m_log.DebugFormat( 487 //m_log.DebugFormat(
486// "[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}", 488 // "[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}",
487// user.Id, user.FirstName, user.LastName, user.HomeURL); 489 // user.Id, user.FirstName, user.LastName, user.HomeURL);
488 } 490 }
489 491
490 public bool IsLocalGridUser(UUID uuid) 492 public bool IsLocalGridUser(UUID uuid)
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs
index 89abbb2..8df1c7b 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs
@@ -48,8 +48,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Hypergrid
48 private static bool m_Enabled = false; 48 private static bool m_Enabled = false;
49 49
50 private IConfigSource m_Config; 50 private IConfigSource m_Config;
51 bool m_Registered = false; 51 private bool m_Registered = false;
52 GatekeeperServiceInConnector m_HypergridHandler; 52 private string m_LocalServiceDll = String.Empty;
53 private GatekeeperServiceInConnector m_HypergridHandler;
54 private UserAgentServerConnector m_UASHandler;
53 55
54 #region IRegionModule interface 56 #region IRegionModule interface
55 57
@@ -63,6 +65,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Hypergrid
63 if (m_Enabled) 65 if (m_Enabled)
64 { 66 {
65 m_log.Info("[HGGRID IN CONNECTOR]: Hypergrid Service In Connector enabled"); 67 m_log.Info("[HGGRID IN CONNECTOR]: Hypergrid Service In Connector enabled");
68 IConfig fconfig = config.Configs["FriendsService"];
69 if (fconfig != null)
70 {
71 m_LocalServiceDll = fconfig.GetString("LocalServiceModule", m_LocalServiceDll);
72 if (m_LocalServiceDll == String.Empty)
73 m_log.WarnFormat("[HGGRID IN CONNECTOR]: Friends LocalServiceModule config missing");
74 }
66 } 75 }
67 76
68 } 77 }
@@ -91,7 +100,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Hypergrid
91 { 100 {
92 if (!m_Enabled) 101 if (!m_Enabled)
93 return; 102 return;
94
95 } 103 }
96 104
97 public void RemoveRegion(Scene scene) 105 public void RemoveRegion(Scene scene)
@@ -112,14 +120,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Hypergrid
112 m_log.Info("[HypergridService]: Starting..."); 120 m_log.Info("[HypergridService]: Starting...");
113 121
114 ISimulationService simService = scene.RequestModuleInterface<ISimulationService>(); 122 ISimulationService simService = scene.RequestModuleInterface<ISimulationService>();
123 IFriendsSimConnector friendsConn = scene.RequestModuleInterface<IFriendsSimConnector>();
124 Object[] args = new Object[] { m_Config };
125 IFriendsService friendsService = ServerUtils.LoadPlugin<IFriendsService>(m_LocalServiceDll, args);
126
115 m_HypergridHandler = new GatekeeperServiceInConnector(m_Config, MainServer.Instance, simService); 127 m_HypergridHandler = new GatekeeperServiceInConnector(m_Config, MainServer.Instance, simService);
116 128
117 IFriendsSimConnector friendsConn = scene.RequestModuleInterface<IFriendsSimConnector>(); 129 m_UASHandler = new UserAgentServerConnector(m_Config, MainServer.Instance, friendsConn);
118 new UserAgentServerConnector(m_Config, MainServer.Instance, friendsConn); 130
119 new HeloServiceInConnector(m_Config, MainServer.Instance, "HeloService"); 131 new HeloServiceInConnector(m_Config, MainServer.Instance, "HeloService");
120 new HGFriendsServerConnector(m_Config, MainServer.Instance, "HGFriendsService"); 132
133 new HGFriendsServerConnector(m_Config, MainServer.Instance, "HGFriendsService", friendsConn);
121 } 134 }
122 scene.RegisterModuleInterface<IGatekeeperService>(m_HypergridHandler.GateKeeper); 135 scene.RegisterModuleInterface<IGatekeeperService>(m_HypergridHandler.GateKeeper);
136 scene.RegisterModuleInterface<IUserAgentService>(m_UASHandler.HomeUsersService);
123 } 137 }
124 138
125 #endregion 139 #endregion
diff --git a/OpenSim/Server/Handlers/Hypergrid/HGFriendServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/HGFriendServerConnector.cs
index 82a7220..6c79c60 100644
--- a/OpenSim/Server/Handlers/Hypergrid/HGFriendServerConnector.cs
+++ b/OpenSim/Server/Handlers/Hypergrid/HGFriendServerConnector.cs
@@ -36,36 +36,42 @@ namespace OpenSim.Server.Handlers.Hypergrid
36{ 36{
37 public class HGFriendsServerConnector : ServiceConnector 37 public class HGFriendsServerConnector : ServiceConnector
38 { 38 {
39 private IFriendsService m_FriendsService;
40 private IUserAgentService m_UserAgentService; 39 private IUserAgentService m_UserAgentService;
40 private IHGFriendsService m_TheService;
41 private string m_ConfigName = "HGFriendsService"; 41 private string m_ConfigName = "HGFriendsService";
42 42
43 // Called from Robust
43 public HGFriendsServerConnector(IConfigSource config, IHttpServer server, string configName) : 44 public HGFriendsServerConnector(IConfigSource config, IHttpServer server, string configName) :
44 base(config, server, configName) 45 this(config, server, configName, null)
45 { 46 {
46 if (configName != string.Empty) 47
48 }
49
50 // Called from standalone configurations
51 public HGFriendsServerConnector(IConfigSource config, IHttpServer server, string configName, IFriendsSimConnector localConn)
52 : base(config, server, configName)
53 {
54 if (configName != string.Empty)
47 m_ConfigName = configName; 55 m_ConfigName = configName;
48 56
57 Object[] args = new Object[] { config, m_ConfigName, localConn };
58
49 IConfig serverConfig = config.Configs[m_ConfigName]; 59 IConfig serverConfig = config.Configs[m_ConfigName];
50 if (serverConfig == null) 60 if (serverConfig == null)
51 throw new Exception(String.Format("No section {0} in config file", m_ConfigName)); 61 throw new Exception(String.Format("No section {0} in config file", m_ConfigName));
52 62
53 string theService = serverConfig.GetString("LocalServiceModule", 63 string theService = serverConfig.GetString("LocalServiceModule",
54 String.Empty); 64 String.Empty);
55
56 if (theService == String.Empty) 65 if (theService == String.Empty)
57 throw new Exception("No LocalServiceModule in config file"); 66 throw new Exception("No LocalServiceModule in config file");
58 67 m_TheService = ServerUtils.LoadPlugin<IHGFriendsService>(theService, args);
59 Object[] args = new Object[] { config };
60 m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(theService, args);
61 68
62 theService = serverConfig.GetString("UserAgentService", string.Empty); 69 theService = serverConfig.GetString("UserAgentService", string.Empty);
63 if (theService == String.Empty) 70 if (theService == String.Empty)
64 throw new Exception("No UserAgentService in " + m_ConfigName); 71 throw new Exception("No UserAgentService in " + m_ConfigName);
72 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(theService, new Object[] { config, localConn });
65 73
66 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(theService, args); 74 server.AddStreamHandler(new HGFriendsServerPostHandler(m_TheService, m_UserAgentService, localConn));
67
68 server.AddStreamHandler(new HGFriendsServerPostHandler(m_FriendsService, m_UserAgentService));
69 } 75 }
70 } 76 }
71} 77}
diff --git a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs
index 661507e..ca566f2 100644
--- a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs
+++ b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs
@@ -39,6 +39,7 @@ using System.Collections.Generic;
39using OpenSim.Server.Base; 39using OpenSim.Server.Base;
40using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
41using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; 41using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
42using GridRegion = OpenSim.Services.Interfaces.GridRegion;
42using OpenSim.Framework; 43using OpenSim.Framework;
43using OpenSim.Framework.Servers.HttpServer; 44using OpenSim.Framework.Servers.HttpServer;
44using OpenMetaverse; 45using OpenMetaverse;
@@ -49,15 +50,22 @@ namespace OpenSim.Server.Handlers.Hypergrid
49 { 50 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 52
52 private IFriendsService m_FriendsService;
53 private IUserAgentService m_UserAgentService; 53 private IUserAgentService m_UserAgentService;
54 private IFriendsSimConnector m_FriendsLocalSimConnector;
55 private IHGFriendsService m_TheService;
54 56
55 public HGFriendsServerPostHandler(IFriendsService service, IUserAgentService uservice) : 57 public HGFriendsServerPostHandler(IHGFriendsService service, IUserAgentService uas, IFriendsSimConnector friendsConn) :
56 base("POST", "/hgfriends") 58 base("POST", "/hgfriends")
57 { 59 {
58 m_FriendsService = service; 60 m_TheService = service;
59 m_UserAgentService = uservice; 61 m_UserAgentService = uas;
60 m_log.DebugFormat("[HGFRIENDS HANDLER]: HGFriendsServerPostHandler is On"); 62 m_FriendsLocalSimConnector = friendsConn;
63
64 m_log.DebugFormat("[HGFRIENDS HANDLER]: HGFriendsServerPostHandler is On ({0})",
65 (m_FriendsLocalSimConnector == null ? "robust" : "standalone"));
66
67 if (m_TheService == null)
68 m_log.ErrorFormat("[HGFRIENDS HANDLER]: TheService is null!");
61 } 69 }
62 70
63 public override byte[] Handle(string path, Stream requestData, 71 public override byte[] Handle(string path, Stream requestData,
@@ -90,6 +98,26 @@ namespace OpenSim.Server.Handlers.Hypergrid
90 98
91 case "deletefriendship": 99 case "deletefriendship":
92 return DeleteFriendship(request); 100 return DeleteFriendship(request);
101
102 /* Same as inter-sim */
103 case "friendship_offered":
104 return FriendshipOffered(request);
105
106 case "validate_friendship_offered":
107 return ValidateFriendshipOffered(request);
108 /*
109 case "friendship_approved":
110 return FriendshipApproved(request);
111
112 case "friendship_denied":
113 return FriendshipDenied(request);
114
115 case "friendship_terminated":
116 return FriendshipTerminated(request);
117
118 case "grant_rights":
119 return GrantRights(request);
120 */
93 } 121 }
94 m_log.DebugFormat("[HGFRIENDS HANDLER]: unknown method {0} request {1}", method.Length, method); 122 m_log.DebugFormat("[HGFRIENDS HANDLER]: unknown method {0} request {1}", method.Length, method);
95 } 123 }
@@ -126,39 +154,20 @@ namespace OpenSim.Server.Handlers.Hypergrid
126 return FailureResult(); 154 return FailureResult();
127 } 155 }
128 156
129 FriendInfo[] friendsInfo = m_FriendsService.GetFriends(principalID); 157 int perms = m_TheService.GetFriendPerms(principalID, friendID);
130 foreach (FriendInfo finfo in friendsInfo) 158 if (perms < 0)
131 { 159 return FailureResult("Friend not found");
132 if (finfo.Friend.StartsWith(friendID.ToString()))
133 return SuccessResult(finfo.TheirFlags.ToString());
134 }
135 160
136 return FailureResult("Friend not found"); 161 return SuccessResult(perms.ToString());
137 } 162 }
138 163
139 byte[] NewFriendship(Dictionary<string, object> request) 164 byte[] NewFriendship(Dictionary<string, object> request)
140 { 165 {
141 if (!VerifyServiceKey(request)) 166 bool verified = VerifyServiceKey(request);
142 return FailureResult();
143 167
144 // OK, can proceed
145 FriendInfo friend = new FriendInfo(request); 168 FriendInfo friend = new FriendInfo(request);
146 UUID friendID;
147 string tmp = string.Empty;
148 if (!Util.ParseUniversalUserIdentifier(friend.Friend, out friendID, out tmp, out tmp, out tmp, out tmp))
149 return FailureResult();
150 169
151 170 bool success = m_TheService.NewFriendship(friend, verified);
152 m_log.DebugFormat("[HGFRIENDS HANDLER]: New friendship {0} {1}", friend.PrincipalID, friend.Friend);
153
154 // If the friendship already exists, return fail
155 FriendInfo[] finfos = m_FriendsService.GetFriends(friend.PrincipalID);
156 foreach (FriendInfo finfo in finfos)
157 if (finfo.Friend.StartsWith(friendID.ToString()))
158 return FailureResult();
159
160 // the user needs to confirm when he gets home
161 bool success = m_FriendsService.StoreFriend(friend.PrincipalID.ToString(), friend.Friend, 0);
162 171
163 if (success) 172 if (success)
164 return SuccessResult(); 173 return SuccessResult();
@@ -174,25 +183,53 @@ namespace OpenSim.Server.Handlers.Hypergrid
174 secret = request["SECRET"].ToString(); 183 secret = request["SECRET"].ToString();
175 184
176 if (secret == string.Empty) 185 if (secret == string.Empty)
177 return FailureResult(); 186 return BoolResult(false);
178 187
179 FriendInfo[] finfos = m_FriendsService.GetFriends(friend.PrincipalID); 188 bool success = m_TheService.DeleteFriendship(friend, secret);
180 foreach (FriendInfo finfo in finfos)
181 {
182 // We check the secret here
183 if (finfo.Friend.StartsWith(friend.Friend) && finfo.Friend.EndsWith(secret))
184 {
185 m_log.DebugFormat("[HGFRIENDS HANDLER]: Delete friendship {0} {1}", friend.PrincipalID, friend.Friend);
186 m_FriendsService.Delete(friend.PrincipalID, finfo.Friend);
187 m_FriendsService.Delete(finfo.Friend, friend.PrincipalID.ToString());
188 189
189 return SuccessResult(); 190 return BoolResult(success);
190 } 191 }
191 }
192 192
193 return FailureResult(); 193 byte[] FriendshipOffered(Dictionary<string, object> request)
194 {
195 UUID fromID = UUID.Zero;
196 UUID toID = UUID.Zero;
197 string message = string.Empty;
198 string name = string.Empty;
199
200 m_log.DebugFormat("[HGFRIENDS HANDLER]: Friendship offered");
201 if (!request.ContainsKey("FromID") || !request.ContainsKey("ToID"))
202 return BoolResult(false);
203
204 if (!UUID.TryParse(request["ToID"].ToString(), out toID))
205 return BoolResult(false);
206
207 message = request["Message"].ToString();
208
209 if (!UUID.TryParse(request["FromID"].ToString(), out fromID))
210 return BoolResult(false);
211
212 if (request.ContainsKey("FromName"))
213 name = request["FromName"].ToString();
214
215 bool success = m_TheService.FriendshipOffered(fromID, name, toID, message);
216
217 return BoolResult(success);
194 } 218 }
195 219
220 byte[] ValidateFriendshipOffered(Dictionary<string, object> request)
221 {
222 FriendInfo friend = new FriendInfo(request);
223 UUID friendID = UUID.Zero;
224 if (!UUID.TryParse(friend.Friend, out friendID))
225 return BoolResult(false);
226
227 bool success = m_TheService.ValidateFriendshipOffered(friend.PrincipalID, friendID);
228
229 return BoolResult(success);
230 }
231
232
196 #endregion 233 #endregion
197 234
198 #region Misc 235 #region Misc
@@ -205,10 +242,15 @@ namespace OpenSim.Server.Handlers.Hypergrid
205 return false; 242 return false;
206 } 243 }
207 244
245 if (request["KEY"] == null || request["SESSIONID"] == null)
246 return false;
247
208 string serviceKey = request["KEY"].ToString(); 248 string serviceKey = request["KEY"].ToString();
209 string sessionStr = request["SESSIONID"].ToString(); 249 string sessionStr = request["SESSIONID"].ToString();
250
210 UUID sessionID; 251 UUID sessionID;
211 UUID.TryParse(sessionStr, out sessionID); 252 if (!UUID.TryParse(sessionStr, out sessionID) || serviceKey == string.Empty)
253 return false;
212 254
213 if (!m_UserAgentService.VerifyAgent(sessionID, serviceKey)) 255 if (!m_UserAgentService.VerifyAgent(sessionID, serviceKey))
214 { 256 {
@@ -256,7 +298,7 @@ namespace OpenSim.Server.Handlers.Hypergrid
256 298
257 doc.AppendChild(rootElement); 299 doc.AppendChild(rootElement);
258 300
259 XmlElement result = doc.CreateElement("", "Result", ""); 301 XmlElement result = doc.CreateElement("", "RESULT", "");
260 result.AppendChild(doc.CreateTextNode("Success")); 302 result.AppendChild(doc.CreateTextNode("Success"));
261 303
262 rootElement.AppendChild(result); 304 rootElement.AppendChild(result);
@@ -289,7 +331,7 @@ namespace OpenSim.Server.Handlers.Hypergrid
289 331
290 doc.AppendChild(rootElement); 332 doc.AppendChild(rootElement);
291 333
292 XmlElement result = doc.CreateElement("", "Result", ""); 334 XmlElement result = doc.CreateElement("", "RESULT", "");
293 result.AppendChild(doc.CreateTextNode("Failure")); 335 result.AppendChild(doc.CreateTextNode("Failure"));
294 336
295 rootElement.AppendChild(result); 337 rootElement.AppendChild(result);
@@ -302,6 +344,28 @@ namespace OpenSim.Server.Handlers.Hypergrid
302 return DocToBytes(doc); 344 return DocToBytes(doc);
303 } 345 }
304 346
347 private byte[] BoolResult(bool value)
348 {
349 XmlDocument doc = new XmlDocument();
350
351 XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration,
352 "", "");
353
354 doc.AppendChild(xmlnode);
355
356 XmlElement rootElement = doc.CreateElement("", "ServerResponse",
357 "");
358
359 doc.AppendChild(rootElement);
360
361 XmlElement result = doc.CreateElement("", "RESULT", "");
362 result.AppendChild(doc.CreateTextNode(value.ToString()));
363
364 rootElement.AppendChild(result);
365
366 return DocToBytes(doc);
367 }
368
305 private byte[] DocToBytes(XmlDocument doc) 369 private byte[] DocToBytes(XmlDocument doc)
306 { 370 {
307 MemoryStream ms = new MemoryStream(); 371 MemoryStream ms = new MemoryStream();
@@ -313,6 +377,7 @@ namespace OpenSim.Server.Handlers.Hypergrid
313 return ms.ToArray(); 377 return ms.ToArray();
314 } 378 }
315 379
380
316 #endregion 381 #endregion
317 } 382 }
318} 383}
diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs
index 7348368..9a0e27e 100644
--- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs
+++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs
@@ -52,6 +52,11 @@ namespace OpenSim.Server.Handlers.Hypergrid
52// MethodBase.GetCurrentMethod().DeclaringType); 52// MethodBase.GetCurrentMethod().DeclaringType);
53 53
54 private IUserAgentService m_HomeUsersService; 54 private IUserAgentService m_HomeUsersService;
55 public IUserAgentService HomeUsersService
56 {
57 get { return m_HomeUsersService; }
58 }
59
55 private string[] m_AuthorizedCallers; 60 private string[] m_AuthorizedCallers;
56 61
57 private bool m_VerifyCallers = false; 62 private bool m_VerifyCallers = false;
diff --git a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs
index eea9853..3fd0c53 100644
--- a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs
+++ b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs
@@ -43,8 +43,18 @@ namespace OpenSim.Services.Connectors.Friends
43 { 43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 45
46 protected virtual string ServicePath()
47 {
48 return "friends";
49 }
50
46 public bool FriendshipOffered(GridRegion region, UUID userID, UUID friendID, string message) 51 public bool FriendshipOffered(GridRegion region, UUID userID, UUID friendID, string message)
47 { 52 {
53 return FriendshipOffered(region, userID, friendID, message, String.Empty);
54 }
55
56 public virtual bool FriendshipOffered(GridRegion region, UUID userID, UUID friendID, string message, string userName)
57 {
48 Dictionary<string, object> sendData = new Dictionary<string, object>(); 58 Dictionary<string, object> sendData = new Dictionary<string, object>();
49 //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); 59 //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
50 //sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); 60 //sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString();
@@ -53,9 +63,10 @@ namespace OpenSim.Services.Connectors.Friends
53 sendData["FromID"] = userID.ToString(); 63 sendData["FromID"] = userID.ToString();
54 sendData["ToID"] = friendID.ToString(); 64 sendData["ToID"] = friendID.ToString();
55 sendData["Message"] = message; 65 sendData["Message"] = message;
66 if (userName != String.Empty)
67 sendData["FromName"] = userName;
56 68
57 return Call(region, sendData); 69 return Call(region, sendData);
58
59 } 70 }
60 71
61 public bool FriendshipApproved(GridRegion region, UUID userID, string userName, UUID friendID) 72 public bool FriendshipApproved(GridRegion region, UUID userID, string userName, UUID friendID)
@@ -138,8 +149,11 @@ namespace OpenSim.Services.Connectors.Friends
138 if (region == null) 149 if (region == null)
139 return false; 150 return false;
140 151
141 m_log.DebugFormat("[FRIENDS SIM CONNECTOR]: region: {0}", region.ExternalHostName + ":" + region.HttpPort); 152 string path = ServicePath();
142 string uri = "http://" + region.ExternalHostName + ":" + region.HttpPort + "/friends"; 153 if (!region.ServerURI.EndsWith("/"))
154 path = "/" + path;
155 string uri = region.ServerURI + path;
156 m_log.DebugFormat("[FRIENDS SIM CONNECTOR]: calling {0}", uri);
143 157
144 try 158 try
145 { 159 {
diff --git a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs
index af4b0da..e3f3260 100644
--- a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs
@@ -40,7 +40,7 @@ using OpenMetaverse;
40 40
41namespace OpenSim.Services.Connectors.Hypergrid 41namespace OpenSim.Services.Connectors.Hypergrid
42{ 42{
43 public class HGFriendsServicesConnector 43 public class HGFriendsServicesConnector : FriendsSimConnector
44 { 44 {
45 private static readonly ILog m_log = 45 private static readonly ILog m_log =
46 LogManager.GetLogger( 46 LogManager.GetLogger(
@@ -66,6 +66,11 @@ namespace OpenSim.Services.Connectors.Hypergrid
66 m_SessionID = sessionID; 66 m_SessionID = sessionID;
67 } 67 }
68 68
69 protected override string ServicePath()
70 {
71 return "hgfriends";
72 }
73
69 #region IFriendsService 74 #region IFriendsService
70 75
71 public uint GetFriendPerms(UUID PrincipalID, UUID friendID) 76 public uint GetFriendPerms(UUID PrincipalID, UUID friendID)
@@ -187,23 +192,69 @@ namespace OpenSim.Services.Connectors.Hypergrid
187 { 192 {
188 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); 193 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
189 194
190 if ((replyData != null) && replyData.ContainsKey("Result") && (replyData["Result"] != null)) 195 if (replyData.ContainsKey("RESULT"))
191 { 196 {
192 bool success = false; 197 if (replyData["RESULT"].ToString().ToLower() == "true")
193 Boolean.TryParse(replyData["Result"].ToString(), out success); 198 return true;
194 return success; 199 else
200 return false;
195 } 201 }
196 else 202 else
197 m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Delete {0} {1} received null response", 203 m_log.DebugFormat("[HGFRIENDS CONNECTOR]: reply data does not contain result field");
198 PrincipalID, Friend); 204
199 } 205 }
200 else 206 else
201 m_log.DebugFormat("[HGFRIENDS CONNECTOR]: DeleteFriend received null reply"); 207 m_log.DebugFormat("[HGFRIENDS CONNECTOR]: received empty reply");
202 208
203 return false; 209 return false;
204 210
205 } 211 }
206 212
213 public bool ValidateFriendshipOffered(UUID fromID, UUID toID)
214 {
215 FriendInfo finfo = new FriendInfo();
216 finfo.PrincipalID = fromID;
217 finfo.Friend = toID.ToString();
218
219 Dictionary<string, object> sendData = finfo.ToKeyValuePairs();
220
221 sendData["METHOD"] = "validate_friendship_offered";
222
223 string reply = string.Empty;
224 string uri = m_ServerURI + "/hgfriends";
225 try
226 {
227 reply = SynchronousRestFormsRequester.MakeRequest("POST",
228 uri,
229 ServerUtils.BuildQueryString(sendData));
230 }
231 catch (Exception e)
232 {
233 m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Exception when contacting friends server at {0}: {1}", uri, e.Message);
234 return false;
235 }
236
237 if (reply != string.Empty)
238 {
239 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
240
241 if (replyData.ContainsKey("RESULT"))
242 {
243 if (replyData["RESULT"].ToString().ToLower() == "true")
244 return true;
245 else
246 return false;
247 }
248 else
249 m_log.DebugFormat("[HGFRIENDS CONNECTOR]: reply data does not contain result field");
250
251 }
252 else
253 m_log.DebugFormat("[HGFRIENDS CONNECTOR]: received empty reply");
254
255 return false;
256
257 }
207 #endregion 258 #endregion
208 } 259 }
209} \ No newline at end of file 260} \ No newline at end of file
diff --git a/OpenSim/Services/HypergridService/HGFriendsService.cs b/OpenSim/Services/HypergridService/HGFriendsService.cs
new file mode 100644
index 0000000..19ee3e2
--- /dev/null
+++ b/OpenSim/Services/HypergridService/HGFriendsService.cs
@@ -0,0 +1,301 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Reflection;
32
33using OpenSim.Framework;
34using OpenSim.Services.Connectors.Friends;
35using OpenSim.Services.Connectors.Hypergrid;
36using OpenSim.Services.Interfaces;
37using GridRegion = OpenSim.Services.Interfaces.GridRegion;
38using OpenSim.Server.Base;
39using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
40
41using OpenMetaverse;
42using log4net;
43using Nini.Config;
44
45namespace OpenSim.Services.HypergridService
46{
47 /// <summary>
48 /// W2W social networking
49 /// </summary>
50 public class HGFriendsService : IHGFriendsService
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 static bool m_Initialized = false;
57
58 protected static IGridUserService m_GridUserService;
59 protected static IGridService m_GridService;
60 protected static IGatekeeperService m_GatekeeperService;
61 protected static IFriendsService m_FriendsService;
62 protected static IPresenceService m_PresenceService;
63 protected static IUserAccountService m_UserAccountService;
64 protected static IFriendsSimConnector m_FriendsLocalSimConnector; // standalone, points to HGFriendsModule
65 protected static FriendsSimConnector m_FriendsSimConnector; // grid
66
67 private static string m_ConfigName = "HGFriendsService";
68
69 public HGFriendsService(IConfigSource config, String configName, IFriendsSimConnector localSimConn)
70 {
71 if (m_FriendsLocalSimConnector == null)
72 m_FriendsLocalSimConnector = localSimConn;
73
74 if (!m_Initialized)
75 {
76 m_Initialized = true;
77
78 if (configName != String.Empty)
79 m_ConfigName = configName;
80
81 Object[] args = new Object[] { config };
82
83 IConfig serverConfig = config.Configs[m_ConfigName];
84 if (serverConfig == null)
85 throw new Exception(String.Format("No section {0} in config file", m_ConfigName));
86
87 string theService = serverConfig.GetString("FriendsService", string.Empty);
88 if (theService == String.Empty)
89 throw new Exception("No FriendsService in config file " + m_ConfigName);
90 m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(theService, args);
91
92 theService = serverConfig.GetString("UserAccountService", string.Empty);
93 if (theService == String.Empty)
94 throw new Exception("No UserAccountService in " + m_ConfigName);
95 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(theService, args);
96
97 theService = serverConfig.GetString("GridService", string.Empty);
98 if (theService == String.Empty)
99 throw new Exception("No GridService in " + m_ConfigName);
100 m_GridService = ServerUtils.LoadPlugin<IGridService>(theService, args);
101
102 theService = serverConfig.GetString("PresenceService", string.Empty);
103 if (theService == String.Empty)
104 throw new Exception("No PresenceService in " + m_ConfigName);
105 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(theService, args);
106
107 m_FriendsSimConnector = new FriendsSimConnector();
108
109 m_log.DebugFormat("[HGFRIENDS SERVICE]: Starting...");
110
111 }
112 }
113
114 #region IHGFriendsService
115
116 public int GetFriendPerms(UUID userID, UUID friendID)
117 {
118 FriendInfo[] friendsInfo = m_FriendsService.GetFriends(userID);
119 foreach (FriendInfo finfo in friendsInfo)
120 {
121 if (finfo.Friend.StartsWith(friendID.ToString()))
122 return finfo.TheirFlags;
123 }
124 return -1;
125 }
126
127 public bool NewFriendship(FriendInfo friend, bool verified)
128 {
129 UUID friendID;
130 string tmp = string.Empty, url = String.Empty, first = String.Empty, last = String.Empty;
131 if (!Util.ParseUniversalUserIdentifier(friend.Friend, out friendID, out url, out first, out last, out tmp))
132 return false;
133
134 m_log.DebugFormat("[HGFRIENDS SERVICE]: New friendship {0} {1} ({2})", friend.PrincipalID, friend.Friend, verified);
135
136 // Does the friendship already exist?
137 FriendInfo[] finfos = m_FriendsService.GetFriends(friend.PrincipalID);
138 foreach (FriendInfo finfo in finfos)
139 {
140 if (finfo.Friend.StartsWith(friendID.ToString()))
141 return false;
142 }
143 // Verified user session. But the user needs to confirm friendship when he gets home
144 if (verified)
145 return m_FriendsService.StoreFriend(friend.PrincipalID.ToString(), friend.Friend, 0);
146
147 // Does the reverted friendship exist? meaning that this user initiated the request
148 finfos = m_FriendsService.GetFriends(friendID);
149 bool userInitiatedOffer = false;
150 foreach (FriendInfo finfo in finfos)
151 {
152 if (friend.Friend.StartsWith(finfo.PrincipalID.ToString()) && finfo.Friend.StartsWith(friend.PrincipalID.ToString()) && finfo.TheirFlags == -1)
153 {
154 userInitiatedOffer = true;
155 // Let's delete the existing friendship relations that was stored
156 m_FriendsService.Delete(friendID, finfo.Friend);
157 break;
158 }
159 }
160
161 if (userInitiatedOffer)
162 {
163 m_FriendsService.StoreFriend(friend.PrincipalID.ToString(), friend.Friend, 1);
164 m_FriendsService.StoreFriend(friend.Friend, friend.PrincipalID.ToString(), 1);
165 // notify the user
166 ForwardToSim("ApproveFriendshipRequest", friendID, Util.UniversalName(first, last, url), "", friend.PrincipalID, "");
167 return true;
168 }
169 return false;
170 }
171
172 public bool DeleteFriendship(FriendInfo friend, string secret)
173 {
174 FriendInfo[] finfos = m_FriendsService.GetFriends(friend.PrincipalID);
175 foreach (FriendInfo finfo in finfos)
176 {
177 // We check the secret here. Or if the friendship request was initiated here, and was declined
178 if (finfo.Friend.StartsWith(friend.Friend) && finfo.Friend.EndsWith(secret))
179 {
180 m_log.DebugFormat("[HGFRIENDS SERVICE]: Delete friendship {0} {1}", friend.PrincipalID, friend.Friend);
181 m_FriendsService.Delete(friend.PrincipalID, finfo.Friend);
182 m_FriendsService.Delete(finfo.Friend, friend.PrincipalID.ToString());
183
184 return true;
185 }
186 }
187
188 return false;
189 }
190
191 public bool FriendshipOffered(UUID fromID, string fromName, UUID toID, string message)
192 {
193 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, toID);
194 if (account == null)
195 return false;
196
197 // OK, we have that user here.
198 // So let's send back the call, but start a thread to continue
199 // with the verification and the actual action.
200
201 Util.FireAndForget(delegate { ProcessFriendshipOffered(fromID, fromName, toID, message); });
202
203 return true;
204 }
205
206 public bool ValidateFriendshipOffered(UUID fromID, UUID toID)
207 {
208 FriendInfo[] finfos = m_FriendsService.GetFriends(toID.ToString());
209 foreach (FriendInfo fi in finfos)
210 {
211 if (fi.Friend.StartsWith(fromID.ToString()) && fi.TheirFlags == -1)
212 return true;
213 }
214 return false;
215 }
216
217 #endregion IHGFriendsService
218
219 #region Aux
220
221 private void ProcessFriendshipOffered(UUID fromID, String fromName, UUID toID, String message)
222 {
223 // Great, it's a genuine request. Let's proceed.
224 // But now we need to confirm that the requester is who he says he is
225 // before we act on the friendship request.
226
227 if (!fromName.Contains("@"))
228 return;
229
230 string[] parts = fromName.Split(new char[] {'@'});
231 if (parts.Length != 2)
232 return;
233
234 string uriStr = "http://" + parts[1];
235 try
236 {
237 new Uri(uriStr);
238 }
239 catch (UriFormatException)
240 {
241 return;
242 }
243
244 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uriStr);
245 Dictionary<string, object> servers = uasConn.GetServerURLs(fromID);
246 if (!servers.ContainsKey("FriendsServerURI"))
247 return;
248
249 HGFriendsServicesConnector friendsConn = new HGFriendsServicesConnector(servers["FriendsServerURI"].ToString());
250 if (!friendsConn.ValidateFriendshipOffered(fromID, toID))
251 {
252 m_log.WarnFormat("[HGFRIENDS SERVICE]: Friendship request from {0} to {1} is invalid. Impersonations?", fromID, toID);
253 return;
254 }
255
256 string fromUUI = Util.UniversalIdentifier(fromID, parts[0], "@" + parts[1], uriStr);
257 // OK, we're good!
258 ForwardToSim("FriendshipOffered", fromID, fromName, fromUUI, toID, message);
259 }
260
261 private bool ForwardToSim(string op, UUID fromID, string name, String fromUUI, UUID toID, string message)
262 {
263 PresenceInfo session = null;
264 GridRegion region = null;
265 PresenceInfo[] sessions = m_PresenceService.GetAgents(new string[] { toID.ToString() });
266 if (sessions != null && sessions.Length > 0)
267 session = sessions[0];
268 if (session != null)
269 region = m_GridService.GetRegionByUUID(UUID.Zero, session.RegionID);
270
271 switch (op)
272 {
273 case "FriendshipOffered":
274 // Let's store backwards
275 string secret = UUID.Random().ToString().Substring(0, 8);
276 m_FriendsService.StoreFriend(toID.ToString(), fromUUI + ";" + secret, 0);
277 if (m_FriendsLocalSimConnector != null) // standalone
278 {
279 GridInstantMessage im = new GridInstantMessage(null, fromID, name, toID,
280 (byte)InstantMessageDialog.FriendshipOffered, message, false, Vector3.Zero);
281 // !! HACK
282 im.imSessionID = im.fromAgentID;
283 return m_FriendsLocalSimConnector.LocalFriendshipOffered(toID, im);
284 }
285 else if (region != null) // grid
286 return m_FriendsSimConnector.FriendshipOffered(region, fromID, toID, message, name);
287 break;
288 case "ApproveFriendshipRequest":
289 if (m_FriendsLocalSimConnector != null) // standalone
290 return m_FriendsLocalSimConnector.LocalFriendshipApproved(fromID, name, toID);
291 else if (region != null) //grid
292 return m_FriendsSimConnector.FriendshipApproved(region, fromID, name, toID);
293 break;
294 }
295
296 return false;
297 }
298
299 #endregion Aux
300 }
301}
diff --git a/OpenSim/Services/Interfaces/IHypergridServices.cs b/OpenSim/Services/Interfaces/IHypergridServices.cs
index 0cd44f7..f48b8a9 100644
--- a/OpenSim/Services/Interfaces/IHypergridServices.cs
+++ b/OpenSim/Services/Interfaces/IHypergridServices.cs
@@ -81,6 +81,17 @@ namespace OpenSim.Services.Interfaces
81 public interface IFriendsSimConnector 81 public interface IFriendsSimConnector
82 { 82 {
83 bool StatusNotify(UUID userID, UUID friendID, bool online); 83 bool StatusNotify(UUID userID, UUID friendID, bool online);
84 bool LocalFriendshipOffered(UUID toID, GridInstantMessage im);
85 bool LocalFriendshipApproved(UUID userID, string userName, UUID friendID);
86 }
87
88 public interface IHGFriendsService
89 {
90 int GetFriendPerms(UUID userID, UUID friendID);
91 bool NewFriendship(FriendInfo finfo, bool verified);
92 bool DeleteFriendship(FriendInfo finfo, string secret);
93 bool FriendshipOffered(UUID from, string fromName, UUID to, string message);
94 bool ValidateFriendshipOffered(UUID fromID, UUID toID);
84 } 95 }
85 96
86 public interface IInstantMessageSimConnector 97 public interface IInstantMessageSimConnector
diff --git a/bin/config-include/StandaloneHypergrid.ini b/bin/config-include/StandaloneHypergrid.ini
index ee51067..75c4788 100644
--- a/bin/config-include/StandaloneHypergrid.ini
+++ b/bin/config-include/StandaloneHypergrid.ini
@@ -159,8 +159,12 @@
159 UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService" 159 UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
160 160
161[HGFriendsService] 161[HGFriendsService]
162 LocalServiceModule = "OpenSim.Services.FriendsService.dll:FriendsService" 162 LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGFriendsService"
163 UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" 163 UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService"
164 FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService"
165 UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
166 GridService = "OpenSim.Services.GridService.dll:GridService"
167 PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService"
164 168
165[HGInstantMessageService] 169[HGInstantMessageService]
166 LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInstantMessageService" 170 LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInstantMessageService"