예제 #1
0
 /// <summary>Parses some arguments and acts upon them</summary>
 /// <param name="args">Array of strings, directly from the command line</param>
 /// <remarks>We have no arguments for now, this is mostly a placeholder (gwyneth 20220425)</remarks>
 private static void ParseArguments(string[] args)
 {
     // Very, very basic and naïve args passing.
     // There is probably a library to deal with this (gwyneth 20220425)
     if (args.Count() == 0)
     {
         DebugUtilities.WriteDebug("Good, no command-line arguments to parse.");
     }
     else if (args.Count() == 1)
     {
         if (args[0] == "--help")
         {
             DebugUtilities.WriteSpecial("Usage: RESTbot --config /path/to/configfile|--debug|--help");
             Environment.Exit(10);
         }
         else if (args[0] == "--debug")
         {
             DebugUtilities.WriteSpecial("`--debug` doesn't work yet...");
         }
     }
     else if (args.Count() == 2)
     {
         if (args[0] == "--config")
         {
             configFile = args[1];                       // should sanitise first (gwyneth 20220425)
             DebugUtilities.WriteDebug($"Command-line argument set configuration file to '{configFile}'");
         }
     }
     else
     {
         DebugUtilities.WriteSpecial("Usage: RESTbot --config /path/to/configfile|--debug|--help");
         Environment.Exit(10);
     }
 }         // end ParseArguments
예제 #2
0
        public override void Think()
        {
            if (Active && me != null && attempts > 0)
            {
                float distance = 0.0f;
                distance = Vector3.Distance(goalPos, me.Client.Self.SimPosition);

                DebugUtilities
                .WriteDebug($"My pos = {me.Client.Self.SimPosition} Goal: {goalPos} and distance is: {distance}  (attempts left: {attempts})");
                if (distance < DISTANCE_BUFFER)
                {
                    DebugUtilities
                    .WriteDebug($"I am close to my goal pos: {goalPos.X}, {goalPos.Y}, {goalPos.Z}");
                    me.Client.Self.AutoPilotCancel();
                    DebugUtilities.WriteSpecial("Cancel Autopilot");
                    me.Client.Self.Movement.TurnToward(goalPos, true);
                    Active   = false;
                    attempts = 0;
                }
                else
                {
                    attempts--;
                }
            }
            else if (attempts <= 0)
            {
                DebugUtilities.WriteDebug("{MethodName}: No more attempts left; aborting...");
                Active = false;
            }
            base.Think();
        }
예제 #3
0
        /// <summary>
        /// Get rid of a specific session.
        /// </summary>
        /// <remarks>Also calls the garbage collector after a successful bot logout (gwyneth 20220411)</remarks>
        /// <param name="key">Session UUID</param>
        public static void DisposeSession(UUID key)
        {
            DebugUtilities.WriteDebug($"Disposing of session {key.ToString()}");
            if (Sessions != null)
            {
                if (!Sessions.ContainsKey(key))
                {
                    return;
                }
                Session s = Sessions[key];
                if (s != null && s.Bot != null)                 // should never happen, we checked before
                {
                    if (s.StatusCallback != null)
                    {
                        s.Bot.OnBotStatus -= s.StatusCallback;
                    }
                    s.Bot.Client.Network.Logout();

                    // Run garbage collector every time a bot logs out.
                    CollectGarbage();
                }
                else
                {
                    DebugUtilities.WriteError($"Weird error in logging out session {key.ToString()} - it was on the Sessions dictionary, but strangely without a 'bot attached");
                }
                Sessions.Remove(key);
            }
            else
            {
                DebugUtilities.WriteError($"DisposeSession called on {key.ToString()}, but we have no Sessions dictionary!");
            }
        } // end DisposeSession()
예제 #4
0
 public override void Think()
 {
     if (Active && me != null && target != null)
     {
         float distance = 0.0f;
         goalPos = target.Position;
         me
         .Client
         .Self
         .AutoPilot(goalPos.X + regionX, goalPos.Y + regionY, goalPos.Z);
         distance = Vector3.Distance(goalPos, me.Client.Self.SimPosition);
         if (distance > 30)
         {
             me.Client.Self.Movement.AlwaysRun = true;
         }
         else
         {
             me.Client.Self.Movement.AlwaysRun = false;
         }
         DebugUtilities.WriteDebug($"My pos = {me.Client.Self.SimPosition} Goal: {goalPos} and distance is: {distance}");
         if (distance < DISTANCE_BUFFER)
         {
             DebugUtilities.WriteDebug($"I am close to my goal pos: <{goalPos.X}, {goalPos.Y}, {goalPos.Z}");
             me.Client.Self.AutoPilotCancel();
             DebugUtilities.WriteSpecial("Cancel Autopilot");
             me.Client.Self.Movement.TurnToward(goalPos, true);
             Active = false;
         }
     }
     base.Think();
 }
예제 #5
0
        public override void Initialize(RestBot bot)
        {
            session = bot.sessionid;
            me      = bot;
            DebugUtilities.WriteDebug($"{session} {MethodName} startup");

            base.Initialize(bot);
        }
예제 #6
0
		/// <summary>
		/// Initialises the plugin.
		/// </summary>
		/// <param name="bot">A currently active RestBot</param>
		public override void Initialize(RestBot bot)
		{
			// ListenCallbacks = new Dictionary<UUID, String>();
			session = bot.sessionid;
			DebugUtilities.WriteDebug($"{session} {MethodName} startup");

			base.Initialize(bot);
		}
예제 #7
0
        /// <summary>
        /// Initialises the plugin.
        /// </summary>
        /// <param name="bot">A currently active RestBot</param>
        /// <returns>void</returns>
        public override void Initialize(RestBot bot)
        {
            session = bot.sessionid;
            DebugUtilities.WriteDebug($"{session} {MethodName} startup");

            // bot.Client.Network.RegisterCallback(PacketType.DirPeopleReply, new NetworkManager.PacketCallback(Avatars_OnDirPeopleReply)); // obsolete, now uses DirectoryManager
            bot.Client.Directory.DirPeopleReply += Avatars_OnDirPeopleReply;
        }
예제 #8
0
        /// <summary>
        /// Initialises the plugin.
        /// </summary>
        /// <param name="bot">A currently active RestBot</param>
        /// <returns>void</returns>
        public override void Initialize(RestBot bot)
        {
            session = bot.sessionid;
            DebugUtilities.WriteDebug($"{session} {MethodName} startup");

            // bot.Client.Avatars.OnAvatarProperties += new AvatarManager.AvatarPropertiesCallback(Avatars_OnAvatarProperties); // obsolete
            bot.Client.Avatars.AvatarPropertiesReply += Avatars_OnAvatarProperties;
        }
예제 #9
0
        /// <summary>
        /// Initialises the plugin.
        /// </summary>
        /// <param name="bot">A currently active RestBot</param>
        /// <returns>void</returns>
        public override void Initialize(RestBot bot)
        {
            session = bot.sessionid;
            DebugUtilities.WriteDebug($"{session} {MethodName} startup");

            // bot.Client.Network.RegisterCallback(PacketType.AvatarPropertiesReply, new NetworkManager.PacketCallback(AvatarPropertiesReply)); // obsolete
            bot.Client.Avatars.AvatarPropertiesReply += AvatarPropertiesReply;
        }
예제 #10
0
        /// <summary>
        /// Initialises the plugin.
        /// </summary>
        /// <param name="bot">A currently active RestBot</param>
        public override void Initialize(RestBot bot)
        {
            session = bot.sessionid;                    // why is this saved? It's never used... (gwyneth 20220213)
            me      = bot;
            DebugUtilities.WriteDebug($"{session} {MethodName} startup");

            base.Initialize(bot);               // wtf is this for? (gwyneth 20220212)
        }
