* Refactored permissions handling to extract info out of permisisons block in ClientView
* Changed some uint constants to Enum valuesThreadPoolClientBranch
parent
8d37e91454
commit
e0424254bd
|
@ -406,9 +406,7 @@ namespace OpenSim.Framework
|
|||
// We keep all this information for fraud purposes in the future.
|
||||
public delegate void MoneyBalanceRequest(IClientAPI remoteClient, LLUUID agentID, LLUUID sessionID, LLUUID TransactionID);
|
||||
|
||||
public delegate void ObjectPermissions(
|
||||
IClientAPI remoteClinet, LLUUID AgentID, LLUUID SessionID,
|
||||
List<ObjectPermissionsPacket.ObjectDataBlock> permChanges);
|
||||
public delegate void ObjectPermissions(IClientAPI controller, LLUUID agentID, LLUUID sessionID, byte field, uint localId, uint mask, byte set);
|
||||
|
||||
public interface IClientAPI
|
||||
{
|
||||
|
|
|
@ -51,10 +51,10 @@ namespace OpenSim.Region.ClientStack
|
|||
/// </summary>
|
||||
public class ClientView : IClientAPI
|
||||
{
|
||||
// ~ClientView()
|
||||
// {
|
||||
// System.Console.WriteLine("[CLIENTVIEW]: Destructor called");
|
||||
// }
|
||||
// ~ClientView()
|
||||
// {
|
||||
// System.Console.WriteLine("[CLIENTVIEW]: Destructor called");
|
||||
// }
|
||||
|
||||
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
|
@ -1006,7 +1006,7 @@ namespace OpenSim.Region.ClientStack
|
|||
int MAX_ITEMS_PER_PACKET = 6;
|
||||
|
||||
Encoding enc = Encoding.ASCII;
|
||||
uint FULL_MASK_PERMISSIONS = 2147483647;
|
||||
uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All;
|
||||
InventoryDescendentsPacket descend;
|
||||
int i;
|
||||
int count;
|
||||
|
@ -1179,7 +1179,7 @@ namespace OpenSim.Region.ClientStack
|
|||
public void SendInventoryItemDetails(LLUUID ownerID, InventoryItemBase item)
|
||||
{
|
||||
Encoding enc = Encoding.ASCII;
|
||||
uint FULL_MASK_PERMISSIONS = 2147483647;
|
||||
uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All;
|
||||
FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply);
|
||||
// TODO: don't create new blocks if recycling an old packet
|
||||
inventoryReply.AgentData.AgentID = AgentId;
|
||||
|
@ -1221,7 +1221,7 @@ namespace OpenSim.Region.ClientStack
|
|||
public void SendInventoryItemCreateUpdate(InventoryItemBase Item)
|
||||
{
|
||||
Encoding enc = Encoding.ASCII;
|
||||
uint FULL_MASK_PERMISSIONS = 2147483647;
|
||||
uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All;
|
||||
UpdateCreateInventoryItemPacket InventoryReply = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket(PacketType.UpdateCreateInventoryItem);
|
||||
// TODO: don't create new blocks if recycling an old packet
|
||||
InventoryReply.AgentData.AgentID = AgentId;
|
||||
|
@ -3100,15 +3100,25 @@ namespace OpenSim.Region.ClientStack
|
|||
}
|
||||
break;
|
||||
case PacketType.ObjectPermissions:
|
||||
m_log.Warn("[CLIENT]: unhandled packet " + PacketType.ObjectPermissions.ToString());
|
||||
if (OnObjectPermissions != null)
|
||||
{
|
||||
ObjectPermissionsPacket newobjPerms = (ObjectPermissionsPacket)Pack;
|
||||
|
||||
List<ObjectPermissionsPacket.ObjectDataBlock> permChanges =
|
||||
new List<ObjectPermissionsPacket.ObjectDataBlock>();
|
||||
LLUUID AgentID = newobjPerms.AgentData.AgentID;
|
||||
LLUUID SessionID = newobjPerms.AgentData.SessionID;
|
||||
|
||||
for (int i = 0; i < newobjPerms.ObjectData.Length; i++)
|
||||
{
|
||||
permChanges.Add(newobjPerms.ObjectData[i]);
|
||||
ObjectPermissionsPacket.ObjectDataBlock permChanges = newobjPerms.ObjectData[i];
|
||||
|
||||
|
||||
byte field = permChanges.Field;
|
||||
uint localID = permChanges.ObjectLocalID;
|
||||
uint mask = permChanges.Mask;
|
||||
byte set = permChanges.Set;
|
||||
|
||||
OnObjectPermissions(this, AgentID, SessionID, field, localID, mask, set);
|
||||
}
|
||||
}
|
||||
|
||||
// Here's our data,
|
||||
|
@ -3123,12 +3133,6 @@ namespace OpenSim.Region.ClientStack
|
|||
// Unfortunately, we have to pass the event the packet because objData is an array
|
||||
// That means multiple object perms may be updated in a single packet.
|
||||
|
||||
LLUUID AgentID = newobjPerms.AgentData.AgentID;
|
||||
LLUUID SessionID = newobjPerms.AgentData.SessionID;
|
||||
if (OnObjectPermissions != null)
|
||||
{
|
||||
OnObjectPermissions(this, AgentID, SessionID, permChanges);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ using OpenSim.Region.Environment.Modules;
|
|||
using OpenSim.Region.Environment.Scenes.Scripting;
|
||||
using OpenSim.Region.Physics.Manager;
|
||||
using OpenSim.Region.Terrain;
|
||||
using Caps=OpenSim.Region.Capabilities.Caps;
|
||||
using Image=System.Drawing.Image;
|
||||
using Timer=System.Timers.Timer;
|
||||
using Caps = OpenSim.Region.Capabilities.Caps;
|
||||
using Image = System.Drawing.Image;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace OpenSim.Region.Environment.Scenes
|
||||
{
|
||||
|
@ -193,10 +193,10 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
}
|
||||
|
||||
// Local reference to the objects in the scene (which are held in innerScene)
|
||||
// public Dictionary<LLUUID, SceneObjectGroup> Objects
|
||||
// {
|
||||
// get { return m_innerScene.SceneObjects; }
|
||||
// }
|
||||
// public Dictionary<LLUUID, SceneObjectGroup> Objects
|
||||
// {
|
||||
// get { return m_innerScene.SceneObjects; }
|
||||
// }
|
||||
|
||||
// Reference to all of the agents in the scene (root and child)
|
||||
protected Dictionary<LLUUID, ScenePresence> m_scenePresences
|
||||
|
@ -205,11 +205,11 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
set { m_innerScene.ScenePresences = value; }
|
||||
}
|
||||
|
||||
// protected Dictionary<LLUUID, SceneObjectGroup> m_sceneObjects
|
||||
// {
|
||||
// get { return m_innerScene.SceneObjects; }
|
||||
// set { m_innerScene.SceneObjects = value; }
|
||||
// }
|
||||
// protected Dictionary<LLUUID, SceneObjectGroup> m_sceneObjects
|
||||
// {
|
||||
// get { return m_innerScene.SceneObjects; }
|
||||
// set { m_innerScene.SceneObjects = value; }
|
||||
// }
|
||||
|
||||
public Dictionary<LLUUID, EntityBase> Entities
|
||||
{
|
||||
|
@ -278,7 +278,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
//m_sceneObjects = new Dictionary<LLUUID, SceneObjectGroup>();
|
||||
|
||||
m_log.Info("[SCENE]: Creating LandMap");
|
||||
Terrain = new TerrainEngine((int) RegionInfo.RegionLocX, (int) RegionInfo.RegionLocY);
|
||||
Terrain = new TerrainEngine((int)RegionInfo.RegionLocX, (int)RegionInfo.RegionLocY);
|
||||
|
||||
httpListener = httpServer;
|
||||
m_dumpAssetsToFile = dumpAssetsToFile;
|
||||
|
@ -314,7 +314,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
}
|
||||
if (OSString.Length > 45)
|
||||
{
|
||||
OSString = OSString.Substring(0,45);
|
||||
OSString = OSString.Substring(0, 45);
|
||||
}
|
||||
|
||||
m_simulatorVersion = "OpenSimulator v0.5-SVN on " + OSString + " ChilTasks:" + m_sendTasksToChild.ToString() + " PhysPrim:" + m_physicalPrim.ToString();
|
||||
|
@ -383,7 +383,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
int resultX = Math.Abs((int)otherRegion.RegionLocX - (int)RegionInfo.RegionLocX);
|
||||
int resultY = Math.Abs((int)otherRegion.RegionLocY - (int)RegionInfo.RegionLocY);
|
||||
if ((resultX <= 1) &&
|
||||
( resultY <= 1))
|
||||
(resultY <= 1))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -434,11 +434,11 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
// Now we figure out what to set the timer to that does the notifications and calls, RestartNow()
|
||||
m_restartTimer.Interval = 15000;
|
||||
m_incrementsof15seconds = (int) seconds/15;
|
||||
m_incrementsof15seconds = (int)seconds / 15;
|
||||
m_RestartTimerCounter = 0;
|
||||
m_restartTimer.AutoReset = true;
|
||||
m_restartTimer.Elapsed += new ElapsedEventHandler(RestartTimer_Elapsed);
|
||||
m_log.Error("[REGION]: Restarting Region in " + (seconds/60) + " minutes");
|
||||
m_log.Error("[REGION]: Restarting Region in " + (seconds / 60) + " minutes");
|
||||
m_restartTimer.Start();
|
||||
SendRegionMessageFromEstateTools(LLUUID.Random(), LLUUID.Random(), String.Empty, RegionInfo.RegionName + ": Restarting in 2 Minutes");
|
||||
//SendGeneralAlert(RegionInfo.RegionName + ": Restarting in 2 Minutes");
|
||||
|
@ -612,7 +612,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
m_log.Debug("[SCENE]: Starting timer");
|
||||
m_heartbeatTimer.Enabled = true;
|
||||
m_heartbeatTimer.Interval = (int) (m_timespan*1000);
|
||||
m_heartbeatTimer.Interval = (int)(m_timespan * 1000);
|
||||
m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
|
||||
}
|
||||
|
||||
|
@ -684,15 +684,15 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
|
||||
|
||||
physicsMS2 = System.Environment.TickCount;
|
||||
if ((m_frame%m_update_physics == 0) && m_physics_enabled)
|
||||
if ((m_frame % m_update_physics == 0) && m_physics_enabled)
|
||||
m_innerScene.UpdatePreparePhysics();
|
||||
physicsMS2 = System.Environment.TickCount - physicsMS2;
|
||||
|
||||
if (m_frame%m_update_entitymovement == 0)
|
||||
if (m_frame % m_update_entitymovement == 0)
|
||||
m_innerScene.UpdateEntityMovement();
|
||||
|
||||
physicsMS = System.Environment.TickCount;
|
||||
if ((m_frame%m_update_physics == 0) && m_physics_enabled)
|
||||
if ((m_frame % m_update_physics == 0) && m_physics_enabled)
|
||||
physicsFPS = m_innerScene.UpdatePhysics(
|
||||
Math.Max(SinceLastFrame.TotalSeconds, m_timespan)
|
||||
);
|
||||
|
@ -701,19 +701,19 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
physicsMS += physicsMS2;
|
||||
|
||||
otherMS = System.Environment.TickCount;
|
||||
if (m_frame%m_update_entities == 0)
|
||||
if (m_frame % m_update_entities == 0)
|
||||
m_innerScene.UpdateEntities();
|
||||
|
||||
if (m_frame%m_update_events == 0)
|
||||
if (m_frame % m_update_events == 0)
|
||||
UpdateEvents();
|
||||
|
||||
if (m_frame%m_update_backup == 0)
|
||||
if (m_frame % m_update_backup == 0)
|
||||
UpdateStorageBackup();
|
||||
|
||||
if (m_frame%m_update_terrain == 0)
|
||||
if (m_frame % m_update_terrain == 0)
|
||||
UpdateTerrain();
|
||||
|
||||
if (m_frame%m_update_land == 0)
|
||||
if (m_frame % m_update_land == 0)
|
||||
UpdateLand();
|
||||
otherMS = System.Environment.TickCount - otherMS;
|
||||
// if (m_frame%m_update_avatars == 0)
|
||||
|
@ -746,7 +746,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
updateLock.ReleaseMutex();
|
||||
|
||||
m_timedilation = m_timespan/(float) SinceLastFrame.TotalSeconds;
|
||||
m_timedilation = m_timespan / (float)SinceLastFrame.TotalSeconds;
|
||||
m_lastupdate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
@ -871,10 +871,10 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
public void ExportWorldMap(string fileName)
|
||||
{
|
||||
List<MapBlockData> mapBlocks =
|
||||
CommsManager.GridService.RequestNeighbourMapBlocks((int) (RegionInfo.RegionLocX - 9),
|
||||
(int) (RegionInfo.RegionLocY - 9),
|
||||
(int) (RegionInfo.RegionLocX + 9),
|
||||
(int) (RegionInfo.RegionLocY + 9));
|
||||
CommsManager.GridService.RequestNeighbourMapBlocks((int)(RegionInfo.RegionLocX - 9),
|
||||
(int)(RegionInfo.RegionLocY - 9),
|
||||
(int)(RegionInfo.RegionLocX + 9),
|
||||
(int)(RegionInfo.RegionLocY + 9));
|
||||
List<AssetBase> textures = new List<AssetBase>();
|
||||
List<Image> bitImages = new List<Image>();
|
||||
|
||||
|
@ -909,9 +909,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
|
||||
for (int i = 0; i < mapBlocks.Count; i++)
|
||||
{
|
||||
ushort x = (ushort) ((mapBlocks[i].X - RegionInfo.RegionLocX) + 10);
|
||||
ushort y = (ushort) ((mapBlocks[i].Y - RegionInfo.RegionLocY) + 10);
|
||||
g.DrawImage(bitImages[i], (x*128), (y*128), 128, 128);
|
||||
ushort x = (ushort)((mapBlocks[i].X - RegionInfo.RegionLocX) + 10);
|
||||
ushort y = (ushort)((mapBlocks[i].Y - RegionInfo.RegionLocY) + 10);
|
||||
g.DrawImage(bitImages[i], (x * 128), (y * 128), 128, 128);
|
||||
}
|
||||
mapTexture.Save(fileName, ImageFormat.Jpeg);
|
||||
}
|
||||
|
@ -1192,9 +1192,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
PrimitiveBaseShape treeShape = new PrimitiveBaseShape();
|
||||
treeShape.PathCurve = 16;
|
||||
treeShape.PathEnd = 49900;
|
||||
treeShape.PCode = newTree ? (byte) PCode.NewTree : (byte) PCode.Tree;
|
||||
treeShape.PCode = newTree ? (byte)PCode.NewTree : (byte)PCode.Tree;
|
||||
treeShape.Scale = scale;
|
||||
treeShape.State = (byte) treeType;
|
||||
treeShape.State = (byte)treeType;
|
||||
return AddNewPrim(uuid, position, rotation, treeShape);
|
||||
}
|
||||
|
||||
|
@ -1680,7 +1680,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
m_innerScene.removeUserCount(true);
|
||||
}
|
||||
// Tell a single agent to disconnect from the region.
|
||||
libsecondlife.Packets.DisableSimulatorPacket disable = (libsecondlife.Packets.DisableSimulatorPacket) PacketPool.Instance.GetPacket(libsecondlife.Packets.PacketType.DisableSimulator);
|
||||
libsecondlife.Packets.DisableSimulatorPacket disable = (libsecondlife.Packets.DisableSimulatorPacket)PacketPool.Instance.GetPacket(libsecondlife.Packets.PacketType.DisableSimulator);
|
||||
presence.ControllingClient.OutPacket(disable, ThrottleOutPacketType.Task);
|
||||
presence.ControllingClient.Close(true);
|
||||
}
|
||||
|
@ -1794,9 +1794,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
/// <param name="mod"></param>
|
||||
public void RegisterModuleInterface<M>(M mod)
|
||||
{
|
||||
if (!ModuleInterfaces.ContainsKey(typeof (M)))
|
||||
if (!ModuleInterfaces.ContainsKey(typeof(M)))
|
||||
{
|
||||
ModuleInterfaces.Add(typeof (M), mod);
|
||||
ModuleInterfaces.Add(typeof(M), mod);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1806,9 +1806,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
/// <returns></returns>
|
||||
public T RequestModuleInterface<T>()
|
||||
{
|
||||
if (ModuleInterfaces.ContainsKey(typeof (T)))
|
||||
if (ModuleInterfaces.ContainsKey(typeof(T)))
|
||||
{
|
||||
return (T) ModuleInterfaces[typeof (T)];
|
||||
return (T)ModuleInterfaces[typeof(T)];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1851,11 +1851,11 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
}
|
||||
}
|
||||
|
||||
public void SendDialogToUser(LLUUID avatarID, string objectName, LLUUID objectID, LLUUID ownerID,string message,LLUUID TextureID,int ch,string[] buttonlabels)
|
||||
public void SendDialogToUser(LLUUID avatarID, string objectName, LLUUID objectID, LLUUID ownerID, string message, LLUUID TextureID, int ch, string[] buttonlabels)
|
||||
{
|
||||
if (m_scenePresences.ContainsKey(avatarID))
|
||||
{
|
||||
m_scenePresences[avatarID].ControllingClient.SendDialog(objectName,objectID,ownerID,message,TextureID,ch,buttonlabels);
|
||||
m_scenePresences[avatarID].ControllingClient.SendDialog(objectName, objectID, ownerID, message, TextureID, ch, buttonlabels);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1895,7 +1895,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
if (obj is SceneObjectGroup)
|
||||
{
|
||||
m_eventManager.TriggerParcelPrimCountAdd((SceneObjectGroup) obj);
|
||||
m_eventManager.TriggerParcelPrimCountAdd((SceneObjectGroup)obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1910,9 +1910,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
/// </summary>
|
||||
/// <param name="message">object containing the instant message data</param>
|
||||
/// <returns>void</returns>
|
||||
public void TriggerGridInstantMessage(GridInstantMessage message,InstantMessageReceiver options)
|
||||
public void TriggerGridInstantMessage(GridInstantMessage message, InstantMessageReceiver options)
|
||||
{
|
||||
m_eventManager.TriggerGridInstantMessage(message,options);
|
||||
m_eventManager.TriggerGridInstantMessage(message, options);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2138,29 +2138,16 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="controller"></param>
|
||||
/// <param name="agentID"></param>
|
||||
/// <param name="sessionID"></param>
|
||||
/// <param name="permChanges"></param>
|
||||
public void HandleObjectPermissionsUpdate(IClientAPI controller, LLUUID agentID, LLUUID sessionID,
|
||||
List<ObjectPermissionsPacket.ObjectDataBlock> permChanges)
|
||||
public void HandleObjectPermissionsUpdate(IClientAPI controller, LLUUID agentID, LLUUID sessionID, byte field, uint localId, uint mask, byte set)
|
||||
{
|
||||
// Check for spoofing.. since this is permissions we're talking about here!
|
||||
if ((controller.SessionId == sessionID) && (controller.AgentId == agentID))
|
||||
{
|
||||
for (int i = 0; i < permChanges.Count; i++)
|
||||
{
|
||||
|
||||
// Tell the object to do permission update
|
||||
byte field = permChanges[i].Field;
|
||||
uint localID = permChanges[i].ObjectLocalID;
|
||||
uint mask = permChanges[i].Mask;
|
||||
byte addRemTF = permChanges[i].Set;
|
||||
SceneObjectGroup chObjectGroup = GetGroupByPrim(localID);
|
||||
chObjectGroup.UpdatePermissions(agentID, field, localID, mask, addRemTF);
|
||||
}
|
||||
SceneObjectGroup chObjectGroup = GetGroupByPrim(localId);
|
||||
chObjectGroup.UpdatePermissions(agentID, field, localId, mask, set);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2226,7 +2213,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
if (ent is SceneObjectGroup)
|
||||
{
|
||||
((SceneObjectGroup) ent).ScheduleGroupForFullUpdate();
|
||||
((SceneObjectGroup)ent).ScheduleGroupForFullUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2246,7 +2233,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
if (ent is SceneObjectGroup)
|
||||
{
|
||||
SceneObjectPart part = ((SceneObjectGroup) ent).GetChildPart(((SceneObjectGroup) ent).UUID);
|
||||
SceneObjectPart part = ((SceneObjectGroup)ent).GetChildPart(((SceneObjectGroup)ent).UUID);
|
||||
if (part != null)
|
||||
{
|
||||
if (part.Name == cmdparams[0])
|
||||
|
@ -2493,20 +2480,20 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
///
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
// public void ForEachObject(Action<SceneObjectGroup> action)
|
||||
// {
|
||||
// List<SceneObjectGroup> presenceList;
|
||||
//
|
||||
// lock (m_sceneObjects)
|
||||
// {
|
||||
// presenceList = new List<SceneObjectGroup>(m_sceneObjects.Values);
|
||||
// }
|
||||
//
|
||||
// foreach (SceneObjectGroup presence in presenceList)
|
||||
// {
|
||||
// action(presence);
|
||||
// }
|
||||
// }
|
||||
// public void ForEachObject(Action<SceneObjectGroup> action)
|
||||
// {
|
||||
// List<SceneObjectGroup> presenceList;
|
||||
//
|
||||
// lock (m_sceneObjects)
|
||||
// {
|
||||
// presenceList = new List<SceneObjectGroup>(m_sceneObjects.Values);
|
||||
// }
|
||||
//
|
||||
// foreach (SceneObjectGroup presence in presenceList)
|
||||
// {
|
||||
// action(presence);
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue