diff --git a/BSBshared/BSBshared.csproj b/BSBshared/BSBshared.csproj index 033ee71..6b92d7a 100644 --- a/BSBshared/BSBshared.csproj +++ b/BSBshared/BSBshared.csproj @@ -15,8 +15,8 @@ - - + + diff --git a/BetterSecondBot.sln b/BetterSecondBot.sln index c07ad16..0749f08 100644 --- a/BetterSecondBot.sln +++ b/BetterSecondBot.sln @@ -10,12 +10,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BSBshared", "BSBshared\BSBs EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libmeta-core", "Libmeta-core", "{7538B15D-152B-4A0F-A24D-A89EDC382564}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreMetaverse-core.Types", "libremetaverse-core\Libremetaverse.types\LibreMetaverse-core.Types.csproj", "{EF718593-1FC7-433A-8495-5B1A7106CAF3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreMetaverse-core.StructuredData", "libremetaverse-core\Libremetaverse.structureddata\LibreMetaverse-core.StructuredData.csproj", "{3928AB19-219D-4284-BFE9-6C0E779F98A3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreMetaverse-core", "libremetaverse-core\Libremetaverse\LibreMetaverse-core.csproj", "{97198293-1B92-4FD2-811E-AE1F33D4B2B2}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B861AB1B-8F09-41A9-8817-CB8A2E961E4C}" ProjectSection(SolutionItems) = preProject Dockerfile = Dockerfile @@ -23,6 +17,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreMetaverse", "libremetaverse-core\LibreMetaverse\LibreMetaverse.csproj", "{27C70F3A-0000-0000-0000-000000000000}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreMetaverse.StructuredData", "libremetaverse-core\LibreMetaverse.StructuredData\LibreMetaverse.StructuredData.csproj", "{89D7A3E5-0000-0000-0000-000000000000}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreMetaverse.Types", "libremetaverse-core\LibreMetaverseTypes\LibreMetaverse.Types.csproj", "{B37B02AD-0000-0000-0000-000000000000}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -66,41 +66,50 @@ Global {42075C8C-8055-4178-8C12-AE97DAFE8484}.Release|Any CPU.ActiveCfg = Release|x64 {42075C8C-8055-4178-8C12-AE97DAFE8484}.Release|x64.ActiveCfg = Release|x64 {42075C8C-8055-4178-8C12-AE97DAFE8484}.Release|x64.Build.0 = Release|x64 - {EF718593-1FC7-433A-8495-5B1A7106CAF3}.Debug|Any CPU.ActiveCfg = Debug|x64 - {EF718593-1FC7-433A-8495-5B1A7106CAF3}.Debug|x64.ActiveCfg = Debug|x64 - {EF718593-1FC7-433A-8495-5B1A7106CAF3}.Debug|x64.Build.0 = Debug|x64 - {EF718593-1FC7-433A-8495-5B1A7106CAF3}.DockerBuild|Any CPU.ActiveCfg = DockerBuild|x64 - {EF718593-1FC7-433A-8495-5B1A7106CAF3}.DockerBuild|x64.ActiveCfg = DockerBuild|x64 - {EF718593-1FC7-433A-8495-5B1A7106CAF3}.DockerBuild|x64.Build.0 = DockerBuild|x64 - {EF718593-1FC7-433A-8495-5B1A7106CAF3}.Release|Any CPU.ActiveCfg = Release|x64 - {EF718593-1FC7-433A-8495-5B1A7106CAF3}.Release|x64.ActiveCfg = Release|x64 - {EF718593-1FC7-433A-8495-5B1A7106CAF3}.Release|x64.Build.0 = Release|x64 - {3928AB19-219D-4284-BFE9-6C0E779F98A3}.Debug|Any CPU.ActiveCfg = Debug|x64 - {3928AB19-219D-4284-BFE9-6C0E779F98A3}.Debug|x64.ActiveCfg = Debug|x64 - {3928AB19-219D-4284-BFE9-6C0E779F98A3}.Debug|x64.Build.0 = Debug|x64 - {3928AB19-219D-4284-BFE9-6C0E779F98A3}.DockerBuild|Any CPU.ActiveCfg = DockerBuild|x64 - {3928AB19-219D-4284-BFE9-6C0E779F98A3}.DockerBuild|x64.ActiveCfg = DockerBuild|x64 - {3928AB19-219D-4284-BFE9-6C0E779F98A3}.DockerBuild|x64.Build.0 = DockerBuild|x64 - {3928AB19-219D-4284-BFE9-6C0E779F98A3}.Release|Any CPU.ActiveCfg = Release|x64 - {3928AB19-219D-4284-BFE9-6C0E779F98A3}.Release|x64.ActiveCfg = Release|x64 - {3928AB19-219D-4284-BFE9-6C0E779F98A3}.Release|x64.Build.0 = Release|x64 - {97198293-1B92-4FD2-811E-AE1F33D4B2B2}.Debug|Any CPU.ActiveCfg = Debug|x64 - {97198293-1B92-4FD2-811E-AE1F33D4B2B2}.Debug|x64.ActiveCfg = Debug|x64 - {97198293-1B92-4FD2-811E-AE1F33D4B2B2}.Debug|x64.Build.0 = Debug|x64 - {97198293-1B92-4FD2-811E-AE1F33D4B2B2}.DockerBuild|Any CPU.ActiveCfg = DockerBuild|x64 - {97198293-1B92-4FD2-811E-AE1F33D4B2B2}.DockerBuild|x64.ActiveCfg = DockerBuild|x64 - {97198293-1B92-4FD2-811E-AE1F33D4B2B2}.DockerBuild|x64.Build.0 = DockerBuild|x64 - {97198293-1B92-4FD2-811E-AE1F33D4B2B2}.Release|Any CPU.ActiveCfg = Release|x64 - {97198293-1B92-4FD2-811E-AE1F33D4B2B2}.Release|x64.ActiveCfg = Release|x64 - {97198293-1B92-4FD2-811E-AE1F33D4B2B2}.Release|x64.Build.0 = Release|x64 + {27C70F3A-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.DockerBuild|Any CPU.ActiveCfg = Debug|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.DockerBuild|Any CPU.Build.0 = Debug|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.DockerBuild|x64.ActiveCfg = Debug|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.DockerBuild|x64.Build.0 = Debug|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|Any CPU + {27C70F3A-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.DockerBuild|Any CPU.ActiveCfg = Debug|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.DockerBuild|Any CPU.Build.0 = Debug|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.DockerBuild|x64.ActiveCfg = Debug|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.DockerBuild|x64.Build.0 = Debug|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|Any CPU + {89D7A3E5-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.DockerBuild|Any CPU.ActiveCfg = Debug|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.DockerBuild|Any CPU.Build.0 = Debug|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.DockerBuild|x64.ActiveCfg = Debug|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.DockerBuild|x64.Build.0 = Debug|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|Any CPU + {B37B02AD-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {EF718593-1FC7-433A-8495-5B1A7106CAF3} = {7538B15D-152B-4A0F-A24D-A89EDC382564} - {3928AB19-219D-4284-BFE9-6C0E779F98A3} = {7538B15D-152B-4A0F-A24D-A89EDC382564} - {97198293-1B92-4FD2-811E-AE1F33D4B2B2} = {7538B15D-152B-4A0F-A24D-A89EDC382564} + {27C70F3A-0000-0000-0000-000000000000} = {7538B15D-152B-4A0F-A24D-A89EDC382564} + {89D7A3E5-0000-0000-0000-000000000000} = {7538B15D-152B-4A0F-A24D-A89EDC382564} + {B37B02AD-0000-0000-0000-000000000000} = {7538B15D-152B-4A0F-A24D-A89EDC382564} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {39A7E333-AFC1-4BA8-9EBC-9298791FDC78} diff --git a/CLI/CliExitOnLogout.cs b/CLI/CliExitOnLogout.cs index f55dbb2..d2e9dee 100644 --- a/CLI/CliExitOnLogout.cs +++ b/CLI/CliExitOnLogout.cs @@ -51,7 +51,10 @@ namespace BetterSecondBot SecondBotHttpServer my_http_server = new SecondBotHttpServer(); my_http_server.StartHttpServer(Bot, Config); */ - new HttpAsService(Bot, Config); + new Thread(() => + { + new HttpAsService(Bot, Config); + }).Start(); } if(use_self_keep_alive == true) { diff --git a/CLI/HttpService/Chat.cs b/CLI/HttpService/Chat.cs new file mode 100644 index 0000000..5b3c8cf --- /dev/null +++ b/CLI/HttpService/Chat.cs @@ -0,0 +1,42 @@ +using BSB.bottypes; +using BSB.Static; +using EmbedIO; +using EmbedIO.Routing; +using EmbedIO.WebApi; +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using Newtonsoft.Json; + +namespace BetterSecondBot.HttpService +{ + public class SecondbotChat : WebApiControllerWithTokens + { + public SecondbotChat(SecondBot mainbot, TokenStorage setuptokens) : base(mainbot, setuptokens) { } + + [Route(HttpVerbs.Get, "/localchathistory/{token}")] + public object localchatHistory(string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + return BasicReply(JsonConvert.SerializeObject(bot.getLocalChatHistory())); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Post, "/localchatsay/{token}")] + public object localchatSay(string token, [FormField] string message) + { + if (tokens.Allow(token, getClientIP()) == true) + { + bot.GetCommandsInterface.Call("say", message); + return BasicReply(JsonConvert.SerializeObject(bot.getLocalChatHistory())); + } + return BasicReply("Token not accepted"); + } + + } + + +} diff --git a/CLI/HttpService/Group.cs b/CLI/HttpService/Group.cs new file mode 100644 index 0000000..b0fb945 --- /dev/null +++ b/CLI/HttpService/Group.cs @@ -0,0 +1,84 @@ +using BSB.bottypes; +using BSB.Static; +using EmbedIO; +using EmbedIO.Routing; +using EmbedIO.WebApi; +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using Newtonsoft.Json; + +namespace BetterSecondBot.HttpService +{ + public class SecondbotGroup : WebApiControllerWithTokens + { + public SecondbotGroup(SecondBot mainbot, TokenStorage setuptokens) : base(mainbot, setuptokens) { } + + [Route(HttpVerbs.Get, "/listgroups/{token}")] + public object listgroups(string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + Dictionary grouppackage = new Dictionary(); + foreach(KeyValuePair entry in bot.MyGroups) + { + grouppackage.Add(entry.Value.ID.ToString(), entry.Value.Name); + } + return BasicReply(JsonConvert.SerializeObject(grouppackage)); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Get, "/listgroupswithunread/{token}")] + public object listgroupswithunread(string group, string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + return BasicReply(JsonConvert.SerializeObject(bot.UnreadGroupchatGroups())); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Get, "/haveunreadgroupchat/{token}")] + public object haveunreadgroupchat(string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + return BasicReply(bot.HasUnreadGroupchats().ToString()); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Get, "/getgroupchat/{group}/{token}")] + public object getgroupchat(string group, string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + if (UUID.TryParse(group, out UUID groupUUID) == true) + { + return BasicReply(JsonConvert.SerializeObject(bot.GetGroupchat(groupUUID))); + } + return BasicReply("Group UUID invaild"); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Post, "/sendgroupchat/{group}/{token}")] + public object sendgroupchat(string group, string token, [FormField] string message) + { + if (tokens.Allow(token, getClientIP()) == true) + { + if (UUID.TryParse(group, out UUID groupUUID) == true) + { + bool status = bot.GetCommandsInterface.Call("Groupchat", group + "~#~" + message, UUID.Zero, "~#~"); + return BasicReply("Processing"); + } + return BasicReply("Group UUID invaild"); + } + return BasicReply("Token not accepted"); + } + + + } +} diff --git a/CLI/HttpService/HttpAsService.cs b/CLI/HttpService/HttpAsService.cs index 3f85bab..e1cd5ec 100644 --- a/CLI/HttpService/HttpAsService.cs +++ b/CLI/HttpService/HttpAsService.cs @@ -32,7 +32,7 @@ namespace BetterSecondBot.HttpService server.RunAsync(); while(Bot.KillMe == false) { - Thread.Sleep(1000); + Thread.Sleep(3000); } } } @@ -43,14 +43,26 @@ namespace BetterSecondBot.HttpService var server = new WebServer(o => o .WithUrlPrefix(url) .WithMode(HttpListenerMode.EmbedIO)) - .WithIPBanning(o => o - .WithMaxRequestsPerSecond(10) - .WithRegexRules("HTTP exception 404") - ) + .WithCors() + //.WithIPBanning(o => o + // .WithMaxRequestsPerSecond(30) + // .WithRegexRules("HTTP exception 404") + //) .WithWebApi("/inventory", m => m - .WithController(() => new SecondbotInventory(Bot, Tokens))) + .WithController(() => new SecondbotInventory(Bot, Tokens)) + ) + .WithWebApi("/chat", m => m + .WithController(() => new SecondbotChat(Bot, Tokens)) + ) + .WithWebApi("/groups", m => m + .WithController(() => new SecondbotGroup(Bot, Tokens)) + ) + .WithWebApi("/ims", m => m + .WithController(() => new SecondbotIm(Bot, Tokens)) + ) .WithWebApi("/core", m => m .WithController(() => new SecondbotCoreWebAPi(Config, Bot, Tokens))) + .WithModule(new ActionModule("/", HttpVerbs.Any, ctx => ctx.SendDataAsync(new { Message = "Error" }))); return server; } @@ -100,7 +112,7 @@ namespace BetterSecondBot.HttpService PurgeExpired(); return false; } - if (info.IP == IPaddress) + if (IPaddress.Equals(info.IP) == true) { return true; } @@ -110,21 +122,27 @@ namespace BetterSecondBot.HttpService public string CreateToken(IPAddress IP) { - PurgeExpired(); - bool used = true; - string last = ""; - while(used == true) + if (IP != null) { - last = helpers.GetSHA1(last + helpers.UnixTimeNow() + new Random().Next(13256).ToString()).Substring(0, 10); - used = tokens.ContainsKey(last); - if (used == false) + PurgeExpired(); + bool used = true; + string last = ""; + while (used == true) { - tokenInfo Info = new tokenInfo(); - Info.IP = IP; - Info.Expires = helpers.UnixTimeNow() + (60 * 10); + last = helpers.GetSHA1(last + helpers.UnixTimeNow() + new Random().Next(13256).ToString()).Substring(0, 10); + used = tokens.ContainsKey(last); + if (used == false) + { + tokenInfo Info = new tokenInfo(); + Info.IP = IP; + Info.Expires = helpers.UnixTimeNow() + (60 * 10); + tokens.Add(last, Info); + break; + } } + return last; } - return last; + return null; } } @@ -132,7 +150,11 @@ namespace BetterSecondBot.HttpService { protected TokenStorage tokens; protected SecondBot bot; - + + protected Object BasicReply(string input) + { + return new { reply = input }; + } public WebApiControllerWithTokens(SecondBot mainbot, TokenStorage setuptokens) { bot = mainbot; diff --git a/CLI/HttpService/Im.cs b/CLI/HttpService/Im.cs new file mode 100644 index 0000000..b30db6e --- /dev/null +++ b/CLI/HttpService/Im.cs @@ -0,0 +1,92 @@ +using BSB.bottypes; +using BSB.Static; +using EmbedIO; +using EmbedIO.Routing; +using EmbedIO.WebApi; +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using Newtonsoft.Json; + +namespace BetterSecondBot.HttpService +{ + public class SecondbotIm : WebApiControllerWithTokens + { + public SecondbotIm(SecondBot mainbot, TokenStorage setuptokens) : base(mainbot, setuptokens) { } + + [Route(HttpVerbs.Get, "/chatwindows/{token}")] + public object chatwindows(string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + return BasicReply(JsonConvert.SerializeObject(bot.GetIMChatWindowKeyNames())); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Get, "/listwithunread/{token}")] + public object listwithunread(string group, string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + List unreadimwindows = new List(); + foreach (UUID window in bot.IMChatWindows()) + { + if (bot.ImChatWindowHasUnread(window) == true) + { + unreadimwindows.Add(window); + } + } + return BasicReply(JsonConvert.SerializeObject(unreadimwindows)); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Get, "/haveunreadims/{token}")] + public object haveunreadims(string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + bool reply = false; + foreach(UUID window in bot.IMChatWindows()) + { + if(bot.ImChatWindowHasUnread(window) == true) + { + reply = true; + break; + } + } + return BasicReply(reply.ToString()); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Get, "/getimchat/{window}/{token}")] + public object getimchat(string window, string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + if (UUID.TryParse(window, out UUID windowUUID) == true) + { + return BasicReply(JsonConvert.SerializeObject(bot.GetIMChatWindow(windowUUID))); + } + return BasicReply("Window UUID invaild"); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Post, "/sendimchat/{avatar}/{token}")] + public object sendgroupchat(string avatar, string token, [FormField] string message) + { + if (tokens.Allow(token, getClientIP()) == true) + { + bot.GetCommandsInterface.Call("im", avatar + "~#~" + message, UUID.Zero, "~#~"); + return BasicReply("ok"); + } + return BasicReply("Token not accepted"); + } + + + } +} diff --git a/CLI/HttpService/Inventory.cs b/CLI/HttpService/Inventory.cs index 25c4865..342960f 100644 --- a/CLI/HttpService/Inventory.cs +++ b/CLI/HttpService/Inventory.cs @@ -14,30 +14,100 @@ namespace BetterSecondBot.HttpService { public SecondbotInventory(SecondBot mainbot, TokenStorage setuptokens) : base(mainbot, setuptokens) { } + + [Route(HttpVerbs.Post, "/rename/{item}/{token}")] + public object rename(string item, string token, [FormField] string newname) + { + if (tokens.Allow(token, getClientIP()) == true) + { + bool status = bot.GetCommandsInterface.Call("RenameInventory", "12~#~" + item + "~#~" + newname); + return BasicReply(status.ToString()); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Get, "/realuuid/{item}/{token}")] + public object realuuid(string item, string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + if (UUID.TryParse(item, out UUID itemUUID) == true) + { + UUID reply = HelperInventory.GetAssetUUID(bot, itemUUID); + if (reply != UUID.Zero) + { + return BasicReply(reply.ToString()); + } + } + return BasicReply("Failed"); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Get, "/send/{item}/{avatar}/{token}")] + public object send(string item, string avatar, string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + if (UUID.TryParse(item, out UUID itemUUID) == true) + { + bool status = bot.GetCommandsInterface.Call("SendItem", avatar+"~#~"+item); + return BasicReply(status.ToString()); + } + return BasicReply("Failed - item must be a vaild UUID"); + } + return BasicReply("Token not accepted"); + } + + [Route(HttpVerbs.Get, "/delete/{item}/{isfolder}/{token}")] + public object delete(string item,string isfolder, string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + if (UUID.TryParse(item, out UUID itemUUID) == true) + { + if (bool.TryParse(isfolder, out bool asfolder) == true) + { + bool status = false; + if (asfolder == true) status = bot.GetCommandsInterface.Call("DeleteInventoryFolder", item); + else status = bot.GetCommandsInterface.Call("DeleteInventoryItem", item); + return BasicReply(status.ToString()); + } + return BasicReply("Failed - isfolder must be True or False"); + } + return BasicReply("Failed - item must be a vaild UUID"); + } + return BasicReply("Token not accepted"); + } + [Route(HttpVerbs.Get, "/folders/{token}")] - public string folders(string token) + public object folders(string token) { if(tokens.Allow(token, getClientIP()) == true) { - return HelperInventory.MapFolderJson(bot); + string reply = HelperInventory.MapFolderJson(bot); + if(reply != null) return BasicReply(reply); + return BasicReply("error"); } - return "Token not accepted"; + return BasicReply("Token not accepted"); } [Route(HttpVerbs.Get, "/contents/{folderUUID}/{token}")] - public string Contents(string folderUUID, string token) + public object Contents(string folderUUID, string token) { if (tokens.Allow(token, getClientIP()) == true) { if (UUID.TryParse(folderUUID, out UUID folder) == true) { - return HelperInventory.MapFolderInventoryJson(bot, folder); + return BasicReply(HelperInventory.MapFolderInventoryJson(bot, folder)); } - return "Invaild folder UUID"; + return BasicReply("Invaild folder UUID"); } - return "Token not accepted"; + return BasicReply("Token not accepted"); } + + } diff --git a/CLI/HttpService/Secondbot.cs b/CLI/HttpService/Secondbot.cs index 8f3497b..0f3c000 100644 --- a/CLI/HttpService/Secondbot.cs +++ b/CLI/HttpService/Secondbot.cs @@ -3,14 +3,16 @@ using BetterSecondBotShared.Static; using BSB.bottypes; using OpenMetaverse; using System.Threading.Tasks; - using EmbedIO; using EmbedIO.Routing; using EmbedIO.WebApi; - +using System; +using System.Collections.Generic; +using Newtonsoft.Json; namespace BetterSecondBot.HttpService { + public class SecondbotCoreWebAPi : WebApiControllerWithTokens { @@ -21,61 +23,92 @@ namespace BetterSecondBot.HttpService } [Route(HttpVerbs.Post, "/gettoken")] - public string GetToken([FormField] string authcode) + public Object GetToken([FormField] string authcode, [FormField] string unixtimegiven) { - long now = helpers.UnixTimeNow() + 120; - int loop = 0; - bool accepted = false; - while(loop <= 30) + long now = helpers.UnixTimeNow(); + long dif = 0; + if(long.TryParse(unixtimegiven,out long given) == true) { - string hashA = helpers.GetSHA1((now + loop) + "" + config.Security_WebUIKey).Substring(0, 10); - string hashB = helpers.GetSHA1((now - loop) + "" + config.Security_WebUIKey).Substring(0, 10); - if ((authcode == hashA) || (authcode == hashB)) + dif = now - given; + now = given; + } + if((dif < 30) && (dif > -30)) + { + var raw = now.ToString() + config.Security_WebUIKey; + string hash = helpers.GetSHA1(raw).Substring(0, 10); + if (hash == authcode) { - accepted = true; - break; + string newtoken = tokens.CreateToken(getClientIP()); + if(newtoken != null) return BasicReply(newtoken); } - loop++; } - if(accepted == true) + return BasicReply("Authcode not accepted"); + } + + [Route(HttpVerbs.Get, "/friends/{token}")] + public object friends(string token) + { + return BasicReply(bot.getJsonFriendlist()); + } + + + [Route(HttpVerbs.Get, "/nearme/{token}")] + public object nearme(string token) + { + if (bot.GetClient.Network.CurrentSim != null) { - return tokens.CreateToken(HttpContext.Request.RemoteEndPoint.Address); + Dictionary NearMe = new Dictionary(); + Dictionary avcopy = bot.GetClient.Network.CurrentSim.ObjectsAvatars.Copy(); + foreach (Avatar av in avcopy.Values) + { + if (av.ID != bot.GetClient.Self.AgentID) + { + NearMe.Add(av.ID, av.Name); + } + } + return BasicReply(JsonConvert.SerializeObject(NearMe)); } - return "Authcode not accepted"; + return BasicReply("Error"); + } + + [Route(HttpVerbs.Get, "/hello")] + public object Hello() + { + return BasicReply("world"); } [Route(HttpVerbs.Get, "/logout/{token}")] - public string Logout(string token) + public object Logout(string token) { if (tokens.Allow(token, getClientIP()) == true) { return tokens.Expire(token); } - return "Token not accepted"; + return BasicReply("Token not accepted"); } [Route(HttpVerbs.Get, "/version/{token}")] - public string Version(string token) + public object Version(string token) { if (tokens.Allow(token, getClientIP()) == true) { - return bot.MyVersion; + return BasicReply(bot.MyVersion); } - return "Token not accepted"; + return BasicReply("Token not accepted"); } [Route(HttpVerbs.Get, "/name/{token}")] - public string Name(string token) + public object Name(string token) { if (tokens.Allow(token, getClientIP()) == true) { - return bot.GetClient.Self.FirstName + " " + bot.GetClient.Self.LastName; + return BasicReply(bot.GetClient.Self.FirstName + " " + bot.GetClient.Self.LastName); } - return "Token not accepted"; + return BasicReply("Token not accepted"); } [Route(HttpVerbs.Post, "/command/{token}")] - public async Task command(string token) + public async Task command(string token) { if (tokens.Allow(token, getClientIP()) == true) { @@ -88,11 +121,11 @@ namespace BetterSecondBot.HttpService bool status = bot.GetCommandsInterface.Call(data.Command, compressedArgs, UUID.Zero, "~#~"); if (status == true) { - return "accepted"; + return BasicReply("accepted"); } } } - return "Token not accepted"; + return BasicReply("Token not accepted"); } } diff --git a/CLI/WikiMake/wikimake.cs b/CLI/WikiMake/wikimake.cs index 8a4b531..700cb7e 100644 --- a/CLI/WikiMake/wikimake.cs +++ b/CLI/WikiMake/wikimake.cs @@ -496,12 +496,40 @@ namespace BetterSecondBot.WikiMake core.callable.Add(new version()); core.callable.Add(new name()); core.callable.Add(new command()); + core.callable.Add(new friends()); + core.callable.Add(new nearme()); + core.callable.Add(new hello()); endpoints.Add(core); Endpoint inventory = new Endpoint(); inventory.name = "inventory"; inventory.callable.Add(new contents()); inventory.callable.Add(new folders()); + inventory.callable.Add(new rename()); + inventory.callable.Add(new realuuid()); + inventory.callable.Add(new send()); + inventory.callable.Add(new delete()); endpoints.Add(inventory); + Endpoint im = new Endpoint(); + im.name = "im"; + im.callable.Add(new chatwindows()); + im.callable.Add(new listwithunread()); + im.callable.Add(new haveunreadims()); + im.callable.Add(new getimchat()); + im.callable.Add(new sendimchat()); + endpoints.Add(im); + Endpoint group = new Endpoint(); + group.name = "group"; + group.callable.Add(new listgroups()); + group.callable.Add(new listgroupswithunread()); + group.callable.Add(new haveunreadgroupchat()); + group.callable.Add(new getgroupchat()); + group.callable.Add(new sendgroupchat()); + endpoints.Add(group); + Endpoint chat = new Endpoint(); + chat.name = "chat"; + chat.callable.Add(new localchathistory()); + chat.callable.Add(new localchatsay()); + endpoints.Add(chat); } public string getCommandMethod(string endpoint, string command) @@ -726,6 +754,37 @@ namespace BetterSecondBot.WikiMake } } + public class friends : APIcall + { + public override void Setup() + { + about = "Gets the friendslist
Formated as follows
friendreplyobject
  • name: String
  • id: String
  • online: bool
"; + returns.Add("array UUID = friendreplyobject"); + base.Setup(); + } + } + + public class nearme : APIcall + { + public override void Setup() + { + about = "returns a list of all known avatars near (same sim)>"; + returns.Add("array UUID = Name"); + base.Setup(); + } + } + + public class hello : APIcall + { + public override void Setup() + { + RequiresToken = false; + about = "used to test you can talk to the api but mostly pointless."; + returns.Add("world"); + base.Setup(); + } + } + public class name : APIcall { public override void Setup() @@ -778,4 +837,184 @@ namespace BetterSecondBot.WikiMake } } + public class rename : postAPIcall + { + public override void Setup() + { + about = "renames a folder or inventory item"; + returns.Add("true|false"); + values.Add("item", new KeyValuePair("URLARG", "UUID of the item/folder we are working on")); + values.Add("newname", new KeyValuePair("string", "What we are setting")); + base.Setup(); + } + } + + public class realuuid : APIcall + { + public override void Setup() + { + about = "converts a inventory uuid to a realworld uuid
Needed for texture preview"; + returns.Add("Failed"); + returns.Add("UUID"); + values.Add("item", new KeyValuePair("URLARG", "UUID of the item/folder we are working on")); + base.Setup(); + } + } + + public class send : APIcall + { + public override void Setup() + { + about = "sends a item to an avatar"; + returns.Add("Failed"); + returns.Add("UUID"); + values.Add("item", new KeyValuePair("URLARG", "UUID of the item we are working on")); + values.Add("avatar", new KeyValuePair("URLARG", "a UUID or Firstname Lastname")); + base.Setup(); + } + } + + public class delete : APIcall + { + public override void Setup() + { + about = "Removes a item/folder from inventory (Make sure you set the isfolder flag correctly!)"; + returns.Add("Failed"); + returns.Add("UUID"); + values.Add("item", new KeyValuePair("URLARG", "UUID of the item/folder we are working on")); + values.Add("isfolder", new KeyValuePair("URLARG", "true or false if this is a folder")); + base.Setup(); + } + } + + public class chatwindows : APIcall + { + public override void Setup() + { + about = "gets a full list of all chat windows"; + returns.Add("array UUID = Name"); + base.Setup(); + } + } + + public class listwithunread : APIcall + { + public override void Setup() + { + about = "gets a list of chat windows with unread messages"; + returns.Add("array of UUID"); + base.Setup(); + } + } + + public class haveunreadims : APIcall + { + public override void Setup() + { + about = "gets if there are any unread im messages at all"; + returns.Add("true|false"); + base.Setup(); + } + } + + public class getimchat : APIcall + { + public override void Setup() + { + about = "gets the chat from the selected window"; + values.Add("window", new KeyValuePair("URLARG", "the UUID of the chat window")); + returns.Add("Chat contents"); + returns.Add("Window UUID invaild"); + base.Setup(); + } + } + + public class sendimchat : postAPIcall + { + public override void Setup() + { + about = "sends a im to the selected avatar"; + values.Add("avatar", new KeyValuePair("URLARG", "a UUID or Firstname Lastname")); + values.Add("message", new KeyValuePair("string", "the message to send")); + returns.Add("ok"); + base.Setup(); + } + } + + public class listgroups : APIcall + { + public override void Setup() + { + about = "fetchs a list of all groups known to the bot"; + returns.Add("array UUID=name"); + base.Setup(); + } + } + + public class listgroupswithunread : APIcall + { + public override void Setup() + { + about = "fetchs a list of all groups with unread messages"; + returns.Add("array UUID"); + base.Setup(); + } + } + + public class haveunreadgroupchat : APIcall + { + public override void Setup() + { + about = "checks if there are any groups with unread messages"; + returns.Add("true|false"); + base.Setup(); + } + } + + public class getgroupchat : APIcall + { + public override void Setup() + { + about = "fetchs the groupchat history"; + values.Add("group ", new KeyValuePair("URLARG", "UUID of the group")); + returns.Add("Group UUID invaild"); + returns.Add("Group Chat"); + base.Setup(); + } + } + + public class sendgroupchat : postAPIcall + { + public override void Setup() + { + about = "sends a message to the groupchat"; + values.Add("group ", new KeyValuePair("URLARG", "UUID of the group")); + values.Add("message ", new KeyValuePair("string", "the message to send")); + returns.Add("Group UUID invaild"); + returns.Add("Processing"); + base.Setup(); + } + } + + public class localchathistory : APIcall + { + public override void Setup() + { + about = "fetchs the last 20 localchat messages"; + returns.Add("array string"); + base.Setup(); + } + } + + public class localchatsay : postAPIcall + { + public override void Setup() + { + about = "sends a message to localchat"; + values.Add("message ", new KeyValuePair("string", "the message to send")); + returns.Add("see->localchathistory"); + base.Setup(); + } + } + } diff --git a/Core/Commands/Friends/Friendslist.cs b/Core/Commands/Friends/Friendslist.cs new file mode 100644 index 0000000..f14c55f --- /dev/null +++ b/Core/Commands/Friends/Friendslist.cs @@ -0,0 +1,18 @@ +using System; +using OpenMetaverse; +namespace BSB.Commands.Friends +{ + public class Friendslist : CoreCommand_SmartReply_1arg + { + public override string Helpfile { get { return "Returns a copy of the friends list"; } } + public override bool CallFunction(string[] args) + { + if (base.CallFunction(args) == true) + { + return bot.GetCommandsInterface.SmartCommandReply(true, args[0], bot.getJsonFriendlist(), CommandName); + } + return false; + } + } + +} diff --git a/Core/Commands/Inventory/DeleteInventory.cs b/Core/Commands/Inventory/DeleteInventory.cs new file mode 100644 index 0000000..8fb6611 --- /dev/null +++ b/Core/Commands/Inventory/DeleteInventory.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using OpenMetaverse; + +namespace BSB.Commands.Inventory +{ + public class DeleteInventoryItem : CoreCommand_1arg + { + public override string[] ArgTypes { get { return new[] { "UUID" }; } } + public override string[] ArgHints { get { return new[] { "inventory UUID" }; } } + public override string Helpfile { get { return "Attempts to Remove the given inventory item"; } } + public override bool CallFunction(string[] args) + { + if (base.CallFunction(args) == true) + { + if (UUID.TryParse(args[0], out UUID removeme) == true) + { + bot.GetClient.Inventory.Remove(new List() { removeme }, new List()); + return true; + } + return Failed("Invaild inventory UUID"); + } + return false; + } + } + + public class DeleteInventoryFolder : CoreCommand_1arg + { + public override string[] ArgTypes { get { return new[] { "UUID" }; } } + public override string[] ArgHints { get { return new[] { "inventory UUID" }; } } + public override string Helpfile { get { return "Attempts to Remove the given inventory folder"; } } + public override bool CallFunction(string[] args) + { + if (base.CallFunction(args) == true) + { + if (UUID.TryParse(args[0], out UUID removeme) == true) + { + bot.GetClient.Inventory.Remove(new List(), new List() { removeme }); + return true; + } + return Failed("Invaild inventory UUID"); + } + return false; + } + } +} diff --git a/Core/Commands/Inventory/RenameInventory.cs b/Core/Commands/Inventory/RenameInventory.cs new file mode 100644 index 0000000..3cf20b2 --- /dev/null +++ b/Core/Commands/Inventory/RenameInventory.cs @@ -0,0 +1,41 @@ +using BSB.Static; +using OpenMetaverse; + +namespace BSB.Commands.Inventory +{ + public class RenameInventory : CoreCommand_3arg + { + public override string[] ArgTypes { get { return new[] { "Smart", "UUID", "Text" }; } } + public override string[] ArgHints { get { return new[] { "Smart reply target: Channel,Avatar,HTTP", "Inventory UUID", "New name" }; } } + public override string Helpfile + { + get + { + return "Renames an inventory item to something else."; + } + } + public override bool CallFunction(string[] args) + { + if (base.CallFunction(args) == true) + { + if (UUID.TryParse(args[1], out UUID target) == true) + { + if (args[2].Length >= 1) + { + InventoryItem item = HelperInventory.getItemByInventoryUUID(bot, target); + if (item != null) + { + item.Name = args[2]; + bot.GetClient.Inventory.RequestUpdateItem(item); + return true; + } + return Failed("Unable to get base item"); + } + return Failed("Item name is to short"); + } + return Failed("Unable to get UUID from target"); + } + return false; + } + } +} diff --git a/Core/Commands/Inventory/getRealUUID.cs b/Core/Commands/Inventory/getRealUUID.cs new file mode 100644 index 0000000..5504de8 --- /dev/null +++ b/Core/Commands/Inventory/getRealUUID.cs @@ -0,0 +1,35 @@ +using BSB.Static; +using OpenMetaverse; + +namespace BSB.Commands.Inventory +{ + public class getRealUUID : CoreCommand_2arg + { + public override string[] ArgTypes { get { return new[] { "Smart", "UUID" }; } } + public override string[] ArgHints { get { return new[] { "Smart reply target: Channel,Avatar,HTTP", "Inventory UUID" }; } } + public override string Helpfile + { + get + { + return "Converts a Inventory UUID into an asset UUID used to send? im not sure yet"; + } + } + public override bool CallFunction(string[] args) + { + if (base.CallFunction(args) == true) + { + if(UUID.TryParse(args[1],out UUID target) == true) + { + UUID reply = HelperInventory.GetAssetUUID(bot, target); + if(reply != UUID.Zero) + { + return bot.GetCommandsInterface.SmartCommandReply(true, args[0], reply.ToString(), CommandName); + } + return bot.GetCommandsInterface.SmartCommandReply(false, args[0], "Unable to fetch asset UUID", CommandName); + } + return bot.GetCommandsInterface.SmartCommandReply(false, args[0], "Unable to process target UUID", CommandName); + } + return false; + } + } +} diff --git a/Core/Commands/Inventory/sendItem.cs b/Core/Commands/Inventory/sendItem.cs index 1dfcc3e..af0eeb9 100644 --- a/Core/Commands/Inventory/sendItem.cs +++ b/Core/Commands/Inventory/sendItem.cs @@ -23,7 +23,7 @@ namespace BSB.Commands.Inventory InventoryItem itm = bot.GetClient.Inventory.FetchItem(targetitem, bot.GetClient.Self.AgentID, (search_delay_time * 1000)); if (itm != null) { - bot.GetClient.Inventory.GiveItem(itm.AssetUUID, itm.Name, itm.AssetType, targetavatar, false); + bot.GetClient.Inventory.GiveItem(itm.UUID, itm.Name, itm.AssetType, targetavatar, false); return true; } else diff --git a/Core/Static/Inventory.cs b/Core/Static/Inventory.cs index a062e7c..cd50ae0 100644 --- a/Core/Static/Inventory.cs +++ b/Core/Static/Inventory.cs @@ -22,6 +22,19 @@ namespace BSB.Static public static class HelperInventory { + public static InventoryItem getItemByInventoryUUID(CommandsBot bot, UUID target) + { + return bot.GetClient.Inventory.FetchItem(target, bot.GetClient.Self.AgentID, 3000); + } + public static UUID GetAssetUUID(CommandsBot bot, UUID target) + { + InventoryItem A = getItemByInventoryUUID(bot, target); + if (A != null) + { + return A.AssetUUID; + } + return UUID.Zero; + } public static InventoryBase FindFolder(CommandsBot bot, InventoryFolder current,UUID target) { List T = bot.GetClient.Inventory.Store.GetContents(current); @@ -102,7 +115,14 @@ namespace BSB.Static public static string MapFolderJson(CommandsBot bot) { - return JsonConvert.SerializeObject(DoMapFolderJson(bot, bot.GetClient.Inventory.Store.RootFolder)).Replace("\\\"","\""); + if (bot.GetClient.Inventory.Store != null) + { + if (bot.GetClient.Inventory.Store.RootFolder != null) + { + return JsonConvert.SerializeObject(DoMapFolderJson(bot, bot.GetClient.Inventory.Store.RootFolder)); + } + } + return null; } public static InventoryMapFolder DoMapFolderJson(CommandsBot bot, InventoryFolder folder) diff --git a/Core/bottypes/AVstorageBot.cs b/Core/bottypes/AVstorageBot.cs index ea985be..b72f03b 100644 --- a/Core/bottypes/AVstorageBot.cs +++ b/Core/bottypes/AVstorageBot.cs @@ -25,6 +25,32 @@ namespace BSB.bottypes protected bool show_av_storage_info_in_status = true; protected string AVstorageBot_laststatus = ""; + + protected Dictionary FriendNames = new Dictionary(); + protected override void AvatarFriendNames(object o, FriendNamesEventArgs E) + { + FriendNames = E.Names; + } + + public string getJsonFriendlist() + { + Dictionary Friends = new Dictionary(); + Dictionary friendscopy = GetClient.Friends.FriendList.Copy(); + foreach (KeyValuePair av in friendscopy) + { + string name = FindAvatarKey2Name(av.Key); + if (name != "loopup") + { + friendreplyobject entry = new friendreplyobject(); + entry.name = name; + entry.id = av.Key.ToString(); + entry.online = av.Value.IsOnline; + Friends.Add(av.Key, entry); + } + } + return JsonConvert.SerializeObject(Friends); + } + public override string GetStatus() { cleanupAvatarStorage(); @@ -46,6 +72,7 @@ namespace BSB.bottypes } reply += AvatarStorageLastUsed.Count.ToString() + " loaded"; } + reply += " - " + FriendNames.Count() + " Friends"; if (reply != "") { reply = " (AVStorage: " + reply + ")"; @@ -299,6 +326,19 @@ namespace BSB.bottypes AvatarStorageLastUsed[avatar_name] = helpers.UnixTimeNow(); return AvatarName2Key[avatar_name].ToString(); } + else if (FriendNames.ContainsValue(avatar_name) == true) + { + string returnvalue = ""; + foreach(UUID entry in FriendNames.Keys) + { + if(FriendNames[entry] == avatar_name) + { + returnvalue = entry.ToString(); + break; + } + } + return returnvalue; + } return ""; } @@ -336,6 +376,10 @@ namespace BSB.bottypes AvatarStorageLastUsed[AvatarKey2Name[avatar_uuid]] = helpers.UnixTimeNow(); return AvatarKey2Name[avatar_uuid]; } + else if(FriendNames.ContainsKey(avatar_uuid) == true) + { + return FriendNames[avatar_uuid]; + } return ""; } @@ -406,5 +450,12 @@ namespace BSB.bottypes public bool found { get; set; } public bool status { get; set; } public string message { get; set; } + } + + public class friendreplyobject + { + public string name; + public string id; + public bool online; } } diff --git a/Core/bottypes/EventsBot.cs b/Core/bottypes/EventsBot.cs index 1fee607..5987c9c 100644 --- a/Core/bottypes/EventsBot.cs +++ b/Core/bottypes/EventsBot.cs @@ -354,11 +354,18 @@ namespace BSB.bottypes Client.Groups.CurrentGroups += GroupsHandler; Client.Self.ScriptQuestion += PermissionsHandler; Client.Friends.FriendshipResponse += FriendshipResponse; + Client.Friends.FriendNames += AvatarFriendNames; delay_group_fetch = helpers.UnixTimeNow() + 10; } base.AfterBotLoginHandler(); } + + protected virtual void AvatarFriendNames(object o, FriendNamesEventArgs E) + { + + } + protected virtual void FriendshipResponse(object o, FriendshipResponseEventArgs E) { diff --git a/Core/bottypes/chatrelay.cs b/Core/bottypes/chatrelay.cs index 3287373..15ea1a5 100644 --- a/Core/bottypes/chatrelay.cs +++ b/Core/bottypes/chatrelay.cs @@ -50,13 +50,22 @@ namespace BSB.bottypes } public override void AddToIMchat(UUID avatar, string name, string message) { + string sendername = name; + if(sendername == GetClient.Self.Name) + { + name = FindAvatarKey2Name(avatar); + } if (im_chat_history.ContainsKey(avatar) == false) { + if(im_chat_history_to_name.ContainsKey(avatar) == false) + { + im_chat_history_to_name.Add(avatar, name); + } im_chat_history.Add(avatar, new List()); im_chat_unread.Add(avatar, false); } var date = DateTime.Now; - im_chat_history[avatar].Add("[" + date.Hour.ToString() + ":" + date.Minute.ToString() + "] " + name + ":" + message + ""); + im_chat_history[avatar].Add("[" + date.Hour.ToString() + ":" + date.Minute.ToString() + "] " + sendername + ":" + message + ""); if (im_chat_history[avatar].Count > imchatlimit) { im_chat_history[avatar].RemoveAt(0); @@ -110,6 +119,11 @@ namespace BSB.bottypes } } } + } + + public override bool HasUnreadGroupchats() + { + return group_chat_unread.ContainsValue(true); } public override bool GroupHasUnread(UUID group) diff --git a/libremetaverse-core/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj b/libremetaverse-core/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj new file mode 100644 index 0000000..71abbb8 --- /dev/null +++ b/libremetaverse-core/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj @@ -0,0 +1,87 @@ + + + Local + 14.0.25123 + 2.0 + {89D7A3E5-0000-0000-0000-000000000000} + Debug;Release;DockerBuild + LibreMetaverse.StructuredData + JScript + Grid + IE50 + false + netcoreapp3.1 + Library + LibreMetaverse.StructuredData + true + + + True + 285212672 + False + + + TRACE;DEBUG + True + 4096 + False + ..\bin\ + False + False + False + 4 + False + 1591,1574,0419 + AnyCPU + + + True + 285212672 + False + TRACE + LibreMetaverse.StructuredData.XML + False + 4096 + True + ..\bin\ + False + False + False + 4 + False + 1591,1574,0419 + AnyCPU + + + none + Linux + false + false + false + linux-x64 + + + + + + + + + + True + + + + + + + + + 1.2.0 + Sjofn LLC, OpenMetaverse Developers + LibreMetaverse.StructuredData + Copyright © OpenMetaverse Developers 2008, 2017. Copyright © Sjofn LLC 2018-2019. All rights reserved. + LICENSE.txt + https://github.com/cinderblocks/libremetaverse + + \ No newline at end of file diff --git a/libremetaverse-core/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.nuspec b/libremetaverse-core/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.nuspec new file mode 100644 index 0000000..aac0f8b --- /dev/null +++ b/libremetaverse-core/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.nuspec @@ -0,0 +1,15 @@ + + + + LibreMetaverse.StructuredData + $version$ + Cinder Biscuits + Cinder Biscuits + https://github.com/cinderblocks/libremetaverse/blob/master/LICENSE.txt + https://github.com/cinderblocks/libremetaverse + false + LibreMetaverse structured data library + Copyright 2017 + LMV OMV OpenMetaverse OpenSim Halcyon OpenMetaverseFoundation VirtualWorld Radegast SecondLife + + \ No newline at end of file diff --git a/libremetaverse-core/LibreMetaverse/LibreMetaverse.csproj b/libremetaverse-core/LibreMetaverse/LibreMetaverse.csproj new file mode 100644 index 0000000..289e680 --- /dev/null +++ b/libremetaverse-core/LibreMetaverse/LibreMetaverse.csproj @@ -0,0 +1,95 @@ + + + Local + 14.0.25123 + 2.0 + {27C70F3A-0000-0000-0000-000000000000} + Debug + Debug;Release;DockerBuild + LibreMetaverse + JScript + Grid + IE50 + false + Library + LibreMetaverse + true + netcoreapp3.1 + + + True + 285212672 + False + TRACE;DEBUG + True + 4096 + False + ..\bin\ + False + False + False + 4 + False + 1591,1574,0419 + AnyCPU + + + True + 285212672 + False + TRACE + LibreMetaverse.XML + False + 4096 + True + ..\bin\ + False + False + False + 4 + False + 1591,1574,0419 + AnyCPU + + + none + Linux + false + false + false + linux-x64 + + + + + + + + + + + + + + + + + + + True + + + + + + + + + 1.2.0 + Sjofn LLC, OpenMetaverse Developers + LibreMetaverse + Copyright © OpenMetaverse Developers 2008, 2017. Copyright © Sjofn LLC 2018-2019. All rights reserved. + LICENSE.txt + https://github.com/cinderblocks/libremetaverse + + \ No newline at end of file diff --git a/libremetaverse-core/LibreMetaverse/LibreMetaverse.nuspec b/libremetaverse-core/LibreMetaverse/LibreMetaverse.nuspec new file mode 100644 index 0000000..d4a4903 --- /dev/null +++ b/libremetaverse-core/LibreMetaverse/LibreMetaverse.nuspec @@ -0,0 +1,15 @@ + + + + LibreMetaverse + $version$ + Cinder Biscuits + Cinder Biscuits + https://github.com/cinderblocks/libremetaverse/blob/master/LICENSE.txt + https://github.com/cinderblocks/libremetaverse + false + LibreMetaverse allows your code to read and work with data send across a SecondLife, Halcyon, OpenSimulator, or related connection. + Copyright 2017 + LMV OMV OpenMetaverse OpenSim OpenSimulator Halcyon OpenMetaverseFoundation VirtualWorld Radegast SecondLife + + \ No newline at end of file diff --git a/libremetaverse-core/Libremetaverse.types/CRC32.cs b/libremetaverse-core/LibreMetaverseTypes/CRC32.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/CRC32.cs rename to libremetaverse-core/LibreMetaverseTypes/CRC32.cs diff --git a/libremetaverse-core/Libremetaverse.types/Color4.cs b/libremetaverse-core/LibreMetaverseTypes/Color4.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/Color4.cs rename to libremetaverse-core/LibreMetaverseTypes/Color4.cs diff --git a/libremetaverse-core/Libremetaverse.types/DoubleDictionary.cs b/libremetaverse-core/LibreMetaverseTypes/DoubleDictionary.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/DoubleDictionary.cs rename to libremetaverse-core/LibreMetaverseTypes/DoubleDictionary.cs diff --git a/libremetaverse-core/Libremetaverse.types/Enums.cs b/libremetaverse-core/LibreMetaverseTypes/Enums.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/Enums.cs rename to libremetaverse-core/LibreMetaverseTypes/Enums.cs diff --git a/libremetaverse-core/Libremetaverse.types/EnumsPrimitive.cs b/libremetaverse-core/LibreMetaverseTypes/EnumsPrimitive.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/EnumsPrimitive.cs rename to libremetaverse-core/LibreMetaverseTypes/EnumsPrimitive.cs diff --git a/libremetaverse-core/Libremetaverse.types/ExpiringCache.cs b/libremetaverse-core/LibreMetaverseTypes/ExpiringCache.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/ExpiringCache.cs rename to libremetaverse-core/LibreMetaverseTypes/ExpiringCache.cs diff --git a/libremetaverse-core/LibreMetaverseTypes/LibreMetaverse.Types.csproj b/libremetaverse-core/LibreMetaverseTypes/LibreMetaverse.Types.csproj new file mode 100644 index 0000000..bd59a44 --- /dev/null +++ b/libremetaverse-core/LibreMetaverseTypes/LibreMetaverse.Types.csproj @@ -0,0 +1,81 @@ + + + Local + 14.0.25123 + 2.0 + {B37B02AD-0000-0000-0000-000000000000} + Debug;Release;DockerBuild + LibreMetaverse.Types + JScript + Grid + IE50 + false + netcoreapp3.1 + Library + LibreMetaverse + true + + + True + 285212672 + False + TRACE;DEBUG + True + 4096 + False + ..\bin\ + False + False + False + 4 + False + 1591,1574,0419 + AnyCPU + + + True + 285212672 + False + TRACE + LibreMetaverseTypes.XML + False + 4096 + True + ..\bin\ + False + False + False + 4 + False + 1591,1574,0419 + AnyCPU + + + none + Linux + false + false + false + linux-x64 + + + + + + + True + + + + + + + + + 1.2.0 + Sjofn LLC, Openmetaverse Developers + Copyright © OpenMetaverse Developers 2008, 2017. Copyright © Sjofn LLC. All rights reserved. + LICENSE.txt + https://github.com/cinderblocks/libremetaverse + + \ No newline at end of file diff --git a/libremetaverse-core/LibreMetaverseTypes/LibreMetaverseTypes.nuspec b/libremetaverse-core/LibreMetaverseTypes/LibreMetaverseTypes.nuspec new file mode 100644 index 0000000..2d87b09 --- /dev/null +++ b/libremetaverse-core/LibreMetaverseTypes/LibreMetaverseTypes.nuspec @@ -0,0 +1,15 @@ + + + + LibreMetaverse.Types + $version$ + Cinder Biscuits + Cinder Biscuits + https://github.com/cinderblocks/libremetaverse/blob/master/LICENSE.txt + https://github.com/cinderblocks/libremetaverse + false + LibreMetaverse type library + Copyright 2017 + LMV OMV OpenMetaverse OpenSim Halcyon OpenMetaverseFoundation VirtualWorld Radegast SecondLife + + \ No newline at end of file diff --git a/libremetaverse-core/Libremetaverse.types/Matrix4.cs b/libremetaverse-core/LibreMetaverseTypes/Matrix4.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/Matrix4.cs rename to libremetaverse-core/LibreMetaverseTypes/Matrix4.cs diff --git a/libremetaverse-core/Libremetaverse.types/Quaternion.cs b/libremetaverse-core/LibreMetaverseTypes/Quaternion.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/Quaternion.cs rename to libremetaverse-core/LibreMetaverseTypes/Quaternion.cs diff --git a/libremetaverse-core/Libremetaverse.types/ThreadSafeDictionary.cs b/libremetaverse-core/LibreMetaverseTypes/ThreadSafeDictionary.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/ThreadSafeDictionary.cs rename to libremetaverse-core/LibreMetaverseTypes/ThreadSafeDictionary.cs diff --git a/libremetaverse-core/Libremetaverse.types/TokenBucket.cs b/libremetaverse-core/LibreMetaverseTypes/TokenBucket.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/TokenBucket.cs rename to libremetaverse-core/LibreMetaverseTypes/TokenBucket.cs diff --git a/libremetaverse-core/Libremetaverse.types/UUID.cs b/libremetaverse-core/LibreMetaverseTypes/UUID.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/UUID.cs rename to libremetaverse-core/LibreMetaverseTypes/UUID.cs diff --git a/libremetaverse-core/Libremetaverse.types/Utils.cs b/libremetaverse-core/LibreMetaverseTypes/Utils.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/Utils.cs rename to libremetaverse-core/LibreMetaverseTypes/Utils.cs diff --git a/libremetaverse-core/Libremetaverse.types/UtilsConversions.cs b/libremetaverse-core/LibreMetaverseTypes/UtilsConversions.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/UtilsConversions.cs rename to libremetaverse-core/LibreMetaverseTypes/UtilsConversions.cs diff --git a/libremetaverse-core/Libremetaverse.types/Vector2.cs b/libremetaverse-core/LibreMetaverseTypes/Vector2.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/Vector2.cs rename to libremetaverse-core/LibreMetaverseTypes/Vector2.cs diff --git a/libremetaverse-core/Libremetaverse.types/Vector3.cs b/libremetaverse-core/LibreMetaverseTypes/Vector3.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/Vector3.cs rename to libremetaverse-core/LibreMetaverseTypes/Vector3.cs diff --git a/libremetaverse-core/Libremetaverse.types/Vector3d.cs b/libremetaverse-core/LibreMetaverseTypes/Vector3d.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/Vector3d.cs rename to libremetaverse-core/LibreMetaverseTypes/Vector3d.cs diff --git a/libremetaverse-core/Libremetaverse.types/Vector4.cs b/libremetaverse-core/LibreMetaverseTypes/Vector4.cs similarity index 100% rename from libremetaverse-core/Libremetaverse.types/Vector4.cs rename to libremetaverse-core/LibreMetaverseTypes/Vector4.cs diff --git a/libremetaverse-core/Libremetaverse.structureddata/LibreMetaverse-core.StructuredData.csproj b/libremetaverse-core/Libremetaverse.structureddata/LibreMetaverse-core.StructuredData.csproj deleted file mode 100644 index ceca150..0000000 --- a/libremetaverse-core/Libremetaverse.structureddata/LibreMetaverse-core.StructuredData.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - True - netcoreapp3.1 - Debug;Release;DockerBuild - x64 - LICENSE.txt - see LibreMetaverse-core - false - 1.0.3 - https://github.com/Madpeterz/libremetaverse-core - https://github.com/Madpeterz/libremetaverse-core - git - 1.0.3.0 - - - none - Linux - false - false - false - linux-x64 - - - - - - - True - - - - \ No newline at end of file diff --git a/libremetaverse-core/Libremetaverse.types/LibreMetaverse-core.Types.csproj b/libremetaverse-core/Libremetaverse.types/LibreMetaverse-core.Types.csproj deleted file mode 100644 index 691a94c..0000000 --- a/libremetaverse-core/Libremetaverse.types/LibreMetaverse-core.Types.csproj +++ /dev/null @@ -1,31 +0,0 @@ - - - True - netcoreapp3.1 - Debug;Release;DockerBuild - x64 - false - see LibreMetaverse-core - LICENSE.txt - https://github.com/Madpeterz/libremetaverse-core - https://github.com/Madpeterz/libremetaverse-core - git - 1.0.3.0 - 1.0.3.0 - 1.0.3 - - - none - Linux - false - false - false - linux-x64 - - - - True - - - - \ No newline at end of file diff --git a/libremetaverse-core/Libremetaverse/Imaging/BakeLayer.cs b/libremetaverse-core/Libremetaverse/Imaging/BakeLayer.cs index 49a9b4f..24677f6 100644 --- a/libremetaverse-core/Libremetaverse/Imaging/BakeLayer.cs +++ b/libremetaverse-core/Libremetaverse/Imaging/BakeLayer.cs @@ -30,6 +30,7 @@ using System.Collections.Generic; using System.IO; using System.Drawing; using OpenMetaverse.Assets; +using log4net; namespace OpenMetaverse.Imaging { @@ -39,6 +40,7 @@ namespace OpenMetaverse.Imaging /// public class Baker { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); #region Properties /// Final baked texture public AssetTexture BakedTexture => bakedTexture; @@ -331,6 +333,7 @@ namespace OpenMetaverse.Imaging } // Apply any alpha wearable textures to make parts of the avatar disappear + m_log.DebugFormat("[XBakes]: Number of alpha wearable textures: {0}", alphaWearableTextures.Count); foreach (ManagedImage img in alphaWearableTextures) AddAlpha(bakedTexture.Image, img); @@ -349,8 +352,11 @@ namespace OpenMetaverse.Imaging lock (ResourceSync) { using (Stream stream = Helpers.GetResourceStream(fileName, Settings.RESOURCE_DIR)) - { - bitmap = LoadTGAClass.LoadTGA(stream); + { + if (stream != null) + { + bitmap = LoadTGAClass.LoadTGA(stream); + } } } if (bitmap == null) diff --git a/libremetaverse-core/Libremetaverse/Imaging/TGALoader.cs b/libremetaverse-core/Libremetaverse/Imaging/TGALoader.cs index 36af43b..dd309bb 100644 --- a/libremetaverse-core/Libremetaverse/Imaging/TGALoader.cs +++ b/libremetaverse-core/Libremetaverse/Imaging/TGALoader.cs @@ -624,8 +624,12 @@ namespace OpenMetaverse.Imaging { using (System.IO.FileStream f = System.IO.File.OpenRead(filename)) { - return LoadTGA(f); + if (f != null) + { + return LoadTGA(f); + } } + return null; // file stream error } catch (System.IO.DirectoryNotFoundException) { diff --git a/libremetaverse-core/Libremetaverse/InventoryAISClient.cs b/libremetaverse-core/Libremetaverse/InventoryAISClient.cs index 96dedc2..8d1e4e1 100644 --- a/libremetaverse-core/Libremetaverse/InventoryAISClient.cs +++ b/libremetaverse-core/Libremetaverse/InventoryAISClient.cs @@ -20,11 +20,16 @@ namespace LibreMetaverse [NonSerialized] private readonly GridClient Client; - private static readonly HttpClient httpClient = new HttpClient(); + private static HttpClient httpClient; public InventoryAISClient(GridClient client) { Client = client; + + HttpClientHandler clientHandler = new HttpClientHandler(); + clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }; + httpClient = new HttpClient(clientHandler); + httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Add("User-Agent", "LibreMetaverse AIS Client"); } diff --git a/libremetaverse-core/Libremetaverse/InventoryManager.cs b/libremetaverse-core/Libremetaverse/InventoryManager.cs index 2d83f25..f25ddc7 100644 --- a/libremetaverse-core/Libremetaverse/InventoryManager.cs +++ b/libremetaverse-core/Libremetaverse/InventoryManager.cs @@ -686,27 +686,30 @@ namespace OpenMetaverse List load_items = new List(); List owner_ids = new List(); - foreach (InventoryBase o in objects) + if (objects != null) { - if (o.GetType() != typeof(InventoryFolder)) + foreach (InventoryBase o in objects) { - InventoryItem ob = (InventoryItem)o; - if ((ob.IsLink() == true) && (fast_loading == false)) + if (o.GetType() != typeof(InventoryFolder)) { - if (Store.Items.ContainsKey(ob.AssetUUID) == false) + InventoryItem ob = (InventoryItem)o; + if ((ob.IsLink() == true) && (fast_loading == false)) { - load_items.Add(ob.AssetUUID); - owner_ids.Add(Client.Self.AgentID); + if (Store.Items.ContainsKey(ob.AssetUUID) == false) + { + load_items.Add(ob.AssetUUID); + owner_ids.Add(Client.Self.AgentID); + } + else + { + cleaned_list.Add(Client.Inventory.FetchItem(ob.AssetUUID, Client.Self.AgentID, 1000 * 5)); + } } else { - cleaned_list.Add(Client.Inventory.FetchItem(ob.AssetUUID, Client.Self.AgentID, 1000 * 5)); + cleaned_list.Add(ob); } } - else - { - cleaned_list.Add(ob); - } } } diff --git a/libremetaverse-core/Libremetaverse/LibreMetaverse-core.csproj b/libremetaverse-core/Libremetaverse/LibreMetaverse-core.csproj deleted file mode 100644 index 0603d15..0000000 --- a/libremetaverse-core/Libremetaverse/LibreMetaverse-core.csproj +++ /dev/null @@ -1,62 +0,0 @@ - - - True - netcoreapp3.1 - Debug;Release;DockerBuild - x64 - false - LICENSE.txt - .net core targeted version of the LibreMetaverse project - https://github.com/Madpeterz/libremetaverse-core - https://github.com/Madpeterz/libremetaverse-core - git - 1.0.3 - 1.0.3.0 - - - none - Linux - false - false - false - linux-x64 - - - - - - - Always - - - - - - - - - - - - - - - True - - - - - - Always - - - Always - - - Always - - - Always - - - \ No newline at end of file diff --git a/libremetaverse-core/Libremetaverse/LibreMetaverse-core.nuspec b/libremetaverse-core/Libremetaverse/LibreMetaverse-core.nuspec deleted file mode 100644 index be54ca9..0000000 --- a/libremetaverse-core/Libremetaverse/LibreMetaverse-core.nuspec +++ /dev/null @@ -1,15 +0,0 @@ - - - - LibreMetaverse-core - $version$ - Madpeterz - Madpeterz - https://github.com/Madpeterz/libremetaverse-core/blob/master/LICENSE.txt - https://github.com/Madpeterz/libremetaverse-core - false - A port of LibreMetaverse to .net core cleaned up - Copyright 2020 - SecondLife Docker Linux Windows Secondbot CLI - - diff --git a/libremetaverse-core/Libremetaverse/Logger.cs b/libremetaverse-core/Libremetaverse/Logger.cs index c58f490..eb1cb46 100644 --- a/libremetaverse-core/Libremetaverse/Logger.cs +++ b/libremetaverse-core/Libremetaverse/Logger.cs @@ -1,209 +1,188 @@ +/* + * Copyright (c) 2006-2016, openmetaverse.co + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.co nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + using System; -using System.Text; +using System.Reflection; +using log4net; +using log4net.Appender; +using log4net.Config; + +[assembly: XmlConfigurator(Watch = true)] namespace OpenMetaverse { - public abstract class LogWriter - { - public static void LogMessage(StringBuilder messageBuilder, Helpers.LogLevel Level) - { - var date = DateTime.Now; - string Message = messageBuilder.ToString(); - messageBuilder.Clear(); - messageBuilder.Append("["); - if (date.Hour < 10) messageBuilder.Append("0"); - messageBuilder.Append(date.Hour.ToString()); - messageBuilder.Append(":"); - if (date.Minute < 10) messageBuilder.Append("0"); - messageBuilder.Append(date.Minute.ToString()); - messageBuilder.Append("] "); - switch (Level) - { - case Helpers.LogLevel.Debug: - { - messageBuilder.Append("Debug - "); - break; - } - case Helpers.LogLevel.Info: - { - messageBuilder.Append("Status - "); - break; - } - case Helpers.LogLevel.Warning: - { - messageBuilder.Append("Warn - "); - break; - } - case Helpers.LogLevel.Error: - { - messageBuilder.Append("Error - "); - break; - } - default: - break; - } - messageBuilder.Append(Message); - WriteMessage(Message); - } - protected static void WriteMessage(string message) - { - - } - } - public class NoLogWriter : LogWriter - { - } - public class ConsoleWriter : LogWriter - { - public new static void WriteMessage(string message) - { - Console.WriteLine(message); - } - } - + /// + /// Singleton logging class for the entire library + /// public static class Logger { - // Warn,Error,Log,Debug functions - #region Message only methods without Levels - public static void Warn(string message) - { - Log(message, Helpers.LogLevel.Warning); - } - public static void Error(string message) - { - Log(message, Helpers.LogLevel.Error); - } - public static void Info(string message) - { - Log(message, Helpers.LogLevel.Info); - } - public static void DebugLog(string message) - { - Log(message, Helpers.LogLevel.Debug); - } - #endregion - #region Message+Exception without levels - public static void Warn(string message, Exception e) - { - Log(message, Helpers.LogLevel.Warning, null, e); - } - public static void Error(string message, Exception e) - { - Log(message, Helpers.LogLevel.Error, null, e); - } - public static void Info(string message, Exception e) - { - Log(message, Helpers.LogLevel.Info, null, e); - } - public static void DebugLog(string message, Exception e) - { - Log(message, Helpers.LogLevel.Debug, null, e); - } - #endregion - #region Message+Client without levels - public static void Warn(string message, GridClient client) - { - Log(message, Helpers.LogLevel.Warning, client); - } - public static void Error(string message, GridClient client) - { - Log(message, Helpers.LogLevel.Error, client); - } - public static void Info(string message, GridClient client) - { - Log(message, Helpers.LogLevel.Info, client); - } - public static void DebugLog(string message, GridClient client) - { - Log(message, Helpers.LogLevel.Debug, client); - } - #endregion - #region Message+Client+Exeption without levels [Anything else call Log Directly] - public static void Warn(string message, GridClient client, Exception exception) - { - Log(message, Helpers.LogLevel.Warning, client, exception); - } - public static void Error(string message, GridClient client, Exception exception) - { - Log(message, Helpers.LogLevel.Error, client, exception); - } - public static void Info(string message, GridClient client, Exception exception) - { - Log(message, Helpers.LogLevel.Info, client, exception); - } - public static void DebugLog(string message, GridClient client, Exception exception) - { - Log(message, Helpers.LogLevel.Debug, client, exception); - } - #endregion + /// + /// Callback used for client apps to receive log messages from + /// the library + /// + /// Data being logged + /// The severity of the log entry from + public delegate void LogCallback(object message, Helpers.LogLevel level); - public static void Log(string message, Helpers.LogLevel Level, GridClient client, Exception exception) + /// Triggered whenever a message is logged. If this is left + /// null, log messages will go to the console + public static event LogCallback OnLogMessage; + + /// log4net logging engine + public static ILog LogInstance; + + /// + /// Default constructor + /// + static Logger() { - Helpers.LogLevel UseLevel = Helpers.LogLevel.Info; - string useWriter = "Console"; - - if (client != null) + LogInstance = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // If error level reporting isn't enabled we assume no logger is configured and initialize a default + // ConsoleAppender + if (!LogInstance.Logger.IsEnabledFor(log4net.Core.Level.Error)) { - UseLevel = client.Settings.LOG_LEVEL; - useWriter = client.Settings.LOG_WRITER; - } - if (UseLevel >= Level) - { - StringBuilder NewMessage = new StringBuilder(); - if (client != null) + IAppender appender = new ConsoleAppender { - if (client.Settings.LOG_NAMES) - { - NewMessage.Append("{"); - NewMessage.Append(client.Self.Name); - NewMessage.Append("} "); - } - } - NewMessage.Append(message); - switch (useWriter) - { - case "NoLogWriter": - { - break; - } - default: - { - ConsoleWriter.LogMessage(NewMessage, Level); - break; - } - } + Layout = new log4net.Layout.PatternLayout("%timestamp [%thread] %-5level - %message%newline") + }; + BasicConfigurator.Configure(LogManager.GetRepository(Assembly.GetCallingAssembly()), appender); + + if(Settings.LOG_LEVEL != Helpers.LogLevel.None) + LogInstance.Info("No log configuration found, defaulting to console logging"); } } - public static void LogFormat(string Message, Helpers.LogLevel Level, int Value) + + /// + /// Send a log message to the logging engine + /// + /// The log message + /// The severity of the log entry + public static void Log(object message, Helpers.LogLevel level) { - LogFormat(Message, new[] { Value.ToString() }); - } - public static void LogFormat(string Message, string[] Values) - { - LogFormat(Message, Helpers.LogLevel.Debug, Values); - } - public static void LogFormat(string Message, Helpers.LogLevel Level, string[] Values) - { - Log(String.Format(Message, Values), Level); + Log(message, level, null, null); } - #region Log overloads - public static void Log(string message) + /// + /// Send a log message to the logging engine + /// + /// The log message + /// The severity of the log entry + /// Instance of the client + public static void Log(object message, Helpers.LogLevel level, GridClient client) { - Log(message, Helpers.LogLevel.Debug); + Log(message, level, client, null); } - public static void Log(string message, Helpers.LogLevel Level) + + /// + /// Send a log message to the logging engine + /// + /// The log message + /// The severity of the log entry + /// Exception that was raised + public static void Log(object message, Helpers.LogLevel level, Exception exception) { - Log(message, Level, null, null); + Log(message, level, null, exception); } - public static void Log(string message, Helpers.LogLevel Level, GridClient client) + + /// + /// Send a log message to the logging engine + /// + /// The log message + /// The severity of the log entry + /// Instance of the client + /// Exception that was raised + public static void Log(object message, Helpers.LogLevel level, GridClient client, Exception exception) { - Log(message, Level, null, null); + if (client != null && client.Settings.LOG_NAMES) + message = $"<{client.Self.Name}>: {message}"; + + OnLogMessage?.Invoke(message, level); + + switch (level) + { + case Helpers.LogLevel.Debug: + if (Settings.LOG_LEVEL == Helpers.LogLevel.Debug) + LogInstance.Debug(message, exception); + break; + case Helpers.LogLevel.Info: + if (Settings.LOG_LEVEL == Helpers.LogLevel.Debug + || Settings.LOG_LEVEL == Helpers.LogLevel.Info) + LogInstance.Info(message, exception); + break; + case Helpers.LogLevel.Warning: + if (Settings.LOG_LEVEL == Helpers.LogLevel.Debug + || Settings.LOG_LEVEL == Helpers.LogLevel.Info + || Settings.LOG_LEVEL == Helpers.LogLevel.Warning) + LogInstance.Warn(message, exception); + break; + case Helpers.LogLevel.Error: + if (Settings.LOG_LEVEL == Helpers.LogLevel.Debug + || Settings.LOG_LEVEL == Helpers.LogLevel.Info + || Settings.LOG_LEVEL == Helpers.LogLevel.Warning + || Settings.LOG_LEVEL == Helpers.LogLevel.Error) + LogInstance.Error(message, exception); + break; + default: + break; + } } - public static void Log(string message, Helpers.LogLevel Level, Exception exception) + + /// + /// If the library is compiled with DEBUG defined, an event will be + /// fired if an OnLogMessage handler is registered and the + /// message will be sent to the logging engine + /// + /// The message to log at the DEBUG level to the + /// current logging engine + public static void DebugLog(object message) { - Log(message, Level, null, exception); + DebugLog(message, null); + } + + /// + /// If the library is compiled with DEBUG defined and + /// GridClient.Settings.DEBUG is true, an event will be + /// fired if an OnLogMessage handler is registered and the + /// message will be sent to the logging engine + /// + /// The message to log at the DEBUG level to the + /// current logging engine + /// Instance of the client + [System.Diagnostics.Conditional("DEBUG")] + public static void DebugLog(object message, GridClient client) + { + if (Settings.LOG_LEVEL != Helpers.LogLevel.Debug) return; + + if (client != null && client.Settings.LOG_NAMES) + message = $"<{client.Self.Name}>: {message}"; + + OnLogMessage?.Invoke(message, Helpers.LogLevel.Debug); + + LogInstance.Debug(message); } - #endregion } -} \ No newline at end of file +} diff --git a/libremetaverse-core/Libremetaverse/ObjectManager.cs b/libremetaverse-core/Libremetaverse/ObjectManager.cs index 572fc64..f6829f4 100644 --- a/libremetaverse-core/Libremetaverse/ObjectManager.cs +++ b/libremetaverse-core/Libremetaverse/ObjectManager.cs @@ -2624,7 +2624,7 @@ namespace OpenMetaverse catch (IndexOutOfRangeException ex) { Logger.Log("Error decoding an ObjectUpdateCompressed packet", Helpers.LogLevel.Warning, Client, ex); - Logger.Log(block.ToString(), Helpers.LogLevel.Warning); + Logger.Log(block, Helpers.LogLevel.Warning); } } } diff --git a/libremetaverse-core/Libremetaverse/Settings.cs b/libremetaverse-core/Libremetaverse/Settings.cs index 55843cf..a30e1e9 100644 --- a/libremetaverse-core/Libremetaverse/Settings.cs +++ b/libremetaverse-core/Libremetaverse/Settings.cs @@ -340,15 +340,27 @@ namespace OpenMetaverse #region Logging Configuration - public string LOG_WRITER = "Console"; + /// + /// Get or set the minimum log level to output to the console by default + /// + /// If the library is not compiled with DEBUG defined and this level is set to DEBUG + /// You will get no output on the console. This behavior can be overriden by creating + /// a logger configuration file for log4net + /// + public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.Debug; + + /// Attach avatar names to log messages public bool LOG_NAMES = true; - public bool LOG_DISKCACHE = false; - public bool LOG_RESENDS = false; - public Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.Info; - + + /// Log packet retransmission info + public bool LOG_RESENDS = true; + + /// Log disk cache misses and other info + public bool LOG_DISKCACHE = true; + #endregion #region Private Fields - + private GridClient Client; private int priceUpload = 0; public static bool SORT_INVENTORY = false; @@ -375,6 +387,5 @@ namespace OpenMetaverse } #endregion - } } diff --git a/libremetaverse-core/Libremetaverse/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so b/libremetaverse-core/Libremetaverse/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so deleted file mode 100644 index 193eca4..0000000 Binary files a/libremetaverse-core/Libremetaverse/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so and /dev/null differ diff --git a/libremetaverse-core/Libremetaverse/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so b/libremetaverse-core/Libremetaverse/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so deleted file mode 100644 index 7a9bdfc..0000000 Binary files a/libremetaverse-core/Libremetaverse/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so and /dev/null differ diff --git a/libremetaverse-core/Libremetaverse/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib b/libremetaverse-core/Libremetaverse/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib deleted file mode 100644 index 91f7264..0000000 Binary files a/libremetaverse-core/Libremetaverse/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib and /dev/null differ diff --git a/libremetaverse-core/Libremetaverse/openjpeg-dotnet-x86_64.dll b/libremetaverse-core/Libremetaverse/openjpeg-dotnet-x86_64.dll deleted file mode 100644 index 9e8cd21..0000000 Binary files a/libremetaverse-core/Libremetaverse/openjpeg-dotnet-x86_64.dll and /dev/null differ diff --git a/libremetaverse-core/Libremetaverse/openjpeg-dotnet.dll b/libremetaverse-core/Libremetaverse/openjpeg-dotnet.dll deleted file mode 100644 index 6377b8d..0000000 Binary files a/libremetaverse-core/Libremetaverse/openjpeg-dotnet.dll and /dev/null differ