예제 #11
0
        }         // end Avatars_OnDirPeopleReply()

        /// <summary>
        /// name2key (avatar name to UUID)
        /// </summary>
        /// <param name="b">RESTbot object</param>
        /// <param name="name">Name of avatar to check</param>
        /// <returns>UUID of corresponding avatar, if it exists</returns>
        public static UUID getKey(RestBot b, String name)
        {
            DebugUtilities.WriteInfo("getKey(): Looking up key for " + name);
            b.Client.Directory.DirPeopleReply += Avatars_OnDirPeopleReply;
            name = name.ToLower();
            DebugUtilities.WriteDebug("getKey(): Looking up: " + name);
            DebugUtilities
            .WriteDebug("getKey(): Key not in cache, requesting directory lookup");                     // how do you know? (gwyneth 20220128)
            lock (KeyLookupEvents)
            {
                KeyLookupEvents.Add(name, new AutoResetEvent(false));
            }
            DebugUtilities
            .WriteDebug("getKey(): Lookup Event added, KeyLookupEvents now has a total of " +
                        KeyLookupEvents.Count.ToString() +
                        " entries");
            DirFindQueryPacket find = new DirFindQueryPacket();

            find.AgentData.AgentID    = b.Client.Self.AgentID;          // was Network and not Self
            find.AgentData.SessionID  = b.Client.Self.SessionID;
            find.QueryData.QueryFlags = 1;

            //find.QueryData.QueryText = Helpers.StringToField(name);
            find.QueryData.QueryText  = Utils.StringToBytes(name);
            find.QueryData.QueryID    = new UUID("00000000000000000000000000000001");
            find.QueryData.QueryStart = 0;

            b.Client.Network.SendPacket((Packet)find);
            DebugUtilities
            .WriteDebug("getKey(): Packet sent - KLE has " +
                        KeyLookupEvents.Count.ToString() +
                        " entries.. now waiting");
            if (!KeyLookupEvents[name].WaitOne(15000, true))
            {
                DebugUtilities
                .WriteWarning("getKey(): timed out on avatar name lookup for " +
                              name);
            }
            DebugUtilities.WriteDebug("getKey(): Waiting done!");
            lock (KeyLookupEvents)
            {
                KeyLookupEvents.Remove(name);
            }
            DebugUtilities
            .WriteDebug($"getKey(): Done with KLE, now has {KeyLookupEvents.Count.ToString()} entries");
            UUID response = new UUID();             // hopefully this sets the response to UUID.Zero first... (gwyneth 20220128)

            if (avatarKeys.ContainsKey(name))
            {
                response = avatarKeys[name];
                lock (avatarKeys)
                {
                    avatarKeys.Remove(name);
                }
            }
            b.Client.Directory.DirPeopleReply -= Avatars_OnDirPeopleReply;
            return(response);
        }         // end getKey()
예제 #12
0
        Process(RestBot b, Dictionary <string, string> Parameters)
        {
            UUID folderID;

            DebugUtilities.WriteDebug("Entering folder key parser");
            try
            {
                bool check = false;
                if (Parameters.ContainsKey("key"))
                {
                    DebugUtilities.WriteDebug("Attempting to parse from POST");
                    check =
                        UUID
                        .TryParse(Parameters["key"].ToString().Replace("_", " "),
                                  out folderID);
                    DebugUtilities.WriteDebug("Succesfully parsed POST");
                }
                else
                {
                    folderID = UUID.Zero;                     // start with root folder
                    check    = true;
                }

                if (
                    check                     // means that we have a correctly parsed key OR no key
                    )
                //  which is fine too (attempts root folder)
                {
                    DebugUtilities.WriteDebug("Entering loop");

                    Manager   = b.Client.Inventory;
                    Inventory = Manager.Store;

                    StringBuilder response = new StringBuilder();

                    InventoryFolder startFolder = new InventoryFolder(folderID);

                    if (folderID == UUID.Zero)
                    {
                        startFolder = Inventory.RootFolder;
                    }

                    PrintFolder(b, startFolder, response);
                    DebugUtilities.WriteDebug("Complete");

                    return($"<inventory>{response}</inventory>");
                }
                else
                {
                    return($"<error>{MethodName}: parsekey</error>");
                }
            }
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
                return($"<error>{MethodName}: {e.Message}</error>");
            }
        }
예제 #13
0
        /// <summary>
        /// Main entry point for logging in with a bot.
        /// </summary>
        /// <param name="session">Current session UUID</param>
        /// <param name="f">Login first name</param>
        /// <param name="l">Login last name</param>
        /// <param name="p">MD5-encoded password</param>
        /// <param name="s">Start location is "last", "home" or could be a <seealso cref="T:OpenMetaverse.URI"/></param>

        public RestBot(UUID session, string f, string l, string p, string s)
        {
            //setting up some class variables
            sessionid             = session;
            myStatus              = Status.Offline;
            Client                = new GridClient();
            First                 = f;
            Last                  = l;
            MD5Password           = p;
            uptime                = DateTime.Now;
            Start                 = (s == String.Empty) ? "last" : s;
            ReloginTimer          = new System.Timers.Timer();
            ReloginTimer.Elapsed += new ElapsedEventHandler(ReloginTimer_Elapsed);

            // Some callbacks..
            DebugUtilities.WriteDebug(session.ToString() + " Initializing callbacks");

            // Client.Network.OnDisconnected += new NetworkManager.DisconnectedCallback(Network_OnDisconnected);
            Client.Network.Disconnected += Network_OnDisconnected;             // new syntax

            // Timer used to update an active plugin.
            updateTimer          = new System.Timers.Timer(500);
            updateTimer.Elapsed +=
                new System.Timers.ElapsedEventHandler(updateTimer_Elapsed);

            // Initialize StatefulPlugins
            DebugUtilities.WriteDebug(session.ToString() + " Initializing plugins");
            StatefulPlugins = new Dictionary <string, StatefulPlugin>();
            foreach (Type t in RestBot.StatefulPluginDefinitions)
            {
                ConstructorInfo?info = t.GetConstructor(Type.EmptyTypes);
                if (info == null)
                {
                    DebugUtilities
                    .WriteDebug(session.ToString() +
                                " could not get constructor for type " +
                                t.ToString());
                    continue;
                }
                StatefulPlugin sp = (StatefulPlugin)info.Invoke(new object[0]);

                // Add it to the dictionary
                RegisterStatefulPlugin(sp.MethodName, sp);
                DebugUtilities
                .WriteDebug(session.ToString() + " * added " + sp.MethodName);

                // Initialize all the handlers, etc
                sp.Initialize(this);
            }
            updateTimer.Start();

            /// The strange lambda assignment is due to insane new rules regarding constructors
            /// in recent versions of C#. (gwyneth 20220213)
            /// <see href="https://stackoverflow.com/a/70146798/1035977" />
            OnBotStatus = new BotStatusCallback((sender, e) => {});
        }
