aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsModule.cs
diff options
context:
space:
mode:
authorMichael Cortez2009-08-05 11:15:53 -0700
committerMichael Cortez2009-08-05 11:15:53 -0700
commit989517725d02d8a2d216e599856eb2625b454e25 (patch)
tree74f31eac6e685361ff5d469cdc6992158964666f /OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsModule.cs
parentforce back the Regions directory, which because it was empty in svn never made (diff)
downloadopensim-SC_OLD-989517725d02d8a2d216e599856eb2625b454e25.zip
opensim-SC_OLD-989517725d02d8a2d216e599856eb2625b454e25.tar.gz
opensim-SC_OLD-989517725d02d8a2d216e599856eb2625b454e25.tar.bz2
opensim-SC_OLD-989517725d02d8a2d216e599856eb2625b454e25.tar.xz
Begin refactoring XmlRpcGroups to a more generic Groups module that allows for replaceable Groups Service Connectors.
Diffstat (limited to 'OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsModule.cs')
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsModule.cs1331
1 files changed, 0 insertions, 1331 deletions
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsModule.cs
deleted file mode 100644
index 2cbc571..0000000
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsModule.cs
+++ /dev/null
@@ -1,1331 +0,0 @@
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;
32
33using log4net;
34using Nini.Config;
35
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38
39using OpenSim.Framework;
40using OpenSim.Framework.Communications;
41using OpenSim.Region.CoreModules.Framework.EventQueue;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44
45using Caps = OpenSim.Framework.Capabilities.Caps;
46using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
47
48
49
50namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
51{
52 public class XmlRpcGroupsModule : ISharedRegionModule, IGroupsModule
53 {
54 /// <summary>
55 /// ; To use this module, you must specify the following in your OpenSim.ini
56 /// [GROUPS]
57 /// Enabled = true
58 /// Module = XmlRpcGroups
59 /// XmlRpcServiceURL = http://osflotsam.org/xmlrpc.php
60 /// XmlRpcMessagingEnabled = true
61 /// XmlRpcNoticesEnabled = true
62 /// XmlRpcDebugEnabled = true
63 /// XmlRpcServiceReadKey = 1234
64 /// XmlRpcServiceWriteKey = 1234
65 ///
66 /// ; Disables HTTP Keep-Alive for Groups Module HTTP Requests, work around for
67 /// ; a problem discovered on some Windows based region servers. Only disable
68 /// ; if you see a large number (dozens) of the following Exceptions:
69 /// ; System.Net.WebException: The request was aborted: The request was canceled.
70 ///
71 /// XmlRpcDisableKeepAlive = false
72 /// </summary>
73
74 private static readonly ILog m_log =
75 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
76
77 private List<Scene> m_sceneList = new List<Scene>();
78
79 private IMessageTransferModule m_msgTransferModule = null;
80
81 private IGroupDataProvider m_groupData = null;
82
83 class GroupRequestIDInfo
84 {
85 public GroupRequestID RequestID = new GroupRequestID();
86 public DateTime LastUsedTMStamp = DateTime.MinValue;
87 }
88 private Dictionary<UUID, GroupRequestIDInfo> m_clientRequestIDInfo = new Dictionary<UUID, GroupRequestIDInfo>();
89 private const int m_clientRequestIDFlushTimeOut = 300000; // Every 5 minutes
90 private Timer m_clientRequestIDFlushTimer = new Timer();
91
92
93 // Configuration settings
94 private const string m_defaultXmlRpcServiceURL = "http://osflotsam.org/xmlrpc.php";
95 private bool m_groupsEnabled = false;
96 private bool m_groupNoticesEnabled = true;
97 private bool m_debugEnabled = true;
98
99 #region IRegionModuleBase Members
100
101 public void Initialise(IConfigSource config)
102 {
103 IConfig groupsConfig = config.Configs["Groups"];
104
105 if (groupsConfig == null)
106 {
107 // Do not run this module by default.
108 return;
109 }
110 else
111 {
112 m_groupsEnabled = groupsConfig.GetBoolean("Enabled", false);
113 if (!m_groupsEnabled)
114 {
115 return;
116 }
117
118 if (groupsConfig.GetString("Module", "Default") != "XmlRpcGroups")
119 {
120 m_groupsEnabled = false;
121
122 return;
123 }
124
125 m_log.InfoFormat("[GROUPS]: Initializing {0}", this.Name);
126
127 string ServiceURL = groupsConfig.GetString("XmlRpcServiceURL", m_defaultXmlRpcServiceURL);
128 bool DisableKeepAlive = groupsConfig.GetBoolean("XmlRpcDisableKeepAlive", false);
129
130 string ServiceReadKey = groupsConfig.GetString("XmlRpcServiceReadKey", string.Empty);
131 string ServiceWriteKey = groupsConfig.GetString("XmlRpcServiceWriteKey", string.Empty);
132
133 m_groupData = new XmlRpcGroupDataProvider(ServiceURL, DisableKeepAlive, ServiceReadKey, ServiceWriteKey);
134 m_log.InfoFormat("[GROUPS]: XmlRpc Service URL set to: {0}", ServiceURL);
135
136 m_groupNoticesEnabled = groupsConfig.GetBoolean("XmlRpcNoticesEnabled", true);
137 m_debugEnabled = groupsConfig.GetBoolean("XmlRpcDebugEnabled", true);
138
139 m_clientRequestIDFlushTimer.Interval = m_clientRequestIDFlushTimeOut;
140 m_clientRequestIDFlushTimer.Elapsed += FlushClientRequestIDInfoCache;
141 m_clientRequestIDFlushTimer.AutoReset = true;
142 m_clientRequestIDFlushTimer.Start();
143 }
144 }
145
146 void FlushClientRequestIDInfoCache(object sender, ElapsedEventArgs e)
147 {
148 lock (m_clientRequestIDInfo)
149 {
150 TimeSpan cacheTimeout = new TimeSpan(0,0, m_clientRequestIDFlushTimeOut / 1000);
151 UUID[] CurrentKeys = new UUID[m_clientRequestIDInfo.Count];
152 foreach (UUID key in CurrentKeys)
153 {
154 if (DateTime.Now - m_clientRequestIDInfo[key].LastUsedTMStamp > cacheTimeout)
155 {
156 m_clientRequestIDInfo.Remove(key);
157 }
158 }
159 }
160 }
161
162 public void AddRegion(Scene scene)
163 {
164 if (m_groupsEnabled)
165 scene.RegisterModuleInterface<IGroupsModule>(this);
166 }
167
168 public void RegionLoaded(Scene scene)
169 {
170 if (!m_groupsEnabled)
171 return;
172
173 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
174
175 if (m_msgTransferModule == null)
176 {
177 m_msgTransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
178
179 // No message transfer module, no notices, group invites, rejects, ejects, etc
180 if (m_msgTransferModule == null)
181 {
182 m_groupsEnabled = false;
183 m_log.Error("[GROUPS]: Could not get MessageTransferModule");
184 Close();
185 return;
186 }
187 }
188
189 lock (m_sceneList)
190 {
191 m_sceneList.Add(scene);
192 }
193
194 scene.EventManager.OnNewClient += OnNewClient;
195 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
196
197 // The InstantMessageModule itself doesn't do this,
198 // so lets see if things explode if we don't do it
199 // scene.EventManager.OnClientClosed += OnClientClosed;
200
201 }
202
203 public void RemoveRegion(Scene scene)
204 {
205 if (!m_groupsEnabled)
206 return;
207
208 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
209
210 lock (m_sceneList)
211 {
212 m_sceneList.Remove(scene);
213 }
214 }
215
216 public void Close()
217 {
218 if (!m_groupsEnabled)
219 return;
220
221 if (m_debugEnabled) m_log.Debug("[GROUPS]: Shutting down XmlRpcGroups module.");
222
223 m_clientRequestIDFlushTimer.Stop();
224 }
225
226 public Type ReplacableInterface
227 {
228 get { return null; }
229 }
230
231 public string Name
232 {
233 get { return "XmlRpcGroupsModule"; }
234 }
235
236 #endregion
237
238 #region ISharedRegionModule Members
239
240 public void PostInitialise()
241 {
242 // NoOp
243 }
244
245 #endregion
246
247 #region EventHandlers
248 private void OnNewClient(IClientAPI client)
249 {
250 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
251
252 client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
253 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
254 client.OnDirFindQuery += OnDirFindQuery;
255 client.OnRequestAvatarProperties += OnRequestAvatarProperties;
256
257 // Used for Notices and Group Invites/Accept/Reject
258 client.OnInstantMessage += OnInstantMessage;
259
260 lock (m_clientRequestIDInfo)
261 {
262 if (m_clientRequestIDInfo.ContainsKey(client.AgentId))
263 {
264 // flush any old RequestID information
265 m_clientRequestIDInfo.Remove(client.AgentId);
266 }
267 }
268 SendAgentGroupDataUpdate(client, client.AgentId);
269 }
270
271 private void OnRequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
272 {
273 GroupMembershipData[] avatarGroups = m_groupData.GetAgentGroupMemberships(GetClientGroupRequestID(remoteClient), avatarID).ToArray();
274 remoteClient.SendAvatarGroupsReply(avatarID, avatarGroups);
275 }
276
277 /*
278 * This becomes very problematic in a shared module. In a shared module you may have more then one
279 * reference to IClientAPI's, one for 0 or 1 root connections, and 0 or more child connections.
280 * The OnClientClosed event does not provide anything to indicate which one of those should be closed
281 * nor does it provide what scene it was from so that the specific reference can be looked up.
282 * The InstantMessageModule.cs does not currently worry about unregistering the handles,
283 * and it should be an issue, since it's the client that references us not the other way around
284 * , so as long as we don't keep a reference to the client laying around, the client can still be GC'ed
285 private void OnClientClosed(UUID AgentId)
286 {
287 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
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
312 void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart)
313 {
314 if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups)
315 {
316 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})", System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart);
317
318 // TODO: This currently ignores pretty much all the query flags including Mature and sort order
319 remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetClientGroupRequestID(remoteClient), queryText).ToArray());
320 }
321
322 }
323
324 private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID)
325 {
326 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
327
328 UUID activeGroupID = UUID.Zero;
329 string activeGroupTitle = string.Empty;
330 string activeGroupName = string.Empty;
331 ulong activeGroupPowers = (ulong)GroupPowers.None;
332
333 GroupMembershipData membership = m_groupData.GetAgentActiveMembership(GetClientGroupRequestID(remoteClient), dataForAgentID);
334 if (membership != null)
335 {
336 activeGroupID = membership.GroupID;
337 activeGroupTitle = membership.GroupTitle;
338 activeGroupPowers = membership.GroupPowers;
339 }
340
341 SendAgentDataUpdate(remoteClient, dataForAgentID, activeGroupID, activeGroupName, activeGroupPowers, activeGroupTitle);
342
343 SendScenePresenceUpdate(dataForAgentID, activeGroupTitle);
344 }
345
346 private void HandleUUIDGroupNameRequest(UUID GroupID,IClientAPI remoteClient)
347 {
348 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
349
350 string GroupName;
351
352 GroupRecord group = m_groupData.GetGroupRecord(GetClientGroupRequestID(remoteClient), GroupID, null);
353 if (group != null)
354 {
355 GroupName = group.GroupName;
356 }
357 else
358 {
359 GroupName = "Unknown";
360 }
361
362 remoteClient.SendGroupNameReply(GroupID, GroupName);
363 }
364
365 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
366 {
367 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
368
369 // Group invitations
370 if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline))
371 {
372 UUID inviteID = new UUID(im.imSessionID);
373 GroupInviteInfo inviteInfo = m_groupData.GetAgentToGroupInvite(GetClientGroupRequestID(remoteClient), inviteID);
374
375 if (inviteInfo == null)
376 {
377 if (m_debugEnabled) m_log.WarnFormat("[GROUPS]: Received an Invite IM for an invite that does not exist {0}.", inviteID);
378 return;
379 }
380
381 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Invite is for Agent {0} to Group {1}.", inviteInfo.AgentID, inviteInfo.GroupID);
382
383 UUID fromAgentID = new UUID(im.fromAgentID);
384 if ((inviteInfo != null) && (fromAgentID == inviteInfo.AgentID))
385 {
386 // Accept
387 if (im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept)
388 {
389 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Received an accept invite notice.");
390
391 // and the sessionid is the role
392 m_groupData.AddAgentToGroup(GetClientGroupRequestID(remoteClient), inviteInfo.AgentID, inviteInfo.GroupID, inviteInfo.RoleID);
393
394 GridInstantMessage msg = new GridInstantMessage();
395 msg.imSessionID = UUID.Zero.Guid;
396 msg.fromAgentID = UUID.Zero.Guid;
397 msg.toAgentID = inviteInfo.AgentID.Guid;
398 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
399 msg.fromAgentName = "Groups";
400 msg.message = string.Format("You have been added to the group.");
401 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageBox;
402 msg.fromGroup = false;
403 msg.offline = (byte)0;
404 msg.ParentEstateID = 0;
405 msg.Position = Vector3.Zero;
406 msg.RegionID = UUID.Zero.Guid;
407 msg.binaryBucket = new byte[0];
408
409 OutgoingInstantMessage(msg, inviteInfo.AgentID);
410
411 UpdateAllClientsWithGroupInfo(inviteInfo.AgentID);
412
413 // TODO: If the inviter is still online, they need an agent dataupdate
414 // and maybe group membership updates for the invitee
415
416 m_groupData.RemoveAgentToGroupInvite(GetClientGroupRequestID(remoteClient), inviteID);
417 }
418
419 // Reject
420 if (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)
421 {
422 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Received a reject invite notice.");
423 m_groupData.RemoveAgentToGroupInvite(GetClientGroupRequestID(remoteClient), inviteID);
424 }
425 }
426 }
427
428 // Group notices
429 if ((im.dialog == (byte)InstantMessageDialog.GroupNotice))
430 {
431 if (!m_groupNoticesEnabled)
432 {
433 return;
434 }
435
436 UUID GroupID = new UUID(im.toAgentID);
437 if (m_groupData.GetGroupRecord(GetClientGroupRequestID(remoteClient), GroupID, null) != null)
438 {
439 UUID NoticeID = UUID.Random();
440 string Subject = im.message.Substring(0, im.message.IndexOf('|'));
441 string Message = im.message.Substring(Subject.Length + 1);
442
443 byte[] bucket;
444
445 if ((im.binaryBucket.Length == 1) && (im.binaryBucket[0] == 0))
446 {
447 bucket = new byte[19];
448 bucket[0] = 0; //dunno
449 bucket[1] = 0; //dunno
450 GroupID.ToBytes(bucket, 2);
451 bucket[18] = 0; //dunno
452 }
453 else
454 {
455 string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket);
456 binBucket = binBucket.Remove(0, 14).Trim();
457 if (m_debugEnabled)
458 {
459 m_log.WarnFormat("I don't understand a group notice binary bucket of: {0}", binBucket);
460
461 OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket);
462
463 foreach (string key in binBucketOSD.Keys)
464 {
465 m_log.WarnFormat("{0}: {1}", key, binBucketOSD[key].ToString());
466 }
467 }
468
469 // treat as if no attachment
470 bucket = new byte[19];
471 bucket[0] = 0; //dunno
472 bucket[1] = 0; //dunno
473 GroupID.ToBytes(bucket, 2);
474 bucket[18] = 0; //dunno
475 }
476
477 m_groupData.AddGroupNotice(GetClientGroupRequestID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket);
478 if (OnNewGroupNotice != null)
479 {
480 OnNewGroupNotice(GroupID, NoticeID);
481 }
482
483 // Send notice out to everyone that wants notices
484 foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetClientGroupRequestID(remoteClient), GroupID))
485 {
486 if (member.AcceptNotices)
487 {
488 // Build notice IIM
489 GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
490
491 msg.toAgentID = member.AgentID.Guid;
492 OutgoingInstantMessage(msg, member.AgentID);
493 }
494 }
495 }
496 }
497
498 // Interop, received special 210 code for ejecting a group member
499 // this only works within the comms servers domain, and won't work hypergrid
500 // TODO:FIXME: Use a presense server of some kind to find out where the
501 // client actually is, and try contacting that region directly to notify them,
502 // or provide the notification via xmlrpc update queue
503 if ((im.dialog == 210))
504 {
505 // This is sent from the region that the ejectee was ejected from
506 // if it's being delivered here, then the ejectee is here
507 // so we need to send local updates to the agent.
508
509 UUID ejecteeID = new UUID(im.toAgentID);
510
511 im.dialog = (byte)InstantMessageDialog.MessageFromAgent;
512 OutgoingInstantMessage(im, ejecteeID);
513
514 IClientAPI ejectee = GetActiveClient(ejecteeID);
515 if (ejectee != null)
516 {
517 UUID groupID = new UUID(im.fromAgentID);
518 ejectee.SendAgentDropGroup(groupID);
519 }
520 }
521 }
522
523 private void OnGridInstantMessage(GridInstantMessage msg)
524 {
525 if (m_debugEnabled) m_log.InfoFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
526
527 // Trigger the above event handler
528 OnInstantMessage(null, msg);
529
530 // If a message from a group arrives here, it may need to be forwarded to a local client
531 if (msg.fromGroup == true)
532 {
533 switch (msg.dialog)
534 {
535 case (byte)InstantMessageDialog.GroupInvitation:
536 case (byte)InstantMessageDialog.GroupNotice:
537 UUID toAgentID = new UUID(msg.toAgentID);
538 IClientAPI localClient = GetActiveClient(toAgentID);
539 if (localClient != null)
540 {
541 localClient.SendInstantMessage(msg);
542 }
543 break;
544 }
545 }
546 }
547
548 #endregion
549
550 #region IGroupsModule Members
551
552 public event NewGroupNotice OnNewGroupNotice;
553
554 public GroupRecord GetGroupRecord(UUID GroupID)
555 {
556 return m_groupData.GetGroupRecord(null, GroupID, null);
557 }
558
559 public void ActivateGroup(IClientAPI remoteClient, UUID groupID)
560 {
561 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
562
563 m_groupData.SetAgentActiveGroup(GetClientGroupRequestID(remoteClient), remoteClient.AgentId, groupID);
564
565 // Changing active group changes title, active powers, all kinds of things
566 // anyone who is in any region that can see this client, should probably be
567 // updated with new group info. At a minimum, they should get ScenePresence
568 // updated with new title.
569 UpdateAllClientsWithGroupInfo(remoteClient.AgentId);
570 }
571
572 /// <summary>
573 /// Get the Role Titles for an Agent, for a specific group
574 /// </summary>
575 public List<GroupTitlesData> GroupTitlesRequest(IClientAPI remoteClient, UUID groupID)
576 {
577 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
578
579 GroupRequestID grID = GetClientGroupRequestID(remoteClient);
580
581 List<GroupRolesData> agentRoles = m_groupData.GetAgentGroupRoles(grID, remoteClient.AgentId, groupID);
582 GroupMembershipData agentMembership = m_groupData.GetAgentGroupMembership(grID, remoteClient.AgentId, groupID);
583
584 List<GroupTitlesData> titles = new List<GroupTitlesData>();
585 foreach (GroupRolesData role in agentRoles)
586 {
587 GroupTitlesData title = new GroupTitlesData();
588 title.Name = role.Name;
589 if (agentMembership != null)
590 {
591 title.Selected = agentMembership.ActiveRole == role.RoleID;
592 }
593 title.UUID = role.RoleID;
594
595 titles.Add(title);
596 }
597
598 return titles;
599 }
600
601 public List<GroupMembersData> GroupMembersRequest(IClientAPI remoteClient, UUID groupID)
602 {
603 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
604
605 List<GroupMembersData> data = m_groupData.GetGroupMembers(GetClientGroupRequestID(remoteClient), groupID);
606 if (m_debugEnabled)
607 {
608 foreach (GroupMembersData member in data)
609 {
610 m_log.DebugFormat("[GROUPS]: {0} {1}", member.AgentID, member.Title);
611 }
612 }
613
614 return data;
615
616 }
617
618 public List<GroupRolesData> GroupRoleDataRequest(IClientAPI remoteClient, UUID groupID)
619 {
620 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
621
622 List<GroupRolesData> data = m_groupData.GetGroupRoles(GetClientGroupRequestID(remoteClient), groupID);
623
624 if (m_debugEnabled)
625 {
626 foreach (GroupRolesData member in data)
627 {
628 m_log.DebugFormat("[GROUPS]: {0} {1}", member.Title, member.Members);
629 }
630 }
631
632 return data;
633
634 }
635
636 public List<GroupRoleMembersData> GroupRoleMembersRequest(IClientAPI remoteClient, UUID groupID)
637 {
638 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
639
640 List<GroupRoleMembersData> data = m_groupData.GetGroupRoleMembers(GetClientGroupRequestID(remoteClient), groupID);
641
642 if (m_debugEnabled)
643 {
644 foreach (GroupRoleMembersData member in data)
645 {
646 m_log.DebugFormat("[GROUPS]: Av: {0} Role: {1}", member.MemberID, member.RoleID);
647 }
648 }
649
650 return data;
651
652
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 GroupRequestID grID = GetClientGroupRequestID(remoteClient);
662
663 GroupRecord groupInfo = m_groupData.GetGroupRecord(GetClientGroupRequestID(remoteClient), groupID, null);
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 = m_groupData.GetGroupMembers(grID, groupID).Count;
671 profile.GroupRolesCount = m_groupData.GetGroupRoles(grID, groupID).Count;
672 profile.InsigniaID = groupInfo.GroupPicture;
673 profile.MaturePublish = groupInfo.MaturePublish;
674 profile.MembershipFee = groupInfo.MembershipFee;
675 profile.Money = 0; // TODO: Get this from the currency server?
676 profile.Name = groupInfo.GroupName;
677 profile.OpenEnrollment = groupInfo.OpenEnrollment;
678 profile.OwnerRole = groupInfo.OwnerRoleID;
679 profile.ShowInList = groupInfo.ShowInList;
680 }
681
682 GroupMembershipData memberInfo = m_groupData.GetAgentGroupMembership(grID, remoteClient.AgentId, groupID);
683 if (memberInfo != null)
684 {
685 profile.MemberTitle = memberInfo.GroupTitle;
686 profile.PowersMask = memberInfo.GroupPowers;
687 }
688
689 return profile;
690 }
691
692 public GroupMembershipData[] GetMembershipData(UUID agentID)
693 {
694 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
695
696 return m_groupData.GetAgentGroupMemberships(null, agentID).ToArray();
697 }
698
699 public GroupMembershipData GetMembershipData(UUID groupID, UUID agentID)
700 {
701 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
702
703 return m_groupData.GetAgentGroupMembership(null, agentID, groupID);
704 }
705
706 public void UpdateGroupInfo(IClientAPI remoteClient, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
707 {
708 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
709
710 // TODO: Security Check?
711
712 m_groupData.UpdateGroup(GetClientGroupRequestID(remoteClient), groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
713 }
714
715 public void SetGroupAcceptNotices(IClientAPI remoteClient, UUID groupID, bool acceptNotices, bool listInProfile)
716 {
717 // TODO: Security Check?
718 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
719
720 m_groupData.SetAgentGroupInfo(GetClientGroupRequestID(remoteClient), remoteClient.AgentId, groupID, acceptNotices, listInProfile);
721 }
722
723 public UUID CreateGroup(IClientAPI remoteClient, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
724 {
725 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
726
727 GroupRequestID grID = GetClientGroupRequestID(remoteClient);
728
729 if (m_groupData.GetGroupRecord(grID, UUID.Zero, name) != null)
730 {
731 remoteClient.SendCreateGroupReply(UUID.Zero, false, "A group with the same name already exists.");
732 return UUID.Zero;
733 }
734 // is there is a money module present ?
735 IMoneyModule money=remoteClient.Scene.RequestModuleInterface<IMoneyModule>();
736 if (money != null)
737 {
738 // do the transaction, that is if the agent has got sufficient funds
739 if (!money.GroupCreationCovered(remoteClient)) {
740 remoteClient.SendCreateGroupReply(UUID.Zero, false, "You have got issuficient funds to create a group.");
741 return UUID.Zero;
742 }
743 money.ApplyGroupCreationCharge(remoteClient.AgentId);
744 }
745 UUID groupID = m_groupData.CreateGroup(grID, name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, remoteClient.AgentId);
746
747 remoteClient.SendCreateGroupReply(groupID, true, "Group created successfullly");
748
749 // Update the founder with new group information.
750 SendAgentGroupDataUpdate(remoteClient, remoteClient.AgentId);
751
752 return groupID;
753 }
754
755 public GroupNoticeData[] GroupNoticesListRequest(IClientAPI remoteClient, UUID groupID)
756 {
757 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
758
759 // ToDo: check if agent is a member of group and is allowed to see notices?
760
761 return m_groupData.GetGroupNotices(GetClientGroupRequestID(remoteClient), groupID).ToArray();
762 }
763
764 /// <summary>
765 /// Get the title of the agent's current role.
766 /// </summary>
767 public string GetGroupTitle(UUID avatarID)
768 {
769 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
770
771 GroupMembershipData membership = m_groupData.GetAgentActiveMembership(null, avatarID);
772 if (membership != null)
773 {
774 return membership.GroupTitle;
775 }
776 return string.Empty;
777 }
778
779 /// <summary>
780 /// Change the current Active Group Role for Agent
781 /// </summary>
782 public void GroupTitleUpdate(IClientAPI remoteClient, UUID groupID, UUID titleRoleID)
783 {
784 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
785
786 m_groupData.SetAgentActiveGroupRole(GetClientGroupRequestID(remoteClient), remoteClient.AgentId, groupID, titleRoleID);
787
788 // TODO: Not sure what all is needed here, but if the active group role change is for the group
789 // the client currently has set active, then we need to do a scene presence update too
790 // if (m_groupData.GetAgentActiveMembership(remoteClient.AgentId).GroupID == GroupID)
791
792 UpdateAllClientsWithGroupInfo(remoteClient.AgentId);
793 }
794
795
796 public void GroupRoleUpdate(IClientAPI remoteClient, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, byte updateType)
797 {
798 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
799
800 // TODO: Security Checks?
801
802 GroupRequestID grID = GetClientGroupRequestID(remoteClient);
803
804 switch ((OpenMetaverse.GroupRoleUpdate)updateType)
805 {
806 case OpenMetaverse.GroupRoleUpdate.Create:
807 m_groupData.AddGroupRole(grID, groupID, UUID.Random(), name, description, title, powers);
808 break;
809
810 case OpenMetaverse.GroupRoleUpdate.Delete:
811 m_groupData.RemoveGroupRole(grID, groupID, roleID);
812 break;
813
814 case OpenMetaverse.GroupRoleUpdate.UpdateAll:
815 case OpenMetaverse.GroupRoleUpdate.UpdateData:
816 case OpenMetaverse.GroupRoleUpdate.UpdatePowers:
817 m_groupData.UpdateGroupRole(grID, groupID, roleID, name, description, title, powers);
818 break;
819
820 case OpenMetaverse.GroupRoleUpdate.NoUpdate:
821 default:
822 // No Op
823 break;
824
825 }
826
827 // TODO: This update really should send out updates for everyone in the role that just got changed.
828 SendAgentGroupDataUpdate(remoteClient, remoteClient.AgentId);
829 }
830
831 public void GroupRoleChanges(IClientAPI remoteClient, UUID groupID, UUID roleID, UUID memberID, uint changes)
832 {
833 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
834 // Todo: Security check
835
836 GroupRequestID grID = GetClientGroupRequestID(remoteClient);
837
838 switch (changes)
839 {
840 case 0:
841 // Add
842 m_groupData.AddAgentToGroupRole(grID, memberID, groupID, roleID);
843
844 break;
845 case 1:
846 // Remove
847 m_groupData.RemoveAgentFromGroupRole(grID, memberID, groupID, roleID);
848
849 break;
850 default:
851 m_log.ErrorFormat("[GROUPS]: {0} does not understand changes == {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, changes);
852 break;
853 }
854
855 // TODO: This update really should send out updates for everyone in the role that just got changed.
856 SendAgentGroupDataUpdate(remoteClient, remoteClient.AgentId);
857 }
858
859 public void GroupNoticeRequest(IClientAPI remoteClient, UUID groupNoticeID)
860 {
861 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
862
863 GroupRequestID grID = GetClientGroupRequestID(remoteClient);
864
865 GroupNoticeInfo data = m_groupData.GetGroupNotice(grID, groupNoticeID);
866
867 if (data != null)
868 {
869 GroupRecord groupInfo = m_groupData.GetGroupRecord(grID, data.GroupID, null);
870
871 GridInstantMessage msg = new GridInstantMessage();
872 msg.imSessionID = UUID.Zero.Guid;
873 msg.fromAgentID = data.GroupID.Guid;
874 msg.toAgentID = remoteClient.AgentId.Guid;
875 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
876 msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName;
877 msg.message = data.noticeData.Subject + "|" + data.Message;
878 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested;
879 msg.fromGroup = true;
880 msg.offline = (byte)0;
881 msg.ParentEstateID = 0;
882 msg.Position = Vector3.Zero;
883 msg.RegionID = UUID.Zero.Guid;
884 msg.binaryBucket = data.BinaryBucket;
885
886 OutgoingInstantMessage(msg, remoteClient.AgentId);
887 }
888
889 }
890
891 public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
892 {
893 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
894
895 GridInstantMessage msg = new GridInstantMessage();
896 msg.imSessionID = UUID.Zero.Guid;
897 msg.toAgentID = agentID.Guid;
898 msg.dialog = dialog;
899 // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice;
900 msg.fromGroup = true;
901 msg.offline = (byte)1; // Allow this message to be stored for offline use
902 msg.ParentEstateID = 0;
903 msg.Position = Vector3.Zero;
904 msg.RegionID = UUID.Zero.Guid;
905
906 GroupNoticeInfo info = m_groupData.GetGroupNotice(null, groupNoticeID);
907 if (info != null)
908 {
909 msg.fromAgentID = info.GroupID.Guid;
910 msg.timestamp = info.noticeData.Timestamp;
911 msg.fromAgentName = info.noticeData.FromName;
912 msg.message = info.noticeData.Subject + "|" + info.Message;
913 msg.binaryBucket = info.BinaryBucket;
914 }
915 else
916 {
917 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID);
918 msg.fromAgentID = UUID.Zero.Guid;
919 msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ;
920 msg.fromAgentName = string.Empty;
921 msg.message = string.Empty;
922 msg.binaryBucket = new byte[0];
923 }
924
925 return msg;
926 }
927
928 public void SendAgentGroupDataUpdate(IClientAPI remoteClient)
929 {
930 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
931
932 // Send agent information about his groups
933 SendAgentGroupDataUpdate(remoteClient, remoteClient.AgentId);
934 }
935
936 public void JoinGroupRequest(IClientAPI remoteClient, UUID groupID)
937 {
938 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
939
940 // Should check to see if OpenEnrollment, or if there's an outstanding invitation
941 m_groupData.AddAgentToGroup(GetClientGroupRequestID(remoteClient), remoteClient.AgentId, groupID, UUID.Zero);
942
943 remoteClient.SendJoinGroupReply(groupID, true);
944
945 // Should this send updates to everyone in the group?
946 SendAgentGroupDataUpdate(remoteClient, remoteClient.AgentId);
947 }
948
949 public void LeaveGroupRequest(IClientAPI remoteClient, UUID groupID)
950 {
951 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
952
953 m_groupData.RemoveAgentFromGroup(GetClientGroupRequestID(remoteClient), remoteClient.AgentId, groupID);
954
955 remoteClient.SendLeaveGroupReply(groupID, true);
956
957 remoteClient.SendAgentDropGroup(groupID);
958
959 // SL sends out notifcations to the group messaging session that the person has left
960 // Should this also update everyone who is in the group?
961 SendAgentGroupDataUpdate(remoteClient, remoteClient.AgentId);
962 }
963
964 public void EjectGroupMemberRequest(IClientAPI remoteClient, UUID groupID, UUID ejecteeID)
965 {
966 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
967
968 GroupRequestID grID = GetClientGroupRequestID(remoteClient);
969
970 // Todo: Security check?
971 m_groupData.RemoveAgentFromGroup(grID, ejecteeID, groupID);
972
973 remoteClient.SendEjectGroupMemberReply(remoteClient.AgentId, groupID, true);
974
975 GroupRecord groupInfo = m_groupData.GetGroupRecord(grID, groupID, null);
976 UserProfileData userProfile = m_sceneList[0].CommsManager.UserService.GetUserProfile(ejecteeID);
977
978 if ((groupInfo == null) || (userProfile == null))
979 {
980 return;
981 }
982
983
984 // Send Message to Ejectee
985 GridInstantMessage msg = new GridInstantMessage();
986
987 msg.imSessionID = UUID.Zero.Guid;
988 msg.fromAgentID = remoteClient.AgentId.Guid;
989 // msg.fromAgentID = info.GroupID;
990 msg.toAgentID = ejecteeID.Guid;
991 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
992 msg.timestamp = 0;
993 msg.fromAgentName = remoteClient.Name;
994 msg.message = string.Format("You have been ejected from '{1}' by {0}.", remoteClient.Name, groupInfo.GroupName);
995 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageFromAgent;
996 msg.fromGroup = false;
997 msg.offline = (byte)0;
998 msg.ParentEstateID = 0;
999 msg.Position = Vector3.Zero;
1000 msg.RegionID = remoteClient.Scene.RegionInfo.RegionID.Guid;
1001 msg.binaryBucket = new byte[0];
1002 OutgoingInstantMessage(msg, ejecteeID);
1003
1004
1005 // Message to ejector
1006 // Interop, received special 210 code for ejecting a group member
1007 // this only works within the comms servers domain, and won't work hypergrid
1008 // TODO:FIXME: Use a presense server of some kind to find out where the
1009 // client actually is, and try contacting that region directly to notify them,
1010 // or provide the notification via xmlrpc update queue
1011
1012 msg = new GridInstantMessage();
1013 msg.imSessionID = UUID.Zero.Guid;
1014 msg.fromAgentID = remoteClient.AgentId.Guid;
1015 msg.toAgentID = remoteClient.AgentId.Guid;
1016 msg.timestamp = 0;
1017 msg.fromAgentName = remoteClient.Name;
1018 if (userProfile != null)
1019 {
1020 msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", remoteClient.Name, groupInfo.GroupName, userProfile.Name);
1021 }
1022 else
1023 {
1024 msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", remoteClient.Name, groupInfo.GroupName, "Unknown member");
1025 }
1026 msg.dialog = (byte)210; //interop
1027 msg.fromGroup = false;
1028 msg.offline = (byte)0;
1029 msg.ParentEstateID = 0;
1030 msg.Position = Vector3.Zero;
1031 msg.RegionID = remoteClient.Scene.RegionInfo.RegionID.Guid;
1032 msg.binaryBucket = new byte[0];
1033 OutgoingInstantMessage(msg, remoteClient.AgentId);
1034
1035
1036 // SL sends out messages to everyone in the group
1037 // Who all should receive updates and what should they be updated with?
1038 UpdateAllClientsWithGroupInfo(ejecteeID);
1039 }
1040
1041 public void InviteGroupRequest(IClientAPI remoteClient, UUID groupID, UUID invitedAgentID, UUID roleID)
1042 {
1043 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1044
1045 // Todo: Security check, probably also want to send some kind of notification
1046 UUID InviteID = UUID.Random();
1047 GroupRequestID grid = GetClientGroupRequestID(remoteClient);
1048
1049 m_groupData.AddAgentToGroupInvite(grid, InviteID, groupID, roleID, invitedAgentID);
1050
1051 // Check to see if the invite went through, if it did not then it's possible
1052 // the remoteClient did not validate or did not have permission to invite.
1053 GroupInviteInfo inviteInfo = m_groupData.GetAgentToGroupInvite(grid, InviteID);
1054
1055 if (inviteInfo != null)
1056 {
1057 if (m_msgTransferModule != null)
1058 {
1059 Guid inviteUUID = InviteID.Guid;
1060
1061 GridInstantMessage msg = new GridInstantMessage();
1062
1063 msg.imSessionID = inviteUUID;
1064
1065 // msg.fromAgentID = remoteClient.AgentId.Guid;
1066 msg.fromAgentID = groupID.Guid;
1067 msg.toAgentID = invitedAgentID.Guid;
1068 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1069 msg.timestamp = 0;
1070 msg.fromAgentName = remoteClient.Name;
1071 msg.message = string.Format("{0} has invited you to join a group. There is no cost to join this group.", remoteClient.Name);
1072 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation;
1073 msg.fromGroup = true;
1074 msg.offline = (byte)0;
1075 msg.ParentEstateID = 0;
1076 msg.Position = Vector3.Zero;
1077 msg.RegionID = remoteClient.Scene.RegionInfo.RegionID.Guid;
1078 msg.binaryBucket = new byte[20];
1079
1080 OutgoingInstantMessage(msg, invitedAgentID);
1081 }
1082 }
1083 }
1084
1085 #endregion
1086
1087 #region Client/Update Tools
1088
1089 /// <summary>
1090 /// Try to find an active IClientAPI reference for agentID giving preference to root connections
1091 /// </summary>
1092 private IClientAPI GetActiveClient(UUID agentID)
1093 {
1094 IClientAPI child = null;
1095
1096 // Try root avatar first
1097 foreach (Scene scene in m_sceneList)
1098 {
1099 if (scene.Entities.ContainsKey(agentID) &&
1100 scene.Entities[agentID] is ScenePresence)
1101 {
1102 ScenePresence user = (ScenePresence)scene.Entities[agentID];
1103 if (!user.IsChildAgent)
1104 {
1105 return user.ControllingClient;
1106 }
1107 else
1108 {
1109 child = user.ControllingClient;
1110 }
1111 }
1112 }
1113
1114 // If we didn't find a root, then just return whichever child we found, or null if none
1115 return child;
1116 }
1117
1118 private GroupRequestID GetClientGroupRequestID(IClientAPI client)
1119 {
1120 if (client == null)
1121 {
1122 return new GroupRequestID();
1123 }
1124
1125 lock (m_clientRequestIDInfo)
1126 {
1127 if (!m_clientRequestIDInfo.ContainsKey(client.AgentId))
1128 {
1129 GroupRequestIDInfo info = new GroupRequestIDInfo();
1130 info.RequestID.AgentID = client.AgentId;
1131 info.RequestID.SessionID = client.SessionId;
1132
1133 UserProfileData userProfile = m_sceneList[0].CommsManager.UserService.GetUserProfile(client.AgentId);
1134 if (userProfile == null)
1135 {
1136 // This should be impossible. If I've been passed a reference to a client
1137 // that client should be registered with the UserService. So something
1138 // is horribly wrong somewhere.
1139
1140 m_log.WarnFormat("[GROUPS]: Could not find a user profile for {0} / {1}", client.Name, client.AgentId);
1141
1142 // Default to local user service and hope for the best?
1143 info.RequestID.UserServiceURL = m_sceneList[0].CommsManager.NetworkServersInfo.UserURL;
1144
1145 }
1146 else if (userProfile is ForeignUserProfileData)
1147 {
1148 // They aren't from around here
1149 ForeignUserProfileData fupd = (ForeignUserProfileData)userProfile;
1150 info.RequestID.UserServiceURL = fupd.UserServerURI;
1151 }
1152 else
1153 {
1154 // They're a local user, use this:
1155 info.RequestID.UserServiceURL = m_sceneList[0].CommsManager.NetworkServersInfo.UserURL;
1156 }
1157
1158 m_clientRequestIDInfo.Add(client.AgentId, info);
1159 }
1160
1161 m_clientRequestIDInfo[client.AgentId].LastUsedTMStamp = DateTime.Now;
1162 }
1163 return m_clientRequestIDInfo[client.AgentId].RequestID;
1164 }
1165
1166 /// <summary>
1167 /// Send 'remoteClient' the group membership 'data' for agent 'dataForAgentID'.
1168 /// </summary>
1169 private void SendGroupMembershipInfoViaCaps(IClientAPI remoteClient, UUID dataForAgentID, GroupMembershipData[] data)
1170 {
1171 if (m_debugEnabled) m_log.InfoFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1172
1173 OSDArray AgentData = new OSDArray(1);
1174 OSDMap AgentDataMap = new OSDMap(1);
1175 AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID));
1176 AgentData.Add(AgentDataMap);
1177
1178
1179 OSDArray GroupData = new OSDArray(data.Length);
1180 OSDArray NewGroupData = new OSDArray(data.Length);
1181
1182 foreach (GroupMembershipData membership in data)
1183 {
1184 OSDMap GroupDataMap = new OSDMap(6);
1185 OSDMap NewGroupDataMap = new OSDMap(1);
1186
1187 GroupDataMap.Add("GroupID", OSD.FromUUID(membership.GroupID));
1188 GroupDataMap.Add("GroupPowers", OSD.FromBinary(membership.GroupPowers));
1189 GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(membership.AcceptNotices));
1190 GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(membership.GroupPicture));
1191 GroupDataMap.Add("Contribution", OSD.FromInteger(membership.Contribution));
1192 GroupDataMap.Add("GroupName", OSD.FromString(membership.GroupName));
1193 NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(membership.ListInProfile));
1194
1195 GroupData.Add(GroupDataMap);
1196 NewGroupData.Add(NewGroupDataMap);
1197 }
1198
1199 OSDMap llDataStruct = new OSDMap(3);
1200 llDataStruct.Add("AgentData", AgentData);
1201 llDataStruct.Add("GroupData", GroupData);
1202 llDataStruct.Add("NewGroupData", NewGroupData);
1203
1204 IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>();
1205
1206 if (queue != null)
1207 {
1208 queue.Enqueue(EventQueueHelper.buildEvent("AgentGroupDataUpdate", llDataStruct), remoteClient.AgentId);
1209 }
1210
1211 }
1212
1213 private void SendScenePresenceUpdate(UUID AgentID, string Title)
1214 {
1215 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Updating scene title for {0} with title: {1}", AgentID, Title);
1216
1217 ScenePresence presence = null;
1218 lock (m_sceneList)
1219 {
1220 foreach (Scene scene in m_sceneList)
1221 {
1222 presence = scene.GetScenePresence(AgentID);
1223 if (presence != null)
1224 {
1225 presence.Grouptitle = Title;
1226
1227 // FixMe: Ter suggests a "Schedule" method that I can't find.
1228 presence.SendFullUpdateToAllClients();
1229 }
1230 }
1231 }
1232 }
1233
1234 /// <summary>
1235 /// Send updates to all clients who might be interested in groups data for dataForClientID
1236 /// </summary>
1237 private void UpdateAllClientsWithGroupInfo(UUID dataForClientID)
1238 {
1239 if (m_debugEnabled) m_log.InfoFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1240
1241 // TODO: Probably isn't nessesary to update every client in every scene.
1242 // Need to examine client updates and do only what's nessesary.
1243 lock (m_sceneList)
1244 {
1245 foreach (Scene scene in m_sceneList)
1246 {
1247 scene.ForEachClient(delegate(IClientAPI client) { SendAgentGroupDataUpdate(client, dataForClientID); });
1248 }
1249 }
1250 }
1251
1252 /// <summary>
1253 /// Update remoteClient with group information about dataForAgentID
1254 /// </summary>
1255 private void SendAgentGroupDataUpdate(IClientAPI remoteClient, UUID dataForAgentID)
1256 {
1257 if (m_debugEnabled) m_log.InfoFormat("[GROUPS]: {0} called for {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Name);
1258
1259 // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
1260
1261 OnAgentDataUpdateRequest(remoteClient, dataForAgentID, UUID.Zero);
1262
1263
1264 // Need to send a group membership update to the client
1265 // UDP version doesn't seem to behave nicely. But we're going to send it out here
1266 // with an empty group membership to hopefully remove groups being displayed due
1267 // to the core Groups Stub
1268 remoteClient.SendGroupMembership(new GroupMembershipData[0]);
1269
1270 GroupMembershipData[] membershipData = m_groupData.GetAgentGroupMemberships(GetClientGroupRequestID(remoteClient), dataForAgentID).ToArray();
1271
1272 SendGroupMembershipInfoViaCaps(remoteClient, dataForAgentID, membershipData);
1273 remoteClient.SendAvatarGroupsReply(dataForAgentID, membershipData);
1274
1275 }
1276
1277 private void SendAgentDataUpdate(IClientAPI remoteClient, UUID dataForAgentID, UUID activeGroupID, string activeGroupName, ulong activeGroupPowers, string activeGroupTitle)
1278 {
1279 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1280
1281 // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
1282 UserProfileData userProfile = m_sceneList[0].CommsManager.UserService.GetUserProfile(dataForAgentID);
1283 string firstname, lastname;
1284 if (userProfile != null)
1285 {
1286 firstname = userProfile.FirstName;
1287 lastname = userProfile.SurName;
1288 }
1289 else
1290 {
1291 firstname = "Unknown";
1292 lastname = "Unknown";
1293 }
1294
1295 remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname,
1296 lastname, activeGroupPowers, activeGroupName,
1297 activeGroupTitle);
1298 }
1299
1300 #endregion
1301
1302 #region IM Backed Processes
1303
1304 private void OutgoingInstantMessage(GridInstantMessage msg, UUID msgTo)
1305 {
1306 if (m_debugEnabled) m_log.InfoFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1307
1308 IClientAPI localClient = GetActiveClient(msgTo);
1309 if (localClient != null)
1310 {
1311 if (m_debugEnabled) m_log.InfoFormat("[GROUPS]: MsgTo ({0}) is local, delivering directly", localClient.Name);
1312 localClient.SendInstantMessage(msg);
1313 }
1314 else
1315 {
1316 if (m_debugEnabled) m_log.InfoFormat("[GROUPS]: MsgTo ({0}) is not local, delivering via TransferModule", msgTo);
1317 m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Message Sent: {0}", success?"Succeeded":"Failed"); });
1318 }
1319 }
1320
1321 public void NotifyChange(UUID groupID)
1322 {
1323 // Notify all group members of a chnge in group roles and/or
1324 // permissions
1325 //
1326 }
1327
1328 #endregion
1329 }
1330
1331}