diff --git a/libsecondlife/InventoryManager.cs b/libsecondlife/InventoryManager.cs index 505dd0ec..4b8b0703 100644 --- a/libsecondlife/InventoryManager.cs +++ b/libsecondlife/InventoryManager.cs @@ -369,6 +369,15 @@ namespace libsecondlife /// Filename of the task inventory asset public delegate void TaskInventoryReplyCallback(LLUUID itemID, short serial, string assetFilename); + /// + /// + /// + /// + /// + /// + /// + public delegate void NotecardUploadedAssetCallback(bool success, string status, LLUUID itemID, LLUUID assetID); + #endregion Delegates #region Events @@ -1404,6 +1413,37 @@ namespace libsecondlife _Client.Network.SendPacket(update); } + /// + /// + /// + /// + /// + /// + public void RequestUploadNotecardAsset(byte[] data, LLUUID notecardID, NotecardUploadedAssetCallback callback) + { + if (_Client.Network.CurrentSim == null || _Client.Network.CurrentSim.Caps == null) + throw new Exception("UpdateNotecardAgentInventory capability is not currently available"); + + Uri url = _Client.Network.CurrentSim.Caps.CapabilityURI("UpdateNotecardAgentInventory"); + + if (url != null) + { + LLSDMap query = new LLSDMap(); + query.Add("item_id", LLSD.FromUUID(notecardID)); + + byte[] postData = StructuredData.LLSDParser.SerializeXmlBytes(query); + + // Make the request + CapsClient request = new CapsClient(url); + request.OnComplete += new CapsClient.CompleteCallback(UploadNotecardAssetResponse); + request.UserData = new object[2] { new KeyValuePair(callback, data), notecardID }; + request.StartRequest(postData); + } + else + { + throw new Exception("UpdateNotecardAgentInventory capability is not currently available"); + } + } #endregion Update #region Rez/Give @@ -2686,6 +2726,47 @@ namespace libsecondlife } } + private void UploadNotecardAssetResponse(CapsClient client, LLSD result, Exception error) + { + LLSDMap contents = (LLSDMap)result; + KeyValuePair kvp = (KeyValuePair)(((object[])client.UserData)[0]); + NotecardUploadedAssetCallback callback = kvp.Key; + byte[] itemData = (byte[])kvp.Value; + + string status = contents["state"].AsString(); + + if (status == "upload") + { + string uploadURL = contents["uploader"].AsString(); + + // This makes the assumption that all uploads go to CurrentSim, to avoid + // the problem of HttpRequestState not knowing anything about simulators + CapsClient upload = new CapsClient(new Uri(uploadURL)); + upload.OnComplete += new CapsClient.CompleteCallback(UploadNotecardAssetResponse); + upload.UserData = new object[2] { kvp, (LLUUID)(((object[])client.UserData)[1]) }; + upload.StartRequest(itemData, "application/octet-stream"); + } + else if (status == "complete") + { + if (contents.ContainsKey("new_asset")) + { + try { callback(true, String.Empty, (LLUUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); } + catch (Exception e) { _Client.Log(e.ToString(), Helpers.LogLevel.Error); } + } + else + { + try { callback(false, "Failed to parse asset and item UUIDs", LLUUID.Zero, LLUUID.Zero); } + catch (Exception e) { _Client.Log(e.ToString(), Helpers.LogLevel.Error); } + } + } + else + { + // Failure + try { callback(false, status, LLUUID.Zero, LLUUID.Zero); } + catch (Exception e) { _Client.Log(e.ToString(), Helpers.LogLevel.Error); } + } + } + #endregion Callbacks } } diff --git a/libsecondlife/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs b/libsecondlife/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs new file mode 100644 index 00000000..511d0310 --- /dev/null +++ b/libsecondlife/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.IO; +using libsecondlife; + +namespace libsecondlife.TestClient +{ + public class CreateNotecardCommand : Command + { + public CreateNotecardCommand(TestClient testClient) + { + Name = "createnotecard"; + Description = "Creates a notecard from a local text file."; + } + + void OnNoteUpdate(bool success, string status, LLUUID itemID, LLUUID assetID) + { + if (success) + Console.WriteLine("Notecard successfully uploaded, ItemID {0} AssetID {1}", itemID, assetID); + } + + public override string Execute(string[] args, LLUUID fromAgentID) + { + if(args.Length < 1) + return "Usage: createnotecard filename.txt"; + + string file = String.Empty; + for (int ct = 0; ct < args.Length; ct++) + file = file + args[ct] + " "; + file = file.TrimEnd(); + + Console.WriteLine("Filename: {0}", file); + if (!File.Exists(file)) + return String.Format("Filename '{0}' does not exist", file); + + System.IO.StreamReader reader = new StreamReader(file); + string body = reader.ReadToEnd(); + + try + { + string desc = String.Format("{0} created by libsecondlife TestClient {1}", file, DateTime.Now); + // create the asset + Client.Inventory.RequestCreateItem(Client.Inventory.FindFolderForType(AssetType.Notecard), file, desc, + AssetType.Notecard, InventoryType.Notecard, PermissionMask.All, + delegate(bool success, InventoryItem item) { + if(success) // upload the asset + Client.Inventory.RequestUploadNotecardAsset(CreateNotecardAsset(body), item.UUID, new InventoryManager.NotecardUploadedAssetCallback(OnNoteUpdate)); + } + ); + return "Done"; + + } + catch (System.Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + return "Error creating notecard."; + } + } + /// + /// + /// + public static byte[] CreateNotecardAsset(string body) + { + // Format the string body into Linden text + string lindenText = "Linden text version 1\n"; + lindenText += "{\n"; + lindenText += "LLEmbeddedItems version 1\n"; + lindenText += "{\n"; + lindenText += "count 0\n"; + lindenText += "}\n"; + lindenText += "Text length " + body.Length + "\n"; + lindenText += body; + lindenText += "}\n"; + + // Assume this is a string, add 1 for the null terminator + byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(lindenText); + byte[] assetData = new byte[stringBytes.Length]; //+ 1]; + Array.Copy(stringBytes, 0, assetData, 0, stringBytes.Length); + + return assetData; + } + } +} \ No newline at end of file diff --git a/libsecondlife/examples/TestClient/TestClient.csproj b/libsecondlife/examples/TestClient/TestClient.csproj index 98456e62..df9c6053 100644 --- a/libsecondlife/examples/TestClient/TestClient.csproj +++ b/libsecondlife/examples/TestClient/TestClient.csproj @@ -65,6 +65,7 @@ +