OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
GroupsModule.cs
Go to the documentation of this file.
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 
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using System.Timers;
32 using log4net;
33 using Mono.Addins;
34 using Nini.Config;
35 using OpenMetaverse;
36 using OpenMetaverse.StructuredData;
37 using OpenSim.Framework;
38 using OpenSim.Region.Framework.Interfaces;
39 using OpenSim.Region.Framework.Scenes;
40 using OpenSim.Services.Interfaces;
42 
43 namespace OpenSim.Groups
44 {
45  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsModule")]
47  {
48  private static readonly ILog m_log =
49  LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 
51  private List<Scene> m_sceneList = new List<Scene>();
52 
53  private IMessageTransferModule m_msgTransferModule = null;
54 
55  private IGroupsServicesConnector m_groupData = null;
56  private IUserManagement m_UserManagement;
57 
58  // Configuration settings
59  private bool m_groupsEnabled = false;
60  private bool m_groupNoticesEnabled = true;
61  private bool m_debugEnabled = false;
62  private int m_levelGroupCreate = 0;
63 
64  #region Region Module interfaceBase Members
65 
66  public void Initialise(IConfigSource config)
67  {
68  IConfig groupsConfig = config.Configs["Groups"];
69 
70  if (groupsConfig == null)
71  {
72  // Do not run this module by default.
73  return;
74  }
75  else
76  {
77  m_groupsEnabled = groupsConfig.GetBoolean("Enabled", false);
78  if (!m_groupsEnabled)
79  {
80  return;
81  }
82 
83  if (groupsConfig.GetString("Module", "Default") != Name)
84  {
85  m_groupsEnabled = false;
86 
87  return;
88  }
89 
90  m_log.InfoFormat("[Groups]: Initializing {0}", this.Name);
91 
92  m_groupNoticesEnabled = groupsConfig.GetBoolean("NoticesEnabled", true);
93  m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", false);
94  m_levelGroupCreate = groupsConfig.GetInt("LevelGroupCreate", 0);
95  }
96  }
97 
98  public void AddRegion(Scene scene)
99  {
100  if (m_groupsEnabled)
101  {
102  scene.RegisterModuleInterface<IGroupsModule>(this);
103  scene.AddCommand(
104  "Debug",
105  this,
106  "debug groups verbose",
107  "debug groups verbose <true|false>",
108  "This setting turns on very verbose groups debugging",
109  HandleDebugGroupsVerbose);
110  }
111  }
112 
113  private void HandleDebugGroupsVerbose(object modules, string[] args)
114  {
115  if (args.Length < 4)
116  {
117  MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
118  return;
119  }
120 
121  bool verbose = false;
122  if (!bool.TryParse(args[3], out verbose))
123  {
124  MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
125  return;
126  }
127 
128  m_debugEnabled = verbose;
129 
130  MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled);
131  }
132 
133  public void RegionLoaded(Scene scene)
134  {
135  if (!m_groupsEnabled)
136  return;
137 
138  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
139 
140 
141  if (m_groupData == null)
142  {
143  m_groupData = scene.RequestModuleInterface<IGroupsServicesConnector>();
144 
145  // No Groups Service Connector, then nothing works...
146  if (m_groupData == null)
147  {
148  m_groupsEnabled = false;
149  m_log.Error("[Groups]: Could not get IGroupsServicesConnector");
150  RemoveRegion(scene);
151  return;
152  }
153  }
154 
155  if (m_msgTransferModule == null)
156  {
157  m_msgTransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
158 
159  // No message transfer module, no notices, group invites, rejects, ejects, etc
160  if (m_msgTransferModule == null)
161  {
162  m_log.Warn("[Groups]: Could not get MessageTransferModule");
163  }
164  }
165 
166  if (m_UserManagement == null)
167  {
168  m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
169  if (m_UserManagement == null)
170  m_log.Warn("[Groups]: Could not get UserManagementModule");
171  }
172 
173  lock (m_sceneList)
174  {
175  m_sceneList.Add(scene);
176  }
177 
178  scene.EventManager.OnNewClient += OnNewClient;
179  scene.EventManager.OnMakeRootAgent += OnMakeRoot;
180  scene.EventManager.OnMakeChildAgent += OnMakeChild;
181  scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
182  // The InstantMessageModule itself doesn't do this,
183  // so lets see if things explode if we don't do it
184  // scene.EventManager.OnClientClosed += OnClientClosed;
185 
186  }
187 
188  public void RemoveRegion(Scene scene)
189  {
190  if (!m_groupsEnabled)
191  return;
192 
193  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
194 
195  scene.EventManager.OnNewClient -= OnNewClient;
196  scene.EventManager.OnMakeRootAgent -= OnMakeRoot;
197  scene.EventManager.OnMakeChildAgent -= OnMakeChild;
198  scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
199 
200  lock (m_sceneList)
201  {
202  m_sceneList.Remove(scene);
203  }
204  }
205 
206  public void Close()
207  {
208  if (!m_groupsEnabled)
209  return;
210 
211  if (m_debugEnabled) m_log.Debug("[Groups]: Shutting down Groups module.");
212  }
213 
214  public Type ReplaceableInterface
215  {
216  get { return null; }
217  }
218 
219  public string Name
220  {
221  get { return "Groups Module V2"; }
222  }
223 
224  public void PostInitialise()
225  {
226  // NoOp
227  }
228 
229  #endregion
230 
231  #region EventHandlers
232  private void OnNewClient(IClientAPI client)
233  {
234  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
235 
236  client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
237  client.OnRequestAvatarProperties += OnRequestAvatarProperties;
238  }
239 
240 
241  private void OnMakeRoot(ScenePresence sp)
242  {
243  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
244 
245  sp.ControllingClient.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
246  // Used for Notices and Group Invites/Accept/Reject
247  sp.ControllingClient.OnInstantMessage += OnInstantMessage;
248 
249  // we should send a DataUpdate here for compatibility,
250  // but this is a bad place and a bad thread to do it
251  // also current viewers do ignore it and ask later on a much nicer thread
252  }
253 
254  private void OnMakeChild(ScenePresence sp)
255  {
256  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
257 
258  sp.ControllingClient.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest;
259  // Used for Notices and Group Invites/Accept/Reject
260  sp.ControllingClient.OnInstantMessage -= OnInstantMessage;
261  }
262 
263  private void OnRequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
264  {
265  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
266 
267  GroupMembershipData[] avatarGroups = GetProfileListedGroupMemberships(remoteClient, avatarID);
268  remoteClient.SendAvatarGroupsReply(avatarID, avatarGroups);
269  }
270 
271  private void OnClientClosed(UUID AgentId, Scene scene)
272  {
273  if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
274  if (scene == null)
275  return;
276 
277  ScenePresence sp = scene.GetScenePresence(AgentId);
278  IClientAPI client = sp.ControllingClient;
279  if (client != null)
280  {
281  client.OnAgentDataUpdateRequest -= OnAgentDataUpdateRequest;
282  client.OnRequestAvatarProperties -= OnRequestAvatarProperties;
283  // make child possible not called?
284  client.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest;
285  client.OnInstantMessage -= OnInstantMessage;
286  }
287 
288  /*
289  lock (m_ActiveClients)
290  {
291  if (m_ActiveClients.ContainsKey(AgentId))
292  {
293  IClientAPI client = m_ActiveClients[AgentId];
294  client.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest;
295  client.OnAgentDataUpdateRequest -= OnAgentDataUpdateRequest;
296  client.OnDirFindQuery -= OnDirFindQuery;
297  client.OnInstantMessage -= OnInstantMessage;
298 
299  m_ActiveClients.Remove(AgentId);
300  }
301  else
302  {
303  if (m_debugEnabled) m_log.WarnFormat("[Groups]: Client closed that wasn't registered here.");
304  }
305 
306  }
307  */
308 
309  }
310 
311  private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID)
312  {
313  // this a private message for own agent only
314  if (dataForAgentID != GetRequestingAgentID(remoteClient))
315  return;
316 
317  SendAgentGroupDataUpdate(remoteClient, false);
318  // its a info request not a change, so nothing is sent to others
319  // they do get the group title with the avatar object update on arrivel to a region
320  }
321 
322  private void HandleUUIDGroupNameRequest(UUID GroupID, IClientAPI remoteClient)
323  {
324  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
325 
326  string GroupName;
327 
328  GroupRecord group = m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), GroupID, null);
329  if (group != null)
330  {
331  GroupName = group.GroupName;
332  }
333  else
334  {
335  GroupName = "Unknown";
336  }
337 
338  remoteClient.SendGroupNameReply(GroupID, GroupName);
339  }
340 
341  private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
342  {
343  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
344 
345  //m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog);
346  // Group invitations
347  if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline))
348  {
349  UUID inviteID = new UUID(im.imSessionID);
350  GroupInviteInfo inviteInfo = m_groupData.GetAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID);
351 
352  if (inviteInfo == null)
353  {
354  if (m_debugEnabled) m_log.WarnFormat("[Groups]: Received an Invite IM for an invite that does not exist {0}.", inviteID);
355  return;
356  }
357 
358  //m_log.DebugFormat("[XXX]: Invite is for Agent {0} to Group {1}.", inviteInfo.AgentID, inviteInfo.GroupID);
359 
360  UUID fromAgentID = new UUID(im.fromAgentID);
361  UUID invitee = UUID.Zero;
362  string tmp = string.Empty;
363  Util.ParseUniversalUserIdentifier(inviteInfo.AgentID, out invitee, out tmp, out tmp, out tmp, out tmp);
364  if ((inviteInfo != null) && (fromAgentID == invitee))
365  {
366  // Accept
367  if (im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept)
368  {
369  //m_log.DebugFormat("[XXX]: Received an accept invite notice.");
370 
371  // and the sessionid is the role
372  string reason = string.Empty;
373  if (!m_groupData.AddAgentToGroup(GetRequestingAgentIDStr(remoteClient), invitee.ToString(), inviteInfo.GroupID, inviteInfo.RoleID, string.Empty, out reason))
374  remoteClient.SendAgentAlertMessage("Unable to add you to the group: " + reason, false);
375  else
376  {
378  msg.imSessionID = UUID.Zero.Guid;
379  msg.fromAgentID = UUID.Zero.Guid;
380  msg.toAgentID = invitee.Guid;
381  msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
382  msg.fromAgentName = "Groups";
383  msg.message = string.Format("You have been added to the group.");
384  msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageBox;
385  msg.fromGroup = false;
386  msg.offline = (byte)0;
387  msg.ParentEstateID = 0;
388  msg.Position = Vector3.Zero;
389  msg.RegionID = UUID.Zero.Guid;
390  msg.binaryBucket = new byte[0];
391 
392  OutgoingInstantMessage(msg, invitee);
393 
394  IClientAPI client = GetActiveClient(invitee);
395  if (client != null)
396  SendDataUpdate(remoteClient, true);
397  }
398 
399  m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID);
400  }
401 
402  // Reject
403  if (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)
404  {
405  if (m_debugEnabled) m_log.DebugFormat("[Groups]: Received a reject invite notice.");
406  m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID);
407 
408  m_groupData.RemoveAgentFromGroup(GetRequestingAgentIDStr(remoteClient), inviteInfo.AgentID, inviteInfo.GroupID);
409  }
410  }
411  }
412 
413  // Group notices
414  if ((im.dialog == (byte)InstantMessageDialog.GroupNotice))
415  {
416  if (!m_groupNoticesEnabled)
417  {
418  return;
419  }
420 
421  UUID GroupID = new UUID(im.toAgentID);
422  if (m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), GroupID, null) != null)
423  {
424  UUID NoticeID = UUID.Random();
425  string Subject = im.message.Substring(0, im.message.IndexOf('|'));
426  string Message = im.message.Substring(Subject.Length + 1);
427 
428  InventoryItemBase item = null;
429  bool hasAttachment = false;
430 
431  if (im.binaryBucket.Length >= 1 && im.binaryBucket[0] > 0)
432  {
433  hasAttachment = true;
434  string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket);
435  binBucket = binBucket.Remove(0, 14).Trim();
436 
437  OSD binBucketOSD = OSDParser.DeserializeLLSDXml(binBucket);
438  if (binBucketOSD is OSDMap)
439  {
440  OSDMap binBucketMap = (OSDMap)binBucketOSD;
441 
442  UUID itemID = binBucketMap["item_id"].AsUUID();
443  UUID ownerID = binBucketMap["owner_id"].AsUUID();
444  item = new InventoryItemBase(itemID, ownerID);
445  item = m_sceneList[0].InventoryService.GetItem(item);
446  }
447  else
448  m_log.DebugFormat("[Groups]: Received OSD with unexpected type: {0}", binBucketOSD.GetType());
449  }
450 
451  if (m_groupData.AddGroupNotice(GetRequestingAgentIDStr(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message,
452  hasAttachment,
453  (byte)(item == null ? 0 : item.AssetType),
454  item == null ? null : item.Name,
455  item == null ? UUID.Zero : item.ID,
456  item == null ? UUID.Zero.ToString() : item.Owner.ToString()))
457  {
458  if (OnNewGroupNotice != null)
459  {
460  OnNewGroupNotice(GroupID, NoticeID);
461  }
462 
463  // Send notice out to everyone that wants notices
464  foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), GroupID))
465  {
466  if (member.AcceptNotices)
467  {
468  // Build notice IIM, one of reach, because the sending may be async
469  GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
470  msg.toAgentID = member.AgentID.Guid;
471  OutgoingInstantMessage(msg, member.AgentID);
472  }
473  }
474  }
475  }
476  }
477 
478  if (im.dialog == (byte)InstantMessageDialog.GroupNoticeInventoryAccepted)
479  {
480  if (im.binaryBucket.Length < 16) // Invalid
481  return;
482 
484 // UUID folderID = new UUID(im.binaryBucket, 0);
485  UUID noticeID = new UUID(im.imSessionID);
486 
487  GroupNoticeInfo notice = m_groupData.GetGroupNotice(remoteClient.AgentId.ToString(), noticeID);
488  if (notice != null)
489  {
490  UUID giver = new UUID(im.toAgentID);
491  string tmp = string.Empty;
492  Util.ParseUniversalUserIdentifier(notice.noticeData.AttachmentOwnerID, out giver, out tmp, out tmp, out tmp, out tmp);
493 
494  m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId);
495  string message;
496  InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId,
497  giver, notice.noticeData.AttachmentItemID, out message);
498 
499  if (itemCopy == null)
500  {
501  remoteClient.SendAgentAlertMessage(message, false);
502  return;
503  }
504 
505  remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0);
506  }
507  }
508 
509  // Interop, received special 210 code for ejecting a group member
510  // this only works within the comms servers domain, and won't work hypergrid
511  // TODO:FIXME: Use a presense server of some kind to find out where the
512  // client actually is, and try contacting that region directly to notify them,
513  // or provide the notification via xmlrpc update queue
514  if ((im.dialog == 210))
515  {
516  // This is sent from the region that the ejectee was ejected from
517  // if it's being delivered here, then the ejectee is here
518  // so we need to send local updates to the agent.
519 
520  UUID ejecteeID = new UUID(im.toAgentID);
521 
522  im.dialog = (byte)InstantMessageDialog.MessageFromAgent;
523  OutgoingInstantMessage(im, ejecteeID);
524 
525  IClientAPI ejectee = GetActiveClient(ejecteeID);
526  if (ejectee != null)
527  {
528  UUID groupID = new UUID(im.imSessionID);
529  ejectee.SendAgentDropGroup(groupID);
530  }
531  }
532  }
533 
534  private void OnGridInstantMessage(GridInstantMessage msg)
535  {
536  if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
537 
538  // Trigger the above event handler
539  OnInstantMessage(null, msg);
540 
541  // If a message from a group arrives here, it may need to be forwarded to a local client
542  if (msg.fromGroup == true)
543  {
544  switch (msg.dialog)
545  {
546  case (byte)InstantMessageDialog.GroupInvitation:
547  case (byte)InstantMessageDialog.GroupNotice:
548  UUID toAgentID = new UUID(msg.toAgentID);
549  IClientAPI localClient = GetActiveClient(toAgentID);
550  if (localClient != null)
551  {
552  localClient.SendInstantMessage(msg);
553  }
554  break;
555  }
556  }
557  }
558 
559  #endregion
560 
561  #region IGroupsModule Members
562 
564 
565  public GroupRecord GetGroupRecord(UUID GroupID)
566  {
567  return m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null);
568  }
569 
570  public GroupRecord GetGroupRecord(string name)
571  {
572  return m_groupData.GetGroupRecord(UUID.Zero.ToString(), UUID.Zero, name);
573  }
574 
575  public void ActivateGroup(IClientAPI remoteClient, UUID groupID)
576  {
577  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
578 
579  m_groupData.SetAgentActiveGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
580 
581  SendAgentGroupDataUpdate(remoteClient, true);
582  }
583 
587  public List<GroupTitlesData> GroupTitlesRequest(IClientAPI remoteClient, UUID groupID)
588  {
589  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
590 
591  List<GroupRolesData> agentRoles = m_groupData.GetAgentGroupRoles(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
592  GroupMembershipData agentMembership = m_groupData.GetAgentGroupMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
593 
594  List<GroupTitlesData> titles = new List<GroupTitlesData>();
595  foreach (GroupRolesData role in agentRoles)
596  {
597  GroupTitlesData title = new GroupTitlesData();
598  title.Name = role.Name;
599  if (agentMembership != null)
600  {
601  title.Selected = agentMembership.ActiveRole == role.RoleID;
602  }
603  title.UUID = role.RoleID;
604 
605  titles.Add(title);
606  }
607 
608  return titles;
609  }
610 
611  public List<GroupMembersData> GroupMembersRequest(IClientAPI remoteClient, UUID groupID)
612  {
613  if (m_debugEnabled)
614  m_log.DebugFormat(
615  "[Groups]: GroupMembersRequest called for {0} from client {1}", groupID, remoteClient.Name);
616 
617  List<GroupMembersData> data = m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), groupID);
618 
619  if (m_debugEnabled)
620  {
621  foreach (GroupMembersData member in data)
622  {
623  m_log.DebugFormat("[Groups]: Member({0}) - IsOwner({1})", member.AgentID, member.IsOwner);
624  }
625  }
626 
627  return data;
628  }
629 
630  public List<GroupRolesData> GroupRoleDataRequest(IClientAPI remoteClient, UUID groupID)
631  {
632  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
633 
634  List<GroupRolesData> data = m_groupData.GetGroupRoles(GetRequestingAgentIDStr(remoteClient), groupID);
635 
636  return data;
637  }
638 
639  public List<GroupRoleMembersData> GroupRoleMembersRequest(IClientAPI remoteClient, UUID groupID)
640  {
641  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
642 
643  List<GroupRoleMembersData> data = m_groupData.GetGroupRoleMembers(GetRequestingAgentIDStr(remoteClient), groupID);
644 
645  if (m_debugEnabled)
646  {
647  foreach (GroupRoleMembersData member in data)
648  {
649  m_log.DebugFormat("[Groups]: Member({0}) - Role({1})", member.MemberID, member.RoleID);
650  }
651  }
652  return data;
653  }
654 
655  public GroupProfileData GroupProfileRequest(IClientAPI remoteClient, UUID groupID)
656  {
657  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
658 
659  GroupProfileData profile = new GroupProfileData();
660 
661  // just to get the OwnerRole...
662  ExtendedGroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), groupID, string.Empty);
663  GroupMembershipData memberInfo = m_groupData.GetAgentGroupMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
664  if (groupInfo != null)
665  {
666  profile.AllowPublish = groupInfo.AllowPublish;
667  profile.Charter = groupInfo.Charter;
668  profile.FounderID = groupInfo.FounderID;
669  profile.GroupID = groupID;
670  profile.GroupMembershipCount = groupInfo.MemberCount;
671  profile.GroupRolesCount = groupInfo.RoleCount;
672  profile.InsigniaID = groupInfo.GroupPicture;
673  profile.MaturePublish = groupInfo.MaturePublish;
674  profile.MembershipFee = groupInfo.MembershipFee;
675  profile.Money = 0;
676  profile.Name = groupInfo.GroupName;
677  profile.OpenEnrollment = groupInfo.OpenEnrollment;
678  profile.OwnerRole = groupInfo.OwnerRoleID;
679  profile.ShowInList = groupInfo.ShowInList;
680  }
681  if (memberInfo != null)
682  {
683  profile.MemberTitle = memberInfo.GroupTitle;
684  profile.PowersMask = memberInfo.GroupPowers;
685  }
686 
687  return profile;
688  }
689 
690  public GroupMembershipData[] GetMembershipData(UUID agentID)
691  {
692  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
693 
694  return m_groupData.GetAgentGroupMemberships(UUID.Zero.ToString(), agentID.ToString()).ToArray();
695  }
696 
697  public GroupMembershipData GetMembershipData(UUID groupID, UUID agentID)
698  {
699  if (m_debugEnabled)
700  m_log.DebugFormat(
701  "[Groups]: {0} called with groupID={1}, agentID={2}",
702  System.Reflection.MethodBase.GetCurrentMethod().Name, groupID, agentID);
703 
704  return m_groupData.GetAgentGroupMembership(UUID.Zero.ToString(), agentID.ToString(), groupID);
705  }
706 
707  public void UpdateGroupInfo(IClientAPI remoteClient, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
708  {
709  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
710 
711  // Note: Permissions checking for modification rights is handled by the Groups Server/Service
712  string reason = string.Empty;
713  if (!m_groupData.UpdateGroup(GetRequestingAgentIDStr(remoteClient), groupID, charter, showInList, insigniaID, membershipFee,
714  openEnrollment, allowPublish, maturePublish, out reason))
715  remoteClient.SendAgentAlertMessage(reason, false);
716  }
717 
718  public void SetGroupAcceptNotices(IClientAPI remoteClient, UUID groupID, bool acceptNotices, bool listInProfile)
719  {
720  // Note: Permissions checking for modification rights is handled by the Groups Server/Service
721  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
722 
723  m_groupData.UpdateMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, acceptNotices, listInProfile);
724  }
725 
726  public UUID CreateGroup(IClientAPI remoteClient, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
727  {
728  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called in {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Scene.RegionInfo.RegionName);
729 
730  if (m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), UUID.Zero, name) != null)
731  {
732  remoteClient.SendCreateGroupReply(UUID.Zero, false, "A group with the same name already exists.");
733  return UUID.Zero;
734  }
735 
736  // check user level
737  ScenePresence avatar = null;
738  Scene scene = (Scene)remoteClient.Scene;
739  scene.TryGetScenePresence(remoteClient.AgentId, out avatar);
740 
741  if (avatar != null)
742  {
743  if (avatar.UserLevel < m_levelGroupCreate)
744  {
745  remoteClient.SendCreateGroupReply(UUID.Zero, false, String.Format("Insufficient permissions to create a group. Requires level {0}", m_levelGroupCreate));
746  return UUID.Zero;
747  }
748  }
749 
750  // check funds
751  // is there is a money module present ?
752  IMoneyModule money = scene.RequestModuleInterface<IMoneyModule>();
753  if (money != null)
754  {
755  // do the transaction, that is if the agent has got sufficient funds
756  if (!money.AmountCovered(remoteClient.AgentId, money.GroupCreationCharge)) {
757  remoteClient.SendCreateGroupReply(UUID.Zero, false, "Insufficient funds to create a group.");
758  return UUID.Zero;
759  }
760  }
761 
762  string reason = string.Empty;
763  UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment,
764  allowPublish, maturePublish, remoteClient.AgentId, out reason);
765 
766  if (groupID != UUID.Zero)
767  {
768  if (money != null)
769  money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, MoneyTransactionType.GroupCreate);
770 
771  remoteClient.SendCreateGroupReply(groupID, true, "Group created successfullly");
772 
773  // Update the founder with new group information.
774  SendAgentGroupDataUpdate(remoteClient, false);
775  }
776  else
777  remoteClient.SendCreateGroupReply(groupID, false, reason);
778 
779  return groupID;
780  }
781 
782  public GroupNoticeData[] GroupNoticesListRequest(IClientAPI remoteClient, UUID groupID)
783  {
784  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
785 
786  // ToDo: check if agent is a member of group and is allowed to see notices?
787 
788  List<ExtendedGroupNoticeData> notices = m_groupData.GetGroupNotices(GetRequestingAgentIDStr(remoteClient), groupID);
789  List<GroupNoticeData> os_notices = new List<GroupNoticeData>();
790  foreach (ExtendedGroupNoticeData n in notices)
791  {
792  GroupNoticeData osn = n.ToGroupNoticeData();
793  os_notices.Add(osn);
794  }
795 
796  return os_notices.ToArray();
797  }
798 
802  public string GetGroupTitle(UUID avatarID)
803  {
804  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
805 
806  GroupMembershipData membership = m_groupData.GetAgentActiveMembership(UUID.Zero.ToString(), avatarID.ToString());
807  if (membership != null)
808  {
809  return membership.GroupTitle;
810  }
811  return string.Empty;
812  }
813 
817  public void GroupTitleUpdate(IClientAPI remoteClient, UUID groupID, UUID titleRoleID)
818  {
819  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
820 
821  m_groupData.SetAgentActiveGroupRole(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, titleRoleID);
822 
823  // TODO: Not sure what all is needed here, but if the active group role change is for the group
824  // the client currently has set active, then we need to do a scene presence update too
825  // if (m_groupData.GetAgentActiveMembership(GetRequestingAgentID(remoteClient)).GroupID == GroupID)
826 
827  SendDataUpdate(remoteClient, true);
828  }
829 
830 
831  public void GroupRoleUpdate(IClientAPI remoteClient, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, byte updateType)
832  {
833  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
834 
835  // Security Checks are handled in the Groups Service.
836 
837  switch ((OpenMetaverse.GroupRoleUpdate)updateType)
838  {
839  case OpenMetaverse.GroupRoleUpdate.Create:
840  string reason = string.Empty;
841  if (!m_groupData.AddGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, UUID.Random(), name, description, title, powers, out reason))
842  remoteClient.SendAgentAlertMessage("Unable to create role: " + reason, false);
843  break;
844 
845  case OpenMetaverse.GroupRoleUpdate.Delete:
846  m_groupData.RemoveGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, roleID);
847  break;
848 
849  case OpenMetaverse.GroupRoleUpdate.UpdateAll:
850  case OpenMetaverse.GroupRoleUpdate.UpdateData:
851  case OpenMetaverse.GroupRoleUpdate.UpdatePowers:
852  if (m_debugEnabled)
853  {
854  GroupPowers gp = (GroupPowers)powers;
855  m_log.DebugFormat("[Groups]: Role ({0}) updated with Powers ({1}) ({2})", name, powers.ToString(), gp.ToString());
856  }
857  m_groupData.UpdateGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, roleID, name, description, title, powers);
858  break;
859 
860  case OpenMetaverse.GroupRoleUpdate.NoUpdate:
861  default:
862  // No Op
863  break;
864 
865  }
866 
867  // TODO: This update really should send out updates for everyone in the role that just got changed.
868  SendDataUpdate(remoteClient, true);
869  }
870 
871  public void GroupRoleChanges(IClientAPI remoteClient, UUID groupID, UUID roleID, UUID memberID, uint changes)
872  {
873  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
874  // Todo: Security check
875 
876  switch (changes)
877  {
878  case 0:
879  // Add
880  m_groupData.AddAgentToGroupRole(GetRequestingAgentIDStr(remoteClient), memberID.ToString(), groupID, roleID);
881 
882  break;
883  case 1:
884  // Remove
885  m_groupData.RemoveAgentFromGroupRole(GetRequestingAgentIDStr(remoteClient), memberID.ToString(), groupID, roleID);
886 
887  break;
888  default:
889  m_log.ErrorFormat("[Groups]: {0} does not understand changes == {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, changes);
890  break;
891  }
892 
893  // TODO: This update really should send out updates for everyone in the role that just got changed.
894  SendDataUpdate(remoteClient, true);
895  }
896 
897  public void GroupNoticeRequest(IClientAPI remoteClient, UUID groupNoticeID)
898  {
899  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called for notice {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, groupNoticeID);
900 
901  GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested);
902 
903  OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient));
904  }
905 
906  public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
907  {
908  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
909 
911  byte[] bucket;
912 
913  msg.imSessionID = groupNoticeID.Guid;
914  msg.toAgentID = agentID.Guid;
915  msg.dialog = dialog;
916  // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice;
917  msg.fromGroup = true;
918  msg.offline = (byte)0;
919  msg.ParentEstateID = 0;
920  msg.Position = Vector3.Zero;
921  msg.RegionID = UUID.Zero.Guid;
922 
923  GroupNoticeInfo info = m_groupData.GetGroupNotice(agentID.ToString(), groupNoticeID);
924  if (info != null)
925  {
926  msg.fromAgentID = info.GroupID.Guid;
927  msg.timestamp = info.noticeData.Timestamp;
928  msg.fromAgentName = info.noticeData.FromName;
929  msg.message = info.noticeData.Subject + "|" + info.Message;
930  if (info.noticeData.HasAttachment)
931  {
932  byte[] name = System.Text.Encoding.UTF8.GetBytes(info.noticeData.AttachmentName);
933  bucket = new byte[19 + name.Length];
934  bucket[0] = 1; // has attachment?
935  bucket[1] = info.noticeData.AttachmentType; // attachment type
936  name.CopyTo(bucket, 18);
937  }
938  else
939  {
940  bucket = new byte[19];
941  bucket[0] = 0; // Has att?
942  bucket[1] = 0; // type
943  bucket[18] = 0; // null terminated
944  }
945 
946  info.GroupID.ToBytes(bucket, 2);
947  msg.binaryBucket = bucket;
948  }
949  else
950  {
951  m_log.DebugFormat("[Groups]: Group Notice {0} not found, composing empty message.", groupNoticeID);
952  msg.fromAgentID = UUID.Zero.Guid;
953  msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ;
954  msg.fromAgentName = string.Empty;
955  msg.message = string.Empty;
956  msg.binaryBucket = new byte[0];
957  }
958 
959  return msg;
960  }
961 
962  public void JoinGroupRequest(IClientAPI remoteClient, UUID groupID)
963  {
964  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
965 
966  string reason = string.Empty;
967  // Should check to see if OpenEnrollment, or if there's an outstanding invitation
968  if (m_groupData.AddAgentToGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, UUID.Zero, string.Empty, out reason))
969  {
970 
971  remoteClient.SendJoinGroupReply(groupID, true);
972 
973  // Should this send updates to everyone in the group?
974  SendAgentGroupDataUpdate(remoteClient, true);
975 
976  if (reason != string.Empty)
977  // A warning
978  remoteClient.SendAlertMessage("Warning: " + reason);
979  }
980  else
981  remoteClient.SendJoinGroupReply(groupID, false);
982  }
983 
984  public void LeaveGroupRequest(IClientAPI remoteClient, UUID groupID)
985  {
986  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
987 
988  m_groupData.RemoveAgentFromGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
989 
990  remoteClient.SendLeaveGroupReply(groupID, true);
991 
992  remoteClient.SendAgentDropGroup(groupID);
993 
994  // SL sends out notifcations to the group messaging session that the person has left
995  // Should this also update everyone who is in the group?
996  SendAgentGroupDataUpdate(remoteClient, true);
997  }
998 
999  public void EjectGroupMemberRequest(IClientAPI remoteClient, UUID groupID, UUID ejecteeID)
1000  {
1001  EjectGroupMember(remoteClient, GetRequestingAgentID(remoteClient), groupID, ejecteeID);
1002  }
1003 
1004  public void EjectGroupMember(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID ejecteeID)
1005  {
1006  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1007 
1008  // Todo: Security check?
1009  m_groupData.RemoveAgentFromGroup(agentID.ToString(), ejecteeID.ToString(), groupID);
1010 
1011  string agentName;
1012  RegionInfo regionInfo;
1013 
1014  // remoteClient provided or just agentID?
1015  if (remoteClient != null)
1016  {
1017  agentName = remoteClient.Name;
1018  regionInfo = remoteClient.Scene.RegionInfo;
1019  remoteClient.SendEjectGroupMemberReply(agentID, groupID, true);
1020  }
1021  else
1022  {
1023  IClientAPI client = GetActiveClient(agentID);
1024 
1025  if (client != null)
1026  {
1027  agentName = client.Name;
1028  regionInfo = client.Scene.RegionInfo;
1029  client.SendEjectGroupMemberReply(agentID, groupID, true);
1030  }
1031  else
1032  {
1033  regionInfo = m_sceneList[0].RegionInfo;
1034  UserAccount acc = m_sceneList[0].UserAccountService.GetUserAccount(regionInfo.ScopeID, agentID);
1035 
1036  if (acc != null)
1037  {
1038  agentName = acc.FirstName + " " + acc.LastName;
1039  }
1040  else
1041  {
1042  agentName = "Unknown member";
1043  }
1044  }
1045  }
1046 
1047  GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null);
1048 
1049  UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(regionInfo.ScopeID, ejecteeID);
1050  if ((groupInfo == null) || (account == null))
1051  {
1052  return;
1053  }
1054 
1055  // Send Message to Ejectee
1057 
1058  msg.imSessionID = UUID.Zero.Guid;
1059  msg.fromAgentID = agentID.Guid;
1060  // msg.fromAgentID = info.GroupID;
1061  msg.toAgentID = ejecteeID.Guid;
1062  //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1063  msg.timestamp = 0;
1064  msg.fromAgentName = agentName;
1065  msg.message = string.Format("You have been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName);
1066  msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageFromAgent;
1067  msg.fromGroup = false;
1068  msg.offline = (byte)0;
1069  msg.ParentEstateID = 0;
1070  msg.Position = Vector3.Zero;
1071  msg.RegionID = regionInfo.RegionID.Guid;
1072  msg.binaryBucket = new byte[0];
1073  OutgoingInstantMessage(msg, ejecteeID);
1074 
1075  // Message to ejector
1076  // Interop, received special 210 code for ejecting a group member
1077  // this only works within the comms servers domain, and won't work hypergrid
1078  // TODO:FIXME: Use a presense server of some kind to find out where the
1079  // client actually is, and try contacting that region directly to notify them,
1080  // or provide the notification via xmlrpc update queue
1081 
1082  msg = new GridInstantMessage();
1083  msg.imSessionID = UUID.Zero.Guid;
1084  msg.fromAgentID = agentID.Guid;
1085  msg.toAgentID = agentID.Guid;
1086  msg.timestamp = 0;
1087  msg.fromAgentName = agentName;
1088  if (account != null)
1089  {
1090  msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName, account.FirstName + " " + account.LastName);
1091  }
1092  else
1093  {
1094  msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName, "Unknown member");
1095  }
1096  msg.dialog = (byte)210; //interop
1097  msg.fromGroup = false;
1098  msg.offline = (byte)0;
1099  msg.ParentEstateID = 0;
1100  msg.Position = Vector3.Zero;
1101  msg.RegionID = regionInfo.RegionID.Guid;
1102  msg.binaryBucket = new byte[0];
1103  OutgoingInstantMessage(msg, agentID);
1104 
1105 
1106  // SL sends out messages to everyone in the group
1107  // Who all should receive updates and what should they be updated with?
1108  SendAgentGroupDataUpdate(remoteClient, false);
1109  }
1110 
1111  public void InviteGroupRequest(IClientAPI remoteClient, UUID groupID, UUID invitedAgentID, UUID roleID)
1112  {
1113  InviteGroup(remoteClient, GetRequestingAgentID(remoteClient), groupID, invitedAgentID, roleID);
1114  }
1115 
1116  public void InviteGroup(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID invitedAgentID, UUID roleID)
1117  {
1118  if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1119 
1120  string agentName = m_UserManagement.GetUserName(agentID);
1121  RegionInfo regionInfo = m_sceneList[0].RegionInfo;
1122 
1123  GroupRecord group = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null);
1124  if (group == null)
1125  {
1126  m_log.DebugFormat("[Groups]: No such group {0}", groupID);
1127  return;
1128  }
1129 
1130  // Todo: Security check, probably also want to send some kind of notification
1131  UUID InviteID = UUID.Random();
1132 
1133  if (m_groupData.AddAgentToGroupInvite(agentID.ToString(), InviteID, groupID, roleID, invitedAgentID.ToString()))
1134  {
1135  if (m_msgTransferModule != null)
1136  {
1137  Guid inviteUUID = InviteID.Guid;
1138 
1140 
1141  msg.imSessionID = inviteUUID;
1142 
1143  // msg.fromAgentID = agentID.Guid;
1144  msg.fromAgentID = groupID.Guid;
1145  msg.toAgentID = invitedAgentID.Guid;
1146  //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1147  msg.timestamp = 0;
1148  msg.fromAgentName = agentName;
1149  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);
1150  msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation;
1151  msg.fromGroup = true;
1152  msg.offline = (byte)0;
1153  msg.ParentEstateID = 0;
1154  msg.Position = Vector3.Zero;
1155  msg.RegionID = regionInfo.RegionID.Guid;
1156  msg.binaryBucket = new byte[20];
1157 
1158  OutgoingInstantMessage(msg, invitedAgentID);
1159  }
1160  }
1161  }
1162 
1163  public List<DirGroupsReplyData> FindGroups(IClientAPI remoteClient, string query)
1164  {
1165  return m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), query);
1166  }
1167 
1168  #endregion
1169 
1170  #region Client/Update Tools
1171 
1175  private IClientAPI GetActiveClient(UUID agentID)
1176  {
1177  IClientAPI child = null;
1178 
1179  // Try root avatar first
1180  foreach (Scene scene in m_sceneList)
1181  {
1182  ScenePresence sp = scene.GetScenePresence(agentID);
1183  if (sp != null)
1184  {
1185  if (!sp.IsChildAgent)
1186  {
1187  return sp.ControllingClient;
1188  }
1189  else
1190  {
1191  child = sp.ControllingClient;
1192  }
1193  }
1194  }
1195 
1196  // If we didn't find a root, then just return whichever child we found, or null if none
1197  return child;
1198  }
1199 
1200  private void SendScenePresenceUpdate(UUID AgentID, string Title)
1201  {
1202  if (m_debugEnabled) m_log.DebugFormat("[Groups]: Updating scene title for {0} with title: {1}", AgentID, Title);
1203 
1204  ScenePresence presence = null;
1205 
1206  foreach (Scene scene in m_sceneList)
1207  {
1208  presence = scene.GetScenePresence(AgentID);
1209  if (presence != null)
1210  {
1211  if (presence.Grouptitle != Title)
1212  {
1213  presence.Grouptitle = Title;
1214 
1215  if (! presence.IsChildAgent)
1216  presence.SendAvatarDataToAllAgents();
1217  }
1218  }
1219  }
1220  }
1221 
1222  public void SendAgentGroupDataUpdate(IClientAPI remoteClient)
1223  {
1224  SendAgentGroupDataUpdate(remoteClient, true);
1225  }
1226 
1230  private void SendAgentGroupDataUpdate(IClientAPI remoteClient, bool tellOthers)
1231  {
1232  if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called for {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Name);
1233 
1234  // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
1235 
1236  UUID agentID = GetRequestingAgentID(remoteClient);
1237 
1238  SendDataUpdate(remoteClient, tellOthers);
1239 
1240  GroupMembershipData[] membershipArray = GetProfileListedGroupMemberships(remoteClient, agentID);
1241  remoteClient.SendAgentGroupDataUpdate(agentID, membershipArray);
1242 
1243  remoteClient.RefreshGroupMembership();
1244  }
1245 
1252  private GroupMembershipData[] GetProfileListedGroupMemberships(IClientAPI requestingClient, UUID dataForAgentID)
1253  {
1254  List<GroupMembershipData> membershipData = m_groupData.GetAgentGroupMemberships(requestingClient.AgentId.ToString(), dataForAgentID.ToString());
1255  GroupMembershipData[] membershipArray;
1256 
1257  // cScene and property accessor 'isGod' are in support of the opertions to bypass 'hidden' group attributes for
1258  // those with a GodLike aspect.
1259  Scene cScene = (Scene)requestingClient.Scene;
1260  bool isGod = cScene.Permissions.IsGod(requestingClient.AgentId);
1261 
1262  if (isGod)
1263  {
1264  membershipArray = membershipData.ToArray();
1265  }
1266  else
1267  {
1268  if (requestingClient.AgentId != dataForAgentID)
1269  {
1270  Predicate<GroupMembershipData> showInProfile = delegate(GroupMembershipData membership)
1271  {
1272  return membership.ListInProfile;
1273  };
1274 
1275  membershipArray = membershipData.FindAll(showInProfile).ToArray();
1276  }
1277  else
1278  {
1279  membershipArray = membershipData.ToArray();
1280  }
1281  }
1282 
1283  if (m_debugEnabled)
1284  {
1285  m_log.InfoFormat("[Groups]: Get group membership information for {0} requested by {1}", dataForAgentID, requestingClient.AgentId);
1286  foreach (GroupMembershipData membership in membershipArray)
1287  {
1288  m_log.InfoFormat("[Groups]: {0} :: {1} - {2} - {3}", dataForAgentID, membership.GroupName, membership.GroupTitle, membership.GroupPowers);
1289  }
1290  }
1291 
1292  return membershipArray;
1293  }
1294 
1295  //tell remoteClient about its agent group info, and optionally send title to others
1296  private void SendDataUpdate(IClientAPI remoteClient, bool tellOthers)
1297  {
1298  if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1299 
1300  UUID activeGroupID = UUID.Zero;
1301  string activeGroupTitle = string.Empty;
1302  string activeGroupName = string.Empty;
1303  ulong activeGroupPowers = (ulong)GroupPowers.None;
1304 
1305  UUID agentID = GetRequestingAgentID(remoteClient);
1306  GroupMembershipData membership = m_groupData.GetAgentActiveMembership(agentID.ToString(), agentID.ToString());
1307  if (membership != null)
1308  {
1309  activeGroupID = membership.GroupID;
1310  activeGroupTitle = membership.GroupTitle;
1311  activeGroupPowers = membership.GroupPowers;
1312  activeGroupName = membership.GroupName;
1313  }
1314 
1315  UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, agentID);
1316  string firstname, lastname;
1317  if (account != null)
1318  {
1319  firstname = account.FirstName;
1320  lastname = account.LastName;
1321  }
1322  else
1323  {
1324  firstname = "Unknown";
1325  lastname = "Unknown";
1326  }
1327 
1328  remoteClient.SendAgentDataUpdate(agentID, activeGroupID, firstname,
1329  lastname, activeGroupPowers, activeGroupName,
1330  activeGroupTitle);
1331 
1332  if (tellOthers)
1333  SendScenePresenceUpdate(agentID, activeGroupTitle);
1334 
1335  ScenePresence sp = (ScenePresence)remoteClient.SceneAgent;
1336  if (sp != null)
1337  sp.Grouptitle = activeGroupTitle;
1338  }
1339 
1340  #endregion
1341 
1342  #region IM Backed Processes
1343 
1344  private void OutgoingInstantMessage(GridInstantMessage msg, UUID msgTo)
1345  {
1346  if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1347 
1348  IClientAPI localClient = GetActiveClient(msgTo);
1349  if (localClient != null)
1350  {
1351  if (m_debugEnabled) m_log.InfoFormat("[Groups]: MsgTo ({0}) is local, delivering directly", localClient.Name);
1352  localClient.SendInstantMessage(msg);
1353  }
1354  else if (m_msgTransferModule != null)
1355  {
1356  if (m_debugEnabled) m_log.InfoFormat("[Groups]: MsgTo ({0}) is not local, delivering via TransferModule", msgTo);
1357  m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { if (m_debugEnabled) m_log.DebugFormat("[Groups]: Message Sent: {0}", success?"Succeeded":"Failed"); });
1358  }
1359  }
1360 
1361  public void NotifyChange(UUID groupID)
1362  {
1363  // Notify all group members of a chnge in group roles and/or
1364  // permissions
1365  //
1366  }
1367 
1368  #endregion
1369 
1370  private string GetRequestingAgentIDStr(IClientAPI client)
1371  {
1372  return GetRequestingAgentID(client).ToString();
1373  }
1374 
1375  private UUID GetRequestingAgentID(IClientAPI client)
1376  {
1377  UUID requestingAgentID = UUID.Zero;
1378  if (client != null)
1379  {
1380  requestingAgentID = client.AgentId;
1381  }
1382  return requestingAgentID;
1383  }
1384 
1385  }
1386 }
RegionInfo RegionInfo
Definition: IScene.cs:64
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
void SetGroupAcceptNotices(IClientAPI remoteClient, UUID groupID, bool acceptNotices, bool listInProfile)
string GetGroupTitle(UUID avatarID)
Get the title of the agent's current role.
void GroupTitleUpdate(IClientAPI remoteClient, UUID groupID, UUID titleRoleID)
Change the current Active Group Role for Agent
bool AmountCovered(UUID agentID, int amount)
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Definition: GroupsModule.cs:98
void ActivateGroup(IClientAPI remoteClient, UUID groupID)
delegate void NewGroupNotice(UUID groupID, UUID noticeID)
OpenSim.Framework.RegionInfo RegionInfo
void InviteGroup(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID invitedAgentID, UUID roleID)
string Name
Returns the full name of the agent/avatar represented by this client
Definition: IClientAPI.cs:754
OpenMetaverse.StructuredData.OSDMap OSDMap
void InviteGroupRequest(IClientAPI remoteClient, UUID groupID, UUID invitedAgentID, UUID roleID)
void LeaveGroupRequest(IClientAPI remoteClient, UUID groupID)
NewGroupNotice OnNewGroupNotice
GroupRecord GetGroupRecord(string name)
Get a group
void JoinGroupRequest(IClientAPI remoteClient, UUID groupID)
void GroupRoleUpdate(IClientAPI remoteClient, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, byte updateType)
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
ISceneAgent SceneAgent
The scene agent for this client. This will only be set if the client has an agent in a scene (i...
Definition: IClientAPI.cs:724
GroupMembershipData GetMembershipData(UUID groupID, UUID agentID)
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
GroupRecord GetGroupRecord(UUID GroupID)
Get a group
void EjectGroupMemberRequest(IClientAPI remoteClient, UUID groupID, UUID ejecteeID)
List< DirGroupsReplyData > FindGroups(IClientAPI remoteClient, string query)
List< GroupRoleMembersData > GroupRoleMembersRequest(IClientAPI remoteClient, UUID groupID)
Inventory Item - contains all the properties associated with an individual inventory piece...
void GroupNoticeRequest(IClientAPI remoteClient, UUID groupNoticeID)
OpenMetaverse.StructuredData.OSD OSD
GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
void SendAgentGroupDataUpdate(IClientAPI remoteClient)
void SendAgentAlertMessage(string message, bool modal)
GroupNoticeData[] GroupNoticesListRequest(IClientAPI remoteClient, UUID groupID)
override bool TryGetScenePresence(UUID agentID, out ScenePresence sp)
Try to get a scene presence from the scene
Definition: Scene.cs:5401
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
List< GroupTitlesData > GroupTitlesRequest(IClientAPI remoteClient, UUID groupID)
Get the Role Titles for an Agent, for a specific group
GroupProfileData GroupProfileRequest(IClientAPI remoteClient, UUID groupID)
void EjectGroupMember(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID ejecteeID)
void NotifyChange(UUID groupID)
GroupMembershipData[] GetMembershipData(UUID agentID)
UUID CreateGroup(IClientAPI remoteClient, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
Create a group
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
Definition: GroupsModule.cs:66
List< GroupRolesData > GroupRoleDataRequest(IClientAPI remoteClient, UUID groupID)
List< GroupMembersData > GroupMembersRequest(IClientAPI remoteClient, UUID groupID)
This maintains the relationship between a UUID and a user name.
void GroupRoleChanges(IClientAPI remoteClient, UUID groupID, UUID roleID, UUID memberID, uint changes)
void UpdateGroupInfo(IClientAPI remoteClient, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
OpenMetaverse.DirectoryManager.DirFindFlags DirFindFlags
Definition: GroupsModule.cs:41