예제 #14
0
        /// <summary>
        /// Handler event for this plugin.
        /// </summary>
        /// <param name="b">A currently active RestBot</param>
        /// <param name="Parameters">A dictionary containing the group UUID and the message to send to group IM</param>
        /// <returns>XML with information on the sent group IM message, if successful;
        /// XML error otherwise</returns>
        public override string Process(RestBot b, Dictionary <string, string> Parameters)
        {
            UUID   groupUUID;
            string message;

            try
            {
                bool check = false;
                if (Parameters.ContainsKey("key"))
                {
                    check = UUID.TryParse(Parameters["key"].ToString().Replace("_", " "), out groupUUID);
                }
                else
                {
                    return("<error>arguments: no key</error>");
                }
                if (check)
                {
                    if (Parameters.ContainsKey("message"))
                    {
                        message = Parameters["message"].ToString().Replace("%20", " ").Replace("+", " ");
                    }
                    else
                    {
                        return("<error>arguments: no message</error>");
                    }
                }
                else
                {
                    return("<error>parsekey</error>");
                }

                message = message.TrimEnd();
                if (message.Length > 1023)
                {
                    message = message.Remove(1023);
                    DebugUtilities.WriteDebug(session + " " + MethodName + " Message truncated at 1024 characters");
                }

                string response = sendIMGroup(b, groupUUID, message);

                if (string.IsNullOrEmpty(response))
                {
                    return("<error>group message not sent, or answer was empty</error>");
                }

                return("<message>" + response.Trim() + "</message>");
            }
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
                return("<error>loads of errors</error>");
            }
        }
예제 #15
0
 /// <summary>
 /// StatefulPlugins stuff
 /// </summary>
 /// <param name="defn">List of plugin definitions</param>
 public static void AddStatefulPluginDefinition(Type defn)
 {
     lock (StatefulPluginDefinitions)
     {
         DebugUtilities.WriteDebug($"Plugin definition: {defn.FullName}");
         if (defn.IsSubclassOf(typeof(StatefulPlugin)))
         {
             StatefulPluginDefinitions.Add(defn);
         }
     }
 }
예제 #16
0
        }         // end getName()

        /// <summary>
        /// Loop through all (pending) replies for UUID/Avatar names
        /// and process them if they contain any key we're looking for.
        /// </summary>
        /// <param name="sender">parameter ignored</param>
        /// <param name="e">List of UUID/Avatar names</param>
        /// <returns>void</returns>
        /// <remarks>using new Directory functionality</remarks>
        public static void Avatars_OnDirPeopleReply(
            object?sender,
            DirPeopleReplyEventArgs e
            )
        {
            if (e.MatchedPeople.Count < 1)
            {
                DebugUtilities
                .WriteWarning("Avatars_OnDirPeopleReply() - Error: empty people directory reply");
            }
            else
            {
                int replyCount = e.MatchedPeople.Count;

                DebugUtilities
                .WriteInfo("Avatars_OnDirPeopleReply() - Processing " +
                           replyCount.ToString() +
                           " DirPeople replies");
                for (int i = 0; i < replyCount; i++)
                {
                    string avatarName =
                        e.MatchedPeople[i].FirstName + " " + e.MatchedPeople[i].LastName;
                    UUID avatarKey = e.MatchedPeople[i].AgentID;
                    DebugUtilities
                    .WriteDebug("Avatars_OnDirPeopleReply() -  Reply " +
                                (i + 1).ToString() +
                                " of " +
                                replyCount.ToString() +
                                " Key : " +
                                avatarKey.ToString() +
                                " Name : " +
                                avatarName);

                    if (!avatarKeys.ContainsKey(avatarName))
                    {
                        /* || avatarKeys[avatarName] == null )	 // apparently dictionary entries cannot be null */
                        lock (avatarKeys)
                        {
                            avatarKeys[avatarName.ToLower()] = avatarKey;
                        }
                    }

                    lock (KeyLookupEvents)
                    {
                        if (KeyLookupEvents.ContainsKey(avatarName.ToLower()))
                        {
                            KeyLookupEvents[avatarName.ToLower()].Set();
                            DebugUtilities.WriteDebug(avatarName.ToLower() + " KLE set!");
                        }
                    }
                }
            }
        }         // end Avatars_OnDirPeopleReply()
예제 #17
0
 /// <summary>Initialisation</summary>
 public override void Initialize(RestBot bot)
 {
     session = bot.sessionid;
     // double-checking this, because I really, really want to force a configuration override to turn this off!
     // (gwyneth 20220412)
     if (Program.config != null && Program.config.plugin.reaper == true)
     {
         DebugUtilities.WriteDebug($"{session} {MethodName} startup");
         Reaper.Init(); //start up the reaper if we havent already (the check to see if we have is in this function)
     }
     else
     {
         DebugUtilities.WriteDebug(session + " REAPER not starting due to configuration override");
     }
 }
예제 #18
0
        /// <summary>
        /// name2key (avatar name to UUID)
        /// </summary>
        /// <param name="b">RESTbot object</param>
        /// <param name="name">Name of avatar to check</param>
        /// <returns>UUID of corresponding avatar, if it exists</returns>
        public UUID getKey(RestBot b, String name)
        {
            DebugUtilities
            .WriteInfo($"{session} {MethodName} Looking up key for {name}");
            name = name.ToLower();
            DebugUtilities.WriteDebug($"Looking up: {name}");
            DebugUtilities
            .WriteDebug("Key not in cache, requesting directory lookup");
            lock (KeyLookupEvents)
            {
                KeyLookupEvents.Add(name, new AutoResetEvent(false));
            }
            DebugUtilities
            .WriteDebug($"Lookup Event added, KeyLookupEvents now has a total of {KeyLookupEvents.Count.ToString()} entries");
            DirFindQueryPacket find = new DirFindQueryPacket();

            find.AgentData.AgentID    = b.Client.Self.AgentID;          // was Network and not Self
            find.AgentData.SessionID  = b.Client.Self.SessionID;
            find.QueryData.QueryFlags = 1;

            //find.QueryData.QueryText = Helpers.StringToField(name);
            find.QueryData.QueryText  = Utils.StringToBytes(name);
            find.QueryData.QueryID    = new UUID("00000000000000000000000000000001");
            find.QueryData.QueryStart = 0;

            b.Client.Network.SendPacket((Packet)find);
            DebugUtilities
            .WriteDebug($"Packet sent - KLE has {KeyLookupEvents.Count.ToString()} entries... now waiting");
            KeyLookupEvents[name].WaitOne(15000, true);
            DebugUtilities.WriteDebug("Waiting done!");
            lock (KeyLookupEvents)
            {
                KeyLookupEvents.Remove(name);
            }
            DebugUtilities
            .WriteDebug($"Done with KLE, now has {KeyLookupEvents.Count.ToString()} entries");
            UUID response = new UUID();

            if (avatarKeys.ContainsKey(name))
            {
                response = avatarKeys[name];
                lock (avatarKeys)
                {
                    avatarKeys.Remove(name);
                }
            }
            return(response);
        }
예제 #19
0
        /// <summary>
        /// Handler event for this plugin.
        /// </summary>
        /// <param name="b">A currently active RestBot</param>
        /// <param name="Parameters">A dictionary containing the group name, or UUID</param>
        /// <returns>XML containing the group name that was activated, if successful; XML error otherwise.</returns>
        public override string Process(RestBot b, Dictionary <string, string> Parameters)
        {
            UUID   groupUUID;
            string groupName;

            DebugUtilities.WriteDebug("Entering group key parser");
            try
            {
                if (Parameters.ContainsKey("name"))
                {
                    groupName = Parameters["name"].ToString().Replace("%20", " ").Replace("+", " ");
                }
                else
                {
                    return($"<error>{MethodName}: arguments</error>");
                }
                DebugUtilities.WriteDebug("Activating group");

                groupUUID = GroupName2UUID(b, groupName);
                if (UUID.Zero != groupUUID)
                {
                    string response = activateGroup(b, groupUUID);
                    DebugUtilities.WriteDebug("Complete");
                    if (response != null)
                    {
                        return($"<active>{response.Trim()}</active>");
                    }
                    else
                    {
                        return($"<error>{MethodName}: group could not be activated</error>");
                    }
                }
                else
                {
                    DebugUtilities.WriteDebug($"Error: group {groupName} doesn't exist");
                    return($"<error>{MethodName}: group name '{groupName}' doesn't exist.</error>");
                }
            }
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
                return($"<error>{MethodName}: parsekey</error>");
            }
        }
