aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Addons
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Addons
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Addons')
-rw-r--r--OpenSim/Addons/Groups/ForeignImporter.cs78
-rw-r--r--OpenSim/Addons/Groups/GroupsExtendedData.cs533
-rw-r--r--OpenSim/Addons/Groups/GroupsMessagingModule.cs848
-rw-r--r--OpenSim/Addons/Groups/GroupsModule.cs1467
-rw-r--r--OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs289
-rw-r--r--OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs707
-rw-r--r--OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs444
-rw-r--r--OpenSim/Addons/Groups/IGroupsServicesConnector.cs112
-rw-r--r--OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs326
-rw-r--r--OpenSim/Addons/Groups/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs696
-rw-r--r--OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs408
-rw-r--r--OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs816
-rw-r--r--OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs888
-rw-r--r--OpenSim/Addons/Groups/Service/GroupsService.cs1060
-rw-r--r--OpenSim/Addons/Groups/Service/GroupsServiceBase.cs101
-rw-r--r--OpenSim/Addons/Groups/Service/HGGroupsService.cs361
-rw-r--r--OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs268
-rw-r--r--OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs171
-rw-r--r--OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs223
-rw-r--r--OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs135
-rw-r--r--OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs83
23 files changed, 10086 insertions, 0 deletions
diff --git a/OpenSim/Addons/Groups/ForeignImporter.cs b/OpenSim/Addons/Groups/ForeignImporter.cs
new file mode 100644
index 0000000..055f76c
--- /dev/null
+++ b/OpenSim/Addons/Groups/ForeignImporter.cs
@@ -0,0 +1,78 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Services.Interfaces;
34
35namespace OpenSim.Groups
36{
37 public class ForeignImporter
38 {
39 IUserManagement m_UserManagement;
40 public ForeignImporter(IUserManagement uman)
41 {
42 m_UserManagement = uman;
43 }
44
45 public GroupMembersData ConvertGroupMembersData(ExtendedGroupMembersData _m)
46 {
47 GroupMembersData m = new GroupMembersData();
48 m.AcceptNotices = _m.AcceptNotices;
49 m.AgentPowers = _m.AgentPowers;
50 m.Contribution = _m.Contribution;
51 m.IsOwner = _m.IsOwner;
52 m.ListInProfile = _m.ListInProfile;
53 m.OnlineStatus = _m.OnlineStatus;
54 m.Title = _m.Title;
55
56 string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
57 Util.ParseUniversalUserIdentifier(_m.AgentID, out m.AgentID, out url, out first, out last, out tmp);
58 if (url != string.Empty)
59 m_UserManagement.AddUser(m.AgentID, first, last, url);
60
61 return m;
62 }
63
64 public GroupRoleMembersData ConvertGroupRoleMembersData(ExtendedGroupRoleMembersData _rm)
65 {
66 GroupRoleMembersData rm = new GroupRoleMembersData();
67 rm.RoleID = _rm.RoleID;
68
69 string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
70 Util.ParseUniversalUserIdentifier(_rm.MemberID, out rm.MemberID, out url, out first, out last, out tmp);
71 if (url != string.Empty)
72 m_UserManagement.AddUser(rm.MemberID, first, last, url);
73
74 return rm;
75 }
76
77 }
78}
diff --git a/OpenSim/Addons/Groups/GroupsExtendedData.cs b/OpenSim/Addons/Groups/GroupsExtendedData.cs
new file mode 100644
index 0000000..c783b9e
--- /dev/null
+++ b/OpenSim/Addons/Groups/GroupsExtendedData.cs
@@ -0,0 +1,533 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31using OpenSim.Framework;
32using OpenMetaverse;
33
34namespace OpenSim.Groups
35{
36 public class ExtendedGroupRecord : GroupRecord
37 {
38 public int MemberCount;
39 public int RoleCount;
40 public string ServiceLocation;
41 public string FounderUUI;
42 }
43
44 public class ExtendedGroupMembershipData : GroupMembershipData
45 {
46 public string AccessToken;
47 }
48
49 public class ExtendedGroupMembersData
50 {
51 // This is the only difference: this is a string
52 public string AgentID;
53 public int Contribution;
54 public string OnlineStatus;
55 public ulong AgentPowers;
56 public string Title;
57 public bool IsOwner;
58 public bool ListInProfile;
59 public bool AcceptNotices;
60 public string AccessToken;
61 }
62
63 public class ExtendedGroupRoleMembersData
64 {
65 public UUID RoleID;
66 // This is the only difference: this is a string
67 public string MemberID;
68
69 }
70
71 public struct ExtendedGroupNoticeData
72 {
73 public UUID NoticeID;
74 public uint Timestamp;
75 public string FromName;
76 public string Subject;
77 public bool HasAttachment;
78 public byte AttachmentType;
79 public string AttachmentName;
80 public UUID AttachmentItemID;
81 public string AttachmentOwnerID;
82
83 public GroupNoticeData ToGroupNoticeData()
84 {
85 GroupNoticeData n = new GroupNoticeData();
86 n.FromName = this.FromName;
87 n.AssetType = this.AttachmentType;
88 n.HasAttachment = this.HasAttachment;
89 n.NoticeID = this.NoticeID;
90 n.Subject = this.Subject;
91 n.Timestamp = this.Timestamp;
92
93 return n;
94 }
95 }
96
97 public class GroupsDataUtils
98 {
99 public static string Sanitize(string s)
100 {
101 return s == null ? string.Empty : s;
102 }
103
104 public static Dictionary<string, object> GroupRecord(ExtendedGroupRecord grec)
105 {
106 Dictionary<string, object> dict = new Dictionary<string, object>();
107 if (grec == null)
108 return dict;
109
110 dict["AllowPublish"] = grec.AllowPublish.ToString();
111 dict["Charter"] = Sanitize(grec.Charter);
112 dict["FounderID"] = grec.FounderID.ToString();
113 dict["FounderUUI"] = Sanitize(grec.FounderUUI);
114 dict["GroupID"] = grec.GroupID.ToString();
115 dict["GroupName"] = Sanitize(grec.GroupName);
116 dict["InsigniaID"] = grec.GroupPicture.ToString();
117 dict["MaturePublish"] = grec.MaturePublish.ToString();
118 dict["MembershipFee"] = grec.MembershipFee.ToString();
119 dict["OpenEnrollment"] = grec.OpenEnrollment.ToString();
120 dict["OwnerRoleID"] = grec.OwnerRoleID.ToString();
121 dict["ServiceLocation"] = Sanitize(grec.ServiceLocation);
122 dict["ShownInList"] = grec.ShowInList.ToString();
123 dict["MemberCount"] = grec.MemberCount.ToString();
124 dict["RoleCount"] = grec.RoleCount.ToString();
125
126 return dict;
127 }
128
129 public static ExtendedGroupRecord GroupRecord(Dictionary<string, object> dict)
130 {
131 if (dict == null)
132 return null;
133
134 ExtendedGroupRecord grec = new ExtendedGroupRecord();
135 if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null)
136 grec.AllowPublish = bool.Parse(dict["AllowPublish"].ToString());
137
138 if (dict.ContainsKey("Charter") && dict["Charter"] != null)
139 grec.Charter = dict["Charter"].ToString();
140 else
141 grec.Charter = string.Empty;
142
143 if (dict.ContainsKey("FounderID") && dict["FounderID"] != null)
144 grec.FounderID = UUID.Parse(dict["FounderID"].ToString());
145
146 if (dict.ContainsKey("FounderUUI") && dict["FounderUUI"] != null)
147 grec.FounderUUI = dict["FounderUUI"].ToString();
148 else
149 grec.FounderUUI = string.Empty;
150
151 if (dict.ContainsKey("GroupID") && dict["GroupID"] != null)
152 grec.GroupID = UUID.Parse(dict["GroupID"].ToString());
153
154 if (dict.ContainsKey("GroupName") && dict["GroupName"] != null)
155 grec.GroupName = dict["GroupName"].ToString();
156 else
157 grec.GroupName = string.Empty;
158
159 if (dict.ContainsKey("InsigniaID") && dict["InsigniaID"] != null)
160 grec.GroupPicture = UUID.Parse(dict["InsigniaID"].ToString());
161
162 if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null)
163 grec.MaturePublish = bool.Parse(dict["MaturePublish"].ToString());
164
165 if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null)
166 grec.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString());
167
168 if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null)
169 grec.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString());
170
171 if (dict.ContainsKey("OwnerRoleID") && dict["OwnerRoleID"] != null)
172 grec.OwnerRoleID = UUID.Parse(dict["OwnerRoleID"].ToString());
173
174 if (dict.ContainsKey("ServiceLocation") && dict["ServiceLocation"] != null)
175 grec.ServiceLocation = dict["ServiceLocation"].ToString();
176 else
177 grec.ServiceLocation = string.Empty;
178
179 if (dict.ContainsKey("ShownInList") && dict["ShownInList"] != null)
180 grec.ShowInList = bool.Parse(dict["ShownInList"].ToString());
181
182 if (dict.ContainsKey("MemberCount") && dict["MemberCount"] != null)
183 grec.MemberCount = Int32.Parse(dict["MemberCount"].ToString());
184
185 if (dict.ContainsKey("RoleCount") && dict["RoleCount"] != null)
186 grec.RoleCount = Int32.Parse(dict["RoleCount"].ToString());
187
188 return grec;
189 }
190
191 public static Dictionary<string, object> GroupMembershipData(ExtendedGroupMembershipData membership)
192 {
193 Dictionary<string, object> dict = new Dictionary<string, object>();
194 if (membership == null)
195 return dict;
196
197 dict["AcceptNotices"] = membership.AcceptNotices.ToString();
198 dict["AccessToken"] = Sanitize(membership.AccessToken);
199 dict["Active"] = membership.Active.ToString();
200 dict["ActiveRole"] = membership.ActiveRole.ToString();
201 dict["AllowPublish"] = membership.AllowPublish.ToString();
202 dict["Charter"] = Sanitize(membership.Charter);
203 dict["Contribution"] = membership.Contribution.ToString();
204 dict["FounderID"] = membership.FounderID.ToString();
205 dict["GroupID"] = membership.GroupID.ToString();
206 dict["GroupName"] = Sanitize(membership.GroupName);
207 dict["GroupPicture"] = membership.GroupPicture.ToString();
208 dict["GroupPowers"] = membership.GroupPowers.ToString();
209 dict["GroupTitle"] = Sanitize(membership.GroupTitle);
210 dict["ListInProfile"] = membership.ListInProfile.ToString();
211 dict["MaturePublish"] = membership.MaturePublish.ToString();
212 dict["MembershipFee"] = membership.MembershipFee.ToString();
213 dict["OpenEnrollment"] = membership.OpenEnrollment.ToString();
214 dict["ShowInList"] = membership.ShowInList.ToString();
215
216 return dict;
217 }
218
219 public static ExtendedGroupMembershipData GroupMembershipData(Dictionary<string, object> dict)
220 {
221 if (dict == null)
222 return null;
223
224 ExtendedGroupMembershipData membership = new ExtendedGroupMembershipData();
225
226 if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null)
227 membership.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString());
228
229 if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null)
230 membership.AccessToken = dict["AccessToken"].ToString();
231 else
232 membership.AccessToken = string.Empty;
233
234 if (dict.ContainsKey("Active") && dict["Active"] != null)
235 membership.Active = bool.Parse(dict["Active"].ToString());
236
237 if (dict.ContainsKey("ActiveRole") && dict["ActiveRole"] != null)
238 membership.ActiveRole = UUID.Parse(dict["ActiveRole"].ToString());
239
240 if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null)
241 membership.AllowPublish = bool.Parse(dict["AllowPublish"].ToString());
242
243 if (dict.ContainsKey("Charter") && dict["Charter"] != null)
244 membership.Charter = dict["Charter"].ToString();
245 else
246 membership.Charter = string.Empty;
247
248 if (dict.ContainsKey("Contribution") && dict["Contribution"] != null)
249 membership.Contribution = Int32.Parse(dict["Contribution"].ToString());
250
251 if (dict.ContainsKey("FounderID") && dict["FounderID"] != null)
252 membership.FounderID = UUID.Parse(dict["FounderID"].ToString());
253
254 if (dict.ContainsKey("GroupID") && dict["GroupID"] != null)
255 membership.GroupID = UUID.Parse(dict["GroupID"].ToString());
256
257 if (dict.ContainsKey("GroupName") && dict["GroupName"] != null)
258 membership.GroupName = dict["GroupName"].ToString();
259 else
260 membership.GroupName = string.Empty;
261
262 if (dict.ContainsKey("GroupPicture") && dict["GroupPicture"] != null)
263 membership.GroupPicture = UUID.Parse(dict["GroupPicture"].ToString());
264
265 if (dict.ContainsKey("GroupPowers") && dict["GroupPowers"] != null)
266 membership.GroupPowers = UInt64.Parse(dict["GroupPowers"].ToString());
267
268 if (dict.ContainsKey("GroupTitle") && dict["GroupTitle"] != null)
269 membership.GroupTitle = dict["GroupTitle"].ToString();
270 else
271 membership.GroupTitle = string.Empty;
272
273 if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null)
274 membership.ListInProfile = bool.Parse(dict["ListInProfile"].ToString());
275
276 if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null)
277 membership.MaturePublish = bool.Parse(dict["MaturePublish"].ToString());
278
279 if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null)
280 membership.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString());
281
282 if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null)
283 membership.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString());
284
285 if (dict.ContainsKey("ShowInList") && dict["ShowInList"] != null)
286 membership.ShowInList = bool.Parse(dict["ShowInList"].ToString());
287
288 return membership;
289 }
290
291 public static Dictionary<string, object> GroupMembersData(ExtendedGroupMembersData member)
292 {
293 Dictionary<string, object> dict = new Dictionary<string, object>();
294
295 dict["AcceptNotices"] = member.AcceptNotices.ToString();
296 dict["AccessToken"] = Sanitize(member.AccessToken);
297 dict["AgentID"] = Sanitize(member.AgentID);
298 dict["AgentPowers"] = member.AgentPowers.ToString();
299 dict["Contribution"] = member.Contribution.ToString();
300 dict["IsOwner"] = member.IsOwner.ToString();
301 dict["ListInProfile"] = member.ListInProfile.ToString();
302 dict["OnlineStatus"] = Sanitize(member.OnlineStatus);
303 dict["Title"] = Sanitize(member.Title);
304
305 return dict;
306 }
307
308 public static ExtendedGroupMembersData GroupMembersData(Dictionary<string, object> dict)
309 {
310 ExtendedGroupMembersData member = new ExtendedGroupMembersData();
311
312 if (dict == null)
313 return member;
314
315 if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null)
316 member.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString());
317
318 if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null)
319 member.AccessToken = Sanitize(dict["AccessToken"].ToString());
320 else
321 member.AccessToken = string.Empty;
322
323 if (dict.ContainsKey("AgentID") && dict["AgentID"] != null)
324 member.AgentID = Sanitize(dict["AgentID"].ToString());
325 else
326 member.AgentID = UUID.Zero.ToString();
327
328 if (dict.ContainsKey("AgentPowers") && dict["AgentPowers"] != null)
329 member.AgentPowers = UInt64.Parse(dict["AgentPowers"].ToString());
330
331 if (dict.ContainsKey("Contribution") && dict["Contribution"] != null)
332 member.Contribution = Int32.Parse(dict["Contribution"].ToString());
333
334 if (dict.ContainsKey("IsOwner") && dict["IsOwner"] != null)
335 member.IsOwner = bool.Parse(dict["IsOwner"].ToString());
336
337 if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null)
338 member.ListInProfile = bool.Parse(dict["ListInProfile"].ToString());
339
340 if (dict.ContainsKey("OnlineStatus") && dict["OnlineStatus"] != null)
341 member.OnlineStatus = Sanitize(dict["OnlineStatus"].ToString());
342 else
343 member.OnlineStatus = string.Empty;
344
345 if (dict.ContainsKey("Title") && dict["Title"] != null)
346 member.Title = Sanitize(dict["Title"].ToString());
347 else
348 member.Title = string.Empty;
349
350 return member;
351 }
352
353 public static Dictionary<string, object> GroupRolesData(GroupRolesData role)
354 {
355 Dictionary<string, object> dict = new Dictionary<string, object>();
356
357 dict["Description"] = Sanitize(role.Description);
358 dict["Members"] = role.Members.ToString();
359 dict["Name"] = Sanitize(role.Name);
360 dict["Powers"] = role.Powers.ToString();
361 dict["RoleID"] = role.RoleID.ToString();
362 dict["Title"] = Sanitize(role.Title);
363
364 return dict;
365 }
366
367 public static GroupRolesData GroupRolesData(Dictionary<string, object> dict)
368 {
369 GroupRolesData role = new GroupRolesData();
370
371 if (dict == null)
372 return role;
373
374 if (dict.ContainsKey("Description") && dict["Description"] != null)
375 role.Description = Sanitize(dict["Description"].ToString());
376 else
377 role.Description = string.Empty;
378
379 if (dict.ContainsKey("Members") && dict["Members"] != null)
380 role.Members = Int32.Parse(dict["Members"].ToString());
381
382 if (dict.ContainsKey("Name") && dict["Name"] != null)
383 role.Name = Sanitize(dict["Name"].ToString());
384 else
385 role.Name = string.Empty;
386
387 if (dict.ContainsKey("Powers") && dict["Powers"] != null)
388 role.Powers = UInt64.Parse(dict["Powers"].ToString());
389
390 if (dict.ContainsKey("Title") && dict["Title"] != null)
391 role.Title = Sanitize(dict["Title"].ToString());
392 else
393 role.Title = string.Empty;
394
395 if (dict.ContainsKey("RoleID") && dict["RoleID"] != null)
396 role.RoleID = UUID.Parse(dict["RoleID"].ToString());
397
398 return role;
399 }
400
401 public static Dictionary<string, object> GroupRoleMembersData(ExtendedGroupRoleMembersData rmember)
402 {
403 Dictionary<string, object> dict = new Dictionary<string, object>();
404
405 dict["RoleID"] = rmember.RoleID.ToString();
406 dict["MemberID"] = rmember.MemberID;
407 return dict;
408 }
409
410 public static ExtendedGroupRoleMembersData GroupRoleMembersData(Dictionary<string, object> dict)
411 {
412 ExtendedGroupRoleMembersData rmember = new ExtendedGroupRoleMembersData();
413
414 if (dict.ContainsKey("RoleID") && dict["RoleID"] != null)
415 rmember.RoleID = new UUID(dict["RoleID"].ToString());
416
417 if (dict.ContainsKey("MemberID") && dict["MemberID"] != null)
418 rmember.MemberID = dict["MemberID"].ToString();
419
420 return rmember;
421 }
422
423 public static Dictionary<string, object> GroupInviteInfo(GroupInviteInfo invite)
424 {
425 Dictionary<string, object> dict = new Dictionary<string, object>();
426
427 dict["InviteID"] = invite.InviteID.ToString();
428 dict["GroupID"] = invite.GroupID.ToString();
429 dict["RoleID"] = invite.RoleID.ToString();
430 dict["AgentID"] = invite.AgentID;
431
432 return dict;
433 }
434
435 public static GroupInviteInfo GroupInviteInfo(Dictionary<string, object> dict)
436 {
437 if (dict == null)
438 return null;
439
440 GroupInviteInfo invite = new GroupInviteInfo();
441
442 invite.InviteID = new UUID(dict["InviteID"].ToString());
443 invite.GroupID = new UUID(dict["GroupID"].ToString());
444 invite.RoleID = new UUID(dict["RoleID"].ToString());
445 invite.AgentID = Sanitize(dict["AgentID"].ToString());
446
447 return invite;
448 }
449
450 public static Dictionary<string, object> GroupNoticeData(ExtendedGroupNoticeData notice)
451 {
452 Dictionary<string, object> dict = new Dictionary<string, object>();
453
454 dict["NoticeID"] = notice.NoticeID.ToString();
455 dict["Timestamp"] = notice.Timestamp.ToString();
456 dict["FromName"] = Sanitize(notice.FromName);
457 dict["Subject"] = Sanitize(notice.Subject);
458 dict["HasAttachment"] = notice.HasAttachment.ToString();
459 dict["AttachmentItemID"] = notice.AttachmentItemID.ToString();
460 dict["AttachmentName"] = Sanitize(notice.AttachmentName);
461 dict["AttachmentType"] = notice.AttachmentType.ToString();
462 dict["AttachmentOwnerID"] = Sanitize(notice.AttachmentOwnerID);
463
464 return dict;
465 }
466
467 public static ExtendedGroupNoticeData GroupNoticeData(Dictionary<string, object> dict)
468 {
469 ExtendedGroupNoticeData notice = new ExtendedGroupNoticeData();
470
471 if (dict == null)
472 return notice;
473
474 notice.NoticeID = new UUID(dict["NoticeID"].ToString());
475 notice.Timestamp = UInt32.Parse(dict["Timestamp"].ToString());
476 notice.FromName = Sanitize(dict["FromName"].ToString());
477 notice.Subject = Sanitize(dict["Subject"].ToString());
478 notice.HasAttachment = bool.Parse(dict["HasAttachment"].ToString());
479 notice.AttachmentItemID = new UUID(dict["AttachmentItemID"].ToString());
480 notice.AttachmentName = dict["AttachmentName"].ToString();
481 notice.AttachmentType = byte.Parse(dict["AttachmentType"].ToString());
482 notice.AttachmentOwnerID = dict["AttachmentOwnerID"].ToString();
483
484 return notice;
485 }
486
487 public static Dictionary<string, object> GroupNoticeInfo(GroupNoticeInfo notice)
488 {
489 Dictionary<string, object> dict = GroupNoticeData(notice.noticeData);
490
491 dict["GroupID"] = notice.GroupID.ToString();
492 dict["Message"] = Sanitize(notice.Message);
493
494 return dict;
495 }
496
497 public static GroupNoticeInfo GroupNoticeInfo(Dictionary<string, object> dict)
498 {
499 GroupNoticeInfo notice = new GroupNoticeInfo();
500
501 notice.noticeData = GroupNoticeData(dict);
502 notice.GroupID = new UUID(dict["GroupID"].ToString());
503 notice.Message = Sanitize(dict["Message"].ToString());
504
505 return notice;
506 }
507
508 public static Dictionary<string, object> DirGroupsReplyData(DirGroupsReplyData g)
509 {
510 Dictionary<string, object> dict = new Dictionary<string, object>();
511
512 dict["GroupID"] = g.groupID;
513 dict["Name"] = g.groupName;
514 dict["NMembers"] = g.members;
515 dict["SearchOrder"] = g.searchOrder;
516
517 return dict;
518 }
519
520 public static DirGroupsReplyData DirGroupsReplyData(Dictionary<string, object> dict)
521 {
522 DirGroupsReplyData g;
523
524 g.groupID = new UUID(dict["GroupID"].ToString());
525 g.groupName = dict["Name"].ToString();
526 Int32.TryParse(dict["NMembers"].ToString(), out g.members);
527 float.TryParse(dict["SearchOrder"].ToString(), out g.searchOrder);
528
529 return g;
530 }
531 }
532
533}
diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs
new file mode 100644
index 0000000..e95db41
--- /dev/null
+++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs
@@ -0,0 +1,848 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
42using GridRegion = OpenSim.Services.Interfaces.GridRegion;
43
44namespace OpenSim.Groups
45{
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsMessagingModule")]
47 public class GroupsMessagingModule : ISharedRegionModule, IGroupsMessagingModule
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private List<Scene> m_sceneList = new List<Scene>();
52 private IPresenceService m_presenceService;
53
54 private IMessageTransferModule m_msgTransferModule = null;
55 private IUserManagement m_UserManagement = null;
56 private IGroupsServicesConnector m_groupData = null;
57
58 // Config Options
59 private bool m_groupMessagingEnabled;
60 private bool m_debugEnabled;
61
62 /// <summary>
63 /// If enabled, module only tries to send group IMs to online users by querying cached presence information.
64 /// </summary>
65 private bool m_messageOnlineAgentsOnly;
66
67 /// <summary>
68 /// Cache for online users.
69 /// </summary>
70 /// <remarks>
71 /// Group ID is key, presence information for online members is value.
72 /// Will only be non-null if m_messageOnlineAgentsOnly = true
73 /// We cache here so that group messages don't constantly have to re-request the online user list to avoid
74 /// attempted expensive sending of messages to offline users.
75 /// The tradeoff is that a user that comes online will not receive messages consistently from all other users
76 /// until caches have updated.
77 /// Therefore, we set the cache expiry to just 20 seconds.
78 /// </remarks>
79 private ExpiringCache<UUID, PresenceInfo[]> m_usersOnlineCache;
80
81 private int m_usersOnlineCacheExpirySeconds = 20;
82
83 private Dictionary<UUID, List<string>> m_groupsAgentsDroppedFromChatSession = new Dictionary<UUID, List<string>>();
84 private Dictionary<UUID, List<string>> m_groupsAgentsInvitedToChatSession = new Dictionary<UUID, List<string>>();
85
86 #region Region Module interfaceBase Members
87
88 public void Initialise(IConfigSource config)
89 {
90 IConfig groupsConfig = config.Configs["Groups"];
91
92 if (groupsConfig == null)
93 // Do not run this module by default.
94 return;
95
96 // if groups aren't enabled, we're not needed.
97 // if we're not specified as the connector to use, then we're not wanted
98 if ((groupsConfig.GetBoolean("Enabled", false) == false)
99 || (groupsConfig.GetString("MessagingModule", "") != Name))
100 {
101 m_groupMessagingEnabled = false;
102 return;
103 }
104
105 m_groupMessagingEnabled = groupsConfig.GetBoolean("MessagingEnabled", true);
106
107 if (!m_groupMessagingEnabled)
108 return;
109
110 m_messageOnlineAgentsOnly = groupsConfig.GetBoolean("MessageOnlineUsersOnly", false);
111
112 if (m_messageOnlineAgentsOnly)
113 {
114 m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>();
115 }
116 else
117 {
118 m_log.Error("[Groups.Messaging]: GroupsMessagingModule V2 requires MessageOnlineUsersOnly = true");
119 m_groupMessagingEnabled = false;
120 return;
121 }
122
123 m_debugEnabled = groupsConfig.GetBoolean("MessagingDebugEnabled", m_debugEnabled);
124
125 m_log.InfoFormat(
126 "[Groups.Messaging]: GroupsMessagingModule enabled with MessageOnlineOnly = {0}, DebugEnabled = {1}",
127 m_messageOnlineAgentsOnly, m_debugEnabled);
128 }
129
130 public void AddRegion(Scene scene)
131 {
132 if (!m_groupMessagingEnabled)
133 return;
134
135 scene.RegisterModuleInterface<IGroupsMessagingModule>(this);
136 m_sceneList.Add(scene);
137
138 scene.EventManager.OnNewClient += OnNewClient;
139 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
140 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
141 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
142 scene.EventManager.OnClientLogin += OnClientLogin;
143
144 scene.AddCommand(
145 "Debug",
146 this,
147 "debug groups messaging verbose",
148 "debug groups messaging verbose <true|false>",
149 "This setting turns on very verbose groups messaging debugging",
150 HandleDebugGroupsMessagingVerbose);
151 }
152
153 public void RegionLoaded(Scene scene)
154 {
155 if (!m_groupMessagingEnabled)
156 return;
157
158 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
159
160 m_groupData = scene.RequestModuleInterface<IGroupsServicesConnector>();
161
162 // No groups module, no groups messaging
163 if (m_groupData == null)
164 {
165 m_log.Error("[Groups.Messaging]: Could not get IGroupsServicesConnector, GroupsMessagingModule is now disabled.");
166 RemoveRegion(scene);
167 return;
168 }
169
170 m_msgTransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
171
172 // No message transfer module, no groups messaging
173 if (m_msgTransferModule == null)
174 {
175 m_log.Error("[Groups.Messaging]: Could not get MessageTransferModule");
176 RemoveRegion(scene);
177 return;
178 }
179
180 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
181
182 // No groups module, no groups messaging
183 if (m_UserManagement == null)
184 {
185 m_log.Error("[Groups.Messaging]: Could not get IUserManagement, GroupsMessagingModule is now disabled.");
186 RemoveRegion(scene);
187 return;
188 }
189
190 if (m_presenceService == null)
191 m_presenceService = scene.PresenceService;
192 }
193
194 public void RemoveRegion(Scene scene)
195 {
196 if (!m_groupMessagingEnabled)
197 return;
198
199 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
200
201 m_sceneList.Remove(scene);
202 scene.EventManager.OnNewClient -= OnNewClient;
203 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
204 scene.EventManager.OnClientLogin -= OnClientLogin;
205 scene.UnregisterModuleInterface<IGroupsMessagingModule>(this);
206 }
207
208 public void Close()
209 {
210 if (!m_groupMessagingEnabled)
211 return;
212
213 if (m_debugEnabled) m_log.Debug("[Groups.Messaging]: Shutting down GroupsMessagingModule module.");
214
215 m_sceneList.Clear();
216
217 m_groupData = null;
218 m_msgTransferModule = null;
219 }
220
221 public Type ReplaceableInterface
222 {
223 get { return null; }
224 }
225
226 public string Name
227 {
228 get { return "Groups Messaging Module V2"; }
229 }
230
231 public void PostInitialise()
232 {
233 // NoOp
234 }
235
236 #endregion
237
238 private void HandleDebugGroupsMessagingVerbose(object modules, string[] args)
239 {
240 if (args.Length < 5)
241 {
242 MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>");
243 return;
244 }
245
246 bool verbose = false;
247 if (!bool.TryParse(args[4], out verbose))
248 {
249 MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>");
250 return;
251 }
252
253 m_debugEnabled = verbose;
254
255 MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled);
256 }
257
258 /// <summary>
259 /// Not really needed, but does confirm that the group exists.
260 /// </summary>
261 public bool StartGroupChatSession(UUID agentID, UUID groupID)
262 {
263 if (m_debugEnabled)
264 m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
265
266 GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null);
267
268 if (groupInfo != null)
269 {
270 return true;
271 }
272 else
273 {
274 return false;
275 }
276 }
277
278 public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
279 {
280 SendMessageToGroup(im, groupID, UUID.Zero, null);
281 }
282
283 public void SendMessageToGroup(
284 GridInstantMessage im, UUID groupID, UUID sendingAgentForGroupCalls, Func<GroupMembersData, bool> sendCondition)
285 {
286 int requestStartTick = Environment.TickCount;
287
288 UUID fromAgentID = new UUID(im.fromAgentID);
289
290 // Unlike current XmlRpcGroups, Groups V2 can accept UUID.Zero when a perms check for the requesting agent
291 // is not necessary.
292 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), groupID);
293
294 int groupMembersCount = groupMembers.Count;
295 PresenceInfo[] onlineAgents = null;
296
297 // In V2 we always only send to online members.
298 // Sending to offline members is not an option.
299 string[] t1 = groupMembers.ConvertAll<string>(gmd => gmd.AgentID.ToString()).ToArray();
300
301 // We cache in order not to overwhelm the presence service on large grids with many groups. This does
302 // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed.
303 // (assuming this is the same across all grid simulators).
304 if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents))
305 {
306 onlineAgents = m_presenceService.GetAgents(t1);
307 m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds);
308 }
309
310 HashSet<string> onlineAgentsUuidSet = new HashSet<string>();
311 Array.ForEach<PresenceInfo>(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID));
312
313 groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList();
314
315// if (m_debugEnabled)
316// m_log.DebugFormat(
317// "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members, {2} online",
318// groupID, groupMembersCount, groupMembers.Count());
319
320 im.imSessionID = groupID.Guid;
321 im.fromGroup = true;
322 IClientAPI thisClient = GetActiveClient(fromAgentID);
323 if (thisClient != null)
324 {
325 im.RegionID = thisClient.Scene.RegionInfo.RegionID.Guid;
326 }
327
328 if ((im.binaryBucket == null) || (im.binaryBucket.Length == 0) || ((im.binaryBucket.Length == 1 && im.binaryBucket[0] == 0)))
329 {
330 ExtendedGroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), groupID, null);
331 if (groupInfo != null)
332 im.binaryBucket = Util.StringToBytes256(groupInfo.GroupName);
333 }
334
335 // Send to self first of all
336 im.toAgentID = im.fromAgentID;
337 im.fromGroup = true;
338 ProcessMessageFromGroupSession(im);
339
340 List<UUID> regions = new List<UUID>();
341 List<UUID> clientsAlreadySent = new List<UUID>();
342
343 // Then send to everybody else
344 foreach (GroupMembersData member in groupMembers)
345 {
346 if (member.AgentID.Guid == im.fromAgentID)
347 continue;
348
349 if (clientsAlreadySent.Contains(member.AgentID))
350 continue;
351
352 clientsAlreadySent.Add(member.AgentID);
353
354 if (sendCondition != null)
355 {
356 if (!sendCondition(member))
357 {
358 if (m_debugEnabled)
359 m_log.DebugFormat(
360 "[Groups.Messaging]: Not sending to {0} as they do not fulfill send condition",
361 member.AgentID);
362
363 continue;
364 }
365 }
366 else if (hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID))
367 {
368 // Don't deliver messages to people who have dropped this session
369 if (m_debugEnabled)
370 m_log.DebugFormat("[Groups.Messaging]: {0} has dropped session, not delivering to them", member.AgentID);
371
372 continue;
373 }
374
375 im.toAgentID = member.AgentID.Guid;
376
377 IClientAPI client = GetActiveClient(member.AgentID);
378 if (client == null)
379 {
380 // If they're not local, forward across the grid
381 // BUT do it only once per region, please! Sim would be even better!
382 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} via Grid", member.AgentID);
383
384 bool reallySend = true;
385 if (onlineAgents != null)
386 {
387 PresenceInfo presence = onlineAgents.First(p => p.UserID == member.AgentID.ToString());
388 if (regions.Contains(presence.RegionID))
389 reallySend = false;
390 else
391 regions.Add(presence.RegionID);
392 }
393
394 if (reallySend)
395 {
396 // We have to create a new IM structure because the transfer module
397 // uses async send
398 GridInstantMessage msg = new GridInstantMessage(im, true);
399 m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { });
400 }
401 }
402 else
403 {
404 // Deliver locally, directly
405 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name);
406
407 ProcessMessageFromGroupSession(im);
408 }
409
410 }
411
412 if (m_debugEnabled)
413 m_log.DebugFormat(
414 "[Groups.Messaging]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms",
415 groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick);
416 }
417
418 #region SimGridEventHandlers
419
420 void OnClientLogin(IClientAPI client)
421 {
422 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name);
423 }
424
425 private void OnNewClient(IClientAPI client)
426 {
427 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name);
428
429 ResetAgentGroupChatSessions(client.AgentId.ToString());
430 }
431
432 void OnMakeRootAgent(ScenePresence sp)
433 {
434 sp.ControllingClient.OnInstantMessage += OnInstantMessage;
435 }
436
437 void OnMakeChildAgent(ScenePresence sp)
438 {
439 sp.ControllingClient.OnInstantMessage -= OnInstantMessage;
440 }
441
442
443 private void OnGridInstantMessage(GridInstantMessage msg)
444 {
445 // The instant message module will only deliver messages of dialog types:
446 // MessageFromAgent, StartTyping, StopTyping, MessageFromObject
447 //
448 // Any other message type will not be delivered to a client by the
449 // Instant Message Module
450
451 UUID regionID = new UUID(msg.RegionID);
452 if (m_debugEnabled)
453 {
454 m_log.DebugFormat("[Groups.Messaging]: {0} called, IM from region {1}",
455 System.Reflection.MethodBase.GetCurrentMethod().Name, regionID);
456
457 DebugGridInstantMessage(msg);
458 }
459
460 // Incoming message from a group
461 if ((msg.fromGroup == true) && (msg.dialog == (byte)InstantMessageDialog.SessionSend))
462 {
463 // We have to redistribute the message across all members of the group who are here
464 // on this sim
465
466 UUID GroupID = new UUID(msg.imSessionID);
467
468 Scene aScene = m_sceneList[0];
469 GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID);
470
471 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), GroupID);
472
473 //if (m_debugEnabled)
474 // foreach (GroupMembersData m in groupMembers)
475 // m_log.DebugFormat("[Groups.Messaging]: member {0}", m.AgentID);
476
477 foreach (Scene s in m_sceneList)
478 {
479 s.ForEachScenePresence(sp =>
480 {
481 // If we got this via grid messaging, it's because the caller thinks
482 // that the root agent is here. We should only send the IM to root agents.
483 if (sp.IsChildAgent)
484 return;
485
486 GroupMembersData m = groupMembers.Find(gmd =>
487 {
488 return gmd.AgentID == sp.UUID;
489 });
490 if (m.AgentID == UUID.Zero)
491 {
492 if (m_debugEnabled)
493 m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he is not a member of the group", sp.UUID);
494 return;
495 }
496
497 // Check if the user has an agent in the region where
498 // the IM came from, and if so, skip it, because the IM
499 // was already sent via that agent
500 if (regionOfOrigin != null)
501 {
502 AgentCircuitData aCircuit = s.AuthenticateHandler.GetAgentCircuitData(sp.UUID);
503 if (aCircuit != null)
504 {
505 if (aCircuit.ChildrenCapSeeds.Keys.Contains(regionOfOrigin.RegionHandle))
506 {
507 if (m_debugEnabled)
508 m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he has an agent in region of origin", sp.UUID);
509 return;
510 }
511 else
512 {
513 if (m_debugEnabled)
514 m_log.DebugFormat("[Groups.Messaging]: not skipping agent {0}", sp.UUID);
515 }
516 }
517 }
518
519 UUID AgentID = sp.UUID;
520 msg.toAgentID = AgentID.Guid;
521
522 if (!hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID))
523 {
524 if (!hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID))
525 AddAgentToSession(AgentID, GroupID, msg);
526 else
527 {
528 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", sp.Name);
529
530 ProcessMessageFromGroupSession(msg);
531 }
532 }
533 });
534
535 }
536 }
537 }
538
539 private void ProcessMessageFromGroupSession(GridInstantMessage msg)
540 {
541 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Session message from {0} going to agent {1}", msg.fromAgentName, msg.toAgentID);
542
543 UUID AgentID = new UUID(msg.fromAgentID);
544 UUID GroupID = new UUID(msg.imSessionID);
545 UUID toAgentID = new UUID(msg.toAgentID);
546
547 switch (msg.dialog)
548 {
549 case (byte)InstantMessageDialog.SessionAdd:
550 AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
551 break;
552
553 case (byte)InstantMessageDialog.SessionDrop:
554 AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID);
555 break;
556
557 case (byte)InstantMessageDialog.SessionSend:
558 // User hasn't dropped, so they're in the session,
559 // maybe we should deliver it.
560 IClientAPI client = GetActiveClient(new UUID(msg.toAgentID));
561 if (client != null)
562 {
563 // Deliver locally, directly
564 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name);
565
566 if (!hasAgentDroppedGroupChatSession(toAgentID.ToString(), GroupID))
567 {
568 if (!hasAgentBeenInvitedToGroupChatSession(toAgentID.ToString(), GroupID))
569 // This actually sends the message too, so no need to resend it
570 // with client.SendInstantMessage
571 AddAgentToSession(toAgentID, GroupID, msg);
572 else
573 client.SendInstantMessage(msg);
574 }
575 }
576 else
577 {
578 m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID);
579 }
580 break;
581
582 default:
583 m_log.WarnFormat("[Groups.Messaging]: I don't know how to proccess a {0} message.", ((InstantMessageDialog)msg.dialog).ToString());
584 break;
585 }
586 }
587
588 private void AddAgentToSession(UUID AgentID, UUID GroupID, GridInstantMessage msg)
589 {
590 // Agent not in session and hasn't dropped from session
591 // Add them to the session for now, and Invite them
592 AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
593
594 IClientAPI activeClient = GetActiveClient(AgentID);
595 if (activeClient != null)
596 {
597 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null);
598 if (groupInfo != null)
599 {
600 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Sending chatterbox invite instant message");
601
602 // Force? open the group session dialog???
603 // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg);
604 IEventQueue eq = activeClient.Scene.RequestModuleInterface<IEventQueue>();
605 eq.ChatterboxInvitation(
606 GroupID
607 , groupInfo.GroupName
608 , new UUID(msg.fromAgentID)
609 , msg.message
610 , AgentID
611 , msg.fromAgentName
612 , msg.dialog
613 , msg.timestamp
614 , msg.offline == 1
615 , (int)msg.ParentEstateID
616 , msg.Position
617 , 1
618 , new UUID(msg.imSessionID)
619 , msg.fromGroup
620 , OpenMetaverse.Utils.StringToBytes(groupInfo.GroupName)
621 );
622
623 eq.ChatterBoxSessionAgentListUpdates(
624 new UUID(GroupID)
625 , AgentID
626 , new UUID(msg.toAgentID)
627 , false //canVoiceChat
628 , false //isModerator
629 , false //text mute
630 );
631 }
632 }
633 }
634
635 #endregion
636
637
638 #region ClientEvents
639 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
640 {
641 if (m_debugEnabled)
642 {
643 m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
644
645 DebugGridInstantMessage(im);
646 }
647
648 // Start group IM session
649 if ((im.dialog == (byte)InstantMessageDialog.SessionGroupStart))
650 {
651 if (m_debugEnabled) m_log.InfoFormat("[Groups.Messaging]: imSessionID({0}) toAgentID({1})", im.imSessionID, im.toAgentID);
652
653 UUID GroupID = new UUID(im.imSessionID);
654 UUID AgentID = new UUID(im.fromAgentID);
655
656 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null);
657
658 if (groupInfo != null)
659 {
660 AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
661
662 ChatterBoxSessionStartReplyViaCaps(remoteClient, groupInfo.GroupName, GroupID);
663
664 IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>();
665 queue.ChatterBoxSessionAgentListUpdates(
666 GroupID
667 , AgentID
668 , new UUID(im.toAgentID)
669 , false //canVoiceChat
670 , false //isModerator
671 , false //text mute
672 );
673 }
674 }
675
676 // Send a message from locally connected client to a group
677 if ((im.dialog == (byte)InstantMessageDialog.SessionSend))
678 {
679 UUID GroupID = new UUID(im.imSessionID);
680 UUID AgentID = new UUID(im.fromAgentID);
681
682 if (m_debugEnabled)
683 m_log.DebugFormat("[Groups.Messaging]: Send message to session for group {0} with session ID {1}", GroupID, im.imSessionID.ToString());
684
685 //If this agent is sending a message, then they want to be in the session
686 AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
687
688 SendMessageToGroup(im, GroupID);
689 }
690 }
691
692 #endregion
693
694 void ChatterBoxSessionStartReplyViaCaps(IClientAPI remoteClient, string groupName, UUID groupID)
695 {
696 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
697
698 OSDMap moderatedMap = new OSDMap(4);
699 moderatedMap.Add("voice", OSD.FromBoolean(false));
700
701 OSDMap sessionMap = new OSDMap(4);
702 sessionMap.Add("moderated_mode", moderatedMap);
703 sessionMap.Add("session_name", OSD.FromString(groupName));
704 sessionMap.Add("type", OSD.FromInteger(0));
705 sessionMap.Add("voice_enabled", OSD.FromBoolean(false));
706
707 OSDMap bodyMap = new OSDMap(4);
708 bodyMap.Add("session_id", OSD.FromUUID(groupID));
709 bodyMap.Add("temp_session_id", OSD.FromUUID(groupID));
710 bodyMap.Add("success", OSD.FromBoolean(true));
711 bodyMap.Add("session_info", sessionMap);
712
713 IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>();
714
715 if (queue != null)
716 {
717 queue.Enqueue(queue.BuildEvent("ChatterBoxSessionStartReply", bodyMap), remoteClient.AgentId);
718 }
719 }
720
721 private void DebugGridInstantMessage(GridInstantMessage im)
722 {
723 // Don't log any normal IMs (privacy!)
724 if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent)
725 {
726 m_log.WarnFormat("[Groups.Messaging]: IM: fromGroup({0})", im.fromGroup ? "True" : "False");
727 m_log.WarnFormat("[Groups.Messaging]: IM: Dialog({0})", ((InstantMessageDialog)im.dialog).ToString());
728 m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentID({0})", im.fromAgentID.ToString());
729 m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentName({0})", im.fromAgentName.ToString());
730 m_log.WarnFormat("[Groups.Messaging]: IM: imSessionID({0})", im.imSessionID.ToString());
731 m_log.WarnFormat("[Groups.Messaging]: IM: message({0})", im.message.ToString());
732 m_log.WarnFormat("[Groups.Messaging]: IM: offline({0})", im.offline.ToString());
733 m_log.WarnFormat("[Groups.Messaging]: IM: toAgentID({0})", im.toAgentID.ToString());
734 m_log.WarnFormat("[Groups.Messaging]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket"));
735 }
736 }
737
738 #region Client Tools
739
740 /// <summary>
741 /// Try to find an active IClientAPI reference for agentID giving preference to root connections
742 /// </summary>
743 private IClientAPI GetActiveClient(UUID agentID)
744 {
745 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Looking for local client {0}", agentID);
746
747 IClientAPI child = null;
748
749 // Try root avatar first
750 foreach (Scene scene in m_sceneList)
751 {
752 ScenePresence sp = scene.GetScenePresence(agentID);
753 if (sp != null)
754 {
755 if (!sp.IsChildAgent)
756 {
757 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name);
758 return sp.ControllingClient;
759 }
760 else
761 {
762 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name);
763 child = sp.ControllingClient;
764 }
765 }
766 }
767
768 // If we didn't find a root, then just return whichever child we found, or null if none
769 if (child == null)
770 {
771 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Could not find local client for agent : {0}", agentID);
772 }
773 else
774 {
775 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Returning child agent for client : {0}", child.Name);
776 }
777 return child;
778 }
779
780 #endregion
781
782 #region GroupSessionTracking
783
784 public void ResetAgentGroupChatSessions(string agentID)
785 {
786 foreach (List<string> agentList in m_groupsAgentsDroppedFromChatSession.Values)
787 agentList.Remove(agentID);
788
789 foreach (List<string> agentList in m_groupsAgentsInvitedToChatSession.Values)
790 agentList.Remove(agentID);
791 }
792
793 public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
794 {
795 // If we're tracking this group, and we can find them in the tracking, then they've been invited
796 return m_groupsAgentsInvitedToChatSession.ContainsKey(groupID)
797 && m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID);
798 }
799
800 public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
801 {
802 // If we're tracking drops for this group,
803 // and we find them, well... then they've dropped
804 return m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)
805 && m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID);
806 }
807
808 public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
809 {
810 if (m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID))
811 {
812 // If not in dropped list, add
813 if (!m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID))
814 {
815 m_groupsAgentsDroppedFromChatSession[groupID].Add(agentID);
816 }
817 }
818 }
819
820 public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
821 {
822 // Add Session Status if it doesn't exist for this session
823 CreateGroupChatSessionTracking(groupID);
824
825 // If nessesary, remove from dropped list
826 if (m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID))
827 {
828 m_groupsAgentsDroppedFromChatSession[groupID].Remove(agentID);
829 }
830
831 // Add to invited
832 if (!m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID))
833 m_groupsAgentsInvitedToChatSession[groupID].Add(agentID);
834 }
835
836 private void CreateGroupChatSessionTracking(UUID groupID)
837 {
838 if (!m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID))
839 {
840 m_groupsAgentsDroppedFromChatSession.Add(groupID, new List<string>());
841 m_groupsAgentsInvitedToChatSession.Add(groupID, new List<string>());
842 }
843
844 }
845 #endregion
846
847 }
848}
diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs
new file mode 100644
index 0000000..d121d1a
--- /dev/null
+++ b/OpenSim/Addons/Groups/GroupsModule.cs
@@ -0,0 +1,1467 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Timers;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
42
43namespace OpenSim.Groups
44{
45 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsModule")]
46 public class GroupsModule : ISharedRegionModule, IGroupsModule
47 {
48 private static readonly ILog m_log =
49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private List<Scene> m_sceneList = new List<Scene>();
52
53 private IMessageTransferModule m_msgTransferModule = null;
54
55 private IGroupsServicesConnector m_groupData = null;
56 private IUserManagement m_UserManagement;
57
58 // Configuration settings
59 private bool m_groupsEnabled = false;
60 private bool m_groupNoticesEnabled = true;
61 private bool m_debugEnabled = false;
62 private int m_levelGroupCreate = 0;
63
64 #region Region Module interfaceBase Members
65
66 public void Initialise(IConfigSource config)
67 {
68 IConfig groupsConfig = config.Configs["Groups"];
69
70 if (groupsConfig == null)
71 {
72 // Do not run this module by default.
73 return;
74 }
75 else
76 {
77 m_groupsEnabled = groupsConfig.GetBoolean("Enabled", false);
78 if (!m_groupsEnabled)
79 {
80 return;
81 }
82
83 if (groupsConfig.GetString("Module", "Default") != Name)
84 {
85 m_groupsEnabled = false;
86
87 return;
88 }
89
90 m_log.InfoFormat("[Groups]: Initializing {0}", this.Name);
91
92 m_groupNoticesEnabled = groupsConfig.GetBoolean("NoticesEnabled", true);
93 m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", false);
94 m_levelGroupCreate = groupsConfig.GetInt("LevelGroupCreate", 0);
95 }
96 }
97
98 public void AddRegion(Scene scene)
99 {
100 if (m_groupsEnabled)
101 {
102 scene.RegisterModuleInterface<IGroupsModule>(this);
103 scene.AddCommand(
104 "Debug",
105 this,
106 "debug groups verbose",
107 "debug groups verbose <true|false>",
108 "This setting turns on very verbose groups debugging",
109 HandleDebugGroupsVerbose);
110 }
111 }
112
113 private void HandleDebugGroupsVerbose(object modules, string[] args)
114 {
115 if (args.Length < 4)
116 {
117 MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
118 return;
119 }
120
121 bool verbose = false;
122 if (!bool.TryParse(args[3], out verbose))
123 {
124 MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
125 return;
126 }
127
128 m_debugEnabled = verbose;
129
130 MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled);
131 }
132
133 public void RegionLoaded(Scene scene)
134 {
135 if (!m_groupsEnabled)
136 return;
137
138 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
139
140 scene.EventManager.OnNewClient += OnNewClient;
141 scene.EventManager.OnMakeRootAgent += OnMakeRoot;
142 scene.EventManager.OnMakeChildAgent += OnMakeChild;
143 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
144 // The InstantMessageModule itself doesn't do this,
145 // so lets see if things explode if we don't do it
146 // scene.EventManager.OnClientClosed += OnClientClosed;
147
148 if (m_groupData == null)
149 {
150 m_groupData = scene.RequestModuleInterface<IGroupsServicesConnector>();
151
152 // No Groups Service Connector, then nothing works...
153 if (m_groupData == null)
154 {
155 m_groupsEnabled = false;
156 m_log.Error("[Groups]: Could not get IGroupsServicesConnector");
157 RemoveRegion(scene);
158 return;
159 }
160 }
161
162 if (m_msgTransferModule == null)
163 {
164 m_msgTransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
165
166 // No message transfer module, no notices, group invites, rejects, ejects, etc
167 if (m_msgTransferModule == null)
168 {
169 m_log.Warn("[Groups]: Could not get MessageTransferModule");
170 }
171 }
172
173 if (m_UserManagement == null)
174 {
175 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
176 if (m_UserManagement == null)
177 m_log.Warn("[Groups]: Could not get UserManagementModule");
178 }
179
180 lock (m_sceneList)
181 {
182 m_sceneList.Add(scene);
183 }
184
185
186 }
187
188 public void RemoveRegion(Scene scene)
189 {
190 if (!m_groupsEnabled)
191 return;
192
193 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
194
195 scene.EventManager.OnNewClient -= OnNewClient;
196 scene.EventManager.OnMakeRootAgent -= OnMakeRoot;
197 scene.EventManager.OnMakeChildAgent -= OnMakeChild;
198 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
199
200 lock (m_sceneList)
201 {
202 m_sceneList.Remove(scene);
203 }
204 }
205
206 public void Close()
207 {
208 if (!m_groupsEnabled)
209 return;
210
211 if (m_debugEnabled) m_log.Debug("[Groups]: Shutting down Groups module.");
212 }
213
214 public Type ReplaceableInterface
215 {
216 get { return null; }
217 }
218
219 public string Name
220 {
221 get { return "Groups Module V2"; }
222 }
223
224 public void PostInitialise()
225 {
226 // NoOp
227 }
228
229 #endregion
230
231 #region EventHandlers
232 private void OnNewClient(IClientAPI client)
233 {
234 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
235
236 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
237 client.OnRequestAvatarProperties += OnRequestAvatarProperties;
238 }
239
240 private void OnMakeRoot(ScenePresence sp)
241 {
242 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
243
244 sp.ControllingClient.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
245 // Used for Notices and Group Invites/Accept/Reject
246 sp.ControllingClient.OnInstantMessage += OnInstantMessage;
247
248 // Send client their groups information.
249 SendAgentGroupDataUpdate(sp.ControllingClient, sp.UUID);
250 }
251
252 private void OnMakeChild(ScenePresence sp)
253 {
254 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
255
256 sp.ControllingClient.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest;
257 // Used for Notices and Group Invites/Accept/Reject
258 sp.ControllingClient.OnInstantMessage -= OnInstantMessage;
259 }
260
261 private void OnRequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
262 {
263 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
264
265 //GroupMembershipData[] avatarGroups = m_groupData.GetAgentGroupMemberships(GetRequestingAgentID(remoteClient), avatarID).ToArray();
266 GroupMembershipData[] avatarGroups = GetProfileListedGroupMemberships(remoteClient, avatarID);
267 remoteClient.SendAvatarGroupsReply(avatarID, avatarGroups);
268 }
269
270 /*
271 * This becomes very problematic in a shared module. In a shared module you may have more then one
272 * reference to IClientAPI's, one for 0 or 1 root connections, and 0 or more child connections.
273 * The OnClientClosed event does not provide anything to indicate which one of those should be closed
274 * nor does it provide what scene it was from so that the specific reference can be looked up.
275 * The InstantMessageModule.cs does not currently worry about unregistering the handles,
276 * and it should be an issue, since it's the client that references us not the other way around
277 * , so as long as we don't keep a reference to the client laying around, the client can still be GC'ed
278 private void OnClientClosed(UUID AgentId)
279 {
280 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
281
282 lock (m_ActiveClients)
283 {
284 if (m_ActiveClients.ContainsKey(AgentId))
285 {
286 IClientAPI client = m_ActiveClients[AgentId];
287 client.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest;
288 client.OnAgentDataUpdateRequest -= OnAgentDataUpdateRequest;
289 client.OnDirFindQuery -= OnDirFindQuery;
290 client.OnInstantMessage -= OnInstantMessage;
291
292 m_ActiveClients.Remove(AgentId);
293 }
294 else
295 {
296 if (m_debugEnabled) m_log.WarnFormat("[Groups]: Client closed that wasn't registered here.");
297 }
298
299
300 }
301 }
302 */
303
304 private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID)
305 {
306 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
307
308 UUID activeGroupID = UUID.Zero;
309 string activeGroupTitle = string.Empty;
310 string activeGroupName = string.Empty;
311 ulong activeGroupPowers = (ulong)GroupPowers.None;
312
313 GroupMembershipData membership = m_groupData.GetAgentActiveMembership(GetRequestingAgentIDStr(remoteClient), dataForAgentID.ToString());
314 if (membership != null)
315 {
316 activeGroupID = membership.GroupID;
317 activeGroupTitle = membership.GroupTitle;
318 activeGroupPowers = membership.GroupPowers;
319 }
320
321 SendAgentDataUpdate(remoteClient, dataForAgentID, activeGroupID, activeGroupName, activeGroupPowers, activeGroupTitle);
322
323 SendScenePresenceUpdate(dataForAgentID, activeGroupTitle);
324 }
325
326 private void HandleUUIDGroupNameRequest(UUID GroupID, IClientAPI remoteClient)
327 {
328 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
329
330 string GroupName;
331
332 GroupRecord group = m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), GroupID, null);
333 if (group != null)
334 {
335 GroupName = group.GroupName;
336 }
337 else
338 {
339 GroupName = "Unknown";
340 }
341
342 remoteClient.SendGroupNameReply(GroupID, GroupName);
343 }
344
345 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
346 {
347 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
348
349 //m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog);
350 // Group invitations
351 if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline))
352 {
353 UUID inviteID = new UUID(im.imSessionID);
354 GroupInviteInfo inviteInfo = m_groupData.GetAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID);
355
356 if (inviteInfo == null)
357 {
358 if (m_debugEnabled) m_log.WarnFormat("[Groups]: Received an Invite IM for an invite that does not exist {0}.", inviteID);
359 return;
360 }
361
362 //m_log.DebugFormat("[XXX]: Invite is for Agent {0} to Group {1}.", inviteInfo.AgentID, inviteInfo.GroupID);
363
364 UUID fromAgentID = new UUID(im.fromAgentID);
365 UUID invitee = UUID.Zero;
366 string tmp = string.Empty;
367 Util.ParseUniversalUserIdentifier(inviteInfo.AgentID, out invitee, out tmp, out tmp, out tmp, out tmp);
368 if ((inviteInfo != null) && (fromAgentID == invitee))
369 {
370 // Accept
371 if (im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept)
372 {
373 //m_log.DebugFormat("[XXX]: Received an accept invite notice.");
374
375 // and the sessionid is the role
376 string reason = string.Empty;
377 if (!m_groupData.AddAgentToGroup(GetRequestingAgentIDStr(remoteClient), invitee.ToString(), inviteInfo.GroupID, inviteInfo.RoleID, string.Empty, out reason))
378 remoteClient.SendAgentAlertMessage("Unable to add you to the group: " + reason, false);
379 else
380 {
381 GridInstantMessage msg = new GridInstantMessage();
382 msg.imSessionID = UUID.Zero.Guid;
383 msg.fromAgentID = UUID.Zero.Guid;
384 msg.toAgentID = invitee.Guid;
385 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
386 msg.fromAgentName = "Groups";
387 msg.message = string.Format("You have been added to the group.");
388 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageBox;
389 msg.fromGroup = false;
390 msg.offline = (byte)0;
391 msg.ParentEstateID = 0;
392 msg.Position = Vector3.Zero;
393 msg.RegionID = UUID.Zero.Guid;
394 msg.binaryBucket = new byte[0];
395
396 OutgoingInstantMessage(msg, invitee);
397
398 UpdateAllClientsWithGroupInfo(invitee);
399 }
400
401 m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID);
402
403 }
404
405 // Reject
406 if (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)
407 {
408 if (m_debugEnabled) m_log.DebugFormat("[Groups]: Received a reject invite notice.");
409 m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID);
410
411 m_groupData.RemoveAgentFromGroup(GetRequestingAgentIDStr(remoteClient), inviteInfo.AgentID, inviteInfo.GroupID);
412 }
413 }
414 }
415
416 // Group notices
417 if ((im.dialog == (byte)InstantMessageDialog.GroupNotice))
418 {
419 if (!m_groupNoticesEnabled)
420 {
421 return;
422 }
423
424 UUID GroupID = new UUID(im.toAgentID);
425 if (m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), GroupID, null) != null)
426 {
427 UUID NoticeID = UUID.Random();
428 string Subject = im.message.Substring(0, im.message.IndexOf('|'));
429 string Message = im.message.Substring(Subject.Length + 1);
430
431 InventoryItemBase item = null;
432 bool hasAttachment = false;
433
434 if (im.binaryBucket.Length >= 1 && im.binaryBucket[0] > 0)
435 {
436 hasAttachment = true;
437 string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket);
438 binBucket = binBucket.Remove(0, 14).Trim();
439
440 OSD binBucketOSD = OSDParser.DeserializeLLSDXml(binBucket);
441 if (binBucketOSD is OSDMap)
442 {
443 OSDMap binBucketMap = (OSDMap)binBucketOSD;
444
445 UUID itemID = binBucketMap["item_id"].AsUUID();
446 UUID ownerID = binBucketMap["owner_id"].AsUUID();
447 item = new InventoryItemBase(itemID, ownerID);
448 item = m_sceneList[0].InventoryService.GetItem(item);
449 }
450 else
451 m_log.DebugFormat("[Groups]: Received OSD with unexpected type: {0}", binBucketOSD.GetType());
452 }
453
454 if (m_groupData.AddGroupNotice(GetRequestingAgentIDStr(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message,
455 hasAttachment,
456 (byte)(item == null ? 0 : item.AssetType),
457 item == null ? null : item.Name,
458 item == null ? UUID.Zero : item.ID,
459 item == null ? UUID.Zero.ToString() : item.Owner.ToString()))
460 {
461 if (OnNewGroupNotice != null)
462 {
463 OnNewGroupNotice(GroupID, NoticeID);
464 }
465
466
467 // Send notice out to everyone that wants notices
468 foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), GroupID))
469 {
470 if (member.AcceptNotices)
471 {
472 // Build notice IIM, one of reach, because the sending may be async
473 GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
474 msg.toAgentID = member.AgentID.Guid;
475 OutgoingInstantMessage(msg, member.AgentID);
476 }
477 }
478 }
479 }
480 }
481
482 if (im.dialog == (byte)InstantMessageDialog.GroupNoticeInventoryAccepted)
483 {
484 if (im.binaryBucket.Length < 16) // Invalid
485 return;
486
487 //// 16 bytes are the UUID. Maybe.
488// UUID folderID = new UUID(im.binaryBucket, 0);
489 UUID noticeID = new UUID(im.imSessionID);
490
491 GroupNoticeInfo notice = m_groupData.GetGroupNotice(remoteClient.AgentId.ToString(), noticeID);
492 if (notice != null)
493 {
494 UUID giver = new UUID(im.toAgentID);
495 string tmp = string.Empty;
496 Util.ParseUniversalUserIdentifier(notice.noticeData.AttachmentOwnerID, out giver, out tmp, out tmp, out tmp, out tmp);
497
498 m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId);
499 string message;
500 InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId,
501 giver, notice.noticeData.AttachmentItemID, out message);
502
503 if (itemCopy == null)
504 {
505 remoteClient.SendAgentAlertMessage(message, false);
506 return;
507 }
508
509 remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0);
510 }
511
512 }
513
514 // Interop, received special 210 code for ejecting a group member
515 // this only works within the comms servers domain, and won't work hypergrid
516 // TODO:FIXME: Use a presense server of some kind to find out where the
517 // client actually is, and try contacting that region directly to notify them,
518 // or provide the notification via xmlrpc update queue
519 if ((im.dialog == 210))
520 {
521 // This is sent from the region that the ejectee was ejected from
522 // if it's being delivered here, then the ejectee is here
523 // so we need to send local updates to the agent.
524
525 UUID ejecteeID = new UUID(im.toAgentID);
526
527 im.dialog = (byte)InstantMessageDialog.MessageFromAgent;
528 OutgoingInstantMessage(im, ejecteeID);
529
530 IClientAPI ejectee = GetActiveClient(ejecteeID);
531 if (ejectee != null)
532 {
533 UUID groupID = new UUID(im.imSessionID);
534 ejectee.SendAgentDropGroup(groupID);
535 }
536 }
537 }
538
539 private void OnGridInstantMessage(GridInstantMessage msg)
540 {
541 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
542
543 // Trigger the above event handler
544 OnInstantMessage(null, msg);
545
546 // If a message from a group arrives here, it may need to be forwarded to a local client
547 if (msg.fromGroup == true)
548 {
549 switch (msg.dialog)
550 {
551 case (byte)InstantMessageDialog.GroupInvitation:
552 case (byte)InstantMessageDialog.GroupNotice:
553 UUID toAgentID = new UUID(msg.toAgentID);
554 IClientAPI localClient = GetActiveClient(toAgentID);
555 if (localClient != null)
556 {
557 localClient.SendInstantMessage(msg);
558 }
559 break;
560 }
561 }
562 }
563
564 #endregion
565
566 #region IGroupsModule Members
567
568 public event NewGroupNotice OnNewGroupNotice;
569
570 public GroupRecord GetGroupRecord(UUID GroupID)
571 {
572 return m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null);
573 }
574
575 public GroupRecord GetGroupRecord(string name)
576 {
577 return m_groupData.GetGroupRecord(UUID.Zero.ToString(), UUID.Zero, name);
578 }
579
580 public void ActivateGroup(IClientAPI remoteClient, UUID groupID)
581 {
582 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
583
584 m_groupData.SetAgentActiveGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
585
586 // Changing active group changes title, active powers, all kinds of things
587 // anyone who is in any region that can see this client, should probably be
588 // updated with new group info. At a minimum, they should get ScenePresence
589 // updated with new title.
590 UpdateAllClientsWithGroupInfo(remoteClient.AgentId);
591 }
592
593 /// <summary>
594 /// Get the Role Titles for an Agent, for a specific group
595 /// </summary>
596 public List<GroupTitlesData> GroupTitlesRequest(IClientAPI remoteClient, UUID groupID)
597 {
598 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
599
600 List<GroupRolesData> agentRoles = m_groupData.GetAgentGroupRoles(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
601 GroupMembershipData agentMembership = m_groupData.GetAgentGroupMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
602
603 List<GroupTitlesData> titles = new List<GroupTitlesData>();
604 foreach (GroupRolesData role in agentRoles)
605 {
606 GroupTitlesData title = new GroupTitlesData();
607 title.Name = role.Name;
608 if (agentMembership != null)
609 {
610 title.Selected = agentMembership.ActiveRole == role.RoleID;
611 }
612 title.UUID = role.RoleID;
613
614 titles.Add(title);
615 }
616
617 return titles;
618 }
619
620 public List<GroupMembersData> GroupMembersRequest(IClientAPI remoteClient, UUID groupID)
621 {
622 if (m_debugEnabled)
623 m_log.DebugFormat(
624 "[Groups]: GroupMembersRequest called for {0} from client {1}", groupID, remoteClient.Name);
625
626 List<GroupMembersData> data = m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), groupID);
627
628 if (m_debugEnabled)
629 {
630 foreach (GroupMembersData member in data)
631 {
632 m_log.DebugFormat("[Groups]: Member({0}) - IsOwner({1})", member.AgentID, member.IsOwner);
633 }
634 }
635
636 return data;
637
638 }
639
640 public List<GroupRolesData> GroupRoleDataRequest(IClientAPI remoteClient, UUID groupID)
641 {
642 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
643
644 List<GroupRolesData> data = m_groupData.GetGroupRoles(GetRequestingAgentIDStr(remoteClient), groupID);
645
646 return data;
647 }
648
649 public List<GroupRoleMembersData> GroupRoleMembersRequest(IClientAPI remoteClient, UUID groupID)
650 {
651 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
652
653 List<GroupRoleMembersData> data = m_groupData.GetGroupRoleMembers(GetRequestingAgentIDStr(remoteClient), groupID);
654
655 if (m_debugEnabled)
656 {
657 foreach (GroupRoleMembersData member in data)
658 {
659 m_log.DebugFormat("[Groups]: Member({0}) - Role({1})", member.MemberID, member.RoleID);
660 }
661 }
662 return data;
663 }
664
665 public GroupProfileData GroupProfileRequest(IClientAPI remoteClient, UUID groupID)
666 {
667 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
668
669 GroupProfileData profile = new GroupProfileData();
670
671 // just to get the OwnerRole...
672 ExtendedGroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), groupID, string.Empty);
673 GroupMembershipData memberInfo = m_groupData.GetAgentGroupMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
674 if (groupInfo != null)
675 {
676 profile.AllowPublish = groupInfo.AllowPublish;
677 profile.Charter = groupInfo.Charter;
678 profile.FounderID = groupInfo.FounderID;
679 profile.GroupID = groupID;
680 profile.GroupMembershipCount = groupInfo.MemberCount;
681 profile.GroupRolesCount = groupInfo.RoleCount;
682 profile.InsigniaID = groupInfo.GroupPicture;
683 profile.MaturePublish = groupInfo.MaturePublish;
684 profile.MembershipFee = groupInfo.MembershipFee;
685 profile.Money = 0;
686 profile.Name = groupInfo.GroupName;
687 profile.OpenEnrollment = groupInfo.OpenEnrollment;
688 profile.OwnerRole = groupInfo.OwnerRoleID;
689 profile.ShowInList = groupInfo.ShowInList;
690 }
691 if (memberInfo != null)
692 {
693 profile.MemberTitle = memberInfo.GroupTitle;
694 profile.PowersMask = memberInfo.GroupPowers;
695 }
696
697 return profile;
698 }
699
700 public GroupMembershipData[] GetMembershipData(UUID agentID)
701 {
702 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
703
704 return m_groupData.GetAgentGroupMemberships(UUID.Zero.ToString(), agentID.ToString()).ToArray();
705 }
706
707 public GroupMembershipData GetMembershipData(UUID groupID, UUID agentID)
708 {
709 if (m_debugEnabled)
710 m_log.DebugFormat(
711 "[Groups]: {0} called with groupID={1}, agentID={2}",
712 System.Reflection.MethodBase.GetCurrentMethod().Name, groupID, agentID);
713
714 return m_groupData.GetAgentGroupMembership(UUID.Zero.ToString(), agentID.ToString(), groupID);
715 }
716
717 public void UpdateGroupInfo(IClientAPI remoteClient, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
718 {
719 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
720
721 // Note: Permissions checking for modification rights is handled by the Groups Server/Service
722 string reason = string.Empty;
723 if (!m_groupData.UpdateGroup(GetRequestingAgentIDStr(remoteClient), groupID, charter, showInList, insigniaID, membershipFee,
724 openEnrollment, allowPublish, maturePublish, out reason))
725 remoteClient.SendAgentAlertMessage(reason, false);
726 }
727
728 public void SetGroupAcceptNotices(IClientAPI remoteClient, UUID groupID, bool acceptNotices, bool listInProfile)
729 {
730 // Note: Permissions checking for modification rights is handled by the Groups Server/Service
731 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
732
733 m_groupData.UpdateMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, acceptNotices, listInProfile);
734 }
735
736 public UUID CreateGroup(IClientAPI remoteClient, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
737 {
738 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called in {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Scene.RegionInfo.RegionName);
739
740 if (m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), UUID.Zero, name) != null)
741 {
742 remoteClient.SendCreateGroupReply(UUID.Zero, false, "A group with the same name already exists.");
743 return UUID.Zero;
744 }
745
746 // check user level
747 ScenePresence avatar = null;
748 Scene scene = (Scene)remoteClient.Scene;
749 scene.TryGetScenePresence(remoteClient.AgentId, out avatar);
750
751 if (avatar != null)
752 {
753 if (avatar.UserLevel < m_levelGroupCreate)
754 {
755 remoteClient.SendCreateGroupReply(UUID.Zero, false, String.Format("Insufficient permissions to create a group. Requires level {0}", m_levelGroupCreate));
756 return UUID.Zero;
757 }
758 }
759
760 // check funds
761 // is there is a money module present ?
762 IMoneyModule money = scene.RequestModuleInterface<IMoneyModule>();
763 if (money != null)
764 {
765 // do the transaction, that is if the agent has got sufficient funds
766 if (!money.AmountCovered(remoteClient.AgentId, money.GroupCreationCharge)) {
767 remoteClient.SendCreateGroupReply(UUID.Zero, false, "Insufficient funds to create a group.");
768 return UUID.Zero;
769 }
770 }
771
772 string reason = string.Empty;
773 UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment,
774 allowPublish, maturePublish, remoteClient.AgentId, out reason);
775
776 if (groupID != UUID.Zero)
777 {
778 if (money != null)
779 money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, MoneyTransactionType.GroupCreate);
780
781 remoteClient.SendCreateGroupReply(groupID, true, "Group created successfullly");
782
783 // Update the founder with new group information.
784 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
785 }
786 else
787 remoteClient.SendCreateGroupReply(groupID, false, reason);
788
789 return groupID;
790 }
791
792 public GroupNoticeData[] GroupNoticesListRequest(IClientAPI remoteClient, UUID groupID)
793 {
794 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
795
796 // ToDo: check if agent is a member of group and is allowed to see notices?
797
798 List<ExtendedGroupNoticeData> notices = m_groupData.GetGroupNotices(GetRequestingAgentIDStr(remoteClient), groupID);
799 List<GroupNoticeData> os_notices = new List<GroupNoticeData>();
800 foreach (ExtendedGroupNoticeData n in notices)
801 {
802 GroupNoticeData osn = n.ToGroupNoticeData();
803 os_notices.Add(osn);
804 }
805
806 return os_notices.ToArray();
807 }
808
809 /// <summary>
810 /// Get the title of the agent's current role.
811 /// </summary>
812 public string GetGroupTitle(UUID avatarID)
813 {
814 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
815
816 GroupMembershipData membership = m_groupData.GetAgentActiveMembership(UUID.Zero.ToString(), avatarID.ToString());
817 if (membership != null)
818 {
819 return membership.GroupTitle;
820 }
821 return string.Empty;
822 }
823
824 /// <summary>
825 /// Change the current Active Group Role for Agent
826 /// </summary>
827 public void GroupTitleUpdate(IClientAPI remoteClient, UUID groupID, UUID titleRoleID)
828 {
829 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
830
831 m_groupData.SetAgentActiveGroupRole(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, titleRoleID);
832
833 // TODO: Not sure what all is needed here, but if the active group role change is for the group
834 // the client currently has set active, then we need to do a scene presence update too
835 // if (m_groupData.GetAgentActiveMembership(GetRequestingAgentID(remoteClient)).GroupID == GroupID)
836
837 UpdateAllClientsWithGroupInfo(GetRequestingAgentID(remoteClient));
838 }
839
840
841 public void GroupRoleUpdate(IClientAPI remoteClient, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, byte updateType)
842 {
843 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
844
845 // Security Checks are handled in the Groups Service.
846
847 switch ((OpenMetaverse.GroupRoleUpdate)updateType)
848 {
849 case OpenMetaverse.GroupRoleUpdate.Create:
850 string reason = string.Empty;
851 if (!m_groupData.AddGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, UUID.Random(), name, description, title, powers, out reason))
852 remoteClient.SendAgentAlertMessage("Unable to create role: " + reason, false);
853 break;
854
855 case OpenMetaverse.GroupRoleUpdate.Delete:
856 m_groupData.RemoveGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, roleID);
857 break;
858
859 case OpenMetaverse.GroupRoleUpdate.UpdateAll:
860 case OpenMetaverse.GroupRoleUpdate.UpdateData:
861 case OpenMetaverse.GroupRoleUpdate.UpdatePowers:
862 if (m_debugEnabled)
863 {
864 GroupPowers gp = (GroupPowers)powers;
865 m_log.DebugFormat("[Groups]: Role ({0}) updated with Powers ({1}) ({2})", name, powers.ToString(), gp.ToString());
866 }
867 m_groupData.UpdateGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, roleID, name, description, title, powers);
868 break;
869
870 case OpenMetaverse.GroupRoleUpdate.NoUpdate:
871 default:
872 // No Op
873 break;
874
875 }
876
877 // TODO: This update really should send out updates for everyone in the role that just got changed.
878 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
879 }
880
881 public void GroupRoleChanges(IClientAPI remoteClient, UUID groupID, UUID roleID, UUID memberID, uint changes)
882 {
883 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
884 // Todo: Security check
885
886 switch (changes)
887 {
888 case 0:
889 // Add
890 m_groupData.AddAgentToGroupRole(GetRequestingAgentIDStr(remoteClient), memberID.ToString(), groupID, roleID);
891
892 break;
893 case 1:
894 // Remove
895 m_groupData.RemoveAgentFromGroupRole(GetRequestingAgentIDStr(remoteClient), memberID.ToString(), groupID, roleID);
896
897 break;
898 default:
899 m_log.ErrorFormat("[Groups]: {0} does not understand changes == {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, changes);
900 break;
901 }
902
903 // TODO: This update really should send out updates for everyone in the role that just got changed.
904 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
905 }
906
907 public void GroupNoticeRequest(IClientAPI remoteClient, UUID groupNoticeID)
908 {
909 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called for notice {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, groupNoticeID);
910
911 GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested);
912
913 OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient));
914 }
915
916 public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
917 {
918 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
919
920 GridInstantMessage msg = new GridInstantMessage();
921 byte[] bucket;
922
923 msg.imSessionID = groupNoticeID.Guid;
924 msg.toAgentID = agentID.Guid;
925 msg.dialog = dialog;
926 // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice;
927 msg.fromGroup = true;
928 msg.offline = (byte)0;
929 msg.ParentEstateID = 0;
930 msg.Position = Vector3.Zero;
931 msg.RegionID = UUID.Zero.Guid;
932
933 GroupNoticeInfo info = m_groupData.GetGroupNotice(agentID.ToString(), groupNoticeID);
934 if (info != null)
935 {
936 msg.fromAgentID = info.GroupID.Guid;
937 msg.timestamp = info.noticeData.Timestamp;
938 msg.fromAgentName = info.noticeData.FromName;
939 msg.message = info.noticeData.Subject + "|" + info.Message;
940 if (info.noticeData.HasAttachment)
941 {
942 byte[] name = System.Text.Encoding.UTF8.GetBytes(info.noticeData.AttachmentName);
943 bucket = new byte[19 + name.Length];
944 bucket[0] = 1; // has attachment?
945 bucket[1] = info.noticeData.AttachmentType; // attachment type
946 name.CopyTo(bucket, 18);
947 }
948 else
949 {
950 bucket = new byte[19];
951 bucket[0] = 0; // Has att?
952 bucket[1] = 0; // type
953 bucket[18] = 0; // null terminated
954 }
955
956 info.GroupID.ToBytes(bucket, 2);
957 msg.binaryBucket = bucket;
958 }
959 else
960 {
961 m_log.DebugFormat("[Groups]: Group Notice {0} not found, composing empty message.", groupNoticeID);
962 msg.fromAgentID = UUID.Zero.Guid;
963 msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ;
964 msg.fromAgentName = string.Empty;
965 msg.message = string.Empty;
966 msg.binaryBucket = new byte[0];
967 }
968
969 return msg;
970 }
971
972 public void SendAgentGroupDataUpdate(IClientAPI remoteClient)
973 {
974 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
975
976 // Send agent information about his groups
977 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
978 }
979
980 public void JoinGroupRequest(IClientAPI remoteClient, UUID groupID)
981 {
982 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
983
984 string reason = string.Empty;
985 // Should check to see if OpenEnrollment, or if there's an outstanding invitation
986 if (m_groupData.AddAgentToGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, UUID.Zero, string.Empty, out reason))
987 {
988
989 remoteClient.SendJoinGroupReply(groupID, true);
990
991 // Should this send updates to everyone in the group?
992 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
993
994 if (reason != string.Empty)
995 // A warning
996 remoteClient.SendAlertMessage("Warning: " + reason);
997 }
998 else
999 remoteClient.SendJoinGroupReply(groupID, false);
1000 }
1001
1002 public void LeaveGroupRequest(IClientAPI remoteClient, UUID groupID)
1003 {
1004 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1005
1006 m_groupData.RemoveAgentFromGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
1007
1008 remoteClient.SendLeaveGroupReply(groupID, true);
1009
1010 remoteClient.SendAgentDropGroup(groupID);
1011
1012 // SL sends out notifcations to the group messaging session that the person has left
1013 // Should this also update everyone who is in the group?
1014 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
1015 }
1016
1017 public void EjectGroupMemberRequest(IClientAPI remoteClient, UUID groupID, UUID ejecteeID)
1018 {
1019 EjectGroupMember(remoteClient, GetRequestingAgentID(remoteClient), groupID, ejecteeID);
1020 }
1021
1022 public void EjectGroupMember(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID ejecteeID)
1023 {
1024 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1025
1026 // Todo: Security check?
1027 m_groupData.RemoveAgentFromGroup(agentID.ToString(), ejecteeID.ToString(), groupID);
1028
1029 string agentName;
1030 RegionInfo regionInfo;
1031
1032 // remoteClient provided or just agentID?
1033 if (remoteClient != null)
1034 {
1035 agentName = remoteClient.Name;
1036 regionInfo = remoteClient.Scene.RegionInfo;
1037 remoteClient.SendEjectGroupMemberReply(agentID, groupID, true);
1038 }
1039 else
1040 {
1041 IClientAPI client = GetActiveClient(agentID);
1042
1043 if (client != null)
1044 {
1045 agentName = client.Name;
1046 regionInfo = client.Scene.RegionInfo;
1047 client.SendEjectGroupMemberReply(agentID, groupID, true);
1048 }
1049 else
1050 {
1051 regionInfo = m_sceneList[0].RegionInfo;
1052 UserAccount acc = m_sceneList[0].UserAccountService.GetUserAccount(regionInfo.ScopeID, agentID);
1053
1054 if (acc != null)
1055 {
1056 agentName = acc.FirstName + " " + acc.LastName;
1057 }
1058 else
1059 {
1060 agentName = "Unknown member";
1061 }
1062 }
1063 }
1064
1065 GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null);
1066
1067 UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(regionInfo.ScopeID, ejecteeID);
1068 if ((groupInfo == null) || (account == null))
1069 {
1070 return;
1071 }
1072
1073 // Send Message to Ejectee
1074 GridInstantMessage msg = new GridInstantMessage();
1075
1076 msg.imSessionID = UUID.Zero.Guid;
1077 msg.fromAgentID = agentID.Guid;
1078 // msg.fromAgentID = info.GroupID;
1079 msg.toAgentID = ejecteeID.Guid;
1080 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1081 msg.timestamp = 0;
1082 msg.fromAgentName = agentName;
1083 msg.message = string.Format("You have been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName);
1084 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageFromAgent;
1085 msg.fromGroup = false;
1086 msg.offline = (byte)0;
1087 msg.ParentEstateID = 0;
1088 msg.Position = Vector3.Zero;
1089 msg.RegionID = regionInfo.RegionID.Guid;
1090 msg.binaryBucket = new byte[0];
1091 OutgoingInstantMessage(msg, ejecteeID);
1092
1093 // Message to ejector
1094 // Interop, received special 210 code for ejecting a group member
1095 // this only works within the comms servers domain, and won't work hypergrid
1096 // TODO:FIXME: Use a presense server of some kind to find out where the
1097 // client actually is, and try contacting that region directly to notify them,
1098 // or provide the notification via xmlrpc update queue
1099
1100 msg = new GridInstantMessage();
1101 msg.imSessionID = UUID.Zero.Guid;
1102 msg.fromAgentID = agentID.Guid;
1103 msg.toAgentID = agentID.Guid;
1104 msg.timestamp = 0;
1105 msg.fromAgentName = agentName;
1106 if (account != null)
1107 {
1108 msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName, account.FirstName + " " + account.LastName);
1109 }
1110 else
1111 {
1112 msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName, "Unknown member");
1113 }
1114 msg.dialog = (byte)210; //interop
1115 msg.fromGroup = false;
1116 msg.offline = (byte)0;
1117 msg.ParentEstateID = 0;
1118 msg.Position = Vector3.Zero;
1119 msg.RegionID = regionInfo.RegionID.Guid;
1120 msg.binaryBucket = new byte[0];
1121 OutgoingInstantMessage(msg, agentID);
1122
1123
1124 // SL sends out messages to everyone in the group
1125 // Who all should receive updates and what should they be updated with?
1126 UpdateAllClientsWithGroupInfo(ejecteeID);
1127 }
1128
1129 public void InviteGroupRequest(IClientAPI remoteClient, UUID groupID, UUID invitedAgentID, UUID roleID)
1130 {
1131 InviteGroup(remoteClient, GetRequestingAgentID(remoteClient), groupID, invitedAgentID, roleID);
1132 }
1133
1134 public void InviteGroup(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID invitedAgentID, UUID roleID)
1135 {
1136 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1137
1138 string agentName = m_UserManagement.GetUserName(agentID);
1139 RegionInfo regionInfo = m_sceneList[0].RegionInfo;
1140
1141 GroupRecord group = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null);
1142 if (group == null)
1143 {
1144 m_log.DebugFormat("[Groups]: No such group {0}", groupID);
1145 return;
1146 }
1147
1148 // Todo: Security check, probably also want to send some kind of notification
1149 UUID InviteID = UUID.Random();
1150
1151 if (m_groupData.AddAgentToGroupInvite(agentID.ToString(), InviteID, groupID, roleID, invitedAgentID.ToString()))
1152 {
1153 if (m_msgTransferModule != null)
1154 {
1155 Guid inviteUUID = InviteID.Guid;
1156
1157 GridInstantMessage msg = new GridInstantMessage();
1158
1159 msg.imSessionID = inviteUUID;
1160
1161 // msg.fromAgentID = agentID.Guid;
1162 msg.fromAgentID = groupID.Guid;
1163 msg.toAgentID = invitedAgentID.Guid;
1164 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1165 msg.timestamp = 0;
1166 msg.fromAgentName = agentName;
1167 msg.message = string.Format("{0} has invited you to join a group called {1}. There is no cost to join this group.", agentName, group.GroupName);
1168 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation;
1169 msg.fromGroup = true;
1170 msg.offline = (byte)0;
1171 msg.ParentEstateID = 0;
1172 msg.Position = Vector3.Zero;
1173 msg.RegionID = regionInfo.RegionID.Guid;
1174 msg.binaryBucket = new byte[20];
1175
1176 OutgoingInstantMessage(msg, invitedAgentID);
1177 }
1178 }
1179 }
1180
1181 public List<DirGroupsReplyData> FindGroups(IClientAPI remoteClient, string query)
1182 {
1183 return m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), query);
1184 }
1185
1186 #endregion
1187
1188 #region Client/Update Tools
1189
1190 /// <summary>
1191 /// Try to find an active IClientAPI reference for agentID giving preference to root connections
1192 /// </summary>
1193 private IClientAPI GetActiveClient(UUID agentID)
1194 {
1195 IClientAPI child = null;
1196
1197 // Try root avatar first
1198 foreach (Scene scene in m_sceneList)
1199 {
1200 ScenePresence sp = scene.GetScenePresence(agentID);
1201 if (sp != null)
1202 {
1203 if (!sp.IsChildAgent)
1204 {
1205 return sp.ControllingClient;
1206 }
1207 else
1208 {
1209 child = sp.ControllingClient;
1210 }
1211 }
1212 }
1213
1214 // If we didn't find a root, then just return whichever child we found, or null if none
1215 return child;
1216 }
1217
1218 /// <summary>
1219 /// Send 'remoteClient' the group membership 'data' for agent 'dataForAgentID'.
1220 /// </summary>
1221 private void SendGroupMembershipInfoViaCaps(IClientAPI remoteClient, UUID dataForAgentID, GroupMembershipData[] data)
1222 {
1223 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1224
1225 // NPCs currently don't have a CAPs structure or event queues. There is a strong argument for conveying this information
1226 // to them anyway since it makes writing server-side bots a lot easier, but for now we don't do anything.
1227 if (remoteClient.SceneAgent.PresenceType == PresenceType.Npc)
1228 return;
1229
1230 OSDArray AgentData = new OSDArray(1);
1231 OSDMap AgentDataMap = new OSDMap(1);
1232 AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID));
1233 AgentData.Add(AgentDataMap);
1234
1235 OSDArray GroupData = new OSDArray(data.Length);
1236 OSDArray NewGroupData = new OSDArray(data.Length);
1237
1238 foreach (GroupMembershipData membership in data)
1239 {
1240 if (GetRequestingAgentID(remoteClient) != dataForAgentID)
1241 {
1242 if (!membership.ListInProfile)
1243 {
1244 // If we're sending group info to remoteclient about another agent,
1245 // filter out groups the other agent doesn't want to share.
1246 continue;
1247 }
1248 }
1249
1250 OSDMap GroupDataMap = new OSDMap(6);
1251 OSDMap NewGroupDataMap = new OSDMap(1);
1252
1253 GroupDataMap.Add("GroupID", OSD.FromUUID(membership.GroupID));
1254 GroupDataMap.Add("GroupPowers", OSD.FromULong(membership.GroupPowers));
1255 GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(membership.AcceptNotices));
1256 GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(membership.GroupPicture));
1257 GroupDataMap.Add("Contribution", OSD.FromInteger(membership.Contribution));
1258 GroupDataMap.Add("GroupName", OSD.FromString(membership.GroupName));
1259 NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(membership.ListInProfile));
1260
1261 GroupData.Add(GroupDataMap);
1262 NewGroupData.Add(NewGroupDataMap);
1263 }
1264
1265 OSDMap llDataStruct = new OSDMap(3);
1266 llDataStruct.Add("AgentData", AgentData);
1267 llDataStruct.Add("GroupData", GroupData);
1268 llDataStruct.Add("NewGroupData", NewGroupData);
1269
1270 if (m_debugEnabled)
1271 {
1272 m_log.InfoFormat("[Groups]: {0}", OSDParser.SerializeJsonString(llDataStruct));
1273 }
1274
1275 IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>();
1276
1277 if (queue != null)
1278 {
1279 queue.Enqueue(queue.BuildEvent("AgentGroupDataUpdate", llDataStruct), GetRequestingAgentID(remoteClient));
1280 }
1281 }
1282
1283 private void SendScenePresenceUpdate(UUID AgentID, string Title)
1284 {
1285 if (m_debugEnabled) m_log.DebugFormat("[Groups]: Updating scene title for {0} with title: {1}", AgentID, Title);
1286
1287 ScenePresence presence = null;
1288
1289 foreach (Scene scene in m_sceneList)
1290 {
1291 presence = scene.GetScenePresence(AgentID);
1292 if (presence != null)
1293 {
1294 if (presence.Grouptitle != Title)
1295 {
1296 presence.Grouptitle = Title;
1297
1298 if (! presence.IsChildAgent)
1299 presence.SendAvatarDataToAllClients();
1300 }
1301 }
1302 }
1303 }
1304
1305 /// <summary>
1306 /// Send updates to all clients who might be interested in groups data for dataForClientID
1307 /// </summary>
1308 private void UpdateAllClientsWithGroupInfo(UUID dataForClientID)
1309 {
1310 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1311
1312 // TODO: Probably isn't nessesary to update every client in every scene.
1313 // Need to examine client updates and do only what's nessesary.
1314 lock (m_sceneList)
1315 {
1316 foreach (Scene scene in m_sceneList)
1317 {
1318 scene.ForEachClient(delegate(IClientAPI client) { SendAgentGroupDataUpdate(client, dataForClientID); });
1319 }
1320 }
1321 }
1322
1323 /// <summary>
1324 /// Update remoteClient with group information about dataForAgentID
1325 /// </summary>
1326 private void SendAgentGroupDataUpdate(IClientAPI remoteClient, UUID dataForAgentID)
1327 {
1328 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called for {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Name);
1329
1330 // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
1331
1332 OnAgentDataUpdateRequest(remoteClient, dataForAgentID, UUID.Zero);
1333
1334 // Need to send a group membership update to the client
1335 // UDP version doesn't seem to behave nicely. But we're going to send it out here
1336 // with an empty group membership to hopefully remove groups being displayed due
1337 // to the core Groups Stub
1338 //remoteClient.SendGroupMembership(new GroupMembershipData[0]);
1339
1340 GroupMembershipData[] membershipArray = GetProfileListedGroupMemberships(remoteClient, dataForAgentID);
1341 SendGroupMembershipInfoViaCaps(remoteClient, dataForAgentID, membershipArray);
1342
1343 //remoteClient.SendAvatarGroupsReply(dataForAgentID, membershipArray);
1344 if (remoteClient.AgentId == dataForAgentID)
1345 remoteClient.RefreshGroupMembership();
1346 }
1347
1348 /// <summary>
1349 /// Get a list of groups memberships for the agent that are marked "ListInProfile"
1350 /// (unless that agent has a godLike aspect, in which case get all groups)
1351 /// </summary>
1352 /// <param name="dataForAgentID"></param>
1353 /// <returns></returns>
1354 private GroupMembershipData[] GetProfileListedGroupMemberships(IClientAPI requestingClient, UUID dataForAgentID)
1355 {
1356 List<GroupMembershipData> membershipData = m_groupData.GetAgentGroupMemberships(requestingClient.AgentId.ToString(), dataForAgentID.ToString());
1357 GroupMembershipData[] membershipArray;
1358
1359 // cScene and property accessor 'isGod' are in support of the opertions to bypass 'hidden' group attributes for
1360 // those with a GodLike aspect.
1361 Scene cScene = (Scene)requestingClient.Scene;
1362 bool isGod = cScene.Permissions.IsGod(requestingClient.AgentId);
1363
1364 if (isGod)
1365 {
1366 membershipArray = membershipData.ToArray();
1367 }
1368 else
1369 {
1370 if (requestingClient.AgentId != dataForAgentID)
1371 {
1372 Predicate<GroupMembershipData> showInProfile = delegate(GroupMembershipData membership)
1373 {
1374 return membership.ListInProfile;
1375 };
1376
1377 membershipArray = membershipData.FindAll(showInProfile).ToArray();
1378 }
1379 else
1380 {
1381 membershipArray = membershipData.ToArray();
1382 }
1383 }
1384
1385 if (m_debugEnabled)
1386 {
1387 m_log.InfoFormat("[Groups]: Get group membership information for {0} requested by {1}", dataForAgentID, requestingClient.AgentId);
1388 foreach (GroupMembershipData membership in membershipArray)
1389 {
1390 m_log.InfoFormat("[Groups]: {0} :: {1} - {2} - {3}", dataForAgentID, membership.GroupName, membership.GroupTitle, membership.GroupPowers);
1391 }
1392 }
1393
1394 return membershipArray;
1395 }
1396
1397
1398 private void SendAgentDataUpdate(IClientAPI remoteClient, UUID dataForAgentID, UUID activeGroupID, string activeGroupName, ulong activeGroupPowers, string activeGroupTitle)
1399 {
1400 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1401
1402 // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
1403 string firstname = "Unknown", lastname = "Unknown";
1404 string name = m_UserManagement.GetUserName(dataForAgentID);
1405 if (!string.IsNullOrEmpty(name))
1406 {
1407 string[] parts = name.Split(new char[] { ' ' });
1408 if (parts.Length >= 2)
1409 {
1410 firstname = parts[0];
1411 lastname = parts[1];
1412 }
1413 }
1414
1415 remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname,
1416 lastname, activeGroupPowers, activeGroupName,
1417 activeGroupTitle);
1418 }
1419
1420 #endregion
1421
1422 #region IM Backed Processes
1423
1424 private void OutgoingInstantMessage(GridInstantMessage msg, UUID msgTo)
1425 {
1426 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1427
1428 IClientAPI localClient = GetActiveClient(msgTo);
1429 if (localClient != null)
1430 {
1431 if (m_debugEnabled) m_log.InfoFormat("[Groups]: MsgTo ({0}) is local, delivering directly", localClient.Name);
1432 localClient.SendInstantMessage(msg);
1433 }
1434 else if (m_msgTransferModule != null)
1435 {
1436 if (m_debugEnabled) m_log.InfoFormat("[Groups]: MsgTo ({0}) is not local, delivering via TransferModule", msgTo);
1437 m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { if (m_debugEnabled) m_log.DebugFormat("[Groups]: Message Sent: {0}", success?"Succeeded":"Failed"); });
1438 }
1439 }
1440
1441 public void NotifyChange(UUID groupID)
1442 {
1443 // Notify all group members of a chnge in group roles and/or
1444 // permissions
1445 //
1446 }
1447
1448 #endregion
1449
1450 private string GetRequestingAgentIDStr(IClientAPI client)
1451 {
1452 return GetRequestingAgentID(client).ToString();
1453 }
1454
1455 private UUID GetRequestingAgentID(IClientAPI client)
1456 {
1457 UUID requestingAgentID = UUID.Zero;
1458 if (client != null)
1459 {
1460 requestingAgentID = client.AgentId;
1461 }
1462 return requestingAgentID;
1463 }
1464
1465 }
1466
1467}
diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs
new file mode 100644
index 0000000..653dbac
--- /dev/null
+++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs
@@ -0,0 +1,289 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33
34using OpenSim.Framework;
35using OpenSim.Server.Base;
36
37using OpenMetaverse;
38using log4net;
39
40namespace OpenSim.Groups
41{
42 public class GroupsServiceHGConnector
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 private string m_ServerURI;
47 private object m_Lock = new object();
48
49 public GroupsServiceHGConnector(string url)
50 {
51 m_ServerURI = url;
52 if (!m_ServerURI.EndsWith("/"))
53 m_ServerURI += "/";
54
55 m_log.DebugFormat("[Groups.HGConnector]: Groups server at {0}", m_ServerURI);
56 }
57
58 public bool CreateProxy(string RequestingAgentID, string AgentID, string accessToken, UUID groupID, string url, string name, out string reason)
59 {
60 reason = string.Empty;
61
62 Dictionary<string, object> sendData = new Dictionary<string,object>();
63 sendData["RequestingAgentID"] = RequestingAgentID;
64 sendData["AgentID"] = AgentID.ToString();
65 sendData["AccessToken"] = accessToken;
66 sendData["GroupID"] = groupID.ToString();
67 sendData["Location"] = url;
68 sendData["Name"] = name;
69 Dictionary<string, object> ret = MakeRequest("POSTGROUP", sendData);
70
71 if (ret == null)
72 return false;
73
74 if (!ret.ContainsKey("RESULT"))
75 return false;
76
77 if (ret["RESULT"].ToString().ToLower() != "true")
78 {
79 reason = ret["REASON"].ToString();
80 return false;
81 }
82
83 return true;
84
85 }
86
87 public void RemoveAgentFromGroup(string AgentID, UUID GroupID, string token)
88 {
89 Dictionary<string, object> sendData = new Dictionary<string, object>();
90 sendData["AgentID"] = AgentID;
91 sendData["GroupID"] = GroupID.ToString();
92 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
93 MakeRequest("REMOVEAGENTFROMGROUP", sendData);
94 }
95
96 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, string token)
97 {
98 if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty)))
99 return null;
100
101 Dictionary<string, object> sendData = new Dictionary<string, object>();
102 if (GroupID != UUID.Zero)
103 sendData["GroupID"] = GroupID.ToString();
104 if (!string.IsNullOrEmpty(GroupName))
105 sendData["Name"] = GroupsDataUtils.Sanitize(GroupName);
106
107 sendData["RequestingAgentID"] = RequestingAgentID;
108 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
109
110 Dictionary<string, object> ret = MakeRequest("GETGROUP", sendData);
111
112 if (ret == null)
113 return null;
114
115 if (!ret.ContainsKey("RESULT"))
116 return null;
117
118 if (ret["RESULT"].ToString() == "NULL")
119 return null;
120
121 return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
122 }
123
124 public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, string token)
125 {
126 List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>();
127
128 Dictionary<string, object> sendData = new Dictionary<string, object>();
129 sendData["GroupID"] = GroupID.ToString();
130 sendData["RequestingAgentID"] = RequestingAgentID;
131 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
132 Dictionary<string, object> ret = MakeRequest("GETGROUPMEMBERS", sendData);
133
134 if (ret == null)
135 return members;
136
137 if (!ret.ContainsKey("RESULT"))
138 return members;
139
140 if (ret["RESULT"].ToString() == "NULL")
141 return members;
142 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
143 {
144 ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary<string, object>)v);
145 members.Add(m);
146 }
147
148 return members;
149 }
150
151 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, string token)
152 {
153 List<GroupRolesData> roles = new List<GroupRolesData>();
154
155 Dictionary<string, object> sendData = new Dictionary<string, object>();
156 sendData["GroupID"] = GroupID.ToString();
157 sendData["RequestingAgentID"] = RequestingAgentID;
158 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
159 Dictionary<string, object> ret = MakeRequest("GETGROUPROLES", sendData);
160
161 if (ret == null)
162 return roles;
163
164 if (!ret.ContainsKey("RESULT"))
165 return roles;
166
167 if (ret["RESULT"].ToString() == "NULL")
168 return roles;
169 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
170 {
171 GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v);
172 roles.Add(m);
173 }
174
175 return roles;
176 }
177
178 public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token)
179 {
180 List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
181
182 Dictionary<string, object> sendData = new Dictionary<string, object>();
183 sendData["GroupID"] = GroupID.ToString();
184 sendData["RequestingAgentID"] = RequestingAgentID;
185 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
186 Dictionary<string, object> ret = MakeRequest("GETROLEMEMBERS", sendData);
187
188 if (ret == null)
189 return rmembers;
190
191 if (!ret.ContainsKey("RESULT"))
192 return rmembers;
193
194 if (ret["RESULT"].ToString() == "NULL")
195 return rmembers;
196
197 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
198 {
199 ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary<string, object>)v);
200 rmembers.Add(m);
201 }
202
203 return rmembers;
204 }
205
206 public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
207 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
208 {
209 Dictionary<string, object> sendData = new Dictionary<string, object>();
210 sendData["GroupID"] = groupID.ToString();
211 sendData["NoticeID"] = noticeID.ToString();
212 sendData["FromName"] = GroupsDataUtils.Sanitize(fromName);
213 sendData["Subject"] = GroupsDataUtils.Sanitize(subject);
214 sendData["Message"] = GroupsDataUtils.Sanitize(message);
215 sendData["HasAttachment"] = hasAttachment.ToString();
216 if (hasAttachment)
217 {
218 sendData["AttachmentType"] = attType.ToString();
219 sendData["AttachmentName"] = attName.ToString();
220 sendData["AttachmentItemID"] = attItemID.ToString();
221 sendData["AttachmentOwnerID"] = attOwnerID;
222 }
223 sendData["RequestingAgentID"] = RequestingAgentID;
224
225 Dictionary<string, object> ret = MakeRequest("ADDNOTICE", sendData);
226
227 if (ret == null)
228 return false;
229
230 if (!ret.ContainsKey("RESULT"))
231 return false;
232
233 if (ret["RESULT"].ToString().ToLower() != "true")
234 return false;
235
236 return true;
237 }
238
239 public bool VerifyNotice(UUID noticeID, UUID groupID)
240 {
241 Dictionary<string, object> sendData = new Dictionary<string, object>();
242 sendData["NoticeID"] = noticeID.ToString();
243 sendData["GroupID"] = groupID.ToString();
244 Dictionary<string, object> ret = MakeRequest("VERIFYNOTICE", sendData);
245
246 if (ret == null)
247 return false;
248
249 if (!ret.ContainsKey("RESULT"))
250 return false;
251
252 if (ret["RESULT"].ToString().ToLower() != "true")
253 return false;
254
255 return true;
256 }
257
258 //
259 //
260 //
261 //
262 //
263
264 #region Make Request
265
266 private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
267 {
268 sendData["METHOD"] = method;
269
270 string reply = string.Empty;
271 lock (m_Lock)
272 reply = SynchronousRestFormsRequester.MakeRequest("POST",
273 m_ServerURI + "hg-groups",
274 ServerUtils.BuildQueryString(sendData));
275
276 //m_log.DebugFormat("[XXX]: reply was {0}", reply);
277
278 if (string.IsNullOrEmpty(reply))
279 return null;
280
281 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
282 reply);
283
284 return replyData;
285 }
286 #endregion
287
288 }
289}
diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs
new file mode 100644
index 0000000..7d57de1
--- /dev/null
+++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs
@@ -0,0 +1,707 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33
34using OpenSim.Framework;
35using OpenSim.Framework.Monitoring;
36using OpenSim.Framework.Servers;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Services.Interfaces;
40
41using OpenMetaverse;
42using Mono.Addins;
43using log4net;
44using Nini.Config;
45
46namespace OpenSim.Groups
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceHGConnectorModule")]
49 public class GroupsServiceHGConnectorModule : ISharedRegionModule, IGroupsServicesConnector
50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 private bool m_Enabled = false;
54 private IGroupsServicesConnector m_LocalGroupsConnector;
55 private string m_LocalGroupsServiceLocation;
56 private IUserManagement m_UserManagement;
57 private IOfflineIMService m_OfflineIM;
58 private IMessageTransferModule m_Messaging;
59 private List<Scene> m_Scenes;
60 private ForeignImporter m_ForeignImporter;
61 private string m_ServiceLocation;
62 private IConfigSource m_Config;
63
64 private Dictionary<string, GroupsServiceHGConnector> m_NetworkConnectors = new Dictionary<string, GroupsServiceHGConnector>();
65 private RemoteConnectorCacheWrapper m_CacheWrapper; // for caching info of external group services
66
67 #region ISharedRegionModule
68
69 public void Initialise(IConfigSource config)
70 {
71 IConfig groupsConfig = config.Configs["Groups"];
72 if (groupsConfig == null)
73 return;
74
75 if ((groupsConfig.GetBoolean("Enabled", false) == false)
76 || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name))
77 {
78 return;
79 }
80
81 m_Config = config;
82 m_ServiceLocation = groupsConfig.GetString("LocalService", "local"); // local or remote
83 m_LocalGroupsServiceLocation = groupsConfig.GetString("GroupsExternalURI", "http://127.0.0.1");
84 m_Scenes = new List<Scene>();
85
86 m_Enabled = true;
87
88 m_log.DebugFormat("[Groups]: Initializing {0} with LocalService {1}", this.Name, m_ServiceLocation);
89 }
90
91 public string Name
92 {
93 get { return "Groups HG Service Connector"; }
94 }
95
96 public Type ReplaceableInterface
97 {
98 get { return null; }
99 }
100
101 public void AddRegion(Scene scene)
102 {
103 if (!m_Enabled)
104 return;
105
106 m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName);
107 scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
108 m_Scenes.Add(scene);
109
110 scene.EventManager.OnNewClient += OnNewClient;
111 }
112
113 public void RemoveRegion(Scene scene)
114 {
115 if (!m_Enabled)
116 return;
117
118 scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
119 m_Scenes.Remove(scene);
120 }
121
122 public void RegionLoaded(Scene scene)
123 {
124 if (!m_Enabled)
125 return;
126
127 if (m_UserManagement == null)
128 {
129 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
130 m_OfflineIM = scene.RequestModuleInterface<IOfflineIMService>();
131 m_Messaging = scene.RequestModuleInterface<IMessageTransferModule>();
132 m_ForeignImporter = new ForeignImporter(m_UserManagement);
133
134 if (m_ServiceLocation.Equals("local"))
135 {
136 m_LocalGroupsConnector = new GroupsServiceLocalConnectorModule(m_Config, m_UserManagement);
137 // Also, if local, create the endpoint for the HGGroupsService
138 new HGGroupsServiceRobustConnector(m_Config, MainServer.Instance, string.Empty,
139 scene.RequestModuleInterface<IOfflineIMService>(), scene.RequestModuleInterface<IUserAccountService>());
140
141 }
142 else
143 m_LocalGroupsConnector = new GroupsServiceRemoteConnectorModule(m_Config, m_UserManagement);
144
145 m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement);
146 }
147
148 }
149
150 public void PostInitialise()
151 {
152 }
153
154 public void Close()
155 {
156 }
157
158 #endregion
159
160 private void OnNewClient(IClientAPI client)
161 {
162 client.OnCompleteMovementToRegion += OnCompleteMovementToRegion;
163 }
164
165 void OnCompleteMovementToRegion(IClientAPI client, bool arg2)
166 {
167 object sp = null;
168 if (client.Scene.TryGetScenePresence(client.AgentId, out sp))
169 {
170 if (sp is ScenePresence && ((ScenePresence)sp).PresenceType != PresenceType.Npc)
171 {
172 AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
173 if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 &&
174 m_OfflineIM != null && m_Messaging != null)
175 {
176 List<GridInstantMessage> ims = m_OfflineIM.GetMessages(aCircuit.AgentID);
177 if (ims != null && ims.Count > 0)
178 foreach (GridInstantMessage im in ims)
179 m_Messaging.SendInstantMessage(im, delegate(bool success) { });
180 }
181 }
182 }
183 }
184
185 #region IGroupsServicesConnector
186
187 public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
188 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
189 {
190 reason = string.Empty;
191 if (m_UserManagement.IsLocalGridUser(RequestingAgentID))
192 return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID,
193 membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason);
194 else
195 {
196 reason = "Only local grid users are allowed to create a new group";
197 return UUID.Zero;
198 }
199 }
200
201 public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
202 bool openEnrollment, bool allowPublish, bool maturePublish, out string reason)
203 {
204 reason = string.Empty;
205 string url = string.Empty;
206 string name = string.Empty;
207 if (IsLocal(groupID, out url, out name))
208 return m_LocalGroupsConnector.UpdateGroup(AgentUUI(RequestingAgentID), groupID, charter, showInList, insigniaID, membershipFee,
209 openEnrollment, allowPublish, maturePublish, out reason);
210 else
211 {
212 reason = "Changes to remote group not allowed. Please go to the group's original world.";
213 return false;
214 }
215 }
216
217 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
218 {
219 string url = string.Empty;
220 string name = string.Empty;
221 if (IsLocal(GroupID, out url, out name))
222 return m_LocalGroupsConnector.GetGroupRecord(AgentUUI(RequestingAgentID), GroupID, GroupName);
223 else if (url != string.Empty)
224 {
225 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID);
226 string accessToken = string.Empty;
227 if (membership != null)
228 accessToken = membership.AccessToken;
229 else
230 return null;
231
232 GroupsServiceHGConnector c = GetConnector(url);
233 if (c != null)
234 {
235 ExtendedGroupRecord grec = m_CacheWrapper.GetGroupRecord(RequestingAgentID, GroupID, GroupName, delegate
236 {
237 return c.GetGroupRecord(AgentUUIForOutside(RequestingAgentID), GroupID, GroupName, accessToken);
238 });
239
240 if (grec != null)
241 ImportForeigner(grec.FounderUUI);
242 return grec;
243 }
244 }
245
246 return null;
247 }
248
249 public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search)
250 {
251 return m_LocalGroupsConnector.FindGroups(AgentUUI(RequestingAgentID), search);
252 }
253
254 public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
255 {
256 string url = string.Empty, gname = string.Empty;
257 if (IsLocal(GroupID, out url, out gname))
258 {
259 string agentID = AgentUUI(RequestingAgentID);
260 return m_LocalGroupsConnector.GetGroupMembers(agentID, GroupID);
261 }
262 else if (!string.IsNullOrEmpty(url))
263 {
264 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID);
265 string accessToken = string.Empty;
266 if (membership != null)
267 accessToken = membership.AccessToken;
268 else
269 return null;
270
271 GroupsServiceHGConnector c = GetConnector(url);
272 if (c != null)
273 {
274 return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate
275 {
276 return c.GetGroupMembers(AgentUUIForOutside(RequestingAgentID), GroupID, accessToken);
277 });
278
279 }
280 }
281 return new List<GroupMembersData>();
282 }
283
284 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
285 {
286 reason = string.Empty;
287 string url = string.Empty, gname = string.Empty;
288
289 if (IsLocal(groupID, out url, out gname))
290 return m_LocalGroupsConnector.AddGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers, out reason);
291 else
292 {
293 reason = "Operation not allowed outside this group's origin world.";
294 return false;
295 }
296 }
297
298 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
299 {
300 string url = string.Empty, gname = string.Empty;
301
302 if (IsLocal(groupID, out url, out gname))
303 return m_LocalGroupsConnector.UpdateGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers);
304 else
305 {
306 return false;
307 }
308
309 }
310
311 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
312 {
313 string url = string.Empty, gname = string.Empty;
314
315 if (IsLocal(groupID, out url, out gname))
316 m_LocalGroupsConnector.RemoveGroupRole(AgentUUI(RequestingAgentID), groupID, roleID);
317 else
318 {
319 return;
320 }
321 }
322
323 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID groupID)
324 {
325 string url = string.Empty, gname = string.Empty;
326
327 if (IsLocal(groupID, out url, out gname))
328 return m_LocalGroupsConnector.GetGroupRoles(AgentUUI(RequestingAgentID), groupID);
329 else if (!string.IsNullOrEmpty(url))
330 {
331 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID);
332 string accessToken = string.Empty;
333 if (membership != null)
334 accessToken = membership.AccessToken;
335 else
336 return null;
337
338 GroupsServiceHGConnector c = GetConnector(url);
339 if (c != null)
340 {
341 return m_CacheWrapper.GetGroupRoles(RequestingAgentID, groupID, delegate
342 {
343 return c.GetGroupRoles(AgentUUIForOutside(RequestingAgentID), groupID, accessToken);
344 });
345
346 }
347 }
348
349 return new List<GroupRolesData>();
350 }
351
352 public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID groupID)
353 {
354 string url = string.Empty, gname = string.Empty;
355
356 if (IsLocal(groupID, out url, out gname))
357 return m_LocalGroupsConnector.GetGroupRoleMembers(AgentUUI(RequestingAgentID), groupID);
358 else if (!string.IsNullOrEmpty(url))
359 {
360 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID);
361 string accessToken = string.Empty;
362 if (membership != null)
363 accessToken = membership.AccessToken;
364 else
365 return null;
366
367 GroupsServiceHGConnector c = GetConnector(url);
368 if (c != null)
369 {
370 return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, groupID, delegate
371 {
372 return c.GetGroupRoleMembers(AgentUUIForOutside(RequestingAgentID), groupID, accessToken);
373 });
374
375 }
376 }
377
378 return new List<GroupRoleMembersData>();
379 }
380
381 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
382 {
383 string url = string.Empty;
384 string name = string.Empty;
385 reason = string.Empty;
386
387 UUID uid = new UUID(AgentID);
388 if (IsLocal(GroupID, out url, out name))
389 {
390 if (m_UserManagement.IsLocalGridUser(uid)) // local user
391 {
392 // normal case: local group, local user
393 return m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason);
394 }
395 else // local group, foreign user
396 {
397 // the user is accepting the invitation, or joining, where the group resides
398 token = UUID.Random().ToString();
399 bool success = m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason);
400
401 if (success)
402 {
403 // Here we always return true. The user has been added to the local group,
404 // independent of whether the remote operation succeeds or not
405 url = m_UserManagement.GetUserServerURL(uid, "GroupsServerURI");
406 if (url == string.Empty)
407 {
408 reason = "You don't have an accessible groups server in your home world. You membership to this group in only within this grid.";
409 return true;
410 }
411
412 GroupsServiceHGConnector c = GetConnector(url);
413 if (c != null)
414 c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason);
415 return true;
416 }
417 return false;
418 }
419 }
420 else if (m_UserManagement.IsLocalGridUser(uid)) // local user
421 {
422 // foreign group, local user. She's been added already by the HG service.
423 // Let's just check
424 if (m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID) != null)
425 return true;
426 }
427
428 reason = "Operation not allowed outside this group's origin world";
429 return false;
430 }
431
432
433 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
434 {
435 string url = string.Empty, name = string.Empty;
436 if (!IsLocal(GroupID, out url, out name) && url != string.Empty)
437 {
438 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
439 if (membership != null)
440 {
441 GroupsServiceHGConnector c = GetConnector(url);
442 if (c != null)
443 c.RemoveAgentFromGroup(AgentUUIForOutside(AgentID), GroupID, membership.AccessToken);
444 }
445 }
446
447 // remove from local service
448 m_LocalGroupsConnector.RemoveAgentFromGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
449 }
450
451 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
452 {
453 string url = string.Empty, gname = string.Empty;
454
455 if (IsLocal(groupID, out url, out gname))
456 return m_LocalGroupsConnector.AddAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID, groupID, roleID, AgentUUI(agentID));
457 else
458 return false;
459 }
460
461 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
462 {
463 return m_LocalGroupsConnector.GetAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID); ;
464 }
465
466 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
467 {
468 m_LocalGroupsConnector.RemoveAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID);
469 }
470
471 public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
472 {
473 string url = string.Empty, gname = string.Empty;
474
475 if (IsLocal(GroupID, out url, out gname))
476 m_LocalGroupsConnector.AddAgentToGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID);
477
478 }
479
480 public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
481 {
482 string url = string.Empty, gname = string.Empty;
483
484 if (IsLocal(GroupID, out url, out gname))
485 m_LocalGroupsConnector.RemoveAgentFromGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID);
486 }
487
488 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
489 {
490 string url = string.Empty, gname = string.Empty;
491
492 if (IsLocal(GroupID, out url, out gname))
493 return m_LocalGroupsConnector.GetAgentGroupRoles(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
494 else
495 return new List<GroupRolesData>();
496 }
497
498 public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
499 {
500 string url = string.Empty, gname = string.Empty;
501
502 if (IsLocal(GroupID, out url, out gname))
503 m_LocalGroupsConnector.SetAgentActiveGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
504 }
505
506 public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
507 {
508 return m_LocalGroupsConnector.GetAgentActiveMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID));
509 }
510
511 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
512 {
513 string url = string.Empty, gname = string.Empty;
514
515 if (IsLocal(GroupID, out url, out gname))
516 m_LocalGroupsConnector.SetAgentActiveGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID);
517 }
518
519 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
520 {
521 m_LocalGroupsConnector.UpdateMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, AcceptNotices, ListInProfile);
522 }
523
524 public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
525 {
526 string url = string.Empty, gname = string.Empty;
527
528 if (IsLocal(GroupID, out url, out gname))
529 return m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
530 else
531 return null;
532 }
533
534 public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
535 {
536 return m_LocalGroupsConnector.GetAgentGroupMemberships(AgentUUI(RequestingAgentID), AgentUUI(AgentID));
537 }
538
539 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
540 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
541 {
542 string url = string.Empty, gname = string.Empty;
543
544 if (IsLocal(groupID, out url, out gname))
545 {
546 if (m_LocalGroupsConnector.AddGroupNotice(AgentUUI(RequestingAgentID), groupID, noticeID, fromName, subject, message,
547 hasAttachment, attType, attName, attItemID, AgentUUI(attOwnerID)))
548 {
549 // then send the notice to every grid for which there are members in this group
550 List<GroupMembersData> members = m_LocalGroupsConnector.GetGroupMembers(AgentUUI(RequestingAgentID), groupID);
551 List<string> urls = new List<string>();
552 foreach (GroupMembersData m in members)
553 {
554 if (!m_UserManagement.IsLocalGridUser(m.AgentID))
555 {
556 string gURL = m_UserManagement.GetUserServerURL(m.AgentID, "GroupsServerURI");
557 if (!urls.Contains(gURL))
558 urls.Add(gURL);
559 }
560 }
561
562 // so we have the list of urls to send the notice to
563 // this may take a long time...
564 WorkManager.RunInThread(delegate
565 {
566 foreach (string u in urls)
567 {
568 GroupsServiceHGConnector c = GetConnector(u);
569 if (c != null)
570 {
571 c.AddNotice(AgentUUIForOutside(RequestingAgentID), groupID, noticeID, fromName, subject, message,
572 hasAttachment, attType, attName, attItemID, AgentUUIForOutside(attOwnerID));
573 }
574 }
575 }, null, string.Format("AddGroupNotice (agent {0}, group {1})", RequestingAgentID, groupID));
576
577 return true;
578 }
579
580 return false;
581 }
582 else
583 return false;
584 }
585
586 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
587 {
588 GroupNoticeInfo notice = m_LocalGroupsConnector.GetGroupNotice(AgentUUI(RequestingAgentID), noticeID);
589
590 if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null)
591 ImportForeigner(notice.noticeData.AttachmentOwnerID);
592
593 return notice;
594 }
595
596 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
597 {
598 return m_LocalGroupsConnector.GetGroupNotices(AgentUUI(RequestingAgentID), GroupID);
599 }
600
601 #endregion
602
603 #region hypergrid groups
604
605 private string AgentUUI(string AgentIDStr)
606 {
607 UUID AgentID = UUID.Zero;
608 try
609 {
610 AgentID = new UUID(AgentIDStr);
611 }
612 catch (FormatException)
613 {
614 return AgentID.ToString();
615 }
616
617 if (m_UserManagement.IsLocalGridUser(AgentID))
618 return AgentID.ToString();
619
620 AgentCircuitData agent = null;
621 foreach (Scene scene in m_Scenes)
622 {
623 agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID);
624 if (agent != null)
625 break;
626 }
627 if (agent != null)
628 return Util.ProduceUserUniversalIdentifier(agent);
629
630 // we don't know anything about this foreign user
631 // try asking the user management module, which may know more
632 return m_UserManagement.GetUserUUI(AgentID);
633
634 }
635
636 private string AgentUUIForOutside(string AgentIDStr)
637 {
638 UUID AgentID = UUID.Zero;
639 try
640 {
641 AgentID = new UUID(AgentIDStr);
642 }
643 catch (FormatException)
644 {
645 return AgentID.ToString();
646 }
647
648 AgentCircuitData agent = null;
649 foreach (Scene scene in m_Scenes)
650 {
651 agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID);
652 if (agent != null)
653 break;
654 }
655 if (agent == null) // oops
656 return AgentID.ToString();
657
658 return Util.ProduceUserUniversalIdentifier(agent);
659 }
660
661 private UUID ImportForeigner(string uID)
662 {
663 UUID userID = UUID.Zero;
664 string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
665 if (Util.ParseUniversalUserIdentifier(uID, out userID, out url, out first, out last, out tmp))
666 m_UserManagement.AddUser(userID, first, last, url);
667
668 return userID;
669 }
670
671 private bool IsLocal(UUID groupID, out string serviceLocation, out string name)
672 {
673 serviceLocation = string.Empty;
674 name = string.Empty;
675 if (groupID.Equals(UUID.Zero))
676 return true;
677
678 ExtendedGroupRecord group = m_LocalGroupsConnector.GetGroupRecord(UUID.Zero.ToString(), groupID, string.Empty);
679 if (group == null)
680 {
681 //m_log.DebugFormat("[XXX]: IsLocal? group {0} not found -- no.", groupID);
682 return false;
683 }
684
685 serviceLocation = group.ServiceLocation;
686 name = group.GroupName;
687 bool isLocal = (group.ServiceLocation == string.Empty);
688 //m_log.DebugFormat("[XXX]: IsLocal? {0}", isLocal);
689 return isLocal;
690 }
691
692 private GroupsServiceHGConnector GetConnector(string url)
693 {
694 lock (m_NetworkConnectors)
695 {
696 if (m_NetworkConnectors.ContainsKey(url))
697 return m_NetworkConnectors[url];
698
699 GroupsServiceHGConnector c = new GroupsServiceHGConnector(url);
700 m_NetworkConnectors[url] = c;
701 }
702
703 return m_NetworkConnectors[url];
704 }
705 #endregion
706 }
707}
diff --git a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs
new file mode 100644
index 0000000..f60c1a5
--- /dev/null
+++ b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs
@@ -0,0 +1,444 @@
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 System.Xml;
32using System.Collections.Generic;
33using System.IO;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Server.Handlers.Base;
40using log4net;
41using OpenMetaverse;
42
43namespace OpenSim.Groups
44{
45 public class HGGroupsServiceRobustConnector : ServiceConnector
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private HGGroupsService m_GroupsService;
50 private string m_ConfigName = "Groups";
51
52 // Called by Robust shell
53 public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
54 this(config, server, configName, null, null)
55 {
56 }
57
58 // Called by the sim-bound module
59 public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName, IOfflineIMService im, IUserAccountService users) :
60 base(config, server, configName)
61 {
62 if (configName != String.Empty)
63 m_ConfigName = configName;
64
65 m_log.DebugFormat("[Groups.RobustHGConnector]: Starting with config name {0}", m_ConfigName);
66
67 string homeURI = Util.GetConfigVarFromSections<string>(config, "HomeURI",
68 new string[] { "Startup", "Hypergrid", m_ConfigName}, string.Empty);
69 if (homeURI == string.Empty)
70 throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide the HomeURI [Startup] or in section {0}", m_ConfigName));
71
72 IConfig cnf = config.Configs[m_ConfigName];
73 if (cnf == null)
74 throw new Exception(String.Format("[Groups.RobustHGConnector]: {0} section does not exist", m_ConfigName));
75
76 if (im == null)
77 {
78 string imDll = cnf.GetString("OfflineIMService", string.Empty);
79 if (imDll == string.Empty)
80 throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide OfflineIMService in section {0}", m_ConfigName));
81
82 Object[] args = new Object[] { config };
83 im = ServerUtils.LoadPlugin<IOfflineIMService>(imDll, args);
84 }
85
86 if (users == null)
87 {
88 string usersDll = cnf.GetString("UserAccountService", string.Empty);
89 if (usersDll == string.Empty)
90 throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide UserAccountService in section {0}", m_ConfigName));
91
92 Object[] args = new Object[] { config };
93 users = ServerUtils.LoadPlugin<IUserAccountService>(usersDll, args);
94 }
95
96 m_GroupsService = new HGGroupsService(config, im, users, homeURI);
97
98 server.AddStreamHandler(new HGGroupsServicePostHandler(m_GroupsService));
99 }
100
101 }
102
103 public class HGGroupsServicePostHandler : BaseStreamHandler
104 {
105 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
106
107 private HGGroupsService m_GroupsService;
108
109 public HGGroupsServicePostHandler(HGGroupsService service) :
110 base("POST", "/hg-groups")
111 {
112 m_GroupsService = service;
113 }
114
115 protected override byte[] ProcessRequest(string path, Stream requestData,
116 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
117 {
118 StreamReader sr = new StreamReader(requestData);
119 string body = sr.ReadToEnd();
120 sr.Close();
121 body = body.Trim();
122
123 //m_log.DebugFormat("[XXX]: query String: {0}", body);
124
125 try
126 {
127 Dictionary<string, object> request =
128 ServerUtils.ParseQueryString(body);
129
130 if (!request.ContainsKey("METHOD"))
131 return FailureResult();
132
133 string method = request["METHOD"].ToString();
134 request.Remove("METHOD");
135
136 m_log.DebugFormat("[Groups.RobustHGConnector]: {0}", method);
137 switch (method)
138 {
139 case "POSTGROUP":
140 return HandleAddGroupProxy(request);
141 case "REMOVEAGENTFROMGROUP":
142 return HandleRemoveAgentFromGroup(request);
143 case "GETGROUP":
144 return HandleGetGroup(request);
145 case "ADDNOTICE":
146 return HandleAddNotice(request);
147 case "VERIFYNOTICE":
148 return HandleVerifyNotice(request);
149 case "GETGROUPMEMBERS":
150 return HandleGetGroupMembers(request);
151 case "GETGROUPROLES":
152 return HandleGetGroupRoles(request);
153 case "GETROLEMEMBERS":
154 return HandleGetRoleMembers(request);
155
156 }
157 m_log.DebugFormat("[Groups.RobustHGConnector]: unknown method request: {0}", method);
158 }
159 catch (Exception e)
160 {
161 m_log.Error(string.Format("[Groups.RobustHGConnector]: Exception {0} ", e.Message), e);
162 }
163
164 return FailureResult();
165 }
166
167 byte[] HandleAddGroupProxy(Dictionary<string, object> request)
168 {
169 Dictionary<string, object> result = new Dictionary<string, object>();
170
171 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID")
172 || !request.ContainsKey("AgentID")
173 || !request.ContainsKey("AccessToken") || !request.ContainsKey("Location"))
174 NullResult(result, "Bad network data");
175
176 else
177 {
178 string RequestingAgentID = request["RequestingAgentID"].ToString();
179 string agentID = request["AgentID"].ToString();
180 UUID groupID = new UUID(request["GroupID"].ToString());
181 string accessToken = request["AccessToken"].ToString();
182 string location = request["Location"].ToString();
183 string name = string.Empty;
184 if (request.ContainsKey("Name"))
185 name = request["Name"].ToString();
186
187 string reason = string.Empty;
188 bool success = m_GroupsService.CreateGroupProxy(RequestingAgentID, agentID, accessToken, groupID, location, name, out reason);
189 result["REASON"] = reason;
190 result["RESULT"] = success.ToString();
191 }
192
193 string xmlString = ServerUtils.BuildXmlResponse(result);
194
195 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
196 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
197 }
198
199 byte[] HandleRemoveAgentFromGroup(Dictionary<string, object> request)
200 {
201 Dictionary<string, object> result = new Dictionary<string, object>();
202
203 if (!request.ContainsKey("AccessToken") || !request.ContainsKey("AgentID") ||
204 !request.ContainsKey("GroupID"))
205 NullResult(result, "Bad network data");
206 else
207 {
208 UUID groupID = new UUID(request["GroupID"].ToString());
209 string agentID = request["AgentID"].ToString();
210 string token = request["AccessToken"].ToString();
211
212 if (!m_GroupsService.RemoveAgentFromGroup(agentID, agentID, groupID, token))
213 NullResult(result, "Internal error");
214 else
215 result["RESULT"] = "true";
216 }
217
218 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
219 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
220 }
221
222 byte[] HandleGetGroup(Dictionary<string, object> request)
223 {
224 Dictionary<string, object> result = new Dictionary<string, object>();
225
226 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AccessToken"))
227 NullResult(result, "Bad network data");
228 else
229 {
230 string RequestingAgentID = request["RequestingAgentID"].ToString();
231 string token = request["AccessToken"].ToString();
232
233 UUID groupID = UUID.Zero;
234 string groupName = string.Empty;
235
236 if (request.ContainsKey("GroupID"))
237 groupID = new UUID(request["GroupID"].ToString());
238 if (request.ContainsKey("Name"))
239 groupName = request["Name"].ToString();
240
241 ExtendedGroupRecord grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID, groupName, token);
242 if (grec == null)
243 NullResult(result, "Group not found");
244 else
245 result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
246 }
247
248 string xmlString = ServerUtils.BuildXmlResponse(result);
249
250 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
251 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
252 }
253
254 byte[] HandleGetGroupMembers(Dictionary<string, object> request)
255 {
256 Dictionary<string, object> result = new Dictionary<string, object>();
257
258 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken"))
259 NullResult(result, "Bad network data");
260 else
261 {
262 UUID groupID = new UUID(request["GroupID"].ToString());
263 string requestingAgentID = request["RequestingAgentID"].ToString();
264 string token = request["AccessToken"].ToString();
265
266 List<ExtendedGroupMembersData> members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID, token);
267 if (members == null || (members != null && members.Count == 0))
268 {
269 NullResult(result, "No members");
270 }
271 else
272 {
273 Dictionary<string, object> dict = new Dictionary<string, object>();
274 int i = 0;
275 foreach (ExtendedGroupMembersData m in members)
276 {
277 dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m);
278 }
279
280 result["RESULT"] = dict;
281 }
282 }
283
284 string xmlString = ServerUtils.BuildXmlResponse(result);
285
286 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
287 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
288 }
289
290 byte[] HandleGetGroupRoles(Dictionary<string, object> request)
291 {
292 Dictionary<string, object> result = new Dictionary<string, object>();
293
294 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken"))
295 NullResult(result, "Bad network data");
296 else
297 {
298 UUID groupID = new UUID(request["GroupID"].ToString());
299 string requestingAgentID = request["RequestingAgentID"].ToString();
300 string token = request["AccessToken"].ToString();
301
302 List<GroupRolesData> roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID, token);
303 if (roles == null || (roles != null && roles.Count == 0))
304 {
305 NullResult(result, "No members");
306 }
307 else
308 {
309 Dictionary<string, object> dict = new Dictionary<string, object>();
310 int i = 0;
311 foreach (GroupRolesData r in roles)
312 dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r);
313
314 result["RESULT"] = dict;
315 }
316 }
317
318 string xmlString = ServerUtils.BuildXmlResponse(result);
319
320 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
321 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
322 }
323
324 byte[] HandleGetRoleMembers(Dictionary<string, object> request)
325 {
326 Dictionary<string, object> result = new Dictionary<string, object>();
327
328 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken"))
329 NullResult(result, "Bad network data");
330 else
331 {
332 UUID groupID = new UUID(request["GroupID"].ToString());
333 string requestingAgentID = request["RequestingAgentID"].ToString();
334 string token = request["AccessToken"].ToString();
335
336 List<ExtendedGroupRoleMembersData> rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID, token);
337 if (rmembers == null || (rmembers != null && rmembers.Count == 0))
338 {
339 NullResult(result, "No members");
340 }
341 else
342 {
343 Dictionary<string, object> dict = new Dictionary<string, object>();
344 int i = 0;
345 foreach (ExtendedGroupRoleMembersData rm in rmembers)
346 dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm);
347
348 result["RESULT"] = dict;
349 }
350 }
351
352 string xmlString = ServerUtils.BuildXmlResponse(result);
353
354 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
355 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
356 }
357
358 byte[] HandleAddNotice(Dictionary<string, object> request)
359 {
360 Dictionary<string, object> result = new Dictionary<string, object>();
361
362 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") ||
363 !request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") ||
364 !request.ContainsKey("HasAttachment"))
365 NullResult(result, "Bad network data");
366
367 else
368 {
369
370 bool hasAtt = bool.Parse(request["HasAttachment"].ToString());
371 byte attType = 0;
372 string attName = string.Empty;
373 string attOwner = string.Empty;
374 UUID attItem = UUID.Zero;
375 if (request.ContainsKey("AttachmentType"))
376 attType = byte.Parse(request["AttachmentType"].ToString());
377 if (request.ContainsKey("AttachmentName"))
378 attName = request["AttachmentType"].ToString();
379 if (request.ContainsKey("AttachmentItemID"))
380 attItem = new UUID(request["AttachmentItemID"].ToString());
381 if (request.ContainsKey("AttachmentOwnerID"))
382 attOwner = request["AttachmentOwnerID"].ToString();
383
384 bool success = m_GroupsService.AddNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
385 new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(),
386 request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner);
387
388 result["RESULT"] = success.ToString();
389 }
390
391 string xmlString = ServerUtils.BuildXmlResponse(result);
392
393 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
394 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
395 }
396
397 byte[] HandleVerifyNotice(Dictionary<string, object> request)
398 {
399 Dictionary<string, object> result = new Dictionary<string, object>();
400
401 if (!request.ContainsKey("NoticeID") || !request.ContainsKey("GroupID"))
402 NullResult(result, "Bad network data");
403
404 else
405 {
406 UUID noticeID = new UUID(request["NoticeID"].ToString());
407 UUID groupID = new UUID(request["GroupID"].ToString());
408
409 bool success = m_GroupsService.VerifyNotice(noticeID, groupID);
410 //m_log.DebugFormat("[XXX]: VerifyNotice returned {0}", success);
411 result["RESULT"] = success.ToString();
412 }
413
414 string xmlString = ServerUtils.BuildXmlResponse(result);
415
416 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
417 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
418 }
419
420 //
421 //
422 //
423 //
424 //
425
426 #region Helpers
427
428 private void NullResult(Dictionary<string, object> result, string reason)
429 {
430 result["RESULT"] = "NULL";
431 result["REASON"] = reason;
432 }
433
434 private byte[] FailureResult()
435 {
436 Dictionary<string, object> result = new Dictionary<string, object>();
437 NullResult(result, "Unknown method");
438 string xmlString = ServerUtils.BuildXmlResponse(result);
439 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
440 }
441
442 #endregion
443 }
444}
diff --git a/OpenSim/Addons/Groups/IGroupsServicesConnector.cs b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs
new file mode 100644
index 0000000..a09b59e
--- /dev/null
+++ b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs
@@ -0,0 +1,112 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33namespace OpenSim.Groups
34{
35 public interface IGroupsServicesConnector
36 {
37 UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee,
38 bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason);
39 bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
40 bool openEnrollment, bool allowPublish, bool maturePublish, out string reason);
41 ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName);
42 List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search);
43 List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID);
44
45 bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason);
46 bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers);
47 void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID);
48 List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID);
49 List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID);
50
51 bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason);
52 void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID);
53
54 bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID);
55 GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID);
56 void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID);
57
58 void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID);
59 void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID);
60 List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID);
61
62 void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID);
63 ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID);
64
65 void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID);
66 void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile);
67
68 /// <summary>
69 /// Get information about a specific group to which the user belongs.
70 /// </summary>
71 /// <param name="RequestingAgentID">The agent requesting the information.</param>
72 /// <param name="AgentID">The agent requested.</param>
73 /// <param name="GroupID">The group requested.</param>
74 /// <returns>
75 /// If the user is a member of the group then the data structure is returned. If not, then null is returned.
76 /// </returns>
77 ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID);
78
79 /// <summary>
80 /// Get information about the groups to which a user belongs.
81 /// </summary>
82 /// <param name="RequestingAgentID">The agent requesting the information.</param>
83 /// <param name="AgentID">The agent requested.</param>
84 /// <returns>
85 /// Information about the groups to which the user belongs. If the user belongs to no groups then an empty
86 /// list is returned.
87 /// </returns>
88 List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID);
89
90 bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
91 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID);
92 GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID);
93 List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID);
94
95 }
96
97 public class GroupInviteInfo
98 {
99 public UUID GroupID = UUID.Zero;
100 public UUID RoleID = UUID.Zero;
101 public string AgentID = string.Empty;
102 public UUID InviteID = UUID.Zero;
103 }
104
105 public class GroupNoticeInfo
106 {
107 public ExtendedGroupNoticeData noticeData = new ExtendedGroupNoticeData();
108 public UUID GroupID = UUID.Zero;
109 public string Message = string.Empty;
110 }
111
112}
diff --git a/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs
new file mode 100644
index 0000000..8e30df5
--- /dev/null
+++ b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs
@@ -0,0 +1,326 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Services.Interfaces;
38
39using OpenMetaverse;
40using Mono.Addins;
41using log4net;
42using Nini.Config;
43
44namespace OpenSim.Groups
45{
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceLocalConnectorModule")]
47 public class GroupsServiceLocalConnectorModule : ISharedRegionModule, IGroupsServicesConnector
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private bool m_Enabled = false;
52 private GroupsService m_GroupsService;
53 private IUserManagement m_UserManagement;
54 private List<Scene> m_Scenes;
55 private ForeignImporter m_ForeignImporter;
56
57 #region constructors
58 public GroupsServiceLocalConnectorModule()
59 {
60 }
61
62 public GroupsServiceLocalConnectorModule(IConfigSource config, IUserManagement uman)
63 {
64 Init(config);
65 m_UserManagement = uman;
66 m_ForeignImporter = new ForeignImporter(uman);
67 }
68 #endregion
69
70 private void Init(IConfigSource config)
71 {
72 m_GroupsService = new GroupsService(config);
73 m_Scenes = new List<Scene>();
74 }
75
76 #region ISharedRegionModule
77
78 public void Initialise(IConfigSource config)
79 {
80 IConfig groupsConfig = config.Configs["Groups"];
81 if (groupsConfig == null)
82 return;
83
84 if ((groupsConfig.GetBoolean("Enabled", false) == false)
85 || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name))
86 {
87 return;
88 }
89
90 Init(config);
91 m_Enabled = true;
92
93 m_log.DebugFormat("[Groups]: Initializing {0}", this.Name);
94 }
95
96 public string Name
97 {
98 get { return "Groups Local Service Connector"; }
99 }
100
101 public Type ReplaceableInterface
102 {
103 get { return null; }
104 }
105
106 public void AddRegion(Scene scene)
107 {
108 if (!m_Enabled)
109 return;
110
111 m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName);
112 scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
113 m_Scenes.Add(scene);
114 }
115
116 public void RemoveRegion(Scene scene)
117 {
118 if (!m_Enabled)
119 return;
120
121 scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
122 m_Scenes.Remove(scene);
123 }
124
125 public void RegionLoaded(Scene scene)
126 {
127 if (!m_Enabled)
128 return;
129
130 if (m_UserManagement == null)
131 {
132 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
133 m_ForeignImporter = new ForeignImporter(m_UserManagement);
134 }
135 }
136
137 public void PostInitialise()
138 {
139 }
140
141 public void Close()
142 {
143 }
144
145 #endregion
146
147 #region IGroupsServicesConnector
148
149 public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
150 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
151 {
152 m_log.DebugFormat("[Groups]: Creating group {0}", name);
153 reason = string.Empty;
154 return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID,
155 membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason);
156 }
157
158 public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
159 bool openEnrollment, bool allowPublish, bool maturePublish, out string reason)
160 {
161 reason = string.Empty;
162 m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
163 return true;
164 }
165
166 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
167 {
168 if (GroupID != UUID.Zero)
169 return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID);
170 else if (GroupName != null)
171 return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupName);
172
173 return null;
174 }
175
176 public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search)
177 {
178 return m_GroupsService.FindGroups(RequestingAgentID, search);
179 }
180
181 public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
182 {
183 List<ExtendedGroupMembersData> _members = m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID);
184 if (_members != null && _members.Count > 0)
185 {
186 List<GroupMembersData> members = _members.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData));
187 return members;
188 }
189
190 return new List<GroupMembersData>();
191 }
192
193 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
194 {
195 return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out reason);
196 }
197
198 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
199 {
200 return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers);
201 }
202
203 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
204 {
205 m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID);
206 }
207
208 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
209 {
210 return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID);
211 }
212
213 public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
214 {
215 List<ExtendedGroupRoleMembersData> _rm = m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID);
216 if (_rm != null && _rm.Count > 0)
217 {
218 List<GroupRoleMembersData> rm = _rm.ConvertAll<GroupRoleMembersData>(new Converter<ExtendedGroupRoleMembersData, GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData));
219 return rm;
220 }
221
222 return new List<GroupRoleMembersData>();
223
224 }
225
226 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
227 {
228 return m_GroupsService.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, token, out reason);
229 }
230
231 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
232 {
233 m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
234 }
235
236 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
237 {
238 return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID);
239 }
240
241 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
242 {
243 return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID); ;
244 }
245
246 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
247 {
248 m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID);
249 }
250
251 public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
252 {
253 m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
254 }
255
256 public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
257 {
258 m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
259 }
260
261 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
262 {
263 return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID);
264 }
265
266 public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
267 {
268 m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID);
269 }
270
271 public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
272 {
273 return m_GroupsService.GetAgentActiveMembership(RequestingAgentID, AgentID);
274 }
275
276 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
277 {
278 m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
279 }
280
281 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
282 {
283 m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile);
284 }
285
286 public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
287 {
288 return m_GroupsService.GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID); ;
289 }
290
291 public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
292 {
293 return m_GroupsService.GetAgentGroupMemberships(RequestingAgentID, AgentID);
294 }
295
296 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
297 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
298 {
299 return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message,
300 hasAttachment, attType, attName, attItemID, attOwnerID);
301 }
302
303 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
304 {
305 GroupNoticeInfo notice = m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID);
306
307 //if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null)
308 //{
309 // UUID userID = UUID.Zero;
310 // string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
311 // Util.ParseUniversalUserIdentifier(notice.noticeData.AttachmentOwnerID, out userID, out url, out first, out last, out tmp);
312 // if (url != string.Empty)
313 // m_UserManagement.AddUser(userID, first, last, url);
314 //}
315
316 return notice;
317 }
318
319 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
320 {
321 return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID);
322 }
323
324 #endregion
325 }
326}
diff --git a/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..cf0de1d
--- /dev/null
+++ b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4using Mono.Addins;
5
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Addons.Groups")]
10[assembly: AssemblyDescription("")]
11[assembly: AssemblyConfiguration("")]
12[assembly: AssemblyCompany("http://opensimulator.org")]
13[assembly: AssemblyProduct("OpenSim.Addons.Groups")]
14[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")]
17
18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)]
22
23// The following GUID is for the ID of the typelib if this project is exposed to COM
24[assembly: Guid("313d4865-d179-4735-9b5a-fe74885878b2")]
25
26// Version information for an assembly consists of the following four values:
27//
28// Major Version
29// Minor Version
30// Build Number
31// Revision
32//
33[assembly: AssemblyVersion("0.8.3.*")]
34
35[assembly: Addin("OpenSim.Groups", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs
new file mode 100644
index 0000000..7450c14
--- /dev/null
+++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs
@@ -0,0 +1,696 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33
34using OpenSim.Framework;
35using OpenSim.Framework.ServiceAuth;
36using OpenSim.Server.Base;
37
38using OpenMetaverse;
39using log4net;
40using Nini.Config;
41
42namespace OpenSim.Groups
43{
44 public class GroupsServiceRemoteConnector
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private string m_ServerURI;
49 private IServiceAuth m_Auth;
50 private object m_Lock = new object();
51
52 public GroupsServiceRemoteConnector(IConfigSource config)
53 {
54 IConfig groupsConfig = config.Configs["Groups"];
55 string url = groupsConfig.GetString("GroupsServerURI", string.Empty);
56 if (!Uri.IsWellFormedUriString(url, UriKind.Absolute))
57 throw new Exception(string.Format("[Groups.RemoteConnector]: Malformed groups server URL {0}. Fix it or disable the Groups feature.", url));
58
59 m_ServerURI = url;
60 if (!m_ServerURI.EndsWith("/"))
61 m_ServerURI += "/";
62
63 /// This is from BaseServiceConnector
64 string authType = Util.GetConfigVarFromSections<string>(config, "AuthType", new string[] { "Network", "Groups" }, "None");
65
66 switch (authType)
67 {
68 case "BasicHttpAuthentication":
69 m_Auth = new BasicHttpAuthentication(config, "Groups");
70 break;
71 }
72 ///
73
74 m_log.DebugFormat("[Groups.RemoteConnector]: Groups server at {0}, authentication {1}",
75 m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString()));
76 }
77
78 public ExtendedGroupRecord CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
79 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
80 {
81 reason = string.Empty;
82
83 ExtendedGroupRecord rec = new ExtendedGroupRecord();
84 rec.AllowPublish = allowPublish;
85 rec.Charter = charter;
86 rec.FounderID = founderID;
87 rec.GroupName = name;
88 rec.GroupPicture = insigniaID;
89 rec.MaturePublish = maturePublish;
90 rec.MembershipFee = membershipFee;
91 rec.OpenEnrollment = openEnrollment;
92 rec.ShowInList = showInList;
93
94 Dictionary<string, object> sendData = GroupsDataUtils.GroupRecord(rec);
95 sendData["RequestingAgentID"] = RequestingAgentID;
96 sendData["OP"] = "ADD";
97 Dictionary<string, object> ret = MakeRequest("PUTGROUP", sendData);
98
99 if (ret == null)
100 return null;
101
102 if (ret["RESULT"].ToString() == "NULL")
103 {
104 reason = ret["REASON"].ToString();
105 return null;
106 }
107
108 return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
109
110 }
111
112 public ExtendedGroupRecord UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
113 {
114 ExtendedGroupRecord rec = new ExtendedGroupRecord();
115 rec.AllowPublish = allowPublish;
116 rec.Charter = charter;
117 rec.GroupPicture = insigniaID;
118 rec.MaturePublish = maturePublish;
119 rec.GroupID = groupID;
120 rec.MembershipFee = membershipFee;
121 rec.OpenEnrollment = openEnrollment;
122 rec.ShowInList = showInList;
123
124 Dictionary<string, object> sendData = GroupsDataUtils.GroupRecord(rec);
125 sendData["RequestingAgentID"] = RequestingAgentID;
126 sendData["OP"] = "UPDATE";
127 Dictionary<string, object> ret = MakeRequest("PUTGROUP", sendData);
128
129 if (ret == null || (ret != null && (!ret.ContainsKey("RESULT") || ret["RESULT"].ToString() == "NULL")))
130 return null;
131
132 return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
133 }
134
135 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
136 {
137 if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty)))
138 return null;
139
140 Dictionary<string, object> sendData = new Dictionary<string, object>();
141 if (GroupID != UUID.Zero)
142 sendData["GroupID"] = GroupID.ToString();
143 if (!string.IsNullOrEmpty(GroupName))
144 sendData["Name"] = GroupsDataUtils.Sanitize(GroupName);
145
146 sendData["RequestingAgentID"] = RequestingAgentID;
147
148 Dictionary<string, object> ret = MakeRequest("GETGROUP", sendData);
149
150 if (ret == null || (ret != null && (!ret.ContainsKey("RESULT") || ret["RESULT"].ToString() == "NULL")))
151 return null;
152
153 return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
154 }
155
156 public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string query)
157 {
158 List<DirGroupsReplyData> hits = new List<DirGroupsReplyData>();
159 if (string.IsNullOrEmpty(query))
160 return hits;
161
162 Dictionary<string, object> sendData = new Dictionary<string, object>();
163 sendData["Query"] = query;
164 sendData["RequestingAgentID"] = RequestingAgentID;
165
166 Dictionary<string, object> ret = MakeRequest("FINDGROUPS", sendData);
167
168 if (ret == null)
169 return hits;
170
171 if (!ret.ContainsKey("RESULT"))
172 return hits;
173
174 if (ret["RESULT"].ToString() == "NULL")
175 return hits;
176
177 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
178 {
179 DirGroupsReplyData m = GroupsDataUtils.DirGroupsReplyData((Dictionary<string, object>)v);
180 hits.Add(m);
181 }
182
183 return hits;
184 }
185
186 public GroupMembershipData AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
187 {
188 reason = string.Empty;
189
190 Dictionary<string, object> sendData = new Dictionary<string,object>();
191 sendData["AgentID"] = AgentID;
192 sendData["GroupID"] = GroupID.ToString();
193 sendData["RoleID"] = RoleID.ToString();
194 sendData["RequestingAgentID"] = RequestingAgentID;
195 sendData["AccessToken"] = token;
196 Dictionary<string, object> ret = MakeRequest("ADDAGENTTOGROUP", sendData);
197
198 if (ret == null)
199 return null;
200
201 if (!ret.ContainsKey("RESULT"))
202 return null;
203
204 if (ret["RESULT"].ToString() == "NULL")
205 {
206 reason = ret["REASON"].ToString();
207 return null;
208 }
209
210 return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]);
211
212 }
213
214 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
215 {
216 Dictionary<string, object> sendData = new Dictionary<string, object>();
217 sendData["AgentID"] = AgentID;
218 sendData["GroupID"] = GroupID.ToString();
219 sendData["RequestingAgentID"] = RequestingAgentID;
220 MakeRequest("REMOVEAGENTFROMGROUP", sendData);
221 }
222
223 public ExtendedGroupMembershipData GetMembership(string RequestingAgentID, string AgentID, UUID GroupID)
224 {
225 Dictionary<string, object> sendData = new Dictionary<string, object>();
226 sendData["AgentID"] = AgentID;
227 if (GroupID != UUID.Zero)
228 sendData["GroupID"] = GroupID.ToString();
229 sendData["RequestingAgentID"] = RequestingAgentID;
230 Dictionary<string, object> ret = MakeRequest("GETMEMBERSHIP", sendData);
231
232 if (ret == null)
233 return null;
234
235 if (!ret.ContainsKey("RESULT"))
236 return null;
237
238 if (ret["RESULT"].ToString() == "NULL")
239 return null;
240
241 return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]);
242 }
243
244 public List<GroupMembershipData> GetMemberships(string RequestingAgentID, string AgentID)
245 {
246 List<GroupMembershipData> memberships = new List<GroupMembershipData>();
247
248 Dictionary<string, object> sendData = new Dictionary<string, object>();
249 sendData["AgentID"] = AgentID;
250 sendData["ALL"] = "true";
251 sendData["RequestingAgentID"] = RequestingAgentID;
252 Dictionary<string, object> ret = MakeRequest("GETMEMBERSHIP", sendData);
253
254 if (ret == null)
255 return memberships;
256
257 if (!ret.ContainsKey("RESULT"))
258 return memberships;
259
260 if (ret["RESULT"].ToString() == "NULL")
261 return memberships;
262
263 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
264 {
265 GroupMembershipData m = GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)v);
266 memberships.Add(m);
267 }
268
269 return memberships;
270 }
271
272 public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
273 {
274 List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>();
275
276 Dictionary<string, object> sendData = new Dictionary<string, object>();
277 sendData["GroupID"] = GroupID.ToString();
278 sendData["RequestingAgentID"] = RequestingAgentID;
279
280 Dictionary<string, object> ret = MakeRequest("GETGROUPMEMBERS", sendData);
281
282 if (ret == null)
283 return members;
284
285 if (!ret.ContainsKey("RESULT"))
286 return members;
287
288 if (ret["RESULT"].ToString() == "NULL")
289 return members;
290
291 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
292 {
293 ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary<string, object>)v);
294 members.Add(m);
295 }
296
297 return members;
298 }
299
300 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
301 {
302 reason = string.Empty;
303
304 Dictionary<string, object> sendData = new Dictionary<string, object>();
305 sendData["GroupID"] = groupID.ToString();
306 sendData["RoleID"] = roleID.ToString();
307 sendData["Name"] = GroupsDataUtils.Sanitize(name);
308 sendData["Description"] = GroupsDataUtils.Sanitize(description);
309 sendData["Title"] = GroupsDataUtils.Sanitize(title);
310 sendData["Powers"] = powers.ToString();
311 sendData["RequestingAgentID"] = RequestingAgentID;
312 sendData["OP"] = "ADD";
313 Dictionary<string, object> ret = MakeRequest("PUTROLE", sendData);
314
315 if (ret == null)
316 return false;
317
318 if (!ret.ContainsKey("RESULT"))
319 return false;
320
321 if (ret["RESULT"].ToString().ToLower() != "true")
322 {
323 reason = ret["REASON"].ToString();
324 return false;
325 }
326
327 return true;
328 }
329
330 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
331 {
332 Dictionary<string, object> sendData = new Dictionary<string, object>();
333 sendData["GroupID"] = groupID.ToString();
334 sendData["RoleID"] = roleID.ToString();
335 sendData["Name"] = GroupsDataUtils.Sanitize(name);
336 sendData["Description"] = GroupsDataUtils.Sanitize(description);
337 sendData["Title"] = GroupsDataUtils.Sanitize(title);
338 sendData["Powers"] = powers.ToString();
339 sendData["RequestingAgentID"] = RequestingAgentID;
340 sendData["OP"] = "UPDATE";
341 Dictionary<string, object> ret = MakeRequest("PUTROLE", sendData);
342
343 if (ret == null)
344 return false;
345
346 if (!ret.ContainsKey("RESULT"))
347 return false;
348
349 if (ret["RESULT"].ToString().ToLower() != "true")
350 return false;
351
352 return true;
353 }
354
355 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
356 {
357 Dictionary<string, object> sendData = new Dictionary<string, object>();
358 sendData["GroupID"] = groupID.ToString();
359 sendData["RoleID"] = roleID.ToString();
360 sendData["RequestingAgentID"] = RequestingAgentID;
361 MakeRequest("REMOVEROLE", sendData);
362 }
363
364 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
365 {
366 List<GroupRolesData> roles = new List<GroupRolesData>();
367
368 Dictionary<string, object> sendData = new Dictionary<string, object>();
369 sendData["GroupID"] = GroupID.ToString();
370 sendData["RequestingAgentID"] = RequestingAgentID;
371 Dictionary<string, object> ret = MakeRequest("GETGROUPROLES", sendData);
372
373 if (ret == null)
374 return roles;
375
376 if (!ret.ContainsKey("RESULT"))
377 return roles;
378
379 if (ret["RESULT"].ToString() == "NULL")
380 return roles;
381
382 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
383 {
384 GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v);
385 roles.Add(m);
386 }
387
388 return roles;
389 }
390
391 public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
392 {
393 List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
394
395 Dictionary<string, object> sendData = new Dictionary<string, object>();
396 sendData["GroupID"] = GroupID.ToString();
397 sendData["RequestingAgentID"] = RequestingAgentID;
398 Dictionary<string, object> ret = MakeRequest("GETROLEMEMBERS", sendData);
399
400 if (ret == null)
401 return rmembers;
402
403 if (!ret.ContainsKey("RESULT"))
404 return rmembers;
405
406 if (ret["RESULT"].ToString() == "NULL")
407 return rmembers;
408
409 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
410 {
411 ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary<string, object>)v);
412 rmembers.Add(m);
413 }
414
415 return rmembers;
416 }
417
418 public bool AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
419 {
420 Dictionary<string, object> sendData = new Dictionary<string, object>();
421 sendData["AgentID"] = AgentID.ToString();
422 sendData["GroupID"] = GroupID.ToString();
423 sendData["RoleID"] = RoleID.ToString();
424 sendData["RequestingAgentID"] = RequestingAgentID;
425 sendData["OP"] = "ADD";
426
427 Dictionary<string, object> ret = MakeRequest("AGENTROLE", sendData);
428
429 if (ret == null)
430 return false;
431
432 if (!ret.ContainsKey("RESULT"))
433 return false;
434
435 if (ret["RESULT"].ToString().ToLower() != "true")
436 return false;
437
438 return true;
439 }
440
441 public bool RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
442 {
443 Dictionary<string, object> sendData = new Dictionary<string, object>();
444 sendData["AgentID"] = AgentID.ToString();
445 sendData["GroupID"] = GroupID.ToString();
446 sendData["RoleID"] = RoleID.ToString();
447 sendData["RequestingAgentID"] = RequestingAgentID;
448 sendData["OP"] = "DELETE";
449
450 Dictionary<string, object> ret = MakeRequest("AGENTROLE", sendData);
451
452 if (ret == null)
453 return false;
454
455 if (!ret.ContainsKey("RESULT"))
456 return false;
457
458 if (ret["RESULT"].ToString().ToLower() != "true")
459 return false;
460
461 return true;
462 }
463
464 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
465 {
466 List<GroupRolesData> roles = new List<GroupRolesData>();
467
468 Dictionary<string, object> sendData = new Dictionary<string, object>();
469 sendData["AgentID"] = AgentID.ToString();
470 sendData["GroupID"] = GroupID.ToString();
471 sendData["RequestingAgentID"] = RequestingAgentID;
472 Dictionary<string, object> ret = MakeRequest("GETAGENTROLES", sendData);
473
474 if (ret == null)
475 return roles;
476
477 if (!ret.ContainsKey("RESULT"))
478 return roles;
479
480 if (ret["RESULT"].ToString() == "NULL")
481 return roles;
482
483 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
484 {
485 GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v);
486 roles.Add(m);
487 }
488
489 return roles;
490 }
491
492 public GroupMembershipData SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
493 {
494 Dictionary<string, object> sendData = new Dictionary<string, object>();
495 sendData["AgentID"] = AgentID.ToString();
496 sendData["GroupID"] = GroupID.ToString();
497 sendData["RequestingAgentID"] = RequestingAgentID;
498 sendData["OP"] = "GROUP";
499
500 Dictionary<string, object> ret = MakeRequest("SETACTIVE", sendData);
501
502 if (ret == null)
503 return null;
504
505 if (!ret.ContainsKey("RESULT"))
506 return null;
507
508 if (ret["RESULT"].ToString() == "NULL")
509 return null;
510
511 return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]);
512 }
513
514 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
515 {
516 Dictionary<string, object> sendData = new Dictionary<string, object>();
517 sendData["AgentID"] = AgentID.ToString();
518 sendData["GroupID"] = GroupID.ToString();
519 sendData["RoleID"] = RoleID.ToString();
520 sendData["RequestingAgentID"] = RequestingAgentID;
521 sendData["OP"] = "ROLE";
522
523 MakeRequest("SETACTIVE", sendData);
524 }
525
526 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
527 {
528 Dictionary<string, object> sendData = new Dictionary<string, object>();
529 sendData["AgentID"] = AgentID.ToString();
530 sendData["GroupID"] = GroupID.ToString();
531 sendData["AcceptNotices"] = AcceptNotices.ToString();
532 sendData["ListInProfile"] = ListInProfile.ToString();
533 sendData["RequestingAgentID"] = RequestingAgentID;
534 MakeRequest("UPDATEMEMBERSHIP", sendData);
535 }
536
537 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
538 {
539 Dictionary<string, object> sendData = new Dictionary<string, object>();
540 sendData["InviteID"] = inviteID.ToString();
541 sendData["GroupID"] = groupID.ToString();
542 sendData["RoleID"] = roleID.ToString();
543 sendData["AgentID"] = agentID.ToString();
544 sendData["RequestingAgentID"] = RequestingAgentID;
545 sendData["OP"] = "ADD";
546
547 Dictionary<string, object> ret = MakeRequest("INVITE", sendData);
548
549 if (ret == null)
550 return false;
551
552 if (!ret.ContainsKey("RESULT"))
553 return false;
554
555 if (ret["RESULT"].ToString().ToLower() != "true") // it may return "NULL"
556 return false;
557
558 return true;
559 }
560
561 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
562 {
563 Dictionary<string, object> sendData = new Dictionary<string, object>();
564 sendData["InviteID"] = inviteID.ToString();
565 sendData["RequestingAgentID"] = RequestingAgentID;
566 sendData["OP"] = "GET";
567
568 Dictionary<string, object> ret = MakeRequest("INVITE", sendData);
569
570 if (ret == null)
571 return null;
572
573 if (!ret.ContainsKey("RESULT"))
574 return null;
575
576 if (ret["RESULT"].ToString() == "NULL")
577 return null;
578
579 return GroupsDataUtils.GroupInviteInfo((Dictionary<string, object>)ret["RESULT"]);
580 }
581
582 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
583 {
584 Dictionary<string, object> sendData = new Dictionary<string, object>();
585 sendData["InviteID"] = inviteID.ToString();
586 sendData["RequestingAgentID"] = RequestingAgentID;
587 sendData["OP"] = "DELETE";
588
589 MakeRequest("INVITE", sendData);
590 }
591
592 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
593 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
594 {
595 Dictionary<string, object> sendData = new Dictionary<string, object>();
596 sendData["GroupID"] = groupID.ToString();
597 sendData["NoticeID"] = noticeID.ToString();
598 sendData["FromName"] = GroupsDataUtils.Sanitize(fromName);
599 sendData["Subject"] = GroupsDataUtils.Sanitize(subject);
600 sendData["Message"] = GroupsDataUtils.Sanitize(message);
601 sendData["HasAttachment"] = hasAttachment.ToString();
602 if (hasAttachment)
603 {
604 sendData["AttachmentType"] = attType.ToString();
605 sendData["AttachmentName"] = attName.ToString();
606 sendData["AttachmentItemID"] = attItemID.ToString();
607 sendData["AttachmentOwnerID"] = attOwnerID;
608 }
609 sendData["RequestingAgentID"] = RequestingAgentID;
610
611 Dictionary<string, object> ret = MakeRequest("ADDNOTICE", sendData);
612
613 if (ret == null)
614 return false;
615
616 if (!ret.ContainsKey("RESULT"))
617 return false;
618
619 if (ret["RESULT"].ToString().ToLower() != "true")
620 return false;
621
622 return true;
623 }
624
625 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
626 {
627 Dictionary<string, object> sendData = new Dictionary<string, object>();
628 sendData["NoticeID"] = noticeID.ToString();
629 sendData["RequestingAgentID"] = RequestingAgentID;
630
631 Dictionary<string, object> ret = MakeRequest("GETNOTICES", sendData);
632
633 if (ret == null)
634 return null;
635
636 if (!ret.ContainsKey("RESULT"))
637 return null;
638
639 if (ret["RESULT"].ToString() == "NULL")
640 return null;
641
642 return GroupsDataUtils.GroupNoticeInfo((Dictionary<string, object>)ret["RESULT"]);
643 }
644
645 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
646 {
647 List<ExtendedGroupNoticeData> notices = new List<ExtendedGroupNoticeData>();
648
649 Dictionary<string, object> sendData = new Dictionary<string, object>();
650 sendData["GroupID"] = GroupID.ToString();
651 sendData["RequestingAgentID"] = RequestingAgentID;
652 Dictionary<string, object> ret = MakeRequest("GETNOTICES", sendData);
653
654 if (ret == null)
655 return notices;
656
657 if (!ret.ContainsKey("RESULT"))
658 return notices;
659
660 if (ret["RESULT"].ToString() == "NULL")
661 return notices;
662
663 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
664 {
665 ExtendedGroupNoticeData m = GroupsDataUtils.GroupNoticeData((Dictionary<string, object>)v);
666 notices.Add(m);
667 }
668
669 return notices;
670 }
671
672 #region Make Request
673
674 private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
675 {
676 sendData["METHOD"] = method;
677
678 string reply = string.Empty;
679 lock (m_Lock)
680 reply = SynchronousRestFormsRequester.MakeRequest("POST",
681 m_ServerURI + "groups",
682 ServerUtils.BuildQueryString(sendData),
683 m_Auth);
684
685 if (reply == string.Empty)
686 return null;
687
688 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
689 reply);
690
691 return replyData;
692 }
693
694 #endregion
695 }
696} \ No newline at end of file
diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs
new file mode 100644
index 0000000..d4739c6
--- /dev/null
+++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs
@@ -0,0 +1,408 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Threading;
33using System.Text;
34
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Server.Base;
39using OpenSim.Services.Interfaces;
40
41using OpenMetaverse;
42using Mono.Addins;
43using log4net;
44using Nini.Config;
45
46namespace OpenSim.Groups
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceRemoteConnectorModule")]
49 public class GroupsServiceRemoteConnectorModule : ISharedRegionModule, IGroupsServicesConnector
50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 private bool m_Enabled = false;
54 private GroupsServiceRemoteConnector m_GroupsService;
55 private IUserManagement m_UserManagement;
56 private List<Scene> m_Scenes;
57
58 private RemoteConnectorCacheWrapper m_CacheWrapper;
59
60 #region constructors
61 public GroupsServiceRemoteConnectorModule()
62 {
63 }
64
65 public GroupsServiceRemoteConnectorModule(IConfigSource config, IUserManagement uman)
66 {
67 Init(config);
68 m_UserManagement = uman;
69 m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement);
70
71 }
72 #endregion
73
74 private void Init(IConfigSource config)
75 {
76 m_GroupsService = new GroupsServiceRemoteConnector(config);
77 m_Scenes = new List<Scene>();
78
79 }
80
81 #region ISharedRegionModule
82
83 public void Initialise(IConfigSource config)
84 {
85 IConfig groupsConfig = config.Configs["Groups"];
86 if (groupsConfig == null)
87 return;
88
89 if ((groupsConfig.GetBoolean("Enabled", false) == false)
90 || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name))
91 {
92 return;
93 }
94
95 Init(config);
96
97 m_Enabled = true;
98 m_log.DebugFormat("[Groups.RemoteConnector]: Initializing {0}", this.Name);
99 }
100
101 public string Name
102 {
103 get { return "Groups Remote Service Connector"; }
104 }
105
106 public Type ReplaceableInterface
107 {
108 get { return null; }
109 }
110
111 public void AddRegion(Scene scene)
112 {
113 if (!m_Enabled)
114 return;
115
116 m_log.DebugFormat("[Groups.RemoteConnector]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName);
117 scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
118 m_Scenes.Add(scene);
119 }
120
121 public void RemoveRegion(Scene scene)
122 {
123 if (!m_Enabled)
124 return;
125
126 scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
127 m_Scenes.Remove(scene);
128 }
129
130 public void RegionLoaded(Scene scene)
131 {
132 if (!m_Enabled)
133 return;
134
135 if (m_UserManagement == null)
136 {
137 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
138 m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement);
139 }
140 }
141
142 public void PostInitialise()
143 {
144 }
145
146 public void Close()
147 {
148 }
149
150 #endregion
151
152 #region IGroupsServicesConnector
153
154 public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
155 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
156 {
157 m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name);
158 string r = string.Empty;
159
160 UUID groupID = m_CacheWrapper.CreateGroup(RequestingAgentID, delegate
161 {
162 return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID,
163 membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out r);
164 });
165
166 reason = r;
167 return groupID;
168 }
169
170 public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
171 bool openEnrollment, bool allowPublish, bool maturePublish, out string reason)
172 {
173 string r = string.Empty;
174
175 bool success = m_CacheWrapper.UpdateGroup(groupID, delegate
176 {
177 return m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
178 });
179
180 reason = r;
181 return success;
182 }
183
184 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
185 {
186 if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty))
187 return null;
188
189 return m_CacheWrapper.GetGroupRecord(RequestingAgentID,GroupID,GroupName, delegate
190 {
191 return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName);
192 });
193 }
194
195 public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search)
196 {
197 // TODO!
198 return m_GroupsService.FindGroups(RequestingAgentID, search);
199 }
200
201 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
202 {
203 string agentFullID = AgentID;
204 m_log.DebugFormat("[Groups.RemoteConnector]: Add agent {0} to group {1}", agentFullID, GroupID);
205 string r = string.Empty;
206
207 bool success = m_CacheWrapper.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, delegate
208 {
209 return m_GroupsService.AddAgentToGroup(RequestingAgentID, agentFullID, GroupID, RoleID, token, out r);
210 });
211
212 reason = r;
213 return success;
214 }
215
216 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
217 {
218 m_CacheWrapper.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID, delegate
219 {
220 m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
221 });
222
223 }
224
225 public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
226 {
227 m_CacheWrapper.SetAgentActiveGroup(AgentID, delegate
228 {
229 return m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID);
230 });
231 }
232
233 public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
234 {
235 return m_CacheWrapper.GetAgentActiveMembership(AgentID, delegate
236 {
237 return m_GroupsService.GetMembership(RequestingAgentID, AgentID, UUID.Zero);
238 });
239 }
240
241 public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
242 {
243 return m_CacheWrapper.GetAgentGroupMembership(AgentID, GroupID, delegate
244 {
245 return m_GroupsService.GetMembership(RequestingAgentID, AgentID, GroupID);
246 });
247 }
248
249 public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
250 {
251 return m_CacheWrapper.GetAgentGroupMemberships(AgentID, delegate
252 {
253 return m_GroupsService.GetMemberships(RequestingAgentID, AgentID);
254 });
255 }
256
257
258 public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
259 {
260 return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate
261 {
262 return m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID);
263 });
264 }
265
266 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
267 {
268 string r = string.Empty;
269 bool success = m_CacheWrapper.AddGroupRole(groupID, roleID, description, name, powers, title, delegate
270 {
271 return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out r);
272 });
273
274 reason = r;
275 return success;
276 }
277
278 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
279 {
280 return m_CacheWrapper.UpdateGroupRole(groupID, roleID, name, description, title, powers, delegate
281 {
282 return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers);
283 });
284 }
285
286 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
287 {
288 m_CacheWrapper.RemoveGroupRole(RequestingAgentID, groupID, roleID, delegate
289 {
290 m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID);
291 });
292 }
293
294 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
295 {
296 return m_CacheWrapper.GetGroupRoles(RequestingAgentID, GroupID, delegate
297 {
298 return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID);
299 });
300 }
301
302 public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
303 {
304 return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, GroupID, delegate
305 {
306 return m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID);
307 });
308 }
309
310 public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
311 {
312 m_CacheWrapper.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate
313 {
314 return m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
315 });
316 }
317
318 public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
319 {
320 m_CacheWrapper.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate
321 {
322 return m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
323 });
324 }
325
326 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
327 {
328 return m_CacheWrapper.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID, delegate
329 {
330 return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID); ;
331 });
332 }
333
334 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
335 {
336 m_CacheWrapper.SetAgentActiveGroupRole(AgentID, GroupID, delegate
337 {
338 m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
339 });
340 }
341
342 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
343 {
344 m_CacheWrapper.UpdateMembership(AgentID, GroupID, AcceptNotices, ListInProfile, delegate
345 {
346 m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile);
347 });
348 }
349
350 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
351 {
352 return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID);
353 }
354
355 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
356 {
357 return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID);
358 }
359
360 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
361 {
362 m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID);
363 }
364
365 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
366 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
367 {
368 GroupNoticeInfo notice = new GroupNoticeInfo();
369 notice.GroupID = groupID;
370 notice.Message = message;
371 notice.noticeData = new ExtendedGroupNoticeData();
372 notice.noticeData.AttachmentItemID = attItemID;
373 notice.noticeData.AttachmentName = attName;
374 notice.noticeData.AttachmentOwnerID = attOwnerID.ToString();
375 notice.noticeData.AttachmentType = attType;
376 notice.noticeData.FromName = fromName;
377 notice.noticeData.HasAttachment = hasAttachment;
378 notice.noticeData.NoticeID = noticeID;
379 notice.noticeData.Subject = subject;
380 notice.noticeData.Timestamp = (uint)Util.UnixTimeSinceEpoch();
381
382 return m_CacheWrapper.AddGroupNotice(groupID, noticeID, notice, delegate
383 {
384 return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message,
385 hasAttachment, attType, attName, attItemID, attOwnerID);
386 });
387 }
388
389 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
390 {
391 return m_CacheWrapper.GetGroupNotice(noticeID, delegate
392 {
393 return m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID);
394 });
395 }
396
397 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
398 {
399 return m_CacheWrapper.GetGroupNotices(GroupID, delegate
400 {
401 return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID);
402 });
403 }
404
405 #endregion
406 }
407
408}
diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs
new file mode 100644
index 0000000..26e844e
--- /dev/null
+++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs
@@ -0,0 +1,816 @@
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 System.Xml;
32using System.Collections.Generic;
33using System.IO;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Framework.ServiceAuth;
40using OpenSim.Server.Handlers.Base;
41using log4net;
42using OpenMetaverse;
43
44namespace OpenSim.Groups
45{
46 public class GroupsServiceRobustConnector : ServiceConnector
47 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private GroupsService m_GroupsService;
51 private string m_ConfigName = "Groups";
52
53 public GroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
54 base(config, server, configName)
55 {
56 string key = string.Empty;
57 if (configName != String.Empty)
58 m_ConfigName = configName;
59
60 m_log.DebugFormat("[Groups.RobustConnector]: Starting with config name {0}", m_ConfigName);
61
62 IConfig groupsConfig = config.Configs[m_ConfigName];
63 if (groupsConfig != null)
64 {
65 key = groupsConfig.GetString("SecretKey", string.Empty);
66 m_log.DebugFormat("[Groups.RobustConnector]: Starting with secret key {0}", key);
67 }
68// else
69// m_log.DebugFormat("[Groups.RobustConnector]: Unable to find {0} section in configuration", m_ConfigName);
70
71 m_GroupsService = new GroupsService(config);
72
73 IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName);
74
75 server.AddStreamHandler(new GroupsServicePostHandler(m_GroupsService, auth));
76 }
77 }
78
79 public class GroupsServicePostHandler : BaseStreamHandler
80 {
81 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
82
83 private GroupsService m_GroupsService;
84
85 public GroupsServicePostHandler(GroupsService service, IServiceAuth auth) :
86 base("POST", "/groups", auth)
87 {
88 m_GroupsService = service;
89 }
90
91 protected override byte[] ProcessRequest(string path, Stream requestData,
92 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
93 {
94 StreamReader sr = new StreamReader(requestData);
95 string body = sr.ReadToEnd();
96 sr.Close();
97 body = body.Trim();
98
99 //m_log.DebugFormat("[XXX]: query String: {0}", body);
100
101 try
102 {
103 Dictionary<string, object> request =
104 ServerUtils.ParseQueryString(body);
105
106 if (!request.ContainsKey("METHOD"))
107 return FailureResult();
108
109 string method = request["METHOD"].ToString();
110 request.Remove("METHOD");
111
112// m_log.DebugFormat("[Groups.Handler]: {0}", method);
113 switch (method)
114 {
115 case "PUTGROUP":
116 return HandleAddOrUpdateGroup(request);
117 case "GETGROUP":
118 return HandleGetGroup(request);
119 case "ADDAGENTTOGROUP":
120 return HandleAddAgentToGroup(request);
121 case "REMOVEAGENTFROMGROUP":
122 return HandleRemoveAgentFromGroup(request);
123 case "GETMEMBERSHIP":
124 return HandleGetMembership(request);
125 case "GETGROUPMEMBERS":
126 return HandleGetGroupMembers(request);
127 case "PUTROLE":
128 return HandlePutRole(request);
129 case "REMOVEROLE":
130 return HandleRemoveRole(request);
131 case "GETGROUPROLES":
132 return HandleGetGroupRoles(request);
133 case "GETROLEMEMBERS":
134 return HandleGetRoleMembers(request);
135 case "AGENTROLE":
136 return HandleAgentRole(request);
137 case "GETAGENTROLES":
138 return HandleGetAgentRoles(request);
139 case "SETACTIVE":
140 return HandleSetActive(request);
141 case "UPDATEMEMBERSHIP":
142 return HandleUpdateMembership(request);
143 case "INVITE":
144 return HandleInvite(request);
145 case "ADDNOTICE":
146 return HandleAddNotice(request);
147 case "GETNOTICES":
148 return HandleGetNotices(request);
149 case "FINDGROUPS":
150 return HandleFindGroups(request);
151 }
152 m_log.DebugFormat("[GROUPS HANDLER]: unknown method request: {0}", method);
153 }
154 catch (Exception e)
155 {
156 m_log.Error(string.Format("[GROUPS HANDLER]: Exception {0} ", e.Message), e);
157 }
158
159 return FailureResult();
160 }
161
162 byte[] HandleAddOrUpdateGroup(Dictionary<string, object> request)
163 {
164 Dictionary<string, object> result = new Dictionary<string, object>();
165
166 ExtendedGroupRecord grec = GroupsDataUtils.GroupRecord(request);
167 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("OP"))
168 NullResult(result, "Bad network data");
169
170 else
171 {
172 string RequestingAgentID = request["RequestingAgentID"].ToString();
173 string reason = string.Empty;
174 string op = request["OP"].ToString();
175 if (op == "ADD")
176 {
177 grec.GroupID = m_GroupsService.CreateGroup(RequestingAgentID, grec.GroupName, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee,
178 grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish, grec.FounderID, out reason);
179
180 }
181 else if (op == "UPDATE")
182 {
183 m_GroupsService.UpdateGroup(RequestingAgentID, grec.GroupID, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee,
184 grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish);
185
186 }
187
188 if (grec.GroupID != UUID.Zero)
189 {
190 grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID);
191 if (grec == null)
192 NullResult(result, "Internal Error");
193 else
194 result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
195 }
196 else
197 NullResult(result, reason);
198 }
199
200 string xmlString = ServerUtils.BuildXmlResponse(result);
201
202 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
203 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
204 }
205
206 byte[] HandleGetGroup(Dictionary<string, object> request)
207 {
208 Dictionary<string, object> result = new Dictionary<string, object>();
209
210 if (!request.ContainsKey("RequestingAgentID"))
211 NullResult(result, "Bad network data");
212 else
213 {
214 string RequestingAgentID = request["RequestingAgentID"].ToString();
215 ExtendedGroupRecord grec = null;
216 if (request.ContainsKey("GroupID"))
217 {
218 UUID groupID = new UUID(request["GroupID"].ToString());
219 grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID);
220 }
221 else if (request.ContainsKey("Name"))
222 {
223 string name = request["Name"].ToString();
224 grec = m_GroupsService.GetGroupRecord(RequestingAgentID, name);
225 }
226
227 if (grec == null)
228 NullResult(result, "Group not found");
229 else
230 result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
231 }
232
233 string xmlString = ServerUtils.BuildXmlResponse(result);
234
235 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
236 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
237 }
238
239 byte[] HandleAddAgentToGroup(Dictionary<string, object> request)
240 {
241 Dictionary<string, object> result = new Dictionary<string, object>();
242
243 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") ||
244 !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID"))
245 NullResult(result, "Bad network data");
246 else
247 {
248 UUID groupID = new UUID(request["GroupID"].ToString());
249 UUID roleID = new UUID(request["RoleID"].ToString());
250 string agentID = request["AgentID"].ToString();
251 string requestingAgentID = request["RequestingAgentID"].ToString();
252 string token = string.Empty;
253 string reason = string.Empty;
254
255 if (request.ContainsKey("AccessToken"))
256 token = request["AccessToken"].ToString();
257
258 if (!m_GroupsService.AddAgentToGroup(requestingAgentID, agentID, groupID, roleID, token, out reason))
259 NullResult(result, reason);
260 else
261 {
262 GroupMembershipData membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID);
263 if (membership == null)
264 NullResult(result, "Internal error");
265 else
266 result["RESULT"] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)membership);
267 }
268 }
269
270 string xmlString = ServerUtils.BuildXmlResponse(result);
271
272 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
273 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
274 }
275
276 byte[] HandleRemoveAgentFromGroup(Dictionary<string, object> request)
277 {
278 Dictionary<string, object> result = new Dictionary<string, object>();
279
280 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID"))
281 NullResult(result, "Bad network data");
282 else
283 {
284 UUID groupID = new UUID(request["GroupID"].ToString());
285 string agentID = request["AgentID"].ToString();
286 string requestingAgentID = request["RequestingAgentID"].ToString();
287
288 if (!m_GroupsService.RemoveAgentFromGroup(requestingAgentID, agentID, groupID))
289 NullResult(result, string.Format("Insufficient permissions.", agentID));
290 else
291 result["RESULT"] = "true";
292 }
293
294 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
295 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
296 }
297
298 byte[] HandleGetMembership(Dictionary<string, object> request)
299 {
300 Dictionary<string, object> result = new Dictionary<string, object>();
301
302 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID"))
303 NullResult(result, "Bad network data");
304 else
305 {
306 string agentID = request["AgentID"].ToString();
307 UUID groupID = UUID.Zero;
308 if (request.ContainsKey("GroupID"))
309 groupID = new UUID(request["GroupID"].ToString());
310 string requestingAgentID = request["RequestingAgentID"].ToString();
311 bool all = request.ContainsKey("ALL");
312
313 if (!all)
314 {
315 ExtendedGroupMembershipData membership = null;
316 if (groupID == UUID.Zero)
317 {
318 membership = m_GroupsService.GetAgentActiveMembership(requestingAgentID, agentID);
319 }
320 else
321 {
322 membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID);
323 }
324
325 if (membership == null)
326 NullResult(result, "No such membership");
327 else
328 result["RESULT"] = GroupsDataUtils.GroupMembershipData(membership);
329 }
330 else
331 {
332 List<GroupMembershipData> memberships = m_GroupsService.GetAgentGroupMemberships(requestingAgentID, agentID);
333 if (memberships == null || (memberships != null && memberships.Count == 0))
334 {
335 NullResult(result, "No memberships");
336 }
337 else
338 {
339 Dictionary<string, object> dict = new Dictionary<string, object>();
340 int i = 0;
341 foreach (GroupMembershipData m in memberships)
342 dict["m-" + i++] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)m);
343
344 result["RESULT"] = dict;
345 }
346 }
347 }
348
349 string xmlString = ServerUtils.BuildXmlResponse(result);
350
351 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
352 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
353 }
354
355 byte[] HandleGetGroupMembers(Dictionary<string, object> request)
356 {
357 Dictionary<string, object> result = new Dictionary<string, object>();
358
359 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID"))
360 NullResult(result, "Bad network data");
361 else
362 {
363 UUID groupID = new UUID(request["GroupID"].ToString());
364 string requestingAgentID = request["RequestingAgentID"].ToString();
365
366 List<ExtendedGroupMembersData> members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID);
367 if (members == null || (members != null && members.Count == 0))
368 {
369 NullResult(result, "No members");
370 }
371 else
372 {
373 Dictionary<string, object> dict = new Dictionary<string, object>();
374 int i = 0;
375 foreach (ExtendedGroupMembersData m in members)
376 {
377 dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m);
378 }
379
380 result["RESULT"] = dict;
381 }
382 }
383
384 string xmlString = ServerUtils.BuildXmlResponse(result);
385
386 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
387 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
388 }
389
390 byte[] HandlePutRole(Dictionary<string, object> request)
391 {
392 Dictionary<string, object> result = new Dictionary<string, object>();
393
394 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") ||
395 !request.ContainsKey("Name") || !request.ContainsKey("Description") || !request.ContainsKey("Title") ||
396 !request.ContainsKey("Powers") || !request.ContainsKey("OP"))
397 NullResult(result, "Bad network data");
398
399 else
400 {
401 string op = request["OP"].ToString();
402 string reason = string.Empty;
403
404 bool success = false;
405 if (op == "ADD")
406 success = m_GroupsService.AddGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
407 new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(),
408 request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString()), out reason);
409
410 else if (op == "UPDATE")
411 success = m_GroupsService.UpdateGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
412 new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(),
413 request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString()));
414
415 result["RESULT"] = success.ToString();
416 }
417
418 string xmlString = ServerUtils.BuildXmlResponse(result);
419
420 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
421 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
422 }
423
424 byte[] HandleRemoveRole(Dictionary<string, object> request)
425 {
426 Dictionary<string, object> result = new Dictionary<string, object>();
427
428 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID"))
429 NullResult(result, "Bad network data");
430
431 else
432 {
433 m_GroupsService.RemoveGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
434 new UUID(request["RoleID"].ToString()));
435 result["RESULT"] = "true";
436 }
437
438 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
439 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
440 }
441
442 byte[] HandleGetGroupRoles(Dictionary<string, object> request)
443 {
444 Dictionary<string, object> result = new Dictionary<string, object>();
445
446 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID"))
447 NullResult(result, "Bad network data");
448 else
449 {
450 UUID groupID = new UUID(request["GroupID"].ToString());
451 string requestingAgentID = request["RequestingAgentID"].ToString();
452
453 List<GroupRolesData> roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID);
454 if (roles == null || (roles != null && roles.Count == 0))
455 {
456 NullResult(result, "No members");
457 }
458 else
459 {
460 Dictionary<string, object> dict = new Dictionary<string, object>();
461 int i = 0;
462 foreach (GroupRolesData r in roles)
463 dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r);
464
465 result["RESULT"] = dict;
466 }
467 }
468
469 string xmlString = ServerUtils.BuildXmlResponse(result);
470
471 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
472 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
473 }
474
475 byte[] HandleGetRoleMembers(Dictionary<string, object> request)
476 {
477 Dictionary<string, object> result = new Dictionary<string, object>();
478
479 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID"))
480 NullResult(result, "Bad network data");
481 else
482 {
483 UUID groupID = new UUID(request["GroupID"].ToString());
484 string requestingAgentID = request["RequestingAgentID"].ToString();
485
486 List<ExtendedGroupRoleMembersData> rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID);
487 if (rmembers == null || (rmembers != null && rmembers.Count == 0))
488 {
489 NullResult(result, "No members");
490 }
491 else
492 {
493 Dictionary<string, object> dict = new Dictionary<string, object>();
494 int i = 0;
495 foreach (ExtendedGroupRoleMembersData rm in rmembers)
496 dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm);
497
498 result["RESULT"] = dict;
499 }
500 }
501
502 string xmlString = ServerUtils.BuildXmlResponse(result);
503
504 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
505 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
506 }
507
508 byte[] HandleAgentRole(Dictionary<string, object> request)
509 {
510 Dictionary<string, object> result = new Dictionary<string, object>();
511
512 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") ||
513 !request.ContainsKey("AgentID") || !request.ContainsKey("OP"))
514 NullResult(result, "Bad network data");
515
516 else
517 {
518 string op = request["OP"].ToString();
519
520 bool success = false;
521 if (op == "ADD")
522 success = m_GroupsService.AddAgentToGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(),
523 new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()));
524
525 else if (op == "DELETE")
526 success = m_GroupsService.RemoveAgentFromGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(),
527 new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()));
528
529 result["RESULT"] = success.ToString();
530 }
531
532 string xmlString = ServerUtils.BuildXmlResponse(result);
533
534 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
535 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
536 }
537
538 byte[] HandleGetAgentRoles(Dictionary<string, object> request)
539 {
540 Dictionary<string, object> result = new Dictionary<string, object>();
541
542 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AgentID"))
543 NullResult(result, "Bad network data");
544 else
545 {
546 UUID groupID = new UUID(request["GroupID"].ToString());
547 string agentID = request["AgentID"].ToString();
548 string requestingAgentID = request["RequestingAgentID"].ToString();
549
550 List<GroupRolesData> roles = m_GroupsService.GetAgentGroupRoles(requestingAgentID, agentID, groupID);
551 if (roles == null || (roles != null && roles.Count == 0))
552 {
553 NullResult(result, "No members");
554 }
555 else
556 {
557 Dictionary<string, object> dict = new Dictionary<string, object>();
558 int i = 0;
559 foreach (GroupRolesData r in roles)
560 dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r);
561
562 result["RESULT"] = dict;
563 }
564 }
565
566 string xmlString = ServerUtils.BuildXmlResponse(result);
567
568 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
569 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
570 }
571
572 byte[] HandleSetActive(Dictionary<string, object> request)
573 {
574 Dictionary<string, object> result = new Dictionary<string, object>();
575
576 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") ||
577 !request.ContainsKey("AgentID") || !request.ContainsKey("OP"))
578 {
579 NullResult(result, "Bad network data");
580 string xmlString = ServerUtils.BuildXmlResponse(result);
581 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
582 }
583 else
584 {
585 string op = request["OP"].ToString();
586
587 if (op == "GROUP")
588 {
589 ExtendedGroupMembershipData group = m_GroupsService.SetAgentActiveGroup(request["RequestingAgentID"].ToString(),
590 request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()));
591
592 if (group == null)
593 NullResult(result, "Internal error");
594 else
595 result["RESULT"] = GroupsDataUtils.GroupMembershipData(group);
596
597 string xmlString = ServerUtils.BuildXmlResponse(result);
598
599 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
600 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
601
602 }
603 else if (op == "ROLE" && request.ContainsKey("RoleID"))
604 {
605 m_GroupsService.SetAgentActiveGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(),
606 new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()));
607 result["RESULT"] = "true";
608 }
609
610 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
611 }
612
613 }
614
615 byte[] HandleUpdateMembership(Dictionary<string, object> request)
616 {
617 Dictionary<string, object> result = new Dictionary<string, object>();
618
619 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID") ||
620 !request.ContainsKey("AcceptNotices") || !request.ContainsKey("ListInProfile"))
621 NullResult(result, "Bad network data");
622
623 else
624 {
625 m_GroupsService.UpdateMembership(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()),
626 bool.Parse(request["AcceptNotices"].ToString()), bool.Parse(request["ListInProfile"].ToString()));
627
628 result["RESULT"] = "true";
629 }
630
631 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
632 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
633 }
634
635 byte[] HandleInvite(Dictionary<string, object> request)
636 {
637 Dictionary<string, object> result = new Dictionary<string, object>();
638
639 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("InviteID"))
640 {
641 NullResult(result, "Bad network data");
642 string xmlString = ServerUtils.BuildXmlResponse(result);
643 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
644 }
645 else
646 {
647 string op = request["OP"].ToString();
648
649 if (op == "ADD" && request.ContainsKey("GroupID") && request.ContainsKey("RoleID") && request.ContainsKey("AgentID"))
650 {
651 bool success = m_GroupsService.AddAgentToGroupInvite(request["RequestingAgentID"].ToString(),
652 new UUID(request["InviteID"].ToString()), new UUID(request["GroupID"].ToString()),
653 new UUID(request["RoleID"].ToString()), request["AgentID"].ToString());
654
655 result["RESULT"] = success.ToString();
656 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
657
658 }
659 else if (op == "DELETE")
660 {
661 m_GroupsService.RemoveAgentToGroupInvite(request["RequestingAgentID"].ToString(), new UUID(request["InviteID"].ToString()));
662 result["RESULT"] = "true";
663 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
664 }
665 else if (op == "GET")
666 {
667 GroupInviteInfo invite = m_GroupsService.GetAgentToGroupInvite(request["RequestingAgentID"].ToString(),
668 new UUID(request["InviteID"].ToString()));
669
670 if (invite != null)
671 result["RESULT"] = GroupsDataUtils.GroupInviteInfo(invite);
672 else
673 result["RESULT"] = "NULL";
674
675 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
676 }
677
678 NullResult(result, "Bad OP in request");
679 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
680 }
681
682 }
683
684 byte[] HandleAddNotice(Dictionary<string, object> request)
685 {
686 Dictionary<string, object> result = new Dictionary<string, object>();
687
688 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") ||
689 !request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") ||
690 !request.ContainsKey("HasAttachment"))
691 NullResult(result, "Bad network data");
692
693 else
694 {
695
696 bool hasAtt = bool.Parse(request["HasAttachment"].ToString());
697 byte attType = 0;
698 string attName = string.Empty;
699 string attOwner = string.Empty;
700 UUID attItem = UUID.Zero;
701 if (request.ContainsKey("AttachmentType"))
702 attType = byte.Parse(request["AttachmentType"].ToString());
703 if (request.ContainsKey("AttachmentName"))
704 attName = request["AttachmentName"].ToString();
705 if (request.ContainsKey("AttachmentItemID"))
706 attItem = new UUID(request["AttachmentItemID"].ToString());
707 if (request.ContainsKey("AttachmentOwnerID"))
708 attOwner = request["AttachmentOwnerID"].ToString();
709
710 bool success = m_GroupsService.AddGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
711 new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(),
712 request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner);
713
714 result["RESULT"] = success.ToString();
715 }
716
717 string xmlString = ServerUtils.BuildXmlResponse(result);
718
719 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
720 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
721 }
722
723 byte[] HandleGetNotices(Dictionary<string, object> request)
724 {
725 Dictionary<string, object> result = new Dictionary<string, object>();
726
727 if (!request.ContainsKey("RequestingAgentID"))
728 NullResult(result, "Bad network data");
729
730 else if (request.ContainsKey("NoticeID")) // just one
731 {
732 GroupNoticeInfo notice = m_GroupsService.GetGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["NoticeID"].ToString()));
733
734 if (notice == null)
735 NullResult(result, "NO such notice");
736 else
737 result["RESULT"] = GroupsDataUtils.GroupNoticeInfo(notice);
738
739 }
740 else if (request.ContainsKey("GroupID")) // all notices for group
741 {
742 List<ExtendedGroupNoticeData> notices = m_GroupsService.GetGroupNotices(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()));
743
744 if (notices == null || (notices != null && notices.Count == 0))
745 NullResult(result, "No notices");
746 else
747 {
748 Dictionary<string, object> dict = new Dictionary<string, object>();
749 int i = 0;
750 foreach (ExtendedGroupNoticeData n in notices)
751 dict["n-" + i++] = GroupsDataUtils.GroupNoticeData(n);
752
753 result["RESULT"] = dict;
754 }
755
756 }
757 else
758 NullResult(result, "Bad OP in request");
759
760 string xmlString = ServerUtils.BuildXmlResponse(result);
761 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
762 }
763
764 byte[] HandleFindGroups(Dictionary<string, object> request)
765 {
766 Dictionary<string, object> result = new Dictionary<string, object>();
767
768 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("Query"))
769 NullResult(result, "Bad network data");
770
771 List<DirGroupsReplyData> hits = m_GroupsService.FindGroups(request["RequestingAgentID"].ToString(), request["Query"].ToString());
772
773 if (hits == null || (hits != null && hits.Count == 0))
774 NullResult(result, "No hits");
775 else
776 {
777 Dictionary<string, object> dict = new Dictionary<string, object>();
778 int i = 0;
779 foreach (DirGroupsReplyData n in hits)
780 dict["n-" + i++] = GroupsDataUtils.DirGroupsReplyData(n);
781
782 result["RESULT"] = dict;
783 }
784
785
786 string xmlString = ServerUtils.BuildXmlResponse(result);
787 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
788 }
789
790
791 #region Helpers
792
793 private void NullResult(Dictionary<string, object> result, string reason)
794 {
795 result["RESULT"] = "NULL";
796 result["REASON"] = reason;
797 }
798
799 private byte[] FailureResult()
800 {
801 Dictionary<string, object> result = new Dictionary<string, object>();
802 NullResult(result, "Unknown method");
803 string xmlString = ServerUtils.BuildXmlResponse(result);
804 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
805 }
806
807 private byte[] FailureResult(string reason)
808 {
809 Dictionary<string, object> result = new Dictionary<string, object>();
810 NullResult(result, reason);
811 string xmlString = ServerUtils.BuildXmlResponse(result);
812 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
813 }
814 #endregion
815 }
816}
diff --git a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs
new file mode 100644
index 0000000..813f796
--- /dev/null
+++ b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs
@@ -0,0 +1,888 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Threading;
32
33using OpenSim.Framework;
34//using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Services.Interfaces;
36
37using OpenMetaverse;
38
39namespace OpenSim.Groups
40{
41 public delegate ExtendedGroupRecord GroupRecordDelegate();
42 public delegate GroupMembershipData GroupMembershipDelegate();
43 public delegate List<GroupMembershipData> GroupMembershipListDelegate();
44 public delegate List<ExtendedGroupMembersData> GroupMembersListDelegate();
45 public delegate List<GroupRolesData> GroupRolesListDelegate();
46 public delegate List<ExtendedGroupRoleMembersData> RoleMembersListDelegate();
47 public delegate GroupNoticeInfo NoticeDelegate();
48 public delegate List<ExtendedGroupNoticeData> NoticeListDelegate();
49 public delegate void VoidDelegate();
50 public delegate bool BooleanDelegate();
51
52 public class RemoteConnectorCacheWrapper
53 {
54 private ForeignImporter m_ForeignImporter;
55
56 private Dictionary<string, bool> m_ActiveRequests = new Dictionary<string, bool>();
57 private const int GROUPS_CACHE_TIMEOUT = 1 * 60; // 1 minutes
58
59 // This all important cache cahces objects of different types:
60 // group-<GroupID> or group-<Name> => ExtendedGroupRecord
61 // active-<AgentID> => GroupMembershipData
62 // membership-<AgentID>-<GroupID> => GroupMembershipData
63 // memberships-<AgentID> => List<GroupMembershipData>
64 // members-<RequestingAgentID>-<GroupID> => List<ExtendedGroupMembersData>
65 // role-<RoleID> => GroupRolesData
66 // roles-<GroupID> => List<GroupRolesData> ; all roles in the group
67 // roles-<GroupID>-<AgentID> => List<GroupRolesData> ; roles that the agent has
68 // rolemembers-<RequestingAgentID>-<GroupID> => List<ExtendedGroupRoleMembersData>
69 // notice-<noticeID> => GroupNoticeInfo
70 // notices-<GroupID> => List<ExtendedGroupNoticeData>
71 private ExpiringCache<string, object> m_Cache = new ExpiringCache<string, object>();
72
73 public RemoteConnectorCacheWrapper(IUserManagement uman)
74 {
75 m_ForeignImporter = new ForeignImporter(uman);
76 }
77
78 public UUID CreateGroup(UUID RequestingAgentID, GroupRecordDelegate d)
79 {
80 //m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name);
81 //reason = string.Empty;
82
83 //ExtendedGroupRecord group = m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID,
84 // membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason);
85 ExtendedGroupRecord group = d();
86
87 if (group == null)
88 return UUID.Zero;
89
90 if (group.GroupID != UUID.Zero)
91 lock (m_Cache)
92 {
93 m_Cache.Add("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT);
94 if (m_Cache.Contains("memberships-" + RequestingAgentID.ToString()))
95 m_Cache.Remove("memberships-" + RequestingAgentID.ToString());
96 }
97
98 return group.GroupID;
99 }
100
101 public bool UpdateGroup(UUID groupID, GroupRecordDelegate d)
102 {
103 //reason = string.Empty;
104 //ExtendedGroupRecord group = m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
105 ExtendedGroupRecord group = d();
106
107 if (group != null && group.GroupID != UUID.Zero)
108 lock (m_Cache)
109 m_Cache.AddOrUpdate("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT);
110 return true;
111 }
112
113 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, GroupRecordDelegate d)
114 {
115 //if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty))
116 // return null;
117
118 object group = null;
119 bool firstCall = false;
120 string cacheKey = "group-";
121 if (GroupID != UUID.Zero)
122 cacheKey += GroupID.ToString();
123 else
124 cacheKey += GroupName;
125
126 //m_log.DebugFormat("[XXX]: GetGroupRecord {0}", cacheKey);
127
128 while (true)
129 {
130 lock (m_Cache)
131 {
132 if (m_Cache.TryGetValue(cacheKey, out group))
133 {
134 //m_log.DebugFormat("[XXX]: GetGroupRecord {0} cached!", cacheKey);
135 return (ExtendedGroupRecord)group;
136 }
137
138 // not cached
139 if (!m_ActiveRequests.ContainsKey(cacheKey))
140 {
141 m_ActiveRequests.Add(cacheKey, true);
142 firstCall = true;
143 }
144 }
145
146 if (firstCall)
147 {
148 try
149 {
150 //group = m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName);
151 group = d();
152
153 lock (m_Cache)
154 {
155 m_Cache.AddOrUpdate(cacheKey, group, GROUPS_CACHE_TIMEOUT);
156 return (ExtendedGroupRecord)group;
157 }
158 }
159 finally
160 {
161 m_ActiveRequests.Remove(cacheKey);
162 }
163 }
164 else
165 Thread.Sleep(50);
166 }
167 }
168
169 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, GroupMembershipDelegate d)
170 {
171 GroupMembershipData membership = d();
172 if (membership == null)
173 return false;
174
175 lock (m_Cache)
176 {
177 // first, remove everything! add a user is a heavy-duty op
178 m_Cache.Clear();
179
180 m_Cache.AddOrUpdate("active-" + AgentID.ToString(), membership, GROUPS_CACHE_TIMEOUT);
181 m_Cache.AddOrUpdate("membership-" + AgentID.ToString() + "-" + GroupID.ToString(), membership, GROUPS_CACHE_TIMEOUT);
182 }
183
184
185 return true;
186 }
187
188 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, VoidDelegate d)
189 {
190 d();
191
192 lock (m_Cache)
193 {
194 string cacheKey = "active-" + AgentID.ToString();
195 if (m_Cache.Contains(cacheKey))
196 m_Cache.Remove(cacheKey);
197
198 cacheKey = "memberships-" + AgentID.ToString();
199 if (m_Cache.Contains(cacheKey))
200 m_Cache.Remove(cacheKey);
201
202 cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
203 if (m_Cache.Contains(cacheKey))
204 m_Cache.Remove(cacheKey);
205
206 cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
207 if (m_Cache.Contains(cacheKey))
208 m_Cache.Remove(cacheKey);
209
210 cacheKey = "roles-" + "-" + GroupID.ToString() + "-" + AgentID.ToString();
211 if (m_Cache.Contains(cacheKey))
212 m_Cache.Remove(cacheKey);
213 }
214 }
215
216 public void SetAgentActiveGroup(string AgentID, GroupMembershipDelegate d)
217 {
218 GroupMembershipData activeGroup = d();
219 string cacheKey = "active-" + AgentID.ToString();
220 lock (m_Cache)
221 if (m_Cache.Contains(cacheKey))
222 m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT);
223 }
224
225 public ExtendedGroupMembershipData GetAgentActiveMembership(string AgentID, GroupMembershipDelegate d)
226 {
227 object membership = null;
228 bool firstCall = false;
229 string cacheKey = "active-" + AgentID.ToString();
230
231 //m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0}", cacheKey);
232
233 while (true)
234 {
235 lock (m_Cache)
236 {
237 if (m_Cache.TryGetValue(cacheKey, out membership))
238 {
239 //m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0} cached!", cacheKey);
240 return (ExtendedGroupMembershipData)membership;
241 }
242
243 // not cached
244 if (!m_ActiveRequests.ContainsKey(cacheKey))
245 {
246 m_ActiveRequests.Add(cacheKey, true);
247 firstCall = true;
248 }
249 }
250
251 if (firstCall)
252 {
253 try
254 {
255 membership = d();
256
257 lock (m_Cache)
258 {
259 m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT);
260 return (ExtendedGroupMembershipData)membership;
261 }
262 }
263 finally
264 {
265 m_ActiveRequests.Remove(cacheKey);
266 }
267 }
268 else
269 Thread.Sleep(50);
270 }
271
272 }
273
274 public ExtendedGroupMembershipData GetAgentGroupMembership(string AgentID, UUID GroupID, GroupMembershipDelegate d)
275 {
276 object membership = null;
277 bool firstCall = false;
278 string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
279
280 //m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey);
281
282 while (true)
283 {
284 lock (m_Cache)
285 {
286 if (m_Cache.TryGetValue(cacheKey, out membership))
287 {
288 //m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey);
289 return (ExtendedGroupMembershipData)membership;
290 }
291
292 // not cached
293 if (!m_ActiveRequests.ContainsKey(cacheKey))
294 {
295 m_ActiveRequests.Add(cacheKey, true);
296 firstCall = true;
297 }
298 }
299
300 if (firstCall)
301 {
302 try
303 {
304 membership = d();
305 lock (m_Cache)
306 {
307 m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT);
308 return (ExtendedGroupMembershipData)membership;
309 }
310 }
311 finally
312 {
313 m_ActiveRequests.Remove(cacheKey);
314 }
315 }
316 else
317 Thread.Sleep(50);
318 }
319 }
320
321 public List<GroupMembershipData> GetAgentGroupMemberships(string AgentID, GroupMembershipListDelegate d)
322 {
323 object memberships = null;
324 bool firstCall = false;
325 string cacheKey = "memberships-" + AgentID.ToString();
326
327 //m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0}", cacheKey);
328
329 while (true)
330 {
331 lock (m_Cache)
332 {
333 if (m_Cache.TryGetValue(cacheKey, out memberships))
334 {
335 //m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0} cached!", cacheKey);
336 return (List<GroupMembershipData>)memberships;
337 }
338
339 // not cached
340 if (!m_ActiveRequests.ContainsKey(cacheKey))
341 {
342 m_ActiveRequests.Add(cacheKey, true);
343 firstCall = true;
344 }
345 }
346
347 if (firstCall)
348 {
349 try
350 {
351 memberships = d();
352 lock (m_Cache)
353 {
354 m_Cache.AddOrUpdate(cacheKey, memberships, GROUPS_CACHE_TIMEOUT);
355 return (List<GroupMembershipData>)memberships;
356 }
357 }
358 finally
359 {
360 m_ActiveRequests.Remove(cacheKey);
361 }
362 }
363 else
364 Thread.Sleep(50);
365 }
366 }
367
368 public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, GroupMembersListDelegate d)
369 {
370 object members = null;
371 bool firstCall = false;
372 // we need to key in also on the requester, because different ppl have different view privileges
373 string cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
374
375 //m_log.DebugFormat("[XXX]: GetGroupMembers {0}", cacheKey);
376
377 while (true)
378 {
379 lock (m_Cache)
380 {
381 if (m_Cache.TryGetValue(cacheKey, out members))
382 {
383 List<ExtendedGroupMembersData> xx = (List<ExtendedGroupMembersData>)members;
384 return xx.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData));
385 }
386
387 // not cached
388 if (!m_ActiveRequests.ContainsKey(cacheKey))
389 {
390 m_ActiveRequests.Add(cacheKey, true);
391 firstCall = true;
392 }
393 }
394
395 if (firstCall)
396 {
397 try
398 {
399 List<ExtendedGroupMembersData> _members = d();
400
401 if (_members != null && _members.Count > 0)
402 members = _members.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData));
403 else
404 members = new List<GroupMembersData>();
405
406 lock (m_Cache)
407 {
408 //m_Cache.AddOrUpdate(cacheKey, members, GROUPS_CACHE_TIMEOUT);
409 m_Cache.AddOrUpdate(cacheKey, _members, GROUPS_CACHE_TIMEOUT);
410
411 return (List<GroupMembersData>)members;
412 }
413 }
414 finally
415 {
416 m_ActiveRequests.Remove(cacheKey);
417 }
418 }
419 else
420 Thread.Sleep(50);
421 }
422 }
423
424 public bool AddGroupRole(UUID groupID, UUID roleID, string description, string name, ulong powers, string title, BooleanDelegate d)
425 {
426 if (d())
427 {
428 GroupRolesData role = new GroupRolesData();
429 role.Description = description;
430 role.Members = 0;
431 role.Name = name;
432 role.Powers = powers;
433 role.RoleID = roleID;
434 role.Title = title;
435
436 lock (m_Cache)
437 {
438 m_Cache.AddOrUpdate("role-" + roleID.ToString(), role, GROUPS_CACHE_TIMEOUT);
439
440 // also remove this list
441 if (m_Cache.Contains("roles-" + groupID.ToString()))
442 m_Cache.Remove("roles-" + groupID.ToString());
443
444 }
445
446 return true;
447 }
448
449 return false;
450 }
451
452 public bool UpdateGroupRole(UUID groupID, UUID roleID, string name, string description, string title, ulong powers, BooleanDelegate d)
453 {
454 if (d())
455 {
456 object role;
457 lock (m_Cache)
458 if (m_Cache.TryGetValue("role-" + roleID.ToString(), out role))
459 {
460 GroupRolesData r = (GroupRolesData)role;
461 r.Description = description;
462 r.Name = name;
463 r.Powers = powers;
464 r.Title = title;
465
466 m_Cache.Update("role-" + roleID.ToString(), r, GROUPS_CACHE_TIMEOUT);
467 }
468 return true;
469 }
470 else
471 {
472 lock (m_Cache)
473 {
474 if (m_Cache.Contains("role-" + roleID.ToString()))
475 m_Cache.Remove("role-" + roleID.ToString());
476
477 // also remove these lists, because they will have an outdated role
478 if (m_Cache.Contains("roles-" + groupID.ToString()))
479 m_Cache.Remove("roles-" + groupID.ToString());
480
481 }
482
483 return false;
484 }
485 }
486
487 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, VoidDelegate d)
488 {
489 d();
490
491 lock (m_Cache)
492 {
493 if (m_Cache.Contains("role-" + roleID.ToString()))
494 m_Cache.Remove("role-" + roleID.ToString());
495
496 // also remove the list, because it will have an removed role
497 if (m_Cache.Contains("roles-" + groupID.ToString()))
498 m_Cache.Remove("roles-" + groupID.ToString());
499
500 if (m_Cache.Contains("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString()))
501 m_Cache.Remove("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString());
502
503 if (m_Cache.Contains("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString()))
504 m_Cache.Remove("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString());
505 }
506 }
507
508 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, GroupRolesListDelegate d)
509 {
510 object roles = null;
511 bool firstCall = false;
512 string cacheKey = "roles-" + GroupID.ToString();
513
514 while (true)
515 {
516 lock (m_Cache)
517 {
518 if (m_Cache.TryGetValue(cacheKey, out roles))
519 return (List<GroupRolesData>)roles;
520
521 // not cached
522 if (!m_ActiveRequests.ContainsKey(cacheKey))
523 {
524 m_ActiveRequests.Add(cacheKey, true);
525 firstCall = true;
526 }
527 }
528
529 if (firstCall)
530 {
531 try
532 {
533 roles = d();
534 if (roles != null)
535 {
536 lock (m_Cache)
537 {
538 m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT);
539 return (List<GroupRolesData>)roles;
540 }
541 }
542 }
543 finally
544 {
545 m_ActiveRequests.Remove(cacheKey);
546 }
547 }
548 else
549 Thread.Sleep(50);
550 }
551 }
552
553 public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, RoleMembersListDelegate d)
554 {
555 object rmembers = null;
556 bool firstCall = false;
557 // we need to key in also on the requester, because different ppl have different view privileges
558 string cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
559
560 //m_log.DebugFormat("[XXX]: GetGroupRoleMembers {0}", cacheKey);
561 while (true)
562 {
563 lock (m_Cache)
564 {
565 if (m_Cache.TryGetValue(cacheKey, out rmembers))
566 {
567 List<ExtendedGroupRoleMembersData> xx = (List<ExtendedGroupRoleMembersData>)rmembers;
568 return xx.ConvertAll<GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData);
569 }
570
571 // not cached
572 if (!m_ActiveRequests.ContainsKey(cacheKey))
573 {
574 m_ActiveRequests.Add(cacheKey, true);
575 firstCall = true;
576 }
577 }
578
579 if (firstCall)
580 {
581 try
582 {
583 List<ExtendedGroupRoleMembersData> _rmembers = d();
584
585 if (_rmembers != null && _rmembers.Count > 0)
586 rmembers = _rmembers.ConvertAll<GroupRoleMembersData>(new Converter<ExtendedGroupRoleMembersData, GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData));
587 else
588 rmembers = new List<GroupRoleMembersData>();
589
590 lock (m_Cache)
591 {
592 // For some strange reason, when I cache the list of GroupRoleMembersData,
593 // it gets emptied out. The TryGet gets an empty list...
594 //m_Cache.AddOrUpdate(cacheKey, rmembers, GROUPS_CACHE_TIMEOUT);
595 // Caching the list of ExtendedGroupRoleMembersData doesn't show that issue
596 // I don't get it.
597 m_Cache.AddOrUpdate(cacheKey, _rmembers, GROUPS_CACHE_TIMEOUT);
598 return (List<GroupRoleMembersData>)rmembers;
599 }
600 }
601 finally
602 {
603 m_ActiveRequests.Remove(cacheKey);
604 }
605 }
606 else
607 Thread.Sleep(50);
608 }
609 }
610
611 public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d)
612 {
613 if (d())
614 {
615 lock (m_Cache)
616 {
617 // update the cached role
618 string cacheKey = "role-" + RoleID.ToString();
619 object obj;
620 if (m_Cache.TryGetValue(cacheKey, out obj))
621 {
622 GroupRolesData r = (GroupRolesData)obj;
623 r.Members++;
624 }
625
626 // add this agent to the list of role members
627 cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
628 if (m_Cache.TryGetValue(cacheKey, out obj))
629 {
630 try
631 {
632 // This may throw an exception, in which case the agentID is not a UUID but a full ID
633 // In that case, let's just remove the whoe things from the cache
634 UUID id = new UUID(AgentID);
635 List<ExtendedGroupRoleMembersData> xx = (List<ExtendedGroupRoleMembersData>)obj;
636 List<GroupRoleMembersData> rmlist = xx.ConvertAll<GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData);
637 GroupRoleMembersData rm = new GroupRoleMembersData();
638 rm.MemberID = id;
639 rm.RoleID = RoleID;
640 rmlist.Add(rm);
641 }
642 catch
643 {
644 m_Cache.Remove(cacheKey);
645 }
646 }
647
648 // Remove the cached info about this agent's roles
649 // because we don't have enough local info about the new role
650 cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString();
651 if (m_Cache.Contains(cacheKey))
652 m_Cache.Remove(cacheKey);
653
654 }
655 }
656 }
657
658 public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d)
659 {
660 if (d())
661 {
662 lock (m_Cache)
663 {
664 // update the cached role
665 string cacheKey = "role-" + RoleID.ToString();
666 object obj;
667 if (m_Cache.TryGetValue(cacheKey, out obj))
668 {
669 GroupRolesData r = (GroupRolesData)obj;
670 r.Members--;
671 }
672
673 cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString();
674 if (m_Cache.Contains(cacheKey))
675 m_Cache.Remove(cacheKey);
676
677 cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
678 if (m_Cache.Contains(cacheKey))
679 m_Cache.Remove(cacheKey);
680 }
681 }
682 }
683
684 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID, GroupRolesListDelegate d)
685 {
686 object roles = null;
687 bool firstCall = false;
688 string cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString();
689
690 //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey);
691
692 while (true)
693 {
694 lock (m_Cache)
695 {
696 if (m_Cache.TryGetValue(cacheKey, out roles))
697 {
698 //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0} cached!", cacheKey);
699 return (List<GroupRolesData>)roles;
700 }
701
702 // not cached
703 if (!m_ActiveRequests.ContainsKey(cacheKey))
704 {
705 m_ActiveRequests.Add(cacheKey, true);
706 firstCall = true;
707 }
708 }
709
710 if (firstCall)
711 {
712 try
713 {
714 roles = d();
715 lock (m_Cache)
716 {
717 m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT);
718 m_ActiveRequests.Remove(cacheKey);
719 return (List<GroupRolesData>)roles;
720 }
721 }
722 finally
723 {
724 m_ActiveRequests.Remove(cacheKey);
725 }
726 }
727 else
728 Thread.Sleep(50);
729 }
730 }
731
732 public void SetAgentActiveGroupRole(string AgentID, UUID GroupID, VoidDelegate d)
733 {
734 d();
735
736 lock (m_Cache)
737 {
738 // Invalidate cached info, because it has ActiveRoleID and Powers
739 string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
740 if (m_Cache.Contains(cacheKey))
741 m_Cache.Remove(cacheKey);
742
743 cacheKey = "memberships-" + AgentID.ToString();
744 if (m_Cache.Contains(cacheKey))
745 m_Cache.Remove(cacheKey);
746 }
747 }
748
749 public void UpdateMembership(string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile, VoidDelegate d)
750 {
751 d();
752
753 lock (m_Cache)
754 {
755 string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
756 if (m_Cache.Contains(cacheKey))
757 m_Cache.Remove(cacheKey);
758
759 cacheKey = "memberships-" + AgentID.ToString();
760 if (m_Cache.Contains(cacheKey))
761 m_Cache.Remove(cacheKey);
762
763 cacheKey = "active-" + AgentID.ToString();
764 object m = null;
765 if (m_Cache.TryGetValue(cacheKey, out m))
766 {
767 GroupMembershipData membership = (GroupMembershipData)m;
768 membership.ListInProfile = ListInProfile;
769 membership.AcceptNotices = AcceptNotices;
770 }
771 }
772 }
773
774 public bool AddGroupNotice(UUID groupID, UUID noticeID, GroupNoticeInfo notice, BooleanDelegate d)
775 {
776 if (d())
777 {
778 lock (m_Cache)
779 {
780 m_Cache.AddOrUpdate("notice-" + noticeID.ToString(), notice, GROUPS_CACHE_TIMEOUT);
781 string cacheKey = "notices-" + groupID.ToString();
782 if (m_Cache.Contains(cacheKey))
783 m_Cache.Remove(cacheKey);
784
785 }
786
787 return true;
788 }
789
790 return false;
791 }
792
793 public GroupNoticeInfo GetGroupNotice(UUID noticeID, NoticeDelegate d)
794 {
795 object notice = null;
796 bool firstCall = false;
797 string cacheKey = "notice-" + noticeID.ToString();
798
799 //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey);
800
801 while (true)
802 {
803 lock (m_Cache)
804 {
805 if (m_Cache.TryGetValue(cacheKey, out notice))
806 {
807 return (GroupNoticeInfo)notice;
808 }
809
810 // not cached
811 if (!m_ActiveRequests.ContainsKey(cacheKey))
812 {
813 m_ActiveRequests.Add(cacheKey, true);
814 firstCall = true;
815 }
816 }
817
818 if (firstCall)
819 {
820 try
821 {
822 GroupNoticeInfo _notice = d();
823
824 lock (m_Cache)
825 {
826 m_Cache.AddOrUpdate(cacheKey, _notice, GROUPS_CACHE_TIMEOUT);
827 return _notice;
828 }
829 }
830 finally
831 {
832 m_ActiveRequests.Remove(cacheKey);
833 }
834 }
835 else
836 Thread.Sleep(50);
837 }
838 }
839
840 public List<ExtendedGroupNoticeData> GetGroupNotices(UUID GroupID, NoticeListDelegate d)
841 {
842 object notices = null;
843 bool firstCall = false;
844 string cacheKey = "notices-" + GroupID.ToString();
845
846 //m_log.DebugFormat("[XXX]: GetGroupNotices {0}", cacheKey);
847
848 while (true)
849 {
850 lock (m_Cache)
851 {
852 if (m_Cache.TryGetValue(cacheKey, out notices))
853 {
854 //m_log.DebugFormat("[XXX]: GetGroupNotices {0} cached!", cacheKey);
855 return (List<ExtendedGroupNoticeData>)notices;
856 }
857
858 // not cached
859 if (!m_ActiveRequests.ContainsKey(cacheKey))
860 {
861 m_ActiveRequests.Add(cacheKey, true);
862 firstCall = true;
863 }
864 }
865
866 if (firstCall)
867 {
868 try
869 {
870 notices = d();
871
872 lock (m_Cache)
873 {
874 m_Cache.AddOrUpdate(cacheKey, notices, GROUPS_CACHE_TIMEOUT);
875 return (List<ExtendedGroupNoticeData>)notices;
876 }
877 }
878 finally
879 {
880 m_ActiveRequests.Remove(cacheKey);
881 }
882 }
883 else
884 Thread.Sleep(50);
885 }
886 }
887 }
888} \ No newline at end of file
diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs
new file mode 100644
index 0000000..07641ef
--- /dev/null
+++ b/OpenSim/Addons/Groups/Service/GroupsService.cs
@@ -0,0 +1,1060 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Timers;
32using log4net;
33using Nini.Config;
34
35using OpenMetaverse;
36using OpenSim.Data;
37using OpenSim.Framework;
38using OpenSim.Services.Interfaces;
39
40namespace OpenSim.Groups
41{
42 public class GroupsService : GroupsServiceBase
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 public const GroupPowers DefaultEveryonePowers = GroupPowers.AllowSetHome |
47 GroupPowers.Accountable |
48 GroupPowers.JoinChat |
49 GroupPowers.AllowVoiceChat |
50 GroupPowers.ReceiveNotices |
51 GroupPowers.StartProposal |
52 GroupPowers.VoteOnProposal;
53
54 public const GroupPowers OwnerPowers = GroupPowers.Accountable |
55 GroupPowers.AllowEditLand |
56 GroupPowers.AllowFly |
57 GroupPowers.AllowLandmark |
58 GroupPowers.AllowRez |
59 GroupPowers.AllowSetHome |
60 GroupPowers.AllowVoiceChat |
61 GroupPowers.AssignMember |
62 GroupPowers.AssignMemberLimited |
63 GroupPowers.ChangeActions |
64 GroupPowers.ChangeIdentity |
65 GroupPowers.ChangeMedia |
66 GroupPowers.ChangeOptions |
67 GroupPowers.CreateRole |
68 GroupPowers.DeedObject |
69 GroupPowers.DeleteRole |
70 GroupPowers.Eject |
71 GroupPowers.FindPlaces |
72 GroupPowers.HostEvent |
73 GroupPowers.Invite |
74 GroupPowers.JoinChat |
75 GroupPowers.LandChangeIdentity |
76 GroupPowers.LandDeed |
77 GroupPowers.LandDivideJoin |
78 GroupPowers.LandEdit |
79 GroupPowers.LandEjectAndFreeze |
80 GroupPowers.LandGardening |
81 GroupPowers.LandManageAllowed |
82 GroupPowers.LandManageBanned |
83 GroupPowers.LandManagePasses |
84 GroupPowers.LandOptions |
85 GroupPowers.LandRelease |
86 GroupPowers.LandSetSale |
87 GroupPowers.ModerateChat |
88 GroupPowers.ObjectManipulate |
89 GroupPowers.ObjectSetForSale |
90 GroupPowers.ReceiveNotices |
91 GroupPowers.RemoveMember |
92 GroupPowers.ReturnGroupOwned |
93 GroupPowers.ReturnGroupSet |
94 GroupPowers.ReturnNonGroup |
95 GroupPowers.RoleProperties |
96 GroupPowers.SendNotices |
97 GroupPowers.SetLandingPoint |
98 GroupPowers.StartProposal |
99 GroupPowers.VoteOnProposal;
100
101 #region Daily Cleanup
102
103 private Timer m_CleanupTimer;
104
105 public GroupsService(IConfigSource config, string configName)
106 : base(config, configName)
107 {
108 }
109
110 public GroupsService(IConfigSource config)
111 : this(config, string.Empty)
112 {
113 // Once a day
114 m_CleanupTimer = new Timer(24 * 60 * 60 * 1000);
115 m_CleanupTimer.AutoReset = true;
116 m_CleanupTimer.Elapsed += new ElapsedEventHandler(m_CleanupTimer_Elapsed);
117 m_CleanupTimer.Enabled = true;
118 m_CleanupTimer.Start();
119 }
120
121 private void m_CleanupTimer_Elapsed(object sender, ElapsedEventArgs e)
122 {
123 m_Database.DeleteOldNotices();
124 m_Database.DeleteOldInvites();
125 }
126
127 #endregion
128
129 public UUID CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
130 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
131 {
132 reason = string.Empty;
133
134 // Check if the group already exists
135 if (m_Database.RetrieveGroup(name) != null)
136 {
137 reason = "A group with that name already exists";
138 return UUID.Zero;
139 }
140
141 // Create the group
142 GroupData data = new GroupData();
143 data.GroupID = UUID.Random();
144 data.Data = new Dictionary<string, string>();
145 data.Data["Name"] = name;
146 data.Data["Charter"] = charter;
147 data.Data["InsigniaID"] = insigniaID.ToString();
148 data.Data["FounderID"] = founderID.ToString();
149 data.Data["MembershipFee"] = membershipFee.ToString();
150 data.Data["OpenEnrollment"] = openEnrollment ? "1" : "0";
151 data.Data["ShowInList"] = showInList ? "1" : "0";
152 data.Data["AllowPublish"] = allowPublish ? "1" : "0";
153 data.Data["MaturePublish"] = maturePublish ? "1" : "0";
154 UUID roleID = UUID.Random();
155 data.Data["OwnerRoleID"] = roleID.ToString();
156
157 if (!m_Database.StoreGroup(data))
158 return UUID.Zero;
159
160 // Create Everyone role
161 _AddOrUpdateGroupRole(RequestingAgentID, data.GroupID, UUID.Zero, "Everyone", "Everyone in the group", "Member of " + name, (ulong)DefaultEveryonePowers, true);
162
163 // Create Owner role
164 _AddOrUpdateGroupRole(RequestingAgentID, data.GroupID, roleID, "Owners", "Owners of the group", "Owner of " + name, (ulong)OwnerPowers, true);
165
166 // Add founder to group
167 _AddAgentToGroup(RequestingAgentID, founderID.ToString(), data.GroupID, roleID);
168
169 return data.GroupID;
170 }
171
172 public void UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
173 {
174 GroupData data = m_Database.RetrieveGroup(groupID);
175 if (data == null)
176 return;
177
178 // Check perms
179 if (!HasPower(RequestingAgentID, groupID, GroupPowers.ChangeActions))
180 {
181 m_log.DebugFormat("[Groups]: ({0}) Attempt at updating group {1} denied because of lack of permission", RequestingAgentID, groupID);
182 return;
183 }
184
185 data.GroupID = groupID;
186 data.Data["Charter"] = charter;
187 data.Data["ShowInList"] = showInList ? "1" : "0";
188 data.Data["InsigniaID"] = insigniaID.ToString();
189 data.Data["MembershipFee"] = membershipFee.ToString();
190 data.Data["OpenEnrollment"] = openEnrollment ? "1" : "0";
191 data.Data["AllowPublish"] = allowPublish ? "1" : "0";
192 data.Data["MaturePublish"] = maturePublish ? "1" : "0";
193
194 m_Database.StoreGroup(data);
195
196 }
197
198 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID)
199 {
200 GroupData data = m_Database.RetrieveGroup(GroupID);
201
202 return _GroupDataToRecord(data);
203 }
204
205 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, string GroupName)
206 {
207 GroupData data = m_Database.RetrieveGroup(GroupName);
208
209 return _GroupDataToRecord(data);
210 }
211
212 public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search)
213 {
214 List<DirGroupsReplyData> groups = new List<DirGroupsReplyData>();
215
216 GroupData[] data = m_Database.RetrieveGroups(search);
217
218 if (data != null && data.Length > 0)
219 {
220 foreach (GroupData d in data)
221 {
222 // Don't list group proxies
223 if (d.Data.ContainsKey("Location") && d.Data["Location"] != string.Empty)
224 continue;
225
226 DirGroupsReplyData g = new DirGroupsReplyData();
227 g.groupID = d.GroupID;
228
229 if (d.Data.ContainsKey("Name"))
230 g.groupName = d.Data["Name"];
231 else
232 m_log.DebugFormat("[Groups]: Key Name not found");
233
234 g.members = m_Database.MemberCount(d.GroupID);
235
236 groups.Add(g);
237 }
238 }
239
240 return groups;
241 }
242
243 public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
244 {
245 List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>();
246
247 GroupData group = m_Database.RetrieveGroup(GroupID);
248 if (group == null)
249 return members;
250
251 // Unfortunately this doesn't quite work on legacy group data because of a bug
252 // that's also being fixed here on CreateGroup. The OwnerRoleID sent to the DB was wrong.
253 // See how to find the ownerRoleID a few lines below.
254 UUID ownerRoleID = new UUID(group.Data["OwnerRoleID"]);
255
256 RoleData[] roles = m_Database.RetrieveRoles(GroupID);
257 if (roles == null)
258 // something wrong with this group
259 return members;
260 List<RoleData> rolesList = new List<RoleData>(roles);
261
262 // Let's find the "real" ownerRoleID
263 RoleData ownerRole = rolesList.Find(r => r.Data["Powers"] == ((long)OwnerPowers).ToString());
264 if (ownerRole != null)
265 ownerRoleID = ownerRole.RoleID;
266
267 // Check visibility?
268 // When we don't want to check visibility, we pass it "all" as the requestingAgentID
269 bool checkVisibility = !RequestingAgentID.Equals(UUID.Zero.ToString());
270
271 if (checkVisibility)
272 {
273 // Is the requester a member of the group?
274 bool isInGroup = false;
275 if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null)
276 isInGroup = true;
277
278 if (!isInGroup) // reduce the roles to the visible ones
279 rolesList = rolesList.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0);
280 }
281
282 MembershipData[] datas = m_Database.RetrieveMembers(GroupID);
283 if (datas == null || (datas != null && datas.Length == 0))
284 return members;
285
286 // OK, we have everything we need
287
288 foreach (MembershipData d in datas)
289 {
290 RoleMembershipData[] rolememberships = m_Database.RetrieveMemberRoles(GroupID, d.PrincipalID);
291 List<RoleMembershipData> rolemembershipsList = new List<RoleMembershipData>(rolememberships);
292
293 ExtendedGroupMembersData m = new ExtendedGroupMembersData();
294
295 // What's this person's current role in the group?
296 UUID selectedRole = new UUID(d.Data["SelectedRoleID"]);
297 RoleData selected = rolesList.Find(r => r.RoleID == selectedRole);
298
299 if (selected != null)
300 {
301 m.Title = selected.Data["Title"];
302 m.AgentPowers = UInt64.Parse(selected.Data["Powers"]);
303 }
304
305 m.AgentID = d.PrincipalID;
306 m.AcceptNotices = d.Data["AcceptNotices"] == "1" ? true : false;
307 m.Contribution = Int32.Parse(d.Data["Contribution"]);
308 m.ListInProfile = d.Data["ListInProfile"] == "1" ? true : false;
309
310 GridUserData gud = m_GridUserService.Get(d.PrincipalID);
311 if (gud != null)
312 {
313 if (bool.Parse(gud.Data["Online"]))
314 {
315 m.OnlineStatus = @"Online";
316 }
317 else
318 {
319 int unixtime = int.Parse(gud.Data["Login"]);
320 // The viewer is very picky about how these strings are formed. Eg. it will crash on malformed dates!
321 m.OnlineStatus = (unixtime == 0) ? @"unknown" : Util.ToDateTime(unixtime).ToString("MM/dd/yyyy");
322 }
323 }
324
325 // Is this person an owner of the group?
326 m.IsOwner = (rolemembershipsList.Find(r => r.RoleID == ownerRoleID) != null) ? true : false;
327
328 members.Add(m);
329 }
330
331 return members;
332 }
333
334 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
335 {
336 reason = string.Empty;
337 // check that the requesting agent has permissions to add role
338 if (!HasPower(RequestingAgentID, groupID, GroupPowers.CreateRole))
339 {
340 m_log.DebugFormat("[Groups]: ({0}) Attempt at creating role in group {1} denied because of lack of permission", RequestingAgentID, groupID);
341 reason = "Insufficient permission to create role";
342 return false;
343 }
344
345 return _AddOrUpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, true);
346
347 }
348
349 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
350 {
351 // check perms
352 if (!HasPower(RequestingAgentID, groupID, GroupPowers.ChangeActions))
353 {
354 m_log.DebugFormat("[Groups]: ({0}) Attempt at changing role in group {1} denied because of lack of permission", RequestingAgentID, groupID);
355 return false;
356 }
357
358 return _AddOrUpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, false);
359 }
360
361 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
362 {
363 // check perms
364 if (!HasPower(RequestingAgentID, groupID, GroupPowers.DeleteRole))
365 {
366 m_log.DebugFormat("[Groups]: ({0}) Attempt at deleting role from group {1} denied because of lack of permission", RequestingAgentID, groupID);
367 return;
368 }
369
370 // Can't delete Everyone and Owners roles
371 if (roleID == UUID.Zero)
372 {
373 m_log.DebugFormat("[Groups]: Attempt at deleting Everyone role from group {0} denied", groupID);
374 return;
375 }
376
377 GroupData group = m_Database.RetrieveGroup(groupID);
378 if (group == null)
379 {
380 m_log.DebugFormat("[Groups]: Attempt at deleting role from non-existing group {0}", groupID);
381 return;
382 }
383
384 if (roleID == new UUID(group.Data["OwnerRoleID"]))
385 {
386 m_log.DebugFormat("[Groups]: Attempt at deleting Owners role from group {0} denied", groupID);
387 return;
388 }
389
390 _RemoveGroupRole(groupID, roleID);
391 }
392
393 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
394 {
395 // TODO: check perms
396 return _GetGroupRoles(GroupID);
397 }
398
399 public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
400 {
401 // TODO: check perms
402
403 // Is the requester a member of the group?
404 bool isInGroup = false;
405 if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null)
406 isInGroup = true;
407
408 return _GetGroupRoleMembers(GroupID, isInGroup);
409 }
410
411 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
412 {
413 reason = string.Empty;
414
415 _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, token);
416
417 return true;
418 }
419
420 public bool RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
421 {
422 // check perms
423 if (RequestingAgentID != AgentID && !HasPower(RequestingAgentID, GroupID, GroupPowers.Eject))
424 return false;
425
426 _RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
427
428 return true;
429 }
430
431 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
432 {
433 // Check whether the invitee is already a member of the group
434 MembershipData m = m_Database.RetrieveMember(groupID, agentID);
435 if (m != null)
436 return false;
437
438 // Check permission to invite
439 if (!HasPower(RequestingAgentID, groupID, GroupPowers.Invite))
440 {
441 m_log.DebugFormat("[Groups]: ({0}) Attempt at inviting to group {1} denied because of lack of permission", RequestingAgentID, groupID);
442 return false;
443 }
444
445 // Check whether there are pending invitations and delete them
446 InvitationData invite = m_Database.RetrieveInvitation(groupID, agentID);
447 if (invite != null)
448 m_Database.DeleteInvite(invite.InviteID);
449
450 invite = new InvitationData();
451 invite.InviteID = inviteID;
452 invite.PrincipalID = agentID;
453 invite.GroupID = groupID;
454 invite.RoleID = roleID;
455 invite.Data = new Dictionary<string, string>();
456
457 return m_Database.StoreInvitation(invite);
458 }
459
460 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
461 {
462 InvitationData data = m_Database.RetrieveInvitation(inviteID);
463
464 if (data == null)
465 return null;
466
467 GroupInviteInfo inviteInfo = new GroupInviteInfo();
468 inviteInfo.AgentID = data.PrincipalID;
469 inviteInfo.GroupID = data.GroupID;
470 inviteInfo.InviteID = data.InviteID;
471 inviteInfo.RoleID = data.RoleID;
472
473 return inviteInfo;
474 }
475
476 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
477 {
478 m_Database.DeleteInvite(inviteID);
479 }
480
481 public bool AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
482 {
483 //if (!m_Database.CheckOwnerRole(RequestingAgentID, GroupID, RoleID))
484 // return;
485
486 // check permissions
487 bool limited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMemberLimited);
488 bool unlimited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMember) | IsOwner(RequestingAgentID, GroupID);
489 if (!limited || !unlimited)
490 {
491 m_log.DebugFormat("[Groups]: ({0}) Attempt at assigning {1} to role {2} denied because of lack of permission", RequestingAgentID, AgentID, RoleID);
492 return false;
493 }
494
495 // AssignMemberLimited means that the person can assign another person to the same roles that she has in the group
496 if (!unlimited && limited)
497 {
498 // check whether person's has this role
499 RoleMembershipData rolemembership = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID);
500 if (rolemembership == null)
501 {
502 m_log.DebugFormat("[Groups]: ({0}) Attempt at assigning {1} to role {2} denied because of limited permission", RequestingAgentID, AgentID, RoleID);
503 return false;
504 }
505 }
506
507 _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
508
509 return true;
510 }
511
512 public bool RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
513 {
514 // Don't remove from Everyone role!
515 if (RoleID == UUID.Zero)
516 return false;
517
518 // check permissions
519 bool unlimited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMember) || IsOwner(RequestingAgentID, GroupID);
520 if (!unlimited)
521 {
522 m_log.DebugFormat("[Groups]: ({0}) Attempt at removing {1} from role {2} denied because of lack of permission", RequestingAgentID, AgentID, RoleID);
523 return false;
524 }
525
526 RoleMembershipData rolemember = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID);
527
528 if (rolemember == null)
529 return false;
530
531 m_Database.DeleteRoleMember(rolemember);
532
533 // Find another role for this person
534 UUID newRoleID = UUID.Zero; // Everyone
535 RoleMembershipData[] rdata = m_Database.RetrieveMemberRoles(GroupID, AgentID);
536 if (rdata != null)
537 foreach (RoleMembershipData r in rdata)
538 {
539 if (r.RoleID != UUID.Zero)
540 {
541 newRoleID = r.RoleID;
542 break;
543 }
544 }
545
546 MembershipData member = m_Database.RetrieveMember(GroupID, AgentID);
547 if (member != null)
548 {
549 member.Data["SelectedRoleID"] = newRoleID.ToString();
550 m_Database.StoreMember(member);
551 }
552
553 return true;
554 }
555
556 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
557 {
558 List<GroupRolesData> roles = new List<GroupRolesData>();
559 // TODO: check permissions
560
561 RoleMembershipData[] data = m_Database.RetrieveMemberRoles(GroupID, AgentID);
562 if (data == null || (data != null && data.Length ==0))
563 return roles;
564
565 foreach (RoleMembershipData d in data)
566 {
567 RoleData rdata = m_Database.RetrieveRole(GroupID, d.RoleID);
568 if (rdata == null) // hippos
569 continue;
570
571 GroupRolesData r = new GroupRolesData();
572 r.Name = rdata.Data["Name"];
573 r.Powers = UInt64.Parse(rdata.Data["Powers"]);
574 r.RoleID = rdata.RoleID;
575 r.Title = rdata.Data["Title"];
576
577 roles.Add(r);
578 }
579
580 return roles;
581 }
582
583 public ExtendedGroupMembershipData SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
584 {
585 // TODO: check perms
586 PrincipalData principal = new PrincipalData();
587 principal.PrincipalID = AgentID;
588 principal.ActiveGroupID = GroupID;
589 m_Database.StorePrincipal(principal);
590
591 return GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID);
592 }
593
594 public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
595 {
596 // 1. get the principal data for the active group
597 PrincipalData principal = m_Database.RetrievePrincipal(AgentID);
598 if (principal == null)
599 return null;
600
601 return GetAgentGroupMembership(RequestingAgentID, AgentID, principal.ActiveGroupID);
602 }
603
604 public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
605 {
606 return GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID, null);
607 }
608
609 private ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID, MembershipData membership)
610 {
611 // 2. get the active group
612 GroupData group = m_Database.RetrieveGroup(GroupID);
613 if (group == null)
614 return null;
615
616 // 3. get the membership info if we don't have it already
617 if (membership == null)
618 {
619 membership = m_Database.RetrieveMember(group.GroupID, AgentID);
620 if (membership == null)
621 return null;
622 }
623
624 // 4. get the active role
625 UUID activeRoleID = new UUID(membership.Data["SelectedRoleID"]);
626 RoleData role = m_Database.RetrieveRole(group.GroupID, activeRoleID);
627
628 ExtendedGroupMembershipData data = new ExtendedGroupMembershipData();
629 data.AcceptNotices = membership.Data["AcceptNotices"] == "1" ? true : false;
630 data.AccessToken = membership.Data["AccessToken"];
631 data.Active = true;
632 data.ActiveRole = activeRoleID;
633 data.AllowPublish = group.Data["AllowPublish"] == "1" ? true : false;
634 data.Charter = group.Data["Charter"];
635 data.Contribution = Int32.Parse(membership.Data["Contribution"]);
636 data.FounderID = new UUID(group.Data["FounderID"]);
637 data.GroupID = new UUID(group.GroupID);
638 data.GroupName = group.Data["Name"];
639 data.GroupPicture = new UUID(group.Data["InsigniaID"]);
640 if (role != null)
641 {
642 data.GroupPowers = UInt64.Parse(role.Data["Powers"]);
643 data.GroupTitle = role.Data["Title"];
644 }
645 data.ListInProfile = membership.Data["ListInProfile"] == "1" ? true : false;
646 data.MaturePublish = group.Data["MaturePublish"] == "1" ? true : false;
647 data.MembershipFee = Int32.Parse(group.Data["MembershipFee"]);
648 data.OpenEnrollment = group.Data["OpenEnrollment"] == "1" ? true : false;
649 data.ShowInList = group.Data["ShowInList"] == "1" ? true : false;
650
651 return data;
652 }
653
654 public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
655 {
656 List<GroupMembershipData> memberships = new List<GroupMembershipData>();
657
658 // 1. Get all the groups that this person is a member of
659 MembershipData[] mdata = m_Database.RetrieveMemberships(AgentID);
660
661 if (mdata == null || (mdata != null && mdata.Length == 0))
662 return memberships;
663
664 foreach (MembershipData d in mdata)
665 {
666 GroupMembershipData gmember = GetAgentGroupMembership(RequestingAgentID, AgentID, d.GroupID, d);
667 if (gmember != null)
668 {
669 memberships.Add(gmember);
670 //m_log.DebugFormat("[XXX]: Member of {0} as {1}", gmember.GroupName, gmember.GroupTitle);
671 //Util.PrintCallStack();
672 }
673 }
674
675 return memberships;
676 }
677
678 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
679 {
680 MembershipData data = m_Database.RetrieveMember(GroupID, AgentID);
681 if (data == null)
682 return;
683
684 data.Data["SelectedRoleID"] = RoleID.ToString();
685 m_Database.StoreMember(data);
686 }
687
688 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
689 {
690 // TODO: check perms
691
692 MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID);
693 if (membership == null)
694 return;
695
696 membership.Data["AcceptNotices"] = AcceptNotices ? "1" : "0";
697 membership.Data["ListInProfile"] = ListInProfile ? "1" : "0";
698
699 m_Database.StoreMember(membership);
700 }
701
702 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
703 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
704 {
705 // Check perms
706 if (!HasPower(RequestingAgentID, groupID, GroupPowers.SendNotices))
707 {
708 m_log.DebugFormat("[Groups]: ({0}) Attempt at sending notice to group {1} denied because of lack of permission", RequestingAgentID, groupID);
709 return false;
710 }
711
712 return _AddNotice(groupID, noticeID, fromName, subject, message, hasAttachment, attType, attName, attItemID, attOwnerID);
713 }
714
715 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
716 {
717 NoticeData data = m_Database.RetrieveNotice(noticeID);
718
719 if (data == null)
720 return null;
721
722 return _NoticeDataToInfo(data);
723 }
724
725 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID groupID)
726 {
727 NoticeData[] data = m_Database.RetrieveNotices(groupID);
728 List<ExtendedGroupNoticeData> infos = new List<ExtendedGroupNoticeData>();
729
730 if (data == null || (data != null && data.Length == 0))
731 return infos;
732
733 foreach (NoticeData d in data)
734 {
735 ExtendedGroupNoticeData info = _NoticeDataToData(d);
736 infos.Add(info);
737 }
738
739 return infos;
740 }
741
742 public void ResetAgentGroupChatSessions(string agentID)
743 {
744 }
745
746 public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
747 {
748 return false;
749 }
750
751 public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
752 {
753 return false;
754 }
755
756 public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
757 {
758 }
759
760 public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
761 {
762 }
763
764 #region Actions without permission checks
765
766 protected void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
767 {
768 _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, string.Empty);
769 }
770
771 protected void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
772 {
773 // 1. Delete membership
774 m_Database.DeleteMember(GroupID, AgentID);
775
776 // 2. Remove from rolememberships
777 m_Database.DeleteMemberAllRoles(GroupID, AgentID);
778
779 // 3. if it was active group, inactivate it
780 PrincipalData principal = m_Database.RetrievePrincipal(AgentID);
781 if (principal != null && principal.ActiveGroupID == GroupID)
782 {
783 principal.ActiveGroupID = UUID.Zero;
784 m_Database.StorePrincipal(principal);
785 }
786 }
787
788 protected void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string accessToken)
789 {
790 // Check if it's already there
791 MembershipData data = m_Database.RetrieveMember(GroupID, AgentID);
792 if (data != null)
793 return;
794
795 // Add the membership
796 data = new MembershipData();
797 data.PrincipalID = AgentID;
798 data.GroupID = GroupID;
799 data.Data = new Dictionary<string, string>();
800 data.Data["SelectedRoleID"] = RoleID.ToString();
801 data.Data["Contribution"] = "0";
802 data.Data["ListInProfile"] = "1";
803 data.Data["AcceptNotices"] = "1";
804 data.Data["AccessToken"] = accessToken;
805
806 m_Database.StoreMember(data);
807
808 // Add principal to everyone role
809 _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, UUID.Zero);
810
811 // Add principal to role, if different from everyone role
812 if (RoleID != UUID.Zero)
813 _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
814
815 // Make thit this active group
816 PrincipalData pdata = new PrincipalData();
817 pdata.PrincipalID = AgentID;
818 pdata.ActiveGroupID = GroupID;
819 m_Database.StorePrincipal(pdata);
820
821 }
822
823 protected bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add)
824 {
825 RoleData data = m_Database.RetrieveRole(groupID, roleID);
826
827 if (add && data != null) // it already exists, can't create
828 {
829 m_log.DebugFormat("[Groups]: Group {0} already exists. Can't create it again", groupID);
830 return false;
831 }
832
833 if (!add && data == null) // it deosn't exist, can't update
834 {
835 m_log.DebugFormat("[Groups]: Group {0} doesn't exist. Can't update it", groupID);
836 return false;
837 }
838
839 if (add)
840 data = new RoleData();
841
842 data.GroupID = groupID;
843 data.RoleID = roleID;
844 data.Data = new Dictionary<string, string>();
845 data.Data["Name"] = name;
846 data.Data["Description"] = description;
847 data.Data["Title"] = title;
848 data.Data["Powers"] = powers.ToString();
849
850 return m_Database.StoreRole(data);
851 }
852
853 protected void _RemoveGroupRole(UUID groupID, UUID roleID)
854 {
855 m_Database.DeleteRole(groupID, roleID);
856 }
857
858 protected void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
859 {
860 RoleMembershipData data = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID);
861 if (data != null)
862 return;
863
864 data = new RoleMembershipData();
865 data.GroupID = GroupID;
866 data.PrincipalID = AgentID;
867 data.RoleID = RoleID;
868 m_Database.StoreRoleMember(data);
869
870 // Make it the SelectedRoleID
871 MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID);
872 if (membership == null)
873 {
874 m_log.DebugFormat("[Groups]: ({0}) No such member {0} in group {1}", AgentID, GroupID);
875 return;
876 }
877
878 membership.Data["SelectedRoleID"] = RoleID.ToString();
879 m_Database.StoreMember(membership);
880
881 }
882
883 protected List<GroupRolesData> _GetGroupRoles(UUID groupID)
884 {
885 List<GroupRolesData> roles = new List<GroupRolesData>();
886
887 RoleData[] data = m_Database.RetrieveRoles(groupID);
888
889 if (data == null || (data != null && data.Length == 0))
890 return roles;
891
892 foreach (RoleData d in data)
893 {
894 GroupRolesData r = new GroupRolesData();
895 r.Description = d.Data["Description"];
896 r.Members = m_Database.RoleMemberCount(groupID, d.RoleID);
897 r.Name = d.Data["Name"];
898 r.Powers = UInt64.Parse(d.Data["Powers"]);
899 r.RoleID = d.RoleID;
900 r.Title = d.Data["Title"];
901
902 roles.Add(r);
903 }
904
905 return roles;
906 }
907
908 protected List<ExtendedGroupRoleMembersData> _GetGroupRoleMembers(UUID GroupID, bool isInGroup)
909 {
910 List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
911
912 RoleData[] rdata = new RoleData[0];
913 if (!isInGroup)
914 {
915 rdata = m_Database.RetrieveRoles(GroupID);
916 if (rdata == null || (rdata != null && rdata.Length == 0))
917 return rmembers;
918 }
919 List<RoleData> rlist = new List<RoleData>(rdata);
920 if (!isInGroup)
921 rlist = rlist.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0);
922
923 RoleMembershipData[] data = m_Database.RetrieveRolesMembers(GroupID);
924
925 if (data == null || (data != null && data.Length == 0))
926 return rmembers;
927
928 foreach (RoleMembershipData d in data)
929 {
930 if (!isInGroup)
931 {
932 RoleData rd = rlist.Find(_r => _r.RoleID == d.RoleID); // visible role
933 if (rd == null)
934 continue;
935 }
936
937 ExtendedGroupRoleMembersData r = new ExtendedGroupRoleMembersData();
938 r.MemberID = d.PrincipalID;
939 r.RoleID = d.RoleID;
940
941 rmembers.Add(r);
942 }
943
944 return rmembers;
945 }
946
947 protected bool _AddNotice(UUID groupID, UUID noticeID, string fromName, string subject, string message,
948 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
949 {
950 NoticeData data = new NoticeData();
951 data.GroupID = groupID;
952 data.NoticeID = noticeID;
953 data.Data = new Dictionary<string, string>();
954 data.Data["FromName"] = fromName;
955 data.Data["Subject"] = subject;
956 data.Data["Message"] = message;
957 data.Data["HasAttachment"] = hasAttachment ? "1" : "0";
958 if (hasAttachment)
959 {
960 data.Data["AttachmentType"] = attType.ToString();
961 data.Data["AttachmentName"] = attName;
962 data.Data["AttachmentItemID"] = attItemID.ToString();
963 data.Data["AttachmentOwnerID"] = attOwnerID;
964 }
965 data.Data["TMStamp"] = ((uint)Util.UnixTimeSinceEpoch()).ToString();
966
967 return m_Database.StoreNotice(data);
968 }
969
970 #endregion
971
972 #region structure translations
973 ExtendedGroupRecord _GroupDataToRecord(GroupData data)
974 {
975 if (data == null)
976 return null;
977
978 ExtendedGroupRecord rec = new ExtendedGroupRecord();
979 rec.AllowPublish = data.Data["AllowPublish"] == "1" ? true : false;
980 rec.Charter = data.Data["Charter"];
981 rec.FounderID = new UUID(data.Data["FounderID"]);
982 rec.GroupID = data.GroupID;
983 rec.GroupName = data.Data["Name"];
984 rec.GroupPicture = new UUID(data.Data["InsigniaID"]);
985 rec.MaturePublish = data.Data["MaturePublish"] == "1" ? true : false;
986 rec.MembershipFee = Int32.Parse(data.Data["MembershipFee"]);
987 rec.OpenEnrollment = data.Data["OpenEnrollment"] == "1" ? true : false;
988 rec.OwnerRoleID = new UUID(data.Data["OwnerRoleID"]);
989 rec.ShowInList = data.Data["ShowInList"] == "1" ? true : false;
990 rec.ServiceLocation = data.Data["Location"];
991 rec.MemberCount = m_Database.MemberCount(data.GroupID);
992 rec.RoleCount = m_Database.RoleCount(data.GroupID);
993
994 return rec;
995 }
996
997 GroupNoticeInfo _NoticeDataToInfo(NoticeData data)
998 {
999 GroupNoticeInfo notice = new GroupNoticeInfo();
1000 notice.GroupID = data.GroupID;
1001 notice.Message = data.Data["Message"];
1002 notice.noticeData = _NoticeDataToData(data);
1003
1004 return notice;
1005 }
1006
1007 ExtendedGroupNoticeData _NoticeDataToData(NoticeData data)
1008 {
1009 ExtendedGroupNoticeData notice = new ExtendedGroupNoticeData();
1010 notice.FromName = data.Data["FromName"];
1011 notice.NoticeID = data.NoticeID;
1012 notice.Subject = data.Data["Subject"];
1013 notice.Timestamp = uint.Parse((string)data.Data["TMStamp"]);
1014 notice.HasAttachment = data.Data["HasAttachment"] == "1" ? true : false;
1015 if (notice.HasAttachment)
1016 {
1017 notice.AttachmentName = data.Data["AttachmentName"];
1018 notice.AttachmentItemID = new UUID(data.Data["AttachmentItemID"].ToString());
1019 notice.AttachmentType = byte.Parse(data.Data["AttachmentType"].ToString());
1020 notice.AttachmentOwnerID = data.Data["AttachmentOwnerID"].ToString();
1021 }
1022
1023
1024 return notice;
1025 }
1026
1027 #endregion
1028
1029 #region permissions
1030 private bool HasPower(string agentID, UUID groupID, GroupPowers power)
1031 {
1032 RoleMembershipData[] rmembership = m_Database.RetrieveMemberRoles(groupID, agentID);
1033 if (rmembership == null || (rmembership != null && rmembership.Length == 0))
1034 return false;
1035
1036 foreach (RoleMembershipData rdata in rmembership)
1037 {
1038 RoleData role = m_Database.RetrieveRole(groupID, rdata.RoleID);
1039 if ( (UInt64.Parse(role.Data["Powers"]) & (ulong)power) != 0 )
1040 return true;
1041 }
1042 return false;
1043 }
1044
1045 private bool IsOwner(string agentID, UUID groupID)
1046 {
1047 GroupData group = m_Database.RetrieveGroup(groupID);
1048 if (group == null)
1049 return false;
1050
1051 RoleMembershipData rmembership = m_Database.RetrieveRoleMember(groupID, new UUID(group.Data["OwnerRoleID"]), agentID);
1052 if (rmembership == null)
1053 return false;
1054
1055 return true;
1056 }
1057 #endregion
1058
1059 }
1060}
diff --git a/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs b/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs
new file mode 100644
index 0000000..8e237aa
--- /dev/null
+++ b/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs
@@ -0,0 +1,101 @@
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.Framework;
32using OpenSim.Data;
33using OpenSim.Services.Interfaces;
34using OpenSim.Services.Base;
35
36namespace OpenSim.Groups
37{
38 public class GroupsServiceBase : ServiceBase
39 {
40 protected IGroupsData m_Database = null;
41 protected IGridUserData m_GridUserService = null;
42
43 public GroupsServiceBase(IConfigSource config, string cName)
44 : base(config)
45 {
46 string dllName = String.Empty;
47 string connString = String.Empty;
48 string realm = "os_groups";
49 string usersRealm = "GridUser";
50 string configName = (cName == string.Empty) ? "Groups" : cName;
51
52 //
53 // Try reading the [DatabaseService] section, if it exists
54 //
55 IConfig dbConfig = config.Configs["DatabaseService"];
56 if (dbConfig != null)
57 {
58 if (dllName == String.Empty)
59 dllName = dbConfig.GetString("StorageProvider", String.Empty);
60 if (connString == String.Empty)
61 connString = dbConfig.GetString("ConnectionString", String.Empty);
62 }
63
64 //
65 // [Groups] section overrides [DatabaseService], if it exists
66 //
67 IConfig groupsConfig = config.Configs[configName];
68 if (groupsConfig != null)
69 {
70 dllName = groupsConfig.GetString("StorageProvider", dllName);
71 connString = groupsConfig.GetString("ConnectionString", connString);
72 realm = groupsConfig.GetString("Realm", realm);
73 }
74
75 //
76 // We tried, but this doesn't exist. We can't proceed.
77 //
78 if (dllName.Equals(String.Empty))
79 throw new Exception("No StorageProvider configured");
80
81 m_Database = LoadPlugin<IGroupsData>(dllName, new Object[] { connString, realm });
82 if (m_Database == null)
83 throw new Exception("Could not find a storage interface in the given module " + dllName);
84
85 //
86 // [GridUserService] section overrides [DatabaseService], if it exists
87 //
88 IConfig usersConfig = config.Configs["GridUserService"];
89 if (usersConfig != null)
90 {
91 dllName = usersConfig.GetString("StorageProvider", dllName);
92 connString = usersConfig.GetString("ConnectionString", connString);
93 usersRealm = usersConfig.GetString("Realm", usersRealm);
94 }
95
96 m_GridUserService = LoadPlugin<IGridUserData>(dllName, new Object[] { connString, usersRealm });
97 if (m_GridUserService == null)
98 throw new Exception("Could not find a storage inferface for the given users module " + dllName);
99 }
100 }
101}
diff --git a/OpenSim/Addons/Groups/Service/HGGroupsService.cs b/OpenSim/Addons/Groups/Service/HGGroupsService.cs
new file mode 100644
index 0000000..56e999b
--- /dev/null
+++ b/OpenSim/Addons/Groups/Service/HGGroupsService.cs
@@ -0,0 +1,361 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Timers;
32using log4net;
33using Nini.Config;
34
35using OpenMetaverse;
36using OpenSim.Data;
37using OpenSim.Framework;
38using OpenSim.Services.Interfaces;
39
40namespace OpenSim.Groups
41{
42 public class HGGroupsService : GroupsService
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 private IOfflineIMService m_OfflineIM;
47 private IUserAccountService m_UserAccounts;
48 private string m_HomeURI;
49
50 public HGGroupsService(IConfigSource config, IOfflineIMService im, IUserAccountService users, string homeURI)
51 : base(config, string.Empty)
52 {
53 m_OfflineIM = im;
54 m_UserAccounts = users;
55 m_HomeURI = homeURI;
56 if (!m_HomeURI.EndsWith("/"))
57 m_HomeURI += "/";
58 }
59
60
61 #region HG specific operations
62
63 public bool CreateGroupProxy(string RequestingAgentID, string agentID, string accessToken, UUID groupID, string serviceLocation, string name, out string reason)
64 {
65 reason = string.Empty;
66 Uri uri = null;
67 try
68 {
69 uri = new Uri(serviceLocation);
70 }
71 catch (UriFormatException)
72 {
73 reason = "Bad location for group proxy";
74 return false;
75 }
76
77 // Check if it already exists
78 GroupData grec = m_Database.RetrieveGroup(groupID);
79 if (grec == null ||
80 (grec != null && grec.Data["Location"] != string.Empty && grec.Data["Location"].ToLower() != serviceLocation.ToLower()))
81 {
82 // Create the group
83 grec = new GroupData();
84 grec.GroupID = groupID;
85 grec.Data = new Dictionary<string, string>();
86 grec.Data["Name"] = name + " @ " + uri.Authority;
87 grec.Data["Location"] = serviceLocation;
88 grec.Data["Charter"] = string.Empty;
89 grec.Data["InsigniaID"] = UUID.Zero.ToString();
90 grec.Data["FounderID"] = UUID.Zero.ToString();
91 grec.Data["MembershipFee"] = "0";
92 grec.Data["OpenEnrollment"] = "0";
93 grec.Data["ShowInList"] = "0";
94 grec.Data["AllowPublish"] = "0";
95 grec.Data["MaturePublish"] = "0";
96 grec.Data["OwnerRoleID"] = UUID.Zero.ToString();
97
98
99 if (!m_Database.StoreGroup(grec))
100 return false;
101 }
102
103 if (grec.Data["Location"] == string.Empty)
104 {
105 reason = "Cannot add proxy membership to non-proxy group";
106 return false;
107 }
108
109 UUID uid = UUID.Zero;
110 string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
111 Util.ParseUniversalUserIdentifier(RequestingAgentID, out uid, out url, out first, out last, out tmp);
112 string fromName = first + "." + last + "@" + url;
113
114 // Invite to group again
115 InviteToGroup(fromName, groupID, new UUID(agentID), grec.Data["Name"]);
116
117 // Stick the proxy membership in the DB already
118 // we'll delete it if the agent declines the invitation
119 MembershipData membership = new MembershipData();
120 membership.PrincipalID = agentID;
121 membership.GroupID = groupID;
122 membership.Data = new Dictionary<string, string>();
123 membership.Data["SelectedRoleID"] = UUID.Zero.ToString();
124 membership.Data["Contribution"] = "0";
125 membership.Data["ListInProfile"] = "1";
126 membership.Data["AcceptNotices"] = "1";
127 membership.Data["AccessToken"] = accessToken;
128
129 m_Database.StoreMember(membership);
130
131 return true;
132 }
133
134 public bool RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, string token)
135 {
136 // check the token
137 MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID);
138 if (membership != null)
139 {
140 if (token != string.Empty && token.Equals(membership.Data["AccessToken"]))
141 {
142 return RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
143 }
144 else
145 {
146 m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]);
147 return false;
148 }
149 }
150 else
151 {
152 m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", AgentID);
153 return false;
154 }
155 }
156
157 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string groupName, string token)
158 {
159 // check the token
160 if (!VerifyToken(GroupID, RequestingAgentID, token))
161 return null;
162
163 ExtendedGroupRecord grec;
164 if (GroupID == UUID.Zero)
165 grec = GetGroupRecord(RequestingAgentID, groupName);
166 else
167 grec = GetGroupRecord(RequestingAgentID, GroupID);
168
169 if (grec != null)
170 FillFounderUUI(grec);
171
172 return grec;
173 }
174
175 public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, string token)
176 {
177 if (!VerifyToken(GroupID, RequestingAgentID, token))
178 return new List<ExtendedGroupMembersData>();
179
180 List<ExtendedGroupMembersData> members = GetGroupMembers(RequestingAgentID, GroupID);
181
182 // convert UUIDs to UUIs
183 members.ForEach(delegate (ExtendedGroupMembersData m)
184 {
185 if (m.AgentID.ToString().Length == 36) // UUID
186 {
187 UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.AgentID));
188 if (account != null)
189 m.AgentID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI);
190 }
191 });
192
193 return members;
194 }
195
196 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, string token)
197 {
198 if (!VerifyToken(GroupID, RequestingAgentID, token))
199 return new List<GroupRolesData>();
200
201 return GetGroupRoles(RequestingAgentID, GroupID);
202 }
203
204 public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token)
205 {
206 if (!VerifyToken(GroupID, RequestingAgentID, token))
207 return new List<ExtendedGroupRoleMembersData>();
208
209 List<ExtendedGroupRoleMembersData> rolemembers = GetGroupRoleMembers(RequestingAgentID, GroupID);
210
211 // convert UUIDs to UUIs
212 rolemembers.ForEach(delegate(ExtendedGroupRoleMembersData m)
213 {
214 if (m.MemberID.ToString().Length == 36) // UUID
215 {
216 UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.MemberID));
217 if (account != null)
218 m.MemberID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI);
219 }
220 });
221
222 return rolemembers;
223 }
224
225 public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
226 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
227 {
228 // check that the group proxy exists
229 ExtendedGroupRecord grec = GetGroupRecord(RequestingAgentID, groupID);
230 if (grec == null)
231 {
232 m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to non-existent group proxy");
233 return false;
234 }
235
236 // check that the group is remote
237 if (grec.ServiceLocation == string.Empty)
238 {
239 m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to local (non-proxy) group");
240 return false;
241 }
242
243 // check that there isn't already a notice with the same ID
244 if (GetGroupNotice(RequestingAgentID, noticeID) != null)
245 {
246 m_log.DebugFormat("[Groups.HGGroupsService]: a notice with the same ID already exists", grec.ServiceLocation);
247 return false;
248 }
249
250 // This has good intentions (security) but it will potentially DDS the origin...
251 // We'll need to send a proof along with the message. Maybe encrypt the message
252 // using key pairs
253 //
254 //// check that the notice actually exists in the origin
255 //GroupsServiceHGConnector c = new GroupsServiceHGConnector(grec.ServiceLocation);
256 //if (!c.VerifyNotice(noticeID, groupID))
257 //{
258 // m_log.DebugFormat("[Groups.HGGroupsService]: notice does not exist at origin {0}", grec.ServiceLocation);
259 // return false;
260 //}
261
262 // ok, we're good!
263 return _AddNotice(groupID, noticeID, fromName, subject, message, hasAttachment, attType, attName, attItemID, attOwnerID);
264 }
265
266 public bool VerifyNotice(UUID noticeID, UUID groupID)
267 {
268 GroupNoticeInfo notice = GetGroupNotice(string.Empty, noticeID);
269
270 if (notice == null)
271 return false;
272
273 if (notice.GroupID != groupID)
274 return false;
275
276 return true;
277 }
278
279 #endregion
280
281 private void InviteToGroup(string fromName, UUID groupID, UUID invitedAgentID, string groupName)
282 {
283 // Todo: Security check, probably also want to send some kind of notification
284 UUID InviteID = UUID.Random();
285
286 if (AddAgentToGroupInvite(InviteID, groupID, invitedAgentID.ToString()))
287 {
288 Guid inviteUUID = InviteID.Guid;
289
290 GridInstantMessage msg = new GridInstantMessage();
291
292 msg.imSessionID = inviteUUID;
293
294 // msg.fromAgentID = agentID.Guid;
295 msg.fromAgentID = groupID.Guid;
296 msg.toAgentID = invitedAgentID.Guid;
297 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
298 msg.timestamp = 0;
299 msg.fromAgentName = fromName;
300 msg.message = string.Format("Please confirm your acceptance to join group {0}.", groupName);
301 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation;
302 msg.fromGroup = true;
303 msg.offline = (byte)0;
304 msg.ParentEstateID = 0;
305 msg.Position = Vector3.Zero;
306 msg.RegionID = UUID.Zero.Guid;
307 msg.binaryBucket = new byte[20];
308
309 string reason = string.Empty;
310 m_OfflineIM.StoreMessage(msg, out reason);
311
312 }
313 }
314
315 private bool AddAgentToGroupInvite(UUID inviteID, UUID groupID, string agentID)
316 {
317 // Check whether the invitee is already a member of the group
318 MembershipData m = m_Database.RetrieveMember(groupID, agentID);
319 if (m != null)
320 return false;
321
322 // Check whether there are pending invitations and delete them
323 InvitationData invite = m_Database.RetrieveInvitation(groupID, agentID);
324 if (invite != null)
325 m_Database.DeleteInvite(invite.InviteID);
326
327 invite = new InvitationData();
328 invite.InviteID = inviteID;
329 invite.PrincipalID = agentID;
330 invite.GroupID = groupID;
331 invite.RoleID = UUID.Zero;
332 invite.Data = new Dictionary<string, string>();
333
334 return m_Database.StoreInvitation(invite);
335 }
336
337 private void FillFounderUUI(ExtendedGroupRecord grec)
338 {
339 UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, grec.FounderID);
340 if (account != null)
341 grec.FounderUUI = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI);
342 }
343
344 private bool VerifyToken(UUID groupID, string agentID, string token)
345 {
346 // check the token
347 MembershipData membership = m_Database.RetrieveMember(groupID, agentID);
348 if (membership != null)
349 {
350 if (token != string.Empty && token.Equals(membership.Data["AccessToken"]))
351 return true;
352 else
353 m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]);
354 }
355 else
356 m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", agentID);
357
358 return false;
359 }
360 }
361}
diff --git a/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs
new file mode 100644
index 0000000..5340bcd
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs
@@ -0,0 +1,268 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using log4net;
31using Mono.Addins;
32using Nini.Config;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Servers;
36using OpenSim.Framework.Client;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40
41namespace OpenSim.OfflineIM
42{
43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineIMConnectorModule")]
44 public class OfflineIMRegionModule : ISharedRegionModule, IOfflineIMService
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private bool m_Enabled = false;
49 private List<Scene> m_SceneList = new List<Scene>();
50 IMessageTransferModule m_TransferModule = null;
51 private bool m_ForwardOfflineGroupMessages = true;
52
53 private IOfflineIMService m_OfflineIMService;
54
55 public void Initialise(IConfigSource config)
56 {
57 IConfig cnf = config.Configs["Messaging"];
58 if (cnf == null)
59 return;
60 if (cnf != null && cnf.GetString("OfflineMessageModule", string.Empty) != Name)
61 return;
62
63 m_Enabled = true;
64
65 string serviceLocation = cnf.GetString("OfflineMessageURL", string.Empty);
66 if (serviceLocation == string.Empty)
67 m_OfflineIMService = new OfflineIMService(config);
68 else
69 m_OfflineIMService = new OfflineIMServiceRemoteConnector(config);
70
71 m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages);
72 m_log.DebugFormat("[OfflineIM.V2]: Offline messages enabled by {0}", Name);
73 }
74
75 public void AddRegion(Scene scene)
76 {
77 if (!m_Enabled)
78 return;
79
80 scene.RegisterModuleInterface<IOfflineIMService>(this);
81 m_SceneList.Add(scene);
82 scene.EventManager.OnNewClient += OnNewClient;
83 }
84
85 public void RegionLoaded(Scene scene)
86 {
87 if (!m_Enabled)
88 return;
89
90 if (m_TransferModule == null)
91 {
92 m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
93 if (m_TransferModule == null)
94 {
95 scene.EventManager.OnNewClient -= OnNewClient;
96
97 m_SceneList.Clear();
98
99 m_log.Error("[OfflineIM.V2]: No message transfer module is enabled. Disabling offline messages");
100 }
101 m_TransferModule.OnUndeliveredMessage += UndeliveredMessage;
102 }
103 }
104
105 public void RemoveRegion(Scene scene)
106 {
107 if (!m_Enabled)
108 return;
109
110 m_SceneList.Remove(scene);
111 scene.EventManager.OnNewClient -= OnNewClient;
112 m_TransferModule.OnUndeliveredMessage -= UndeliveredMessage;
113
114 scene.ForEachClient(delegate(IClientAPI client)
115 {
116 client.OnRetrieveInstantMessages -= RetrieveInstantMessages;
117 client.OnMuteListRequest -= OnMuteListRequest;
118 });
119 }
120
121 public void PostInitialise()
122 {
123 }
124
125 public string Name
126 {
127 get { return "Offline Message Module V2"; }
128 }
129
130 public Type ReplaceableInterface
131 {
132 get { return null; }
133 }
134
135 public void Close()
136 {
137 m_SceneList.Clear();
138 }
139
140 private Scene FindScene(UUID agentID)
141 {
142 foreach (Scene s in m_SceneList)
143 {
144 ScenePresence presence = s.GetScenePresence(agentID);
145 if (presence != null && !presence.IsChildAgent)
146 return s;
147 }
148 return null;
149 }
150
151 private IClientAPI FindClient(UUID agentID)
152 {
153 foreach (Scene s in m_SceneList)
154 {
155 ScenePresence presence = s.GetScenePresence(agentID);
156 if (presence != null && !presence.IsChildAgent)
157 return presence.ControllingClient;
158 }
159 return null;
160 }
161
162 private void OnNewClient(IClientAPI client)
163 {
164 client.OnRetrieveInstantMessages += RetrieveInstantMessages;
165 client.OnMuteListRequest += OnMuteListRequest;
166 }
167
168 private void RetrieveInstantMessages(IClientAPI client)
169 {
170 m_log.DebugFormat("[OfflineIM.V2]: Retrieving stored messages for {0}", client.AgentId);
171
172 List<GridInstantMessage> msglist = m_OfflineIMService.GetMessages(client.AgentId);
173
174 if (msglist == null)
175 m_log.DebugFormat("[OfflineIM.V2]: WARNING null message list.");
176
177 foreach (GridInstantMessage im in msglist)
178 {
179 if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
180 // send it directly or else the item will be given twice
181 client.SendInstantMessage(im);
182 else
183 {
184 // Send through scene event manager so all modules get a chance
185 // to look at this message before it gets delivered.
186 //
187 // Needed for proper state management for stored group
188 // invitations
189 //
190 Scene s = FindScene(client.AgentId);
191 if (s != null)
192 s.EventManager.TriggerIncomingInstantMessage(im);
193 }
194 }
195 }
196
197 // Apparently this is needed in order for the viewer to request the IMs.
198 private void OnMuteListRequest(IClientAPI client, uint crc)
199 {
200 m_log.DebugFormat("[OfflineIM.V2] Got mute list request for crc {0}", crc);
201 string filename = "mutes" + client.AgentId.ToString();
202
203 IXfer xfer = client.Scene.RequestModuleInterface<IXfer>();
204 if (xfer != null)
205 {
206 xfer.AddNewFile(filename, new Byte[0]);
207 client.SendMuteListUpdate(filename);
208 }
209 }
210
211 private void UndeliveredMessage(GridInstantMessage im)
212 {
213 if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
214 im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
215 im.dialog != (byte)InstantMessageDialog.GroupNotice &&
216 im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
217 im.dialog != (byte)InstantMessageDialog.InventoryOffered)
218 {
219 return;
220 }
221
222 if (!m_ForwardOfflineGroupMessages)
223 {
224 if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
225 im.dialog == (byte)InstantMessageDialog.GroupInvitation)
226 return;
227 }
228
229 string reason = string.Empty;
230 bool success = m_OfflineIMService.StoreMessage(im, out reason);
231
232 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
233 {
234 IClientAPI client = FindClient(new UUID(im.fromAgentID));
235 if (client == null)
236 return;
237
238 client.SendInstantMessage(new GridInstantMessage(
239 null, new UUID(im.toAgentID),
240 "System", new UUID(im.fromAgentID),
241 (byte)InstantMessageDialog.MessageFromAgent,
242 "User is not logged in. " +
243 (success ? "Message saved." : "Message not saved: " + reason),
244 false, new Vector3()));
245 }
246 }
247
248 #region IOfflineIM
249
250 public List<GridInstantMessage> GetMessages(UUID principalID)
251 {
252 return m_OfflineIMService.GetMessages(principalID);
253 }
254
255 public bool StoreMessage(GridInstantMessage im, out string reason)
256 {
257 return m_OfflineIMService.StoreMessage(im, out reason);
258 }
259
260 public void DeleteMessages(UUID userID)
261 {
262 m_OfflineIMService.DeleteMessages(userID);
263 }
264
265 #endregion
266 }
267}
268
diff --git a/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0699660
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4using Mono.Addins;
5
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Addons.OfflineIM")]
10[assembly: AssemblyDescription("")]
11[assembly: AssemblyConfiguration("")]
12[assembly: AssemblyCompany("http://opensimulator.org")]
13[assembly: AssemblyProduct("OpenSim.Addons.OfflineIM")]
14[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")]
17
18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)]
22
23// The following GUID is for the ID of the typelib if this project is exposed to COM
24[assembly: Guid("a16a9905-4393-4872-9fca-4c81bedbd9f2")]
25
26// Version information for an assembly consists of the following four values:
27//
28// Major Version
29// Minor Version
30// Build Number
31// Revision
32//
33[assembly: AssemblyVersion("0.8.3.*")]
34
35[assembly: Addin("OpenSim.OfflineIM", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs
new file mode 100644
index 0000000..047b8be
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs
@@ -0,0 +1,171 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33
34using OpenSim.Framework;
35using OpenSim.Framework.ServiceAuth;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38
39using OpenMetaverse;
40using log4net;
41using Nini.Config;
42
43namespace OpenSim.OfflineIM
44{
45 public class OfflineIMServiceRemoteConnector : IOfflineIMService
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private string m_ServerURI = string.Empty;
50 private IServiceAuth m_Auth;
51 private object m_Lock = new object();
52
53 public OfflineIMServiceRemoteConnector(string url)
54 {
55 m_ServerURI = url;
56 m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0}", m_ServerURI);
57 }
58
59 public OfflineIMServiceRemoteConnector(IConfigSource config)
60 {
61 IConfig cnf = config.Configs["Messaging"];
62 if (cnf == null)
63 {
64 m_log.WarnFormat("[OfflineIM.V2.RemoteConnector]: Missing Messaging configuration");
65 return;
66 }
67
68 m_ServerURI = cnf.GetString("OfflineMessageURL", string.Empty);
69
70 /// This is from BaseServiceConnector
71 string authType = Util.GetConfigVarFromSections<string>(config, "AuthType", new string[] { "Network", "Messaging" }, "None");
72
73 switch (authType)
74 {
75 case "BasicHttpAuthentication":
76 m_Auth = new BasicHttpAuthentication(config, "Messaging");
77 break;
78 }
79 ///
80 m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0} with auth {1}",
81 m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString()));
82 }
83
84 #region IOfflineIMService
85 public List<GridInstantMessage> GetMessages(UUID principalID)
86 {
87 List<GridInstantMessage> ims = new List<GridInstantMessage>();
88
89 Dictionary<string, object> sendData = new Dictionary<string, object>();
90 sendData["PrincipalID"] = principalID;
91 Dictionary<string, object> ret = MakeRequest("GET", sendData);
92
93 if (ret == null)
94 return ims;
95
96 if (!ret.ContainsKey("RESULT"))
97 return ims;
98
99 string result = ret["RESULT"].ToString();
100 if (result == "NULL" || result.ToLower() == "false")
101 {
102 string reason = ret.ContainsKey("REASON") ? ret["REASON"].ToString() : "Unknown error";
103 m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: GetMessages for {0} failed: {1}", principalID, reason);
104 return ims;
105 }
106
107 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
108 {
109 GridInstantMessage m = OfflineIMDataUtils.GridInstantMessage((Dictionary<string, object>)v);
110 ims.Add(m);
111 }
112
113 return ims;
114 }
115
116 public bool StoreMessage(GridInstantMessage im, out string reason)
117 {
118 reason = string.Empty;
119 Dictionary<string, object> sendData = OfflineIMDataUtils.GridInstantMessage(im);
120
121 Dictionary<string, object> ret = MakeRequest("STORE", sendData);
122
123 if (ret == null)
124 {
125 reason = "Bad response from server";
126 return false;
127 }
128
129 string result = ret["RESULT"].ToString();
130 if (result == "NULL" || result.ToLower() == "false")
131 {
132 reason = ret.ContainsKey("REASON") ? ret["REASON"].ToString() : "Unknown error";
133 return false;
134 }
135
136 return true;
137 }
138
139 public void DeleteMessages(UUID userID)
140 {
141 Dictionary<string, object> sendData = new Dictionary<string, object>();
142 sendData["UserID"] = userID;
143
144 MakeRequest("DELETE", sendData);
145 }
146
147 #endregion
148
149
150 #region Make Request
151
152 private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
153 {
154 sendData["METHOD"] = method;
155
156 string reply = string.Empty;
157 lock (m_Lock)
158 reply = SynchronousRestFormsRequester.MakeRequest("POST",
159 m_ServerURI + "/offlineim",
160 ServerUtils.BuildQueryString(sendData),
161 m_Auth);
162
163 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
164 reply);
165
166 return replyData;
167 }
168 #endregion
169
170 }
171}
diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs
new file mode 100644
index 0000000..b3673da
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs
@@ -0,0 +1,223 @@
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 System.Xml;
32using System.Collections.Generic;
33using System.IO;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Framework.ServiceAuth;
40using OpenSim.Server.Handlers.Base;
41using log4net;
42using OpenMetaverse;
43
44namespace OpenSim.OfflineIM
45{
46 public class OfflineIMServiceRobustConnector : ServiceConnector
47 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private IOfflineIMService m_OfflineIMService;
51 private string m_ConfigName = "Messaging";
52
53 public OfflineIMServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
54 base(config, server, configName)
55 {
56 if (configName != String.Empty)
57 m_ConfigName = configName;
58
59 m_log.DebugFormat("[OfflineIM.V2.RobustConnector]: Starting with config name {0}", m_ConfigName);
60
61 m_OfflineIMService = new OfflineIMService(config);
62
63 IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName);
64
65 server.AddStreamHandler(new OfflineIMServicePostHandler(m_OfflineIMService, auth));
66 }
67 }
68
69 public class OfflineIMServicePostHandler : BaseStreamHandler
70 {
71 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
72
73 private IOfflineIMService m_OfflineIMService;
74
75 public OfflineIMServicePostHandler(IOfflineIMService service, IServiceAuth auth) :
76 base("POST", "/offlineim", auth)
77 {
78 m_OfflineIMService = service;
79 }
80
81 protected override byte[] ProcessRequest(string path, Stream requestData,
82 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
83 {
84 StreamReader sr = new StreamReader(requestData);
85 string body = sr.ReadToEnd();
86 sr.Close();
87 body = body.Trim();
88
89 //m_log.DebugFormat("[XXX]: query String: {0}", body);
90
91 try
92 {
93 Dictionary<string, object> request =
94 ServerUtils.ParseQueryString(body);
95
96 if (!request.ContainsKey("METHOD"))
97 return FailureResult();
98
99 string method = request["METHOD"].ToString();
100 request.Remove("METHOD");
101
102 switch (method)
103 {
104 case "GET":
105 return HandleGet(request);
106 case "STORE":
107 return HandleStore(request);
108 case "DELETE":
109 return HandleDelete(request);
110 }
111 m_log.DebugFormat("[OFFLINE IM HANDLER]: unknown method request: {0}", method);
112 }
113 catch (Exception e)
114 {
115 m_log.Error(string.Format("[OFFLINE IM HANDLER]: Exception {0} ", e.Message), e);
116 }
117
118 return FailureResult();
119 }
120
121 byte[] HandleStore(Dictionary<string, object> request)
122 {
123 Dictionary<string, object> result = new Dictionary<string, object>();
124
125 GridInstantMessage im = OfflineIMDataUtils.GridInstantMessage(request);
126
127 string reason = string.Empty;
128
129 bool success = m_OfflineIMService.StoreMessage(im, out reason);
130
131 result["RESULT"] = success.ToString();
132 if (!success)
133 result["REASON"] = reason;
134
135 string xmlString = ServerUtils.BuildXmlResponse(result);
136
137 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
138 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
139 }
140
141 byte[] HandleGet(Dictionary<string, object> request)
142 {
143 Dictionary<string, object> result = new Dictionary<string, object>();
144
145 if (!request.ContainsKey("PrincipalID"))
146 NullResult(result, "Bad network data");
147 else
148 {
149 UUID principalID = new UUID(request["PrincipalID"].ToString());
150 List<GridInstantMessage> ims = m_OfflineIMService.GetMessages(principalID);
151
152 Dictionary<string, object> dict = new Dictionary<string, object>();
153 int i = 0;
154 foreach (GridInstantMessage m in ims)
155 dict["im-" + i++] = OfflineIMDataUtils.GridInstantMessage(m);
156
157 result["RESULT"] = dict;
158 }
159
160 string xmlString = ServerUtils.BuildXmlResponse(result);
161
162 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
163 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
164 }
165
166 byte[] HandleDelete(Dictionary<string, object> request)
167 {
168 if (!request.ContainsKey("UserID"))
169 {
170 return FailureResult();
171 }
172 else
173 {
174 UUID userID = new UUID(request["UserID"].ToString());
175 m_OfflineIMService.DeleteMessages(userID);
176
177 return SuccessResult();
178 }
179 }
180
181 #region Helpers
182
183 private void NullResult(Dictionary<string, object> result, string reason)
184 {
185 result["RESULT"] = "NULL";
186 result["REASON"] = reason;
187 }
188
189 private byte[] FailureResult()
190 {
191 return BoolResult(false);
192 }
193
194 private byte[] SuccessResult()
195 {
196 return BoolResult(true);
197 }
198
199 private byte[] BoolResult(bool value)
200 {
201 XmlDocument doc = new XmlDocument();
202
203 XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration,
204 "", "");
205
206 doc.AppendChild(xmlnode);
207
208 XmlElement rootElement = doc.CreateElement("", "ServerResponse",
209 "");
210
211 doc.AppendChild(rootElement);
212
213 XmlElement result = doc.CreateElement("", "RESULT", "");
214 result.AppendChild(doc.CreateTextNode(value.ToString()));
215
216 rootElement.AppendChild(result);
217
218 return Util.DocToBytes(doc);
219 }
220
221 #endregion
222 }
223}
diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs
new file mode 100644
index 0000000..02084ff
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs
@@ -0,0 +1,135 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Runtime.Serialization;
33using System.Text;
34using System.Timers;
35using System.Xml;
36using System.Xml.Serialization;
37using log4net;
38using Nini.Config;
39
40using OpenMetaverse;
41using OpenSim.Data;
42using OpenSim.Framework;
43using OpenSim.Services.Interfaces;
44
45namespace OpenSim.OfflineIM
46{
47 public class OfflineIMService : OfflineIMServiceBase, IOfflineIMService
48 {
49// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 private const int MAX_IM = 25;
51
52 private XmlSerializer m_serializer;
53 private static bool m_Initialized = false;
54
55 public OfflineIMService(IConfigSource config)
56 : base(config)
57 {
58 m_serializer = new XmlSerializer(typeof(GridInstantMessage));
59 if (!m_Initialized)
60 {
61 m_Database.DeleteOld();
62 m_Initialized = true;
63 }
64 }
65
66 public List<GridInstantMessage> GetMessages(UUID principalID)
67 {
68 List<GridInstantMessage> ims = new List<GridInstantMessage>();
69
70 OfflineIMData[] messages = m_Database.Get("PrincipalID", principalID.ToString());
71
72 if (messages == null || (messages != null && messages.Length == 0))
73 return ims;
74
75 foreach (OfflineIMData m in messages)
76 {
77 using (MemoryStream mstream = new MemoryStream(Encoding.UTF8.GetBytes(m.Data["Message"])))
78 {
79 GridInstantMessage im = (GridInstantMessage)m_serializer.Deserialize(mstream);
80 ims.Add(im);
81 }
82 }
83
84 // Then, delete them
85 m_Database.Delete("PrincipalID", principalID.ToString());
86
87 return ims;
88 }
89
90 public bool StoreMessage(GridInstantMessage im, out string reason)
91 {
92 reason = string.Empty;
93
94 // Check limits
95 UUID principalID = new UUID(im.toAgentID);
96 long count = m_Database.GetCount("PrincipalID", principalID.ToString());
97 if (count >= MAX_IM)
98 {
99 reason = "Number of offline IMs has maxed out";
100 return false;
101 }
102
103 string imXml;
104 using (MemoryStream mstream = new MemoryStream())
105 {
106 XmlWriterSettings settings = new XmlWriterSettings();
107 settings.Encoding = Util.UTF8NoBomEncoding;
108
109 using (XmlWriter writer = XmlWriter.Create(mstream, settings))
110 {
111 m_serializer.Serialize(writer, im);
112 writer.Flush();
113 }
114
115 imXml = Util.UTF8NoBomEncoding.GetString(mstream.ToArray());
116 }
117
118 OfflineIMData data = new OfflineIMData();
119 data.PrincipalID = principalID;
120 data.FromID = new UUID(im.fromAgentID);
121 data.Data = new Dictionary<string, string>();
122 data.Data["Message"] = imXml;
123
124 return m_Database.Store(data);
125
126 }
127
128 public void DeleteMessages(UUID userID)
129 {
130 m_Database.Delete("PrincipalID", userID.ToString());
131 m_Database.Delete("FromID", userID.ToString());
132 }
133
134 }
135}
diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs
new file mode 100644
index 0000000..3376be4
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs
@@ -0,0 +1,83 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Data;
33using OpenSim.Services.Interfaces;
34using OpenSim.Services.Base;
35
36namespace OpenSim.OfflineIM
37{
38 public class OfflineIMServiceBase : ServiceBase
39 {
40 protected IOfflineIMData m_Database = null;
41
42 public OfflineIMServiceBase(IConfigSource config)
43 : base(config)
44 {
45 string dllName = String.Empty;
46 string connString = String.Empty;
47 string realm = "im_offline";
48
49 //
50 // Try reading the [DatabaseService] section, if it exists
51 //
52 IConfig dbConfig = config.Configs["DatabaseService"];
53 if (dbConfig != null)
54 {
55 if (dllName == String.Empty)
56 dllName = dbConfig.GetString("StorageProvider", String.Empty);
57 if (connString == String.Empty)
58 connString = dbConfig.GetString("ConnectionString", String.Empty);
59 }
60
61 //
62 // [Messaging] section overrides [DatabaseService], if it exists
63 //
64 IConfig imConfig = config.Configs["Messaging"];
65 if (imConfig != null)
66 {
67 dllName = imConfig.GetString("StorageProvider", dllName);
68 connString = imConfig.GetString("ConnectionString", connString);
69 realm = imConfig.GetString("Realm", realm);
70 }
71
72 //
73 // We tried, but this doesn't exist. We can't proceed.
74 //
75 if (dllName.Equals(String.Empty))
76 throw new Exception("No StorageProvider configured");
77
78 m_Database = LoadPlugin<IOfflineIMData>(dllName, new Object[] { connString, realm });
79 if (m_Database == null)
80 throw new Exception("Could not find a storage interface in the given module " + dllName);
81 }
82 }
83}