From 179f4ddabbc89228502b8ec91f996562ec56e6d6 Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Thu, 24 Mar 2011 23:54:23 +0100 Subject: [PATCH] The Octopus Feature ___ .-' `'. / \ | ; | | ___.--, _.._ |0) ~ (0) | _.---'`__.-( (_. __.--'`_.. '.__.\ '--. \_.-' ,.--'` `""` ( ,.--'` ',__ /./; ;, '.__.'` __ _`) ) .---.__.' / | |\ \__..--"" """--.,_ `---' .'.''-._.-'`_./ /\ '. \ _.-~~~````~~~-._`-.__.' | | .' _.-' | | \ \ '. `~---` \ \/ .' \ \ '. '-._) \/ / \ \ `=.__`~-. jgs / /\ `) ) / / `"".`\ , _.-'.'\ \ / / ( ( / / `--~` ) ) .-'.' '.'. | ( (/` ( (` ) ) '-; ` '-; (-' --- indra/llmessage/llhttpclient.cpp | 5 + indra/llmessage/llhttpclient.h | 2 + indra/llui/lluictrlfactory.cpp | 49 +++- indra/llui/lluictrlfactory.h | 10 + indra/llxml/llxmlnode.cpp | 6 +- indra/llxml/llxmlnode.h | 2 +- indra/llxml/llxmltree.cpp | 117 ++++++++- indra/llxml/llxmltree.h | 17 ++ indra/newview/CMakeLists.txt | 92 +++---- indra/newview/hippofloaterxml.cpp | 381 +++++++++++++++++++++++++++++ indra/newview/hippofloaterxml.h | 48 ++++ indra/newview/hipporestrequest.cpp | 297 ++++++++++++++++++++++ indra/newview/hipporestrequest.h | 90 ++++++- indra/newview/llagent.cpp | 2 + indra/newview/llagent.h | 2 + indra/newview/llstartup.cpp | 1 + indra/newview/llviewermessage.cpp | 62 +++++ indra/newview/llviewerobject.cpp | 1 + indra/newview/llviewerobject.h | 2 + indra/newview/llvoavatar.cpp | 204 ++++++++++----- indra/newview/llvoavatar.h | 11 +- 21 files changed, 1277 insertions(+), 124 deletions(-) create mode 100755 indra/newview/hippofloaterxml.cpp create mode 100755 indra/newview/hippofloaterxml.h diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index e58df16bb..4d0a076e7 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -599,3 +599,8 @@ bool LLHTTPClient::hasPump() { return theClientPump != NULL; } + +LLPumpIO &LLHTTPClient::getPump() +{ + return *theClientPump; +} diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 3d0646e5f..44c685e38 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -156,6 +156,8 @@ public: ///< must be called before any of the above calls are made static bool hasPump(); ///< for testing + static LLPumpIO &getPump(); + ///< Hippo special }; #endif // LL_LLHTTPCLIENT_H diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 07eb39bd6..75dfde1ff 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -225,6 +225,16 @@ bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNo } +bool LLUICtrlFactory::getLayeredXMLNodeFromBuffer(const std::string &buffer, LLXMLNodePtr& root) +{ + if (!LLXMLNode::parseBuffer(buffer.data(), buffer.size(), root, 0)) { + llwarns << "Error reading UI description from buffer." << llendl; + return false; + } + return true; +} + + //----------------------------------------------------------------------------- // buildFloater() //----------------------------------------------------------------------------- @@ -238,6 +248,23 @@ void LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filen return; } + buildFloaterInternal(floaterp, root, filename, factory_map, open); +} + +void LLUICtrlFactory::buildFloaterFromBuffer(LLFloater *floaterp, const std::string &buffer, + const LLCallbackMap::map_t *factory_map, BOOL open) /* Flawfinder: ignore */ +{ + LLXMLNodePtr root; + + if (!LLUICtrlFactory::getLayeredXMLNodeFromBuffer(buffer, root)) + return; + + buildFloaterInternal(floaterp, root, "(buffer)", factory_map, open); +} + +void LLUICtrlFactory::buildFloaterInternal(LLFloater *floaterp, LLXMLNodePtr &root, const std::string &filename, + const LLCallbackMap::map_t *factory_map, BOOL open) /* Flawfinder: ignore */ +{ // root must be called floater if( !(root->hasName("floater") || root->hasName("multi_floater") ) ) { @@ -294,13 +321,31 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename) BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename, const LLCallbackMap::map_t* factory_map) { - BOOL didPost = FALSE; LLXMLNodePtr root; if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) { - return didPost; + return FALSE; } + + return buildPanelInternal(panelp, root, filename, factory_map); + } + +BOOL LLUICtrlFactory::buildPanelFromBuffer(LLPanel *panelp, const std::string &buffer, + const LLCallbackMap::map_t* factory_map) +{ + LLXMLNodePtr root; + + if (!LLUICtrlFactory::getLayeredXMLNodeFromBuffer(buffer, root)) + return FALSE; + + return buildPanelInternal(panelp, root, "(buffer)", factory_map); +} + +BOOL LLUICtrlFactory::buildPanelInternal(LLPanel* panelp, LLXMLNodePtr &root, const std::string &filename, + const LLCallbackMap::map_t* factory_map) +{ + BOOL didPost = FALSE; // root must be called panel if( !root->hasName("panel" ) ) diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 5e7c24efc..ef3a97be5 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -53,8 +53,12 @@ public: void buildFloater(LLFloater* floaterp, const std::string &filename, const LLCallbackMap::map_t* factory_map = NULL, BOOL open = TRUE); + void buildFloaterFromBuffer(LLFloater *floaterp, const std::string &buffer, + const LLCallbackMap::map_t *factory_map = NULL, BOOL open = TRUE); BOOL buildPanel(LLPanel* panelp, const std::string &filename, const LLCallbackMap::map_t* factory_map = NULL); + BOOL buildPanelFromBuffer(LLPanel *panelp, const std::string &buffer, + const LLCallbackMap::map_t* factory_map = NULL); void removePanel(LLPanel* panelp) { mBuiltPanels.erase(panelp->getHandle()); } void removeFloater(LLFloater* floaterp) { mBuiltFloaters.erase(floaterp->getHandle()); } @@ -77,6 +81,7 @@ public: virtual LLView* createWidget(LLPanel *parent, LLXMLNodePtr node); static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); + static bool getLayeredXMLNodeFromBuffer(const std::string &buffer, LLXMLNodePtr& root); static const std::vector& getXUIPaths(); @@ -94,6 +99,11 @@ private: static std::vector sXUIPaths; LLPanel* mDummyPanel; + + void buildFloaterInternal(LLFloater *floaterp, LLXMLNodePtr &root, const std::string &filename, + const LLCallbackMap::map_t *factory_map, BOOL open); + BOOL buildPanelInternal(LLPanel* panelp, LLXMLNodePtr &root, const std::string &filename, + const LLCallbackMap::map_t* factory_map = NULL); }; diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 800b13573..a33da9dea 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -677,7 +677,7 @@ bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXML U32 length = ftell(fp); fseek(fp, 0, SEEK_SET); - U8* buffer = new U8[length+1]; + char *buffer = new char[length+1]; size_t nread = fread(buffer, 1, length, fp); buffer[nread] = 0; fclose(fp); @@ -689,7 +689,7 @@ bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXML // static bool LLXMLNode::parseBuffer( - U8* buffer, + const char *buffer, U32 length, LLXMLNodePtr& node, LLXMLNode* defaults) @@ -708,7 +708,7 @@ bool LLXMLNode::parseBuffer( XML_SetUserData(my_parser, (void *)file_node_ptr); // Do the parsing - if (XML_Parse(my_parser, (const char *)buffer, length, TRUE) != XML_STATUS_OK) + if (XML_Parse(my_parser, buffer, length, TRUE) != XML_STATUS_OK) { llwarns << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h index d4e127b05..bce2ff733 100644 --- a/indra/llxml/llxmlnode.h +++ b/indra/llxml/llxmlnode.h @@ -141,7 +141,7 @@ public: LLXMLNodePtr& node, LLXMLNode* defaults_tree); static bool parseBuffer( - U8* buffer, + const char *buffer, U32 length, LLXMLNodePtr& node, LLXMLNode* defaults); diff --git a/indra/llxml/llxmltree.cpp b/indra/llxml/llxmltree.cpp index bc2690def..463d7fc61 100644 --- a/indra/llxml/llxmltree.cpp +++ b/indra/llxml/llxmltree.cpp @@ -50,6 +50,7 @@ LLStdStringTable LLXmlTree::sAttributeKeys(1024); LLXmlTree::LLXmlTree() : mRoot( NULL ), + mParser(0), mNodeNames(512) { } @@ -83,6 +84,39 @@ BOOL LLXmlTree::parseFile(const std::string &path, BOOL keep_contents) return success; } +bool LLXmlTree::parseBufferStart(bool keep_contents) +{ + if (mRoot) delete mRoot; + mRoot = NULL; + + if (mParser) delete mParser; + mParser = new LLXmlTreeParser(this); + mParser->parseBufferStart(keep_contents); + return (mParser != 0); +} + +bool LLXmlTree::parseBuffer(const char *buf, int len) +{ + bool success = mParser->parseBuffer(buf, len); + if (!success) { + S32 line_number = mParser->getCurrentLineNumber(); + const char* error = mParser->getErrorString(); + llwarns << "LLXmlTree parse failed in line " << line_number << ": " << error << llendl; + delete mParser; + mParser = 0; + } + return success; +} + +bool LLXmlTree::parseBufferFinalize() +{ + bool success = mParser->parseBufferFinalize(&mRoot); + delete mParser; + mParser = 0; + return success; +} + + void LLXmlTree::dump() { if( mRoot ) @@ -102,6 +136,25 @@ void LLXmlTree::dumpNode( LLXmlTreeNode* node, const std::string& prefix ) } } +void LLXmlTree::write(std::string &buffer) const +{ + if (mRoot) writeNode(mRoot, buffer, ""); +} + +void LLXmlTree::writeNode(LLXmlTreeNode *node, std::string &buffer, const std::string &indent) const +{ + if (!node->getFirstChild()) { + node->writeNoChild(buffer, indent); + } else { + node->writeStart(buffer, indent); + std::string newIndent = indent + " "; + for (LLXmlTreeNode *child=node->getFirstChild(); child; child=node->getNextChild()) + writeNode(child, buffer, newIndent); + node->writeEnd(buffer, indent); + } +} + + ////////////////////////////////////////////////////////////// // LLXmlTreeNode @@ -139,6 +192,43 @@ void LLXmlTreeNode::dump( const std::string& prefix ) llcont << llendl; } +void LLXmlTreeNode::writeNoChild(std::string &buffer, const std::string &indent) const +{ + if (!mContents.empty()) { + writeStart(buffer, indent); + writeEnd(buffer, indent); + } else { + buffer += indent + '<' + mName; + writeAttributes(buffer); + buffer += "/>\n"; + } +} + +void LLXmlTreeNode::writeStart(std::string &buffer, const std::string &indent) const +{ + buffer += indent + '<' + mName; + writeAttributes(buffer); + buffer += ">\n"; +} + +void LLXmlTreeNode::writeEnd(std::string &buffer, const std::string &indent) const +{ + if (!mContents.empty()) { + buffer += indent + " " + mContents + '\n'; + } + buffer += indent + "\n"; +} + +void LLXmlTreeNode::writeAttributes(std::string &buffer) const +{ + attribute_map_t::const_iterator it, end = mAttributes.end(); + for (it=mAttributes.begin(); it!=end; ++it) { + LLStdStringHandle key = it->first; + const std::string *value = it->second; + buffer += ' ' + *key + "=\"" + *value + '"'; + } +} + BOOL LLXmlTreeNode::hasAttribute(const std::string& name) { LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); @@ -528,7 +618,7 @@ BOOL LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, B BOOL success = LLXmlParser::parseFile(path); - *root = mRoot; + if (root) *root = mRoot; mRoot = NULL; if( success ) @@ -540,6 +630,31 @@ BOOL LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, B return success; } +void LLXmlTreeParser::parseBufferStart(BOOL keep_contents) +{ + llassert(!mRoot); + llassert(!mCurrent); + mKeepContents = keep_contents; +} + +bool LLXmlTreeParser::parseBuffer(const char *buf, int len) +{ + return (LLXmlParser::parse(buf, len, false) != 0); +} + +bool LLXmlTreeParser::parseBufferFinalize(LLXmlTreeNode** root) +{ + bool success = (LLXmlParser::parse(0, 0, true) != 0); + + if (root) *root = mRoot; + mRoot = NULL; + + llassert(!success || !mCurrent); + mCurrent = NULL; + + return success; +} + const std::string& LLXmlTreeParser::tabs() { diff --git a/indra/llxml/llxmltree.h b/indra/llxml/llxmltree.h index 1a020f213..2ac75046e 100644 --- a/indra/llxml/llxmltree.h +++ b/indra/llxml/llxmltree.h @@ -63,11 +63,18 @@ public: virtual BOOL parseFile(const std::string &path, BOOL keep_contents = TRUE); + bool parseBufferStart(bool keep_contents = true); + bool parseBuffer(const char *buf, int len); + bool parseBufferFinalize(); + LLXmlTreeNode* getRoot() { return mRoot; } void dump(); void dumpNode( LLXmlTreeNode* node, const std::string& prefix ); + void write(std::string &buffer) const; + void writeNode(LLXmlTreeNode *node, std::string &buffer, const std::string &indent) const; + static LLStdStringHandle addAttributeString( const std::string& name) { return sAttributeKeys.addString( name ); @@ -79,6 +86,7 @@ public: protected: LLXmlTreeNode* mRoot; + LLXmlTreeParser *mParser; // local LLStdStringTable mNodeNames; @@ -175,6 +183,11 @@ private: void dump( const std::string& prefix ); + void writeNoChild(std::string &buffer, const std::string &indent) const; + void writeStart(std::string &buffer, const std::string &indent) const; + void writeEnd(std::string &buffer, const std::string &indent) const; + void writeAttributes(std::string &buffer) const; + protected: typedef std::map attribute_map_t; attribute_map_t mAttributes; @@ -207,6 +220,10 @@ public: BOOL parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents ); + void parseBufferStart(BOOL keep_contents); + bool parseBuffer(const char *buf, int len); + bool parseBufferFinalize(LLXmlTreeNode** root); + protected: const std::string& tabs(); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 329e79d44..bb4bb62d7 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -65,31 +65,32 @@ include_directories( set(viewer_SOURCE_FILES floaterlocalassetbrowse.cpp - aoremotectrl.cpp - floaterao.cpp + aoremotectrl.cpp + floaterao.cpp floatervoicelicense.cpp cofmgr.cpp - ascentdaycyclemanager.cpp - ascentfloatercontactgroups.cpp + ascentdaycyclemanager.cpp + ascentfloatercontactgroups.cpp ascentprefssys.cpp - ascentprefsvan.cpp - ascentuploadbrowser.cpp - dhparam.cpp - dsaparam.cpp - emerald.cpp - emeraldboobutils.cpp + ascentprefsvan.cpp + ascentuploadbrowser.cpp + dhparam.cpp + dsaparam.cpp + emerald.cpp + emeraldboobutils.cpp dofloaterhex.cpp dohexeditor.cpp - floatersculptpreview.cpp - hbfloatergrouptitles.cpp + floatersculptpreview.cpp + hbfloatergrouptitles.cpp hgfloatertexteditor.cpp - hippogridmanager.cpp - hippolimits.cpp - hipporestrequest.cpp - hippopanelgrids.cpp + hippogridmanager.cpp + hippofloaterxml.cpp + hippolimits.cpp + hipporestrequest.cpp + hippopanelgrids.cpp jcfloaterareasearch.cpp - chatbar_as_cmdline.cpp - qtoolalign.cpp + chatbar_as_cmdline.cpp + qtoolalign.cpp llagent.cpp llagentaccess.cpp llagentdata.cpp @@ -160,9 +161,9 @@ set(viewer_SOURCE_FILES llfloateravatarpicker.cpp llfloateravatartextures.cpp llfloaterbeacons.cpp - llfloaterblacklist.cpp - llviewerdisplayname.cpp - llfloaterdisplayname.cpp + llfloaterblacklist.cpp + llviewerdisplayname.cpp + llfloaterdisplayname.cpp llfloaterbuildoptions.cpp llfloaterbulkpermission.cpp llfloaterbump.cpp @@ -184,7 +185,7 @@ set(viewer_SOURCE_FILES llfloaterevent.cpp llfloaterexport.cpp llfloaterexploreanimations.cpp - llfloaterexploresounds.cpp + llfloaterexploresounds.cpp llfloaterfriends.cpp llfloaterfonttest.cpp llfloatergesture.cpp @@ -500,8 +501,8 @@ set(viewer_SOURCE_FILES llxmlrpctransaction.cpp noise.cpp pipeline.cpp - scriptcounter.cpp - wlfPanel_AdvSettings.cpp + scriptcounter.cpp + wlfPanel_AdvSettings.cpp rlvhandler.cpp rlvhelper.cpp rlvcommon.cpp @@ -537,28 +538,29 @@ set(viewer_HEADER_FILES floaterlocalassetbrowse.h aoremotectrl.h - floaterao.h + floaterao.h floatervoicelicense.h - cofmgr.h - ascentdaycyclemanager.h - ascentfloatercontactgroups.h - ascentprefssys.h - ascentprefsvan.h - ascentuploadbrowser.h - emerald.h - emeraldboobutils.h + cofmgr.h + ascentdaycyclemanager.h + ascentfloatercontactgroups.h + ascentprefssys.h + ascentprefsvan.h + ascentuploadbrowser.h + emerald.h + emeraldboobutils.h dofloaterhex.h dohexeditor.h - floatersculptpreview.h - hbfloatergrouptitles.h + floatersculptpreview.h + hbfloatergrouptitles.h hgfloatertexteditor.h - hippogridmanager.h - hippolimits.h - hipporestrequest.h - hippopanelgrids.h + hippogridmanager.h + hippofloaterxml.h + hippolimits.h + hipporestrequest.h + hippopanelgrids.h jcfloaterareasearch.h - chatbar_as_cmdline.h - qtoolalign.h + chatbar_as_cmdline.h + qtoolalign.h llagent.h llagentaccess.h llagentdata.h @@ -654,7 +656,7 @@ set(viewer_HEADER_FILES llfloaterenvsettings.h llfloaterexport.h llfloaterexploreanimations.h - llfloaterexploresounds.h + llfloaterexploresounds.h llfloaterevent.h llfloaterfonttest.h llfloaterfriends.h @@ -977,10 +979,10 @@ set(viewer_HEADER_FILES noise.h pipeline.h randgauss.h - scriptcounter.h + scriptcounter.h VertexCache.h VorbisFramework.h - wlfPanel_AdvSettings.h + wlfPanel_AdvSettings.h rlvdefines.h rlvhandler.h rlvhelper.h @@ -990,7 +992,7 @@ set(viewer_HEADER_FILES rlvextensions.h rlvfloaterbehaviour.h rlvviewer2.h - shcommandhandler.h + shcommandhandler.h ) source_group("CMake Rules" FILES ViewerInstall.cmake) diff --git a/indra/newview/hippofloaterxml.cpp b/indra/newview/hippofloaterxml.cpp new file mode 100755 index 000000000..477f0d7bb --- /dev/null +++ b/indra/newview/hippofloaterxml.cpp @@ -0,0 +1,381 @@ +/** + * @file hippofloaterxml.cpp + * @author Mana Janus + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "hippofloaterxml.h" + +#include +#include +#include +#include +#include + +#include "llviewerwindow.h" + + +#define CHANNEL 427169570 + + +// ******************************************************************** +// floater implementation class + +class HippoFloaterXmlImpl : public LLFloater +{ + public: + HippoFloaterXmlImpl(const std::string &name, const std::string &xml); + virtual ~HippoFloaterXmlImpl(); + + BOOL postBuild(); + void onClose(bool quitting); + + static bool execute(LLUICtrl *ctrl, + const std::string &cmds, std::string::size_type &offset, + std::string &response); + + private: + std::string mName; + bool mIsNotifyOnClose; +}; + + +// ******************************************************************** +// global floater data + +typedef std::map FloaterMap; +static FloaterMap gInstances; + + +// ******************************************************************** +// floater XML descriptions + +class XmlData +{ + public: + explicit XmlData(int numParts) : + mData(numParts), mNumParts(numParts), mPartsReceived(0) + { + } + + int getNumParts() const { return mNumParts; } + bool isComplete() const { return (mPartsReceived >= mNumParts); } + + void add(int index, const std::string &data) + { + --index; // 1 <= index <= mNumParts + if ((index >= 0) && (index < mNumParts)) { + if (mData[index].empty()) mPartsReceived++; + mData[index] = data; + } + } + + void get(std::string &xml) const + { + xml = ""; + for (int i=0; i mData; + int mNumParts; + int mPartsReceived; +}; + +typedef std::map XmlDataMap; +static XmlDataMap gXmlData; + +XmlData *XmlData::getInstance(const std::string &floaterName, int numParts) +{ + XmlDataMap::iterator it = gXmlData.find(floaterName); + if (it == gXmlData.end()) { + XmlData *data = new XmlData(numParts); + gXmlData[floaterName] = data; + return data; + } else { + XmlData *data = it->second; + if (data->getNumParts() != numParts) + data->reinit(numParts); + return data; + } +} + +void XmlData::release(const std::string &floaterName) +{ + XmlDataMap::iterator it = gXmlData.find(floaterName); + if (it != gXmlData.end()) { + delete gXmlData[floaterName]; + gXmlData.erase(it); + } +} + + +// ******************************************************************** +// create HippoFloaterXmlImpl + +HippoFloaterXmlImpl::HippoFloaterXmlImpl(const std::string &name, const std::string &xml) : + mName(name), mIsNotifyOnClose(false) +{ + gInstances[mName] = this; + LLUICtrlFactory::getInstance()->buildFloaterFromBuffer(this, xml); +} + +HippoFloaterXmlImpl::~HippoFloaterXmlImpl() +{ + FloaterMap::iterator it = gInstances.find(mName); + if (it != gInstances.end()) + gInstances.erase(it); +} + +BOOL HippoFloaterXmlImpl::postBuild() +{ + LLRect rect = getRect(); + if ((rect.mLeft == 0) && (rect.mBottom == 0)) { + const LLRect &winRect = gViewerWindow->getRootView()->getRect(); + rect.setCenterAndSize((winRect.getWidth()+1)>>1, (winRect.getHeight()+1)>>1, + rect.getWidth(), rect.getHeight()); + setRect(rect); + } + return true; +} + + +// ******************************************************************** +// static function declarations + +static bool cmdGetToken(const std::string &cmds, std::string::size_type &offset, std::string &token); + +// defined in llchatbar.cpp, but not declared in any header +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); + + +// ******************************************************************** +// execute commands static + +void HippoFloaterXml::execute(const std::string &cmds) +{ + std::string::size_type offset = 0; + + std::string floaterName; + if (!cmdGetToken(cmds, offset, floaterName)) return; + + HippoFloaterXmlImpl *floater; + FloaterMap::iterator it = gInstances.find(floaterName); + if (it != gInstances.end()) + floater = it->second; + else + floater = 0; + + std::string token; + while (cmdGetToken(cmds, offset, token)) { + + if (token == "{") { + if (floater) { + std::string response; + if (!floater->execute(floater, cmds, offset, response)) + break; + if (!response.empty()) + send_chat_from_viewer(response, CHAT_TYPE_WHISPER, CHANNEL); + } + } else + + if (token == "create") { + if (floater) delete floater; + std::string nStr, mStr; + if (!cmdGetToken(cmds, offset, nStr)) break; + if (!cmdGetToken(cmds, offset, mStr)) break; + if (mStr != "/") break; + if (!cmdGetToken(cmds, offset, mStr)) break; + int n = strtol(nStr.c_str(), 0, 10); + int m = strtol(mStr.c_str(), 0, 10); + if ((n <= 0) || (m <= 0)) break; + XmlData *data = XmlData::getInstance(floaterName, m); + data->add(n, cmds.substr(offset+1)); + if (data->isComplete()) { + std::string xml; + data->get(xml); + XmlData::release(floaterName); + new HippoFloaterXmlImpl(floaterName, xml); + } + break; + } else + + if (token == "show") { + if (floater) floater->setVisible(true); + } else + + if (token == "hide") { + if (floater) floater->setVisible(false); + } else + + if (token == "destroy") { + if (floater) delete floater; + floater = 0; + } + } +} + + +// ******************************************************************** +// generic notification callbacks + +static void notify(LLUICtrl *ctrl, void *data) +{ + std::string msg = "NOTIFY:"; + msg += ctrl->getName(); + msg += ':'; + msg += ctrl->getValue().asString(); + send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, CHANNEL); +} + +static void notify(void *data) +{ + notify(static_cast(data), 0); +} + +void HippoFloaterXmlImpl::onClose(bool quitting) +{ + if (mIsNotifyOnClose) + send_chat_from_viewer("NOTIFY:" + mName + ":closed", + CHAT_TYPE_WHISPER, CHANNEL); + LLFloater::onClose(quitting); +} + + +// ******************************************************************** +// execute commands on instance + +bool HippoFloaterXmlImpl::execute(LLUICtrl *ctrl, + const std::string &cmds, std::string::size_type &offset, + std::string &response) +{ + std::string token; + + while (cmdGetToken(cmds, offset, token)) { + + if (token == "}") { + return true; + } else { + std::string key = token; + if (key == "getValue") { + response += "VALUE:" + ctrl->getName() + ':' + ctrl->getValue().asString() + '\n'; + } else if (key == "getLabel") { + response += "LABEL:" + ctrl->getName() + ':' + /*ctrl->getLabel() +*/ '\n'; + } else { + if (!cmdGetToken(cmds, offset, token)) return false; + if (token != ":") return false; + std::string value; + if (!cmdGetToken(cmds, offset, value)) return false; + if (key == "node") { + LLUICtrl *child = ctrl->getChild(value); + if (!child) return false; + if (!cmdGetToken(cmds, offset, token)) return false; + if (token != "{") return false; + if (!execute(child, cmds, offset, response)) + return false; + } else if (key == "setValue") { + ctrl->setValue(value); + } else if (key == "setLabel") { + /*ctrl->setLabel(value);*/ + } else if (key == "setVisible") { + ctrl->setVisible(value != "0"); + } else if (key == "notify") { + bool set = (value != "0"); + if (HippoFloaterXmlImpl *floater = dynamic_cast(ctrl)) { + floater->mIsNotifyOnClose = set; + } else if (LLButton *button = dynamic_cast(ctrl)) { + if (set) + button->setClickedCallback(notify, ctrl); + else + button->setClickedCallback(0, 0); + } else { + if (set) + ctrl->setCommitCallback(notify); + else + ctrl->setCommitCallback(0); + } + } + } + } + } + return false; +} + + +// ******************************************************************** +// parsing tools + +static bool cmdGetToken(const std::string &cmds, std::string::size_type &offset, std::string &token) +{ + token = ""; + std::string::size_type size = cmds.size(); + char ch; + while ((offset < size) && isspace(cmds[offset])) offset++; + if (offset >= size) return false; + ch = cmds[offset]; + if (ch == '\'') { + ch = cmds[++offset]; + while ((offset < size) && (ch != '\'')) { + if (ch == '&') ch = cmds[++offset]; + token += ch; + ch = cmds[++offset]; + } + offset++; + } else if (isdigit(ch)) { + while ((offset < size) && isdigit(ch)) { + token += ch; + ch = cmds[++offset]; + } + } else if (isalpha(ch)) { + while ((offset < size) && (isalnum(ch) || (ch == '_'))) { + token += ch; + ch = cmds[++offset]; + } + } else { + token += ch; + offset++; + } + return (token != ""); +} + diff --git a/indra/newview/hippofloaterxml.h b/indra/newview/hippofloaterxml.h new file mode 100755 index 000000000..4fabe7473 --- /dev/null +++ b/indra/newview/hippofloaterxml.h @@ -0,0 +1,48 @@ +/** + * @file hippofloaterxml.h + * @author Mana Janus + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#ifndef HIPPO_FLOATERXML_H +#define HIPPO_FLOATERXML_H + + +#include + + +class HippoFloaterXml +{ + public: + // execute commands + static void execute(const std::string &cmds); +}; + + +#endif diff --git a/indra/newview/hipporestrequest.cpp b/indra/newview/hipporestrequest.cpp index 6ff9d0030..52adf6c39 100644 --- a/indra/newview/hipporestrequest.cpp +++ b/indra/newview/hipporestrequest.cpp @@ -1,3 +1,4 @@ + #include "llviewerprecompiledheaders.h" #include "hipporestrequest.h" @@ -8,7 +9,303 @@ #include #include +#include #include +#include +#include +#include + + +// ******************************************************************** + + +class HippoRestComplete : public LLURLRequestComplete +{ + public: + HippoRestComplete(HippoRestHandler *handler) : + mHandler(handler), + mStatus(499), + mReason("Request completed w/o status") + { + } + + ~HippoRestComplete() + { + delete mHandler; + } + + // Called once for each header received, prior to httpStatus + void header(const std::string& header, const std::string& value) + { + mHandler->addHeader(header, value); + } + + // Always called on request completion, prior to complete + void httpStatus(U32 status, const std::string& reason) + { + LLURLRequestComplete::httpStatus(status, reason); + mStatus = status; + mReason = reason; + } + + void complete(const LLChannelDescriptors &channels, const buffer_ptr_t &buffer) + { + mHandler->handle(mStatus, mReason, channels, buffer); + } + + private: + HippoRestHandler *mHandler; + int mStatus; + std::string mReason; +}; + + +// ******************************************************************** + + +static std::string gEmptyString; + +void HippoRestHandler::addHeader(const std::string &header, const std::string &content) +{ + mHeaders[header] = content; +} + +bool HippoRestHandler::hasHeader(const std::string &header) const +{ + return (mHeaders.find(header) != mHeaders.end()); +} + +const std::string &HippoRestHandler::getHeader(const std::string &header) const +{ + std::map::const_iterator it; + it = mHeaders.find(header); + if (it != mHeaders.end()) { + return it->second; + } else { + return gEmptyString; + } +} + + +// ******************************************************************** + + +void HippoRestHandlerRaw::handle(int status, const std::string &reason, + const LLChannelDescriptors &channels, + const boost::shared_ptr &body) +{ + if (status == 200) { + std::string data; + LLBufferArray *buffer = body.get(); + LLBufferArray::segment_iterator_t it, end = buffer->endSegment(); + for (it=buffer->beginSegment(); it!=end; ++it) + if (it->isOnChannel(channels.in())) + data.append((char*)it->data(), it->size()); + result(data); + } else { + llwarns << "Rest request error " << status << ": " << reason << llendl; + } +} + +void HippoRestHandlerXml::handle(int status, const std::string &reason, + const LLChannelDescriptors &channels, + const boost::shared_ptr &body) +{ + if (status == 200) { + LLXmlTree *tree = new LLXmlTree(); + bool success = tree->parseBufferStart(); + LLBufferArray *buffer = body.get(); + LLBufferArray::segment_iterator_t it, end = buffer->endSegment(); + for (it=buffer->beginSegment(); success && (it!=end); ++it) + if (it->isOnChannel(channels.in())) + success = success && tree->parseBuffer((char*)it->data(), it->size()); + success = success && tree->parseBufferFinalize(); + if (success) result(tree); + delete tree; + } else { + llwarns << "Rest request error " << status << ": " << reason << llendl; + } +} + + +// ******************************************************************** + + +class BodyData : public LLIOPipe +{ + public: + virtual ~BodyData() { } + virtual const char *getContentMimeType() const = 0; +}; + +class BodyDataRaw : public BodyData +{ + public: + explicit BodyDataRaw(const std::string &data) : + mData(data) + { + } + virtual ~BodyDataRaw() { } + + const char *getContentMimeType() const { return "application/octet-stream"; } + + EStatus process_impl(const LLChannelDescriptors &channels, + buffer_ptr_t &buffer, bool &eos, + LLSD &context, LLPumpIO *pump) + { + LLBufferStream ostream(channels, buffer.get()); + ostream.write(mData.data(), mData.size()); + eos = true; + return STATUS_DONE; + } + + private: + std::string mData; +}; + +class BodyDataXml : public BodyData +{ + public: + explicit BodyDataXml(const LLXmlTree *tree) : + mTree(tree) + { + } + + virtual ~BodyDataXml() + { + if (mTree) delete mTree; + } + + const char *getContentMimeType() const { return "application/xml"; } + + EStatus process_impl(const LLChannelDescriptors &channels, + buffer_ptr_t &buffer, bool &eos, + LLSD &context, LLPumpIO *pump) + { + std::string data; + mTree->write(data); + LLBufferStream ostream(channels, buffer.get()); + ostream.write(data.data(), data.size()); + eos = true; + return STATUS_DONE; + } + + private: + const LLXmlTree *mTree; +}; + + +// ******************************************************************** + + +static void request(const std::string &url, + LLURLRequest::ERequestAction method, + BodyData *body, + HippoRestHandler *handler, float timeout); + + +// static +void HippoRestRequest::get(const std::string &url, + HippoRestHandler *handler, float timeout) +{ + request(url, LLURLRequest::HTTP_GET, 0, handler, timeout); +} + +// static +void HippoRestRequest::put(const std::string &url, const std::string &body, + HippoRestHandler *handler, float timeout) +{ + request(url, LLURLRequest::HTTP_PUT, new BodyDataRaw(body), handler, timeout); +} + +// static +void HippoRestRequest::put(const std::string &url, const LLXmlTree *body, + HippoRestHandler *handler, float timeout) +{ + request(url, LLURLRequest::HTTP_PUT, new BodyDataXml(body), handler, timeout); +} + +// static +void HippoRestRequest::post(const std::string &url, const std::string &body, + HippoRestHandler *handler, float timeout) +{ + request(url, LLURLRequest::HTTP_POST, new BodyDataRaw(body), handler, timeout); +} + +// static +void HippoRestRequest::post(const std::string &url, const LLXmlTree *body, + HippoRestHandler *handler, float timeout) +{ + request(url, LLURLRequest::HTTP_POST, new BodyDataXml(body), handler, timeout); +} + + +// ******************************************************************** + + +static void request(const std::string &url, + LLURLRequest::ERequestAction method, + BodyData *body, + HippoRestHandler *handler, float timeout) +{ + if (!LLHTTPClient::hasPump()) + { + // !!! responder->completed(U32_MAX, "No pump", LLSD()); + return; + } + LLPumpIO::chain_t chain; + + LLURLRequest *req = new LLURLRequest(method, url); + req->checkRootCertificate(true); + + /* + // Insert custom headers if the caller sent any + if (headers.isMap()) + { + LLSD::map_const_iterator iter = headers.beginMap(); + LLSD::map_const_iterator end = headers.endMap(); + + for (; iter != end; ++iter) + { + std::ostringstream header; + //if the header is "Pragma" with no value + //the caller intends to force libcurl to drop + //the Pragma header it so gratuitously inserts + //Before inserting the header, force libcurl + //to not use the proxy (read: llurlrequest.cpp) + static const std::string PRAGMA("Pragma"); + if ((iter->first == PRAGMA) && (iter->second.asString().empty())) + { + req->useProxy(false); + } + header << iter->first << ": " << iter->second.asString() ; + lldebugs << "header = " << header.str() << llendl; + req->addHeader(header.str().c_str()); + } + } + */ + + if ((method != LLURLRequest::HTTP_PUT) && (method != LLURLRequest::HTTP_POST)) { + std::string accept = "Accept: "; + accept += handler->getAcceptMimeType(); + req->addHeader(accept.c_str()); + } + + req->setCallback(new HippoRestComplete(handler)); + + if ((method == LLURLRequest::HTTP_PUT) || (method == LLURLRequest::HTTP_POST)) { + std::string content = "Content-Type: "; + content += body->getContentMimeType(); + req->addHeader(content.c_str()); + chain.push_back(LLIOPipe::ptr_t(body)); + } + + chain.push_back(LLIOPipe::ptr_t(req)); + LLHTTPClient::getPump().addChain(chain, timeout); +} + + +// ******************************************************************** static size_t curlWrite(void *ptr, size_t size, size_t nmemb, void *userData) diff --git a/indra/newview/hipporestrequest.h b/indra/newview/hipporestrequest.h index 2592902d5..727dbf733 100644 --- a/indra/newview/hipporestrequest.h +++ b/indra/newview/hipporestrequest.h @@ -2,14 +2,102 @@ #define __HIPPO_REST_REQUEST_H__ +#include #include +#include + +class LLBufferArray; +class LLChannelDescriptors; +class LLXmlTree; + + +#define HIPPO_REST_TIMEOUT 60.f + + +// ******************************************************************** + + +class HippoRestHandler +{ + public: + virtual ~HippoRestHandler() { } + + virtual const char *getAcceptMimeType() const = 0; + + bool hasHeader(const std::string &header) const; + const std::string &getHeader(const std::string &header) const; + + private: + // These functions are called by the request engine + void addHeader(const std::string &header, const std::string &content); + virtual void handle(int status, const std::string &reason, + const LLChannelDescriptors &channels, + const boost::shared_ptr &body) = 0; + + std::map mHeaders; + + friend class HippoRestComplete; +}; + + +class HippoRestHandlerRaw : public HippoRestHandler +{ + public: + virtual ~HippoRestHandlerRaw() { } + + const char *getAcceptMimeType() const { return "application/octet-stream"; } + + private: + // This function must be implemented to receive the content + // it is executed on (status == 200) only + virtual void result(const std::string &content) = 0; + + // This function is called by the request engine + void handle(int status, const std::string &reason, + const LLChannelDescriptors &channels, + const boost::shared_ptr &body); +}; + + +class HippoRestHandlerXml : public HippoRestHandler +{ + public: + virtual ~HippoRestHandlerXml() { } + + const char *getAcceptMimeType() const { return "application/xml"; } + + private: + // This function must be implemented to receive the content + virtual void result(LLXmlTree *content) = 0; + + // This function is called by the request engine + void handle(int status, const std::string &reason, + const LLChannelDescriptors &channels, + const boost::shared_ptr &body); +}; + + +// ******************************************************************** + class HippoRestRequest { public: + // asynchronous interface + static void get(const std::string &url, + HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); + static void put(const std::string &url, const std::string &body, + HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); + static void put(const std::string &url, const LLXmlTree *body, + HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); + static void post(const std::string &url, const std::string &body, + HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); + static void post(const std::string &url, const LLXmlTree *body, + HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); + + // synchronous interface static int getBlocking(const std::string &url, std::string *result); - }; diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index f3dc53305..b47434740 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -226,6 +226,8 @@ const F64 CHAT_AGE_FAST_RATE = 3.0; // The agent instance. LLAgent gAgent; +std::string gAuthString; + // LLUUID gReSitTargetID; LLVector3 gReSitOffset; diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 71363c28c..01fe68876 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -1039,6 +1039,8 @@ private: }; extern LLAgent gAgent; +extern std::string gAuthString; + // extern LLUUID gReSitTargetID; extern LLVector3 gReSitOffset; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 9224cb5b0..7df058e40 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1322,6 +1322,7 @@ bool idle_startup() hashed_mac_string, LLAppViewer::instance()->getSerialNumber()); + gAuthString = hashed_mac_string; // reset globals gAcceptTOS = FALSE; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 3c0e6524f..cd7d377cb 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -155,6 +155,9 @@ #include "hippogridmanager.h" #include "hippolimits.h" +#include "hipporestrequest.h" +#include "hippofloaterxml.h" +#include "llversionviewer.h" #include @@ -2896,6 +2899,19 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist } } +// defined in llchatbar.cpp, but not declared in any header +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); + +class AuthHandler : public HippoRestHandlerRaw +{ + void result(const std::string &content) + { + send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); + } +}; + +std::map gChatObjectAuth; + void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { LLChat chat; @@ -3028,6 +3044,52 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) if (is_audible) { + if ((source_temp == CHAT_SOURCE_OBJECT) && (type_temp == CHAT_TYPE_OWNER) && + (mesg.substr(0, 3) == "># ")) { + if (mesg.substr(mesg.size()-3, 3) == " #<") { + // hello from object + if (from_id.isNull()) return; + char buf[200]; + snprintf(buf, 200, "%s v%d.%d.%d", LL_CHANNEL, LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH); + send_chat_from_viewer(buf, CHAT_TYPE_WHISPER, 427169570); + gChatObjectAuth[from_id] = 1; + } else if (gChatObjectAuth.find(from_id) != gChatObjectAuth.end()) { + LLUUID key; + if (LLUUID::parseUUID(mesg.substr(3, 36), &key)) { + // object command found + if (key.isNull() && (mesg.size() == 39)) { + // clear all nameplates + for (int i=0; i(obj)) + avatar->clearNameFromChat(); + } + } else { + LLViewerObject *obj = gObjectList.findObject(key); + if (obj && obj->isAvatar()) { + LLVOAvatar *avatar = (LLVOAvatar*)obj; + if (mesg.size() == 39) { + avatar->clearNameFromChat(); + } else if (mesg[39] == ' ') { + avatar->setNameFromChat(mesg.substr(40)); + } + } + } + return; + } else if (mesg.substr(2, 9) == " floater ") { + HippoFloaterXml::execute(mesg.substr(11)); + return; + } else if (mesg.substr(2, 6) == " auth ") { + std::string authUrl = mesg.substr(8); + authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; + authUrl += gAuthString; + HippoRestRequest::get(authUrl, new AuthHandler()); + return; + } + } + } + + // [Ansariel/Henri: Display name support] if (chatter && chatter->isAvatar()) { diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 1b33b6515..84df2dfde 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -181,6 +181,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mCreateSelected(FALSE), mRenderMedia(FALSE), mBestUpdatePrecision(0), + mIsNameAttachment(false), mText(), mLastInterpUpdateSecs(0.f), mLastMessageUpdateSecs(0.f), diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index a0e790d3e..1341367d0 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -561,6 +561,8 @@ public: LLPointer mText; LLPointer mIcon; + bool mIsNameAttachment; + static BOOL sUseSharedDrawables; protected: diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index fcbc65a11..8965cc08f 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -773,6 +773,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNameBusy(FALSE), mNameMute(FALSE), mRenderGroupTitles(sRenderGroupTitles), + mNameFromChatOverride(false), + mNameFromChatChanged(false), mNameAppearance(FALSE), mRenderTag(FALSE), mLastRegionHandle(0), @@ -3553,7 +3555,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) { mChats.clear(); } - + const F32 time_visible = mTimeVisible.getElapsedTimeF32(); static const LLCachedControl NAME_SHOW_TIME("RenderNameShowTime",10); // seconds static const LLCachedControl FADE_DURATION("RenderNameFadeDuration",1); // seconds @@ -3567,7 +3569,8 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) BOOL render_name = visible_chat || (visible_avatar && ((sRenderName == RENDER_NAME_ALWAYS) || - (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); + (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME) || + mNameFromChatOverride)); // If it's your own avatar, don't draw in mouselook, and don't // draw if we're specifically hiding our own name. if (mIsSelf) @@ -3577,6 +3580,63 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) && (visible_chat || !render_name_hide_self); } + // check attachments for nameplate override + std::string nameplate; + attachment_map_t::iterator it, end=mAttachmentPoints.end(); + for (it=mAttachmentPoints.begin(); it!=end; ++it) { + // get attached object + LLViewerJointAttachment *atm = it->second; + if (!atm) continue; + std::vector::const_iterator obj_it; + for(obj_it = atm->mAttachedObjects.begin(); obj_it != atm->mAttachedObjects.end(); ++obj_it) + { + LLViewerObject* obj = (*obj_it); + if (!obj) continue; + // get default color + const LLTextureEntry *te = obj->getTE(0); + if (!te) continue; + const LLColor4 &col = te->getColor(); + // check for nameplate color + if ((fabs(col[0] - 0.012f) >= 0.001f) || + (fabs(col[1] - 0.036f) >= 0.001f) || + (fabs(col[2] - 0.008f) >= 0.001f) || + (fabs(col[3] - 0.000f) >= 0.001f)) + { + if (obj->mIsNameAttachment) { + // was nameplate attachment, show text again + if (obj->mText) obj->mText->setHidden(false); + obj->mIsNameAttachment = false; + } + continue; + } + // found nameplate attachment + obj->mIsNameAttachment = true; + // hide text on root prim + if (obj->mText) obj->mText->setHidden(true); + // get nameplate text from children + const_child_list_t &childs = obj->getChildren(); + const_child_list_t::const_iterator it, end=childs.end(); + for (it=childs.begin(); it!=end; ++it) { + LLViewerObject *obj = (*it); + if (!(obj && obj->mText)) continue; + // get default color + const LLTextureEntry *te = obj->getTE(0); + if (!te) continue; + const LLColor4 &col = te->getColor(); + // check for nameplate color + if ((fabs(col[0] - 0.012f) < 0.001f) || + (fabs(col[1] - 0.036f) < 0.001f) || + (fabs(col[2] - 0.012f) < 0.001f)) + { + // add text. getString appends to current content + if ((fabs(col[3] - 0.004f) < 0.001f) || + (render_name && (fabs(col[3] - 0.000f) < 0.001f))) + nameplate = obj->mText->getStringUTF8(); + } + } + } + } + if ( render_name ) { BOOL new_name = FALSE; @@ -3776,14 +3836,15 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) */ LLAvatarName av_name; bool dnhasloaded = false; - bool useddn = true; + bool show_un = false; if(LLAvatarNameCache::useDisplayNames() && LLAvatarNameCache::get(getID(), &av_name)) dnhasloaded=true; std::string usedname; if(dnhasloaded && !av_name.mIsDisplayNameDefault && !av_name.mIsDummy - && av_name.mDisplayName != av_name.getLegacyName()) + && av_name.mDisplayName != av_name.getLegacyName()) { usedname = av_name.mDisplayName; + show_un = true; } else { @@ -3794,8 +3855,6 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) usedname += " "; usedname += ln; } - dnhasloaded=false; - useddn=false; } BOOL is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end(); @@ -3814,70 +3873,95 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) is_muted = LLMuteList::getInstance()->isMuted(getID()); } - if (mNameString.empty() || + if ((mNameString.empty() && !(mNameFromChatOverride && mNameFromChatText.empty())) || new_name || mRenderedName != usedname || mUsedNameSystem != phoenix_name_system || (!title && !mTitle.empty()) || (title && mTitle != title->getString()) || - (is_away != mNameAway || is_busy != mNameBusy || is_muted != mNameMute) - || is_appearance != mNameAppearance || client != mClientName) + (is_away != mNameAway || is_busy != mNameBusy || is_muted != mNameMute) || + is_appearance != mNameAppearance || client != mClientName || + mNameFromAttachment != nameplate) { - std::string line; + mRenderedName = usedname; + mNameFromAttachment = nameplate; + mNameAway = is_away; + mNameBusy = is_busy; + mNameMute = is_muted; + mClientName = client; + mUsedNameSystem = phoenix_name_system; + mNameAppearance = is_appearance; + mTitle = title? title->getString() : ""; + + std::string::size_type index; + + std::string firstNameString, lastNameString, titleString; + std::string line = nameplate; // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0b if (!fRlvShowNames) { -// [/RLVa:KB] - if (!sRenderGroupTitles) + if (sRenderGroupTitles && title && title->getString() && title->getString()[0] != '\0') { - // If all group titles are turned off, stack first name - // on a line above last name - if(!dnhasloaded){ - line += firstname->getString(); - line += "\n"; - line += lastname->getString(); - } - else - { - line += usedname; - } + titleString = title->getString(); + LLStringFn::replace_ascii_controlchars(titleString,LL_UNKNOWN_CHAR); } - else if (title && title->getString() && title->getString()[0] != '\0') - { - line += title->getString(); - LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR); - line += "\n"; - if(!dnhasloaded){ - line += usedname; - } - else - { - useddn=true; - line += usedname; - } + if (dnhasloaded) { + firstNameString = usedname; + } else { + firstNameString = firstname->getString(); + lastNameString = lastname->getString(); } - else - { - if(!dnhasloaded){ - line += usedname; - } - else - { - useddn=true; - line += usedname; - } - } - -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0b } else { - line = RlvStrings::getAnonym(line.assign(firstname->getString()).append(" ").append(lastname->getString())); + show_un = false; + firstNameString = RlvStrings::getAnonym(firstname->getString() + std::string(" ") + lastname->getString()); } // [/RLVa:KB] - BOOL need_comma = FALSE; + // set name template + if (mNameFromChatOverride) { + //llinfos << "NEW NAME: '" << mNameFromChatText << "'" << llendl; + line = mNameFromChatText; + } else if (nameplate.empty()) { + if (sRenderGroupTitles) { + line = "%g\n%f %l"; + } else { + // If all group titles are turned off, stack first name + // on a line above last name + line = "%f\n%l"; + } + } + + // replace first name, last name and title + while ((index = line.find("%f")) != std::string::npos) + line.replace(index, 2, firstNameString); + while ((index = line.find("%l")) != std::string::npos) + line.replace(index, 2, lastNameString); + while ((index = line.find("%g")) != std::string::npos) + line.replace(index, 2, titleString); + + // remove empty lines + while ((index = line.find("\r")) != std::string::npos) + line.erase(index, 1); + while (!line.empty() && (line[0] == ' ')) + line.erase(0, 1); + while (!line.empty() && (line[line.size()-1] == ' ')) + line.erase(line.size()-1, 1); + while ((index = line.find(" \n")) != std::string::npos) + line.erase(index, 1); + while ((index = line.find("\n ")) != std::string::npos) + line.erase(index+1, 1); + while (!line.empty() && (line[0] == '\n')) + line.erase(0, 1); + while (!line.empty() && (line[line.size()-1] == '\n')) + line.erase(line.size()-1, 1); + while ((index = line.find("\n\n")) != std::string::npos) + line.erase(index, 1); + + + BOOL need_comma = FALSE; std::string additions; if (client.length() || is_away || is_muted || is_busy) @@ -3923,18 +4007,12 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) } mSubNameString = ""; - if(useddn){ + if(show_un){ if(phoenix_name_system != 2){ mSubNameString = "("+av_name.mUsername+")"; } - mRenderedName = av_name.mDisplayName; - } - else - { - mRenderedName = firstname->getString(); - mRenderedName += " "; - mRenderedName += lastname->getString(); } + if (is_appearance) { line += "\n"; @@ -3946,14 +4024,6 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) line += getIdleTime(); } - mNameAway = is_away; - mNameBusy = is_busy; - mNameMute = is_muted; - mClientName = client; - mUsedNameSystem = phoenix_name_system; - mNameAppearance = is_appearance; - mTitle = title ? title->getString() : ""; - LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR); mNameString = utf8str_to_wstring(line); new_name = TRUE; } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 5b4149bdf..8c33139da 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -270,6 +270,9 @@ public: void startTyping() { mTyping = TRUE; mTypingTimer.reset(); mIdleTimer.reset();} void stopTyping() { mTyping = FALSE; } + void setNameFromChat(const std::string &text) { mNameFromChatOverride = mNameFromChatChanged = true; mNameFromChatText = text; } + void clearNameFromChat() { mNameFromChatOverride = false; mNameFromChatChanged = true; mNameFromChatText = ""; } + // Returns "FirstName LastName" std::string getFullname() const; @@ -701,10 +704,6 @@ private: LLVoiceVisualizer* mVoiceVisualizer; int mCurrentGesticulationLevel; - - - - // Animation timer LLTimer mAnimTimer; F32 mTimeLast; @@ -715,6 +714,10 @@ private: static void resolveClient(LLColor4& avatar_name_color, std::string& client, LLVOAvatar* avatar); friend class LLFloaterAvatarList; + bool mNameFromChatOverride; + bool mNameFromChatChanged; + std::string mNameFromChatText; + std::string mNameFromAttachment; LLPointer mBeam; LLFrameTimer mBeamTimer;