예제 #20
0
        Process(RestBot b, Dictionary <string, string> Parameters)
        {
            /// <summary>UUID for the prim/object that we intend the bot to touch</summary>
            UUID touchTargetID = UUID.Zero;

            DebugUtilities.WriteDebug($"{b.sessionid} {MethodName} - Searching for prim to touch");
            try
            {
                bool check = false;
                if (Parameters.ContainsKey("prim"))
                {
                    check =
                        UUID
                        .TryParse(Parameters["prim"].ToString().Replace("_", " "),
                                  out touchTargetID);
                }

                if (!check)
                {
                    return("<error>prim to touch not specified</error>");
                }

                // If we get to this point means that we have a correctly parsed key for the target prim
                DebugUtilities.WriteDebug($"{b.sessionid} {MethodName} - Trying to touch {touchTargetID.ToString()}...");

                Primitive targetPrim = b.Client.Network.CurrentSim.ObjectsPrimitives.Find(
                    prim => prim.ID == touchTargetID
                    );

                if (targetPrim != null)
                {
                    b.Client.Self.Touch(targetPrim.LocalID);
                    return($"<{MethodName}>touching {targetPrim.ID.ToString()} ({targetPrim.LocalID})</{MethodName}>");
                }

                return($"<error>no prim with UUID {touchTargetID} found</error>");
            }
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
                return($"<error>{e.Message}</error>");
            }
        }
예제 #21
0
        /// <summary>
        /// Handler event for this plugin.
        /// </summary>
        /// <param name="b">A currently active RestBot</param>
        /// <param name="Parameters">A dictionary containing the group UUID</param>
        /// <returns>XML with information on the activated group key if successful,
        /// XML error otherwise</returns>
        public override string Process(RestBot b, Dictionary <string, string> Parameters)
        {
            UUID groupUUID;

            DebugUtilities.WriteDebug("Entering group key parser");
            try
            {
                bool check = false;
                if (Parameters.ContainsKey("key"))
                {
                    DebugUtilities.WriteDebug("Attempting to parse from POST");
                    check = UUID.TryParse(Parameters["key"].ToString().Replace("_", " "), out groupUUID);
                    DebugUtilities.WriteDebug("Succesfully parsed POST");
                }
                else
                {
                    return($"<error>{MethodName}: invalid arguments</error>");
                }
                if (check)
                {
                    DebugUtilities.WriteDebug("Activating group");
                    string?response = activateGroup(b, groupUUID);
                    DebugUtilities.WriteDebug("Complete");
                    if (response != null)
                    {
                        return($"<active>{response.Trim()}</active>");
                    }
                    else
                    {
                        return($"<error>{MethodName}: group could not be activated</error>");
                    }
                }
                else
                {
                    return($"<error>{MethodName}: parsekey</error>");
                }
            }
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
                return($"<error>{MethodName}: parsekey</error>");
            }
        }
예제 #22
0
        /*
         * // obsoleted packet call
         * public void Avatars_OnDirPeopleReply(Packet packet, Simulator simulator)
         * {
         *      DirPeopleReplyPacket reply = (DirPeopleReplyPacket)packet;
         *      DebugUtilities.WriteDebug("Got DirPeopleReply!");
         *      if (reply.QueryReplies.Length < 1) {
         *              DebugUtilities.WriteWarning(session + " {MethodName + " Error - empty people directory reply");
         *      } else {
         *              int replyCount = reply.QueryReplies.Length;
         *              DebugUtilities.WriteInfo(session + " {MethodName + " Proccesing {replyCount.ToString() + " DirPeople replies");
         *              for ( int i = 0 ; i <  replyCount ; i++ ) {
         *                      string avatarName = Utils.BytesToString(reply.QueryReplies[i].FirstName) + " {Utils.BytesToString(reply.QueryReplies[i].LastName);
         *                      UUID avatarKey = reply.QueryReplies[i].AgentID;
         *                      DebugUtilities.WriteDebug(session + " {MethodName + " Reply {(i + 1).ToString() + " of {replyCount.ToString() + " Key : {avatarKey.ToString() + " Name : {avatarName);
         *
         *                      if ( !avatarKeys.ContainsKey(avatarName) ) // || avatarKeys[avatarName] == null ) { // apparently dictionary entries cannot be null
         *                              lock ( avatarKeys ) {
         *                                      avatarKeys[avatarName.ToLower()] = avatarKey;
         *                              }
         *                      }
         *
         *                      lock(KeyLookupEvents)
         *                      {
         *                               if ( KeyLookupEvents.ContainsKey(avatarName.ToLower())) {
         *                                               KeyLookupEvents[avatarName.ToLower()].Set();
         *                                      DebugUtilities.WriteDebug(avatarName.ToLower() + " KLE set!");
         *                               }
         *                      }
         *              }
         *      }
         * } */
        /// <summary>
        /// Loop through all (pending) replies for UUID/Avatar names
        /// and process them if they contain any key we're looking for.
        /// </summary>
        /// <param name="sender">parameter ignored</param>
        /// <param name="e">List of UUID/Avatar names</param>
        /// <returns>void</returns>
        /// <remarks>using new Directory functionality</remarks>
        public void Avatars_OnDirPeopleReply(
            object?sender,
            DirPeopleReplyEventArgs e
            )
        {
            if (e.MatchedPeople.Count < 1)
            {
                DebugUtilities
                .WriteWarning($"{session} {MethodName} Error - empty people directory reply");
            }
            else
            {
                int replyCount = e.MatchedPeople.Count;

                DebugUtilities
                .WriteInfo($"{session} {MethodName} Processing {replyCount.ToString()} DirPeople replies");
                for (int i = 0; i < replyCount; i++)
                {
                    string avatarName = e.MatchedPeople[i].FirstName + e.MatchedPeople[i].LastName;
                    UUID   avatarKey  = e.MatchedPeople[i].AgentID;
                    DebugUtilities
                    .WriteDebug($"{session} {MethodName} Reply {(i + 1).ToString()} of {replyCount.ToString()} Key: {avatarKey.ToString()} Name: {avatarName}");

                    if (!avatarKeys.ContainsKey(avatarName))
                    {
                        /* || avatarKeys[avatarName] == null )	 // apparently dictionary entries cannot be null */
                        lock (avatarKeys)
                        {
                            avatarKeys[avatarName.ToLower()] = avatarKey;
                        }
                    }

                    lock (KeyLookupEvents)
                    {
                        if (KeyLookupEvents.ContainsKey(avatarName.ToLower()))
                        {
                            KeyLookupEvents[avatarName.ToLower()].Set();
                            DebugUtilities.WriteDebug($"{avatarName.ToLower()} KLE set!");
                        }
                    }
                }
            }
        }
