123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * 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.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Collections;
- using System.Collections.Generic;
- using System.IO;
- using System.Threading;
- using System.Xml;
- using System.Drawing;
- using OpenSim.Framework;
- using OpenSim.Framework.Servers;
- using OpenSim.Framework.Communications;
- using OpenSim.Framework.Communications.Cache;
- using OpenMetaverse;
- using OpenMetaverse.Imaging;
- using Nini.Config;
- namespace OpenSim.ApplicationPlugins.Rest.Inventory
- {
- public class RestAppearanceServices : IRest
- {
- private static readonly int PARM_USERID = 0;
- // private static readonly int PARM_PATH = 1;
- private bool enabled = false;
- private string qPrefix = "appearance";
- /// <summary>
- /// The constructor makes sure that the service prefix is absolute
- /// and the registers the service handler and the allocator.
- /// </summary>
- public RestAppearanceServices()
- {
- Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId);
- Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
- // This is better than a null reference.
- if (Rest.AvatarServices == null)
- throw new Exception(String.Format("{0} OpenSim inventory services are not available",
- MsgId));
- if (Rest.UserServices == null)
- throw new Exception(String.Format("{0} OpenSim user profile services are not available",
- MsgId));
- // If a relative path was specified for the handler's domain,
- // add the standard prefix to make it absolute, e.g. /admin
- if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
- {
- Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
- qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
- Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
- }
- // Register interface using the absolute URI.
- Rest.Plugin.AddPathHandler(DoAppearance,qPrefix,Allocate);
- // Activate if everything went OK
- enabled = true;
- Rest.Log.InfoFormat("{0} User appearance services initialization complete", MsgId);
- }
- /// <summary>
- /// Post-construction, pre-enabled initialization opportunity
- /// Not currently exploited.
- /// </summary>
- public void Initialize()
- {
- }
- /// <summary>
- /// Called by the plug-in to halt service processing. Local processing is
- /// disabled.
- /// </summary>
- public void Close()
- {
- enabled = false;
- Rest.Log.InfoFormat("{0} User appearance services closing down", MsgId);
- }
- /// <summary>
- /// This property is declared locally because it is used a lot and
- /// brevity is nice.
- /// </summary>
- internal string MsgId
- {
- get { return Rest.MsgId; }
- }
- #region Interface
- /// <summary>
- /// The plugin (RestHandler) calls this method to allocate the request
- /// state carrier for a new request. It is destroyed when the request
- /// completes. All request-instance specific state is kept here. This
- /// is registered when this service provider is registered.
- /// </summary>
- /// <param name=request>Inbound HTTP request information</param>
- /// <param name=response>Outbound HTTP request information</param>
- /// <param name=qPrefix>REST service domain prefix</param>
- /// <returns>A RequestData instance suitable for this service</returns>
- private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
- {
- return (RequestData) new AppearanceRequestData(request, response, prefix);
- }
- /// <summary>
- /// This method is registered with the handler when this service provider
- /// is initialized. It is called whenever the plug-in identifies this service
- /// provider as the best match for a given request.
- /// It handles all aspects of inventory REST processing, i.e. /admin/inventory
- /// </summary>
- /// <param name=hdata>A consolidated HTTP request work area</param>
- private void DoAppearance(RequestData hdata)
- {
- AppearanceRequestData rdata = (AppearanceRequestData) hdata;
- Rest.Log.DebugFormat("{0} DoAppearance ENTRY", MsgId);
- // If we're disabled, do nothing.
- if (!enabled)
- {
- return;
- }
- // Now that we know this is a serious attempt to
- // access inventory data, we should find out who
- // is asking, and make sure they are authorized
- // to do so. We need to validate the caller's
- // identity before revealing anything about the
- // status quo. Authenticate throws an exception
- // via Fail if no identity information is present.
- //
- // With the present HTTP server we can't use the
- // builtin authentication mechanisms because they
- // would be enforced for all in-bound requests.
- // Instead we look at the headers ourselves and
- // handle authentication directly.
- try
- {
- if (!rdata.IsAuthenticated)
- {
- rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName));
- }
- }
- catch (RestException e)
- {
- if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
- {
- Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
- Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
- }
- else
- {
- Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
- Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
- }
- throw (e);
- }
- Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName);
- // We can only get here if we are authorized
- //
- // The requestor may have specified an UUID or
- // a conjoined FirstName LastName string. We'll
- // try both. If we fail with the first, UUID,
- // attempt, we try the other. As an example, the
- // URI for a valid inventory request might be:
- //
- // http://<host>:<port>/admin/inventory/Arthur Dent
- //
- // Indicating that this is an inventory request for
- // an avatar named Arthur Dent. This is ALL that is
- // required to designate a GET for an entire
- // inventory.
- //
- // Do we have at least a user agent name?
- if (rdata.Parameters.Length < 1)
- {
- Rest.Log.WarnFormat("{0} Appearance: No user agent identifier specified", MsgId);
- rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified");
- }
- // The first parameter MUST be the agent identification, either an UUID
- // or a space-separated First-name Last-Name specification. We check for
- // an UUID first, if anyone names their character using a valid UUID
- // that identifies another existing avatar will cause this a problem...
- try
- {
- rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]);
- Rest.Log.DebugFormat("{0} UUID supplied", MsgId);
- rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid);
- }
- catch
- {
- string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE);
- if (names.Length == 2)
- {
- Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId);
- rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]);
- }
- else
- {
- Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId);
- rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity");
- }
- }
- // If the user profile is null then either the server is broken, or the
- // user is not known. We always assume the latter case.
- if (rdata.userProfile != null)
- {
- Rest.Log.DebugFormat("{0} User profile obtained for agent {1} {2}",
- MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
- }
- else
- {
- Rest.Log.WarnFormat("{0} No user profile for {1}", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity");
- }
- // If we get to here, then we have effectively validated the user's
- switch (rdata.method)
- {
- case Rest.HEAD : // Do the processing, set the status code, suppress entity
- DoGet(rdata);
- rdata.buffer = null;
- break;
- case Rest.GET : // Do the processing, set the status code, return entity
- DoGet(rdata);
- break;
- case Rest.PUT : // Update named element
- DoUpdate(rdata);
- break;
- case Rest.POST : // Add new information to identified context.
- DoExtend(rdata);
- break;
- case Rest.DELETE : // Delete information
- DoDelete(rdata);
- break;
- default :
- Rest.Log.WarnFormat("{0} Method {1} not supported for {2}",
- MsgId, rdata.method, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed,
- String.Format("{0} not supported", rdata.method));
- break;
- }
- }
- #endregion Interface
- #region method-specific processing
- /// <summary>
- /// This method implements GET processing for user's appearance.
- /// </summary>
- /// <param name=rdata>HTTP service request work area</param>
- private void DoGet(AppearanceRequestData rdata)
- {
- rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
- if (rdata.userAppearance == null)
- {
- rdata.Fail(Rest.HttpStatusCodeNoContent,
- String.Format("appearance data not found for user {0} {1}",
- rdata.userProfile.FirstName, rdata.userProfile.SurName));
- }
- rdata.initXmlWriter();
- FormatUserAppearance(rdata);
- // Indicate a successful request
- rdata.Complete();
- // Send the response to the user. The body will be implicitly
- // constructed from the result of the XML writer.
- rdata.Respond(String.Format("Appearance {0} Normal completion", rdata.method));
- }
- /// <summary>
- /// POST adds NEW information to the user profile database.
- /// This effectively resets the appearance before applying those
- /// characteristics supplied in the request.
- /// </summary>
- private void DoExtend(AppearanceRequestData rdata)
- {
- bool created = false;
- bool modified = false;
- string newnode = String.Empty;
- Rest.Log.DebugFormat("{0} POST ENTRY", MsgId);
- //AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
- rdata.userAppearance = new AvatarAppearance();
- // Although the following behavior is admitted by HTTP I am becoming
- // increasingly doubtful that it is appropriate for REST. If I attempt to
- // add a new record, and it already exists, then it seems to me that the
- // attempt should fail, rather than update the existing record.
- if (GetUserAppearance(rdata))
- {
- modified = rdata.userAppearance != null;
- created = !modified;
- Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
- // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
- }
- else
- {
- created = true;
- Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
- // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
- }
- if (created)
- {
- newnode = String.Format("{0} {1}", rdata.userProfile.FirstName,
- rdata.userProfile.SurName);
- // Must include a location header with a URI that identifies the new resource.
- rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}{3}{4}",
- rdata.hostname,rdata.port,rdata.path,Rest.UrlPathSeparator, newnode));
- rdata.Complete(Rest.HttpStatusCodeCreated);
- }
- else
- {
- if (modified)
- {
- rdata.Complete(Rest.HttpStatusCodeOK);
- }
- else
- {
- rdata.Complete(Rest.HttpStatusCodeNoContent);
- }
- }
- rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
-
- }
- /// <summary>
- /// This updates the user's appearance. not all aspects need to be provided,
- /// only those supplied will be changed.
- /// </summary>
- private void DoUpdate(AppearanceRequestData rdata)
- {
- bool created = false;
- bool modified = false;
- rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
- // If the user exists then this is considered a modification regardless
- // of what may, or may not be, specified in the payload.
- if (rdata.userAppearance != null)
- {
- modified = true;
- Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
- Rest.UserServices.UpdateUserProfile(rdata.userProfile);
- }
- if (created)
- {
- rdata.Complete(Rest.HttpStatusCodeCreated);
- }
- else
- {
- if (modified)
- {
- rdata.Complete(Rest.HttpStatusCodeOK);
- }
- else
- {
- rdata.Complete(Rest.HttpStatusCodeNoContent);
- }
- }
- rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
- }
- /// <summary>
- /// Delete the specified user's appearance. This actually performs a reset
- /// to the default avatar appearance, if the info is already there.
- /// Existing ownership is preserved. All prior updates are lost and can not
- /// be recovered.
- /// </summary>
- private void DoDelete(AppearanceRequestData rdata)
- {
- AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
- if (old != null)
- {
- rdata.userAppearance = new AvatarAppearance();
- rdata.userAppearance.Owner = old.Owner;
-
- Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
- rdata.Complete();
- }
- else
- {
- rdata.Complete(Rest.HttpStatusCodeNoContent);
- }
- rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
- }
- #endregion method-specific processing
- private bool GetUserAppearance(AppearanceRequestData rdata)
- {
- XmlReader xml;
- bool indata = false;
- rdata.initXmlReader();
- xml = rdata.reader;
- while (xml.Read())
- {
- switch (xml.NodeType)
- {
- case XmlNodeType.Element :
- switch (xml.Name)
- {
- case "Appearance" :
- if (xml.MoveToAttribute("Height"))
- {
- rdata.userAppearance.AvatarHeight = (float) Convert.ToDouble(xml.Value);
- indata = true;
- }
- if (xml.MoveToAttribute("Owner"))
- {
- rdata.userAppearance.Owner = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Serial"))
- {
- rdata.userAppearance.Serial = Convert.ToInt32(xml.Value);
- indata = true;
- }
- break;
- case "Body" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.BodyItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.BodyAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Skin" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.SkinItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.SkinAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Hair" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.HairItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.HairAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Eyes" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.EyesItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.EyesAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Shirt" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.ShirtItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.ShirtAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Pants" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.PantsItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.PantsAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Shoes" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.ShoesItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.ShoesAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Socks" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.SocksItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.SocksAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Jacket" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.JacketItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.JacketAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Gloves" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.GlovesItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.GlovesAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "UnderShirt" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.UnderShirtItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.UnderShirtAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "UnderPants" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.UnderPantsItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.UnderPantsAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Skirt" :
- if (xml.MoveToAttribute("Item"))
- {
- rdata.userAppearance.SkirtItem = (UUID)xml.Value;
- indata = true;
- }
- if (xml.MoveToAttribute("Asset"))
- {
- rdata.userAppearance.SkirtAsset = (UUID)xml.Value;
- indata = true;
- }
- break;
- case "Attachment" :
- {
- int ap;
- UUID asset;
- UUID item;
- if (xml.MoveToAttribute("AtPoint"))
- {
- ap = Convert.ToInt32(xml.Value);
- if (xml.MoveToAttribute("Asset"))
- {
- asset = new UUID(xml.Value);
- if (xml.MoveToAttribute("Asset"))
- {
- item = new UUID(xml.Value);
- rdata.userAppearance.SetAttachment(ap, item, asset);
- indata = true;
- }
- }
- }
- }
- break;
- case "Texture" :
- if (xml.MoveToAttribute("Default"))
- {
- rdata.userAppearance.Texture = new Primitive.TextureEntry(new UUID(xml.Value));
- indata = true;
- }
- break;
- case "Face" :
- {
- uint index;
- if (xml.MoveToAttribute("Index"))
- {
- index = Convert.ToUInt32(xml.Value);
- if (xml.MoveToAttribute("Id"))
- {
- rdata.userAppearance.Texture.CreateFace(index).TextureID = new UUID(xml.Value);
- indata = true;
- }
- }
- }
- break;
- case "VisualParameters" :
- {
- xml.ReadContentAsBase64(rdata.userAppearance.VisualParams,
- 0, rdata.userAppearance.VisualParams.Length);
- indata = true;
- }
- break;
- }
- break;
- }
- }
- return indata;
- }
- private void FormatPart(AppearanceRequestData rdata, string part, UUID item, UUID asset)
- {
- if (item != UUID.Zero || asset != UUID.Zero)
- {
- rdata.writer.WriteStartElement(part);
- if (item != UUID.Zero)
- {
- rdata.writer.WriteAttributeString("Item",item.ToString());
- }
- if (asset != UUID.Zero)
- {
- rdata.writer.WriteAttributeString("Asset",asset.ToString());
- }
- rdata.writer.WriteEndElement();
- }
- }
- private void FormatUserAppearance(AppearanceRequestData rdata)
- {
- Rest.Log.DebugFormat("{0} FormatUserAppearance", MsgId);
- if (rdata.userAppearance != null)
- {
- Rest.Log.DebugFormat("{0} FormatUserAppearance: appearance object exists", MsgId);
- rdata.writer.WriteStartElement("Appearance");
- rdata.writer.WriteAttributeString("Height", rdata.userAppearance.AvatarHeight.ToString());
- if (rdata.userAppearance.Owner != UUID.Zero)
- rdata.writer.WriteAttributeString("Owner", rdata.userAppearance.Owner.ToString());
- rdata.writer.WriteAttributeString("Serial", rdata.userAppearance.Serial.ToString());
- FormatPart(rdata, "Body", rdata.userAppearance.BodyItem, rdata.userAppearance.BodyAsset);
- FormatPart(rdata, "Skin", rdata.userAppearance.SkinItem, rdata.userAppearance.SkinAsset);
- FormatPart(rdata, "Hair", rdata.userAppearance.HairItem, rdata.userAppearance.HairAsset);
- FormatPart(rdata, "Eyes", rdata.userAppearance.EyesItem, rdata.userAppearance.EyesAsset);
- FormatPart(rdata, "Shirt", rdata.userAppearance.ShirtItem, rdata.userAppearance.ShirtAsset);
- FormatPart(rdata, "Pants", rdata.userAppearance.PantsItem, rdata.userAppearance.PantsAsset);
- FormatPart(rdata, "Skirt", rdata.userAppearance.SkirtItem, rdata.userAppearance.SkirtAsset);
- FormatPart(rdata, "Shoes", rdata.userAppearance.ShoesItem, rdata.userAppearance.ShoesAsset);
- FormatPart(rdata, "Socks", rdata.userAppearance.SocksItem, rdata.userAppearance.SocksAsset);
- FormatPart(rdata, "Jacket", rdata.userAppearance.JacketItem, rdata.userAppearance.JacketAsset);
- FormatPart(rdata, "Gloves", rdata.userAppearance.GlovesItem, rdata.userAppearance.GlovesAsset);
- FormatPart(rdata, "UnderShirt", rdata.userAppearance.UnderShirtItem, rdata.userAppearance.UnderShirtAsset);
- FormatPart(rdata, "UnderPants", rdata.userAppearance.UnderPantsItem, rdata.userAppearance.UnderPantsAsset);
- Hashtable attachments = rdata.userAppearance.GetAttachments();
- if (attachments != null)
- {
- Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId);
- rdata.writer.WriteStartElement("Attachments");
- for (int i = 0; i < attachments.Count; i++)
- {
- Hashtable attachment = attachments[i] as Hashtable;
- rdata.writer.WriteStartElement("Attachment");
- rdata.writer.WriteAttributeString("AtPoint", i.ToString());
- rdata.writer.WriteAttributeString("Item", (string) attachment["item"]);
- rdata.writer.WriteAttributeString("Asset", (string) attachment["asset"]);
- rdata.writer.WriteEndElement();
- }
- rdata.writer.WriteEndElement();
- }
- Primitive.TextureEntry texture = rdata.userAppearance.Texture;
- if (texture != null && (texture.DefaultTexture != null || texture.FaceTextures != null))
- {
- Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting textures", MsgId);
- rdata.writer.WriteStartElement("Texture");
- if (texture.DefaultTexture != null)
- {
- Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting default texture", MsgId);
- rdata.writer.WriteAttributeString("Default",
- texture.DefaultTexture.TextureID.ToString());
- }
- if (texture.FaceTextures != null)
- {
- Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting face textures", MsgId);
- for (int i=0; i<texture.FaceTextures.Length;i++)
- {
- if (texture.FaceTextures[i] != null)
- {
- rdata.writer.WriteStartElement("Face");
- rdata.writer.WriteAttributeString("Index", i.ToString());
- rdata.writer.WriteAttributeString("Id",
- texture.FaceTextures[i].TextureID.ToString());
- rdata.writer.WriteEndElement();
- }
- }
- }
- rdata.writer.WriteEndElement();
- }
- Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting visual parameters", MsgId);
- rdata.writer.WriteStartElement("VisualParameters");
- rdata.writer.WriteBase64(rdata.userAppearance.VisualParams,0,
- rdata.userAppearance.VisualParams.Length);
- rdata.writer.WriteEndElement();
- rdata.writer.WriteFullEndElement();
- }
- Rest.Log.DebugFormat("{0} FormatUserAppearance: completed", MsgId);
- return;
- }
- #region appearance RequestData extension
- internal class AppearanceRequestData : RequestData
- {
- /// <summary>
- /// These are the inventory specific request/response state
- /// extensions.
- /// </summary>
- internal UUID uuid = UUID.Zero;
- internal UserProfileData userProfile = null;
- internal AvatarAppearance userAppearance = null;
- internal AppearanceRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
- : base(request, response, prefix)
- {
- }
- }
- #endregion Appearance RequestData extension
- }
- }
|