From 7f090f7bec5264ca9e203c27dfb6b2992bb2bcbd Mon Sep 17 00:00:00 2001 From: McCabe Maxsted Date: Mon, 14 Sep 2009 17:52:41 -0700 Subject: Merged in jacek/next --- linden/indra/newview/rlvhandler.h | 462 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 462 insertions(+) create mode 100644 linden/indra/newview/rlvhandler.h (limited to 'linden/indra/newview/rlvhandler.h') diff --git a/linden/indra/newview/rlvhandler.h b/linden/indra/newview/rlvhandler.h new file mode 100644 index 0000000..df3ff9b --- /dev/null +++ b/linden/indra/newview/rlvhandler.h @@ -0,0 +1,462 @@ +#ifndef RLV_HANDLER_H +#define RLV_HANDLER_H + +#include "llagentconstants.h" +#include "llappviewer.h" +#include "llformat.h" +#include "llversionviewer.h" +#include "llviewerjointattachment.h" +#include "llviewerobject.h" +#include "llwearable.h" + +#include "rlvhelper.h" +#include "rlvevent.h" +#include "rlvmultistringsearch.h" + +// ============================================================================ +/* + * RlvHandler + * ========== + * + */ + +typedef std::map rlv_object_map_t; +typedef std::multimap rlv_detach_map_t; +typedef std::map rlv_reattach_map_t; +typedef std::multimap rlv_exception_map_t; +typedef std::map rlv_redir_map_t; + +class RlvHandler +{ +public: + RlvHandler(); + ~RlvHandler(); + + // -------------------------------- + + /* + * Rule checking functions + */ +public: + // Returns a pointer to the attachment point for a supplied parameter + LLViewerJointAttachment* getAttachPoint(const std::string& strText, bool fExact) const; + LLViewerJointAttachment* getAttachPoint(const LLInventoryItem* pItem, bool fStrict) const; + LLViewerJointAttachment* getAttachPoint(const LLInventoryCategory* pFolder, bool fStrict) const; + LLViewerJointAttachment* getAttachPointLegacy(const LLInventoryCategory* pFolder) const; + S32 getAttachPointIndex(std::string strText, bool fExact) const; + S32 getAttachPointIndex(LLViewerObject* pObj) const; + S32 getAttachPointIndex(const LLViewerJointAttachment* pObj) const; + bool hasAttachPointName(const LLInventoryItem* pItem, bool fStrict) const; + + // Returns TRUE is at least one object contains the specified behaviour (and optional parameter) + // NOTE: - to check @detach=n -> hasLockedAttachment() / hasLockedHUD() / isDetachable() + // - to check @addoutfit=n -> isWearable() + // - to check @remoutfit=n -> isRemovable() + // - to check exceptions -> isException() + // (You *can* use hasBehaviour(); the specialized ones just don't have to iterate over all the objects) + bool hasBehaviour(ERlvBehaviour eBehaviour) const { return (eBehaviour < RLV_BHVR_COUNT) ? (0 != m_Behaviours[eBehaviour]) : false; } + bool hasBehaviour(const std::string& strBehaviour) const; + bool hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption) const; + bool hasBehaviour(const std::string& strBehaviour, const std::string& strOption) const; + + // Returns TRUE if at least one object (except the specified one) contains the specified behaviour + bool hasBehaviourExcept(ERlvBehaviour eBehaviour, const LLUUID& idObj) const; + bool hasBehaviourExcept(const std::string& strBehaviour, const LLUUID& uuid) const; + bool hasBehaviourExcept(ERlvBehaviour eBehaviour, const std::string& strOption, const LLUUID& idObj) const; + bool hasBehaviourExcept(const std::string& strBehaviour, const std::string& strOption, const LLUUID& idObj) const; + + // Returns TRUE if there is at least 1 undetachable attachment + bool hasLockedAttachment() const { return (0 != m_Attachments.size()); } + // Returns TRUE if there is at least 1 undetachable HUD attachment + bool hasLockedHUD() const; + + // Returns TRUE if the specified attachment point is detachable + bool isDetachable(S32 idxAttachPt) const { return (idxAttachPt) && (m_Attachments.find(idxAttachPt) == m_Attachments.end()); } + bool isDetachable(const LLInventoryItem* pItem) const; + bool isDetachable(LLViewerObject* pObj) const; + // Returns TRUE if the specified attachment point is set undetachable by anything other than pObj (or one of its children) + bool isDetachableExcept(S32 idxAttachPt, LLViewerObject* pObj) const; + // Marks the specified attachment point as (un)detachable (return value indicates success ; used by unit tests) + bool setDetachable(S32 idxAttachPt, const LLUUID& idRlvObj, bool fDetachable); + bool setDetachable(LLViewerObject* pObj, const LLUUID& idRlvObj, bool fDetachable); + + // Adds or removes an exception for the specified restriction + void addException(ERlvBehaviour eBehaviour, const LLUUID& uuid); + void removeException(ERlvBehaviour eBehaviour, const LLUUID& uuid); + // Returns TRUE is the specified UUID is exempt from a restriction (tplure/sendim/recvim/etc) + bool isException(ERlvBehaviour eBehaviour, const LLUUID& uuid) const; + bool isException(const std::string& strBehaviour, const LLUUID& uuid) const; + + // Returns TRUE if the specified layer is removable (use hasBehaviour(RLV_BHVR_REMOUTFIT) for the general case) + bool isRemovable(EWearableType type) const { return (type < WT_COUNT) ? (0 == m_LayersRem[type]) : true; } + // Returns TRUE if the specified layer is not remoutfit blocked by any object (except the one specified by UUID) + bool isRemovableExcept(EWearableType type, const LLUUID& idObj) const; + // Returns TRUE if the inventory item is strippable by @detach or @remoutfit + bool isStrippable(const LLUUID& idItem) const; + // Returns TRUE if the specified layer is wearable (use hasBehaviour(RLV_BHVR_ADDOUTFIT) for the general case) + bool isWearable(EWearableType type) const { return (type < WT_COUNT) ? (0 == m_LayersAdd[type]) : true; } + + // Returns TRUE if the composite folder doesn't contain any "locked" items + bool canTakeOffComposite(const LLInventoryCategory* pFolder) const; + // Returns TRUE if the folder is a composite folder and optionally returns the name + bool getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const; + // Returns TRUE if the inventory item belongs to a composite folder and optionally returns the name and composite folder + bool getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const; + // Returns TRUE if the folder is a composite folder + bool isCompositeFolder(const LLInventoryCategory* pFolder) const; + // Returns TRUE if the inventory item belongs to a composite folder + bool isCompositeDescendent(const LLUUID& idItem) const; + // Returns TRUE if the inventory item is part of a folded composite folder and should be hidden from @getoufit or @getattach + bool isHiddenCompositeItem(const LLUUID& idItem, const std::string& strItemType) const; + + // -------------------------------- + + /* + * Helper functions + */ +public: + // Accessors + bool getCanCancelTp() const { return m_fCanCancelTp; } // @accepttp and @tpto + void setCanCancelTp(bool fAllow) { m_fCanCancelTp = fAllow; } // @accepttp and @tpto + + // Command specific helper functions + bool canShowHoverText(LLViewerObject* pObj) const; // @showhovertext* command family + void filterChat(std::string& strUTF8Text, bool fFilterEmote) const; // @sendchat, @recvchat and @redirchat + void filterLocation(std::string& strUTF8Text) const; // @showloc + void filterNames(std::string& strUTF8Text) const; // @shownames + const std::string& getAnonym(const std::string& strName) const; // @shownames + std::string getVersionString() const; // @version + BOOL isAgentNearby(const LLUUID& uuid) const; // @shownames + bool redirectChatOrEmote(const std::string& strUTF8Test) const; // @redirchat and @rediremote + + // Command processing helper functions + BOOL processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj); + void processRetainedCommands(); + void retainCommand(const std::string& strObj, const LLUUID& idObj, const std::string& strCmd); + + // Returns a pointer to the currently executing command (do *not* save this pointer) + const RlvCommand* getCurrentCommand() const { return m_pCurCommand; } + // Returns the UUID of the object we're currently executing a command for + const LLUUID& getCurrentObject() const { return m_idCurObject; } + + // Initialization + static BOOL canDisable(); + static BOOL isEnabled() { return m_fEnabled; } + static void initLookupTables(); + static BOOL setEnabled(BOOL fEnable); +protected: + void clearState(); + + // -------------------------------- + + /* + * Inventory related functions + */ +public: + // Starts a fetch of everything under the shared root (if there is one) + static void fetchSharedInventory(); + // Returns the path of the supplied folder (relative to the shared root) + std::string getSharedPath(const LLViewerInventoryCategory* pFolder) const; + std::string getSharedPath(const LLUUID& idFolder) const; + // Returns a pointer to the shared root folder (if there is one) + static LLViewerInventoryCategory* getSharedRoot(); + // A "folded folder" is a folder whose items logically belong to the grandparent rather than the parent + bool isFoldedFolder(const LLInventoryCategory* pFolder, bool fAttach) const; + bool isFoldedFolderLegacy(const LLInventoryCategory* pFolder, bool fAttach) const; +protected: + // Find all folders that match a supplied criteria (clears the supplied array) + bool findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const; + + // Returns a subfolder of idParent that starts with name (exact match > partial match) + LLViewerInventoryCategory* getSharedFolder(const LLUUID& idParent, const std::string& strName) const; + // Looks up a folder from a path (relative to the shared root) + LLViewerInventoryCategory* getSharedFolder(const std::string& strPath) const; + + bool getWornInfo(const LLInventoryCategory* pFolder, U8& wiFolder, U8& wiChildren) const; + + // -------------------------------- + + /* + * Event handling (forwards to registered observers if we don't handle the command) + */ +public: + BOOL addObserver(RlvObserver* pObserver) { return m_Emitter.addObserver(pObserver); } + BOOL removeObserver(RlvObserver* pObserver) { return m_Emitter.remObserver(pObserver); } + void addBehaviourObserver(RlvBehaviourObserver* pBhvrObserver); + void removeBehaviourObserver(RlvBehaviourObserver* pBhvrObserver); + void notifyBehaviourObservers(const RlvCommand& rlvCmd, bool fInternal); + + // Externally invoked event handlers + void onAttach(LLViewerJointAttachment* pAttachPt, bool fFullyLoaded); // LLVOAvatar::attachObject() + void onDetach(LLViewerJointAttachment* pAttachPt); // LLVOAvatar::detachObject() + bool onGC(); // RlvGCTimer::tick() + void onSavedAssetIntoInventory(const LLUUID& idItem); // LLInventoryModel::processSaveAssetIntoInventory() +protected: + BOOL processAddCommand(const LLUUID& uuid, const RlvCommand& rlvCmd); + BOOL processRemoveCommand(const LLUUID& uuid, const RlvCommand& rlvCmd); + BOOL processReplyCommand(const LLUUID& uuid, const RlvCommand& rlvCmd) const; + BOOL processForceCommand(const LLUUID& uuid, const RlvCommand& rlvCmd) const; + + // Command handlers (exist for no other reason than to keep the length of the processXXX functions down) + void onForceDetach(const LLUUID& idObj, const std::string& strOption) const; + void onForceRemOutfit(const LLUUID& idObj, const std::string& strOption) const; + bool onForceSit(const LLUUID& uuid, const std::string& strOption) const; + void onForceWear(const std::string& strPath, bool fAttach, bool fMatchAll) const; + bool onGetPath(const LLUUID& uuid, const std::string& strOption, std::string& strReply) const; + void onGetInvWorn(const std::string& strPath, std::string &strReply) const; + + // -------------------------------- + + /* + * Member variables + */ +public: + static BOOL fNoSetEnv; + static BOOL fLegacyNaming; + + static const std::string cstrSharedRoot; // Name of the shared root folder + static const std::string cstrBlockedRecvIM; // Stand-in text for incoming IM when recvim restricted + static const std::string cstrBlockedSendIM; // Stand-in text for outgoing IM when sendim restricted + static const std::string cstrHidden; // General purpose "this was censored" text + static const std::string cstrHiddenParcel; + static const std::string cstrHiddenRegion; + static const std::string cstrMsgRecvIM; // Message sent to IM sender when sendim restricted + static const std::string cstrMsgTpLure; // Message sent to tplure sender when tplure restricted + static const std::string cstrAnonyms[28]; +protected: + rlv_object_map_t m_Objects; // Map of objects that have active restrictions (by UUID) + rlv_exception_map_t m_Exceptions; // Map of UUIDs that are exempt from the associated ERlvBehaviour + rlv_detach_map_t m_Attachments; // Map of locked attachments (attachment point index -> object that issued @detach=n) + S16 m_LayersAdd[WT_COUNT]; // Array of locked layers (reference counted) + S16 m_LayersRem[WT_COUNT]; // Array of locked layers (reference counted) + S16 m_Behaviours[RLV_BHVR_COUNT]; + + rlv_retained_list_t m_Retained; + rlv_reattach_map_t m_AttachPending; + rlv_reattach_map_t m_DetachPending; + rlv_redir_map_t m_Redirections; + RlvGCTimer* m_pGCTimer; + RlvWLSnapshot* m_pWLSnapshot; + + RlvCommand* m_pCurCommand; // Convenience (see @tpto) + LLUUID m_idCurObject; // Convenience (see @tpto) + + mutable RlvEventEmitter m_Emitter; + mutable std::list m_BhvrObservers; + RlvBehaviourNotifyObserver* m_pBhvrNotify; + + static BOOL m_fEnabled; // Use setEnabled() to toggle this + static BOOL m_fFetchStarted; // TRUE if we fired off an inventory fetch + static BOOL m_fFetchComplete; // TRUE if everything was fetched + static RlvMultiStringSearch m_AttachLookup; // Lookup table for attachment names (lower case) + + bool m_fCanCancelTp; + + friend class RlvSharedRootFetcher; // Fetcher needs access to m_fFetchComplete + friend class RlvGCTimer; // Timer clear its own point at destruction + + // -------------------------------- + + /* + * Internal access functions used by unit tests + */ +public: + const rlv_object_map_t* getObjectMap() const { return &m_Objects; } + const rlv_exception_map_t* getExceptionMap() const { return &m_Exceptions; } + const rlv_detach_map_t* getDetachMap() const { return &m_Attachments; } + #ifdef RLV_DEBUG_TESTS + const S16* getAddLayers() const { return m_LayersAdd; } + const S16* getRemLayers() const { return m_LayersRem; } + const S16* getBehaviours() const { return m_Behaviours; } + const rlv_retained_list_t* getRetainedList() const { return &m_Retained; } + #endif // RLV_DEBUG_TESTS +}; + +typedef RlvHandler rlv_handler_t; +extern rlv_handler_t gRlvHandler; + +// ============================================================================ +// Inlined member functions +// + +// Checked: 2009-07-09 (RLVa-1.0.0f) +inline void RlvHandler::addException(ERlvBehaviour eBehaviour, const LLUUID& uuid) +{ + if (!uuid.isNull()) + m_Exceptions.insert(std::pair(uuid, eBehaviour)); +} + +// Checked: 2009-07-09 (RLVa-1.0.0f) | Modified: RLVa-1.0.0f +inline bool RlvHandler::canShowHoverText(LLViewerObject *pObj) const +{ + return ( (!pObj) || (LL_PCODE_VOLUME != pObj->getPCode()) || + !( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTALL)) || + ( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTWORLD)) && (!pObj->isHUDAttachment()) ) || + ( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTHUD)) && (pObj->isHUDAttachment()) ) || + (isException(RLV_BHVR_SHOWHOVERTEXT, pObj->getID())) ) ); +} + +// Checked: 2009-05-23 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d +inline S32 RlvHandler::getAttachPointIndex(std::string strText, bool fExact) const +{ + U16 nParam; RlvMultiStringSearchMatch match; + LLStringUtil::toLower(strText); + return (fExact) ? ((m_AttachLookup.getExactMatchParam(strText, nParam)) ? nParam : 0) + : ((m_AttachLookup.findLast(strText, match)) ? match.nParam : 0); +} + +// Checked: 2009-05-23 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d +inline S32 RlvHandler::getAttachPointIndex(LLViewerObject* pObj) const +{ + return (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0; +} + +// Checked: 2009-06-02 (RLVa-0.2.0g) +inline std::string RlvHandler::getSharedPath(const LLUUID& idFolder) const +{ + return getSharedPath(gInventory.getCategory(idFolder)); // getSharedPath() has a NULL pointer check so this is safe +} + +// Checked: 2009-06-07 (RLVa-0.2.1c) +inline std::string RlvHandler::getVersionString() const +{ + return llformat("RestrainedLife viewer v%d.%d.%d (%s %d.%d.%d.%d - RLVa %d.%d.%d)", + RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, + LLAppViewer::instance()->getSecondLifeTitle().c_str(), LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VERSION_BUILD, + RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH); +} + +// Checked: 2009-05-23 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d +inline bool RlvHandler::hasAttachPointName(const LLInventoryItem *pItem, bool fStrict) const +{ + return (getAttachPoint(pItem, fStrict) != NULL); // getAttachPoint() has a NULL pointer check so this is safe +} + +// Checked: +inline bool RlvHandler::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption) const +{ + return hasBehaviourExcept(eBehaviour, strOption, LLUUID::null); +} + +// Checked: +inline bool RlvHandler::hasBehaviour(const std::string& strBehaviour) const +{ + return hasBehaviourExcept(strBehaviour, LLUUID::null); +} + +// Checked: +inline bool RlvHandler::hasBehaviour(const std::string& strBehaviour, const std::string& strOption) const +{ + return hasBehaviourExcept(strBehaviour, strOption, LLUUID::null); +} + +// Checked: +inline bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBehaviour, const LLUUID& idObj) const +{ + return hasBehaviourExcept(eBehaviour, std::string(), idObj); +} + +#ifdef RLV_EXPERIMENTAL_COMPOSITES + // Checked: + inline bool RlvHandler::isCompositeFolder(const LLInventoryCategory* pFolder) const + { + return getCompositeInfo(pFolder, NULL); + } + + // Checked: + inline bool RlvHandler::isCompositeDescendent(const LLUUID& idItem) const + { + return getCompositeInfo(idItem, NULL, NULL); + } +#endif // RLV_EXPERIMENTAL_COMPOSITES + +// Checked: 2009-05-23 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d +inline bool RlvHandler::isDetachable(LLViewerObject* pObj) const +{ + return (pObj == NULL) || (!pObj->isAttachment()) || (isDetachable(getAttachPointIndex(pObj))); +} + +// Checked: +inline bool RlvHandler::isException(ERlvBehaviour eBehaviour, const LLUUID& uuid) const +{ + for (rlv_exception_map_t::const_iterator itException = m_Exceptions.lower_bound(uuid), + endException = m_Exceptions.upper_bound(uuid); itException != endException; ++itException) + { + if (itException->second == eBehaviour) + return true; + } + return false; +} + +// Checked: +inline bool RlvHandler::isException(const std::string& strBehaviour, const LLUUID& uuid) const +{ + return hasBehaviour(strBehaviour, uuid.asString()); +} + +// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b +inline bool RlvHandler::isFoldedFolder(const LLInventoryCategory* pFolder, bool fAttach) const +{ + return + ( + // .() type folder (on detach we don't care about its children, but on attach there can only be 1 attachment) + ( (gRlvHandler.getAttachPoint(pFolder, true)) && + ( (!fAttach) || (1 == rlvGetDirectDescendentsCount(pFolder, LLAssetType::AT_OBJECT))) ) + #ifdef RLV_EXTENSION_FLAG_NOSTRIP + // .(nostrip) folder + || ( (pFolder) && (".("RLV_FOLDER_FLAG_NOSTRIP")" == pFolder->getName()) ) + #endif // RLV_EXTENSION_FLAG_NOSTRIP + ); +} + +// Checked: 2009-05-23 (RLVa-0.2.0d) | Added: RLVa-0.2.0d +inline bool RlvHandler::isRemovableExcept(EWearableType type, const LLUUID& idObj) const +{ + // NOTE: mind the bitwise OR rather than the logical OR!! + return (isRemovable(type)) || !( (hasBehaviourExcept(RLV_BHVR_REMOUTFIT, idObj)) | + (hasBehaviourExcept(RLV_BHVR_REMOUTFIT, LLWearable::typeToTypeName(type), idObj)) ); +} + +#ifndef RLV_EXTENSION_FLAG_NOSTRIP + // Checked: 2009-05-23 (RLVa-0.2.0d) | Added: RLVa-0.2.0d + bool RlvHandler::isStrippable(const LLUUID& idItem) const + { + return true; + } +#endif // RLV_EXTENSION_FLAG_NOSTRIP + +// Checked: 2009-07-09 (RLVa-1.0.0f) +inline void RlvHandler::removeException(ERlvBehaviour eBehaviour, const LLUUID &uuid) +{ + if (!uuid.isNull()) + { + for (rlv_exception_map_t::iterator itException = m_Exceptions.lower_bound(uuid), + endException = m_Exceptions.upper_bound(uuid); itException != endException; ++itException) + { + if (itException->second == eBehaviour) + { + m_Exceptions.erase(itException); + break; + } + } + } +} + +// Checked: 2009-08-05 (RLVa-1.0.1e) | Modified: RLVa-1.0.1e +inline void RlvHandler::retainCommand(const std::string& strObj, const LLUUID& idObj, const std::string& strCmd) +{ + #ifdef RLV_DEBUG + RLV_INFOS << "[" << idObj << "]: " << strCmd << " (retaining)" << LL_ENDL; + #endif // RLV_DEBUG + m_Retained.push_back(RlvRetainedCommand(strObj, idObj, strCmd)); +} + +// Checked: 2009-05-23 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d +inline bool RlvHandler::setDetachable(LLViewerObject* pObj, const LLUUID& idRlvObj, bool fDetachable) +{ + return setDetachable(getAttachPointIndex(pObj), idRlvObj, fDetachable); // getAttachPointIndex() has a NULL pointer check +} + +// ============================================================================ + +#endif // RLV_HANDLER_H -- cgit v1.1