예제 #23
0
        Process(RestBot b, Dictionary <string, string> Parameters)
        {
            UUID agentKey;

            DebugUtilities.WriteDebug("Entering avatarname parser");
            try
            {
                bool check = false;
                if (Parameters.ContainsKey("key"))
                {
                    DebugUtilities.WriteDebug("Attempting to parse from POST");
                    check =
                        UUID
                        .TryParse(Parameters["key"].ToString().Replace("_", " "),
                                  out agentKey);
                    DebugUtilities.WriteDebug("Succesfully parsed POST");
                }
                else
                {
                    return("<error>arguments</error>");
                }
                if (check)
                {
                    DebugUtilities.WriteDebug("Parsing name");
                    string response = getName(b, agentKey);
                    DebugUtilities.WriteDebug("Parsed name");
                    DebugUtilities.WriteDebug("Complete");
                    return($"<name>{response.Trim()}</name>");
                }
                else
                {
                    return("<error>parsekey</error>");
                }
            }
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
                return("<error>parsekey</error>");
            }
        }
예제 #24
0
 /// <summary>
 /// Loop through all (pending) replies for UUID/Avatar names
 /// and process them if they contain any key we're looking for.
 /// </summary>
 /// <param name="sender">parameter ignored</param>
 /// <param name="e">List of UUID/Avatar names</param>
 /// <returns>void</returns>
 /// <remarks>obsolete syntax changed</remarks>
 private void Avatars_OnAvatarNames(object?sender, UUIDNameReplyEventArgs e)
 {
     DebugUtilities.WriteDebug($"{session.ToString()} Processing {e.Names.Count.ToString()} AvatarNames replies");
     foreach (KeyValuePair <UUID, string> kvp in e.Names)
     {
         if (!avatarNames.ContainsKey(kvp.Key) || avatarNames[kvp.Key] == null)
         {
             DebugUtilities.WriteDebug($"{session.ToString()} Reply Name: {kvp.Value} Key: {kvp.Key.ToString()}");
             lock (avatarNames)
             {
                 // avatarNames[kvp.Key] = new Avatar(); // why all this trouble?
                 // FIXME: Change this to .name when we move inside libsecondlife
                 // avatarNames[kvp.Key].Name = kvp.Value; // protected
                 avatarNames[kvp.Key] = kvp.Value;
             }
             if (NameLookupEvents.ContainsKey(kvp.Key))
             {
                 NameLookupEvents[kvp.Key].Set();
             }
         }
     }
 }
예제 #25
0
        DoProcessing(Dictionary <string, string> Parameters, string[] parts)
        {
            string Method      = parts[0];
            string?debugparams = null;              // must allow null (gwyneth 20220109)

            foreach (KeyValuePair <string, string> kvp in Parameters)
            {
                debugparams = $"{debugparams} [{kvp.Key}={kvp.Value}] ";
            }
            DebugUtilities.WriteDebug($"Session ID: {sessionid}, Method: {Method}, Parameters: {debugparams}");

            //Actual processing
            if (Plugins.ContainsKey(Method))
            {
                return(Plugins[Method].Process(this, Parameters));
            }
            else             //Process the stateful plugins
            if (StatefulPlugins.ContainsKey(Method))
            {
                return(StatefulPlugins[Method].Process(this, Parameters));
            }
            else if (Method == "stat")
            {
                string response = $@"<{Method}>
	<name>{Client.Self.FirstName} {Client.Self.LastName}</name>
	<key>{Client.Self.AgentID.ToString()}</key>
	<uptime>{(DateTime.Now - uptime)}</uptime>
</{Method}>
";
                return(response);
            }
            else if (Method == "status")
            {
                return($"<{Method}>{myStatus.ToString()}</{Method}>");
            }
            return("<error>novalidplugin</error>");
        } // end DoProcessing
예제 #26
0
        /// <summary>
        /// getKeySimple gets an avatar's UUID key, given its (full) avatar name
        /// </summary>
        /// <param name="b">RESTbot object</param>
        /// <param name="name">Name of avatar to check</param>
        /// <returns>UUID of corresponding avatar, if it exists</returns>
        public static UUID getKeySimple(RestBot b, String name)
        {
            // add callback to handle reply
            b.Client.Avatars.AvatarPickerReply += Avatars_AvatarPickerReply;

            name = name.ToLower();

            lock (ToAvatarName)
            {
                ToAvatarName = name;
            }

            // Check if the avatar UUID is already in our cache
            if (!Name2Key.ContainsKey(name))
            {
                // Send the Query, it requires a random session ID (probably for manually killing it)
                b.Client.Avatars.RequestAvatarNameSearch(name, UUID.Random());
                // waits a reasonable amount for a reply
                NameSearchEvent.WaitOne(6000, false);
            }

            // Now we either have the key, or the avatar doesn't exist, or the network broke.
            // In all cases, we remove the callback and return whatever we've got.
            if (Name2Key.ContainsKey(name))
            {
                UUID id = Name2Key[name];
                b.Client.Avatars.AvatarPickerReply -= Avatars_AvatarPickerReply;
                return(id);
            }
            else
            {
                b.Client.Avatars.AvatarPickerReply -= Avatars_AvatarPickerReply;
                DebugUtilities.WriteDebug("$Name lookup for {name} failed, NULL_KEY returned");
                return(UUID.Zero);
            }
        }         // end getKeySimple
예제 #27
0
        } = "0.0.0.0";                                                                                  // will be filled in later by Main() (gwyneth 20220425)

        /// <summary>
        /// Bootstrap method.
        /// </summary>
        /// <param name="args">Arguments passed to the application</param>
        /// <remarks>The arguments seem to get promptly ignored! (gwyneth 20220109)</remarks>
        static void Main(string[] args)
        {
            // LogManager.GetLogger(typeof(RestBot));

            // new function to parse some useful arguments and do interesting things (gwyneth 20220425)
            ParseArguments(args);

            // see if we can get the version string
            try
            {
                // Note: we ought to also extract the Assembly name, we presume it's the default (gwyneth 20220426)
#if Windows
                var fileVersionInfo = FileVersionInfo.GetVersionInfo("@RESTbot.dll");
#else
                var fileVersionInfo = FileVersionInfo.GetVersionInfo("@RESTbot");
#endif
                Version = fileVersionInfo.FileVersion + "-file";
            }
            catch (Exception e1)
            {
                // nope, this doesn't work under macOS
                DebugUtilities.WriteDebug($"Cannot retrieve file version, exception caught: {e1.Message}");
                // let's try to get the assembly name instead
                try
                {
                    var assembly = Assembly.GetExecutingAssembly();
                    Version = assembly.GetName().Version + "-assembly";
                }
                catch (Exception e2)
                {
                    // nope, that didn't work either
                    DebugUtilities.WriteDebug($"Cannot retrieve assembly version either, exception caught: {e2.Message}");
                    // finally, our last choice is trying the Informational Version
                    try
                    {
                        var assembly = Assembly.GetEntryAssembly();
                        if (assembly != null)
                        {
                            var customAttribute = assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>();
                            if (customAttribute != null)
                            {
                                var infoVersion = customAttribute.InformationalVersion;

                                if (infoVersion != null)
                                {
                                    Version = infoVersion;
                                }
                            }
                        }
                    }
                    catch (Exception e3)
                    {
                        // we're out of luck today, we cannot even get the Informational Versoin
                        DebugUtilities.WriteDebug($"Also cannot retrieve informational version, exception caught: {e3.Message}");
                        // we'll have to stick with the hard-coded default Version instead...
                    }
                }
            }
            if (Version == null)
            {
                Version = "0.0.0.0";
            }
            DebugUtilities.WriteInfo($"RESTbot file version: {Version}");

            DebugUtilities.WriteInfo($"Reading config file '{configFile}'...");
            config = XMLConfig.Configuration.LoadConfiguration(configFile);
            if (config == null)
            {
                // configuration is mandatory! (gwyneth 20220213)
                DebugUtilities.WriteError($"Unable to open configuration file '{configFile}'! Aborting...");
                Environment.Exit(1);
                return;
            }

            DebugUtilities.WriteInfo("RESTbot startup");
            // Sessions should never be null (?) (gwyneth 20220214)
            if (Sessions == null)
            {
                // Trouble expects us later on, when adding and removing sessions...
                DebugUtilities.WriteError("Error initialising Sessions directory; it was set to null!");
            }

            /// <summary>Get the file version of LibreMetaverse.</summary>
            /// <remarks><see href="https://stackoverflow.com/a/14612480/1035977"/> (gwyneth 20220414)</remarks>
            FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(@"LibreMetaverse.dll");

            // Print the file name and version number.
            DebugUtilities.WriteInfo($"LibreMetaverse DLL version: {myFileVersionInfo.FileDescription} {myFileVersionInfo.FileVersion}");

            DebugUtilities.WriteInfo("Loading plugins");
            RegisterAllCommands(Assembly.GetExecutingAssembly());
            DebugUtilities.WriteDebug("Loading stateful plugins");
            RegisterAllStatefulPlugins(Assembly.GetExecutingAssembly());

            DebugUtilities.WriteInfo($"Listening on port {config.networking.port.ToString()}");

            // Set up the listener / router
            Listener = new RESTBot.Server.Router(IPAddress.Parse(config.networking.ip), config.networking.port);

            StillRunning = true;
            DebugUtilities.WriteInfo("Startup complete");
            uptime = DateTime.Now;

            // let's see if we can figure out how much memory is being wasted
            int stupidCounter = 0;
            while (StillRunning)
            {
                System.Threading.Thread.Sleep(1);
                //TODO: Replace above with a manualresetevent

                if (stupidCounter % 3600000 == 0)                       // stop every hour and check available memory (gwyneth 20220210)
                {
                    CollectGarbage();
                }
                stupidCounter++;
            }

            Listener.StillRunning = false;
        }
