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