aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Addons/Groups/Service/HGGroupsService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Addons/Groups/Service/HGGroupsService.cs')
-rw-r--r--OpenSim/Addons/Groups/Service/HGGroupsService.cs353
1 files changed, 353 insertions, 0 deletions
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}