예제 #28
0
        /// <summary>
        /// Process a request (assuming it exists)
        /// </summary>
        /// <param name="headers">Request headers (including path, etc.)</param>
        /// <param name="body">Request body (will usually have all parameters from POST)</param>
        public static string DoProcessing(RequestHeaders headers, string body)
        {
            // Abort if we don't even have a valid configuration; too many things depend on it... (gwyneth 20220213)
            if (Program.config == null)
            {
                return("<error>No valid configuration loaded, aborting</error>");
            }

            //Setup variables
            DebugUtilities.WriteInfo($"New request - {headers.RequestLine.Path}");
            //Split the URL
            string[] parts = headers.RequestLine.Path.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length < 1)
            {
                return("<error>invalidmethod</error>");
            }
            string Method = parts[0];
            /// <summary>Process the request params from POST, URL</summary>
            Dictionary <string, string> Parameters = RestBot.HandleDataFromRequest(headers, body);
            string debugparams = String.Empty;
            string debugparts  = String.Empty;

            foreach (KeyValuePair <string, string> kvp in Parameters)
            {
                debugparams = debugparams + "[" + kvp.Key + "=" + kvp.Value + "] ";
            }
            DebugUtilities.WriteDebug($"Parameters (total: {Parameters.Count()}) - '{debugparams}'");
            foreach (string s in parts)
            {
                debugparts = debugparts + "[ " + s + " ]";
            }
            DebugUtilities.WriteDebug($"Parts (total: {parts.Count()}) - '{debugparts}'");
            if (Method == "establish_session")
            {
                DebugUtilities.WriteDebug("We have an `establish_session` method.");
                // Alright, we're going to try to establish a session
                // Start location is optional (gwyneth 20220421)
                if (parts.Length >= 2 && parts[1] == Program.config.security.serverPass &&
                    Parameters.ContainsKey("first") && Parameters.ContainsKey("last") && Parameters.ContainsKey("pass"))
                {
                    DebugUtilities.WriteDebug("Found required parameters for establish_session");
                    if (Sessions != null)
                    {
                        foreach (KeyValuePair <UUID, Session> ss in Sessions)
                        {
                            if (ss.Value != null && ss.Value.Bot != null)
                            {
                                DebugUtilities.WriteSpecial($"Avatar check: [{ss.Value.Bot.First.ToLower()}/{ss.Value.Bot.Last.ToLower()}] = [{Parameters["first"].ToLower()}/{Parameters["last"].ToLower()}]");
                                if (Parameters["first"].ToLower() == ss.Value.Bot.First.ToLower() &&
                                    Parameters["last"].ToLower() == ss.Value.Bot.Last.ToLower()
                                    )
                                {
                                    DebugUtilities.WriteWarning($"Already running avatar {Parameters["first"]} {Parameters["last"]}");

                                    /// <value>Temporary string to construct a full response, if possible; if not, we catch the
                                    /// exception and return a much shorter version</value>
                                    /// <remarks>This is a hack. The issue is that we're probably acessing nullable
                                    /// elements without checking. (gwyneth 20220428)</remarks>
                                    string returnString = "";

                                    try
                                    {
                                        // Attempt to get a
                                        returnString = $@"<existing_session>true</existing_session>
	<session_id>{ss.Key.ToString()}</session_id>
	<key>{ss.Value.Bot.Client.Self.AgentID.ToString()}</key>
	<name>{ss.Value.Bot.Client.Self.FirstName} {ss.Value.Bot.Client.Self.LastName}</name>
	<FirstName>{ss.Value.Bot.Client.Self.FirstName}</FirstName>
	<LastName>{ss.Value.Bot.Client.Self.LastName}</LastName>
	<status>{ss.Value.Bot.myStatus.ToString()}</status>
	<uptime>{ss.Value.Bot.getUptimeISO8601()}</uptime>
	<start>{ss.Value.Bot.Start}</start>
	<CurrentSim>{ss.Value.Bot.Client.Network.CurrentSim.ToString()}</CurrentSim>
	<Position>{ss.Value.Bot.Client.Self.SimPosition.X},{ss.Value.Bot.Client.Self.SimPosition.Y},{ss.Value.Bot.Client.Self.SimPosition.Z}</Position>
	<Rotation>{ss.Value.Bot.Client.Self.SimRotation.X},{ss.Value.Bot.Client.Self.SimRotation.Y},{ss.Value.Bot.Client.Self.SimRotation.Z},{ss.Value.Bot.Client.Self.SimRotation.W}</Rotation>
";
                                    }
                                    catch (Exception e)
                                    {
                                        DebugUtilities.WriteError($"Could not generate full response, error was: '{e.Message}'; falling back to the simple, minimalistic answer");
                                        returnString = $"<existing_session>true</existing_session><session_id>{ss.Key.ToString()}</session_id>";
                                    }
                                    return(returnString);
                                }
                            }
                        }
                    }
                    else
                    {
                        DebugUtilities.WriteDebug("No available sessions...");
                    }
                    UUID    id = UUID.Random();
                    Session s  = new Session();
                    s.ID           = id;
                    s.Hostname     = headers.Hostname;
                    s.LastAccessed = DateTime.Now;
                    // Needs the $1$ for the md5 on the login for LibreMetaverse
                    if (!Parameters["pass"].StartsWith("$1$"))
                    {
                        Parameters["pass"] = "******" + Parameters["pass"];
                    }
                    // check if user has provided us with a starting location (default is to use the last location)
                    // (gwyneth 20220420)
                    string gridLocation = Parameters.ContainsKey("start") ? Parameters["start"] : "last";
                    s.Bot = new RestBot(s.ID, Parameters["first"], Parameters["last"], Parameters["pass"], gridLocation);

                    if (Sessions != null)
                    {
                        lock (Sessions)
                        {
                            Sessions.Add(id, s);
                        }
                    }
                    else
                    {
                        // no "else", we have no dictionary
                        DebugUtilities.WriteWarning("Possible issue: we have null Sessions when adding, which shouldn't happen");
                    }
                    RestBot.LoginReply reply = s.Bot.Login();
                    if (reply.wasFatal)
                    {
                        if (Sessions != null)
                        {
                            lock (Sessions)
                            {
                                if (Sessions.ContainsKey(id))
                                {
                                    Sessions.Remove(id);
                                }
                            }
                        }
                        else
                        {
                            // no "else", we have no dictionary
                            DebugUtilities.WriteWarning("Possible issue: we have null Sessions when removing, which shouldn't happen");
                        }
                    }
                    return(reply.xmlReply);
                }
                else
                {
                    String result = String.Empty;
                    if (parts.Length < 2)
                    {
                        result = "Missing a part.";
                    }
                    if (!Parameters.ContainsKey("first"))
                    {
                        result = result + " Missing 'first' arg.";
                    }
                    if (!Parameters.ContainsKey("last"))
                    {
                        result = result + " Missing 'last' arg.";
                    }
                    if (!Parameters.ContainsKey("pass"))
                    {
                        result = result + " Missing 'pass' arg.";
                    }
                    return($"<error>arguments: {result}</error>");
                }
            }
            // Note: formerly undocumented functionality!! (gwyneth 20220414)
            else if (Method == "server_quit")
            {
                if (parts.Length < 2)
                {
                    return($"<error>{Method}: missing 'pass' arg.</error>");
                }
                if (parts[1] == Program.config.security.serverPass)
                {
                    if (Sessions != null)
                    {
                        foreach (KeyValuePair <UUID, Session> s in Sessions)
                        {
                            lock (Sessions) DisposeSession(s.Key);
                        }
                        StillRunning = false;
                        // note: a caveat of this undocumented method is that it requires a _new_
                        // incoming request to actually kill the server... could be a ping, though. (gwyneth 20220414)
                        return("<status>success - all bot sessions were logged out and a request was made for queued shutdown</status>");
                    }
                    else
                    {
                        // it's fine if there are no sessions (gwyneth 20220414)
                        return("<status>success - no sessions were active</status>");
                    }
                }
                else
                {
                    // wrong password sent! (gwyneth 20220414)
                    return($"<error>{Method}: server authentication failure</error>");
                }
            }
            else if (Method == "ping")
            {
                if (parts.Length < 2)
                {
                    return($"<error>{Method}: missing 'pass' arg.</error>");
                }
                if (parts[1] == Program.config.security.serverPass)
                {
                    return($"<{Method}>I'm alive!</{Method}>");
                }
                else
                {
                    // wrong password sent! (gwyneth 20220414)
                    return($"<error>{Method}: server authentication failure</error>");
                }
            }
            else if (Method == "session_list")
            {
                if (parts.Length < 2)
                {
                    return("<error>missing 'pass' arg.</error>");
                }
                if (parts[1] == Program.config.security.serverPass)
                {
                    bool check = false;
                    if (Program.Sessions.Count != 0)                     // no sessions? that's fine, no need to abort
                    {
                        check = true;
                    }

                    string response = $"<{Method}>";
                    if (check)                          // optimisation: if empty, no need to run the foreach (gwyneth 20220424)
                    {
                        foreach (KeyValuePair <OpenMetaverse.UUID, RESTBot.Session> kvp in Program.Sessions)
                        {
                            if (kvp.Value.Bot != null && kvp.Value.Bot.Client != null && kvp.Value.Bot.Client.Self != null && kvp.Value.Bot.Client.Network != null)
                            {
                                response += $@"
	<session>
		<session_id>{kvp.Key.ToString()}</session_id>
		<key>{kvp.Value.Bot.Client.Self.AgentID.ToString()}</key>
		<name>{kvp.Value.Bot.Client.Self.FirstName} {kvp.Value.Bot.Client.Self.LastName}</name>
		<FirstName>{kvp.Value.Bot.Client.Self.FirstName}</FirstName>
		<LastName>{kvp.Value.Bot.Client.Self.LastName}</LastName>
		<status>{kvp.Value.Bot.myStatus.ToString()}</status>
		<uptime>{kvp.Value.Bot.getUptimeISO8601()}</uptime>
		<start>{kvp.Value.Bot.Start}</start>
		<CurrentSim>{kvp.Value.Bot.Client.Network.CurrentSim.ToString()}</CurrentSim>
		<Position>{kvp.Value.Bot.Client.Self.SimPosition.X},{kvp.Value.Bot.Client.Self.SimPosition.Y},{kvp.Value.Bot.Client.Self.SimPosition.Z}</Position>
		<Rotation>{kvp.Value.Bot.Client.Self.SimRotation.X},{kvp.Value.Bot.Client.Self.SimRotation.Y},{kvp.Value.Bot.Client.Self.SimRotation.Z},{kvp.Value.Bot.Client.Self.SimRotation.W}</Rotation>
	</session>"    ;
                            }
                            else
                            {
                                // Somehow, we have a session ID that has no bot assigned;
                                // this should never be the case, but... (gwyneth 20220426)
                                response += $"<session><session_id>{kvp.Key.ToString()}</session_id><key>{UUID.Zero.ToString()}</key></session>";
                            }
                        }
                    }
                    else
                    {
                        response += "no sessions";
                    }
                    response += $"</{Method}>";
                    return(response);
                }
                else
                {
                    // wrong password sent! (gwyneth 20220414)
                    return($"<error>{Method}: server authentication failure</error>");
                }
            }
            else if (Method == "stats")
            {
                if (parts.Length < 2)
                {
                    return($"<error>{Method}: missing 'pass' arg.</error>");
                }
                if (parts[1] == Program.config.security.serverPass)
                {
                    string response = "<stats><bots>" + ((Sessions != null) ? Sessions.Count.ToString() : "0") + "</bots>"
                                      + "<uptime>" + (DateTime.Now - uptime) + "</uptime></stats>";
                    return(response);
                }
                else
                {
                    return($"<error>{Method}: server authentication failure</error>");
                }
            }

            //Only a method? pssh.
            if (parts.Length == 1)
            {
                return("<error>no session key found</error>");
            }

            UUID sess = new UUID();

            try
            {
                sess = new UUID(parts[1]);
            }
            catch (FormatException)
            {
                return("<error>cannot parse the session key</error>");
            }
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
            }

            //Session checking
            if (!ValidSession(sess, headers.Hostname))
            {
                return("<error>invalidsession</error>");
            }

            //YEY PROCESSING
            RestBot?r = null;

            if (Sessions != null)
            {
                r = Sessions[sess].Bot;
            }

            if (r == null)
            {
                return($"<error>no RestBot found for session {sess.ToString()}</error>");
            }
            //Last accessed for plugins
            if (Sessions != null)
            {
                Sessions[sess].LastAccessed = DateTime.Now;
            }
            //Pre-error checking
            if (r.myStatus != RestBot.Status.Connected) //Still logging in?
            {
                return($"<error>{r.myStatus.ToString()}</error>");
            }
            else if (!r.Client.Network.Connected) //Disconnected?
            {
                return("<error>clientdisconnected</error>");
            }
            else if (Method == "exit")
            {
                DisposeSession(sess);
                return("<disposed>true</disposed>");
            }
            else if (Method == "stats")
            {
                string response = "<bots>" + ((Sessions != null) ? Sessions.Count.ToString() : "NaN") + "</bots>";
                response += "<uptime>" + (DateTime.Now - uptime) + "</uptime>";
                return(response);
            }

            return(r.DoProcessing(Parameters, parts));
        } // end DoProcessing
