aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorMelanie2013-06-04 21:09:25 +0100
committerMelanie2013-06-04 21:09:25 +0100
commit648e258b8e79e52df18f41f2ec79016a095f7766 (patch)
treede96993d11a0183ac026cec61e0e5a937f801c3c /OpenSim
parentMerge branch 'master' into careminster (diff)
parentNew HttpServer_OpenSim.dll with increased limits on number of connections, re... (diff)
downloadopensim-SC-648e258b8e79e52df18f41f2ec79016a095f7766.zip
opensim-SC-648e258b8e79e52df18f41f2ec79016a095f7766.tar.gz
opensim-SC-648e258b8e79e52df18f41f2ec79016a095f7766.tar.bz2
opensim-SC-648e258b8e79e52df18f41f2ec79016a095f7766.tar.xz
Merge branch 'master' into careminster
Conflicts: OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
Diffstat (limited to '')
-rw-r--r--OpenSim/Data/IProfilesData.cs56
-rw-r--r--OpenSim/Data/MySQL/MySQLUserProfilesData.cs1096
-rw-r--r--OpenSim/Data/MySQL/Resources/UserProfiles.migrations83
-rw-r--r--OpenSim/Framework/Animation.cs20
-rw-r--r--OpenSim/Framework/UserProfiles.cs117
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs16
-rw-r--r--OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs1328
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs226
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs1
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs110
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs26
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs23
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs12
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs8
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs3
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs271
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs326
-rw-r--r--OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs119
-rw-r--r--OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs461
-rw-r--r--OpenSim/Services/Interfaces/IUserProfilesService.cs75
-rw-r--r--OpenSim/Services/UserProfilesService/UserProfilesService.cs187
-rw-r--r--OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs86
25 files changed, 4443 insertions, 228 deletions
diff --git a/OpenSim/Data/IProfilesData.cs b/OpenSim/Data/IProfilesData.cs
new file mode 100644
index 0000000..0de7f68
--- /dev/null
+++ b/OpenSim/Data/IProfilesData.cs
@@ -0,0 +1,56 @@
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 OpenMetaverse;
30using OpenMetaverse.StructuredData;
31using OpenSim.Framework;
32
33namespace OpenSim.Data
34{
35
36 public interface IProfilesData
37 {
38 OSDArray GetClassifiedRecords(UUID creatorId);
39 bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result);
40 bool DeleteClassifiedRecord(UUID recordId);
41 OSDArray GetAvatarPicks(UUID avatarId);
42 UserProfilePick GetPickInfo(UUID avatarId, UUID pickId);
43 bool UpdatePicksRecord(UserProfilePick pick);
44 bool DeletePicksRecord(UUID pickId);
45 bool GetAvatarNotes(ref UserProfileNotes note);
46 bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result);
47 bool GetAvatarProperties(ref UserProfileProperties props, ref string result);
48 bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result);
49 bool UpdateAvatarInterests(UserProfileProperties up, ref string result);
50 bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result);
51 bool GetUserAppData(ref UserAppData props, ref string result);
52 bool SetUserAppData(UserAppData props, ref string result);
53 OSDArray GetUserImageAssets(UUID avatarId);
54 }
55}
56
diff --git a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs
new file mode 100644
index 0000000..4c6c8e3
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs
@@ -0,0 +1,1096 @@
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.Data;
30using System.Reflection;
31using OpenSim.Data;
32using OpenSim.Framework;
33using MySql.Data.MySqlClient;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using log4net;
37
38namespace OpenSim.Data.MySQL
39{
40 public class UserProfilesData: IProfilesData
41 {
42 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 #region Properites
45 string ConnectionString
46 {
47 get; set;
48 }
49
50 protected object Lock
51 {
52 get; set;
53 }
54
55 protected virtual Assembly Assembly
56 {
57 get { return GetType().Assembly; }
58 }
59
60 #endregion Properties
61
62 #region class Member Functions
63 public UserProfilesData(string connectionString)
64 {
65 ConnectionString = connectionString;
66 Init();
67 }
68
69 void Init()
70 {
71 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
72 {
73 dbcon.Open();
74
75 Migration m = new Migration(dbcon, Assembly, "UserProfiles");
76 m.Update();
77 }
78 }
79 #endregion Member Functions
80
81 #region Classifieds Queries
82 /// <summary>
83 /// Gets the classified records.
84 /// </summary>
85 /// <returns>
86 /// Array of classified records
87 /// </returns>
88 /// <param name='creatorId'>
89 /// Creator identifier.
90 /// </param>
91 public OSDArray GetClassifiedRecords(UUID creatorId)
92 {
93 OSDArray data = new OSDArray();
94
95 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
96 {
97 string query = "SELECT classifieduuid, name FROM classifieds WHERE creatoruuid = ?Id";
98 dbcon.Open();
99 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
100 {
101 cmd.Parameters.AddWithValue("?Id", creatorId);
102 using( MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default))
103 {
104 if(reader.HasRows)
105 {
106 while (reader.Read())
107 {
108 OSDMap n = new OSDMap();
109 UUID Id = UUID.Zero;
110
111 string Name = null;
112 try
113 {
114 UUID.TryParse(Convert.ToString( reader["classifieduuid"]), out Id);
115 Name = Convert.ToString(reader["name"]);
116 }
117 catch (Exception e)
118 {
119 m_log.DebugFormat("[PROFILES_DATA]" +
120 ": UserAccount exception {0}", e.Message);
121 }
122 n.Add("classifieduuid", OSD.FromUUID(Id));
123 n.Add("name", OSD.FromString(Name));
124 data.Add(n);
125 }
126 }
127 }
128 }
129 }
130 return data;
131 }
132
133 public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result)
134 {
135 string query = string.Empty;
136
137
138 query += "INSERT INTO classifieds (";
139 query += "`classifieduuid`,";
140 query += "`creatoruuid`,";
141 query += "`creationdate`,";
142 query += "`expirationdate`,";
143 query += "`category`,";
144 query += "`name`,";
145 query += "`description`,";
146 query += "`parceluuid`,";
147 query += "`parentestate`,";
148 query += "`snapshotuuid`,";
149 query += "`simname`,";
150 query += "`posglobal`,";
151 query += "`parcelname`,";
152 query += "`classifiedflags`,";
153 query += "`priceforlisting`) ";
154 query += "VALUES (";
155 query += "?ClassifiedId,";
156 query += "?CreatorId,";
157 query += "?CreatedDate,";
158 query += "?ExpirationDate,";
159 query += "?Category,";
160 query += "?Name,";
161 query += "?Description,";
162 query += "?ParcelId,";
163 query += "?ParentEstate,";
164 query += "?SnapshotId,";
165 query += "?SimName,";
166 query += "?GlobalPos,";
167 query += "?ParcelName,";
168 query += "?Flags,";
169 query += "?ListingPrice ) ";
170 query += "ON DUPLICATE KEY UPDATE ";
171 query += "category=?Category, ";
172 query += "expirationdate=?ExpirationDate, ";
173 query += "name=?Name, ";
174 query += "description=?Description, ";
175 query += "parentestate=?ParentEstate, ";
176 query += "posglobal=?GlobalPos, ";
177 query += "parcelname=?ParcelName, ";
178 query += "classifiedflags=?Flags, ";
179 query += "priceforlisting=?ListingPrice, ";
180 query += "snapshotuuid=?SnapshotId";
181
182 if(string.IsNullOrEmpty(ad.ParcelName))
183 ad.ParcelName = "Unknown";
184 if(ad.ParcelId == null)
185 ad.ParcelId = UUID.Zero;
186 if(string.IsNullOrEmpty(ad.Description))
187 ad.Description = "No Description";
188
189 DateTime epoch = new DateTime(1970, 1, 1);
190 DateTime now = DateTime.Now;
191 TimeSpan epochnow = now - epoch;
192 TimeSpan duration;
193 DateTime expiration;
194 TimeSpan epochexp;
195
196 if(ad.Flags == 2)
197 {
198 duration = new TimeSpan(7,0,0,0);
199 expiration = now.Add(duration);
200 epochexp = expiration - epoch;
201 }
202 else
203 {
204 duration = new TimeSpan(365,0,0,0);
205 expiration = now.Add(duration);
206 epochexp = expiration - epoch;
207 }
208 ad.CreationDate = (int)epochnow.TotalSeconds;
209 ad.ExpirationDate = (int)epochexp.TotalSeconds;
210
211 try
212 {
213 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
214 {
215 dbcon.Open();
216 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
217 {
218 cmd.Parameters.AddWithValue("?ClassifiedId", ad.ClassifiedId.ToString());
219 cmd.Parameters.AddWithValue("?CreatorId", ad.CreatorId.ToString());
220 cmd.Parameters.AddWithValue("?CreatedDate", ad.CreationDate.ToString());
221 cmd.Parameters.AddWithValue("?ExpirationDate", ad.ExpirationDate.ToString());
222 cmd.Parameters.AddWithValue("?Category", ad.Category.ToString());
223 cmd.Parameters.AddWithValue("?Name", ad.Name.ToString());
224 cmd.Parameters.AddWithValue("?Description", ad.Description.ToString());
225 cmd.Parameters.AddWithValue("?ParcelId", ad.ParcelId.ToString());
226 cmd.Parameters.AddWithValue("?ParentEstate", ad.ParentEstate.ToString());
227 cmd.Parameters.AddWithValue("?SnapshotId", ad.SnapshotId.ToString ());
228 cmd.Parameters.AddWithValue("?SimName", ad.SimName.ToString());
229 cmd.Parameters.AddWithValue("?GlobalPos", ad.GlobalPos.ToString());
230 cmd.Parameters.AddWithValue("?ParcelName", ad.ParcelName.ToString());
231 cmd.Parameters.AddWithValue("?Flags", ad.Flags.ToString());
232 cmd.Parameters.AddWithValue("?ListingPrice", ad.Price.ToString ());
233
234 cmd.ExecuteNonQuery();
235 }
236 }
237 }
238 catch (Exception e)
239 {
240 m_log.DebugFormat("[PROFILES_DATA]" +
241 ": ClassifiedesUpdate exception {0}", e.Message);
242 result = e.Message;
243 return false;
244 }
245 return true;
246 }
247
248 public bool DeleteClassifiedRecord(UUID recordId)
249 {
250 string query = string.Empty;
251
252 query += "DELETE FROM classifieds WHERE ";
253 query += "classifieduuid = ?ClasifiedId";
254
255 try
256 {
257 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
258 {
259 dbcon.Open();
260
261 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
262 {
263 cmd.Parameters.AddWithValue("?ClassifiedId", recordId.ToString());
264
265 lock(Lock)
266 {
267 cmd.ExecuteNonQuery();
268 }
269 }
270 }
271 }
272 catch (Exception e)
273 {
274 m_log.DebugFormat("[PROFILES_DATA]" +
275 ": DeleteClassifiedRecord exception {0}", e.Message);
276 return false;
277 }
278 return true;
279 }
280
281 public bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result)
282 {
283 string query = string.Empty;
284
285 query += "SELECT * FROM classifieds WHERE ";
286 query += "classifieduuid = ?AdId";
287
288 try
289 {
290 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
291 {
292 dbcon.Open();
293 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
294 {
295 cmd.Parameters.AddWithValue("?AdId", ad.ClassifiedId.ToString());
296
297 using (MySqlDataReader reader = cmd.ExecuteReader())
298 {
299 if(reader.Read ())
300 {
301 ad.CreatorId = new UUID(reader.GetGuid("creatoruuid"));
302 ad.ParcelId = new UUID(reader.GetGuid("parceluuid"));
303 ad.SnapshotId = new UUID(reader.GetGuid("snapshotuuid"));
304 ad.CreationDate = Convert.ToInt32(reader["creationdate"]);
305 ad.ExpirationDate = Convert.ToInt32(reader["expirationdate"]);
306 ad.ParentEstate = Convert.ToInt32(reader["parentestate"]);
307 ad.Flags = (byte)reader.GetUInt32("classifiedflags");
308 ad.Category = reader.GetInt32("category");
309 ad.Price = reader.GetInt16("priceforlisting");
310 ad.Name = reader.GetString("name");
311 ad.Description = reader.GetString("description");
312 ad.SimName = reader.GetString("simname");
313 ad.GlobalPos = reader.GetString("posglobal");
314 ad.ParcelName = reader.GetString("parcelname");
315
316 }
317 }
318 }
319 dbcon.Close();
320 }
321 }
322 catch (Exception e)
323 {
324 m_log.DebugFormat("[PROFILES_DATA]" +
325 ": GetPickInfo exception {0}", e.Message);
326 }
327 return true;
328 }
329 #endregion Classifieds Queries
330
331 #region Picks Queries
332 public OSDArray GetAvatarPicks(UUID avatarId)
333 {
334 string query = string.Empty;
335
336 query += "SELECT `pickuuid`,`name` FROM userpicks WHERE ";
337 query += "creatoruuid = ?Id";
338 OSDArray data = new OSDArray();
339
340 try
341 {
342 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
343 {
344 dbcon.Open();
345 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
346 {
347 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
348
349 using (MySqlDataReader reader = cmd.ExecuteReader())
350 {
351 if(reader.HasRows)
352 {
353 while (reader.Read())
354 {
355 OSDMap record = new OSDMap();
356
357 record.Add("pickuuid",OSD.FromString((string)reader["pickuuid"]));
358 record.Add("name",OSD.FromString((string)reader["name"]));
359 data.Add(record);
360 }
361 }
362 }
363 }
364 }
365 }
366 catch (Exception e)
367 {
368 m_log.DebugFormat("[PROFILES_DATA]" +
369 ": GetAvatarPicks exception {0}", e.Message);
370 }
371 return data;
372 }
373
374 public UserProfilePick GetPickInfo(UUID avatarId, UUID pickId)
375 {
376 string query = string.Empty;
377 UserProfilePick pick = new UserProfilePick();
378
379 query += "SELECT * FROM userpicks WHERE ";
380 query += "creatoruuid = ?CreatorId AND ";
381 query += "pickuuid = ?PickId";
382
383 try
384 {
385 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
386 {
387 dbcon.Open();
388 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
389 {
390 cmd.Parameters.AddWithValue("?CreatorId", avatarId.ToString());
391 cmd.Parameters.AddWithValue("?PickId", pickId.ToString());
392
393 using (MySqlDataReader reader = cmd.ExecuteReader())
394 {
395 if(reader.HasRows)
396 {
397 reader.Read();
398
399 string description = (string)reader["description"];
400
401 if (string.IsNullOrEmpty(description))
402 description = "No description given.";
403
404 UUID.TryParse((string)reader["pickuuid"], out pick.PickId);
405 UUID.TryParse((string)reader["creatoruuid"], out pick.CreatorId);
406 UUID.TryParse((string)reader["parceluuid"], out pick.ParcelId);
407 UUID.TryParse((string)reader["snapshotuuid"], out pick.SnapshotId);
408 pick.GlobalPos = (string)reader["posglobal"];
409 bool.TryParse((string)reader["toppick"], out pick.TopPick);
410 bool.TryParse((string)reader["enabled"], out pick.Enabled);
411 pick.Name = (string)reader["name"];
412 pick.Desc = description;
413 pick.User = (string)reader["user"];
414 pick.OriginalName = (string)reader["originalname"];
415 pick.SimName = (string)reader["simname"];
416 pick.SortOrder = (int)reader["sortorder"];
417 }
418 }
419 }
420 dbcon.Close();
421 }
422 }
423 catch (Exception e)
424 {
425 m_log.DebugFormat("[PROFILES_DATA]" +
426 ": GetPickInfo exception {0}", e.Message);
427 }
428 return pick;
429 }
430
431 public bool UpdatePicksRecord(UserProfilePick pick)
432 {
433 string query = string.Empty;
434
435 query += "INSERT INTO userpicks VALUES (";
436 query += "?PickId,";
437 query += "?CreatorId,";
438 query += "?TopPick,";
439 query += "?ParcelId,";
440 query += "?Name,";
441 query += "?Desc,";
442 query += "?SnapshotId,";
443 query += "?User,";
444 query += "?Original,";
445 query += "?SimName,";
446 query += "?GlobalPos,";
447 query += "?SortOrder,";
448 query += "?Enabled) ";
449 query += "ON DUPLICATE KEY UPDATE ";
450 query += "parceluuid=?ParcelId,";
451 query += "name=?Name,";
452 query += "description=?Desc,";
453 query += "snapshotuuid=?SnapshotId,";
454 query += "pickuuid=?PickId,";
455 query += "posglobal=?GlobalPos";
456
457 try
458 {
459 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
460 {
461 dbcon.Open();
462 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
463 {
464 cmd.Parameters.AddWithValue("?PickId", pick.PickId.ToString());
465 cmd.Parameters.AddWithValue("?CreatorId", pick.CreatorId.ToString());
466 cmd.Parameters.AddWithValue("?TopPick", pick.TopPick.ToString());
467 cmd.Parameters.AddWithValue("?ParcelId", pick.ParcelId.ToString());
468 cmd.Parameters.AddWithValue("?Name", pick.Name.ToString());
469 cmd.Parameters.AddWithValue("?Desc", pick.Desc.ToString());
470 cmd.Parameters.AddWithValue("?SnapshotId", pick.SnapshotId.ToString());
471 cmd.Parameters.AddWithValue("?User", pick.User.ToString());
472 cmd.Parameters.AddWithValue("?Original", pick.OriginalName.ToString());
473 cmd.Parameters.AddWithValue("?SimName",pick.SimName.ToString());
474 cmd.Parameters.AddWithValue("?GlobalPos", pick.GlobalPos);
475 cmd.Parameters.AddWithValue("?SortOrder", pick.SortOrder.ToString ());
476 cmd.Parameters.AddWithValue("?Enabled", pick.Enabled.ToString());
477
478 cmd.ExecuteNonQuery();
479 }
480 }
481 }
482 catch (Exception e)
483 {
484 m_log.DebugFormat("[PROFILES_DATA]" +
485 ": UpdateAvatarNotes exception {0}", e.Message);
486 return false;
487 }
488 return true;
489 }
490
491 public bool DeletePicksRecord(UUID pickId)
492 {
493 string query = string.Empty;
494
495 query += "DELETE FROM userpicks WHERE ";
496 query += "pickuuid = ?PickId";
497
498 try
499 {
500 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
501 {
502 dbcon.Open();
503
504 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
505 {
506 cmd.Parameters.AddWithValue("?PickId", pickId.ToString());
507
508 cmd.ExecuteNonQuery();
509 }
510 }
511 }
512 catch (Exception e)
513 {
514 m_log.DebugFormat("[PROFILES_DATA]" +
515 ": DeleteUserPickRecord exception {0}", e.Message);
516 return false;
517 }
518 return true;
519 }
520 #endregion Picks Queries
521
522 #region Avatar Notes Queries
523 public bool GetAvatarNotes(ref UserProfileNotes notes)
524 { // WIP
525 string query = string.Empty;
526
527 query += "SELECT `notes` FROM usernotes WHERE ";
528 query += "useruuid = ?Id AND ";
529 query += "targetuuid = ?TargetId";
530 OSDArray data = new OSDArray();
531
532 try
533 {
534 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
535 {
536 dbcon.Open();
537 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
538 {
539 cmd.Parameters.AddWithValue("?Id", notes.UserId.ToString());
540 cmd.Parameters.AddWithValue("?TargetId", notes.TargetId.ToString());
541
542 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
543 {
544 if(reader.HasRows)
545 {
546 reader.Read();
547 notes.Notes = OSD.FromString((string)reader["notes"]);
548 }
549 }
550 }
551 }
552 }
553 catch (Exception e)
554 {
555 m_log.DebugFormat("[PROFILES_DATA]" +
556 ": GetAvatarNotes exception {0}", e.Message);
557 }
558 return true;
559 }
560
561 public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result)
562 {
563 string query = string.Empty;
564 bool remove;
565
566 if(string.IsNullOrEmpty(note.Notes))
567 {
568 remove = true;
569 query += "DELETE FROM usernotes WHERE ";
570 query += "useruuid=?UserId AND ";
571 query += "targetuuid=?TargetId";
572 }
573 else
574 {
575 remove = false;
576 query += "INSERT INTO usernotes VALUES ( ";
577 query += "?UserId,";
578 query += "?TargetId,";
579 query += "?Notes )";
580 query += "ON DUPLICATE KEY ";
581 query += "UPDATE ";
582 query += "notes=?Notes";
583 }
584
585 try
586 {
587 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
588 {
589 dbcon.Open();
590 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
591 {
592 if(!remove)
593 cmd.Parameters.AddWithValue("?Notes", note.Notes);
594 cmd.Parameters.AddWithValue("?TargetId", note.TargetId.ToString ());
595 cmd.Parameters.AddWithValue("?UserId", note.UserId.ToString());
596
597 cmd.ExecuteNonQuery();
598 }
599 }
600 }
601 catch (Exception e)
602 {
603 m_log.DebugFormat("[PROFILES_DATA]" +
604 ": UpdateAvatarNotes exception {0}", e.Message);
605 return false;
606 }
607 return true;
608
609 }
610 #endregion Avatar Notes Queries
611
612 #region Avatar Properties
613 public bool GetAvatarProperties(ref UserProfileProperties props, ref string result)
614 {
615 string query = string.Empty;
616
617 query += "SELECT * FROM userprofile WHERE ";
618 query += "useruuid = ?Id";
619
620 try
621 {
622 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
623 {
624 dbcon.Open();
625 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
626 {
627 cmd.Parameters.AddWithValue("?Id", props.UserId.ToString());
628
629 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
630 {
631 if(reader.HasRows)
632 {
633 m_log.DebugFormat("[PROFILES_DATA]" +
634 ": Getting data for {0}.", props.UserId);
635 reader.Read();
636 props.WebUrl = (string)reader["profileURL"];
637 UUID.TryParse((string)reader["profileImage"], out props.ImageId);
638 props.AboutText = (string)reader["profileAboutText"];
639 UUID.TryParse((string)reader["profileFirstImage"], out props.FirstLifeImageId);
640 props.FirstLifeText = (string)reader["profileFirstText"];
641 UUID.TryParse((string)reader["profilePartner"], out props.PartnerId);
642 props.WantToMask = (int)reader["profileWantToMask"];
643 props.WantToText = (string)reader["profileWantToText"];
644 props.SkillsMask = (int)reader["profileSkillsMask"];
645 props.SkillsText = (string)reader["profileSkillsText"];
646 props.Language = (string)reader["profileLanguages"];
647 }
648 else
649 {
650 m_log.DebugFormat("[PROFILES_DATA]" +
651 ": No data for {0}", props.UserId);
652
653 props.WebUrl = string.Empty;
654 props.ImageId = UUID.Zero;
655 props.AboutText = string.Empty;
656 props.FirstLifeImageId = UUID.Zero;
657 props.FirstLifeText = string.Empty;
658 props.PartnerId = UUID.Zero;
659 props.WantToMask = 0;
660 props.WantToText = string.Empty;
661 props.SkillsMask = 0;
662 props.SkillsText = string.Empty;
663 props.Language = string.Empty;
664 props.PublishProfile = false;
665 props.PublishMature = false;
666
667 query = "INSERT INTO userprofile (";
668 query += "useruuid, ";
669 query += "profilePartner, ";
670 query += "profileAllowPublish, ";
671 query += "profileMaturePublish, ";
672 query += "profileURL, ";
673 query += "profileWantToMask, ";
674 query += "profileWantToText, ";
675 query += "profileSkillsMask, ";
676 query += "profileSkillsText, ";
677 query += "profileLanguages, ";
678 query += "profileImage, ";
679 query += "profileAboutText, ";
680 query += "profileFirstImage, ";
681 query += "profileFirstText) VALUES (";
682 query += "?userId, ";
683 query += "?profilePartner, ";
684 query += "?profileAllowPublish, ";
685 query += "?profileMaturePublish, ";
686 query += "?profileURL, ";
687 query += "?profileWantToMask, ";
688 query += "?profileWantToText, ";
689 query += "?profileSkillsMask, ";
690 query += "?profileSkillsText, ";
691 query += "?profileLanguages, ";
692 query += "?profileImage, ";
693 query += "?profileAboutText, ";
694 query += "?profileFirstImage, ";
695 query += "?profileFirstText)";
696
697 dbcon.Close();
698 dbcon.Open();
699
700 using (MySqlCommand put = new MySqlCommand(query, dbcon))
701 {
702 put.Parameters.AddWithValue("?userId", props.UserId.ToString());
703 put.Parameters.AddWithValue("?profilePartner", props.PartnerId.ToString());
704 put.Parameters.AddWithValue("?profileAllowPublish", props.PublishProfile);
705 put.Parameters.AddWithValue("?profileMaturePublish", props.PublishMature);
706 put.Parameters.AddWithValue("?profileURL", props.WebUrl);
707 put.Parameters.AddWithValue("?profileWantToMask", props.WantToMask);
708 put.Parameters.AddWithValue("?profileWantToText", props.WantToText);
709 put.Parameters.AddWithValue("?profileSkillsMask", props.SkillsMask);
710 put.Parameters.AddWithValue("?profileSkillsText", props.SkillsText);
711 put.Parameters.AddWithValue("?profileLanguages", props.Language);
712 put.Parameters.AddWithValue("?profileImage", props.ImageId.ToString());
713 put.Parameters.AddWithValue("?profileAboutText", props.AboutText);
714 put.Parameters.AddWithValue("?profileFirstImage", props.FirstLifeImageId.ToString());
715 put.Parameters.AddWithValue("?profileFirstText", props.FirstLifeText);
716
717 put.ExecuteNonQuery();
718 }
719 }
720 }
721 }
722 }
723 }
724 catch (Exception e)
725 {
726 m_log.DebugFormat("[PROFILES_DATA]" +
727 ": Requst properties exception {0}", e.Message);
728 result = e.Message;
729 return false;
730 }
731 return true;
732 }
733
734 public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result)
735 {
736 string query = string.Empty;
737
738 query += "UPDATE userprofile SET ";
739 query += "profilePartner=?profilePartner, ";
740 query += "profileURL=?profileURL, ";
741 query += "profileImage=?image, ";
742 query += "profileAboutText=?abouttext,";
743 query += "profileFirstImage=?firstlifeimage,";
744 query += "profileFirstText=?firstlifetext ";
745 query += "WHERE useruuid=?uuid";
746
747 try
748 {
749 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
750 {
751 dbcon.Open();
752 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
753 {
754 cmd.Parameters.AddWithValue("?profileURL", props.WebUrl);
755 cmd.Parameters.AddWithValue("?profilePartner", props.PartnerId.ToString());
756 cmd.Parameters.AddWithValue("?image", props.ImageId.ToString());
757 cmd.Parameters.AddWithValue("?abouttext", props.AboutText);
758 cmd.Parameters.AddWithValue("?firstlifeimage", props.FirstLifeImageId.ToString());
759 cmd.Parameters.AddWithValue("?firstlifetext", props.FirstLifeText);
760 cmd.Parameters.AddWithValue("?uuid", props.UserId.ToString());
761
762 cmd.ExecuteNonQuery();
763 }
764 }
765 }
766 catch (Exception e)
767 {
768 m_log.DebugFormat("[PROFILES_DATA]" +
769 ": AgentPropertiesUpdate exception {0}", e.Message);
770
771 return false;
772 }
773 return true;
774 }
775 #endregion Avatar Properties
776
777 #region Avatar Interests
778 public bool UpdateAvatarInterests(UserProfileProperties up, ref string result)
779 {
780 string query = string.Empty;
781
782 query += "UPDATE userprofile SET ";
783 query += "profileWantToMask=?WantMask, ";
784 query += "profileWantToText=?WantText,";
785 query += "profileSkillsMask=?SkillsMask,";
786 query += "profileSkillsText=?SkillsText, ";
787 query += "profileLanguages=?Languages ";
788 query += "WHERE useruuid=?uuid";
789
790 try
791 {
792 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
793 {
794 dbcon.Open();
795 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
796 {
797 cmd.Parameters.AddWithValue("?WantMask", up.WantToMask);
798 cmd.Parameters.AddWithValue("?WantText", up.WantToText);
799 cmd.Parameters.AddWithValue("?SkillsMask", up.SkillsMask);
800 cmd.Parameters.AddWithValue("?SkillsText", up.SkillsText);
801 cmd.Parameters.AddWithValue("?Languages", up.Language);
802 cmd.Parameters.AddWithValue("?uuid", up.UserId.ToString());
803
804 cmd.ExecuteNonQuery();
805 }
806 }
807 }
808 catch (Exception e)
809 {
810 m_log.DebugFormat("[PROFILES_DATA]" +
811 ": AgentInterestsUpdate exception {0}", e.Message);
812 result = e.Message;
813 return false;
814 }
815 return true;
816 }
817 #endregion Avatar Interests
818
819 public OSDArray GetUserImageAssets(UUID avatarId)
820 {
821 OSDArray data = new OSDArray();
822 string query = "SELECT `snapshotuuid` FROM {0} WHERE `creatoruuid` = ?Id";
823
824 // Get classified image assets
825
826
827 try
828 {
829 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
830 {
831 dbcon.Open();
832
833 using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`classifieds`"), dbcon))
834 {
835 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
836
837 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
838 {
839 if(reader.HasRows)
840 {
841 while (reader.Read())
842 {
843 data.Add(new OSDString((string)reader["snapshotuuid"].ToString ()));
844 }
845 }
846 }
847 }
848
849 dbcon.Close();
850 dbcon.Open();
851
852 using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`userpicks`"), dbcon))
853 {
854 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
855
856 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
857 {
858 if(reader.HasRows)
859 {
860 while (reader.Read())
861 {
862 data.Add(new OSDString((string)reader["snapshotuuid"].ToString ()));
863 }
864 }
865 }
866 }
867
868 dbcon.Close();
869 dbcon.Open();
870
871 query = "SELECT `profileImage`, `profileFirstImage` FROM `userprofile` WHERE `useruuid` = ?Id";
872
873 using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`userpicks`"), dbcon))
874 {
875 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
876
877 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
878 {
879 if(reader.HasRows)
880 {
881 while (reader.Read())
882 {
883 data.Add(new OSDString((string)reader["profileImage"].ToString ()));
884 data.Add(new OSDString((string)reader["profileFirstImage"].ToString ()));
885 }
886 }
887 }
888 }
889 }
890 }
891 catch (Exception e)
892 {
893 m_log.DebugFormat("[PROFILES_DATA]" +
894 ": GetAvatarNotes exception {0}", e.Message);
895 }
896 return data;
897 }
898
899 #region User Preferences
900 public OSDArray GetUserPreferences(UUID avatarId)
901 {
902 string query = string.Empty;
903
904 query += "SELECT imviaemail,visible,email FROM ";
905 query += "usersettings WHERE ";
906 query += "useruuid = ?Id";
907
908 OSDArray data = new OSDArray();
909
910 try
911 {
912 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
913 {
914 dbcon.Open();
915 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
916 {
917 cmd.Parameters.AddWithValue("?Id", avatarId.ToString());
918
919 using (MySqlDataReader reader = cmd.ExecuteReader())
920 {
921 if(reader.HasRows)
922 {
923 reader.Read();
924 OSDMap record = new OSDMap();
925
926 record.Add("imviaemail",OSD.FromString((string)reader["imviaemail"]));
927 record.Add("visible",OSD.FromString((string)reader["visible"]));
928 record.Add("email",OSD.FromString((string)reader["email"]));
929 data.Add(record);
930 }
931 else
932 {
933 using (MySqlCommand put = new MySqlCommand(query, dbcon))
934 {
935 query = "INSERT INTO usersettings VALUES ";
936 query += "(?Id,'false','false', '')";
937
938 lock(Lock)
939 {
940 put.ExecuteNonQuery();
941 }
942 }
943 }
944 }
945 }
946 }
947 }
948 catch (Exception e)
949 {
950 m_log.DebugFormat("[PROFILES_DATA]" +
951 ": Get preferences exception {0}", e.Message);
952 }
953 return data;
954 }
955
956 public bool UpdateUserPreferences(bool emailIm, bool visible, UUID avatarId )
957 {
958 string query = string.Empty;
959
960 query += "UPDATE userpsettings SET ";
961 query += "imviaemail=?ImViaEmail, ";
962 query += "visible=?Visible,";
963 query += "WHERE useruuid=?uuid";
964
965 try
966 {
967 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
968 {
969 dbcon.Open();
970 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
971 {
972 cmd.Parameters.AddWithValue("?ImViaEmail", emailIm.ToString().ToLower ());
973 cmd.Parameters.AddWithValue("?WantText", visible.ToString().ToLower ());
974 cmd.Parameters.AddWithValue("?uuid", avatarId.ToString());
975
976 lock(Lock)
977 {
978 cmd.ExecuteNonQuery();
979 }
980 }
981 }
982 }
983 catch (Exception e)
984 {
985 m_log.DebugFormat("[PROFILES_DATA]" +
986 ": AgentInterestsUpdate exception {0}", e.Message);
987 return false;
988 }
989 return true;
990 }
991 #endregion User Preferences
992
993 #region Integration
994 public bool GetUserAppData(ref UserAppData props, ref string result)
995 {
996 string query = string.Empty;
997
998 query += "SELECT * FROM `userdata` WHERE ";
999 query += "UserId = ?Id AND ";
1000 query += "TagId = ?TagId";
1001
1002 try
1003 {
1004 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
1005 {
1006 dbcon.Open();
1007 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
1008 {
1009 cmd.Parameters.AddWithValue("?Id", props.UserId.ToString());
1010 cmd.Parameters.AddWithValue ("?TagId", props.TagId.ToString());
1011
1012 using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
1013 {
1014 if(reader.HasRows)
1015 {
1016 reader.Read();
1017 props.DataKey = (string)reader["DataKey"];
1018 props.DataVal = (string)reader["DataVal"];
1019 }
1020 else
1021 {
1022 query += "INSERT INTO userdata VALUES ( ";
1023 query += "?UserId,";
1024 query += "?TagId,";
1025 query += "?DataKey,";
1026 query += "?DataVal) ";
1027
1028 using (MySqlCommand put = new MySqlCommand(query, dbcon))
1029 {
1030 put.Parameters.AddWithValue("?Id", props.UserId.ToString());
1031 put.Parameters.AddWithValue("?TagId", props.TagId.ToString());
1032 put.Parameters.AddWithValue("?DataKey", props.DataKey.ToString());
1033 put.Parameters.AddWithValue("?DataVal", props.DataVal.ToString());
1034
1035 lock(Lock)
1036 {
1037 put.ExecuteNonQuery();
1038 }
1039 }
1040 }
1041 }
1042 }
1043 }
1044 }
1045 catch (Exception e)
1046 {
1047 m_log.DebugFormat("[PROFILES_DATA]" +
1048 ": Requst application data exception {0}", e.Message);
1049 result = e.Message;
1050 return false;
1051 }
1052 return true;
1053 }
1054
1055 public bool SetUserAppData(UserAppData props, ref string result)
1056 {
1057 string query = string.Empty;
1058
1059 query += "UPDATE userdata SET ";
1060 query += "TagId = ?TagId, ";
1061 query += "DataKey = ?DataKey, ";
1062 query += "DataVal = ?DataVal WHERE ";
1063 query += "UserId = ?UserId AND ";
1064 query += "TagId = ?TagId";
1065
1066 try
1067 {
1068 using (MySqlConnection dbcon = new MySqlConnection(ConnectionString))
1069 {
1070 dbcon.Open();
1071 using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
1072 {
1073 cmd.Parameters.AddWithValue("?UserId", props.UserId.ToString());
1074 cmd.Parameters.AddWithValue("?TagId", props.TagId.ToString ());
1075 cmd.Parameters.AddWithValue("?DataKey", props.DataKey.ToString ());
1076 cmd.Parameters.AddWithValue("?DataVal", props.DataKey.ToString ());
1077
1078 lock(Lock)
1079 {
1080 cmd.ExecuteNonQuery();
1081 }
1082 }
1083 }
1084 }
1085 catch (Exception e)
1086 {
1087 m_log.DebugFormat("[PROFILES_DATA]" +
1088 ": SetUserData exception {0}", e.Message);
1089 return false;
1090 }
1091 return true;
1092 }
1093 #endregion Integration
1094 }
1095}
1096
diff --git a/OpenSim/Data/MySQL/Resources/UserProfiles.migrations b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations
new file mode 100644
index 0000000..c29f1ab
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations
@@ -0,0 +1,83 @@
1:VERSION 1 # -------------------------------
2
3begin;
4
5CREATE TABLE IF NOT EXISTS `classifieds` (
6 `classifieduuid` char(36) NOT NULL,
7 `creatoruuid` char(36) NOT NULL,
8 `creationdate` int(20) NOT NULL,
9 `expirationdate` int(20) NOT NULL,
10 `category` varchar(20) NOT NULL,
11 `name` varchar(255) NOT NULL,
12 `description` text NOT NULL,
13 `parceluuid` char(36) NOT NULL,
14 `parentestate` int(11) NOT NULL,
15 `snapshotuuid` char(36) NOT NULL,
16 `simname` varchar(255) NOT NULL,
17 `posglobal` varchar(255) NOT NULL,
18 `parcelname` varchar(255) NOT NULL,
19 `classifiedflags` int(8) NOT NULL,
20 `priceforlisting` int(5) NOT NULL,
21 PRIMARY KEY (`classifieduuid`)
22) ENGINE=InnoDB DEFAULT CHARSET=latin1;
23
24
25CREATE TABLE IF NOT EXISTS `usernotes` (
26 `useruuid` varchar(36) NOT NULL,
27 `targetuuid` varchar(36) NOT NULL,
28 `notes` text NOT NULL,
29 UNIQUE KEY `useruuid` (`useruuid`,`targetuuid`)
30) ENGINE=MyISAM DEFAULT CHARSET=latin1;
31
32
33CREATE TABLE IF NOT EXISTS `userpicks` (
34 `pickuuid` varchar(36) NOT NULL,
35 `creatoruuid` varchar(36) NOT NULL,
36 `toppick` enum('true','false') NOT NULL,
37 `parceluuid` varchar(36) NOT NULL,
38 `name` varchar(255) NOT NULL,
39 `description` text NOT NULL,
40 `snapshotuuid` varchar(36) NOT NULL,
41 `user` varchar(255) NOT NULL,
42 `originalname` varchar(255) NOT NULL,
43 `simname` varchar(255) NOT NULL,
44 `posglobal` varchar(255) NOT NULL,
45 `sortorder` int(2) NOT NULL,
46 `enabled` enum('true','false') NOT NULL,
47 PRIMARY KEY (`pickuuid`)
48) ENGINE=MyISAM DEFAULT CHARSET=latin1;
49
50
51CREATE TABLE IF NOT EXISTS `userprofile` (
52 `useruuid` varchar(36) NOT NULL,
53 `profilePartner` varchar(36) NOT NULL,
54 `profileAllowPublish` binary(1) NOT NULL,
55 `profileMaturePublish` binary(1) NOT NULL,
56 `profileURL` varchar(255) NOT NULL,
57 `profileWantToMask` int(3) NOT NULL,
58 `profileWantToText` text NOT NULL,
59 `profileSkillsMask` int(3) NOT NULL,
60 `profileSkillsText` text NOT NULL,
61 `profileLanguages` text NOT NULL,
62 `profileImage` varchar(36) NOT NULL,
63 `profileAboutText` text NOT NULL,
64 `profileFirstImage` varchar(36) NOT NULL,
65 `profileFirstText` text NOT NULL,
66 PRIMARY KEY (`useruuid`)
67) ENGINE=MyISAM DEFAULT CHARSET=latin1;
68
69commit;
70
71:VERSION 2 # -------------------------------
72
73begin;
74CREATE TABLE IF NOT EXISTS `userdata` (
75 `UserId` char(36) NOT NULL,
76 `TagId` varchar(64) NOT NULL,
77 `DataKey` varchar(255),
78 `DataVal` varchar(255),
79 PRIMARY KEY (`UserId`,`TagId`)
80) ENGINE=MyISAM DEFAULT CHARSET=latin1;
81
82commit;
83
diff --git a/OpenSim/Framework/Animation.cs b/OpenSim/Framework/Animation.cs
index 232f5a1..8bdf8f4 100644
--- a/OpenSim/Framework/Animation.cs
+++ b/OpenSim/Framework/Animation.cs
@@ -120,5 +120,25 @@ namespace OpenSim.Framework
120 sequenceNum = args["seq_num"].AsInteger(); 120 sequenceNum = args["seq_num"].AsInteger();
121 } 121 }
122 122
123 public override bool Equals(object obj)
124 {
125 Animation other = obj as Animation;
126 if (other != null)
127 {
128 return (other.AnimID == this.AnimID
129 && other.SequenceNum == this.SequenceNum
130 && other.ObjectID == this.ObjectID);
131 }
132
133 return base.Equals(obj);
134 }
135
136 public override string ToString()
137 {
138 return "AnimID=" + AnimID.ToString()
139 + "/seq=" + SequenceNum.ToString()
140 + "/objID=" + ObjectID.ToString();
141 }
142
123 } 143 }
124} 144}
diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs
new file mode 100644
index 0000000..6133591
--- /dev/null
+++ b/OpenSim/Framework/UserProfiles.cs
@@ -0,0 +1,117 @@
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 OpenMetaverse;
30
31namespace OpenSim.Framework
32{
33 public class UserClassifiedAdd
34 {
35 public UUID ClassifiedId = UUID.Zero;
36 public UUID CreatorId = UUID.Zero;
37 public int CreationDate = 0;
38 public int ExpirationDate = 0;
39 public int Category = 0;
40 public string Name = string.Empty;
41 public string Description = string.Empty;
42 public UUID ParcelId = UUID.Zero;
43 public int ParentEstate = 0;
44 public UUID SnapshotId = UUID.Zero;
45 public string SimName = string.Empty;
46 public string GlobalPos = "<0,0,0>";
47 public string ParcelName = string.Empty;
48 public byte Flags = 0;
49 public int Price = 0;
50 }
51
52 public class UserProfileProperties
53 {
54 public UUID UserId = UUID.Zero;
55 public UUID PartnerId = UUID.Zero;
56 public bool PublishProfile = false;
57 public bool PublishMature = false;
58 public string WebUrl = string.Empty;
59 public int WantToMask = 0;
60 public string WantToText = string.Empty;
61 public int SkillsMask = 0;
62 public string SkillsText = string.Empty;
63 public string Language = string.Empty;
64 public UUID ImageId = UUID.Zero;
65 public string AboutText = string.Empty;
66 public UUID FirstLifeImageId = UUID.Zero;
67 public string FirstLifeText = string.Empty;
68 }
69
70 public class UserProfilePick
71 {
72 public UUID PickId = UUID.Zero;
73 public UUID CreatorId = UUID.Zero;
74 public bool TopPick = false;
75 public string Name = string.Empty;
76 public string OriginalName = string.Empty;
77 public string Desc = string.Empty;
78 public UUID ParcelId = UUID.Zero;
79 public UUID SnapshotId = UUID.Zero;
80 public string User = string.Empty;
81 public string SimName = string.Empty;
82 public string GlobalPos = "<0,0,0>";
83 public int SortOrder = 0;
84 public bool Enabled = false;
85 }
86
87 public class UserProfileNotes
88 {
89 public UUID UserId;
90 public UUID TargetId;
91 public string Notes;
92 }
93
94 public class UserAccountProperties
95 {
96 public string EmailAddress = string.Empty;
97 public string Firstname = string.Empty;
98 public string LastName = string.Empty;
99 public string Password = string.Empty;
100 public string UserId = string.Empty;
101 }
102
103 public class UserAccountAuth
104 {
105 public string UserId = UUID.Zero.ToString();
106 public string Password = string.Empty;
107 }
108
109 public class UserAppData
110 {
111 public string TagId = string.Empty;
112 public string DataKey = string.Empty;
113 public string UserId = UUID.Zero.ToString();
114 public string DataVal = string.Empty;
115 }
116}
117
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
index 89a4d30..d22f3f4 100644
--- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
@@ -26,27 +26,25 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic;
30using Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Region.Framework.Interfaces;
35using System;
36using System.Reflection;
37using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
38using System.Collections.Specialized; 31using System.Collections.Specialized;
39using System.Reflection;
40using System.IO; 32using System.IO;
33using System.Reflection;
41using System.Web; 34using System.Web;
42using System.Xml; 35using System.Xml;
43using log4net; 36using log4net;
44using Mono.Addins; 37using Mono.Addins;
38using Nini.Config;
39using OpenMetaverse;
45using OpenMetaverse.Messages.Linden; 40using OpenMetaverse.Messages.Linden;
46using OpenMetaverse.StructuredData; 41using OpenMetaverse.StructuredData;
42using OpenSim.Framework;
47using OpenSim.Framework.Capabilities; 43using OpenSim.Framework.Capabilities;
48using OpenSim.Framework.Servers; 44using OpenSim.Framework.Servers;
49using OpenSim.Framework.Servers.HttpServer; 45using OpenSim.Framework.Servers.HttpServer;
46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Region.Framework.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps; 48using Caps = OpenSim.Framework.Capabilities.Caps;
51using OSDArray = OpenMetaverse.StructuredData.OSDArray; 49using OSDArray = OpenMetaverse.StructuredData.OSDArray;
52using OSDMap = OpenMetaverse.StructuredData.OSDMap; 50using OSDMap = OpenMetaverse.StructuredData.OSDMap;
diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
new file mode 100644
index 0000000..5b228ee
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
@@ -0,0 +1,1328 @@
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.IO;
30using System.Text;
31using System.Collections;
32using System.Collections.Generic;
33using System.Globalization;
34using System.Net;
35using System.Net.Sockets;
36using System.Reflection;
37using System.Xml;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using log4net;
41using Nini.Config;
42using Nwc.XmlRpc;
43using OpenSim.Framework;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Services.Interfaces;
47using Mono.Addins;
48using OpenSim.Services.Connectors.Hypergrid;
49
50namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
51{
52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")]
53 public class UserProfileModule : IProfileModule, INonSharedRegionModule
54 {
55 /// <summary>
56 /// Logging
57 /// </summary>
58 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59
60 // The pair of Dictionaries are used to handle the switching of classified ads
61 // by maintaining a cache of classified id to creator id mappings and an interest
62 // count. The entries are removed when the interest count reaches 0.
63 Dictionary<UUID,UUID> classifiedCache = new Dictionary<UUID, UUID>();
64 Dictionary<UUID,int> classifiedInterest = new Dictionary<UUID, int>();
65
66 public Scene Scene
67 {
68 get; private set;
69 }
70
71 /// <summary>
72 /// Gets or sets the ConfigSource.
73 /// </summary>
74 /// <value>
75 /// The configuration
76 /// </value>
77 public IConfigSource Config {
78 get;
79 set;
80 }
81
82 /// <summary>
83 /// Gets or sets the URI to the profile server.
84 /// </summary>
85 /// <value>
86 /// The profile server URI.
87 /// </value>
88 public string ProfileServerUri {
89 get;
90 set;
91 }
92
93 IProfileModule ProfileModule
94 {
95 get; set;
96 }
97
98 IUserManagement UserManagementModule
99 {
100 get; set;
101 }
102
103 /// <summary>
104 /// Gets or sets a value indicating whether this
105 /// <see cref="BlueWall.SlipStream.ProfileModule.UserProfileModule"/> is enabled.
106 /// </summary>
107 /// <value>
108 /// <c>true</c> if enabled; otherwise, <c>false</c>.
109 /// </value>
110 public bool Enabled {
111 get;
112 set;
113 }
114
115 #region IRegionModuleBase implementation
116 /// <summary>
117 /// This is called to initialize the region module. For shared modules, this is called exactly once, after
118 /// creating the single (shared) instance. For non-shared modules, this is called once on each instance, after
119 /// the instace for the region has been created.
120 /// </summary>
121 /// <param name='source'>
122 /// Source.
123 /// </param>
124 public void Initialise(IConfigSource source)
125 {
126 Config = source;
127 ReplaceableInterface = typeof(IProfileModule);
128
129 IConfig profileConfig = Config.Configs["UserProfiles"];
130
131 if (profileConfig == null)
132 {
133 Enabled = false;
134 return;
135 }
136
137 // If we find ProfileURL then we configure for FULL support
138 // else we setup for BASIC support
139 ProfileServerUri = profileConfig.GetString("ProfileServiceURL", "");
140 if (ProfileServerUri == "")
141 {
142 Enabled = false;
143 return;
144 }
145
146 m_log.Debug("[PROFILES]: Full Profiles Enabled");
147 ReplaceableInterface = null;
148 Enabled = true;
149 }
150
151 /// <summary>
152 /// Adds the region.
153 /// </summary>
154 /// <param name='scene'>
155 /// Scene.
156 /// </param>
157 public void AddRegion(Scene scene)
158 {
159 if(!Enabled)
160 return;
161
162 Scene = scene;
163 Scene.RegisterModuleInterface<IProfileModule>(this);
164 Scene.EventManager.OnNewClient += OnNewClient;
165 Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent;
166
167 UserManagementModule = Scene.RequestModuleInterface<IUserManagement>();
168 }
169
170 void HandleOnMakeRootAgent (ScenePresence obj)
171 {
172 GetImageAssets(((IScenePresence)obj).UUID);
173 }
174
175 /// <summary>
176 /// Removes the region.
177 /// </summary>
178 /// <param name='scene'>
179 /// Scene.
180 /// </param>
181 public void RemoveRegion(Scene scene)
182 {
183 if(!Enabled)
184 return;
185 }
186
187 /// <summary>
188 /// This will be called once for every scene loaded. In a shared module this will be multiple times in one
189 /// instance, while a nonshared module instance will only be called once. This method is called after AddRegion
190 /// has been called in all modules for that scene, providing an opportunity to request another module's
191 /// interface, or hook an event from another module.
192 /// </summary>
193 /// <param name='scene'>
194 /// Scene.
195 /// </param>
196 public void RegionLoaded(Scene scene)
197 {
198 if(!Enabled)
199 return;
200 }
201
202 /// <summary>
203 /// If this returns non-null, it is the type of an interface that this module intends to register. This will
204 /// cause the loader to defer loading of this module until all other modules have been loaded. If no other
205 /// module has registered the interface by then, this module will be activated, else it will remain inactive,
206 /// letting the other module take over. This should return non-null ONLY in modules that are intended to be
207 /// easily replaceable, e.g. stub implementations that the developer expects to be replaced by third party
208 /// provided modules.
209 /// </summary>
210 /// <value>
211 /// The replaceable interface.
212 /// </value>
213 public Type ReplaceableInterface
214 {
215 get; private set;
216 }
217
218 /// <summary>
219 /// Called as the instance is closed.
220 /// </summary>
221 public void Close()
222 {
223 }
224
225 /// <value>
226 /// The name of the module
227 /// </value>
228 /// <summary>
229 /// Gets the module name.
230 /// </summary>
231 public string Name
232 {
233 get { return "UserProfileModule"; }
234 }
235 #endregion IRegionModuleBase implementation
236
237 #region Region Event Handlers
238 /// <summary>
239 /// Raises the new client event.
240 /// </summary>
241 /// <param name='client'>
242 /// Client.
243 /// </param>
244 void OnNewClient(IClientAPI client)
245 {
246 //Profile
247 client.OnRequestAvatarProperties += RequestAvatarProperties;
248 client.OnUpdateAvatarProperties += AvatarPropertiesUpdate;
249 client.OnAvatarInterestUpdate += AvatarInterestsUpdate;
250
251 // Classifieds
252 client.AddGenericPacketHandler("avatarclassifiedsrequest", ClassifiedsRequest);
253 client.OnClassifiedInfoUpdate += ClassifiedInfoUpdate;
254 client.OnClassifiedInfoRequest += ClassifiedInfoRequest;
255 client.OnClassifiedDelete += ClassifiedDelete;
256
257 // Picks
258 client.AddGenericPacketHandler("avatarpicksrequest", PicksRequest);
259 client.AddGenericPacketHandler("pickinforequest", PickInfoRequest);
260 client.OnPickInfoUpdate += PickInfoUpdate;
261 client.OnPickDelete += PickDelete;
262
263 // Notes
264 client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest);
265 client.OnAvatarNotesUpdate += NotesUpdate;
266 }
267 #endregion Region Event Handlers
268
269 #region Classified
270 ///
271 /// <summary>
272 /// Handles the avatar classifieds request.
273 /// </summary>
274 /// <param name='sender'>
275 /// Sender.
276 /// </param>
277 /// <param name='method'>
278 /// Method.
279 /// </param>
280 /// <param name='args'>
281 /// Arguments.
282 /// </param>
283 public void ClassifiedsRequest(Object sender, string method, List<String> args)
284 {
285 if (!(sender is IClientAPI))
286 return;
287
288 IClientAPI remoteClient = (IClientAPI)sender;
289
290 UUID targetID;
291 UUID.TryParse(args[0], out targetID);
292
293 // Can't handle NPC yet...
294 ScenePresence p = FindPresence(targetID);
295
296 if (null != p)
297 {
298 if (p.PresenceType == PresenceType.Npc)
299 return;
300 }
301
302 string serverURI = string.Empty;
303 bool foreign = GetUserProfileServerURI(targetID, out serverURI);
304 UUID creatorId = UUID.Zero;
305
306 OSDMap parameters= new OSDMap();
307 UUID.TryParse(args[0], out creatorId);
308 parameters.Add("creatorId", OSD.FromUUID(creatorId));
309 OSD Params = (OSD)parameters;
310 if(!JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString()))
311 {
312 // Error Handling here!
313 // if(parameters.ContainsKey("message")
314 }
315
316 parameters = (OSDMap)Params;
317
318 OSDArray list = (OSDArray)parameters["result"];
319
320 Dictionary<UUID, string> classifieds = new Dictionary<UUID, string>();
321
322 foreach(OSD map in list)
323 {
324 OSDMap m = (OSDMap)map;
325 UUID cid = m["classifieduuid"].AsUUID();
326 string name = m["name"].AsString();
327
328 classifieds[cid] = name;
329
330 if(!classifiedCache.ContainsKey(cid))
331 {
332 classifiedCache.Add(cid,creatorId);
333 classifiedInterest.Add(cid, 0);
334 }
335
336 classifiedInterest[cid] ++;
337 }
338
339 remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds);
340 }
341
342 public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient)
343 {
344 UUID target = remoteClient.AgentId;
345 UserClassifiedAdd ad = new UserClassifiedAdd();
346 ad.ClassifiedId = queryClassifiedID;
347
348 if(classifiedCache.ContainsKey(queryClassifiedID))
349 {
350 target = classifiedCache[queryClassifiedID];
351
352 if(classifiedInterest[queryClassifiedID] -- == 0)
353 {
354 lock(classifiedCache)
355 {
356 lock(classifiedInterest)
357 {
358 classifiedInterest.Remove(queryClassifiedID);
359 }
360 classifiedCache.Remove(queryClassifiedID);
361 }
362 }
363 }
364
365
366 string serverURI = string.Empty;
367 bool foreign = GetUserProfileServerURI(target, out serverURI);
368
369 object Ad = (object)ad;
370 if(!JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString()))
371 {
372 remoteClient.SendAgentAlertMessage(
373 "Error getting classified info", false);
374 return;
375 }
376 ad = (UserClassifiedAdd) Ad;
377
378 if(ad.CreatorId == UUID.Zero)
379 return;
380
381 Vector3 globalPos = new Vector3();
382 Vector3.TryParse(ad.GlobalPos, out globalPos);
383
384 remoteClient.SendClassifiedInfoReply(ad.ClassifiedId, ad.CreatorId, (uint)ad.CreationDate, (uint)ad.ExpirationDate,
385 (uint)ad.Category, ad.Name, ad.Description, ad.ParcelId, (uint)ad.ParentEstate,
386 ad.SnapshotId, ad.SimName, globalPos, ad.ParcelName, ad.Flags, ad.Price);
387
388 }
389
390 /// <summary>
391 /// Classifieds info update.
392 /// </summary>
393 /// <param name='queryclassifiedID'>
394 /// Queryclassified I.
395 /// </param>
396 /// <param name='queryCategory'>
397 /// Query category.
398 /// </param>
399 /// <param name='queryName'>
400 /// Query name.
401 /// </param>
402 /// <param name='queryDescription'>
403 /// Query description.
404 /// </param>
405 /// <param name='queryParcelID'>
406 /// Query parcel I.
407 /// </param>
408 /// <param name='queryParentEstate'>
409 /// Query parent estate.
410 /// </param>
411 /// <param name='querySnapshotID'>
412 /// Query snapshot I.
413 /// </param>
414 /// <param name='queryGlobalPos'>
415 /// Query global position.
416 /// </param>
417 /// <param name='queryclassifiedFlags'>
418 /// Queryclassified flags.
419 /// </param>
420 /// <param name='queryclassifiedPrice'>
421 /// Queryclassified price.
422 /// </param>
423 /// <param name='remoteClient'>
424 /// Remote client.
425 /// </param>
426 public void ClassifiedInfoUpdate(UUID queryclassifiedID, uint queryCategory, string queryName, string queryDescription, UUID queryParcelID,
427 uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags,
428 int queryclassifiedPrice, IClientAPI remoteClient)
429 {
430 UserClassifiedAdd ad = new UserClassifiedAdd();
431
432 Scene s = (Scene) remoteClient.Scene;
433 Vector3 pos = remoteClient.SceneAgent.AbsolutePosition;
434 ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y);
435 ScenePresence p = FindPresence(remoteClient.AgentId);
436 Vector3 avaPos = p.AbsolutePosition;
437
438 string serverURI = string.Empty;
439 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
440
441 if (land == null)
442 {
443 ad.ParcelName = string.Empty;
444 }
445 else
446 {
447 ad.ParcelName = land.LandData.Name;
448 }
449
450 ad.CreatorId = remoteClient.AgentId;
451 ad.ClassifiedId = queryclassifiedID;
452 ad.Category = Convert.ToInt32(queryCategory);
453 ad.Name = queryName;
454 ad.Description = queryDescription;
455 ad.ParentEstate = Convert.ToInt32(queryParentEstate);
456 ad.SnapshotId = querySnapshotID;
457 ad.SimName = remoteClient.Scene.RegionInfo.RegionName;
458 ad.GlobalPos = queryGlobalPos.ToString ();
459 ad.Flags = queryclassifiedFlags;
460 ad.Price = queryclassifiedPrice;
461 ad.ParcelId = p.currentParcelUUID;
462
463 object Ad = ad;
464
465 OSD X = OSD.SerializeMembers(Ad);
466
467 if(!JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString()))
468 {
469 remoteClient.SendAgentAlertMessage(
470 "Error updating classified", false);
471 }
472 }
473
474 /// <summary>
475 /// Classifieds delete.
476 /// </summary>
477 /// <param name='queryClassifiedID'>
478 /// Query classified I.
479 /// </param>
480 /// <param name='remoteClient'>
481 /// Remote client.
482 /// </param>
483 public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient)
484 {
485 string serverURI = string.Empty;
486 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
487
488 UUID classifiedId;
489 OSDMap parameters= new OSDMap();
490 UUID.TryParse(queryClassifiedID.ToString(), out classifiedId);
491 parameters.Add("classifiedId", OSD.FromUUID(classifiedId));
492 OSD Params = (OSD)parameters;
493 if(!JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString()))
494 {
495 remoteClient.SendAgentAlertMessage(
496 "Error classified delete", false);
497 }
498
499 parameters = (OSDMap)Params;
500 }
501 #endregion Classified
502
503 #region Picks
504 /// <summary>
505 /// Handles the avatar picks request.
506 /// </summary>
507 /// <param name='sender'>
508 /// Sender.
509 /// </param>
510 /// <param name='method'>
511 /// Method.
512 /// </param>
513 /// <param name='args'>
514 /// Arguments.
515 /// </param>
516 public void PicksRequest(Object sender, string method, List<String> args)
517 {
518 if (!(sender is IClientAPI))
519 return;
520
521 IClientAPI remoteClient = (IClientAPI)sender;
522
523 UUID targetId;
524 UUID.TryParse(args[0], out targetId);
525
526 // Can't handle NPC yet...
527 ScenePresence p = FindPresence(targetId);
528
529 if (null != p)
530 {
531 if (p.PresenceType == PresenceType.Npc)
532 return;
533 }
534
535 string serverURI = string.Empty;
536 bool foreign = GetUserProfileServerURI(targetId, out serverURI);
537
538 OSDMap parameters= new OSDMap();
539 parameters.Add("creatorId", OSD.FromUUID(targetId));
540 OSD Params = (OSD)parameters;
541 if(!JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString()))
542 {
543 remoteClient.SendAgentAlertMessage(
544 "Error requesting picks", false);
545 return;
546 }
547
548 parameters = (OSDMap)Params;
549
550 OSDArray list = (OSDArray)parameters["result"];
551
552 Dictionary<UUID, string> picks = new Dictionary<UUID, string>();
553
554 foreach(OSD map in list)
555 {
556 OSDMap m = (OSDMap)map;
557 UUID cid = m["pickuuid"].AsUUID();
558 string name = m["name"].AsString();
559
560 m_log.DebugFormat("[PROFILES]: PicksRequest {0}", name);
561
562 picks[cid] = name;
563 }
564 remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks);
565 }
566
567 /// <summary>
568 /// Handles the pick info request.
569 /// </summary>
570 /// <param name='sender'>
571 /// Sender.
572 /// </param>
573 /// <param name='method'>
574 /// Method.
575 /// </param>
576 /// <param name='args'>
577 /// Arguments.
578 /// </param>
579 public void PickInfoRequest(Object sender, string method, List<String> args)
580 {
581 if (!(sender is IClientAPI))
582 return;
583
584 UUID targetID;
585 UUID.TryParse(args[0], out targetID);
586 string serverURI = string.Empty;
587 bool foreign = GetUserProfileServerURI(targetID, out serverURI);
588 IClientAPI remoteClient = (IClientAPI)sender;
589
590 UserProfilePick pick = new UserProfilePick();
591 UUID.TryParse(args[0], out pick.CreatorId);
592 UUID.TryParse(args[1], out pick.PickId);
593
594
595 object Pick = (object)pick;
596 if(!JsonRpcRequest(ref Pick, "pickinforequest", serverURI, UUID.Random().ToString()))
597 {
598 remoteClient.SendAgentAlertMessage(
599 "Error selecting pick", false);
600 }
601 pick = (UserProfilePick) Pick;
602 if(pick.SnapshotId == UUID.Zero)
603 {
604 // In case of a new UserPick, the data may not be ready and we would send wrong data, skip it...
605 m_log.DebugFormat("[PROFILES]: PickInfoRequest: SnapshotID is {0}", UUID.Zero.ToString());
606 return;
607 }
608
609 Vector3 globalPos;
610 Vector3.TryParse(pick.GlobalPos,out globalPos);
611
612 m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString());
613
614 remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name,
615 pick.Desc,pick.SnapshotId,pick.User,pick.OriginalName,pick.SimName,
616 globalPos,pick.SortOrder,pick.Enabled);
617 }
618
619 /// <summary>
620 /// Updates the userpicks
621 /// </summary>
622 /// <param name='remoteClient'>
623 /// Remote client.
624 /// </param>
625 /// <param name='pickID'>
626 /// Pick I.
627 /// </param>
628 /// <param name='creatorID'>
629 /// the creator of the pick
630 /// </param>
631 /// <param name='topPick'>
632 /// Top pick.
633 /// </param>
634 /// <param name='name'>
635 /// Name.
636 /// </param>
637 /// <param name='desc'>
638 /// Desc.
639 /// </param>
640 /// <param name='snapshotID'>
641 /// Snapshot I.
642 /// </param>
643 /// <param name='sortOrder'>
644 /// Sort order.
645 /// </param>
646 /// <param name='enabled'>
647 /// Enabled.
648 /// </param>
649 public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled)
650 {
651
652 m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString());
653 UserProfilePick pick = new UserProfilePick();
654 string serverURI = string.Empty;
655 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
656 ScenePresence p = FindPresence(remoteClient.AgentId);
657
658 Vector3 avaPos = p.AbsolutePosition;
659 // Getting the global position for the Avatar
660 Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.RegionLocX*Constants.RegionSize + avaPos.X,
661 remoteClient.Scene.RegionInfo.RegionLocY*Constants.RegionSize + avaPos.Y,
662 avaPos.Z);
663
664 string landOwnerName = string.Empty;
665 ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y);
666 if(land.LandData.IsGroupOwned)
667 {
668 IGroupsModule groupMod = p.Scene.RequestModuleInterface<IGroupsModule>();
669 UUID groupId = land.LandData.GroupID;
670 GroupRecord groupRecord = groupMod.GetGroupRecord(groupId);
671 landOwnerName = groupRecord.GroupName;
672 }
673 else
674 {
675 IUserAccountService accounts = p.Scene.RequestModuleInterface<IUserAccountService>();
676 UserAccount user = accounts.GetUserAccount(p.Scene.RegionInfo.ScopeID, land.LandData.OwnerID);
677 landOwnerName = user.Name;
678 }
679
680 pick.PickId = pickID;
681 pick.CreatorId = creatorID;
682 pick.TopPick = topPick;
683 pick.Name = name;
684 pick.Desc = desc;
685 pick.ParcelId = p.currentParcelUUID;
686 pick.SnapshotId = snapshotID;
687 pick.User = landOwnerName;
688 pick.SimName = remoteClient.Scene.RegionInfo.RegionName;
689 pick.GlobalPos = posGlobal.ToString();
690 pick.SortOrder = sortOrder;
691 pick.Enabled = enabled;
692
693 object Pick = (object)pick;
694 if(!JsonRpcRequest(ref Pick, "picks_update", serverURI, UUID.Random().ToString()))
695 {
696 remoteClient.SendAgentAlertMessage(
697 "Error updating pick", false);
698 }
699
700 m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString());
701 }
702
703 /// <summary>
704 /// Delete a Pick
705 /// </summary>
706 /// <param name='remoteClient'>
707 /// Remote client.
708 /// </param>
709 /// <param name='queryPickID'>
710 /// Query pick I.
711 /// </param>
712 public void PickDelete(IClientAPI remoteClient, UUID queryPickID)
713 {
714 string serverURI = string.Empty;
715 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
716
717 OSDMap parameters= new OSDMap();
718 parameters.Add("pickId", OSD.FromUUID(queryPickID));
719 OSD Params = (OSD)parameters;
720 if(!JsonRpcRequest(ref Params, "picks_delete", serverURI, UUID.Random().ToString()))
721 {
722 remoteClient.SendAgentAlertMessage(
723 "Error picks delete", false);
724 }
725 }
726 #endregion Picks
727
728 #region Notes
729 /// <summary>
730 /// Handles the avatar notes request.
731 /// </summary>
732 /// <param name='sender'>
733 /// Sender.
734 /// </param>
735 /// <param name='method'>
736 /// Method.
737 /// </param>
738 /// <param name='args'>
739 /// Arguments.
740 /// </param>
741 public void NotesRequest(Object sender, string method, List<String> args)
742 {
743 UserProfileNotes note = new UserProfileNotes();
744
745 if (!(sender is IClientAPI))
746 return;
747
748 IClientAPI remoteClient = (IClientAPI)sender;
749 string serverURI = string.Empty;
750 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
751 note.TargetId = remoteClient.AgentId;
752 UUID.TryParse(args[0], out note.UserId);
753
754 object Note = (object)note;
755 if(!JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString()))
756 {
757 remoteClient.SendAgentAlertMessage(
758 "Error requesting note", false);
759 }
760 note = (UserProfileNotes) Note;
761
762 remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes);
763 }
764
765 /// <summary>
766 /// Avatars the notes update.
767 /// </summary>
768 /// <param name='remoteClient'>
769 /// Remote client.
770 /// </param>
771 /// <param name='queryTargetID'>
772 /// Query target I.
773 /// </param>
774 /// <param name='queryNotes'>
775 /// Query notes.
776 /// </param>
777 public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes)
778 {
779 UserProfileNotes note = new UserProfileNotes();
780
781 note.UserId = remoteClient.AgentId;
782 note.TargetId = queryTargetID;
783 note.Notes = queryNotes;
784
785 string serverURI = string.Empty;
786 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
787
788 object Note = note;
789 if(!JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString()))
790 {
791 remoteClient.SendAgentAlertMessage(
792 "Error updating note", false);
793 }
794 }
795 #endregion Notes
796
797 #region Avatar Properties
798 /// <summary>
799 /// Update the avatars interests .
800 /// </summary>
801 /// <param name='remoteClient'>
802 /// Remote client.
803 /// </param>
804 /// <param name='wantmask'>
805 /// Wantmask.
806 /// </param>
807 /// <param name='wanttext'>
808 /// Wanttext.
809 /// </param>
810 /// <param name='skillsmask'>
811 /// Skillsmask.
812 /// </param>
813 /// <param name='skillstext'>
814 /// Skillstext.
815 /// </param>
816 /// <param name='languages'>
817 /// Languages.
818 /// </param>
819 public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages)
820 {
821 UserProfileProperties prop = new UserProfileProperties();
822
823 prop.UserId = remoteClient.AgentId;
824 prop.WantToMask = (int)wantmask;
825 prop.WantToText = wanttext;
826 prop.SkillsMask = (int)skillsmask;
827 prop.SkillsText = skillstext;
828 prop.Language = languages;
829
830 string serverURI = string.Empty;
831 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
832
833 object Param = prop;
834 if(!JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString()))
835 {
836 remoteClient.SendAgentAlertMessage(
837 "Error updating interests", false);
838 }
839 }
840
841 public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
842 {
843 if ( String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString()))
844 {
845 // Looking for a reason that some viewers are sending null Id's
846 m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID);
847 return;
848 }
849
850 // Can't handle NPC yet...
851 ScenePresence p = FindPresence(avatarID);
852
853 if (null != p)
854 {
855 if (p.PresenceType == PresenceType.Npc)
856 return;
857 }
858
859 string serverURI = string.Empty;
860 bool foreign = GetUserProfileServerURI(avatarID, out serverURI);
861
862 UserAccount account = null;
863 Dictionary<string,object> userInfo;
864
865 if (!foreign)
866 {
867 account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID);
868 }
869 else
870 {
871 userInfo = new Dictionary<string, object>();
872 }
873
874 Byte[] charterMember = new Byte[1];
875 string born = String.Empty;
876 uint flags = 0x00;
877
878 if (null != account)
879 {
880 if (account.UserTitle == "")
881 {
882 charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8);
883 }
884 else
885 {
886 charterMember = Utils.StringToBytes(account.UserTitle);
887 }
888
889 born = Util.ToDateTime(account.Created).ToString(
890 "M/d/yyyy", CultureInfo.InvariantCulture);
891 flags = (uint)(account.UserFlags & 0xff);
892 }
893 else
894 {
895 if (GetUserAccountData(avatarID, out userInfo) == true)
896 {
897 if ((string)userInfo["user_title"] == "")
898 {
899 charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8);
900 }
901 else
902 {
903 charterMember = Utils.StringToBytes((string)userInfo["user_title"]);
904 }
905
906 int val_born = (int)userInfo["user_created"];
907 born = Util.ToDateTime(val_born).ToString(
908 "M/d/yyyy", CultureInfo.InvariantCulture);
909
910 // picky, picky
911 int val_flags = (int)userInfo["user_flags"];
912 flags = (uint)(val_flags & 0xff);
913 }
914 }
915
916 UserProfileProperties props = new UserProfileProperties();
917 string result = string.Empty;
918
919 props.UserId = avatarID;
920 GetProfileData(ref props, out result);
921
922 remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags,
923 props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId);
924
925
926 remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask,
927 props.SkillsText, props.Language);
928 }
929
930 /// <summary>
931 /// Updates the avatar properties.
932 /// </summary>
933 /// <param name='remoteClient'>
934 /// Remote client.
935 /// </param>
936 /// <param name='newProfile'>
937 /// New profile.
938 /// </param>
939 public void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile)
940 {
941 if (remoteClient.AgentId == newProfile.ID)
942 {
943 UserProfileProperties prop = new UserProfileProperties();
944
945 prop.UserId = remoteClient.AgentId;
946 prop.WebUrl = newProfile.ProfileUrl;
947 prop.ImageId = newProfile.Image;
948 prop.AboutText = newProfile.AboutText;
949 prop.FirstLifeImageId = newProfile.FirstLifeImage;
950 prop.FirstLifeText = newProfile.FirstLifeAboutText;
951
952 string serverURI = string.Empty;
953 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
954
955 object Prop = prop;
956
957 if(!JsonRpcRequest(ref Prop, "avatar_properties_update", serverURI, UUID.Random().ToString()))
958 {
959 remoteClient.SendAgentAlertMessage(
960 "Error updating properties", false);
961 }
962
963 RequestAvatarProperties(remoteClient, newProfile.ID);
964 }
965 }
966
967
968 /// <summary>
969 /// Gets the profile data.
970 /// </summary>
971 /// <returns>
972 /// The profile data.
973 /// </returns>
974 /// <param name='userID'>
975 /// User I.
976 /// </param>
977 bool GetProfileData(ref UserProfileProperties properties, out string message)
978 {
979 // Can't handle NPC yet...
980 ScenePresence p = FindPresence(properties.UserId);
981
982 if (null != p)
983 {
984 if (p.PresenceType == PresenceType.Npc)
985 {
986 message = "Id points to NPC";
987 return false;
988 }
989 }
990
991 string serverURI = string.Empty;
992 bool foreign = GetUserProfileServerURI(properties.UserId, out serverURI);
993
994 // This is checking a friend on the home grid
995 // Not HG friend
996 if ( String.IsNullOrEmpty(serverURI))
997 {
998 message = "No Presence - foreign friend";
999 return false;
1000 }
1001
1002 object Prop = (object)properties;
1003 JsonRpcRequest(ref Prop, "avatar_properties_request", serverURI, UUID.Random().ToString());
1004 properties = (UserProfileProperties)Prop;
1005
1006 message = "Success";
1007 return true;
1008 }
1009 #endregion Avatar Properties
1010
1011 #region Utils
1012 bool GetImageAssets(UUID avatarId)
1013 {
1014 string profileServerURI = string.Empty;
1015 string assetServerURI = string.Empty;
1016
1017 bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI);
1018
1019 if(!foreign)
1020 return true;
1021
1022 assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI");
1023
1024 OSDMap parameters= new OSDMap();
1025 parameters.Add("avatarId", OSD.FromUUID(avatarId));
1026 OSD Params = (OSD)parameters;
1027 if(!JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString()))
1028 {
1029 // Error Handling here!
1030 // if(parameters.ContainsKey("message")
1031 return false;
1032 }
1033
1034 parameters = (OSDMap)Params;
1035
1036 OSDArray list = (OSDArray)parameters["result"];
1037
1038 foreach(OSD asset in list)
1039 {
1040 OSDString assetId = (OSDString)asset;
1041
1042 Scene.AssetService.Get(string.Format("{0}/{1}",assetServerURI, assetId.AsString()), this,
1043 delegate (string assetID, Object s, AssetBase a)
1044 {
1045 // m_log.DebugFormat("[PROFILES]: Getting Image Assets {0}", assetID);
1046 return;
1047 });
1048 }
1049 return true;
1050 }
1051
1052 /// <summary>
1053 /// Gets the user account data.
1054 /// </summary>
1055 /// <returns>
1056 /// The user profile data.
1057 /// </returns>
1058 /// <param name='userID'>
1059 /// If set to <c>true</c> user I.
1060 /// </param>
1061 /// <param name='userInfo'>
1062 /// If set to <c>true</c> user info.
1063 /// </param>
1064 bool GetUserAccountData(UUID userID, out Dictionary<string, object> userInfo)
1065 {
1066 Dictionary<string,object> info = new Dictionary<string, object>();
1067
1068 if (UserManagementModule.IsLocalGridUser(userID))
1069 {
1070 // Is local
1071 IUserAccountService uas = Scene.UserAccountService;
1072 UserAccount account = uas.GetUserAccount(Scene.RegionInfo.ScopeID, userID);
1073
1074 info["user_flags"] = account.UserFlags;
1075 info["user_created"] = account.Created;
1076
1077 if (!String.IsNullOrEmpty(account.UserTitle))
1078 info["user_title"] = account.UserTitle;
1079 else
1080 info["user_title"] = "";
1081
1082 userInfo = info;
1083
1084 return false;
1085 }
1086 else
1087 {
1088 // Is Foreign
1089 string home_url = UserManagementModule.GetUserServerURL(userID, "HomeURI");
1090
1091 if (String.IsNullOrEmpty(home_url))
1092 {
1093 info["user_flags"] = 0;
1094 info["user_created"] = 0;
1095 info["user_title"] = "Unavailable";
1096
1097 userInfo = info;
1098 return true;
1099 }
1100
1101 UserAgentServiceConnector uConn = new UserAgentServiceConnector(home_url);
1102
1103 Dictionary<string, object> account = uConn.GetUserInfo(userID);
1104
1105 if (account.Count > 0)
1106 {
1107 if (account.ContainsKey("user_flags"))
1108 info["user_flags"] = account["user_flags"];
1109 else
1110 info["user_flags"] = "";
1111
1112 if (account.ContainsKey("user_created"))
1113 info["user_created"] = account["user_created"];
1114 else
1115 info["user_created"] = "";
1116
1117 info["user_title"] = "HG Visitor";
1118 }
1119 else
1120 {
1121 info["user_flags"] = 0;
1122 info["user_created"] = 0;
1123 info["user_title"] = "HG Visitor";
1124 }
1125 userInfo = info;
1126 return true;
1127 }
1128 }
1129
1130 /// <summary>
1131 /// Gets the user profile server UR.
1132 /// </summary>
1133 /// <returns>
1134 /// The user profile server UR.
1135 /// </returns>
1136 /// <param name='userID'>
1137 /// If set to <c>true</c> user I.
1138 /// </param>
1139 /// <param name='serverURI'>
1140 /// If set to <c>true</c> server UR.
1141 /// </param>
1142 bool GetUserProfileServerURI(UUID userID, out string serverURI)
1143 {
1144 bool local;
1145 local = UserManagementModule.IsLocalGridUser(userID);
1146
1147 if (!local)
1148 {
1149 serverURI = UserManagementModule.GetUserServerURL(userID, "ProfileServerURI");
1150 // Is Foreign
1151 return true;
1152 }
1153 else
1154 {
1155 serverURI = ProfileServerUri;
1156 // Is local
1157 return false;
1158 }
1159 }
1160
1161 /// <summary>
1162 /// Finds the presence.
1163 /// </summary>
1164 /// <returns>
1165 /// The presence.
1166 /// </returns>
1167 /// <param name='clientID'>
1168 /// Client I.
1169 /// </param>
1170 ScenePresence FindPresence(UUID clientID)
1171 {
1172 ScenePresence p;
1173
1174 p = Scene.GetScenePresence(clientID);
1175 if (p != null && !p.IsChildAgent)
1176 return p;
1177
1178 return null;
1179 }
1180 #endregion Util
1181
1182 #region Web Util
1183 /// <summary>
1184 /// Sends json-rpc request with a serializable type.
1185 /// </summary>
1186 /// <returns>
1187 /// OSD Map.
1188 /// </returns>
1189 /// <param name='parameters'>
1190 /// Serializable type .
1191 /// </param>
1192 /// <param name='method'>
1193 /// Json-rpc method to call.
1194 /// </param>
1195 /// <param name='uri'>
1196 /// URI of json-rpc service.
1197 /// </param>
1198 /// <param name='jsonId'>
1199 /// Id for our call.
1200 /// </param>
1201 bool JsonRpcRequest(ref object parameters, string method, string uri, string jsonId)
1202 {
1203 if (jsonId == null)
1204 throw new ArgumentNullException ("jsonId");
1205 if (uri == null)
1206 throw new ArgumentNullException ("uri");
1207 if (method == null)
1208 throw new ArgumentNullException ("method");
1209 if (parameters == null)
1210 throw new ArgumentNullException ("parameters");
1211
1212 // Prep our payload
1213 OSDMap json = new OSDMap();
1214
1215 json.Add("jsonrpc", OSD.FromString("2.0"));
1216 json.Add("id", OSD.FromString(jsonId));
1217 json.Add("method", OSD.FromString(method));
1218 // Experiment
1219 json.Add("params", OSD.SerializeMembers(parameters));
1220
1221 string jsonRequestData = OSDParser.SerializeJsonString(json);
1222 byte[] content = Encoding.UTF8.GetBytes(jsonRequestData);
1223
1224 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
1225 // webRequest.Credentials = new NetworkCredential(rpcUser, rpcPass);
1226 webRequest.ContentType = "application/json-rpc";
1227 webRequest.Method = "POST";
1228
1229 Stream dataStream = webRequest.GetRequestStream();
1230 dataStream.Write(content, 0, content.Length);
1231 dataStream.Close();
1232
1233 WebResponse webResponse = null;
1234 try
1235 {
1236 webResponse = webRequest.GetResponse();
1237 }
1238 catch (WebException e)
1239 {
1240 Console.WriteLine("Web Error" + e.Message);
1241 Console.WriteLine ("Please check input");
1242 return false;
1243 }
1244
1245 byte[] buf = new byte[8192];
1246 Stream rstream = webResponse.GetResponseStream();
1247 OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream);
1248
1249 if(mret.ContainsKey("error"))
1250 return false;
1251
1252 // get params...
1253 OSD.DeserializeMembers(ref parameters, (OSDMap) mret["result"]);
1254 return true;
1255 }
1256
1257 /// <summary>
1258 /// Sends json-rpc request with OSD parameter.
1259 /// </summary>
1260 /// <returns>
1261 /// The rpc request.
1262 /// </returns>
1263 /// <param name='data'>
1264 /// data - incoming as parameters, outgong as result/error
1265 /// </param>
1266 /// <param name='method'>
1267 /// Json-rpc method to call.
1268 /// </param>
1269 /// <param name='uri'>
1270 /// URI of json-rpc service.
1271 /// </param>
1272 /// <param name='jsonId'>
1273 /// If set to <c>true</c> json identifier.
1274 /// </param>
1275 bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId)
1276 {
1277 OSDMap map = new OSDMap();
1278
1279 map["jsonrpc"] = "2.0";
1280 if(string.IsNullOrEmpty(jsonId))
1281 map["id"] = UUID.Random().ToString();
1282 else
1283 map["id"] = jsonId;
1284
1285 map["method"] = method;
1286 map["params"] = data;
1287
1288 string jsonRequestData = OSDParser.SerializeJsonString(map);
1289 byte[] content = Encoding.UTF8.GetBytes(jsonRequestData);
1290
1291 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
1292 webRequest.ContentType = "application/json-rpc";
1293 webRequest.Method = "POST";
1294
1295 Stream dataStream = webRequest.GetRequestStream();
1296 dataStream.Write(content, 0, content.Length);
1297 dataStream.Close();
1298
1299 WebResponse webResponse = null;
1300 try
1301 {
1302 webResponse = webRequest.GetResponse();
1303 }
1304 catch (WebException e)
1305 {
1306 Console.WriteLine("Web Error" + e.Message);
1307 Console.WriteLine ("Please check input");
1308 return false;
1309 }
1310
1311 byte[] buf = new byte[8192];
1312 Stream rstream = webResponse.GetResponseStream();
1313
1314 OSDMap response = new OSDMap();
1315 response = (OSDMap)OSDParser.DeserializeJson(rstream);
1316 if(response.ContainsKey("error"))
1317 {
1318 data = response["error"];
1319 return false;
1320 }
1321
1322 data = response;
1323
1324 return true;
1325 }
1326 #endregion Web Util
1327 }
1328}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs
new file mode 100644
index 0000000..323535a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs
@@ -0,0 +1,226 @@
1
2/*
3 * Copyright (c) Contributors, http://opensimulator.org/
4 * See CONTRIBUTORS.TXT for a full list of copyright holders.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the OpenSimulator Project nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29using log4net;
30using Mono.Addins;
31using Nini.Config;
32using System;
33using System.Collections.Generic;
34using System.Reflection;
35using OpenSim.Framework;
36using OpenSim.Framework.Console;
37using OpenSim.Server.Base;
38using OpenSim.Server.Handlers;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Framework.Servers;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
44using GridRegion = OpenSim.Services.Interfaces.GridRegion;
45using OpenMetaverse;
46
47namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile
48{
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalUserProfilesServicesConnector")]
50 public class LocalUserProfilesServicesConnector : ISharedRegionModule
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Dictionary<UUID, Scene> regions = new Dictionary<UUID, Scene>();
57
58 public IUserProfilesService ServiceModule
59 {
60 get; private set;
61 }
62
63 public bool Enabled
64 {
65 get; private set;
66 }
67
68 public string Name
69 {
70 get
71 {
72 return "LocalUserProfilesServicesConnector";
73 }
74 }
75
76 public string ConfigName
77 {
78 get; private set;
79 }
80
81 public Type ReplaceableInterface
82 {
83 get { return null; }
84 }
85
86 public LocalUserProfilesServicesConnector()
87 {
88 m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector no params");
89 }
90
91 public LocalUserProfilesServicesConnector(IConfigSource source)
92 {
93 m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector instantiated directly.");
94 InitialiseService(source);
95 }
96
97 public void InitialiseService(IConfigSource source)
98 {
99 ConfigName = "UserProfilesService";
100
101 // Instantiate the request handler
102 IHttpServer Server = MainServer.Instance;
103
104 IConfig config = source.Configs[ConfigName];
105 if (config == null)
106 {
107 m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: UserProfilesService missing from OpenSim.ini");
108 return;
109 }
110
111 if(!config.GetBoolean("Enabled",false))
112 {
113 Enabled = false;
114 return;
115 }
116
117 Enabled = true;
118
119 string serviceDll = config.GetString("LocalServiceModule",
120 String.Empty);
121
122 if (serviceDll == String.Empty)
123 {
124 m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: No LocalServiceModule named in section UserProfilesService");
125 return;
126 }
127
128 Object[] args = new Object[] { source, ConfigName };
129 ServiceModule =
130 ServerUtils.LoadPlugin<IUserProfilesService>(serviceDll,
131 args);
132
133 if (ServiceModule == null)
134 {
135 m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: Can't load user profiles service");
136 return;
137 }
138
139 Enabled = true;
140
141 JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule);
142
143 Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest);
144 Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate);
145 Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest);
146 Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete);
147 Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest);
148 Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest);
149 Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate);
150 Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete);
151 Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest);
152 Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate);
153 Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest);
154 Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate);
155 Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate);
156 Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest);
157 Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData);
158 Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData);
159
160 }
161
162 #region ISharedRegionModule implementation
163
164 void ISharedRegionModule.PostInitialise()
165 {
166 if(!Enabled)
167 return;
168 }
169
170 #endregion
171
172 #region IRegionModuleBase implementation
173
174 void IRegionModuleBase.Initialise(IConfigSource source)
175 {
176 IConfig moduleConfig = source.Configs["Modules"];
177 if (moduleConfig != null)
178 {
179 string name = moduleConfig.GetString("UserProfilesServices", "");
180 if (name == Name)
181 {
182 InitialiseService(source);
183 m_log.Info("[LOCAL USERPROFILES SERVICE CONNECTOR]: Local user profiles connector enabled");
184 }
185 }
186 }
187
188 void IRegionModuleBase.Close()
189 {
190 return;
191 }
192
193 void IRegionModuleBase.AddRegion(Scene scene)
194 {
195 if (!Enabled)
196 return;
197
198 lock (regions)
199 {
200 if (regions.ContainsKey(scene.RegionInfo.RegionID))
201 m_log.ErrorFormat("[LOCAL USERPROFILES SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!");
202 else
203 regions.Add(scene.RegionInfo.RegionID, scene);
204 }
205 }
206
207 void IRegionModuleBase.RemoveRegion(Scene scene)
208 {
209 if (!Enabled)
210 return;
211
212 lock (regions)
213 {
214 if (regions.ContainsKey(scene.RegionInfo.RegionID))
215 regions.Remove(scene.RegionInfo.RegionID);
216 }
217 }
218
219 void IRegionModuleBase.RegionLoaded(Scene scene)
220 {
221 if (!Enabled)
222 return;
223 }
224 #endregion
225 }
226} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
index c32820e..3849a3f 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
@@ -56,6 +56,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
56 56
57 public LocalGridServicesConnector() 57 public LocalGridServicesConnector()
58 { 58 {
59 m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector no parms.");
59 } 60 }
60 61
61 public LocalGridServicesConnector(IConfigSource source) 62 public LocalGridServicesConnector(IConfigSource source)
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
index 66edfed..5dee64d 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
@@ -28,8 +28,11 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using System.Text;
31using log4net; 32using log4net;
32using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35
33using OpenSim.Framework; 36using OpenSim.Framework;
34 37
35using Animation = OpenSim.Framework.Animation; 38using Animation = OpenSim.Framework.Animation;
@@ -60,6 +63,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
60 ResetDefaultAnimation(); 63 ResetDefaultAnimation();
61 } 64 }
62 65
66 public AnimationSet(OSDArray pArray)
67 {
68 ResetDefaultAnimation();
69 FromOSDArray(pArray);
70 }
71
63 public bool HasAnimation(UUID animID) 72 public bool HasAnimation(UUID animID)
64 { 73 {
65 if (m_defaultAnimation.AnimID == animID) 74 if (m_defaultAnimation.AnimID == animID)
@@ -218,5 +227,106 @@ namespace OpenSim.Region.Framework.Scenes.Animation
218 foreach (OpenSim.Framework.Animation anim in theArray) 227 foreach (OpenSim.Framework.Animation anim in theArray)
219 m_animations.Add(anim); 228 m_animations.Add(anim);
220 } 229 }
230
231 // Create representation of this AnimationSet as an OSDArray.
232 // First two entries in the array are the default and implicitDefault animations
233 // followed by the other animations.
234 public OSDArray ToOSDArray()
235 {
236 OSDArray ret = new OSDArray();
237 ret.Add(DefaultAnimation.PackUpdateMessage());
238 ret.Add(ImplicitDefaultAnimation.PackUpdateMessage());
239
240 foreach (OpenSim.Framework.Animation anim in m_animations)
241 ret.Add(anim.PackUpdateMessage());
242
243 return ret;
244 }
245
246 public void FromOSDArray(OSDArray pArray)
247 {
248 this.Clear();
249
250 if (pArray.Count >= 1)
251 {
252 m_defaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[0]);
253 }
254 if (pArray.Count >= 2)
255 {
256 m_implicitDefaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[1]);
257 }
258 for (int ii = 2; ii < pArray.Count; ii++)
259 {
260 m_animations.Add(new OpenSim.Framework.Animation((OSDMap)pArray[ii]));
261 }
262 }
263
264 // Compare two AnimationSets and return 'true' if the default animations are the same
265 // and all of the animations in the list are equal.
266 public override bool Equals(object obj)
267 {
268 AnimationSet other = obj as AnimationSet;
269 if (other != null)
270 {
271 if (this.DefaultAnimation.Equals(other.DefaultAnimation)
272 && this.ImplicitDefaultAnimation.Equals(other.ImplicitDefaultAnimation))
273 {
274 // The defaults are the same. Is the list of animations the same?
275 OpenSim.Framework.Animation[] thisAnims = this.ToArray();
276 OpenSim.Framework.Animation[] otherAnims = other.ToArray();
277 if (thisAnims.Length == 0 && otherAnims.Length == 0)
278 return true; // the common case
279 if (thisAnims.Length == otherAnims.Length)
280 {
281 // Do this the hard way but since the list is usually short this won't take long.
282 foreach (OpenSim.Framework.Animation thisAnim in thisAnims)
283 {
284 bool found = false;
285 foreach (OpenSim.Framework.Animation otherAnim in otherAnims)
286 {
287 if (thisAnim.Equals(otherAnim))
288 {
289 found = true;
290 break;
291 }
292 }
293 if (!found)
294 {
295 // If anything is not in the other list, these are not equal
296 return false;
297 }
298 }
299 // Found everything in the other list. Since lists are equal length, they must be equal.
300 return true;
301 }
302 }
303 return false;
304 }
305 // Don't know what was passed, but the base system will figure it out for me.
306 return base.Equals(obj);
307 }
308
309 public override string ToString()
310 {
311 StringBuilder buff = new StringBuilder();
312 buff.Append("dflt=");
313 buff.Append(DefaultAnimation.ToString());
314 buff.Append(",iDflt=");
315 if (DefaultAnimation == ImplicitDefaultAnimation)
316 buff.Append("same");
317 else
318 buff.Append(ImplicitDefaultAnimation.ToString());
319 if (m_animations.Count > 0)
320 {
321 buff.Append(",anims=");
322 foreach (OpenSim.Framework.Animation anim in m_animations)
323 {
324 buff.Append("<");
325 buff.Append(anim.ToString());
326 buff.Append(">,");
327 }
328 }
329 return buff.ToString();
330 }
221 } 331 }
222} 332}
diff --git a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs
index c2b0468..b79dd8f 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs
@@ -104,5 +104,31 @@ namespace OpenSim.Region.Framework.Scenes.Animation
104 104
105 return UUID.Zero; 105 return UUID.Zero;
106 } 106 }
107
108 /// <summary>
109 /// Get the name of the animation given a UUID. If there is no matching animation
110 /// return the UUID as a string.
111 /// </summary>
112 public static string GetDefaultAnimationName(UUID uuid)
113 {
114 string ret = "unknown";
115 if (AnimsUUID.ContainsValue(uuid))
116 {
117 foreach (KeyValuePair<string, UUID> kvp in AnimsUUID)
118 {
119 if (kvp.Value == uuid)
120 {
121 ret = kvp.Key;
122 break;
123 }
124 }
125 }
126 else
127 {
128 ret = uuid.ToString();
129 }
130
131 return ret;
132 }
107 } 133 }
108} \ No newline at end of file 134} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index 65c279e..eb70eee 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -93,7 +93,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation
93 GetAnimName(animID), animID, m_scenePresence.Name); 93 GetAnimName(animID), animID, m_scenePresence.Name);
94 94
95 if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) 95 if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID))
96 {
96 SendAnimPack(); 97 SendAnimPack();
98 }
97 } 99 }
98 100
99 // Called from scripts 101 // Called from scripts
@@ -132,7 +134,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation
132 GetAnimName(animID), animID, m_scenePresence.Name); 134 GetAnimName(animID), animID, m_scenePresence.Name);
133 135
134 if (m_animations.Remove(animID, allowNoDefault)) 136 if (m_animations.Remove(animID, allowNoDefault))
137 {
135 SendAnimPack(); 138 SendAnimPack();
139 }
136 } 140 }
137 141
138 public void avnChangeAnim(UUID animID, bool addRemove, bool sendPack) 142 public void avnChangeAnim(UUID animID, bool addRemove, bool sendPack)
@@ -180,8 +184,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
180 /// The movement animation is reserved for "main" animations 184 /// The movement animation is reserved for "main" animations
181 /// that are mutually exclusive, e.g. flying and sitting. 185 /// that are mutually exclusive, e.g. flying and sitting.
182 /// </summary> 186 /// </summary>
183 public void TrySetMovementAnimation(string anim) 187 /// <returns>'true' if the animation was updated</returns>
188 public bool TrySetMovementAnimation(string anim)
184 { 189 {
190 bool ret = false;
185 if (!m_scenePresence.IsChildAgent) 191 if (!m_scenePresence.IsChildAgent)
186 { 192 {
187// m_log.DebugFormat( 193// m_log.DebugFormat(
@@ -198,6 +204,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
198 // 16384 is CHANGED_ANIMATION 204 // 16384 is CHANGED_ANIMATION
199 m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); 205 m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION});
200 SendAnimPack(); 206 SendAnimPack();
207 ret = true;
201 } 208 }
202 } 209 }
203 else 210 else
@@ -206,6 +213,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
206 "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}", 213 "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}",
207 anim, m_scenePresence.Name); 214 anim, m_scenePresence.Name);
208 } 215 }
216 return ret;
209 } 217 }
210 218
211 /// <summary> 219 /// <summary>
@@ -439,8 +447,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
439 /// <summary> 447 /// <summary>
440 /// Update the movement animation of this avatar according to its current state 448 /// Update the movement animation of this avatar according to its current state
441 /// </summary> 449 /// </summary>
442 public void UpdateMovementAnimations() 450 /// <returns>'true' if the animation was changed</returns>
451 public bool UpdateMovementAnimations()
443 { 452 {
453 bool ret = false;
444 lock (m_animations) 454 lock (m_animations)
445 { 455 {
446 string newMovementAnimation = DetermineMovementAnimation(); 456 string newMovementAnimation = DetermineMovementAnimation();
@@ -454,9 +464,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
454 464
455 // Only set it if it's actually changed, give a script 465 // Only set it if it's actually changed, give a script
456 // a chance to stop a default animation 466 // a chance to stop a default animation
457 TrySetMovementAnimation(CurrentMovementAnimation); 467 ret = TrySetMovementAnimation(CurrentMovementAnimation);
458 } 468 }
459 } 469 }
470 return ret;
460 } 471 }
461 472
462 public UUID[] GetAnimationArray() 473 public UUID[] GetAnimationArray()
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 4733547..4fec44f 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -974,6 +974,8 @@ namespace OpenSim.Region.Framework.Scenes
974 public delegate void RegionStarted(Scene scene); 974 public delegate void RegionStarted(Scene scene);
975 public event RegionStarted OnRegionStarted; 975 public event RegionStarted OnRegionStarted;
976 976
977 public delegate void RegionHeartbeatStart(Scene scene);
978 public event RegionHeartbeatStart OnRegionHeartbeatStart;
977 public delegate void RegionHeartbeatEnd(Scene scene); 979 public delegate void RegionHeartbeatEnd(Scene scene);
978 public event RegionHeartbeatEnd OnRegionHeartbeatEnd; 980 public event RegionHeartbeatEnd OnRegionHeartbeatEnd;
979 981
@@ -3096,6 +3098,27 @@ namespace OpenSim.Region.Framework.Scenes
3096 } 3098 }
3097 } 3099 }
3098 3100
3101 public void TriggerRegionHeartbeatStart(Scene scene)
3102 {
3103 RegionHeartbeatStart handler = OnRegionHeartbeatStart;
3104
3105 if (handler != null)
3106 {
3107 foreach (RegionHeartbeatStart d in handler.GetInvocationList())
3108 {
3109 try
3110 {
3111 d(scene);
3112 }
3113 catch (Exception e)
3114 {
3115 m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionHeartbeatStart failed - continuing {0} - {1}",
3116 e.Message, e.StackTrace);
3117 }
3118 }
3119 }
3120 }
3121
3099 public void TriggerRegionHeartbeatEnd(Scene scene) 3122 public void TriggerRegionHeartbeatEnd(Scene scene)
3100 { 3123 {
3101 RegionHeartbeatEnd handler = OnRegionHeartbeatEnd; 3124 RegionHeartbeatEnd handler = OnRegionHeartbeatEnd;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 6bac468..6ef83fb 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1569,6 +1569,8 @@ namespace OpenSim.Region.Framework.Scenes
1569 1569
1570 try 1570 try
1571 { 1571 {
1572 EventManager.TriggerRegionHeartbeatStart(this);
1573
1572 // Apply taints in terrain module to terrain in physics scene 1574 // Apply taints in terrain module to terrain in physics scene
1573 if (Frame % m_update_terrain == 0) 1575 if (Frame % m_update_terrain == 0)
1574 { 1576 {
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 83bd3fb..1859cb1 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -2310,6 +2310,7 @@ namespace OpenSim.Region.Framework.Scenes
2310 AddToPhysicalScene(false); 2310 AddToPhysicalScene(false);
2311 2311
2312 Animator.TrySetMovementAnimation("STAND"); 2312 Animator.TrySetMovementAnimation("STAND");
2313 TriggerScenePresenceUpdated();
2313 } 2314 }
2314 2315
2315 private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) 2316 private SceneObjectPart FindNextAvailableSitTarget(UUID targetID)
@@ -2408,7 +2409,7 @@ namespace OpenSim.Region.Framework.Scenes
2408 ControllingClient.SendSitResponse( 2409 ControllingClient.SendSitResponse(
2409 part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); 2410 part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
2410 2411
2411 m_requestedSitTargetUUID = targetID; 2412 m_requestedSitTargetUUID = part.UUID;
2412 2413
2413 HandleAgentSit(ControllingClient, UUID); 2414 HandleAgentSit(ControllingClient, UUID);
2414 2415
@@ -2436,7 +2437,7 @@ namespace OpenSim.Region.Framework.Scenes
2436 if (part != null) 2437 if (part != null)
2437 { 2438 {
2438 m_requestedSitTargetID = part.LocalId; 2439 m_requestedSitTargetID = part.LocalId;
2439 m_requestedSitTargetUUID = targetID; 2440 m_requestedSitTargetUUID = part.UUID;
2440 2441
2441 } 2442 }
2442 else 2443 else
@@ -2635,6 +2636,7 @@ namespace OpenSim.Region.Framework.Scenes
2635 } 2636 }
2636 Animator.TrySetMovementAnimation(sitAnimation); 2637 Animator.TrySetMovementAnimation(sitAnimation);
2637 SendAvatarDataToAllAgents(); 2638 SendAvatarDataToAllAgents();
2639 TriggerScenePresenceUpdated();
2638 } 2640 }
2639 } 2641 }
2640 2642
@@ -2643,6 +2645,7 @@ namespace OpenSim.Region.Framework.Scenes
2643// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. 2645// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick..
2644 m_AngularVelocity = Vector3.Zero; 2646 m_AngularVelocity = Vector3.Zero;
2645 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); 2647 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
2648 TriggerScenePresenceUpdated();
2646 SitGround = true; 2649 SitGround = true;
2647 RemoveFromPhysicalScene(); 2650 RemoveFromPhysicalScene();
2648 } 2651 }
@@ -2659,11 +2662,13 @@ namespace OpenSim.Region.Framework.Scenes
2659 public void HandleStartAnim(IClientAPI remoteClient, UUID animID) 2662 public void HandleStartAnim(IClientAPI remoteClient, UUID animID)
2660 { 2663 {
2661 Animator.AddAnimation(animID, UUID.Zero); 2664 Animator.AddAnimation(animID, UUID.Zero);
2665 TriggerScenePresenceUpdated();
2662 } 2666 }
2663 2667
2664 public void HandleStopAnim(IClientAPI remoteClient, UUID animID) 2668 public void HandleStopAnim(IClientAPI remoteClient, UUID animID)
2665 { 2669 {
2666 Animator.RemoveAnimation(animID, false); 2670 Animator.RemoveAnimation(animID, false);
2671 TriggerScenePresenceUpdated();
2667 } 2672 }
2668 2673
2669 public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) 2674 public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack)
@@ -3693,7 +3698,8 @@ namespace OpenSim.Region.Framework.Scenes
3693 3698
3694// if (m_updateCount > 0) 3699// if (m_updateCount > 0)
3695// { 3700// {
3696 Animator.UpdateMovementAnimations(); 3701 if (Animator.UpdateMovementAnimations())
3702 TriggerScenePresenceUpdated();
3697// m_updateCount--; 3703// m_updateCount--;
3698// } 3704// }
3699 3705
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
index 20affa6..2f07c42 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
@@ -841,7 +841,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
841 requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); 841 requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff);
842 requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); 842 requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel);
843 requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); 843 requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange);
844 requrl = String.Format("{0}&chan_ckamping_distance={1}", requrl, m_vivoxChannelClampingDistance); 844 requrl = String.Format("{0}&chan_clamping_distance={1}", requrl, m_vivoxChannelClampingDistance);
845 845
846 XmlElement resp = VivoxCall(requrl, true); 846 XmlElement resp = VivoxCall(requrl, true);
847 if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) 847 if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri))
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 2651e3b..afd547a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -54,6 +54,9 @@ public static class BSParam
54 // =================== 54 // ===================
55 // From: 55 // From:
56 56
57 public static bool UseSeparatePhysicsThread { get; private set; }
58 public static float PhysicsTimeStep { get; private set; }
59
57 // Level of Detail values kept as float because that's what the Meshmerizer wants 60 // Level of Detail values kept as float because that's what the Meshmerizer wants
58 public static float MeshLOD { get; private set; } 61 public static float MeshLOD { get; private set; }
59 public static float MeshCircularLOD { get; private set; } 62 public static float MeshCircularLOD { get; private set; }
@@ -354,6 +357,11 @@ public static class BSParam
354 // v = value (appropriate type) 357 // v = value (appropriate type)
355 private static ParameterDefnBase[] ParameterDefinitions = 358 private static ParameterDefnBase[] ParameterDefinitions =
356 { 359 {
360 new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat",
361 false ),
362 new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval",
363 0.1f ),
364
357 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", 365 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties",
358 true, 366 true,
359 (s) => { return ShouldMeshSculptedPrim; }, 367 (s) => { return ShouldMeshSculptedPrim; },
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index e11e365..95bdc7b 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -1513,7 +1513,8 @@ public class BSPrim : BSPhysObject
1513 CurrentEntityProperties = entprop; 1513 CurrentEntityProperties = entprop;
1514 1514
1515 // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. 1515 // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims.
1516 base.RequestPhysicsterseUpdate(); 1516
1517 PhysScene.PostUpdate(this);
1517 } 1518 }
1518} 1519}
1519} 1520}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 39f5b0a..423c389 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -56,12 +56,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
56 public string BulletEngineName { get; private set; } 56 public string BulletEngineName { get; private set; }
57 public BSAPITemplate PE; 57 public BSAPITemplate PE;
58 58
59 // If the physics engine is running on a separate thread
60 public Thread m_physicsThread;
61
59 public Dictionary<uint, BSPhysObject> PhysObjects; 62 public Dictionary<uint, BSPhysObject> PhysObjects;
60 public BSShapeCollection Shapes; 63 public BSShapeCollection Shapes;
61 64
62 // Keeping track of the objects with collisions so we can report begin and end of a collision 65 // Keeping track of the objects with collisions so we can report begin and end of a collision
63 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); 66 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
64 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); 67 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
68
69 // All the collision processing is protected with this lock object
70 public Object CollisionLock = new Object();
71
72 // Properties are updated here
73 public Object UpdateLock = new Object();
74 public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>();
75
65 // Keep track of all the avatars so we can send them a collision event 76 // Keep track of all the avatars so we can send them a collision event
66 // every tick so OpenSim will update its animation. 77 // every tick so OpenSim will update its animation.
67 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); 78 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
@@ -77,12 +88,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
77 public BSConstraintCollection Constraints { get; private set; } 88 public BSConstraintCollection Constraints { get; private set; }
78 89
79 // Simulation parameters 90 // Simulation parameters
91 internal float m_physicsStepTime; // if running independently, the interval simulated by default
92
80 internal int m_maxSubSteps; 93 internal int m_maxSubSteps;
81 internal float m_fixedTimeStep; 94 internal float m_fixedTimeStep;
82 internal long m_simulationStep = 0; 95
83 internal float NominalFrameRate { get; set; } 96 internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc.
97
98 internal long m_simulationStep = 0; // The current simulation step.
84 public long SimulationStep { get { return m_simulationStep; } } 99 public long SimulationStep { get { return m_simulationStep; } }
85 internal float LastTimeStep { get; private set; } 100
101 internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate()
102
103 internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to
86 104
87 // Physical objects can register for prestep or poststep events 105 // Physical objects can register for prestep or poststep events
88 public delegate void PreStepAction(float timeStep); 106 public delegate void PreStepAction(float timeStep);
@@ -90,7 +108,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
90 public event PreStepAction BeforeStep; 108 public event PreStepAction BeforeStep;
91 public event PostStepAction AfterStep; 109 public event PostStepAction AfterStep;
92 110
93 // A value of the time now so all the collision and update routines do not have to get their own 111 // A value of the time 'now' so all the collision and update routines do not have to get their own
94 // Set to 'now' just before all the prims and actors are called for collisions and updates 112 // Set to 'now' just before all the prims and actors are called for collisions and updates
95 public int SimulationNowTime { get; private set; } 113 public int SimulationNowTime { get; private set; }
96 114
@@ -188,6 +206,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
188 PhysObjects = new Dictionary<uint, BSPhysObject>(); 206 PhysObjects = new Dictionary<uint, BSPhysObject>();
189 Shapes = new BSShapeCollection(this); 207 Shapes = new BSShapeCollection(this);
190 208
209 m_simulatedTime = 0f;
210 LastTimeStep = 0.1f;
211
191 // Allocate pinned memory to pass parameters. 212 // Allocate pinned memory to pass parameters.
192 UnmanagedParams = new ConfigurationParameters[1]; 213 UnmanagedParams = new ConfigurationParameters[1];
193 214
@@ -227,10 +248,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
227 TerrainManager = new BSTerrainManager(this); 248 TerrainManager = new BSTerrainManager(this);
228 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 249 TerrainManager.CreateInitialGroundPlaneAndTerrain();
229 250
251 // Put some informational messages into the log file.
230 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); 252 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
231 253
232 InTaintTime = false; 254 InTaintTime = false;
233 m_initialized = true; 255 m_initialized = true;
256
257 // If the physics engine runs on its own thread, start same.
258 if (BSParam.UseSeparatePhysicsThread)
259 {
260 // The physics simulation should happen independently of the heartbeat loop
261 m_physicsThread = new Thread(BulletSPluginPhysicsThread);
262 m_physicsThread.Name = BulletEngineName;
263 m_physicsThread.Start();
264 }
234 } 265 }
235 266
236 // All default parameter values are set here. There should be no values set in the 267 // All default parameter values are set here. There should be no values set in the
@@ -270,6 +301,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
270 } 301 }
271 else 302 else
272 { 303 {
304 // Nothing in the configuration INI file so assume unmanaged and other defaults.
273 BulletEngineName = "BulletUnmanaged"; 305 BulletEngineName = "BulletUnmanaged";
274 m_physicsLoggingEnabled = false; 306 m_physicsLoggingEnabled = false;
275 VehicleLoggingEnabled = false; 307 VehicleLoggingEnabled = false;
@@ -317,6 +349,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
317 349
318 switch (selectionName) 350 switch (selectionName)
319 { 351 {
352 case "bullet":
320 case "bulletunmanaged": 353 case "bulletunmanaged":
321 ret = new BSAPIUnman(engineName, this); 354 ret = new BSAPIUnman(engineName, this);
322 break; 355 break;
@@ -494,25 +527,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
494 #endregion // Prim and Avatar addition and removal 527 #endregion // Prim and Avatar addition and removal
495 528
496 #region Simulation 529 #region Simulation
497 // Simulate one timestep 530
531 // Call from the simulator to send physics information to the simulator objects.
532 // This pushes all the collision and property update events into the objects in
533 // the simulator and, since it is on the heartbeat thread, there is an implicit
534 // locking of those data structures from other heartbeat events.
535 // If the physics engine is running on a separate thread, the update information
536 // will be in the ObjectsWithCollions and ObjectsWithUpdates structures.
498 public override float Simulate(float timeStep) 537 public override float Simulate(float timeStep)
499 { 538 {
539 if (!BSParam.UseSeparatePhysicsThread)
540 {
541 DoPhysicsStep(timeStep);
542 }
543 return SendUpdatesToSimulator(timeStep);
544 }
545
546 // Call the physics engine to do one 'timeStep' and collect collisions and updates
547 // into ObjectsWithCollisions and ObjectsWithUpdates data structures.
548 private void DoPhysicsStep(float timeStep)
549 {
500 // prevent simulation until we've been initialized 550 // prevent simulation until we've been initialized
501 if (!m_initialized) return 5.0f; 551 if (!m_initialized) return;
502 552
503 LastTimeStep = timeStep; 553 LastTimeStep = timeStep;
504 554
505 int updatedEntityCount = 0; 555 int updatedEntityCount = 0;
506 int collidersCount = 0; 556 int collidersCount = 0;
507 557
508 int beforeTime = 0; 558 int beforeTime = Util.EnvironmentTickCount();
509 int simTime = 0; 559 int simTime = 0;
510 560
511 // update the prim states while we know the physics engine is not busy
512 int numTaints = _taintOperations.Count; 561 int numTaints = _taintOperations.Count;
513
514 InTaintTime = true; // Only used for debugging so locking is not necessary. 562 InTaintTime = true; // Only used for debugging so locking is not necessary.
515 563
564 // update the prim states while we know the physics engine is not busy
516 ProcessTaints(); 565 ProcessTaints();
517 566
518 // Some of the physical objects requre individual, pre-step calls 567 // Some of the physical objects requre individual, pre-step calls
@@ -535,18 +584,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
535 int numSubSteps = 0; 584 int numSubSteps = 0;
536 try 585 try
537 { 586 {
538 if (PhysicsLogging.Enabled)
539 beforeTime = Util.EnvironmentTickCount();
540
541 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); 587 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
542 588
543 if (PhysicsLogging.Enabled)
544 {
545 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
546 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
547 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
548 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
549 }
550 } 589 }
551 catch (Exception e) 590 catch (Exception e)
552 { 591 {
@@ -558,77 +597,62 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
558 collidersCount = 0; 597 collidersCount = 0;
559 } 598 }
560 599
600 // Make the physics engine dump useful statistics periodically
561 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) 601 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
562 PE.DumpPhysicsStatistics(World); 602 PE.DumpPhysicsStatistics(World);
563 603
564 // Get a value for 'now' so all the collision and update routines don't have to get their own. 604 // Get a value for 'now' so all the collision and update routines don't have to get their own.
565 SimulationNowTime = Util.EnvironmentTickCount(); 605 SimulationNowTime = Util.EnvironmentTickCount();
566 606
567 // If there were collisions, process them by sending the event to the prim. 607 // Send collision information to the colliding objects. The objects decide if the collision
568 // Collisions must be processed before updates. 608 // is 'real' (like linksets don't collide with themselves) and the individual objects
569 if (collidersCount > 0) 609 // know if the simulator has subscribed to collisions.
610 lock (CollisionLock)
570 { 611 {
571 for (int ii = 0; ii < collidersCount; ii++) 612 if (collidersCount > 0)
572 { 613 {
573 uint cA = m_collisionArray[ii].aID; 614 for (int ii = 0; ii < collidersCount; ii++)
574 uint cB = m_collisionArray[ii].bID;
575 Vector3 point = m_collisionArray[ii].point;
576 Vector3 normal = m_collisionArray[ii].normal;
577 float penetration = m_collisionArray[ii].penetration;
578 SendCollision(cA, cB, point, normal, penetration);
579 SendCollision(cB, cA, point, -normal, penetration);
580 }
581 }
582
583 // The above SendCollision's batch up the collisions on the objects.
584 // Now push the collisions into the simulator.
585 if (ObjectsWithCollisions.Count > 0)
586 {
587 foreach (BSPhysObject bsp in ObjectsWithCollisions)
588 if (!bsp.SendCollisions())
589 { 615 {
590 // If the object is done colliding, see that it's removed from the colliding list 616 uint cA = m_collisionArray[ii].aID;
591 ObjectsWithNoMoreCollisions.Add(bsp); 617 uint cB = m_collisionArray[ii].bID;
618 Vector3 point = m_collisionArray[ii].point;
619 Vector3 normal = m_collisionArray[ii].normal;
620 float penetration = m_collisionArray[ii].penetration;
621 SendCollision(cA, cB, point, normal, penetration);
622 SendCollision(cB, cA, point, -normal, penetration);
592 } 623 }
624 }
593 } 625 }
594 626
595 // This is a kludge to get avatar movement updates. 627 // If any of the objects had updated properties, tell the managed objects about the update
596 // The simulator expects collisions for avatars even if there are have been no collisions. 628 // and remember that there was a change so it will be passed to the simulator.
597 // The event updates avatar animations and stuff. 629 lock (UpdateLock)
598 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
599 foreach (BSPhysObject bsp in m_avatars)
600 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
601 bsp.SendCollisions();
602
603 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
604 // Not done above because it is inside an iteration of ObjectWithCollisions.
605 // This complex collision processing is required to create an empty collision
606 // event call after all real collisions have happened on an object. This enables
607 // the simulator to generate the 'collision end' event.
608 if (ObjectsWithNoMoreCollisions.Count > 0)
609 {
610 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
611 ObjectsWithCollisions.Remove(po);
612 ObjectsWithNoMoreCollisions.Clear();
613 }
614 // Done with collisions.
615
616 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
617 if (updatedEntityCount > 0)
618 { 630 {
619 for (int ii = 0; ii < updatedEntityCount; ii++) 631 if (updatedEntityCount > 0)
620 { 632 {
621 EntityProperties entprop = m_updateArray[ii]; 633 for (int ii = 0; ii < updatedEntityCount; ii++)
622 BSPhysObject pobj;
623 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
624 { 634 {
625 pobj.UpdateProperties(entprop); 635 EntityProperties entprop = m_updateArray[ii];
636 BSPhysObject pobj;
637 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
638 {
639 pobj.UpdateProperties(entprop);
640 }
626 } 641 }
627 } 642 }
628 } 643 }
629 644
645 // Some actors want to know when the simulation step is complete.
630 TriggerPostStepEvent(timeStep); 646 TriggerPostStepEvent(timeStep);
631 647
648 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
649 if (PhysicsLogging.Enabled)
650 {
651 DetailLog("{0},DoPhysicsStep,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
652 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
653 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
654 }
655
632 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. 656 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
633 // Only enable this in a limited test world with few objects. 657 // Only enable this in a limited test world with few objects.
634 if (m_physicsPhysicalDumpEnabled) 658 if (m_physicsPhysicalDumpEnabled)
@@ -637,7 +661,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
637 // The physics engine returns the number of milliseconds it simulated this call. 661 // The physics engine returns the number of milliseconds it simulated this call.
638 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 662 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
639 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). 663 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
640 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; 664 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
665 }
666
667 // Called by a BSPhysObject to note that it has changed properties and this information
668 // should be passed up to the simulator at the proper time.
669 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
670 // this is is under UpdateLock.
671 public void PostUpdate(BSPhysObject updatee)
672 {
673 ObjectsWithUpdates.Add(updatee);
674 }
675
676 // The simulator thinks it is physics time so return all the collisions and position
677 // updates that were collected in actual physics simulation.
678 private float SendUpdatesToSimulator(float timeStep)
679 {
680 if (!m_initialized) return 5.0f;
681
682 DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
683 BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
684 // Push the collisions into the simulator.
685 lock (CollisionLock)
686 {
687 if (ObjectsWithCollisions.Count > 0)
688 {
689 foreach (BSPhysObject bsp in ObjectsWithCollisions)
690 if (!bsp.SendCollisions())
691 {
692 // If the object is done colliding, see that it's removed from the colliding list
693 ObjectsWithNoMoreCollisions.Add(bsp);
694 }
695 }
696
697 // This is a kludge to get avatar movement updates.
698 // The simulator expects collisions for avatars even if there are have been no collisions.
699 // The event updates avatar animations and stuff.
700 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
701 foreach (BSPhysObject bsp in m_avatars)
702 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
703 bsp.SendCollisions();
704
705 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
706 // Not done above because it is inside an iteration of ObjectWithCollisions.
707 // This complex collision processing is required to create an empty collision
708 // event call after all real collisions have happened on an object. This allows
709 // the simulator to generate the 'collision end' event.
710 if (ObjectsWithNoMoreCollisions.Count > 0)
711 {
712 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
713 ObjectsWithCollisions.Remove(po);
714 ObjectsWithNoMoreCollisions.Clear();
715 }
716 }
717
718 // Call the simulator for each object that has physics property updates.
719 HashSet<BSPhysObject> updatedObjects = null;
720 lock (UpdateLock)
721 {
722 if (ObjectsWithUpdates.Count > 0)
723 {
724 updatedObjects = ObjectsWithUpdates;
725 ObjectsWithUpdates = new HashSet<BSPhysObject>();
726 }
727 }
728 if (updatedObjects != null)
729 {
730 foreach (BSPhysObject obj in updatedObjects)
731 {
732 obj.RequestPhysicsterseUpdate();
733 }
734 updatedObjects.Clear();
735 }
736
737 // Return the framerate simulated to give the above returned results.
738 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
739 float simTime = m_simulatedTime;
740 m_simulatedTime = 0f;
741 return simTime;
641 } 742 }
642 743
643 // Something has collided 744 // Something has collided
@@ -656,7 +757,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
656 return; 757 return;
657 } 758 }
658 759
659 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. 760 // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
660 BSPhysObject collidee = null; 761 BSPhysObject collidee = null;
661 PhysObjects.TryGetValue(collidingWith, out collidee); 762 PhysObjects.TryGetValue(collidingWith, out collidee);
662 763
@@ -664,13 +765,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
664 765
665 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 766 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
666 { 767 {
667 // If a collision was posted, remember to send it to the simulator 768 // If a collision was 'good', remember to send it to the simulator
668 ObjectsWithCollisions.Add(collider); 769 ObjectsWithCollisions.Add(collider);
669 } 770 }
670 771
671 return; 772 return;
672 } 773 }
673 774
775 public void BulletSPluginPhysicsThread()
776 {
777 while (m_initialized)
778 {
779 int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
780 DoPhysicsStep(BSParam.PhysicsTimeStep);
781 int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
782 int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
783
784 if (simulationTimeVsRealtimeDifferenceMS > 0)
785 {
786 // The simulation of the time interval took less than realtime.
787 // Do a sleep for the rest of realtime.
788 DetailLog("{0},BulletSPluginPhysicsThread,sleeping={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
789 Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
790 }
791 else
792 {
793 // The simulation took longer than realtime.
794 // Do some scaling of simulation time.
795 // TODO.
796 DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
797 }
798 }
799 }
800
674 #endregion // Simulation 801 #endregion // Simulation
675 802
676 public override void GetResults() { } 803 public override void GetResults() { }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
index 6879ebb..1e19032 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
@@ -37,6 +37,8 @@ using OpenSim.Region.ScriptEngine.Interfaces;
37using OpenSim.Region.ScriptEngine.Shared; 37using OpenSim.Region.ScriptEngine.Shared;
38using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; 38using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
39using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; 39using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
40using System.Reflection;
41using log4net;
40 42
41namespace OpenSim.Region.ScriptEngine.Shared.Api 43namespace OpenSim.Region.ScriptEngine.Shared.Api
42{ 44{
@@ -45,15 +47,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
45 /// </summary> 47 /// </summary>
46 public class AsyncCommandManager 48 public class AsyncCommandManager
47 { 49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
48 private static Thread cmdHandlerThread; 52 private static Thread cmdHandlerThread;
49 private static int cmdHandlerThreadCycleSleepms; 53 private static int cmdHandlerThreadCycleSleepms;
50 54
51 private static List<IScene> m_Scenes = new List<IScene>(); 55 /// <summary>
56 /// Lock for reading/writing static components of AsyncCommandManager.
57 /// </summary>
58 /// <remarks>
59 /// This lock exists so that multiple threads from different engines and/or different copies of the same engine
60 /// are prevented from running non-thread safe code (e.g. read/write of lists) concurrently.
61 /// </remarks>
62 private static object staticLock = new object();
63
52 private static List<IScriptEngine> m_ScriptEngines = 64 private static List<IScriptEngine> m_ScriptEngines =
53 new List<IScriptEngine>(); 65 new List<IScriptEngine>();
54 66
55 public IScriptEngine m_ScriptEngine; 67 public IScriptEngine m_ScriptEngine;
56 private IScene m_Scene;
57 68
58 private static Dictionary<IScriptEngine, Dataserver> m_Dataserver = 69 private static Dictionary<IScriptEngine, Dataserver> m_Dataserver =
59 new Dictionary<IScriptEngine, Dataserver>(); 70 new Dictionary<IScriptEngine, Dataserver>();
@@ -70,67 +81,99 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
70 81
71 public Dataserver DataserverPlugin 82 public Dataserver DataserverPlugin
72 { 83 {
73 get { return m_Dataserver[m_ScriptEngine]; } 84 get
85 {
86 lock (staticLock)
87 return m_Dataserver[m_ScriptEngine];
88 }
74 } 89 }
75 90
76 public Timer TimerPlugin 91 public Timer TimerPlugin
77 { 92 {
78 get { return m_Timer[m_ScriptEngine]; } 93 get
94 {
95 lock (staticLock)
96 return m_Timer[m_ScriptEngine];
97 }
79 } 98 }
80 99
81 public HttpRequest HttpRequestPlugin 100 public HttpRequest HttpRequestPlugin
82 { 101 {
83 get { return m_HttpRequest[m_ScriptEngine]; } 102 get
103 {
104 lock (staticLock)
105 return m_HttpRequest[m_ScriptEngine];
106 }
84 } 107 }
85 108
86 public Listener ListenerPlugin 109 public Listener ListenerPlugin
87 { 110 {
88 get { return m_Listener[m_ScriptEngine]; } 111 get
112 {
113 lock (staticLock)
114 return m_Listener[m_ScriptEngine];
115 }
89 } 116 }
90 117
91 public SensorRepeat SensorRepeatPlugin 118 public SensorRepeat SensorRepeatPlugin
92 { 119 {
93 get { return m_SensorRepeat[m_ScriptEngine]; } 120 get
121 {
122 lock (staticLock)
123 return m_SensorRepeat[m_ScriptEngine];
124 }
94 } 125 }
95 126
96 public XmlRequest XmlRequestPlugin 127 public XmlRequest XmlRequestPlugin
97 { 128 {
98 get { return m_XmlRequest[m_ScriptEngine]; } 129 get
130 {
131 lock (staticLock)
132 return m_XmlRequest[m_ScriptEngine];
133 }
99 } 134 }
100 135
101 public IScriptEngine[] ScriptEngines 136 public IScriptEngine[] ScriptEngines
102 { 137 {
103 get { return m_ScriptEngines.ToArray(); } 138 get
139 {
140 lock (staticLock)
141 return m_ScriptEngines.ToArray();
142 }
104 } 143 }
105 144
106 public AsyncCommandManager(IScriptEngine _ScriptEngine) 145 public AsyncCommandManager(IScriptEngine _ScriptEngine)
107 { 146 {
108 m_ScriptEngine = _ScriptEngine; 147 m_ScriptEngine = _ScriptEngine;
109 m_Scene = m_ScriptEngine.World; 148
110 149 // If there is more than one scene in the simulator or multiple script engines are used on the same region
111 if (m_Scenes.Count == 0) 150 // then more than one thread could arrive at this block of code simultaneously. However, it cannot be
112 ReadConfig(); 151 // executed concurrently both because concurrent list operations are not thread-safe and because of other
113 152 // race conditions such as the later check of cmdHandlerThread == null.
114 if (!m_Scenes.Contains(m_Scene)) 153 lock (staticLock)
115 m_Scenes.Add(m_Scene); 154 {
116 if (!m_ScriptEngines.Contains(m_ScriptEngine)) 155 if (m_ScriptEngines.Count == 0)
117 m_ScriptEngines.Add(m_ScriptEngine); 156 ReadConfig();
118 157
119 // Create instances of all plugins 158 if (!m_ScriptEngines.Contains(m_ScriptEngine))
120 if (!m_Dataserver.ContainsKey(m_ScriptEngine)) 159 m_ScriptEngines.Add(m_ScriptEngine);
121 m_Dataserver[m_ScriptEngine] = new Dataserver(this); 160
122 if (!m_Timer.ContainsKey(m_ScriptEngine)) 161 // Create instances of all plugins
123 m_Timer[m_ScriptEngine] = new Timer(this); 162 if (!m_Dataserver.ContainsKey(m_ScriptEngine))
124 if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) 163 m_Dataserver[m_ScriptEngine] = new Dataserver(this);
125 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); 164 if (!m_Timer.ContainsKey(m_ScriptEngine))
126 if (!m_Listener.ContainsKey(m_ScriptEngine)) 165 m_Timer[m_ScriptEngine] = new Timer(this);
127 m_Listener[m_ScriptEngine] = new Listener(this); 166 if (!m_HttpRequest.ContainsKey(m_ScriptEngine))
128 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) 167 m_HttpRequest[m_ScriptEngine] = new HttpRequest(this);
129 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); 168 if (!m_Listener.ContainsKey(m_ScriptEngine))
130 if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) 169 m_Listener[m_ScriptEngine] = new Listener(this);
131 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); 170 if (!m_SensorRepeat.ContainsKey(m_ScriptEngine))
132 171 m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this);
133 StartThread(); 172 if (!m_XmlRequest.ContainsKey(m_ScriptEngine))
173 m_XmlRequest[m_ScriptEngine] = new XmlRequest(this);
174
175 StartThread();
176 }
134 } 177 }
135 178
136 private static void StartThread() 179 private static void StartThread()
@@ -179,42 +222,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
179 { 222 {
180 try 223 try
181 { 224 {
182 while (true) 225 Thread.Sleep(cmdHandlerThreadCycleSleepms);
183 {
184 Thread.Sleep(cmdHandlerThreadCycleSleepms);
185 226
186 DoOneCmdHandlerPass(); 227 DoOneCmdHandlerPass();
187 228
188 Watchdog.UpdateThread(); 229 Watchdog.UpdateThread();
189 }
190 } 230 }
191 catch 231 catch (Exception e)
192 { 232 {
233 m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e);
193 } 234 }
194 } 235 }
195 } 236 }
196 237
197 private static void DoOneCmdHandlerPass() 238 private static void DoOneCmdHandlerPass()
198 { 239 {
199 // Check HttpRequests 240 lock (staticLock)
200 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); 241 {
242 // Check HttpRequests
243 m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests();
201 244
202 // Check XMLRPCRequests 245 // Check XMLRPCRequests
203 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); 246 m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests();
204 247
205 foreach (IScriptEngine s in m_ScriptEngines) 248 foreach (IScriptEngine s in m_ScriptEngines)
206 { 249 {
207 // Check Listeners 250 // Check Listeners
208 m_Listener[s].CheckListeners(); 251 m_Listener[s].CheckListeners();
209 252
210 // Check timers 253 // Check timers
211 m_Timer[s].CheckTimerEvents(); 254 m_Timer[s].CheckTimerEvents();
212 255
213 // Check Sensors 256 // Check Sensors
214 m_SensorRepeat[s].CheckSenseRepeaterEvents(); 257 m_SensorRepeat[s].CheckSenseRepeaterEvents();
215 258
216 // Check dataserver 259 // Check dataserver
217 m_Dataserver[s].ExpireRequests(); 260 m_Dataserver[s].ExpireRequests();
261 }
218 } 262 }
219 } 263 }
220 264
@@ -226,31 +270,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
226 public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) 270 public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
227 { 271 {
228 // Remove a specific script 272 // Remove a specific script
273// m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID);
229 274
230 // Remove dataserver events 275 lock (staticLock)
231 m_Dataserver[engine].RemoveEvents(localID, itemID); 276 {
277 // Remove dataserver events
278 m_Dataserver[engine].RemoveEvents(localID, itemID);
232 279
233 // Remove from: Timers 280 // Remove from: Timers
234 m_Timer[engine].UnSetTimerEvents(localID, itemID); 281 m_Timer[engine].UnSetTimerEvents(localID, itemID);
235 282
236 // Remove from: HttpRequest 283 // Remove from: HttpRequest
237 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>(); 284 IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
238 if (iHttpReq != null) 285 if (iHttpReq != null)
239 iHttpReq.StopHttpRequest(localID, itemID); 286 iHttpReq.StopHttpRequest(localID, itemID);
240 287
241 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>(); 288 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
242 if (comms != null) 289 if (comms != null)
243 comms.DeleteListener(itemID); 290 comms.DeleteListener(itemID);
244 291
245 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>(); 292 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
246 if (xmlrpc != null) 293 if (xmlrpc != null)
247 { 294 {
248 xmlrpc.DeleteChannels(itemID); 295 xmlrpc.DeleteChannels(itemID);
249 xmlrpc.CancelSRDRequests(itemID); 296 xmlrpc.CancelSRDRequests(itemID);
250 } 297 }
251 298
252 // Remove Sensors 299 // Remove Sensors
253 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); 300 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
301 }
254 } 302 }
255 303
256 /// <summary> 304 /// <summary>
@@ -260,10 +308,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
260 /// <returns></returns> 308 /// <returns></returns>
261 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) 309 public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine)
262 { 310 {
263 if (m_SensorRepeat.ContainsKey(engine)) 311 lock (staticLock)
264 return m_SensorRepeat[engine]; 312 {
265 else 313 if (m_SensorRepeat.ContainsKey(engine))
266 return null; 314 return m_SensorRepeat[engine];
315 else
316 return null;
317 }
267 } 318 }
268 319
269 /// <summary> 320 /// <summary>
@@ -273,10 +324,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
273 /// <returns></returns> 324 /// <returns></returns>
274 public static Dataserver GetDataserverPlugin(IScriptEngine engine) 325 public static Dataserver GetDataserverPlugin(IScriptEngine engine)
275 { 326 {
276 if (m_Dataserver.ContainsKey(engine)) 327 lock (staticLock)
277 return m_Dataserver[engine]; 328 {
278 else 329 if (m_Dataserver.ContainsKey(engine))
279 return null; 330 return m_Dataserver[engine];
331 else
332 return null;
333 }
280 } 334 }
281 335
282 /// <summary> 336 /// <summary>
@@ -286,10 +340,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
286 /// <returns></returns> 340 /// <returns></returns>
287 public static Timer GetTimerPlugin(IScriptEngine engine) 341 public static Timer GetTimerPlugin(IScriptEngine engine)
288 { 342 {
289 if (m_Timer.ContainsKey(engine)) 343 lock (staticLock)
290 return m_Timer[engine]; 344 {
291 else 345 if (m_Timer.ContainsKey(engine))
292 return null; 346 return m_Timer[engine];
347 else
348 return null;
349 }
293 } 350 }
294 351
295 /// <summary> 352 /// <summary>
@@ -299,10 +356,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
299 /// <returns></returns> 356 /// <returns></returns>
300 public static Listener GetListenerPlugin(IScriptEngine engine) 357 public static Listener GetListenerPlugin(IScriptEngine engine)
301 { 358 {
302 if (m_Listener.ContainsKey(engine)) 359 lock (staticLock)
303 return m_Listener[engine]; 360 {
304 else 361 if (m_Listener.ContainsKey(engine))
305 return null; 362 return m_Listener[engine];
363 else
364 return null;
365 }
306 } 366 }
307 367
308 public static void StateChange(IScriptEngine engine, uint localID, UUID itemID) 368 public static void StateChange(IScriptEngine engine, uint localID, UUID itemID)
@@ -332,28 +392,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
332 { 392 {
333 List<Object> data = new List<Object>(); 393 List<Object> data = new List<Object>();
334 394
335 Object[] listeners = m_Listener[engine].GetSerializationData(itemID); 395 lock (staticLock)
336 if (listeners.Length > 0)
337 { 396 {
338 data.Add("listener"); 397 Object[] listeners = m_Listener[engine].GetSerializationData(itemID);
339 data.Add(listeners.Length); 398 if (listeners.Length > 0)
340 data.AddRange(listeners); 399 {
341 } 400 data.Add("listener");
401 data.Add(listeners.Length);
402 data.AddRange(listeners);
403 }
342 404
343 Object[] timers=m_Timer[engine].GetSerializationData(itemID); 405 Object[] timers=m_Timer[engine].GetSerializationData(itemID);
344 if (timers.Length > 0) 406 if (timers.Length > 0)
345 { 407 {
346 data.Add("timer"); 408 data.Add("timer");
347 data.Add(timers.Length); 409 data.Add(timers.Length);
348 data.AddRange(timers); 410 data.AddRange(timers);
349 } 411 }
350 412
351 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); 413 Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID);
352 if (sensors.Length > 0) 414 if (sensors.Length > 0)
353 { 415 {
354 data.Add("sensor"); 416 data.Add("sensor");
355 data.Add(sensors.Length); 417 data.Add(sensors.Length);
356 data.AddRange(sensors); 418 data.AddRange(sensors);
419 }
357 } 420 }
358 421
359 return data.ToArray(); 422 return data.ToArray();
@@ -378,41 +441,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
378 441
379 idx+=len; 442 idx+=len;
380 443
444 lock (staticLock)
445 {
381 switch (type) 446 switch (type)
382 { 447 {
383 case "listener": 448 case "listener":
384 m_Listener[engine].CreateFromData(localID, itemID, 449 m_Listener[engine].CreateFromData(localID, itemID,
385 hostID, item); 450 hostID, item);
386 break; 451 break;
387 case "timer": 452 case "timer":
388 m_Timer[engine].CreateFromData(localID, itemID, 453 m_Timer[engine].CreateFromData(localID, itemID,
389 hostID, item); 454 hostID, item);
390 break; 455 break;
391 case "sensor": 456 case "sensor":
392 m_SensorRepeat[engine].CreateFromData(localID, 457 m_SensorRepeat[engine].CreateFromData(localID,
393 itemID, hostID, item); 458 itemID, hostID, item);
394 break; 459 break;
460 }
395 } 461 }
396 } 462 }
397 } 463 }
398 } 464 }
399
400 #region Check llRemoteData channels
401
402 #endregion
403
404 #region Check llListeners
405
406 #endregion
407
408 /// <summary>
409 /// If set to true then threads and stuff should try to make a graceful exit
410 /// </summary>
411 public bool PleaseShutdown
412 {
413 get { return _PleaseShutdown; }
414 set { _PleaseShutdown = value; }
415 }
416 private bool _PleaseShutdown = false;
417 } 465 }
418} 466}
diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs
new file mode 100644
index 0000000..5a24ee3
--- /dev/null
+++ b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs
@@ -0,0 +1,119 @@
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.Reflection;
30using Nini.Config;
31using OpenSim.Server.Base;
32using OpenSim.Services.Interfaces;
33using OpenSim.Framework.Servers.HttpServer;
34using OpenSim.Framework;
35using OpenSim.Server.Handlers.Base;
36using log4net;
37
38namespace OpenSim.Server.Handlers.Profiles
39{
40 public class UserProfilesConnector: ServiceConnector
41 {
42 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44
45 // Our Local Module
46 public IUserProfilesService ServiceModule
47 {
48 get; private set;
49 }
50
51 // The HTTP server.
52 public IHttpServer Server
53 {
54 get; private set;
55 }
56
57 public string ConfigName
58 {
59 get; private set;
60 }
61
62 public bool Enabled
63 {
64 get; private set;
65 }
66
67 public UserProfilesConnector(IConfigSource config, IHttpServer server, string configName) :
68 base(config, server, configName)
69 {
70 ConfigName = "UserProfilesService";
71 if(!string.IsNullOrEmpty(configName))
72 ConfigName = configName;
73
74 IConfig serverConfig = config.Configs[ConfigName];
75 if (serverConfig == null)
76 throw new Exception(String.Format("No section {0} in config file", ConfigName));
77
78 if(!serverConfig.GetBoolean("Enabled",false))
79 {
80 Enabled = false;
81 return;
82 }
83
84 Enabled = true;
85
86 Server = server;
87
88 string service = serverConfig.GetString("LocalServiceModule", String.Empty);
89
90 Object[] args = new Object[] { config, ConfigName };
91 ServiceModule = ServerUtils.LoadPlugin<IUserProfilesService>(service, args);
92
93 JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule);
94
95 Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest);
96 Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate);
97 Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest);
98 Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete);
99 Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest);
100 Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest);
101 Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate);
102 Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete);
103 Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest);
104 Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate);
105 Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest);
106 Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate);
107 Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate);
108 Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest);
109// Server.AddJsonRPCHandler("user_preferences_request", handler.UserPreferencesRequest);
110// Server.AddJsonRPCHandler("user_preferences_update", handler.UserPreferencesUpdate);
111// Server.AddJsonRPCHandler("user_account_create", handler.UserAccountCreate);
112// Server.AddJsonRPCHandler("user_account_auth", handler.UserAccountAuth);
113// Server.AddJsonRPCHandler("user_account_test", handler.UserAccountTest);
114 Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData);
115 Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData);
116 }
117 }
118}
119
diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs
new file mode 100644
index 0000000..f5f0794
--- /dev/null
+++ b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs
@@ -0,0 +1,461 @@
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.Reflection;
30using OpenMetaverse;
31using OpenMetaverse.StructuredData;
32using log4net;
33using OpenSim.Services.Interfaces;
34using OpenSim.Framework.Servers.HttpServer;
35using OpenSim.Framework;
36
37namespace OpenSim.Server.Handlers
38{
39 public class UserProfilesHandlers
40 {
41 public UserProfilesHandlers ()
42 {
43 }
44 }
45
46 public class JsonRpcProfileHandlers
47 {
48 static readonly ILog m_log =
49 LogManager.GetLogger(
50 MethodBase.GetCurrentMethod().DeclaringType);
51
52 public IUserProfilesService Service
53 {
54 get; private set;
55 }
56
57 public JsonRpcProfileHandlers(IUserProfilesService service)
58 {
59 Service = service;
60 }
61
62 #region Classifieds
63 /// <summary>
64 /// Request avatar's classified ads.
65 /// </summary>
66 /// <returns>
67 /// An array containing all the calassified uuid and it's name created by the creator id
68 /// </returns>
69 /// <param name='json'>
70 /// Our parameters are in the OSDMap json["params"]
71 /// </param>
72 /// <param name='response'>
73 /// If set to <c>true</c> response.
74 /// </param>
75 public bool AvatarClassifiedsRequest(OSDMap json, ref JsonRpcResponse response)
76 {
77 if(!json.ContainsKey("params"))
78 {
79 response.Error.Code = ErrorCode.ParseError;
80 m_log.DebugFormat ("Classified Request");
81 return false;
82 }
83
84 OSDMap request = (OSDMap)json["params"];
85 UUID creatorId = new UUID(request["creatorId"].AsString());
86
87
88 OSDArray data = (OSDArray) Service.AvatarClassifiedsRequest(creatorId);
89 response.Result = data;
90
91 return true;
92 }
93
94 public bool ClassifiedUpdate(OSDMap json, ref JsonRpcResponse response)
95 {
96 if(!json.ContainsKey("params"))
97 {
98 response.Error.Code = ErrorCode.ParseError;
99 response.Error.Message = "Error parsing classified update request";
100 m_log.DebugFormat ("Classified Update Request");
101 return false;
102 }
103
104 string result = string.Empty;
105 UserClassifiedAdd ad = new UserClassifiedAdd();
106 object Ad = (object)ad;
107 OSD.DeserializeMembers(ref Ad, (OSDMap)json["params"]);
108 if(Service.ClassifiedUpdate(ad, ref result))
109 {
110 response.Result = OSD.SerializeMembers(ad);
111 return true;
112 }
113
114 response.Error.Code = ErrorCode.InternalError;
115 response.Error.Message = string.Format("{0}", result);
116 return false;
117 }
118
119 public bool ClassifiedDelete(OSDMap json, ref JsonRpcResponse response)
120 {
121 if(!json.ContainsKey("params"))
122 {
123 response.Error.Code = ErrorCode.ParseError;
124 m_log.DebugFormat ("Classified Delete Request");
125 return false;
126 }
127
128 OSDMap request = (OSDMap)json["params"];
129 UUID classifiedId = new UUID(request["classifiedID"].AsString());
130
131 OSDMap res = new OSDMap();
132 res["result"] = OSD.FromString("success");
133 response.Result = res;
134
135 return true;
136
137 }
138
139 public bool ClassifiedInfoRequest(OSDMap json, ref JsonRpcResponse response)
140 {
141 if(!json.ContainsKey("params"))
142 {
143 response.Error.Code = ErrorCode.ParseError;
144 response.Error.Message = "no parameters supplied";
145 m_log.DebugFormat ("Classified Info Request");
146 return false;
147 }
148
149 string result = string.Empty;
150 UserClassifiedAdd ad = new UserClassifiedAdd();
151 object Ad = (object)ad;
152 OSD.DeserializeMembers(ref Ad, (OSDMap)json["params"]);
153 if(Service.ClassifiedInfoRequest(ref ad, ref result))
154 {
155 response.Result = OSD.SerializeMembers(ad);
156 return true;
157 }
158
159 response.Error.Code = ErrorCode.InternalError;
160 response.Error.Message = string.Format("{0}", result);
161 return false;
162 }
163 #endregion Classifieds
164
165 #region Picks
166 public bool AvatarPicksRequest(OSDMap json, ref JsonRpcResponse response)
167 {
168 if(!json.ContainsKey("params"))
169 {
170 response.Error.Code = ErrorCode.ParseError;
171 m_log.DebugFormat ("Avatar Picks Request");
172 return false;
173 }
174
175 OSDMap request = (OSDMap)json["params"];
176 UUID creatorId = new UUID(request["creatorId"].AsString());
177
178
179 OSDArray data = (OSDArray) Service.AvatarPicksRequest(creatorId);
180 response.Result = data;
181
182 return true;
183 }
184
185 public bool PickInfoRequest(OSDMap json, ref JsonRpcResponse response)
186 {
187 if(!json.ContainsKey("params"))
188 {
189 response.Error.Code = ErrorCode.ParseError;
190 response.Error.Message = "no parameters supplied";
191 m_log.DebugFormat ("Avatar Picks Info Request");
192 return false;
193 }
194
195 string result = string.Empty;
196 UserProfilePick pick = new UserProfilePick();
197 object Pick = (object)pick;
198 OSD.DeserializeMembers(ref Pick, (OSDMap)json["params"]);
199 if(Service.PickInfoRequest(ref pick, ref result))
200 {
201 response.Result = OSD.SerializeMembers(pick);
202 return true;
203 }
204
205 response.Error.Code = ErrorCode.InternalError;
206 response.Error.Message = string.Format("{0}", result);
207 return false;
208 }
209
210 public bool PicksUpdate(OSDMap json, ref JsonRpcResponse response)
211 {
212 if(!json.ContainsKey("params"))
213 {
214 response.Error.Code = ErrorCode.ParseError;
215 response.Error.Message = "no parameters supplied";
216 m_log.DebugFormat ("Avatar Picks Update Request");
217 return false;
218 }
219
220 string result = string.Empty;
221 UserProfilePick pick = new UserProfilePick();
222 object Pick = (object)pick;
223 OSD.DeserializeMembers(ref Pick, (OSDMap)json["params"]);
224 if(Service.PicksUpdate(ref pick, ref result))
225 {
226 response.Result = OSD.SerializeMembers(pick);
227 return true;
228 }
229
230 response.Error.Code = ErrorCode.InternalError;
231 response.Error.Message = "unable to update pick";
232
233 return false;
234 }
235
236 public bool PicksDelete(OSDMap json, ref JsonRpcResponse response)
237 {
238 if(!json.ContainsKey("params"))
239 {
240 response.Error.Code = ErrorCode.ParseError;
241 m_log.DebugFormat ("Avatar Picks Delete Request");
242 return false;
243 }
244
245 OSDMap request = (OSDMap)json["params"];
246 UUID pickId = new UUID(request["pickId"].AsString());
247 if(Service.PicksDelete(pickId))
248 return true;
249
250 response.Error.Code = ErrorCode.InternalError;
251 response.Error.Message = "data error removing record";
252 return false;
253 }
254 #endregion Picks
255
256 #region Notes
257 public bool AvatarNotesRequest(OSDMap json, ref JsonRpcResponse response)
258 {
259 if(!json.ContainsKey("params"))
260 {
261 response.Error.Code = ErrorCode.ParseError;
262 response.Error.Message = "Params missing";
263 m_log.DebugFormat ("Avatar Notes Request");
264 return false;
265 }
266
267 string result = string.Empty;
268 UserProfileNotes note = new UserProfileNotes();
269 object Note = (object)note;
270 OSD.DeserializeMembers(ref Note, (OSDMap)json["params"]);
271 if(Service.AvatarNotesRequest(ref note))
272 {
273 response.Result = OSD.SerializeMembers(note);
274 return true;
275 }
276
277 object Notes = (object) note;
278 OSD.DeserializeMembers(ref Notes, (OSDMap)json["params"]);
279 return true;
280 }
281
282 public bool NotesUpdate(OSDMap json, ref JsonRpcResponse response)
283 {
284 if(!json.ContainsKey("params"))
285 {
286 response.Error.Code = ErrorCode.ParseError;
287 response.Error.Message = "No parameters";
288 m_log.DebugFormat ("Avatar Notes Update Request");
289 return false;
290 }
291
292 string result = string.Empty;
293 UserProfileNotes note = new UserProfileNotes();
294 object Notes = (object) note;
295 OSD.DeserializeMembers(ref Notes, (OSDMap)json["params"]);
296 if(Service.NotesUpdate(ref note, ref result))
297 {
298 response.Result = OSD.SerializeMembers(note);
299 return true;
300 }
301 return true;
302 }
303 #endregion Notes
304
305 #region Profile Properties
306 public bool AvatarPropertiesRequest(OSDMap json, ref JsonRpcResponse response)
307 {
308 if(!json.ContainsKey("params"))
309 {
310 response.Error.Code = ErrorCode.ParseError;
311 response.Error.Message = "no parameters supplied";
312 m_log.DebugFormat ("Avatar Properties Request");
313 return false;
314 }
315
316 string result = string.Empty;
317 UserProfileProperties props = new UserProfileProperties();
318 object Props = (object)props;
319 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
320 if(Service.AvatarPropertiesRequest(ref props, ref result))
321 {
322 response.Result = OSD.SerializeMembers(props);
323 return true;
324 }
325
326 response.Error.Code = ErrorCode.InternalError;
327 response.Error.Message = string.Format("{0}", result);
328 return false;
329 }
330
331 public bool AvatarPropertiesUpdate(OSDMap json, ref JsonRpcResponse response)
332 {
333 if(!json.ContainsKey("params"))
334 {
335 response.Error.Code = ErrorCode.ParseError;
336 response.Error.Message = "no parameters supplied";
337 m_log.DebugFormat ("Avatar Properties Update Request");
338 return false;
339 }
340
341 string result = string.Empty;
342 UserProfileProperties props = new UserProfileProperties();
343 object Props = (object)props;
344 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
345 if(Service.AvatarPropertiesUpdate(ref props, ref result))
346 {
347 response.Result = OSD.SerializeMembers(props);
348 return true;
349 }
350
351 response.Error.Code = ErrorCode.InternalError;
352 response.Error.Message = string.Format("{0}", result);
353 return false;
354 }
355 #endregion Profile Properties
356
357 #region Interests
358 public bool AvatarInterestsUpdate(OSDMap json, ref JsonRpcResponse response)
359 {
360 if(!json.ContainsKey("params"))
361 {
362 response.Error.Code = ErrorCode.ParseError;
363 response.Error.Message = "no parameters supplied";
364 m_log.DebugFormat ("Avatar Interests Update Request");
365 return false;
366 }
367
368 string result = string.Empty;
369 UserProfileProperties props = new UserProfileProperties();
370 object Props = (object)props;
371 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
372 if(Service.AvatarInterestsUpdate(props, ref result))
373 {
374 response.Result = OSD.SerializeMembers(props);
375 return true;
376 }
377
378 response.Error.Code = ErrorCode.InternalError;
379 response.Error.Message = string.Format("{0}", result);
380 return false;
381 }
382 #endregion Interests
383
384 #region Utility
385 public bool AvatarImageAssetsRequest(OSDMap json, ref JsonRpcResponse response)
386 {
387 if(!json.ContainsKey("params"))
388 {
389 response.Error.Code = ErrorCode.ParseError;
390 m_log.DebugFormat ("Avatar Image Assets Request");
391 return false;
392 }
393
394 OSDMap request = (OSDMap)json["params"];
395 UUID avatarId = new UUID(request["avatarId"].AsString());
396
397 OSDArray data = (OSDArray) Service.AvatarImageAssetsRequest(avatarId);
398 response.Result = data;
399
400 return true;
401 }
402 #endregion Utiltiy
403
404 #region UserData
405 public bool RequestUserAppData(OSDMap json, ref JsonRpcResponse response)
406 {
407 if(!json.ContainsKey("params"))
408 {
409 response.Error.Code = ErrorCode.ParseError;
410 response.Error.Message = "no parameters supplied";
411 m_log.DebugFormat ("User Application Service URL Request: No Parameters!");
412 return false;
413 }
414
415 string result = string.Empty;
416 UserAppData props = new UserAppData();
417 object Props = (object)props;
418 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
419 if(Service.RequestUserAppData(ref props, ref result))
420 {
421 OSDMap res = new OSDMap();
422 res["result"] = OSD.FromString("success");
423 res["token"] = OSD.FromString (result);
424 response.Result = res;
425
426 return true;
427 }
428
429 response.Error.Code = ErrorCode.InternalError;
430 response.Error.Message = string.Format("{0}", result);
431 return false;
432 }
433
434 public bool UpdateUserAppData(OSDMap json, ref JsonRpcResponse response)
435 {
436 if(!json.ContainsKey("params"))
437 {
438 response.Error.Code = ErrorCode.ParseError;
439 response.Error.Message = "no parameters supplied";
440 m_log.DebugFormat ("User App Data Update Request");
441 return false;
442 }
443
444 string result = string.Empty;
445 UserAppData props = new UserAppData();
446 object Props = (object)props;
447 OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]);
448 if(Service.SetUserAppData(props, ref result))
449 {
450 response.Result = OSD.SerializeMembers(props);
451 return true;
452 }
453
454 response.Error.Code = ErrorCode.InternalError;
455 response.Error.Message = string.Format("{0}", result);
456 return false;
457 }
458 #endregion UserData
459 }
460}
461
diff --git a/OpenSim/Services/Interfaces/IUserProfilesService.cs b/OpenSim/Services/Interfaces/IUserProfilesService.cs
new file mode 100644
index 0000000..319d307
--- /dev/null
+++ b/OpenSim/Services/Interfaces/IUserProfilesService.cs
@@ -0,0 +1,75 @@
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 OpenSim.Framework;
30using OpenMetaverse;
31using OpenMetaverse.StructuredData;
32
33namespace OpenSim.Services.Interfaces
34{
35 public interface IUserProfilesService
36 {
37 #region Classifieds
38 OSD AvatarClassifiedsRequest(UUID creatorId);
39 bool ClassifiedUpdate(UserClassifiedAdd ad, ref string result);
40 bool ClassifiedInfoRequest(ref UserClassifiedAdd ad, ref string result);
41 bool ClassifiedDelete(UUID recordId);
42 #endregion Classifieds
43
44 #region Picks
45 OSD AvatarPicksRequest(UUID creatorId);
46 bool PickInfoRequest(ref UserProfilePick pick, ref string result);
47 bool PicksUpdate(ref UserProfilePick pick, ref string result);
48 bool PicksDelete(UUID pickId);
49 #endregion Picks
50
51 #region Notes
52 bool AvatarNotesRequest(ref UserProfileNotes note);
53 bool NotesUpdate(ref UserProfileNotes note, ref string result);
54 #endregion Notes
55
56 #region Profile Properties
57 bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result);
58 bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result);
59 #endregion Profile Properties
60
61 #region Interests
62 bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result);
63 #endregion Interests
64
65 #region Utility
66 OSD AvatarImageAssetsRequest(UUID avatarId);
67 #endregion Utility
68
69 #region UserData
70 bool RequestUserAppData(ref UserAppData prop, ref string result);
71 bool SetUserAppData(UserAppData prop, ref string result);
72 #endregion UserData
73 }
74}
75
diff --git a/OpenSim/Services/UserProfilesService/UserProfilesService.cs b/OpenSim/Services/UserProfilesService/UserProfilesService.cs
new file mode 100644
index 0000000..d00f34d
--- /dev/null
+++ b/OpenSim/Services/UserProfilesService/UserProfilesService.cs
@@ -0,0 +1,187 @@
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.Reflection;
30using System.Text;
31using Nini.Config;
32using log4net;
33using OpenSim.Server.Base;
34using OpenSim.Services.Interfaces;
35using OpenSim.Services.UserAccountService;
36using OpenSim.Data;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40
41namespace OpenSim.Services.ProfilesService
42{
43 public class UserProfilesService: UserProfilesServiceBase, IUserProfilesService
44 {
45 static readonly ILog m_log =
46 LogManager.GetLogger(
47 MethodBase.GetCurrentMethod().DeclaringType);
48
49 IUserAccountService userAccounts;
50 IAuthenticationService authService;
51
52 public UserProfilesService(IConfigSource config, string configName):
53 base(config, configName)
54 {
55 IConfig Config = config.Configs[configName];
56 if (Config == null)
57 {
58 m_log.Warn("[PROFILES]: No configuration found!");
59 return;
60 }
61 Object[] args = null;
62
63 args = new Object[] { config };
64 string accountService = Config.GetString("UserAccountService", String.Empty);
65 if (accountService != string.Empty)
66 userAccounts = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
67
68 args = new Object[] { config };
69 string authServiceConfig = Config.GetString("AuthenticationServiceModule", String.Empty);
70 if (accountService != string.Empty)
71 authService = ServerUtils.LoadPlugin<IAuthenticationService>(authServiceConfig, args);
72 }
73
74 #region Classifieds
75 public OSD AvatarClassifiedsRequest(UUID creatorId)
76 {
77 OSDArray records = ProfilesData.GetClassifiedRecords(creatorId);
78
79 return records;
80 }
81
82 public bool ClassifiedUpdate(UserClassifiedAdd ad, ref string result)
83 {
84 if(!ProfilesData.UpdateClassifiedRecord(ad, ref result))
85 {
86 return false;
87 }
88 result = "success";
89 return true;
90 }
91
92 public bool ClassifiedDelete(UUID recordId)
93 {
94 if(ProfilesData.DeleteClassifiedRecord(recordId))
95 return true;
96
97 return false;
98 }
99
100 public bool ClassifiedInfoRequest(ref UserClassifiedAdd ad, ref string result)
101 {
102 if(ProfilesData.GetClassifiedInfo(ref ad, ref result))
103 return true;
104
105 return false;
106 }
107 #endregion Classifieds
108
109 #region Picks
110 public OSD AvatarPicksRequest(UUID creatorId)
111 {
112 OSDArray records = ProfilesData.GetAvatarPicks(creatorId);
113
114 return records;
115 }
116
117 public bool PickInfoRequest(ref UserProfilePick pick, ref string result)
118 {
119 pick = ProfilesData.GetPickInfo(pick.CreatorId, pick.PickId);
120 result = "OK";
121 return true;
122 }
123
124 public bool PicksUpdate(ref UserProfilePick pick, ref string result)
125 {
126 return ProfilesData.UpdatePicksRecord(pick);
127 }
128
129 public bool PicksDelete(UUID pickId)
130 {
131 return ProfilesData.DeletePicksRecord(pickId);
132 }
133 #endregion Picks
134
135 #region Notes
136 public bool AvatarNotesRequest(ref UserProfileNotes note)
137 {
138 return ProfilesData.GetAvatarNotes(ref note);
139 }
140
141 public bool NotesUpdate(ref UserProfileNotes note, ref string result)
142 {
143 return ProfilesData.UpdateAvatarNotes(ref note, ref result);
144 }
145 #endregion Notes
146
147 #region Profile Properties
148 public bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result)
149 {
150 return ProfilesData.GetAvatarProperties(ref prop, ref result);
151 }
152
153 public bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result)
154 {
155 return ProfilesData.UpdateAvatarProperties(ref prop, ref result);
156 }
157 #endregion Profile Properties
158
159 #region Interests
160 public bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result)
161 {
162 return ProfilesData.UpdateAvatarInterests(prop, ref result);
163 }
164 #endregion Interests
165
166 #region Utility
167 public OSD AvatarImageAssetsRequest(UUID avatarId)
168 {
169 OSDArray records = ProfilesData.GetUserImageAssets(avatarId);
170 return records;
171 }
172 #endregion Utility
173
174 #region UserData
175 public bool RequestUserAppData(ref UserAppData prop, ref string result)
176 {
177 return ProfilesData.GetUserAppData(ref prop, ref result);
178 }
179
180 public bool SetUserAppData(UserAppData prop, ref string result)
181 {
182 return true;
183 }
184 #endregion UserData
185 }
186}
187
diff --git a/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs
new file mode 100644
index 0000000..927f7c9
--- /dev/null
+++ b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs
@@ -0,0 +1,86 @@
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.Reflection;
30using Nini.Config;
31using log4net;
32using OpenSim.Services.Base;
33using OpenSim.Data;
34
35namespace OpenSim.Services.ProfilesService
36{
37 public class UserProfilesServiceBase: ServiceBase
38 {
39 static readonly ILog m_log =
40 LogManager.GetLogger(
41 MethodBase.GetCurrentMethod().DeclaringType);
42
43 public IProfilesData ProfilesData;
44
45 public string ConfigName
46 {
47 get; private set;
48 }
49
50 public UserProfilesServiceBase(IConfigSource config, string configName):
51 base(config)
52 {
53 if(string.IsNullOrEmpty(configName))
54 {
55 m_log.WarnFormat("[PROFILES]: Configuration section not given!");
56 return;
57 }
58
59 string dllName = String.Empty;
60 string connString = null;
61 string realm = String.Empty;
62
63 IConfig dbConfig = config.Configs["DatabaseService"];
64 if (dbConfig != null)
65 {
66 if (dllName == String.Empty)
67 dllName = dbConfig.GetString("StorageProvider", String.Empty);
68 if (string.IsNullOrEmpty(connString))
69 connString = dbConfig.GetString("ConnectionString", String.Empty);
70 }
71
72 IConfig ProfilesConfig = config.Configs[configName];
73 if (ProfilesConfig != null)
74 {
75 connString = ProfilesConfig.GetString("ConnectionString", connString);
76 realm = ProfilesConfig.GetString("Realm", realm);
77 }
78
79 ProfilesData = LoadPlugin<IProfilesData>(dllName, new Object[] { connString });
80 if (ProfilesData == null)
81 throw new Exception("Could not find a storage interface in the given module");
82
83 }
84 }
85}
86