예제 #29
0
        Process(RestBot b, Dictionary <string, string> Parameters)
        {
            UUID
                itemID,
                avatarKey;
            InventoryManager Manager;

            DebugUtilities.WriteDebug("Entering key parser");
            try
            {
                bool check = false;
                if (Parameters.ContainsKey("itemID"))
                {
                    DebugUtilities.WriteDebug("Attempting to parse from POST");
                    check =
                        UUID
                        .TryParse(Parameters["itemID"].ToString().Replace("_", " "),
                                  out itemID);

                    if (check)
                    {
                        check =
                            UUID
                            .TryParse(Parameters["avatarKey"].ToString().Replace("_", " "),
                                      out avatarKey);
                        DebugUtilities.WriteDebug("Succesfully parsed POST");
                    }
                    else
                    {
                        return($"<error>{MethodName}: parsekey itemID</error>");
                    }
                }
                else
                {
                    return($"<error{MethodName}:>parsekey</error>");
                }

                if (
                    check                     // means that we have a correctly parsed key
                    )
                {
                    DebugUtilities
                    .WriteDebug($"Give Item {itemID.ToString()} to avatar {avatarKey.ToString()}");

                    // Extract item information from inventory
                    InventoryItem oneItem;

                    oneItem =
                        b.Client.Inventory.FetchItem(itemID, b.Client.Self.AgentID, 5000);

                    // to-do: catch timeout explicitly
                    if (oneItem == null)
                    {
                        return($"<error>item {itemID.ToString()} not found</error>");
                    }

                    // attempt to send it to the avatar
                    Manager = b.Client.Inventory;

                    Manager
                    .GiveItem(oneItem.UUID,
                              oneItem.Name,
                              oneItem.AssetType,
                              avatarKey,
                              false);

                    return($"<item><name>{oneItem.Name}</name><assetType>{oneItem.AssetType}</assetType><itemID>{itemID.ToString()}</itemID><avatarKey>{avatarKey.ToString()}</avatarKey></item>");
                }
                else
                {
                    return($"<error>{MethodName}: parsekey avatarKey</error>");
                }
            }
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
                return($"<error>{MethodName}: {e.Message}</error>");
            }
        }
예제 #30
0
        Process(RestBot b, Dictionary <string, string> Parameters)
        {
            UUID embedItemID = UUID.Zero;
            string
                notecardName,
                notecardData;

            DebugUtilities.WriteDebug("Entering key parser");
            try
            {
                // item ID to embed is optional; handle later
                if (Parameters.ContainsKey("key"))
                {
                    UUID
                    .TryParse(Parameters["key"].ToString().Replace("_", " "),
                              out embedItemID);
                }

                // notecard data is required!
                if (Parameters.ContainsKey("notecard"))
                {
                    DebugUtilities
                    .WriteDebug("Attempting to parse notecard data from POST");
                    notecardData = Parameters["notecard"];
                }
                else
                {
                    return("<error>notecard text data not found</error>");
                }

                // notecard name is optional, we'll assign a random name
                if (Parameters.ContainsKey("name"))
                {
                    DebugUtilities
                    .WriteDebug("Attempting to parse notecard name from POST");
                    notecardName = Parameters["name"];

                    DebugUtilities.WriteDebug("Succesfully parsed POST");
                }
                else
                {
                    notecardName = "(no name)";
                }

                UUID
                    notecardItemID  = UUID.Zero,
                    notecardAssetID = UUID.Zero;
                bool
                    success                  = false,
                    finalUploadSuccess       = false;
                string         message       = String.Empty;
                AutoResetEvent notecardEvent = new AutoResetEvent(false);

                DebugUtilities
                .WriteDebug($"Notecard data ('{notecardName}') found: '{notecardData}'");


                #region Notecard asset data

                AssetNotecard notecard = new AssetNotecard();
                notecard.BodyText = notecardData;

                // Item embedding
                if (embedItemID != UUID.Zero)
                {
                    // Try to fetch the inventory item
                    InventoryItem?item = FetchItem(b, embedItemID);
                    if (item != null)
                    {
                        notecard.EmbeddedItems = new List <InventoryItem> {
                            item
                        };
                        notecard.BodyText += (char)0xdbc0 + (char)0xdc00;
                    }
                    else
                    {
                        return("Failed to fetch inventory item " + embedItemID);
                    }
                }

                notecard.Encode();


                #endregion Notecard asset data


                b
                .Client
                .Inventory
                .RequestCreateItem(b
                                   .Client
                                   .Inventory
                                   .FindFolderForType(AssetType.Notecard),
                                   notecardName,
                                   notecardName + " created by LibreMetaverse RESTbot " + DateTime.Now,
                                   AssetType.Notecard,
                                   UUID.Random(),
                                   InventoryType.Notecard,
                                   PermissionMask.All,
                                   delegate(bool createSuccess, InventoryItem item)
                {
                    if (createSuccess)
                    {
                        #region Upload an empty notecard asset first

                        AutoResetEvent emptyNoteEvent = new AutoResetEvent(false);
                        AssetNotecard empty           = new AssetNotecard();
                        empty.BodyText = "\n";
                        empty.Encode();

                        b
                        .Client
                        .Inventory
                        .RequestUploadNotecardAsset(empty.AssetData,
                                                    item.UUID,
                                                    delegate(
                                                        bool uploadSuccess,
                                                        string status,
                                                        UUID itemID,
                                                        UUID assetID)
                        {
                            notecardItemID  = itemID;
                            notecardAssetID = assetID;
                            success         = uploadSuccess;
                            message         = status ?? "Unknown error uploading notecard asset";
                            emptyNoteEvent.Set();
                        });

                        emptyNoteEvent.WaitOne(NOTECARD_CREATE_TIMEOUT, false);


                        #endregion Upload an empty notecard asset first


                        if (success)
                        {
                            // Upload the actual notecard asset
                            b
                            .Client
                            .Inventory
                            .RequestUploadNotecardAsset(notecard.AssetData, item.UUID,
                                                        delegate(bool uploadSuccess, string status, UUID itemID, UUID assetID)
                            {
                                notecardItemID     = itemID;
                                notecardAssetID    = assetID;
                                finalUploadSuccess = uploadSuccess;
                                message            = status ?? "Unknown error uploading notecard asset";
                                notecardEvent.Set();
                            });
                        }
                        else
                        {
                            notecardEvent.Set();
                        }
                    }
                    else
                    {
                        message = "Notecard item creation failed";
                        notecardEvent.Set();
                    }
                });                         // end delegate // end RequestCreateItem

                notecardEvent.WaitOne(NOTECARD_CREATE_TIMEOUT, false);

                // DebugUtilities.WriteDebug("Notecard possibly created, ItemID " + notecardItemID + " AssetID " + notecardAssetID + " Content: '" + DownloadNotecard(b, notecardItemID, notecardAssetID) + "'");
                if (finalUploadSuccess)
                {
                    DebugUtilities
                    .WriteDebug($"Notecard successfully created, ItemID {notecardItemID}; AssetID {notecardAssetID}; Content: '{DownloadNotecard(b, notecardItemID, notecardAssetID)}'");
                    return($"<notecard><ItemID>{notecardItemID}</ItemID><AssetID>{notecardAssetID}</AssetID><name>{notecardName}</name></notecard>");
                }
                else
                {
                    return($"<error>Notecard creation failed: {message}</error>");
                }
            }             // end try
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
                return($"<error>{MethodName}: {e.Message}</error>");
            }
        }