summaryrefslogtreecommitdiff
path: root/indra/llinventory
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llinventory')
-rw-r--r--indra/llinventory/llcategory.cpp161
-rw-r--r--indra/llinventory/llcategory.h80
-rw-r--r--indra/llinventory/lleconomy.cpp227
-rw-r--r--indra/llinventory/lleconomy.h116
-rw-r--r--indra/llinventory/llinventory.cpp1773
-rw-r--r--indra/llinventory/llinventory.h411
-rw-r--r--indra/llinventory/llnotecard.cpp286
-rw-r--r--indra/llinventory/llnotecard.h41
-rw-r--r--indra/llinventory/llparcel.cpp1813
-rw-r--r--indra/llinventory/llparcel.h576
-rw-r--r--indra/llinventory/llparcelflags.h105
-rw-r--r--indra/llinventory/llpermissions.cpp1171
-rw-r--r--indra/llinventory/llpermissions.h426
-rw-r--r--indra/llinventory/llpermissionsflags.h78
-rw-r--r--indra/llinventory/llsaleinfo.cpp356
-rw-r--r--indra/llinventory/llsaleinfo.h110
-rw-r--r--indra/llinventory/lltransactionflags.cpp43
-rw-r--r--indra/llinventory/lltransactionflags.h27
-rw-r--r--indra/llinventory/lltransactiontypes.h93
-rw-r--r--indra/llinventory/lluserrelations.cpp89
-rw-r--r--indra/llinventory/lluserrelations.h154
21 files changed, 8136 insertions, 0 deletions
diff --git a/indra/llinventory/llcategory.cpp b/indra/llinventory/llcategory.cpp
new file mode 100644
index 0000000000..7a7bbf530a
--- /dev/null
+++ b/indra/llinventory/llcategory.cpp
@@ -0,0 +1,161 @@
+/**
+ * @file llcategory.cpp
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llcategory.h"
+
+#include "message.h"
+
+const LLCategory LLCategory::none;
+
+///----------------------------------------------------------------------------
+/// Local function declarations, constants, enums, and typedefs
+///----------------------------------------------------------------------------
+
+// This is the storage of the category names. It's loosely based on a
+// heap-like structure with indices into it for faster searching and
+// so that we don't have to maintain a balanced heap. It's *VITALLY*
+// important that the CATEGORY_INDEX and CATEGORY_NAME tables are kept
+// in synch.
+
+// CATEGORY_INDEX indexes into CATEGORY_NAME at the first occurance of
+// a child. Thus, the first child of root is "Object" which is located
+// in CATEGORY_NAME[1].
+const S32 CATEGORY_INDEX[] =
+{
+ 1, // ROOT
+ 6, // object
+ 7, // clothing
+ 7, // texture
+ 7, // sound
+ 7, // landmark
+ 7, // object|component
+ 7, // off the end (required for child count calculations)
+};
+
+// The heap of names
+const char* CATEGORY_NAME[] =
+{
+ "(none)",
+ "Object", // (none)
+ "Clothing",
+ "Texture",
+ "Sound",
+ "Landmark",
+ "Component", // object
+ NULL
+};
+
+///----------------------------------------------------------------------------
+/// Class llcategory
+///----------------------------------------------------------------------------
+
+LLCategory::LLCategory()
+{
+ // this is used as a simple compile time assertion. If this code
+ // fails to compile, the depth has been changed, and we need to
+ // clean up some of the code that relies on the depth, such as the
+ // default constructor. If CATEGORY_DEPTH != 4, this code will
+ // attempt to construct a zero length array - which the compiler
+ // should balk at.
+// static const char CATEGORY_DEPTH_CHECK[(CATEGORY_DEPTH == 4)?1:0] = {' '}; // unused
+
+ // actually initialize the object.
+ mData[0] = 0;
+ mData[1] = 0;
+ mData[2] = 0;
+ mData[3] = 0;
+}
+
+void LLCategory::init(U32 value)
+{
+ U8 v;
+ for(S32 i = 0; i < CATEGORY_DEPTH; i++)
+ {
+ v = (U8)((0x000000ff) & value);
+ mData[CATEGORY_DEPTH - 1 - i] = v;
+ value >>= 8;
+ }
+}
+
+U32 LLCategory::getU32() const
+{
+ U32 rv = 0;
+ rv |= mData[0];
+ rv <<= 8;
+ rv |= mData[1];
+ rv <<= 8;
+ rv |= mData[2];
+ rv <<= 8;
+ rv |= mData[3];
+ return rv;
+}
+
+S32 LLCategory::getSubCategoryCount() const
+{
+ S32 rv = CATEGORY_INDEX[mData[0] + 1] - CATEGORY_INDEX[mData[0]];
+ return rv;
+}
+
+// This method will return a category that is the nth subcategory. If
+// you're already at the bottom of the hierarchy, then the method will
+// return a copy of this.
+LLCategory LLCategory::getSubCategory(U8 n) const
+{
+ LLCategory rv(*this);
+ for(S32 i = 0; i < (CATEGORY_DEPTH - 1); i++)
+ {
+ if(rv.mData[i] == 0)
+ {
+ rv.mData[i] = n + 1;
+ break;
+ }
+ }
+ return rv;
+}
+
+// This method will return the name of the leaf category type
+const char* LLCategory::lookupName() const
+{
+ S32 i = 0;
+ S32 index = mData[i++];
+ while((i < CATEGORY_DEPTH) && (mData[i] != 0))
+ {
+ index = CATEGORY_INDEX[index];
+ ++i;
+ }
+ return CATEGORY_NAME[index];
+}
+
+// message serialization
+void LLCategory::packMessage(LLMessageSystem* msg) const
+{
+ U32 data = getU32();
+ msg->addU32Fast(_PREHASH_Category, data);
+}
+
+// message serialization
+void LLCategory::unpackMessage(LLMessageSystem* msg, const char* block)
+{
+ U32 data;
+ msg->getU32Fast(block, _PREHASH_Category, data);
+ init(data);
+}
+
+// message serialization
+void LLCategory::unpackMultiMessage(LLMessageSystem* msg, const char* block,
+ S32 block_num)
+{
+ U32 data;
+ msg->getU32Fast(block, _PREHASH_Category, data, block_num);
+ init(data);
+}
+
+///----------------------------------------------------------------------------
+/// Local function definitions
+///----------------------------------------------------------------------------
diff --git a/indra/llinventory/llcategory.h b/indra/llinventory/llcategory.h
new file mode 100644
index 0000000000..a28b707d93
--- /dev/null
+++ b/indra/llinventory/llcategory.h
@@ -0,0 +1,80 @@
+/**
+ * @file llcategory.h
+ * @brief LLCategory class header file.
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLCATEGORY_H
+#define LL_LLCATEGORY_H
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLCategory
+//
+// An instance of the LLCategory class represents a particular
+// category in a hierarchical classification system. For now, it is 4
+// levels deep with 255 (minus 1) possible values at each level. If a
+// non zero value is found at level 4, that is the leaf category,
+// otherwise, it is the first level that has a 0 in the next depth
+// level.
+//
+// To output the names of all top level categories, you could do the
+// following:
+//
+// S32 count = LLCategory::none.getSubCategoryCount();
+// for(S32 i = 0; i < count; i++)
+// {
+// llinfos << none.getSubCategory(i).lookupNmae() << llendl;
+// }
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLMessageSystem;
+
+class LLCategory
+{
+public:
+ // Nice default static const.
+ static const LLCategory none;
+
+ // construction. Since this is really a POD type, destruction,
+ // copy, and assignment are handled by the compiler.
+ LLCategory();
+ explicit LLCategory(U32 value) { init(value); }
+
+ // methods
+ void init(U32 value);
+ U32 getU32() const;
+ S32 getSubCategoryCount() const;
+
+ // This method will return a category that is the nth
+ // subcategory. If you're already at the bottom of the hierarchy,
+ // then the method will return a copy of this.
+ LLCategory getSubCategory(U8 n) const;
+
+ // This method will return the name of the leaf category type
+ const char* lookupName() const;
+
+ // This method will return the full hierarchy name in an easily
+ // interpreted (TOP)|(SUB1)|(SUB2) format. *NOTE: not implemented
+ // because we don't have anything but top level categories at the
+ // moment.
+ //const char* lookupFullName() const;
+
+ // message serialization
+ void packMessage(LLMessageSystem* msg) const;
+ void unpackMessage(LLMessageSystem* msg, const char* block);
+ void unpackMultiMessage(LLMessageSystem* msg, const char* block,
+ S32 block_num);
+protected:
+ enum
+ {
+ CATEGORY_TOP = 0,
+ CATEGORY_DEPTH = 4,
+ };
+
+ U8 mData[CATEGORY_DEPTH];
+};
+
+
+#endif // LL_LLCATEGORY_H
diff --git a/indra/llinventory/lleconomy.cpp b/indra/llinventory/lleconomy.cpp
new file mode 100644
index 0000000000..378ab8ced1
--- /dev/null
+++ b/indra/llinventory/lleconomy.cpp
@@ -0,0 +1,227 @@
+/**
+ * @file lleconomy.cpp
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "lleconomy.h"
+#include "llerror.h"
+#include "message.h"
+#include "v3math.h"
+
+LLGlobalEconomy::LLGlobalEconomy()
+: mObjectCount( -1 ),
+ mObjectCapacity( -1 ),
+ mPriceObjectClaim( -1 ),
+ mPricePublicObjectDecay( -1 ),
+ mPricePublicObjectDelete( -1 ),
+ mPriceEnergyUnit( -1 ),
+ mPriceUpload( -1 ),
+ mPriceRentLight( -1 ),
+ mTeleportMinPrice( -1 ),
+ mTeleportPriceExponent( -1 ),
+ mPriceGroupCreate( -1 )
+{ }
+
+LLGlobalEconomy::~LLGlobalEconomy()
+{ }
+
+// static
+void LLGlobalEconomy::processEconomyData(LLMessageSystem *msg, void** user_data)
+{
+ S32 i;
+ F32 f;
+
+ LLGlobalEconomy *this_ptr = (LLGlobalEconomy*)user_data;
+
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_ObjectCapacity, i);
+ this_ptr->setObjectCapacity(i);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_ObjectCount, i);
+ this_ptr->setObjectCount(i);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceEnergyUnit, i);
+ this_ptr->setPriceEnergyUnit(i);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceObjectClaim, i);
+ this_ptr->setPriceObjectClaim(i);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_PricePublicObjectDecay, i);
+ this_ptr->setPricePublicObjectDecay(i);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_PricePublicObjectDelete, i);
+ this_ptr->setPricePublicObjectDelete(i);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceUpload, i);
+ this_ptr->setPriceUpload(i);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceRentLight, i);
+ this_ptr->setPriceRentLight(i);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_TeleportMinPrice, i);
+ this_ptr->setTeleportMinPrice(i);
+ msg->getF32Fast(_PREHASH_Info, _PREHASH_TeleportPriceExponent, f);
+ this_ptr->setTeleportPriceExponent(f);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceGroupCreate, i);
+ this_ptr->setPriceGroupCreate(i);
+}
+
+S32 LLGlobalEconomy::calculateTeleportCost(F32 distance) const
+{
+ S32 min_cost = getTeleportMinPrice();
+ F32 exponent = getTeleportPriceExponent();
+ F32 divisor = 100.f * pow(3.f, exponent);
+ S32 cost = (U32)(distance * pow(log10(distance), exponent) / divisor);
+ if (cost < 0)
+ {
+ cost = 0;
+ }
+ else if (cost < min_cost)
+ {
+ cost = min_cost;
+ }
+
+ return cost;
+}
+
+S32 LLGlobalEconomy::calculateLightRent(const LLVector3& object_size) const
+{
+ F32 intensity_mod = llmax(object_size.magVec(), 1.f);
+ return (S32)(intensity_mod * getPriceRentLight());
+}
+
+void LLGlobalEconomy::print()
+{
+ llinfos << "Global Economy Settings: " << llendl;
+ llinfos << "Object Capacity: " << mObjectCapacity << llendl;
+ llinfos << "Object Count: " << mObjectCount << llendl;
+ llinfos << "Claim Price Per Object: " << mPriceObjectClaim << llendl;
+ llinfos << "Claim Price Per Public Object: " << mPricePublicObjectDecay << llendl;
+ llinfos << "Delete Price Per Public Object: " << mPricePublicObjectDelete << llendl;
+ llinfos << "Release Price Per Public Object: " << getPricePublicObjectRelease() << llendl;
+ llinfos << "Price Per Energy Unit: " << mPriceEnergyUnit << llendl;
+ llinfos << "Price Per Upload: " << mPriceUpload << llendl;
+ llinfos << "Light Base Price: " << mPriceRentLight << llendl;
+ llinfos << "Teleport Min Price: " << mTeleportMinPrice << llendl;
+ llinfos << "Teleport Price Exponent: " << mTeleportPriceExponent << llendl;
+ llinfos << "Price for group creation: " << mPriceGroupCreate << llendl;
+}
+
+LLRegionEconomy::LLRegionEconomy()
+: LLGlobalEconomy(),
+ mPriceObjectRent( -1.f ),
+ mPriceObjectScaleFactor( -1.f ),
+ mEnergyEfficiency( -1.f ),
+ mBasePriceParcelClaimDefault(-1),
+ mBasePriceParcelClaimActual(-1),
+ mPriceParcelClaimFactor(-1.f),
+ mBasePriceParcelRent(-1),
+ mAreaOwned(-1.f),
+ mAreaTotal(-1.f)
+{ }
+
+LLRegionEconomy::~LLRegionEconomy()
+{ }
+
+BOOL LLRegionEconomy::hasData() const
+{
+ return (mBasePriceParcelRent != -1);
+}
+
+// static
+void LLRegionEconomy::processEconomyData(LLMessageSystem *msg, void** user_data)
+{
+ S32 i;
+ F32 f;
+
+ LLGlobalEconomy::processEconomyData(msg, user_data);
+
+ LLRegionEconomy *this_ptr = (LLRegionEconomy*)user_data;
+
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceParcelClaim, i);
+ this_ptr->setBasePriceParcelClaimDefault(i);
+ msg->getF32(_PREHASH_Info, _PREHASH_PriceParcelClaimFactor, f);
+ this_ptr->setPriceParcelClaimFactor(f);
+ msg->getF32Fast(_PREHASH_Info, _PREHASH_EnergyEfficiency, f);
+ this_ptr->setEnergyEfficiency(f);
+ msg->getF32Fast(_PREHASH_Info, _PREHASH_PriceObjectRent, f);
+ this_ptr->setPriceObjectRent(f);
+ msg->getF32Fast(_PREHASH_Info, _PREHASH_PriceObjectScaleFactor, f);
+ this_ptr->setPriceObjectScaleFactor(f);
+ msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceParcelRent, i);
+ this_ptr->setBasePriceParcelRent(i);
+}
+
+// static
+void LLRegionEconomy::processEconomyDataRequest(LLMessageSystem *msg, void **user_data)
+{
+ LLRegionEconomy *this_ptr = (LLRegionEconomy*)user_data;
+
+ msg->newMessageFast(_PREHASH_EconomyData);
+ msg->nextBlockFast(_PREHASH_Info);
+ msg->addS32Fast(_PREHASH_ObjectCapacity, this_ptr->getObjectCapacity());
+ msg->addS32Fast(_PREHASH_ObjectCount, this_ptr->getObjectCount());
+ msg->addS32Fast(_PREHASH_PriceEnergyUnit, this_ptr->getPriceEnergyUnit());
+ msg->addS32Fast(_PREHASH_PriceObjectClaim, this_ptr->getPriceObjectClaim());
+ msg->addS32Fast(_PREHASH_PricePublicObjectDecay, this_ptr->getPricePublicObjectDecay());
+ msg->addS32Fast(_PREHASH_PricePublicObjectDelete, this_ptr->getPricePublicObjectDelete());
+ msg->addS32Fast(_PREHASH_PriceParcelClaim, this_ptr->mBasePriceParcelClaimActual);
+ msg->addF32Fast(_PREHASH_PriceParcelClaimFactor, this_ptr->mPriceParcelClaimFactor);
+ msg->addS32Fast(_PREHASH_PriceUpload, this_ptr->getPriceUpload());
+ msg->addS32Fast(_PREHASH_PriceRentLight, this_ptr->getPriceRentLight());
+ msg->addS32Fast(_PREHASH_TeleportMinPrice, this_ptr->getTeleportMinPrice());
+ msg->addF32Fast(_PREHASH_TeleportPriceExponent, this_ptr->getTeleportPriceExponent());
+
+ msg->addF32Fast(_PREHASH_EnergyEfficiency, this_ptr->getEnergyEfficiency());
+ msg->addF32Fast(_PREHASH_PriceObjectRent, this_ptr->getPriceObjectRent());
+ msg->addF32Fast(_PREHASH_PriceObjectScaleFactor, this_ptr->getPriceObjectScaleFactor());
+ msg->addS32Fast(_PREHASH_PriceParcelRent, this_ptr->getPriceParcelRent());
+ msg->addS32Fast(_PREHASH_PriceGroupCreate, this_ptr->getPriceGroupCreate());
+
+ msg->sendReliable(msg->getSender());
+}
+
+
+S32 LLRegionEconomy::getPriceParcelClaim() const
+{
+ //return (S32)((F32)mBasePriceParcelClaim * (mAreaTotal / (mAreaTotal - mAreaOwned)));
+ return (S32)((F32)mBasePriceParcelClaimActual * mPriceParcelClaimFactor);
+}
+
+S32 LLRegionEconomy::getPriceParcelRent() const
+{
+ return mBasePriceParcelRent;
+}
+
+
+void LLRegionEconomy::print()
+{
+ this->LLGlobalEconomy::print();
+
+ llinfos << "Region Economy Settings: " << llendl;
+ llinfos << "Land (square meters): " << mAreaTotal << llendl;
+ llinfos << "Owned Land (square meters): " << mAreaOwned << llendl;
+ llinfos << "Daily Object Rent: " << mPriceObjectRent << llendl;
+ llinfos << "Daily Land Rent (per meter): " << getPriceParcelRent() << llendl;
+ llinfos << "Energey Efficiency: " << mEnergyEfficiency << llendl;
+}
+
+
+void LLRegionEconomy::setBasePriceParcelClaimDefault(S32 val)
+{
+ mBasePriceParcelClaimDefault = val;
+ if(mBasePriceParcelClaimActual == -1)
+ {
+ mBasePriceParcelClaimActual = val;
+ }
+}
+
+void LLRegionEconomy::setBasePriceParcelClaimActual(S32 val)
+{
+ mBasePriceParcelClaimActual = val;
+}
+
+void LLRegionEconomy::setPriceParcelClaimFactor(F32 val)
+{
+ mPriceParcelClaimFactor = val;
+}
+
+void LLRegionEconomy::setBasePriceParcelRent(S32 val)
+{
+ mBasePriceParcelRent = val;
+}
diff --git a/indra/llinventory/lleconomy.h b/indra/llinventory/lleconomy.h
new file mode 100644
index 0000000000..c71fc9e6d0
--- /dev/null
+++ b/indra/llinventory/lleconomy.h
@@ -0,0 +1,116 @@
+/**
+ * @file lleconomy.h
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLECONOMY_H
+#define LL_LLECONOMY_H
+
+class LLMessageSystem;
+class LLVector3;
+
+class LLGlobalEconomy
+{
+public:
+ LLGlobalEconomy();
+ virtual ~LLGlobalEconomy();
+
+ virtual void print();
+
+ static void processEconomyData(LLMessageSystem *msg, void **user_data);
+
+ S32 calculateTeleportCost(F32 distance) const;
+ S32 calculateLightRent(const LLVector3& object_size) const;
+
+ S32 getObjectCount() const { return mObjectCount; }
+ S32 getObjectCapacity() const { return mObjectCapacity; }
+ S32 getPriceObjectClaim() const { return mPriceObjectClaim; }
+ S32 getPricePublicObjectDecay() const { return mPricePublicObjectDecay; }
+ S32 getPricePublicObjectDelete() const { return mPricePublicObjectDelete; }
+ S32 getPricePublicObjectRelease() const { return mPriceObjectClaim - mPricePublicObjectDelete; }
+ S32 getPriceEnergyUnit() const { return mPriceEnergyUnit; }
+ S32 getPriceUpload() const { return mPriceUpload; }
+ S32 getPriceRentLight() const { return mPriceRentLight; }
+ S32 getTeleportMinPrice() const { return mTeleportMinPrice; }
+ F32 getTeleportPriceExponent() const { return mTeleportPriceExponent; }
+ S32 getPriceGroupCreate() const { return mPriceGroupCreate; }
+
+
+ void setObjectCount(S32 val) { mObjectCount = val; }
+ void setObjectCapacity(S32 val) { mObjectCapacity = val; }
+ void setPriceObjectClaim(S32 val) { mPriceObjectClaim = val; }
+ void setPricePublicObjectDecay(S32 val) { mPricePublicObjectDecay = val; }
+ void setPricePublicObjectDelete(S32 val) { mPricePublicObjectDelete = val; }
+ void setPriceEnergyUnit(S32 val) { mPriceEnergyUnit = val; }
+ void setPriceUpload(S32 val) { mPriceUpload = val; }
+ void setPriceRentLight(S32 val) { mPriceRentLight = val; }
+ void setTeleportMinPrice(S32 val) { mTeleportMinPrice = val; }
+ void setTeleportPriceExponent(F32 val) { mTeleportPriceExponent = val; }
+ void setPriceGroupCreate(S32 val) { mPriceGroupCreate = val; }
+
+private:
+ S32 mObjectCount;
+ S32 mObjectCapacity;
+ S32 mPriceObjectClaim; // per primitive
+ S32 mPricePublicObjectDecay; // per primitive
+ S32 mPricePublicObjectDelete; // per primitive
+ S32 mPriceEnergyUnit;
+ S32 mPriceUpload;
+ S32 mPriceRentLight;
+ S32 mTeleportMinPrice;
+ F32 mTeleportPriceExponent;
+ S32 mPriceGroupCreate;
+};
+
+
+class LLRegionEconomy : public LLGlobalEconomy
+{
+public:
+ LLRegionEconomy();
+ ~LLRegionEconomy();
+
+ static void processEconomyData(LLMessageSystem *msg, void **user_data);
+ static void processEconomyDataRequest(LLMessageSystem *msg, void **user_data);
+
+ void print();
+
+ BOOL hasData() const;
+ F32 getPriceObjectRent() const { return mPriceObjectRent; }
+ F32 getPriceObjectScaleFactor() const {return mPriceObjectScaleFactor;}
+ F32 getEnergyEfficiency() const { return mEnergyEfficiency; }
+ S32 getPriceParcelClaim() const;
+ S32 getPriceParcelRent() const;
+ F32 getAreaOwned() const { return mAreaOwned; }
+ F32 getAreaTotal() const { return mAreaTotal; }
+ S32 getBasePriceParcelClaimActual() const { return mBasePriceParcelClaimActual; }
+
+ void setPriceObjectRent(F32 val) { mPriceObjectRent = val; }
+ void setPriceObjectScaleFactor(F32 val) { mPriceObjectScaleFactor = val; }
+ void setEnergyEfficiency(F32 val) { mEnergyEfficiency = val; }
+
+ void setBasePriceParcelClaimDefault(S32 val);
+ void setBasePriceParcelClaimActual(S32 val);
+ void setPriceParcelClaimFactor(F32 val);
+ void setBasePriceParcelRent(S32 val);
+
+ void setAreaOwned(F32 val) { mAreaOwned = val; }
+ void setAreaTotal(F32 val) { mAreaTotal = val; }
+
+private:
+ F32 mPriceObjectRent;
+ F32 mPriceObjectScaleFactor;
+ F32 mEnergyEfficiency;
+
+ S32 mBasePriceParcelClaimDefault;
+ S32 mBasePriceParcelClaimActual;
+ F32 mPriceParcelClaimFactor;
+ S32 mBasePriceParcelRent;
+
+ F32 mAreaOwned;
+ F32 mAreaTotal;
+
+};
+
+#endif
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
new file mode 100644
index 0000000000..bffc4df281
--- /dev/null
+++ b/indra/llinventory/llinventory.cpp
@@ -0,0 +1,1773 @@
+/**
+ * @file llinventory.cpp
+ * @brief Implementation of the inventory system.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include <time.h>
+
+#include "llinventory.h"
+
+#include "lldbstrings.h"
+#include "llcrypto.h"
+#include "llsd.h"
+#include "message.h"
+#include <boost/tokenizer.hpp>
+
+#include "llsdutil.h"
+
+#include "llsdutil.h"
+
+///----------------------------------------------------------------------------
+/// Local function declarations, constants, enums, and typedefs
+///----------------------------------------------------------------------------
+
+const U8 TASK_INVENTORY_ITEM_KEY = 0;
+const U8 TASK_INVENTORY_ASSET_KEY = 1;
+
+const LLUUID MAGIC_ID("3c115e51-04f4-523c-9fa6-98aff1034730");
+
+// helper function which returns true if inventory type and asset type
+// are potentially compatible. For example, an attachment must be an
+// object, but a wearable can be a bodypart or clothing asset.
+bool inventory_and_asset_types_match(
+ LLInventoryType::EType inventory_type,
+ LLAssetType::EType asset_type);
+
+
+///----------------------------------------------------------------------------
+/// Class LLInventoryType
+///----------------------------------------------------------------------------
+
+// Unlike asset type names, not limited to 8 characters.
+// Need not match asset type names.
+static const char* INVENTORY_TYPE_NAMES[LLInventoryType::IT_COUNT] =
+{
+ "texture", // 0
+ "sound",
+ "callcard",
+ "landmark",
+ NULL,
+ NULL, // 5
+ "object",
+ "notecard",
+ "category",
+ "root",
+ "script", // 10
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "snapshot", // 15
+ NULL,
+ "attach",
+ "wearable",
+ "animation",
+ "gesture", // 20
+};
+
+// This table is meant for decoding to human readable form. Put any
+// and as many printable characters you want in each one.
+// See also LLAssetType::mAssetTypeHumanNames
+static const char* INVENTORY_TYPE_HUMAN_NAMES[LLInventoryType::IT_COUNT] =
+{
+ "texture", // 0
+ "sound",
+ "calling card",
+ "landmark",
+ NULL,
+ NULL, // 5
+ "object",
+ "note card",
+ "folder",
+ "root",
+ "script", // 10
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "snapshot", // 15
+ NULL,
+ "attachment",
+ "wearable",
+ "animation",
+ "gesture", // 20
+};
+
+// Maps asset types to the default inventory type for that kind of asset.
+// Thus, "Lost and Found" is a "Category"
+static const LLInventoryType::EType
+DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
+{
+ LLInventoryType::IT_TEXTURE, // AT_TEXTURE
+ LLInventoryType::IT_SOUND, // AT_SOUND
+ LLInventoryType::IT_CALLINGCARD, // AT_CALLINGCARD
+ LLInventoryType::IT_LANDMARK, // AT_LANDMARK
+ LLInventoryType::IT_LSL, // AT_SCRIPT
+ LLInventoryType::IT_WEARABLE, // AT_CLOTHING
+ LLInventoryType::IT_OBJECT, // AT_OBJECT
+ LLInventoryType::IT_NOTECARD, // AT_NOTECARD
+ LLInventoryType::IT_CATEGORY, // AT_CATEGORY
+ LLInventoryType::IT_ROOT_CATEGORY, // AT_ROOT_CATEGORY
+ LLInventoryType::IT_LSL, // AT_LSL_TEXT
+ LLInventoryType::IT_LSL, // AT_LSL_BYTECODE
+ LLInventoryType::IT_TEXTURE, // AT_TEXTURE_TGA
+ LLInventoryType::IT_WEARABLE, // AT_BODYPART
+ LLInventoryType::IT_CATEGORY, // AT_TRASH
+ LLInventoryType::IT_CATEGORY, // AT_SNAPSHOT_CATEGORY
+ LLInventoryType::IT_CATEGORY, // AT_LOST_AND_FOUND
+ LLInventoryType::IT_SOUND, // AT_SOUND_WAV
+ LLInventoryType::IT_NONE, // AT_IMAGE_TGA
+ LLInventoryType::IT_NONE, // AT_IMAGE_JPEG
+ LLInventoryType::IT_ANIMATION, // AT_ANIMATION
+ LLInventoryType::IT_GESTURE, // AT_GESTURE
+};
+
+static const int MAX_POSSIBLE_ASSET_TYPES = 2;
+static const LLAssetType::EType
+INVENTORY_TO_ASSET_TYPE[LLInventoryType::IT_COUNT][MAX_POSSIBLE_ASSET_TYPES] =
+{
+ { LLAssetType::AT_TEXTURE, LLAssetType::AT_NONE }, // IT_TEXTURE
+ { LLAssetType::AT_SOUND, LLAssetType::AT_NONE }, // IT_SOUND
+ { LLAssetType::AT_CALLINGCARD, LLAssetType::AT_NONE }, // IT_CALLINGCARD
+ { LLAssetType::AT_LANDMARK, LLAssetType::AT_NONE }, // IT_LANDMARK
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_OBJECT, LLAssetType::AT_NONE }, // IT_OBJECT
+ { LLAssetType::AT_NOTECARD, LLAssetType::AT_NONE }, // IT_NOTECARD
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE }, // IT_CATEGORY
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE }, // IT_ROOT_CATEGORY
+ { LLAssetType::AT_LSL_TEXT, LLAssetType::AT_LSL_BYTECODE }, // IT_LSL
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_TEXTURE, LLAssetType::AT_NONE }, // IT_SNAPSHOT
+ { LLAssetType::AT_NONE, LLAssetType::AT_NONE },
+ { LLAssetType::AT_OBJECT, LLAssetType::AT_NONE }, // IT_ATTACHMENT
+ { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART }, // IT_WEARABLE
+ { LLAssetType::AT_ANIMATION, LLAssetType::AT_NONE }, // IT_ANIMATION
+ { LLAssetType::AT_GESTURE, LLAssetType::AT_NONE }, // IT_GESTURE
+};
+
+// static
+const char* LLInventoryType::lookup(EType type)
+{
+ if((type >= 0) && (type < IT_COUNT))
+ {
+ return INVENTORY_TYPE_NAMES[S32(type)];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// static
+LLInventoryType::EType LLInventoryType::lookup(const char* name)
+{
+ for(S32 i = 0; i < IT_COUNT; ++i)
+ {
+ if((INVENTORY_TYPE_NAMES[i])
+ && (0 == strcmp(name, INVENTORY_TYPE_NAMES[i])))
+ {
+ // match
+ return (EType)i;
+ }
+ }
+ return IT_NONE;
+}
+
+// XUI:translate
+// translation from a type to a human readable form.
+// static
+const char* LLInventoryType::lookupHumanReadable(EType type)
+{
+ if((type >= 0) && (type < IT_COUNT))
+ {
+ return INVENTORY_TYPE_HUMAN_NAMES[S32(type)];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// return the default inventory for the given asset type.
+// static
+LLInventoryType::EType LLInventoryType::defaultForAssetType(LLAssetType::EType asset_type)
+{
+ if((asset_type >= 0) && (asset_type < LLAssetType::AT_COUNT))
+ {
+ return DEFAULT_ASSET_FOR_INV_TYPE[S32(asset_type)];
+ }
+ else
+ {
+ return IT_NONE;
+ }
+}
+
+///----------------------------------------------------------------------------
+/// Class LLInventoryObject
+///----------------------------------------------------------------------------
+
+LLInventoryObject::LLInventoryObject(
+ const LLUUID& uuid,
+ const LLUUID& parent_uuid,
+ LLAssetType::EType type,
+ const LLString& name) :
+ mUUID(uuid),
+ mParentUUID(parent_uuid),
+ mType(type),
+ mName(name)
+{
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ LLString::trim(mName);
+ LLString::truncate(mName, DB_INV_ITEM_NAME_STR_LEN);
+}
+
+LLInventoryObject::LLInventoryObject() :
+ mType(LLAssetType::AT_NONE)
+{
+}
+
+LLInventoryObject::~LLInventoryObject( void )
+{
+}
+
+void LLInventoryObject::copy(const LLInventoryObject* other)
+{
+ mUUID = other->mUUID;
+ mParentUUID = other->mParentUUID;
+ mType = other->mType;
+ mName = other->mName;
+}
+
+const LLUUID& LLInventoryObject::getUUID() const
+{
+ return mUUID;
+}
+
+const LLUUID& LLInventoryObject::getParentUUID() const
+{
+ return mParentUUID;
+}
+
+const LLString& LLInventoryObject::getName() const
+{
+ return mName;
+}
+
+LLAssetType::EType LLInventoryObject::getType() const
+{
+ return mType;
+}
+
+void LLInventoryObject::setUUID(const LLUUID& new_uuid)
+{
+ mUUID = new_uuid;
+}
+
+void LLInventoryObject::rename(const LLString& n)
+{
+ LLString new_name(n);
+ LLString::replaceNonstandardASCII(new_name, ' ');
+ LLString::replaceChar(new_name, '|', ' ');
+ LLString::trim(new_name);
+ LLString::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
+
+ if( new_name != mName )
+ {
+ mName = new_name;
+ }
+}
+
+void LLInventoryObject::setParent(const LLUUID& new_parent)
+{
+ mParentUUID = new_parent;
+}
+
+void LLInventoryObject::setType(LLAssetType::EType type)
+{
+ mType = type;
+}
+
+
+// virtual
+BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+ while(input_stream.good())
+ {
+ input_stream.getline(buffer, MAX_STRING);
+ sscanf(buffer, " %254s %254s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("obj_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %254s %[^|]", keyword, valuestr);
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ LLString::trim(mName);
+ LLString::truncate(mName, DB_INV_ITEM_NAME_STR_LEN);
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in LLInventoryObject::importLegacyStream() for object " << mUUID << llendl;
+ }
+ }
+ return TRUE;
+}
+
+// exportFile should be replaced with exportLegacyStream
+// not sure whether exportLegacyStream(llofstream(fp)) would work, fp may need to get icramented...
+BOOL LLInventoryObject::exportFile(FILE* fp, BOOL) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ fprintf(fp, "\tinv_object\t0\n\t{\n");
+ mUUID.toString(uuid_str);
+ fprintf(fp, "\t\tobj_id\t%s\n", uuid_str);
+ mParentUUID.toString(uuid_str);
+ fprintf(fp, "\t\tparent_id\t%s\n", uuid_str);
+ fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+ fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
+ fprintf(fp,"\t}\n");
+ return TRUE;
+}
+
+BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ output_stream << "\tinv_object\t0\n\t{\n";
+ mUUID.toString(uuid_str);
+ output_stream << "\t\tobj_id\t" << uuid_str << "\n";
+ mParentUUID.toString(uuid_str);
+ output_stream << "\t\tparent_id\t" << uuid_str << "\n";
+ output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
+ output_stream << "\t\tname\t" << mName.c_str() << "|\n";
+ output_stream << "\t}\n";
+ return TRUE;
+}
+
+
+void LLInventoryObject::removeFromServer()
+{
+ // don't do nothin'
+ llwarns << "LLInventoryObject::removeFromServer() called. Doesn't do anything." << llendl;
+}
+
+void LLInventoryObject::updateParentOnServer(BOOL) const
+{
+ // don't do nothin'
+ llwarns << "LLInventoryObject::updateParentOnServer() called. Doesn't do anything." << llendl;
+}
+
+void LLInventoryObject::updateServer(BOOL) const
+{
+ // don't do nothin'
+ llwarns << "LLInventoryObject::updateServer() called. Doesn't do anything." << llendl;
+}
+
+
+///----------------------------------------------------------------------------
+/// Class LLInventoryItem
+///----------------------------------------------------------------------------
+
+LLInventoryItem::LLInventoryItem(
+ const LLUUID& uuid,
+ const LLUUID& parent_uuid,
+ const LLPermissions& permissions,
+ const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ LLInventoryType::EType inv_type,
+ const LLString& name,
+ const LLString& desc,
+ const LLSaleInfo& sale_info,
+ U32 flags,
+ S32 creation_date_utc) :
+ LLInventoryObject(uuid, parent_uuid, type, name),
+ mPermissions(permissions),
+ mAssetUUID(asset_uuid),
+ mDescription(desc),
+ mSaleInfo(sale_info),
+ mInventoryType(inv_type),
+ mFlags(flags),
+ mCreationDate(creation_date_utc)
+{
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+ LLString::replaceChar(mDescription, '|', ' ');
+}
+
+LLInventoryItem::LLInventoryItem() :
+ LLInventoryObject(),
+ mPermissions(),
+ mAssetUUID(),
+ mDescription(),
+ mSaleInfo(),
+ mInventoryType(LLInventoryType::IT_NONE),
+ mFlags(0),
+ mCreationDate(0)
+{
+}
+
+LLInventoryItem::LLInventoryItem(const LLInventoryItem* other) :
+ LLInventoryObject()
+{
+ copy(other);
+}
+
+LLInventoryItem::~LLInventoryItem()
+{
+}
+
+// virtual
+void LLInventoryItem::copy(const LLInventoryItem* other)
+{
+ LLInventoryObject::copy(other);
+ mPermissions = other->mPermissions;
+ mAssetUUID = other->mAssetUUID;
+ mDescription = other->mDescription;
+ mSaleInfo = other->mSaleInfo;
+ mInventoryType = other->mInventoryType;
+ mFlags = other->mFlags;
+ mCreationDate = other->mCreationDate;
+}
+
+// As a constructor alternative, the clone() method works like a
+// copy constructor, but gens a new UUID.
+void LLInventoryItem::clone(LLPointer<LLInventoryItem>& newitem) const
+{
+ newitem = new LLInventoryItem;
+ newitem->copy(this);
+ newitem->mUUID.generate();
+}
+
+const LLPermissions& LLInventoryItem::getPermissions() const
+{
+ return mPermissions;
+}
+
+const LLUUID& LLInventoryItem::getCreatorUUID() const
+{
+ return mPermissions.getCreator();
+}
+
+const LLUUID& LLInventoryItem::getAssetUUID() const
+{
+ return mAssetUUID;
+}
+
+void LLInventoryItem::setAssetUUID(const LLUUID& asset_id)
+{
+ mAssetUUID = asset_id;
+}
+
+
+const LLString& LLInventoryItem::getDescription() const
+{
+ return mDescription;
+}
+
+S32 LLInventoryItem::getCreationDate() const
+{
+ return mCreationDate;
+}
+
+U32 LLInventoryItem::getCRC32() const
+{
+ // *FIX: Not a real crc - more of a checksum.
+ // *NOTE: We currently do not validate the name or description,
+ // but if they change in transit, it's no big deal.
+ U32 crc = mUUID.getCRC32();
+ //lldebugs << "1 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mParentUUID.getCRC32();
+ //lldebugs << "2 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mPermissions.getCRC32();
+ //lldebugs << "3 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mAssetUUID.getCRC32();
+ //lldebugs << "4 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mType;
+ //lldebugs << "5 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mInventoryType;
+ //lldebugs << "6 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mFlags;
+ //lldebugs << "7 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mSaleInfo.getCRC32();
+ //lldebugs << "8 crc: " << std::hex << crc << std::dec << llendl;
+ crc += mCreationDate;
+ //lldebugs << "9 crc: " << std::hex << crc << std::dec << llendl;
+ return crc;
+}
+
+
+void LLInventoryItem::setDescription(const LLString& d)
+{
+ LLString new_desc(d);
+ LLString::replaceNonstandardASCII(new_desc, ' ');
+ LLString::replaceChar(new_desc, '|', ' ');
+ if( new_desc != mDescription )
+ {
+ mDescription = new_desc;
+ }
+}
+
+void LLInventoryItem::setPermissions(const LLPermissions& perm)
+{
+ mPermissions = perm;
+}
+
+void LLInventoryItem::setInventoryType(LLInventoryType::EType inv_type)
+{
+ mInventoryType = inv_type;
+}
+
+void LLInventoryItem::setFlags(U32 flags)
+{
+ mFlags = flags;
+}
+
+void LLInventoryItem::setCreationDate(S32 creation_date_utc)
+{
+ mCreationDate = creation_date_utc;
+}
+
+
+const LLSaleInfo& LLInventoryItem::getSaleInfo() const
+{
+ return mSaleInfo;
+}
+
+void LLInventoryItem::setSaleInfo(const LLSaleInfo& sale_info)
+{
+ mSaleInfo = sale_info;
+}
+
+LLInventoryType::EType LLInventoryItem::getInventoryType() const
+{
+ return mInventoryType;
+}
+
+U32 LLInventoryItem::getFlags() const
+{
+ return mFlags;
+}
+
+// virtual
+void LLInventoryItem::packMessage(LLMessageSystem* msg) const
+{
+ msg->addUUIDFast(_PREHASH_ItemID, mUUID);
+ msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
+ mPermissions.packMessage(msg);
+ msg->addUUIDFast(_PREHASH_AssetID, mAssetUUID);
+ S8 type = static_cast<S8>(mType);
+ msg->addS8Fast(_PREHASH_Type, type);
+ type = static_cast<S8>(mInventoryType);
+ msg->addS8Fast(_PREHASH_InvType, type);
+ msg->addU32Fast(_PREHASH_Flags, mFlags);
+ mSaleInfo.packMessage(msg);
+ msg->addStringFast(_PREHASH_Name, mName);
+ msg->addStringFast(_PREHASH_Description, mDescription);
+ msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
+ U32 crc = getCRC32();
+ msg->addU32Fast(_PREHASH_CRC, crc);
+}
+
+// virtual
+BOOL LLInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
+{
+ msg->getUUIDFast(block, _PREHASH_ItemID, mUUID, block_num);
+ msg->getUUIDFast(block, _PREHASH_FolderID, mParentUUID, block_num);
+ mPermissions.unpackMessage(msg, block, block_num);
+ msg->getUUIDFast(block, _PREHASH_AssetID, mAssetUUID, block_num);
+
+ S8 type;
+ msg->getS8Fast(block, _PREHASH_Type, type, block_num);
+ mType = static_cast<LLAssetType::EType>(type);
+ msg->getS8(block, "InvType", type, block_num);
+ mInventoryType = static_cast<LLInventoryType::EType>(type);
+
+ msg->getU32Fast(block, _PREHASH_Flags, mFlags, block_num);
+
+ mSaleInfo.unpackMultiMessage(msg, block, block_num);
+
+ char name[DB_INV_ITEM_NAME_BUF_SIZE];
+ msg->getStringFast(block, _PREHASH_Name, DB_INV_ITEM_NAME_BUF_SIZE, name, block_num);
+ mName.assign(name);
+ LLString::replaceNonstandardASCII(mName, ' ');
+
+ char desc[DB_INV_ITEM_DESC_BUF_SIZE];
+ msg->getStringFast(block, _PREHASH_Description, DB_INV_ITEM_DESC_BUF_SIZE, desc, block_num);
+ mDescription.assign(desc);
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+
+ msg->getS32(block, "CreationDate", mCreationDate, block_num);
+
+ U32 local_crc = getCRC32();
+ U32 remote_crc = 0;
+ msg->getU32(block, "CRC", remote_crc, block_num);
+//#define CRC_CHECK
+#ifdef CRC_CHECK
+ if(local_crc == remote_crc)
+ {
+ lldebugs << "crc matches" << llendl;
+ return TRUE;
+ }
+ else
+ {
+ llwarns << "inventory crc mismatch: local=" << std::hex << local_crc
+ << " remote=" << remote_crc << std::dec << llendl;
+ return FALSE;
+ }
+#else
+ return (local_crc == remote_crc);
+#endif
+}
+
+// virtual
+BOOL LLInventoryItem::importFile(FILE* fp)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+ char junk[MAX_STRING];
+ BOOL success = TRUE;
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+
+ mInventoryType = LLInventoryType::IT_NONE;
+ mAssetUUID.setNull();
+ while(success && (!feof(fp)))
+ {
+ fgets(buffer, MAX_STRING, fp);
+ sscanf(buffer, " %254s %254s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("item_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("permissions", keyword))
+ {
+ success = mPermissions.importFile(fp);
+ }
+ else if(0 == strcmp("sale_info", keyword))
+ {
+ // Sale info used to contain next owner perm. It is now in
+ // the permissions. Thus, we read that out, and fix legacy
+ // objects. It's possible this op would fail, but it
+ // should pick up the vast majority of the tasks.
+ BOOL has_perm_mask = FALSE;
+ U32 perm_mask = 0;
+ success = mSaleInfo.importFile(fp, has_perm_mask, perm_mask);
+ if(has_perm_mask)
+ {
+ if(perm_mask == PERM_NONE)
+ {
+ perm_mask = mPermissions.getMaskOwner();
+ }
+ // fair use fix.
+ if(!(perm_mask & PERM_COPY))
+ {
+ perm_mask |= PERM_TRANSFER;
+ }
+ mPermissions.setMaskNext(perm_mask);
+ }
+ }
+ else if(0 == strcmp("shadow_id", keyword))
+ {
+ mAssetUUID.set(valuestr);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+ }
+ else if(0 == strcmp("asset_id", keyword))
+ {
+ mAssetUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("inv_type", keyword))
+ {
+ mInventoryType = LLInventoryType::lookup(valuestr);
+ }
+ else if(0 == strcmp("flags", keyword))
+ {
+ sscanf(valuestr, "%x", &mFlags);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %254s%[\t]%[^|]", keyword, junk, valuestr);
+
+ // IW: sscanf chokes and puts | in valuestr if there's no name
+ if (valuestr[0] == '|')
+ {
+ valuestr[0] = '\000';
+ }
+
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ else if(0 == strcmp("desc", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s%[\t]%[^|]", keyword, junk, valuestr);
+
+ if (valuestr[0] == '|')
+ {
+ valuestr[0] = '\000';
+ }
+
+ mDescription.assign(valuestr);
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+ /* TODO -- ask Ian about this code
+ const char *donkey = mDescription.c_str();
+ if (donkey[0] == '|')
+ {
+ llerrs << "Donkey" << llendl;
+ }
+ */
+ }
+ else if(0 == strcmp("creation_date", keyword))
+ {
+ sscanf(valuestr, "%d", &mCreationDate);
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in inventory import of item " << mUUID << llendl;
+ }
+ }
+
+ // Need to convert 1.0 simstate files to a useful inventory type
+ // and potentially deal with bad inventory tyes eg, a landmark
+ // marked as a texture.
+ if((LLInventoryType::IT_NONE == mInventoryType)
+ || !inventory_and_asset_types_match(mInventoryType, mType))
+ {
+ lldebugs << "Resetting inventory type for " << mUUID << llendl;
+ mInventoryType = LLInventoryType::defaultForAssetType(mType);
+ }
+ return success;
+}
+
+BOOL LLInventoryItem::exportFile(FILE* fp, BOOL include_asset_key) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ fprintf(fp, "\tinv_item\t0\n\t{\n");
+ mUUID.toString(uuid_str);
+ fprintf(fp, "\t\titem_id\t%s\n", uuid_str);
+ mParentUUID.toString(uuid_str);
+ fprintf(fp, "\t\tparent_id\t%s\n", uuid_str);
+ mPermissions.exportFile(fp);
+
+ // Check for permissions to see the asset id, and if so write it
+ // out as an asset id. Otherwise, apply our cheesy encryption.
+ if(include_asset_key)
+ {
+ U32 mask = mPermissions.getMaskBase();
+ if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
+ || (mAssetUUID.isNull()))
+ {
+ mAssetUUID.toString(uuid_str);
+ fprintf(fp, "\t\tasset_id\t%s\n", uuid_str);
+ }
+ else
+ {
+ LLUUID shadow_id(mAssetUUID);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.encrypt(shadow_id.mData, UUID_BYTES);
+ shadow_id.toString(uuid_str);
+ fprintf(fp, "\t\tshadow_id\t%s\n", uuid_str);
+ }
+ }
+ else
+ {
+ LLUUID::null.toString(uuid_str);
+ fprintf(fp, "\t\tasset_id\t%s\n", uuid_str);
+ }
+ fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+ const char* inv_type_str = LLInventoryType::lookup(mInventoryType);
+ if(inv_type_str) fprintf(fp, "\t\tinv_type\t%s\n", inv_type_str);
+ fprintf(fp, "\t\tflags\t%08x\n", mFlags);
+ mSaleInfo.exportFile(fp);
+ fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
+ fprintf(fp, "\t\tdesc\t%s|\n", mDescription.c_str());
+ fprintf(fp, "\t\tcreation_date\t%d\n", mCreationDate);
+ fprintf(fp,"\t}\n");
+ return TRUE;
+}
+
+// virtual
+BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+ char junk[MAX_STRING];
+ BOOL success = TRUE;
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+
+ mInventoryType = LLInventoryType::IT_NONE;
+ mAssetUUID.setNull();
+ while(success && input_stream.good())
+ {
+ input_stream.getline(buffer, MAX_STRING);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("item_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("permissions", keyword))
+ {
+ success = mPermissions.importLegacyStream(input_stream);
+ }
+ else if(0 == strcmp("sale_info", keyword))
+ {
+ // Sale info used to contain next owner perm. It is now in
+ // the permissions. Thus, we read that out, and fix legacy
+ // objects. It's possible this op would fail, but it
+ // should pick up the vast majority of the tasks.
+ BOOL has_perm_mask = FALSE;
+ U32 perm_mask = 0;
+ success = mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask);
+ if(has_perm_mask)
+ {
+ if(perm_mask == PERM_NONE)
+ {
+ perm_mask = mPermissions.getMaskOwner();
+ }
+ // fair use fix.
+ if(!(perm_mask & PERM_COPY))
+ {
+ perm_mask |= PERM_TRANSFER;
+ }
+ mPermissions.setMaskNext(perm_mask);
+ }
+ }
+ else if(0 == strcmp("shadow_id", keyword))
+ {
+ mAssetUUID.set(valuestr);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+ }
+ else if(0 == strcmp("asset_id", keyword))
+ {
+ mAssetUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("inv_type", keyword))
+ {
+ mInventoryType = LLInventoryType::lookup(valuestr);
+ }
+ else if(0 == strcmp("flags", keyword))
+ {
+ sscanf(valuestr, "%x", &mFlags);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s%[\t]%[^|]", keyword, junk, valuestr);
+
+ // IW: sscanf chokes and puts | in valuestr if there's no name
+ if (valuestr[0] == '|')
+ {
+ valuestr[0] = '\000';
+ }
+
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ else if(0 == strcmp("desc", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s%[\t]%[^|]", keyword, junk, valuestr);
+
+ if (valuestr[0] == '|')
+ {
+ valuestr[0] = '\000';
+ }
+
+ mDescription.assign(valuestr);
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+ /* TODO -- ask Ian about this code
+ const char *donkey = mDescription.c_str();
+ if (donkey[0] == '|')
+ {
+ llerrs << "Donkey" << llendl;
+ }
+ */
+ }
+ else if(0 == strcmp("creation_date", keyword))
+ {
+ sscanf(valuestr, "%d", &mCreationDate);
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in inventory import of item " << mUUID << llendl;
+ }
+ }
+
+ // Need to convert 1.0 simstate files to a useful inventory type
+ // and potentially deal with bad inventory tyes eg, a landmark
+ // marked as a texture.
+ if((LLInventoryType::IT_NONE == mInventoryType)
+ || !inventory_and_asset_types_match(mInventoryType, mType))
+ {
+ lldebugs << "Resetting inventory type for " << mUUID << llendl;
+ mInventoryType = LLInventoryType::defaultForAssetType(mType);
+ }
+ return success;
+}
+
+BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ output_stream << "\tinv_item\t0\n\t{\n";
+ mUUID.toString(uuid_str);
+ output_stream << "\t\titem_id\t" << uuid_str << "\n";
+ mParentUUID.toString(uuid_str);
+ output_stream << "\t\tparent_id\t" << uuid_str << "\n";
+ mPermissions.exportLegacyStream(output_stream);
+
+ // Check for permissions to see the asset id, and if so write it
+ // out as an asset id. Otherwise, apply our cheesy encryption.
+ if(include_asset_key)
+ {
+ U32 mask = mPermissions.getMaskBase();
+ if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
+ || (mAssetUUID.isNull()))
+ {
+ mAssetUUID.toString(uuid_str);
+ output_stream << "\t\tasset_id\t" << uuid_str << "\n";
+ }
+ else
+ {
+ LLUUID shadow_id(mAssetUUID);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.encrypt(shadow_id.mData, UUID_BYTES);
+ shadow_id.toString(uuid_str);
+ output_stream << "\t\tshadow_id\t" << uuid_str << "\n";
+ }
+ }
+ else
+ {
+ LLUUID::null.toString(uuid_str);
+ output_stream << "\t\tasset_id\t" << uuid_str << "\n";
+ }
+ output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
+ const char* inv_type_str = LLInventoryType::lookup(mInventoryType);
+ if(inv_type_str)
+ output_stream << "\t\tinv_type\t" << inv_type_str << "\n";
+ char buffer[32];
+ sprintf(buffer, "\t\tflags\t%08x\n", mFlags);
+ output_stream << buffer;
+ mSaleInfo.exportLegacyStream(output_stream);
+ output_stream << "\t\tname\t" << mName.c_str() << "|\n";
+ output_stream << "\t\tdesc\t" << mDescription.c_str() << "|\n";
+ output_stream << "\t\tcreation_date\t" << mCreationDate << "\n";
+ output_stream << "\t}\n";
+ return TRUE;
+}
+
+LLSD LLInventoryItem::asLLSD() const
+{
+ LLSD sd = LLSD();
+ sd["item_id"] = mUUID;
+ sd["parent_id"] = mParentUUID;
+ sd["permissions"] = ll_create_sd_from_permissions(mPermissions);
+
+ U32 mask = mPermissions.getMaskBase();
+ if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
+ || (mAssetUUID.isNull()))
+ {
+ sd["asset_id"] = mAssetUUID;
+ }
+ else
+ {
+ LLUUID shadow_id(mAssetUUID);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.encrypt(shadow_id.mData, UUID_BYTES);
+ sd["shadow_id"] = shadow_id;
+ }
+ sd["type"] = LLAssetType::lookup(mType);
+ const char* inv_type_str = LLInventoryType::lookup(mInventoryType);
+ if(inv_type_str)
+ {
+ sd["inv_type"] = inv_type_str;
+ }
+ sd["flags"] = ll_sd_from_U32(mFlags);
+ sd["sale_info"] = mSaleInfo;
+ sd["name"] = mName;
+ sd["desc"] = mDescription;
+ sd["creation_date"] = mCreationDate;
+
+ return sd;
+}
+
+bool LLInventoryItem::fromLLSD(LLSD& sd)
+{
+ mInventoryType = LLInventoryType::IT_NONE;
+ mAssetUUID.setNull();
+ const char *w;
+
+ w = "item_id";
+ if (sd.has(w))
+ {
+ mUUID = sd[w];
+ }
+ w = "parent_id";
+ if (sd.has(w))
+ {
+ mParentUUID = sd[w];
+ }
+ w = "permissions";
+ if (sd.has(w))
+ {
+ mPermissions = ll_permissions_from_sd(sd[w]);
+ }
+ w = "sale_info";
+ if (sd.has(w))
+ {
+ // Sale info used to contain next owner perm. It is now in
+ // the permissions. Thus, we read that out, and fix legacy
+ // objects. It's possible this op would fail, but it
+ // should pick up the vast majority of the tasks.
+ BOOL has_perm_mask = FALSE;
+ U32 perm_mask = 0;
+ if (!mSaleInfo.fromLLSD(sd[w], has_perm_mask, perm_mask))
+ {
+ goto fail;
+ }
+ if (has_perm_mask)
+ {
+ if(perm_mask == PERM_NONE)
+ {
+ perm_mask = mPermissions.getMaskOwner();
+ }
+ // fair use fix.
+ if(!(perm_mask & PERM_COPY))
+ {
+ perm_mask |= PERM_TRANSFER;
+ }
+ mPermissions.setMaskNext(perm_mask);
+ }
+ }
+ w = "shadow_id";
+ if (sd.has(w))
+ {
+ mAssetUUID = sd[w];
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+ }
+ w = "asset_id";
+ if (sd.has(w))
+ {
+ mAssetUUID = sd[w];
+ }
+ w = "type";
+ if (sd.has(w))
+ {
+ mType = LLAssetType::lookup(sd[w].asString().c_str());
+ }
+ w = "inv_type";
+ if (sd.has(w))
+ {
+ mInventoryType = LLInventoryType::lookup(sd[w].asString().c_str());
+ }
+ w = "flags";
+ if (sd.has(w))
+ {
+ mFlags = ll_U32_from_sd(sd[w]);
+ }
+ w = "name";
+ if (sd.has(w))
+ {
+ mName = sd[w].asString();
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ w = "desc";
+ if (sd.has(w))
+ {
+ mDescription = sd[w].asString();
+ LLString::replaceNonstandardASCII(mDescription, ' ');
+ }
+ w = "creation_date";
+ if (sd.has(w))
+ {
+ mCreationDate = sd[w];
+ }
+
+ // Need to convert 1.0 simstate files to a useful inventory type
+ // and potentially deal with bad inventory tyes eg, a landmark
+ // marked as a texture.
+ if((LLInventoryType::IT_NONE == mInventoryType)
+ || !inventory_and_asset_types_match(mInventoryType, mType))
+ {
+ lldebugs << "Resetting inventory type for " << mUUID << llendl;
+ mInventoryType = LLInventoryType::defaultForAssetType(mType);
+ }
+
+ return true;
+fail:
+ return false;
+
+}
+
+LLXMLNode *LLInventoryItem::exportFileXML(BOOL include_asset_key) const
+{
+ LLMemType m1(LLMemType::MTYPE_INVENTORY);
+ LLXMLNode *ret = new LLXMLNode("item", FALSE);
+
+ ret->createChild("uuid", TRUE)->setUUIDValue(1, &mUUID);
+ ret->createChild("parent_uuid", TRUE)->setUUIDValue(1, &mParentUUID);
+
+ mPermissions.exportFileXML()->setParent(ret);
+
+ // Check for permissions to see the asset id, and if so write it
+ // out as an asset id. Otherwise, apply our cheesy encryption.
+ if(include_asset_key)
+ {
+ U32 mask = mPermissions.getMaskBase();
+ if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
+ || (mAssetUUID.isNull()))
+ {
+ ret->createChild("asset_id", FALSE)->setUUIDValue(1, &mAssetUUID);
+ }
+ else
+ {
+ LLUUID shadow_id(mAssetUUID);
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.encrypt(shadow_id.mData, UUID_BYTES);
+
+ ret->createChild("shadow_id", FALSE)->setUUIDValue(1, &shadow_id);
+ }
+ }
+
+ LLString type_str = LLAssetType::lookup(mType);
+ LLString inv_type_str = LLInventoryType::lookup(mInventoryType);
+
+ ret->createChild("asset_type", FALSE)->setStringValue(1, &type_str);
+ ret->createChild("inventory_type", FALSE)->setStringValue(1, &inv_type_str);
+ S32 tmp_flags = (S32) mFlags;
+ ret->createChild("flags", FALSE)->setByteValue(4, (U8*)(&tmp_flags), LLXMLNode::ENCODING_HEX);
+
+ mSaleInfo.exportFileXML()->setParent(ret);
+
+ LLString temp;
+ temp.assign(mName);
+ ret->createChild("name", FALSE)->setStringValue(1, &temp);
+ temp.assign(mDescription);
+ ret->createChild("description", FALSE)->setStringValue(1, &temp);
+ ret->createChild("creation_date", FALSE)->setIntValue(1, &mCreationDate);
+
+ return ret;
+}
+
+BOOL LLInventoryItem::importXML(LLXMLNode* node)
+{
+ BOOL success = FALSE;
+ if (node)
+ {
+ success = TRUE;
+ LLXMLNodePtr sub_node;
+ if (node->getChild("uuid", sub_node))
+ success = (1 == sub_node->getUUIDValue(1, &mUUID));
+ if (node->getChild("parent_uuid", sub_node))
+ success = success && (1 == sub_node->getUUIDValue(1, &mParentUUID));
+ if (node->getChild("permissions", sub_node))
+ success = success && mPermissions.importXML(sub_node);
+ if (node->getChild("asset_id", sub_node))
+ success = success && (1 == sub_node->getUUIDValue(1, &mAssetUUID));
+ if (node->getChild("shadow_id", sub_node))
+ {
+ success = success && (1 == sub_node->getUUIDValue(1, &mAssetUUID));
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+ }
+ if (node->getChild("asset_type", sub_node))
+ mType = LLAssetType::lookup(sub_node->getValue().c_str());
+ if (node->getChild("inventory_type", sub_node))
+ mInventoryType = LLInventoryType::lookup(sub_node->getValue().c_str());
+ if (node->getChild("flags", sub_node))
+ {
+ S32 tmp_flags = 0;
+ success = success && (1 == sub_node->getIntValue(1, &tmp_flags));
+ mFlags = (U32) tmp_flags;
+ }
+ if (node->getChild("sale_info", sub_node))
+ success = success && mSaleInfo.importXML(sub_node);
+ if (node->getChild("name", sub_node))
+ mName = sub_node->getValue();
+ if (node->getChild("description", sub_node))
+ mDescription = sub_node->getValue();
+ if (node->getChild("creation_date", sub_node))
+ success = success && (1 == sub_node->getIntValue(1, &mCreationDate));
+ if (!success)
+ {
+ lldebugs << "LLInventory::importXML() failed for node named '"
+ << node->getName() << "'" << llendl;
+ }
+ }
+ return success;
+}
+
+S32 LLInventoryItem::packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override) const
+{
+ // Figure out which permissions to use.
+ LLPermissions perm;
+ if (perm_override)
+ {
+ // Use the permissions override.
+ perm = *perm_override;
+ }
+ else
+ {
+ // Use the current permissions.
+ perm = getPermissions();
+ }
+
+ // describe the inventory item
+ char* buffer = (char*) bin_bucket;
+ char creator_id_str[UUID_STR_LENGTH];
+
+ perm.getCreator().toString(creator_id_str);
+ char owner_id_str[UUID_STR_LENGTH];
+ perm.getOwner().toString(owner_id_str);
+ char last_owner_id_str[UUID_STR_LENGTH];
+ perm.getLastOwner().toString(last_owner_id_str);
+ char group_id_str[UUID_STR_LENGTH];
+ perm.getGroup().toString(group_id_str);
+ char asset_id_str[UUID_STR_LENGTH];
+ getAssetUUID().toString(asset_id_str);
+ S32 size = sprintf(buffer,
+ "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x",
+ getType(),
+ getInventoryType(),
+ getName().c_str(),
+ creator_id_str,
+ owner_id_str,
+ last_owner_id_str,
+ group_id_str,
+ perm.getMaskBase(),
+ perm.getMaskOwner(),
+ perm.getMaskGroup(),
+ perm.getMaskEveryone(),
+ perm.getMaskNextOwner(),
+ asset_id_str,
+ getDescription().c_str(),
+ getSaleInfo().getSaleType(),
+ getSaleInfo().getSalePrice(),
+ getFlags()) + 1;
+
+ return size;
+}
+
+void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size)
+{
+ // Early exit on an empty binary bucket.
+ if (bin_bucket_size <= 1) return;
+
+ // Convert the bin_bucket into a string.
+ char* item_buffer = new char[bin_bucket_size+1];
+ memcpy(item_buffer, bin_bucket, bin_bucket_size);
+ item_buffer[bin_bucket_size] = '\0';
+ std::string str(item_buffer);
+
+ lldebugs << "item buffer: " << item_buffer << llendl;
+ delete[] item_buffer;
+
+ // Tokenize the string.
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
+ tokenizer tokens(str, sep);
+ tokenizer::iterator iter = tokens.begin();
+
+ // Extract all values.
+ LLUUID item_id;
+ item_id.generate();
+ setUUID(item_id);
+
+ LLAssetType::EType type;
+ type = (LLAssetType::EType)(atoi((*(iter++)).c_str()));
+ setType( type );
+
+ LLInventoryType::EType inv_type;
+ inv_type = (LLInventoryType::EType)(atoi((*(iter++)).c_str()));
+ setInventoryType( inv_type );
+
+ LLString name((*(iter++)).c_str());
+ rename( name );
+
+ LLUUID creator_id((*(iter++)).c_str());
+ LLUUID owner_id((*(iter++)).c_str());
+ LLUUID last_owner_id((*(iter++)).c_str());
+ LLUUID group_id((*(iter++)).c_str());
+ PermissionMask mask_base = strtoul((*(iter++)).c_str(), NULL, 16);
+ PermissionMask mask_owner = strtoul((*(iter++)).c_str(), NULL, 16);
+ PermissionMask mask_group = strtoul((*(iter++)).c_str(), NULL, 16);
+ PermissionMask mask_every = strtoul((*(iter++)).c_str(), NULL, 16);
+ PermissionMask mask_next = strtoul((*(iter++)).c_str(), NULL, 16);
+ LLPermissions perm;
+ perm.init(creator_id, owner_id, last_owner_id, group_id);
+ perm.initMasks(mask_base, mask_owner, mask_group, mask_every, mask_next);
+ setPermissions(perm);
+ //lldebugs << "perm: " << perm << llendl;
+
+ LLUUID asset_id((*(iter++)).c_str());
+ setAssetUUID(asset_id);
+
+ LLString desc((*(iter++)).c_str());
+ setDescription(desc);
+
+ LLSaleInfo::EForSale sale_type;
+ sale_type = (LLSaleInfo::EForSale)(atoi((*(iter++)).c_str()));
+ S32 price = atoi((*(iter++)).c_str());
+ LLSaleInfo sale_info(sale_type, price);
+ setSaleInfo(sale_info);
+
+ U32 flags = strtoul((*(iter++)).c_str(), NULL, 16);
+ setFlags(flags);
+
+ time_t now = time(NULL);
+ setCreationDate(now);
+}
+
+// returns TRUE if a should appear before b
+BOOL item_dictionary_sort( LLInventoryItem* a, LLInventoryItem* b )
+{
+ return (LLString::compareDict( a->getName().c_str(), b->getName().c_str() ) < 0);
+}
+
+// returns TRUE if a should appear before b
+BOOL item_date_sort( LLInventoryItem* a, LLInventoryItem* b )
+{
+ return a->getCreationDate() < b->getCreationDate();
+}
+
+
+///----------------------------------------------------------------------------
+/// Class LLInventoryCategory
+///----------------------------------------------------------------------------
+
+LLInventoryCategory::LLInventoryCategory(
+ const LLUUID& uuid,
+ const LLUUID& parent_uuid,
+ LLAssetType::EType preferred_type,
+ const LLString& name) :
+ LLInventoryObject(uuid, parent_uuid, LLAssetType::AT_CATEGORY, name),
+ mPreferredType(preferred_type)
+{
+}
+
+LLInventoryCategory::LLInventoryCategory() :
+ mPreferredType(LLAssetType::AT_NONE)
+{
+ mType = LLAssetType::AT_CATEGORY;
+}
+
+LLInventoryCategory::LLInventoryCategory(const LLInventoryCategory* other) :
+ LLInventoryObject()
+{
+ copy(other);
+}
+
+LLInventoryCategory::~LLInventoryCategory()
+{
+}
+
+// virtual
+void LLInventoryCategory::copy(const LLInventoryCategory* other)
+{
+ LLInventoryObject::copy(other);
+ mPreferredType = other->mPreferredType;
+}
+
+LLAssetType::EType LLInventoryCategory::getPreferredType() const
+{
+ return mPreferredType;
+}
+
+void LLInventoryCategory::setPreferredType(LLAssetType::EType type)
+{
+ mPreferredType = type;
+}
+
+// virtual
+void LLInventoryCategory::packMessage(LLMessageSystem* msg) const
+{
+ msg->addUUIDFast(_PREHASH_FolderID, mUUID);
+ msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
+ S8 type = static_cast<S8>(mPreferredType);
+ msg->addS8Fast(_PREHASH_Type, type);
+ msg->addStringFast(_PREHASH_Name, mName);
+}
+
+// virtual
+void LLInventoryCategory::unpackMessage(LLMessageSystem* msg,
+ const char* block,
+ S32 block_num)
+{
+ msg->getUUIDFast(block, _PREHASH_FolderID, mUUID, block_num);
+ msg->getUUIDFast(block, _PREHASH_ParentID, mParentUUID, block_num);
+ S8 type;
+ msg->getS8Fast(block, _PREHASH_Type, type, block_num);
+ mPreferredType = static_cast<LLAssetType::EType>(type);
+ char name[DB_INV_ITEM_NAME_BUF_SIZE];
+ msg->getStringFast(block, _PREHASH_Name, DB_INV_ITEM_NAME_BUF_SIZE, name, block_num);
+ mName.assign(name);
+ LLString::replaceNonstandardASCII(mName, ' ');
+}
+
+// virtual
+BOOL LLInventoryCategory::importFile(FILE* fp)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+ while(!feof(fp))
+ {
+ fgets(buffer, MAX_STRING, fp);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("cat_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("pref_type", keyword))
+ {
+ mPreferredType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s %[^|]", keyword, valuestr);
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in inventory import category " << mUUID << llendl;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLInventoryCategory::exportFile(FILE* fp, BOOL) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ fprintf(fp, "\tinv_category\t0\n\t{\n");
+ mUUID.toString(uuid_str);
+ fprintf(fp, "\t\tcat_id\t%s\n", uuid_str);
+ mParentUUID.toString(uuid_str);
+ fprintf(fp, "\t\tparent_id\t%s\n", uuid_str);
+ fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+ fprintf(fp, "\t\tpref_type\t%s\n", LLAssetType::lookup(mPreferredType));
+ fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
+ fprintf(fp,"\t}\n");
+ return TRUE;
+}
+
+
+// virtual
+BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
+{
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+ while(input_stream.good())
+ {
+ input_stream.getline(buffer, MAX_STRING);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("cat_id", keyword))
+ {
+ mUUID.set(valuestr);
+ }
+ else if(0 == strcmp("parent_id", keyword))
+ {
+ mParentUUID.set(valuestr);
+ }
+ else if(0 == strcmp("type", keyword))
+ {
+ mType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("pref_type", keyword))
+ {
+ mPreferredType = LLAssetType::lookup(valuestr);
+ }
+ else if(0 == strcmp("name", keyword))
+ {
+ //strcpy(valuestr, buffer + strlen(keyword) + 3);
+ // *NOTE: Not ANSI C, but widely supported.
+ sscanf(buffer, " %s %[^|]", keyword, valuestr);
+ mName.assign(valuestr);
+ LLString::replaceNonstandardASCII(mName, ' ');
+ LLString::replaceChar(mName, '|', ' ');
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in inventory import category " << mUUID << llendl;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) const
+{
+ char uuid_str[UUID_STR_LENGTH];
+ output_stream << "\tinv_category\t0\n\t{\n";
+ mUUID.toString(uuid_str);
+ output_stream << "\t\tcat_id\t" << uuid_str << "\n";
+ mParentUUID.toString(uuid_str);
+ output_stream << "\t\tparent_id\t" << uuid_str << "\n";
+ output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
+ output_stream << "\t\tpref_type\t" << LLAssetType::lookup(mPreferredType) << "\n";
+ output_stream << "\t\tname\t" << mName.c_str() << "|\n";
+ output_stream << "\t}\n";
+ return TRUE;
+}
+
+///----------------------------------------------------------------------------
+/// Local function definitions
+///----------------------------------------------------------------------------
+
+bool inventory_and_asset_types_match(
+ LLInventoryType::EType inventory_type,
+ LLAssetType::EType asset_type)
+{
+ bool rv = false;
+ if((inventory_type >= 0) && (inventory_type < LLInventoryType::IT_COUNT))
+ {
+ for(S32 i = 0; i < MAX_POSSIBLE_ASSET_TYPES; ++i)
+ {
+ if(INVENTORY_TO_ASSET_TYPE[inventory_type][i] == asset_type)
+ {
+ rv = true;
+ break;
+ }
+ }
+ }
+ return rv;
+}
+
+///----------------------------------------------------------------------------
+/// exported functions
+///----------------------------------------------------------------------------
+
+static const std::string INV_ITEM_ID_LABEL("item_id");
+static const std::string INV_FOLDER_ID_LABEL("folder_id");
+static const std::string INV_PARENT_ID_LABEL("parent_id");
+static const std::string INV_ASSET_TYPE_LABEL("asset_type");
+static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
+static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
+static const std::string INV_NAME_LABEL("name");
+static const std::string INV_DESC_LABEL("description");
+static const std::string INV_PERMISSIONS_LABEL("permissions");
+static const std::string INV_ASSET_ID_LABEL("asset_id");
+static const std::string INV_SALE_INFO_LABEL("sale_info");
+static const std::string INV_FLAGS_LABEL("flags");
+static const std::string INV_CREATION_DATE_LABEL("created_at");
+
+LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item)
+{
+ LLSD rv;
+ if(item.isNull()) return rv;
+ if (item->getType() == LLAssetType::AT_NONE)
+ {
+ llwarns << "ll_create_sd_from_inventory_item() for item with AT_NONE"
+ << llendl;
+ return rv;
+ }
+ rv[INV_ITEM_ID_LABEL] = item->getUUID();
+ rv[INV_PARENT_ID_LABEL] = item->getParentUUID();
+ rv[INV_NAME_LABEL] = item->getName();
+ rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(item->getType());
+ rv[INV_ASSET_ID_LABEL] = item->getAssetUUID();
+ rv[INV_DESC_LABEL] = item->getDescription();
+ rv[INV_SALE_INFO_LABEL] = ll_create_sd_from_sale_info(item->getSaleInfo());
+ rv[INV_PERMISSIONS_LABEL] =
+ ll_create_sd_from_permissions(item->getPermissions());
+ rv[INV_INVENTORY_TYPE_LABEL] =
+ LLInventoryType::lookup(item->getInventoryType());
+ rv[INV_FLAGS_LABEL] = (S32)item->getFlags();
+ rv[INV_CREATION_DATE_LABEL] = item->getCreationDate();
+ return rv;
+}
+
+LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item)
+{
+ LLPointer<LLInventoryItem> rv = new LLInventoryItem;
+ rv->setUUID(sd_item[INV_ITEM_ID_LABEL].asUUID());
+ rv->setParent(sd_item[INV_PARENT_ID_LABEL].asUUID());
+ rv->rename(sd_item[INV_NAME_LABEL].asString());
+ rv->setType(
+ LLAssetType::lookup(sd_item[INV_ASSET_TYPE_LABEL].asString().c_str()));
+ rv->setAssetUUID(sd_item[INV_ASSET_ID_LABEL].asUUID());
+ rv->setDescription(sd_item[INV_DESC_LABEL].asString());
+ rv->setSaleInfo(ll_sale_info_from_sd(sd_item[INV_SALE_INFO_LABEL]));
+ rv->setPermissions(ll_permissions_from_sd(sd_item[INV_PERMISSIONS_LABEL]));
+ rv->setInventoryType(
+ LLInventoryType::lookup(
+ sd_item[INV_INVENTORY_TYPE_LABEL].asString().c_str()));
+ rv->setFlags((U32)(sd_item[INV_FLAGS_LABEL].asInteger()));
+ rv->setCreationDate(sd_item[INV_CREATION_DATE_LABEL].asInteger());
+ return rv;
+}
+
+LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat)
+{
+ LLSD rv;
+ if(cat.isNull()) return rv;
+ if (cat->getType() == LLAssetType::AT_NONE)
+ {
+ llwarns << "ll_create_sd_from_inventory_category() for cat with AT_NONE"
+ << llendl;
+ return rv;
+ }
+ rv[INV_FOLDER_ID_LABEL] = cat->getUUID();
+ rv[INV_PARENT_ID_LABEL] = cat->getParentUUID();
+ rv[INV_NAME_LABEL] = cat->getName();
+ rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(cat->getType());
+ if(LLAssetType::AT_NONE != cat->getPreferredType())
+ {
+ rv[INV_PREFERRED_TYPE_LABEL] =
+ LLAssetType::lookup(cat->getPreferredType());
+ }
+ return rv;
+}
+
+LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat)
+{
+ LLPointer<LLInventoryCategory> rv = new LLInventoryCategory;
+ rv->setUUID(sd_cat[INV_FOLDER_ID_LABEL].asUUID());
+ rv->setParent(sd_cat[INV_PARENT_ID_LABEL].asUUID());
+ rv->rename(sd_cat[INV_NAME_LABEL].asString());
+ rv->setType(
+ LLAssetType::lookup(sd_cat[INV_ASSET_TYPE_LABEL].asString().c_str()));
+ rv->setPreferredType(
+ LLAssetType::lookup(
+ sd_cat[INV_PREFERRED_TYPE_LABEL].asString().c_str()));
+ return rv;
+}
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
new file mode 100644
index 0000000000..9f750c46b2
--- /dev/null
+++ b/indra/llinventory/llinventory.h
@@ -0,0 +1,411 @@
+/**
+ * @file llinventory.h
+ * @brief LLInventoryItem and LLInventoryCategory class declaration.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLINVENTORY_H
+#define LL_LLINVENTORY_H
+
+#include <functional>
+
+#include "llassetstorage.h"
+#include "lldarray.h"
+#include "llpermissions.h"
+#include "llsaleinfo.h"
+#include "llsd.h"
+#include "lluuid.h"
+#include "llxmlnode.h"
+
+// consts for Key field in the task inventory update message
+extern const U8 TASK_INVENTORY_ITEM_KEY;
+extern const U8 TASK_INVENTORY_ASSET_KEY;
+
+// anonymous enumeration to specify a max inventory buffer size for
+// use in packBinaryBucket()
+enum
+{
+ MAX_INVENTORY_BUFFER_SIZE = 1024
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryType
+//
+// Class used to encapsulate operations around inventory type.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLInventoryType
+{
+public:
+ enum EType
+ {
+ IT_TEXTURE = 0,
+ IT_SOUND = 1,
+ IT_CALLINGCARD = 2,
+ IT_LANDMARK = 3,
+ //IT_SCRIPT = 4,
+ //IT_CLOTHING = 5,
+ IT_OBJECT = 6,
+ IT_NOTECARD = 7,
+ IT_CATEGORY = 8,
+ IT_ROOT_CATEGORY = 9,
+ IT_LSL = 10,
+ //IT_LSL_BYTECODE = 11,
+ //IT_TEXTURE_TGA = 12,
+ //IT_BODYPART = 13,
+ //IT_TRASH = 14,
+ IT_SNAPSHOT = 15,
+ //IT_LOST_AND_FOUND = 16,
+ IT_ATTACHMENT = 17,
+ IT_WEARABLE = 18,
+ IT_ANIMATION = 19,
+ IT_GESTURE = 20,
+ IT_COUNT = 21,
+
+ IT_NONE = -1
+ };
+
+ // machine transation between type and strings
+ static EType lookup(const char* name);
+ static const char* lookup(EType type);
+
+ // translation from a type to a human readable form.
+ static const char* lookupHumanReadable(EType type);
+
+ // return the default inventory for the given asset type.
+ static EType defaultForAssetType(LLAssetType::EType asset_type);
+
+private:
+ // don't instantiate or derive one of these objects
+ LLInventoryType( void ) {}
+ ~LLInventoryType( void ) {}
+
+//private:
+// static const char* mInventoryTypeNames[];
+// static const char* mInventoryTypeHumanNames[];
+// static LLInventoryType::EType mInventoryAssetType[];
+};
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryObject
+//
+// This is the base class for inventory objects that handles the
+// common code between items and categories. The 'mParentUUID' member
+// means the parent category since all inventory objects except each
+// user's root category are in some category. Each user's root
+// category will have mParentUUID==LLUUID::null.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLMessageSystem;
+
+class LLInventoryObject : public LLRefCount
+{
+protected:
+ LLUUID mUUID;
+ LLUUID mParentUUID;
+ LLAssetType::EType mType;
+ LLString mName;
+
+protected:
+ virtual ~LLInventoryObject( void );
+
+public:
+ MEM_TYPE_NEW(LLMemType::MTYPE_INVENTORY);
+ LLInventoryObject(const LLUUID& uuid, const LLUUID& parent_uuid,
+ LLAssetType::EType type, const LLString& name);
+ LLInventoryObject();
+ virtual void copy(const LLInventoryObject* other); // LLRefCount requires custom copy
+
+ // accessors
+ const LLUUID& getUUID() const;
+ const LLUUID& getParentUUID() const;
+ const LLString& getName() const;
+ LLAssetType::EType getType() const;
+
+ // mutators - will not call updateServer();
+ void setUUID(const LLUUID& new_uuid);
+ void rename(const LLString& new_name);
+ void setParent(const LLUUID& new_parent);
+ void setType(LLAssetType::EType type);
+
+ // file support - implemented here so that a minimal information
+ // set can be transmitted between simulator and viewer.
+// virtual BOOL importFile(FILE* fp);
+ virtual BOOL exportFile(FILE* fp, BOOL include_asset_key = TRUE) const;
+
+ virtual BOOL importLegacyStream(std::istream& input_stream);
+ virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const;
+
+ // virtual methods
+ virtual void removeFromServer();
+ virtual void updateParentOnServer(BOOL) const;
+ virtual void updateServer(BOOL) const;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryItem
+//
+// An inventory item represents something that the current user has in
+// their inventory.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLInventoryItem : public LLInventoryObject
+{
+public:
+ typedef LLDynamicArray<LLPointer<LLInventoryItem> > item_array_t;
+
+protected:
+ LLPermissions mPermissions;
+ LLUUID mAssetUUID;
+ LLString mDescription;
+ LLSaleInfo mSaleInfo;
+ LLInventoryType::EType mInventoryType;
+ U32 mFlags;
+ S32 mCreationDate; // seconds from 1/1/1970, UTC
+
+public:
+ enum
+ {
+ // The meaning of LLInventoryItem::mFlags is distinct for each
+ // inventory type.
+ II_FLAGS_NONE = 0,
+
+ // landmark flags
+ II_FLAGS_LANDMARK_VISITED = 1,
+
+ // flag to indicate that object permissions should have next
+ // owner perm be more restrictive on rez. We bump this into
+ // the second byte of the flags since the low byte is used to
+ // track attachment points.
+ II_FLAGS_OBJECT_SLAM_PERM = 0x100,
+
+ // These flags specify which permissions masks to overwrite
+ // upon rez. Normally, if no permissions slam (above) or
+ // overwrite flags are set, the asset's permissions are
+ // used and the inventory's permissions are ignored. If
+ // any of these flags are set, the inventory's permissions
+ // take precedence.
+ II_FLAGS_OBJECT_PERM_OVERWRITE_BASE = 0x010000,
+ II_FLAGS_OBJECT_PERM_OVERWRITE_OWNER = 0x020000,
+ II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP = 0x040000,
+ II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE = 0x080000,
+ II_FLAGS_OBJECT_PERM_OVERWRITE_NEXT_OWNER = 0x100000,
+
+ // wearables use the low order byte of flags to store the
+ // EWearableType enumeration found in newview/llwearable.h
+ };
+
+protected:
+ ~LLInventoryItem(); // ref counted
+
+public:
+ MEM_TYPE_NEW(LLMemType::MTYPE_INVENTORY);
+ LLInventoryItem(const LLUUID& uuid,
+ const LLUUID& parent_uuid,
+ const LLPermissions& permissions,
+ const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ LLInventoryType::EType inv_type,
+ const LLString& name,
+ const LLString& desc,
+ const LLSaleInfo& sale_info,
+ U32 flags,
+ S32 creation_date_utc);
+ LLInventoryItem();
+ // Create a copy of an inventory item from a pointer to another item
+ // Note: Because InventoryItems are ref counted, reference copy (a = b)
+ // is prohibited
+ LLInventoryItem(const LLInventoryItem* other);
+ virtual void copy(const LLInventoryItem* other); // LLRefCount requires custom copy
+
+ // As a constructor alternative, the clone() method works like a
+ // copy constructor, but gens a new UUID.
+ // It is up to the caller to delete (unref) the item.
+ virtual void clone(LLPointer<LLInventoryItem>& newitem) const;
+
+ // accessors
+ const LLPermissions& getPermissions() const;
+ const LLUUID& getCreatorUUID() const;
+ const LLUUID& getAssetUUID() const;
+ const LLString& getDescription() const;
+ const LLSaleInfo& getSaleInfo() const;
+ LLInventoryType::EType getInventoryType() const;
+ U32 getFlags() const;
+ S32 getCreationDate() const;
+ U32 getCRC32() const; // really more of a checksum.
+
+ // mutators - will not call updateServer(), and will never fail
+ // (though it may correct to sane values)
+ void setAssetUUID(const LLUUID& asset_id);
+ void setDescription(const LLString& new_desc);
+ void setSaleInfo(const LLSaleInfo& sale_info);
+ void setPermissions(const LLPermissions& perm);
+ void setInventoryType(LLInventoryType::EType inv_type);
+ void setFlags(U32 flags);
+ void setCreationDate(S32 creation_date_utc);
+
+ // Put this inventory item onto the current outgoing mesage. It
+ // assumes you have already called nextBlock().
+ virtual void packMessage(LLMessageSystem* msg) const;
+
+ // unpack returns TRUE if the inventory item came through the
+ // network ok. It uses a simple crc check which is defeatable, but
+ // we want to detect network mangling somehow.
+ virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
+
+ // file support
+ virtual BOOL importFile(FILE* fp);
+ virtual BOOL exportFile(FILE* fp, BOOL include_asset_key = TRUE) const;
+
+ virtual BOOL importLegacyStream(std::istream& input_stream);
+ virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const;
+
+ virtual LLXMLNode *exportFileXML(BOOL include_asset_key = TRUE) const;
+ BOOL importXML(LLXMLNode* node);
+
+ // helper functions
+
+ // pack all information needed to reconstruct this item into the given binary bucket.
+ // perm_override is optional
+ S32 packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override = NULL) const;
+ void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);
+ LLSD asLLSD() const;
+ bool fromLLSD(LLSD& sd);
+
+};
+
+BOOL item_dictionary_sort(LLInventoryItem* a,LLInventoryItem* b);
+BOOL item_date_sort(LLInventoryItem* a, LLInventoryItem* b);
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryCategory
+//
+// An instance of this class represents a category of inventory
+// items. Users come with a set of default categories, and can create
+// new ones as needed.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLInventoryCategory : public LLInventoryObject
+{
+public:
+ typedef LLDynamicArray<LLPointer<LLInventoryCategory> > cat_array_t;
+
+protected:
+ ~LLInventoryCategory();
+
+public:
+ MEM_TYPE_NEW(LLMemType::MTYPE_INVENTORY);
+ LLInventoryCategory(const LLUUID& uuid, const LLUUID& parent_uuid,
+ LLAssetType::EType preferred_type,
+ const LLString& name);
+ LLInventoryCategory();
+ LLInventoryCategory(const LLInventoryCategory* other);
+ virtual void copy(const LLInventoryCategory* other); // LLRefCount requires custom copy
+
+ // accessors and mutators
+ LLAssetType::EType getPreferredType() const;
+ void setPreferredType(LLAssetType::EType type);
+ // For messaging system support
+ virtual void packMessage(LLMessageSystem* msg) const;
+ virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
+
+ // file support
+ virtual BOOL importFile(FILE* fp);
+ virtual BOOL exportFile(FILE* fp, BOOL include_asset_key = TRUE) const;
+
+ virtual BOOL importLegacyStream(std::istream& input_stream);
+ virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const;
+
+protected:
+ // The type of asset that this category was "meant" to hold
+ // (although it may in fact hold any type).
+ LLAssetType::EType mPreferredType;
+
+};
+
+
+//-----------------------------------------------------------------------------
+// Useful bits
+//-----------------------------------------------------------------------------
+
+// This functor tests if an item is transferrable and returns true if
+// it is. Derived from unary_function<> so that the object can be used
+// in stl-compliant adaptable predicates (eg, not1<>). You might want
+// to use this in std::partition() or similar logic.
+struct IsItemTransferable : public std::unary_function<LLInventoryItem*, bool>
+{
+ LLUUID mDestID;
+ IsItemTransferable(const LLUUID& dest_id) : mDestID(dest_id) {}
+ bool operator()(const LLInventoryItem* item) const
+ {
+ return (item->getPermissions().allowTransferTo(mDestID)) ? true:false;
+ }
+};
+
+// This functor is used to set the owner and group of inventory items,
+// for example, in a simple std::for_each() loop. Note that the call
+// to setOwnerAndGroup can fail if authority_id != LLUUID::null.
+struct SetItemOwnerAndGroup
+{
+ LLUUID mAuthorityID;
+ LLUUID mOwnerID;
+ LLUUID mGroupID;
+ SetItemOwnerAndGroup(const LLUUID& authority_id,
+ const LLUUID& owner_id,
+ const LLUUID& group_id) :
+ mAuthorityID(authority_id), mOwnerID(owner_id), mGroupID(group_id) {}
+ void operator()(LLInventoryItem* item) const
+ {
+ LLPermissions perm = item->getPermissions();
+ bool is_atomic = (LLAssetType::AT_OBJECT == item->getType()) ? false : true;
+ perm.setOwnerAndGroup(mAuthorityID, mOwnerID, mGroupID, is_atomic);
+ item->setPermissions(perm);
+ }
+};
+
+// This functor is used to unset the share with group, everyone perms, and
+// for sale info for objects being sold through contents.
+struct SetNotForSale
+{
+ LLUUID mAgentID;
+ LLUUID mGroupID;
+ SetNotForSale(const LLUUID& agent_id,
+ const LLUUID& group_id) :
+ mAgentID(agent_id), mGroupID(group_id) {}
+ void operator()(LLInventoryItem* item) const
+ {
+ // Clear group & everyone permissions.
+ LLPermissions perm = item->getPermissions();
+ perm.setGroupBits(mAgentID, mGroupID, FALSE, PERM_MODIFY | PERM_MOVE | PERM_COPY);
+ perm.setEveryoneBits(mAgentID, mGroupID, FALSE, PERM_MOVE | PERM_COPY);
+ item->setPermissions(perm);
+
+ // Mark group & everyone permissions for overwrite on the next
+ // rez if it is an object.
+ if(LLAssetType::AT_OBJECT == item->getType())
+ {
+ U32 flags = item->getFlags();
+ flags |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
+ flags |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
+ item->setFlags(flags);
+ }
+
+ // Clear for sale info.
+ item->setSaleInfo(LLSaleInfo::DEFAULT);
+ }
+};
+
+typedef std::list<LLPointer<LLInventoryObject> > InventoryObjectList;
+
+// These functions convert between structured data and an inventroy
+// item, appropriate for serialization.
+LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
+LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
+LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);
+LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat);
+
+#endif // LL_LLINVENTORY_H
diff --git a/indra/llinventory/llnotecard.cpp b/indra/llinventory/llnotecard.cpp
new file mode 100644
index 0000000000..3e994a61aa
--- /dev/null
+++ b/indra/llinventory/llnotecard.cpp
@@ -0,0 +1,286 @@
+/**
+ * @file llnotecard.cpp
+ * @brief LLNotecard class definition
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+#include "llinventory.h"
+#include "llnotecard.h"
+#include "llstreamtools.h"
+
+LLNotecard::LLNotecard(U32 max_text)
+: mMaxText(max_text)
+{
+}
+
+LLNotecard::~LLNotecard()
+{
+}
+
+bool LLNotecard::importEmbeddedItemsStream(std::istream& str)
+{
+ // Version 1 format:
+ // LLEmbeddedItems version 1
+ // {
+ // count <number of entries being used and not deleted>
+ // {
+ // ext char index <index>
+ // <InventoryItem chunk>
+ // }
+ // }
+
+ S32 i;
+ S32 count = 0;
+
+ str >> std::ws >> "LLEmbeddedItems version" >> mEmbeddedVersion >> "\n";
+ if (str.fail())
+ {
+ llwarns << "Invalid Linden text file header" << llendl;
+ goto import_file_failed;
+ }
+
+ if( 1 != mEmbeddedVersion )
+ {
+ llwarns << "Invalid LLEmbeddedItems version: " << mEmbeddedVersion << llendl;
+ goto import_file_failed;
+ }
+
+ str >> std::ws >> "{\n";
+ if(str.fail())
+ {
+ llwarns << "Invalid Linden text file format: missing {" << llendl;
+ goto import_file_failed;
+ }
+
+ str >> std::ws >> "count " >> count >> "\n";
+ if(str.fail())
+ {
+ llwarns << "Invalid LLEmbeddedItems count" << llendl;
+ goto import_file_failed;
+ }
+
+ if((count < 0))
+ {
+ llwarns << "Invalid LLEmbeddedItems count value: " << count << llendl;
+ goto import_file_failed;
+ }
+
+ for(i = 0; i < count; i++)
+ {
+ str >> std::ws >> "{\n";
+ if(str.fail())
+ {
+ llwarns << "Invalid LLEmbeddedItems file format: missing {" << llendl;
+ goto import_file_failed;
+ }
+
+ U32 index = 0;
+ str >> std::ws >> "ext char index " >> index >> "\n";
+ if(str.fail())
+ {
+ llwarns << "Invalid LLEmbeddedItems file format: missing ext char index" << llendl;
+ goto import_file_failed;
+ }
+
+ if( (index < 0) )
+ {
+ llwarns << "Invalid LLEmbeddedItems file format: invalid ext char index: " << index << llendl;
+ goto import_file_failed;
+ }
+
+ str >> std::ws >> "inv_item\t0\n";
+ if(str.fail())
+ {
+ llwarns << "Invalid LLEmbeddedItems file format: missing inv_item" << llendl;
+ goto import_file_failed;
+ }
+
+ LLPointer<LLInventoryItem> item = new LLInventoryItem;
+ if (!item->importLegacyStream(str))
+ {
+ llinfos << "notecard import failed" << llendl;
+ goto import_file_failed;
+ }
+ mItems.push_back(item);
+
+ str >> std::ws >> "}\n";
+ if(str.fail())
+ {
+ llwarns << "Invalid LLEmbeddedItems file format: missing }" << llendl;
+ goto import_file_failed;
+ }
+ }
+
+ str >> std::ws >> "}\n";
+ if(str.fail())
+ {
+ llwarns << "Invalid LLEmbeddedItems file format: missing }" << llendl;
+ goto import_file_failed;
+ }
+
+ return true;
+
+ import_file_failed:
+ return false;
+}
+
+bool LLNotecard::importStream(std::istream& str)
+{
+ // Version 1 format:
+ // Linden text version 1
+ // {
+ // <EmbeddedItemList chunk>
+ // Text length
+ // <ASCII text; 0x80 | index = embedded item>
+ // }
+
+ // Version 2 format: (NOTE: Imports identically to version 1)
+ // Linden text version 2
+ // {
+ // <EmbeddedItemList chunk>
+ // Text length
+ // <UTF8 text; FIRST_EMBEDDED_CHAR + index = embedded item>
+ // }
+
+ str >> std::ws >> "Linden text version " >> mVersion >> "\n";
+ if(str.fail())
+ {
+ llwarns << "Invalid Linden text file header " << llendl;
+ return FALSE;
+ }
+
+ if( 1 != mVersion && 2 != mVersion)
+ {
+ llwarns << "Invalid Linden text file version: " << mVersion << llendl;
+ return FALSE;
+ }
+
+ str >> std::ws >> "{\n";
+ if(str.fail())
+ {
+ llwarns << "Invalid Linden text file format" << llendl;
+ return FALSE;
+ }
+
+ if(!importEmbeddedItemsStream(str))
+ {
+ return FALSE;
+ }
+
+ char line_buf[STD_STRING_BUF_SIZE];
+ str.getline(line_buf, STD_STRING_BUF_SIZE);
+ if(str.fail())
+ {
+ llwarns << "Invalid Linden text length field" << llendl;
+ return FALSE;
+ }
+ line_buf[STD_STRING_STR_LEN] = '\0';
+
+ U32 text_len = 0;
+ if( 1 != sscanf(line_buf, "Text length %d", &text_len) )
+ {
+ llwarns << "Invalid Linden text length field" << llendl;
+ return FALSE;
+ }
+
+ if(text_len > mMaxText)
+ {
+ llwarns << "Invalid Linden text length: " << text_len << llendl;
+ return FALSE;
+ }
+
+ BOOL success = TRUE;
+
+ char* text = new char[text_len + 1];
+ fullread(str, text, text_len);
+ if(str.fail())
+ {
+ llwarns << "Invalid Linden text: text shorter than text length: " << text_len << llendl;
+ success = FALSE;
+ }
+ text[text_len] = '\0';
+
+ if(success)
+ {
+ // Actually set the text
+ mText = text;
+ }
+
+ delete[] text;
+
+ return success;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+bool LLNotecard::exportEmbeddedItemsStream( std::ostream& out_stream )
+{
+ out_stream << "LLEmbeddedItems version 1\n";
+ out_stream << "{\n";
+
+ out_stream << llformat("count %d\n", mItems.size() );
+
+ S32 idx = 0;
+ for (std::vector<LLPointer<LLInventoryItem> >::iterator iter = mItems.begin();
+ iter != mItems.end(); ++iter)
+ {
+ LLInventoryItem* item = *iter;
+ if (item)
+ {
+ out_stream << "{\n";
+ out_stream << llformat("ext char index %d\n", idx );
+ if( !item->exportLegacyStream( out_stream ) )
+ {
+ return FALSE;
+ }
+ out_stream << "}\n";
+ }
+ ++idx;
+ }
+
+ out_stream << "}\n";
+
+ return TRUE;
+}
+
+bool LLNotecard::exportStream( std::ostream& out_stream )
+{
+ out_stream << "Linden text version 2\n";
+ out_stream << "{\n";
+
+ if( !exportEmbeddedItemsStream( out_stream ) )
+ {
+ return FALSE;
+ }
+
+ out_stream << llformat("Text length %d\n", mText.length() );
+ out_stream << mText;
+ out_stream << "}\n";
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+const std::vector<LLPointer<LLInventoryItem> >& LLNotecard::getItems() const
+{
+ return mItems;
+}
+
+LLString& LLNotecard::getText()
+{
+ return mText;
+}
+
+void LLNotecard::setItems(const std::vector<LLPointer<LLInventoryItem> >& items)
+{
+ mItems = items;
+}
+
+void LLNotecard::setText(const LLString& text)
+{
+ mText = text;
+}
diff --git a/indra/llinventory/llnotecard.h b/indra/llinventory/llnotecard.h
new file mode 100644
index 0000000000..5f510a674f
--- /dev/null
+++ b/indra/llinventory/llnotecard.h
@@ -0,0 +1,41 @@
+/**
+ * @file llnotecard.h
+ * @brief LLNotecard class declaration
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_NOTECARD_H
+#define LL_NOTECARD_H
+
+const S32 MAX_NOTECARD_SIZE = 65536;
+
+class LLNotecard
+{
+public:
+ LLNotecard(U32 max_text);
+ virtual ~LLNotecard();
+
+ bool importStream(std::istream& str);
+ bool exportStream(std::ostream& str);
+
+ const std::vector<LLPointer<LLInventoryItem> >& getItems() const;
+ LLString& getText();
+
+ void setItems(const std::vector<LLPointer<LLInventoryItem> >& items);
+ void setText(const LLString& text);
+ S32 getVersion() { return mVersion; }
+ S32 getEmbeddedVersion() { return mEmbeddedVersion; }
+
+private:
+ bool importEmbeddedItemsStream(std::istream& str);
+ bool exportEmbeddedItemsStream(std::ostream& str);
+ std::vector<LLPointer<LLInventoryItem> > mItems;
+ LLString mText;
+ U32 mMaxText;
+ S32 mVersion;
+ S32 mEmbeddedVersion;
+};
+
+#endif /* LL_NOTECARD_H */
diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp
new file mode 100644
index 0000000000..a19c2216df
--- /dev/null
+++ b/indra/llinventory/llparcel.cpp
@@ -0,0 +1,1813 @@
+/**
+ * @file llparcel.cpp
+ * @brief A land parcel.
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "indra_constants.h"
+#include <iostream>
+
+#include "llparcel.h"
+#include "llstreamtools.h"
+
+#include "llmath.h"
+#include "lltransactiontypes.h"
+#include "lltransactionflags.h"
+#include "message.h"
+#include "u64.h"
+
+static const F32 SOME_BIG_NUMBER = 1000.0f;
+static const F32 SOME_BIG_NEG_NUMBER = -1000.0f;
+static const char* PARCEL_OWNERSHIP_STATUS_STRING[LLParcel::OS_COUNT] =
+{
+ "leased",
+ "lease_pending",
+ "abandoned"
+};
+
+// NOTE: Adding parcel categories also requires updating:
+// * newview/app_settings/floater_directory.xml category combobox
+// * Web site "create event" tools
+static const char* PARCEL_CATEGORY_STRING[LLParcel::C_COUNT] =
+{
+ "none",
+ "linden",
+ "adult",
+ "arts",
+ "store", // "business" legacy name
+ "educational",
+ "game", // "gaming" legacy name
+ "gather", // "hangout" legacy name
+ "newcomer",
+ "park",
+ "home", // "residential" legacy name
+ "shopping",
+ "stage",
+ "other",
+};
+static const char* PARCEL_CATEGORY_UI_STRING[LLParcel::C_COUNT + 1] =
+{
+ "None",
+ "Linden Location",
+ "Adult",
+ "Arts & Culture",
+ "Business",
+ "Educational",
+ "Gaming",
+ "Hangout",
+ "Newcomer Friendly",
+ "Parks & Nature",
+ "Residential",
+ "Shopping",
+ "Stage",
+ "Other",
+ "Any", // valid string for parcel searches
+};
+
+static const char* PARCEL_ACTION_STRING[LLParcel::A_COUNT + 1] =
+{
+ "create",
+ "release",
+ "absorb",
+ "absorbed",
+ "divide",
+ "division",
+ "acquire",
+ "relinquish",
+ "confirm",
+ "unknown"
+};
+
+// Timeouts for parcels
+// default is 21 days * 24h/d * 60m/h * 60s/m *1000000 usec/s = 1814400000000
+const U64 DEFAULT_USEC_CONVERSION_TIMEOUT = U64L(1814400000000);
+// ***** TESTING is 10 minutes
+//const U64 DEFAULT_USEC_CONVERSION_TIMEOUT = U64L(600000000);
+
+// group is 60 days * 24h/d * 60m/h * 60s/m *1000000 usec/s = 5184000000000
+const U64 GROUP_USEC_CONVERSION_TIMEOUT = U64L(5184000000000);
+// ***** TESTING is 10 minutes
+//const U64 GROUP_USEC_CONVERSION_TIMEOUT = U64L(600000000);
+
+// default sale timeout is 2 days -> 172800000000
+const U64 DEFAULT_USEC_SALE_TIMEOUT = U64L(172800000000);
+// ***** TESTING is 10 minutes
+//const U64 DEFAULT_USEC_SALE_TIMEOUT = U64L(600000000);
+
+// more grace period extensions.
+const U64 SEVEN_DAYS_IN_USEC = U64L(604800000000);
+
+// if more than 100,000s before sale revert, and no extra extension
+// has been given, go ahead and extend it more. That's about 1.2 days.
+const S32 EXTEND_GRACE_IF_MORE_THAN_SEC = 100000;
+
+
+const char* ownership_status_to_string(LLParcel::EOwnershipStatus status);
+LLParcel::EOwnershipStatus ownership_string_to_status(const char* s);
+//const char* revert_action_to_string(LLParcel::ESaleTimerExpireAction action);
+//LLParcel::ESaleTimerExpireAction revert_string_to_action(const char* s);
+const char* category_to_string(LLParcel::ECategory category);
+const char* category_to_ui_string(LLParcel::ECategory category);
+LLParcel::ECategory category_string_to_category(const char* s);
+LLParcel::ECategory category_ui_string_to_category(const char* s);
+
+LLParcel::LLParcel()
+{
+ init(LLUUID::null, TRUE, FALSE, FALSE, 0, 0, 0, 0, 0, 1.f, 0);
+}
+
+
+LLParcel::LLParcel(const LLUUID &owner_id,
+ BOOL modify, BOOL terraform, BOOL damage,
+ time_t claim_date, S32 claim_price_per_meter,
+ S32 rent_price_per_meter, S32 area, S32 sim_object_limit, F32 parcel_object_bonus,
+ BOOL is_group_owned)
+{
+ init( owner_id, modify, terraform, damage, claim_date,
+ claim_price_per_meter, rent_price_per_meter, area, sim_object_limit, parcel_object_bonus,
+ is_group_owned);
+}
+
+
+// virtual
+LLParcel::~LLParcel()
+{
+ // user list cleaned up by LLDynamicArray destructor.
+}
+
+void LLParcel::init(const LLUUID &owner_id,
+ BOOL modify, BOOL terraform, BOOL damage,
+ time_t claim_date, S32 claim_price_per_meter,
+ S32 rent_price_per_meter, S32 area, S32 sim_object_limit, F32 parcel_object_bonus,
+ BOOL is_group_owned)
+{
+ mID.setNull();
+ mOwnerID = owner_id;
+ mGroupOwned = is_group_owned;
+ mClaimDate = claim_date;
+ mClaimPricePerMeter = claim_price_per_meter;
+ mRentPricePerMeter = rent_price_per_meter;
+ mArea = area;
+ mDiscountRate = 1.0f;
+ mDrawDistance = 512.f;
+
+ mUserLookAt.setVec(0.0f, 0.f, 0.f);
+ // Default to using the parcel's landing point, if any.
+ mLandingType = L_LANDING_POINT;
+
+ // *FIX: if owner_id != null, should be owned or sale pending,
+ // investigate init callers.
+ mStatus = OS_NONE;
+ mCategory = C_NONE;
+ mAuthBuyerID.setNull();
+ //mBuyerID.setNull();
+ //mJoinNeighbors = 0x0;
+ mSaleTimerExpires.setTimerExpirySec(0);
+ mSaleTimerExpires.stop();
+ mGraceExtension = 0;
+ //mExpireAction = STEA_REVERT;
+ mRecordTransaction = FALSE;
+
+ mAuctionID = 0;
+ mIsReservedForNewbie = FALSE;
+ mInEscrow = false;
+
+ mParcelFlags = PF_DEFAULT;
+ setParcelFlag(PF_CREATE_OBJECTS, modify);
+ setParcelFlag(PF_ALLOW_TERRAFORM, terraform);
+ setParcelFlag(PF_ALLOW_DAMAGE, damage);
+
+ mSalePrice = 10000;
+ setName(NULL);
+ setDesc(NULL);
+ setMusicURL(NULL);
+ setMediaURL(NULL);
+ mMediaID.setNull();
+ mMediaAutoScale = 0;
+
+ mGroupID.setNull();
+
+ mPassPrice = PARCEL_PASS_PRICE_DEFAULT;
+ mPassHours = PARCEL_PASS_HOURS_DEFAULT;
+
+ mAABBMin.setVec(SOME_BIG_NUMBER, SOME_BIG_NUMBER, SOME_BIG_NUMBER);
+ mAABBMax.setVec(SOME_BIG_NEG_NUMBER, SOME_BIG_NEG_NUMBER, SOME_BIG_NEG_NUMBER);
+
+ mLocalID = 0;
+
+ //mSimWidePrimCorrection = 0;
+ setMaxPrimCapacity((S32)(sim_object_limit * area / (F32)(REGION_WIDTH_METERS * REGION_WIDTH_METERS)));
+ setSimWideMaxPrimCapacity(0);
+ setSimWidePrimCount(0);
+ setOwnerPrimCount(0);
+ setGroupPrimCount(0);
+ setOtherPrimCount(0);
+ setSelectedPrimCount(0);
+ setTempPrimCount(0);
+ setCleanOtherTime(0);
+ setParcelPrimBonus(parcel_object_bonus);
+
+ setPreviousOwnerID(LLUUID::null);
+ setPreviouslyGroupOwned(FALSE);
+}
+
+void LLParcel::overrideOwner(const LLUUID& owner_id, BOOL is_group_owned)
+{
+ // Override with system permission (LLUUID::null)
+ // Overridden parcels have no group
+ mOwnerID = owner_id;
+ mGroupOwned = is_group_owned;
+ if(mGroupOwned)
+ {
+ mGroupID = mOwnerID;
+ }
+ else
+ {
+ mGroupID.setNull();
+ }
+ mInEscrow = false;
+}
+
+void LLParcel::overrideParcelFlags(U32 flags)
+{
+ mParcelFlags = flags;
+}
+
+void set_std_string(const char* src, std::string& dest)
+{
+ if(src)
+ {
+ dest.assign(src);
+ }
+ else
+ {
+#if (LL_LINUX && __GNUC__ < 3)
+ dest.assign(std::string(""));
+#else
+ dest.clear();
+#endif
+ }
+}
+
+void LLParcel::setName(const char* name)
+{
+ // The escaping here must match the escaping in the database
+ // abstraction layer.
+ set_std_string(name, mName);
+ LLStringFn::replace_nonprintable(mName, LL_UNKNOWN_CHAR);
+}
+
+void LLParcel::setDesc(const char* desc)
+{
+ // The escaping here must match the escaping in the database
+ // abstraction layer.
+ set_std_string(desc, mDesc);
+ mDesc = rawstr_to_utf8(mDesc);
+}
+
+void LLParcel::setMusicURL(const char* url)
+{
+ set_std_string(url, mMusicURL);
+
+ // The escaping here must match the escaping in the database
+ // abstraction layer.
+ // This should really filter the url in some way. Other than
+ // simply requiring non-printable.
+ LLStringFn::replace_nonprintable(mMusicURL, LL_UNKNOWN_CHAR);
+}
+
+void LLParcel::setMediaURL(const char* url)
+{
+ set_std_string(url, mMediaURL);
+
+ // The escaping here must match the escaping in the database
+ // abstraction layer if it's ever added.
+ // This should really filter the url in some way. Other than
+ // simply requiring non-printable.
+ LLStringFn::replace_nonprintable(mMediaURL, LL_UNKNOWN_CHAR);
+}
+
+// virtual
+void LLParcel::setLocalID(S32 local_id)
+{
+ mLocalID = local_id;
+}
+
+void LLParcel::setParcelFlag(U32 flag, BOOL b)
+{
+ if (b)
+ {
+ mParcelFlags |= flag;
+ }
+ else
+ {
+ mParcelFlags &= ~flag;
+ }
+}
+
+
+BOOL LLParcel::allowModifyBy(const LLUUID &agent_id, const LLUUID &group_id) const
+{
+ if (agent_id == LLUUID::null)
+ {
+ // system always can enter
+ return TRUE;
+ }
+ else if (isPublic())
+ {
+ return TRUE;
+ }
+ else if (agent_id == mOwnerID)
+ {
+ // owner can always perform operations
+ return TRUE;
+ }
+ else if (mParcelFlags & PF_CREATE_OBJECTS)
+ {
+ return TRUE;
+ }
+ else if ((mParcelFlags & PF_CREATE_GROUP_OBJECTS)
+ && group_id.notNull() )
+ {
+ return (getGroupID() == group_id);
+ }
+
+ return FALSE;
+}
+
+BOOL LLParcel::allowTerraformBy(const LLUUID &agent_id) const
+{
+ if (agent_id == LLUUID::null)
+ {
+ // system always can enter
+ return TRUE;
+ }
+ else if(OS_LEASED == mStatus)
+ {
+ if(agent_id == mOwnerID)
+ {
+ // owner can modify leased land
+ return TRUE;
+ }
+ else
+ {
+ // otherwise check other people
+ return mParcelFlags & PF_ALLOW_TERRAFORM;
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+bool LLParcel::isAgentBlockedFromParcel(LLParcel* parcelp,
+ const LLUUID& agent_id,
+ const std::vector<LLUUID>& group_ids,
+ const BOOL is_agent_identified,
+ const BOOL is_agent_transacted)
+{
+ S32 current_group_access = parcelp->blockAccess(agent_id, LLUUID::null, is_agent_identified, is_agent_transacted);
+ S32 count;
+ bool is_allowed = (current_group_access == BA_ALLOWED) ? true: false;
+ LLUUID group_id;
+
+ count = group_ids.size();
+ for (int i = 0; i < count && !is_allowed; i++)
+ {
+ group_id = group_ids[i];
+ current_group_access = parcelp->blockAccess(agent_id, group_id, is_agent_identified, is_agent_transacted);
+
+ if (current_group_access == BA_ALLOWED) is_allowed = true;
+ }
+
+ return !is_allowed;
+}
+
+BOOL LLParcel::isAgentBanned(const LLUUID& agent_id) const
+{
+ // Test ban list
+ if (getParcelFlag(PF_USE_BAN_LIST)
+ && (mBanList.find(agent_id) != mBanList.end()))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+S32 LLParcel::blockAccess(const LLUUID& agent_id, const LLUUID& group_id,
+ const BOOL is_agent_identified,
+ const BOOL is_agent_transacted) const
+{
+ // Test ban list
+ if (isAgentBanned(agent_id))
+ {
+ return BA_BANNED;
+ }
+
+ // Always allow owner on (unless he banned himself, useful for
+ // testing). We will also allow estate owners/managers in if they
+ // are not explicitly banned.
+ if (agent_id == mOwnerID)
+ {
+ return BA_ALLOWED;
+ }
+
+ // Special case when using pass list where group access is being restricted but not
+ // using access list. In this case group members are allowed only if they buy a pass.
+ // We return BA_NOT_IN_LIST if not in list
+ BOOL passWithGroup = getParcelFlag(PF_USE_PASS_LIST) && !getParcelFlag(PF_USE_ACCESS_LIST)
+ && getParcelFlag(PF_USE_ACCESS_GROUP) && !mGroupID.isNull() && group_id == mGroupID;
+
+
+ // Test group list
+ if (getParcelFlag(PF_USE_ACCESS_GROUP)
+ && !mGroupID.isNull()
+ && group_id == mGroupID
+ && !passWithGroup)
+ {
+ return BA_ALLOWED;
+ }
+
+ // Test access list
+ if (getParcelFlag(PF_USE_ACCESS_LIST) || passWithGroup )
+ {
+ if (mAccessList.find(agent_id) != mAccessList.end())
+ {
+ return BA_ALLOWED;
+ }
+
+ return BA_NOT_ON_LIST;
+ }
+
+ // If we're not doing any other limitations, all users
+ // can enter, unless
+ if ( !getParcelFlag(PF_USE_ACCESS_GROUP)
+ && !getParcelFlag(PF_USE_ACCESS_LIST))
+ {
+ //If the land is group owned, and you are in the group, bypass these checks
+ if(getIsGroupOwned() && group_id == mGroupID)
+ {
+ return BA_ALLOWED;
+ }
+
+ // Test for "payment" access levels
+ // Anonymous - No Payment Info on File
+ if(getParcelFlag(PF_DENY_ANONYMOUS) && !is_agent_identified && !is_agent_transacted)
+ {
+ return BA_NO_ACCESS_LEVEL;
+ }
+ // Identified - Payment Info on File
+ // Must check to make sure we're only banning Identified, since Transacted accounts
+ // also have their identified flag set
+ if(getParcelFlag(PF_DENY_IDENTIFIED) && is_agent_identified && !is_agent_transacted)
+ {
+ return BA_NO_ACCESS_LEVEL;
+ }
+ // Transacted - Payment Info Used
+ if(getParcelFlag(PF_DENY_TRANSACTED) && is_agent_transacted)
+ {
+ return BA_NO_ACCESS_LEVEL;
+ }
+ return BA_ALLOWED;
+ }
+
+ return BA_NOT_IN_GROUP;
+
+}
+
+
+void LLParcel::setArea(S32 area, S32 sim_object_limit)
+{
+ mArea = area;
+ setMaxPrimCapacity((S32)(sim_object_limit * area / (F32)(REGION_WIDTH_METERS * REGION_WIDTH_METERS)));
+}
+
+void LLParcel::setDiscountRate(F32 rate)
+{
+ // this is to make sure that the rate is at least sane - this is
+ // not intended to enforce economy rules. It only enfoces that the
+ // rate is a scaler between 0 and 1.
+ mDiscountRate = llclampf(rate);
+}
+
+
+//-----------------------------------------------------------
+// File input and output
+//-----------------------------------------------------------
+
+
+// WARNING: Area will be wrong until you calculate it.
+BOOL LLParcel::importStream(std::istream& input_stream)
+{
+ U32 setting;
+ S32 secs_until_revert = 0;
+
+ skip_to_end_of_next_keyword("{", input_stream);
+ if (!input_stream.good())
+ {
+ llwarns << "LLParcel::importStream() - bad input_stream" << llendl;
+ return FALSE;
+ }
+
+ while (input_stream.good())
+ {
+ skip_comments_and_emptyspace(input_stream);
+ LLString line, keyword, value;
+ get_line(line, input_stream, MAX_STRING);
+ get_keyword_and_value(keyword, value, line);
+
+ if ("}" == keyword)
+ {
+ break;
+ }
+ else if ("parcel_id" == keyword)
+ {
+ mID.set(value.c_str());
+ }
+ else if ("status" == keyword)
+ {
+ mStatus = ownership_string_to_status(value.c_str());
+ }
+ else if ("category" == keyword)
+ {
+ mCategory = category_string_to_category(value.c_str());
+ }
+ else if ("local_id" == keyword)
+ {
+ LLString::convertToS32(value, mLocalID);
+ }
+ else if ("name" == keyword)
+ {
+ setName( value.c_str() );
+ }
+ else if ("desc" == keyword)
+ {
+ setDesc( value.c_str() );
+ }
+ else if ("music_url" == keyword)
+ {
+ setMusicURL( value.c_str() );
+ }
+ else if ("media_url" == keyword)
+ {
+ setMediaURL( value.c_str() );
+ }
+ else if ("media_id" == keyword)
+ {
+ mMediaID.set( value.c_str() );
+ }
+ else if ("media_auto_scale" == keyword)
+ {
+ LLString::convertToU8(value, mMediaAutoScale);
+ }
+ else if ("owner_id" == keyword)
+ {
+ mOwnerID.set( value.c_str() );
+ }
+ else if ("group_owned" == keyword)
+ {
+ LLString::convertToBOOL(value, mGroupOwned);
+ }
+ else if ("clean_other_time" == keyword)
+ {
+ S32 time;
+ LLString::convertToS32(value, time);
+ setCleanOtherTime(time);
+ }
+ else if ("auth_buyer_id" == keyword)
+ {
+ mAuthBuyerID.set(value.c_str());
+ }
+ else if ("snapshot_id" == keyword)
+ {
+ mSnapshotID.set(value.c_str());
+ }
+ else if ("user_location" == keyword)
+ {
+ sscanf(value.c_str(), "%f %f %f",
+ &mUserLocation.mV[VX],
+ &mUserLocation.mV[VY],
+ &mUserLocation.mV[VZ]);
+ }
+ else if ("user_look_at" == keyword)
+ {
+ sscanf(value.c_str(), "%f %f %f",
+ &mUserLookAt.mV[VX],
+ &mUserLookAt.mV[VY],
+ &mUserLookAt.mV[VZ]);
+ }
+ else if ("landing_type" == keyword)
+ {
+ S32 landing_type = 0;
+ LLString::convertToS32(value, landing_type);
+ mLandingType = (ELandingType) landing_type;
+ }
+ else if ("join_neighbors" == keyword)
+ {
+ llinfos << "found deprecated keyword join_neighbors" << llendl;
+ }
+ else if ("revert_sale" == keyword)
+ {
+ LLString::convertToS32(value, secs_until_revert);
+ if (secs_until_revert > 0)
+ {
+ mSaleTimerExpires.start();
+ mSaleTimerExpires.setTimerExpirySec((F32)secs_until_revert);
+ }
+ }
+ else if("extended_grace" == keyword)
+ {
+ LLString::convertToS32(value, mGraceExtension);
+ }
+ else if ("user_list_type" == keyword)
+ {
+ // deprecated
+ }
+ else if("auction_id" == keyword)
+ {
+ LLString::convertToU32(value, mAuctionID);
+ }
+ else if("reserved_newbie" == keyword)
+ {
+ LLString::convertToBOOL(value, mIsReservedForNewbie);
+ }
+ else if ("allow_modify" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_CREATE_OBJECTS, setting);
+ }
+ else if ("allow_group_modify" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_CREATE_GROUP_OBJECTS, setting);
+ }
+ else if ("allow_all_object_entry" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_ALL_OBJECT_ENTRY, setting);
+ }
+ else if ("allow_group_object_entry" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_GROUP_OBJECT_ENTRY, setting);
+ }
+ else if ("allow_deed_to_group" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_DEED_TO_GROUP, setting);
+ }
+ else if("contribute_with_deed" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_CONTRIBUTE_WITH_DEED, setting);
+ }
+ else if ("allow_terraform" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_TERRAFORM, setting);
+ }
+ else if ("allow_damage" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_DAMAGE, setting);
+ }
+ else if ("allow_fly" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_FLY, setting);
+ }
+ else if ("allow_landmark" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_LANDMARK, setting);
+ }
+ else if ("sound_local" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_SOUND_LOCAL, setting);
+ }
+ else if ("allow_group_scripts" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_GROUP_SCRIPTS, setting);
+ }
+ else if ("allow_scripts" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_OTHER_SCRIPTS, setting);
+ }
+ else if ("for_sale" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_FOR_SALE, setting);
+ }
+ else if ("sell_w_objects" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_SELL_PARCEL_OBJECTS, setting);
+ }
+ else if ("use_pass_list" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_USE_PASS_LIST, setting);
+ }
+ else if ("show_directory" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_SHOW_DIRECTORY, setting);
+ }
+ else if ("allow_publish" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_ALLOW_PUBLISH, setting);
+ }
+ else if ("mature_publish" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_MATURE_PUBLISH, setting);
+ }
+ else if ("claim_date" == keyword)
+ {
+ // BUG: This will fail when time rolls over in 2038.
+ S32 time;
+ LLString::convertToS32(value, time);
+ mClaimDate = time;
+ }
+ else if ("claim_price" == keyword)
+ {
+ LLString::convertToS32(value, mClaimPricePerMeter);
+ }
+ else if ("rent_price" == keyword)
+ {
+ LLString::convertToS32(value, mRentPricePerMeter);
+ }
+ else if ("discount_rate" == keyword)
+ {
+ LLString::convertToF32(value, mDiscountRate);
+ }
+ else if ("draw_distance" == keyword)
+ {
+ LLString::convertToF32(value, mDrawDistance);
+ }
+ else if ("sale_price" == keyword)
+ {
+ LLString::convertToS32(value, mSalePrice);
+ }
+ else if ("pass_price" == keyword)
+ {
+ LLString::convertToS32(value, mPassPrice);
+ }
+ else if ("pass_hours" == keyword)
+ {
+ LLString::convertToF32(value, mPassHours);
+ }
+ else if ("box" == keyword)
+ {
+ // deprecated
+ }
+ else if ("aabb_min" == keyword)
+ {
+ sscanf(value.c_str(), "%f %f %f",
+ &mAABBMin.mV[VX], &mAABBMin.mV[VY], &mAABBMin.mV[VZ]);
+ }
+ else if ("use_access_group" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_USE_ACCESS_GROUP, setting);
+ }
+ else if ("use_access_list" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_USE_ACCESS_LIST, setting);
+ }
+ else if ("use_ban_list" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_USE_BAN_LIST, setting);
+ }
+ else if ("group_name" == keyword)
+ {
+ llinfos << "found deprecated keyword group_name" << llendl;
+ }
+ else if ("group_id" == keyword)
+ {
+ mGroupID.set( value.c_str() );
+ }
+ // TODO: DEPRECATED FLAG
+ // Flag removed from simstate files in 1.11.1
+ // Remove at some point where we have guarenteed this flag
+ // no longer exists anywhere in simstate files.
+ else if ("require_identified" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_DENY_ANONYMOUS, setting);
+ }
+ // TODO: DEPRECATED FLAG
+ // Flag removed from simstate files in 1.11.1
+ // Remove at some point where we have guarenteed this flag
+ // no longer exists anywhere in simstate files.
+ else if ("require_transacted" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_DENY_ANONYMOUS, setting);
+ setParcelFlag(PF_DENY_IDENTIFIED, setting);
+ }
+ else if ("restrict_pushobject" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_RESTRICT_PUSHOBJECT, setting);
+ }
+ else if ("deny_anonymous" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_DENY_ANONYMOUS, setting);
+ }
+ else if ("deny_identified" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_DENY_IDENTIFIED, setting);
+ }
+ else if ("deny_transacted" == keyword)
+ {
+ LLString::convertToU32(value, setting);
+ setParcelFlag(PF_DENY_TRANSACTED, setting);
+ }
+ else if ("access_list" == keyword)
+ {
+ S32 entry_count = 0;
+ LLString::convertToS32(value, entry_count);
+ for (S32 i = 0; i < entry_count; i++)
+ {
+ LLAccessEntry entry;
+ if (importAccessEntry(input_stream, &entry))
+ {
+ mAccessList[entry.mID] = entry;
+ }
+ }
+ }
+ else if ("ban_list" == keyword)
+ {
+ S32 entry_count = 0;
+ LLString::convertToS32(value, entry_count);
+ for (S32 i = 0; i < entry_count; i++)
+ {
+ LLAccessEntry entry;
+ if (importAccessEntry(input_stream, &entry))
+ {
+ mBanList[entry.mID] = entry;
+ }
+ }
+ }
+ else if ("renter_list" == keyword)
+ {
+ /*
+ S32 entry_count = 0;
+ LLString::convertToS32(value, entry_count);
+ for (S32 i = 0; i < entry_count; i++)
+ {
+ LLAccessEntry entry;
+ if (importAccessEntry(input_stream, &entry))
+ {
+ mRenterList.put(entry);
+ }
+ }*/
+ }
+ else if ("pass_list" == keyword)
+ {
+ // legacy - put into access list
+ S32 entry_count = 0;
+ LLString::convertToS32(value, entry_count);
+ for (S32 i = 0; i < entry_count; i++)
+ {
+ LLAccessEntry entry;
+ if (importAccessEntry(input_stream, &entry))
+ {
+ mAccessList[entry.mID] = entry;
+ }
+ }
+ }
+
+ else
+ {
+ llwarns << "Unknown keyword in parcel section: <"
+ << keyword << ">" << llendl;
+ }
+ }
+
+ // this code block detects if we have loaded a 1.1 simstate file,
+ // and follows the conversion rules specified in
+ // design_docs/land/pay_for_parcel.txt.
+ F32 time_to_expire = 0.0f;
+ if(mID.isNull())
+ {
+ mID.generate();
+ mStatus = OS_LEASE_PENDING;
+ //mBuyerID = mOwnerID;
+ if(getIsGroupOwned())
+ {
+ time_to_expire += GROUP_USEC_CONVERSION_TIMEOUT / SEC_TO_MICROSEC;
+ }
+ else
+ {
+ time_to_expire += DEFAULT_USEC_CONVERSION_TIMEOUT / SEC_TO_MICROSEC;
+ }
+ //mExpireAction = STEA_PUBLIC;
+ mRecordTransaction = TRUE;
+ }
+
+ // this code block deals with giving an extension to pending
+ // parcels to the midday of 2004-01-19 if they were originally set
+ // for some time on 2004-01-12.
+ if((0 == mGraceExtension)
+ && (EXTEND_GRACE_IF_MORE_THAN_SEC < secs_until_revert))
+ {
+ const S32 NEW_CONVERSION_DATE = 1074538800; // 2004-01-19T11:00:00
+ time_t now = time(NULL); // now in epoch
+ secs_until_revert = (S32)(NEW_CONVERSION_DATE - now);
+ time_to_expire = (F32)secs_until_revert;
+ mGraceExtension = 1;
+ }
+
+ // This code block adds yet another week to the deadline. :(
+ if(1 == mGraceExtension)
+ {
+ time_to_expire += SEVEN_DAYS_IN_USEC / SEC_TO_MICROSEC;
+ mGraceExtension = 2;
+ }
+
+ if (time_to_expire > 0)
+ {
+ mSaleTimerExpires.setTimerExpirySec(time_to_expire);
+ mSaleTimerExpires.start();
+ }
+
+ // successful import
+ return TRUE;
+}
+
+
+BOOL LLParcel::importAccessEntry(std::istream& input_stream, LLAccessEntry* entry)
+{
+ skip_to_end_of_next_keyword("{", input_stream);
+ while (input_stream.good())
+ {
+ skip_comments_and_emptyspace(input_stream);
+ LLString line, keyword, value;
+ get_line(line, input_stream, MAX_STRING);
+ get_keyword_and_value(keyword, value, line);
+
+ if ("}" == keyword)
+ {
+ break;
+ }
+ else if ("id" == keyword)
+ {
+ entry->mID.set( value.c_str() );
+ }
+ else if ("name" == keyword)
+ {
+ // deprecated
+ }
+ else if ("time" == keyword)
+ {
+ S32 when;
+ LLString::convertToS32(value, when);
+ entry->mTime = when;
+ }
+ else if ("flags" == keyword)
+ {
+ U32 setting;
+ LLString::convertToU32(value, setting);
+ entry->mFlags = setting;
+ }
+ else
+ {
+ llwarns << "Unknown keyword in parcel access entry section: <"
+ << keyword << ">" << llendl;
+ }
+ }
+ return input_stream.good();
+}
+
+BOOL LLParcel::exportStream(std::ostream& output_stream)
+{
+ S32 setting;
+ char id_string[MAX_STRING];
+
+ std::ios::fmtflags old_flags = output_stream.flags();
+ output_stream.setf(std::ios::showpoint);
+ output_stream << "\t{\n";
+
+ mID.toString(id_string);
+ output_stream << "\t\t parcel_id " << id_string << "\n";
+ output_stream << "\t\t status " << ownership_status_to_string(mStatus) << "\n";
+ output_stream << "\t\t category " << category_to_string(mCategory) << "\n";
+
+ output_stream << "\t\t local_id " << mLocalID << "\n";
+
+ const char* name = (mName.empty() ? "" : mName.c_str() );
+ output_stream << "\t\t name " << name << "\n";
+
+ const char* desc = (mDesc.empty() ? "" : mDesc.c_str() );
+ output_stream << "\t\t desc " << desc << "\n";
+
+ const char* music_url = (mMusicURL.empty() ? "" : mMusicURL.c_str() );
+ output_stream << "\t\t music_url " << music_url << "\n";
+
+ const char* media_url = (mMediaURL.empty() ? "" : mMediaURL.c_str() );
+ output_stream << "\t\t media_url " << media_url << "\n";
+
+ output_stream << "\t\t media_auto_scale " << (mMediaAutoScale ? 1 : 0) << "\n";
+
+ mMediaID.toString(id_string);
+ output_stream << "\t\t media_id " << id_string << "\n";
+
+ mOwnerID.toString(id_string);
+ output_stream << "\t\t owner_id " << id_string << "\n";
+ output_stream << "\t\t group_owned " << (mGroupOwned ? 1 : 0) << "\n";
+ output_stream << "\t\t clean_other_time " << getCleanOtherTime() << "\n";
+
+ if(!mAuthBuyerID.isNull())
+ {
+ mAuthBuyerID.toString(id_string);
+ output_stream << "\t\t auth_buyer_id " << id_string << "\n";
+ }
+ if (!mSnapshotID.isNull())
+ {
+ mSnapshotID.toString(id_string);
+ output_stream << "\t\t snapshot_id " << id_string << "\n";
+ }
+ if (!mUserLocation.isExactlyZero())
+ {
+ output_stream << "\t\t user_location "
+ << (F64)mUserLocation.mV[VX]
+ << " " << (F64)mUserLocation.mV[VY]
+ << " " << (F64)mUserLocation.mV[VZ] << "\n";
+ output_stream << "\t\t user_look_at "
+ << (F64)mUserLookAt.mV[VX]
+ << " " << (F64)mUserLookAt.mV[VY]
+ << " " << (F64)mUserLookAt.mV[VZ] << "\n";
+ }
+ output_stream << "\t\t landing_type " << mLandingType << "\n";
+ //if(mJoinNeighbors)
+ //{
+ // output_stream << "\t\t join_neighbors " << mJoinNeighbors << "\n";
+ //}
+ if(mSaleTimerExpires.getStarted())
+ {
+ S32 dt_sec = (S32) mSaleTimerExpires.getRemainingTimeF32()+60; // Add a minute to prevent race conditions
+ output_stream << "\t\t revert_sale " << dt_sec << "\n";
+ //output_stream << "\t\t revert_action " << revert_action_to_string(mExpireAction) << "\n";
+ output_stream << "\t\t extended_grace " << mGraceExtension << "\n";
+ }
+
+ if(0 != mAuctionID)
+ {
+ output_stream << "\t\t auction_id " << mAuctionID << "\n";
+ }
+ if(mIsReservedForNewbie)
+ {
+ output_stream << "\t\t reserved_newbie " << mIsReservedForNewbie << "\n";
+ }
+
+ output_stream << "\t\t allow_modify " << getAllowModify() << "\n";
+ output_stream << "\t\t allow_group_modify " << getAllowGroupModify() << "\n";
+ output_stream << "\t\t allow_all_object_entry " << getAllowAllObjectEntry() << "\n";
+ output_stream << "\t\t allow_group_object_entry " << getAllowGroupObjectEntry() << "\n";
+ output_stream << "\t\t allow_terraform " << getAllowTerraform() << "\n";
+ output_stream << "\t\t allow_deed_to_group " << getAllowDeedToGroup() << "\n";
+ output_stream << "\t\t contribute_with_deed " << getContributeWithDeed() << "\n";
+ output_stream << "\t\t allow_damage " << getAllowDamage() << "\n";
+ output_stream << "\t\t claim_date " << (S32)mClaimDate << "\n";
+ output_stream << "\t\t claim_price " << mClaimPricePerMeter << "\n";
+ output_stream << "\t\t rent_price " << mRentPricePerMeter << "\n";
+ output_stream << "\t\t discount_rate " << mDiscountRate << "\n";
+ output_stream << "\t\t allow_fly " << (getAllowFly() ? 1 : 0) << "\n";
+ output_stream << "\t\t allow_landmark " << (getAllowLandmark() ? 1 : 0) << "\n";
+ output_stream << "\t\t sound_local " << (getSoundLocal() ? 1 : 0) << "\n";
+ output_stream << "\t\t allow_scripts " << (getAllowOtherScripts() ? 1 : 0) << "\n";
+ output_stream << "\t\t allow_group_scripts " << (getAllowGroupScripts() ? 1 : 0) << "\n";
+ output_stream << "\t\t for_sale " << (getForSale() ? 1 : 0) << "\n";
+ output_stream << "\t\t sell_w_objects " << (getSellWithObjects() ? 1 : 0) << "\n";
+ output_stream << "\t\t draw_distance " << mDrawDistance << "\n";
+ output_stream << "\t\t sale_price " << mSalePrice << "\n";
+
+ setting = (getParcelFlag(PF_USE_ACCESS_GROUP) ? 1 : 0);
+ output_stream << "\t\t use_access_group " << setting << "\n";
+
+ setting = (getParcelFlag(PF_USE_ACCESS_LIST) ? 1 : 0);
+ output_stream << "\t\t use_access_list " << setting << "\n";
+
+ setting = (getParcelFlag(PF_USE_BAN_LIST) ? 1 : 0);
+ output_stream << "\t\t use_ban_list " << setting << "\n";
+
+ mGroupID.toString(id_string);
+ output_stream << "\t\t group_id " << id_string << "\n";
+
+ //const char* group_name
+ // = (mGroupName.isEmpty() ? "" : mGroupName.c_str() );
+ //output_stream << "\t\t group_name " << group_name << "\n";
+
+ setting = (getParcelFlag(PF_USE_PASS_LIST) ? 1 : 0);
+ output_stream << "\t\t use_pass_list " << setting << "\n";
+
+ output_stream << "\t\t pass_price " << mPassPrice << "\n";
+ output_stream << "\t\t pass_hours " << mPassHours << "\n";
+
+ setting = (getParcelFlag(PF_SHOW_DIRECTORY) ? 1 : 0);
+ output_stream << "\t\t show_directory " << setting << "\n";
+
+ setting = (getParcelFlag(PF_ALLOW_PUBLISH) ? 1 : 0);
+ output_stream << "\t\t allow_publish " << setting << "\n";
+
+ setting = (getParcelFlag(PF_MATURE_PUBLISH) ? 1 : 0);
+ output_stream << "\t\t mature_publish " << setting << "\n";
+
+ setting = (getParcelFlag(PF_DENY_ANONYMOUS) ? 1 : 0);
+ output_stream << "\t\t deny_anonymous " << setting << "\n";
+
+ setting = (getParcelFlag(PF_DENY_IDENTIFIED) ? 1 : 0);
+ output_stream << "\t\t deny_identified " << setting << "\n";
+
+ setting = (getParcelFlag(PF_DENY_TRANSACTED) ? 1 : 0);
+ output_stream << "\t\t deny_transacted " << setting << "\n";
+
+ setting = (getParcelFlag(PF_RESTRICT_PUSHOBJECT) ? 1 : 0);
+ output_stream << "\t\t restrict_pushobject " << setting << "\n";
+
+ output_stream << "\t\t aabb_min "
+ << mAABBMin.mV[VX]
+ << " " << mAABBMin.mV[VY]
+ << " " << mAABBMin.mV[VZ] << "\n";
+
+ if (!mAccessList.empty())
+ {
+ output_stream << "\t\t access_list " << mAccessList.size() << "\n";
+ access_map_const_iterator cit = mAccessList.begin();
+ access_map_const_iterator end = mAccessList.end();
+
+ for ( ; cit != end; ++cit)
+ {
+ output_stream << "\t\t{\n";
+ const LLAccessEntry& entry = (*cit).second;
+ entry.mID.toString(id_string);
+ output_stream << "\t\t\tid " << id_string << "\n";
+ output_stream << "\t\t\ttime " << entry.mTime << "\n";
+ output_stream << "\t\t\tflags " << entry.mFlags << "\n";
+ output_stream << "\t\t}\n";
+ }
+ }
+
+ if (!mBanList.empty())
+ {
+ output_stream << "\t\t ban_list " << mBanList.size() << "\n";
+ access_map_const_iterator cit = mBanList.begin();
+ access_map_const_iterator end = mBanList.end();
+
+ for ( ; cit != end; ++cit)
+ {
+ output_stream << "\t\t{\n";
+ const LLAccessEntry& entry = (*cit).second;
+ entry.mID.toString(id_string);
+ output_stream << "\t\t\tid " << id_string << "\n";
+ output_stream << "\t\t\ttime " << entry.mTime << "\n";
+ output_stream << "\t\t\tflags " << entry.mFlags << "\n";
+ output_stream << "\t\t}\n";
+ }
+ }
+
+ /*if (mRenterList.count() > 0)
+ {
+ output_stream << "\t\t renter_list " << mRenterList.count() << "\n";
+ for (i = 0; i < mRenterList.count(); i++)
+ {
+ output_stream << "\t\t{\n";
+ const LLAccessEntry& entry = mRenterList.get(i);
+ entry.mID.toString(id_string);
+ output_stream << "\t\t\tid " << id_string << "\n";
+ output_stream << "\t\t\ttime " << entry.mTime << "\n";
+ output_stream << "\t\t\tflags " << entry.mFlags << "\n";
+ output_stream << "\t\t}\n";
+ }
+ }*/
+
+ output_stream << "\t}\n";
+ output_stream.flags(old_flags);
+
+ return TRUE;
+}
+
+
+// Assumes we are in a block "ParcelData"
+void LLParcel::packMessage(LLMessageSystem* msg)
+{
+ msg->addU32Fast( _PREHASH_ParcelFlags, getParcelFlags() );
+ msg->addS32Fast( _PREHASH_SalePrice, getSalePrice() );
+ msg->addStringFast( _PREHASH_Name, getName() );
+ msg->addStringFast( _PREHASH_Desc, getDesc() );
+ msg->addStringFast( _PREHASH_MusicURL, getMusicURL() );
+ msg->addStringFast( _PREHASH_MediaURL, getMediaURL() );
+ msg->addU8 ( "MediaAutoScale", getMediaAutoScale () );
+ msg->addUUIDFast( _PREHASH_MediaID, getMediaID() );
+ msg->addUUIDFast( _PREHASH_GroupID, getGroupID() );
+ msg->addS32Fast( _PREHASH_PassPrice, mPassPrice );
+ msg->addF32Fast( _PREHASH_PassHours, mPassHours );
+ msg->addU8Fast( _PREHASH_Category, (U8)mCategory);
+ msg->addUUIDFast( _PREHASH_AuthBuyerID, mAuthBuyerID);
+ msg->addUUIDFast( _PREHASH_SnapshotID, mSnapshotID);
+ msg->addVector3Fast(_PREHASH_UserLocation, mUserLocation);
+ msg->addVector3Fast(_PREHASH_UserLookAt, mUserLookAt);
+ msg->addU8Fast( _PREHASH_LandingType, (U8)mLandingType);
+}
+
+
+void LLParcel::unpackMessage(LLMessageSystem* msg)
+{
+ char buffer[256];
+
+ msg->getU32Fast( _PREHASH_ParcelData,_PREHASH_ParcelFlags, mParcelFlags );
+ msg->getS32Fast( _PREHASH_ParcelData,_PREHASH_SalePrice, mSalePrice );
+ msg->getStringFast( _PREHASH_ParcelData,_PREHASH_Name, 256, buffer );
+ setName(buffer);
+ msg->getStringFast( _PREHASH_ParcelData,_PREHASH_Desc, 256, buffer );
+ setDesc(buffer);
+ msg->getStringFast( _PREHASH_ParcelData,_PREHASH_MusicURL, 256, buffer );
+ setMusicURL(buffer);
+ msg->getStringFast( _PREHASH_ParcelData,_PREHASH_MediaURL, 256, buffer );
+ setMediaURL(buffer);
+
+ // non-optimized version
+ msg->getU8 ( "ParcelData", "MediaAutoScale", mMediaAutoScale );
+
+ msg->getUUIDFast( _PREHASH_ParcelData,_PREHASH_MediaID, mMediaID );
+ msg->getUUIDFast( _PREHASH_ParcelData,_PREHASH_GroupID, mGroupID );
+ msg->getS32Fast( _PREHASH_ParcelData,_PREHASH_PassPrice, mPassPrice );
+ msg->getF32Fast( _PREHASH_ParcelData,_PREHASH_PassHours, mPassHours );
+ U8 category;
+ msg->getU8Fast( _PREHASH_ParcelData,_PREHASH_Category, category);
+ mCategory = (ECategory)category;
+ msg->getUUIDFast( _PREHASH_ParcelData,_PREHASH_AuthBuyerID, mAuthBuyerID);
+ msg->getUUIDFast( _PREHASH_ParcelData,_PREHASH_SnapshotID, mSnapshotID);
+ msg->getVector3Fast(_PREHASH_ParcelData,_PREHASH_UserLocation, mUserLocation);
+ msg->getVector3Fast(_PREHASH_ParcelData,_PREHASH_UserLookAt, mUserLookAt);
+ U8 landing_type;
+ msg->getU8Fast( _PREHASH_ParcelData,_PREHASH_LandingType, landing_type);
+ mLandingType = (ELandingType)landing_type;
+}
+
+
+void LLParcel::packAccessEntries(LLMessageSystem* msg,
+ const std::map<LLUUID,LLAccessEntry>& list)
+{
+ access_map_const_iterator cit = list.begin();
+ access_map_const_iterator end = list.end();
+
+ if (cit == end)
+ {
+ msg->nextBlockFast(_PREHASH_List);
+ msg->addUUIDFast(_PREHASH_ID, LLUUID::null );
+ msg->addS32Fast(_PREHASH_Time, 0 );
+ msg->addU32Fast(_PREHASH_Flags, 0 );
+ return;
+ }
+
+ for ( ; cit != end; ++cit)
+ {
+ const LLAccessEntry& entry = (*cit).second;
+
+ msg->nextBlockFast(_PREHASH_List);
+ msg->addUUIDFast(_PREHASH_ID, entry.mID );
+ msg->addS32Fast(_PREHASH_Time, entry.mTime );
+ msg->addU32Fast(_PREHASH_Flags, entry.mFlags );
+ }
+}
+
+
+void LLParcel::unpackAccessEntries(LLMessageSystem* msg,
+ std::map<LLUUID,LLAccessEntry>* list)
+{
+ LLUUID id;
+ S32 time;
+ U32 flags;
+
+ S32 i;
+ S32 count = msg->getNumberOfBlocksFast(_PREHASH_List);
+ for (i = 0; i < count; i++)
+ {
+ msg->getUUIDFast(_PREHASH_List, _PREHASH_ID, id, i);
+ msg->getS32Fast( _PREHASH_List, _PREHASH_Time, time, i);
+ msg->getU32Fast( _PREHASH_List, _PREHASH_Flags, flags, i);
+
+ if (id.notNull())
+ {
+ LLAccessEntry entry;
+ entry.mID = id;
+ entry.mTime = time;
+ entry.mFlags = flags;
+
+ (*list)[entry.mID] = entry;
+ }
+ }
+}
+
+
+void LLParcel::expirePasses(S32 now)
+{
+ access_map_iterator itor = mAccessList.begin();
+ while (itor != mAccessList.end())
+ {
+ const LLAccessEntry& entry = (*itor).second;
+
+ if (entry.mTime != 0 && entry.mTime < now)
+ {
+ mAccessList.erase(itor++);
+ }
+ else
+ {
+ ++itor;
+ }
+ }
+}
+
+
+bool LLParcel::operator==(const LLParcel &rhs) const
+{
+ if (mOwnerID != rhs.mOwnerID)
+ return FALSE;
+
+ if (mParcelFlags != rhs.mParcelFlags)
+ return FALSE;
+
+ if (mClaimDate != rhs.mClaimDate)
+ return FALSE;
+
+ if (mClaimPricePerMeter != rhs.mClaimPricePerMeter)
+ return FALSE;
+
+ if (mRentPricePerMeter != rhs.mRentPricePerMeter)
+ return FALSE;
+
+ return TRUE;
+}
+
+// Calculate rent
+S32 LLParcel::getTotalRent() const
+{
+ return (S32)floor(0.5f + (F32)mArea * (F32)mRentPricePerMeter * (1.0f - mDiscountRate));
+}
+
+F32 LLParcel::getAdjustedRentPerMeter() const
+{
+ return ((F32)mRentPricePerMeter * (1.0f - mDiscountRate));
+}
+
+LLVector3 LLParcel::getCenterpoint() const
+{
+ LLVector3 rv;
+ rv.mV[VX] = (getAABBMin().mV[VX] + getAABBMax().mV[VX]) * 0.5f;
+ rv.mV[VY] = (getAABBMin().mV[VY] + getAABBMax().mV[VY]) * 0.5f;
+ rv.mV[VZ] = 0.0f;
+ return rv;
+}
+
+void LLParcel::extendAABB(const LLVector3& box_min, const LLVector3& box_max)
+{
+ // Patch up min corner of AABB
+ S32 i;
+ for (i=0; i<3; i++)
+ {
+ if (box_min.mV[i] < mAABBMin.mV[i])
+ {
+ mAABBMin.mV[i] = box_min.mV[i];
+ }
+ }
+
+ // Patch up max corner of AABB
+ for (i=0; i<3; i++)
+ {
+ if (box_max.mV[i] > mAABBMax.mV[i])
+ {
+ mAABBMax.mV[i] = box_max.mV[i];
+ }
+ }
+}
+
+BOOL LLParcel::addToAccessList(const LLUUID& agent_id, S32 time)
+{
+ if (!((mParcelFlags & PF_USE_ACCESS_LIST) || (mParcelFlags & PF_USE_PASS_LIST))
+ || mAccessList.size() >= (U32) PARCEL_MAX_ACCESS_LIST)
+ {
+ // Not using access list, so not a rational thing to do
+ return FALSE;
+ }
+ if (agent_id == getOwnerID())
+ {
+ // Can't add owner to these lists
+ return FALSE;
+ }
+ access_map_iterator itor = mAccessList.begin();
+ while (itor != mAccessList.end())
+ {
+ const LLAccessEntry& entry = (*itor).second;
+ if (entry.mID == agent_id)
+ {
+ if (time == 0 || (entry.mTime != 0 && entry.mTime < time))
+ {
+ mAccessList.erase(itor++);
+ }
+ else
+ {
+ // existing one expires later
+ return FALSE;
+ }
+ }
+ else
+ {
+ ++itor;
+ }
+ }
+
+ removeFromBanList(agent_id);
+
+ LLAccessEntry new_entry;
+ new_entry.mID = agent_id;
+ new_entry.mTime = time;
+ new_entry.mFlags = 0x0;
+ mAccessList[new_entry.mID] = new_entry;
+ return TRUE;
+}
+
+BOOL LLParcel::addToBanList(const LLUUID& agent_id, S32 time)
+{
+ if (!(mParcelFlags & PF_USE_BAN_LIST)
+ || mBanList.size() >= (U32) PARCEL_MAX_ACCESS_LIST)
+ {
+ // Not using ban list, so not a rational thing to do
+ return FALSE;
+ }
+ if (agent_id == getOwnerID())
+ {
+ // Can't add owner to these lists
+ return FALSE;
+ }
+
+ access_map_iterator itor = mBanList.begin();
+ while (itor != mBanList.end())
+ {
+ const LLAccessEntry& entry = (*itor).second;
+ if (entry.mID == agent_id)
+ {
+ if (time == 0 || (entry.mTime != 0 && entry.mTime < time))
+ {
+ mBanList.erase(itor++);
+ }
+ else
+ {
+ // existing one expires later
+ return FALSE;
+ }
+ }
+ else
+ {
+ ++itor;
+ }
+ }
+
+ removeFromAccessList(agent_id);
+
+ LLAccessEntry new_entry;
+ new_entry.mID = agent_id;
+ new_entry.mTime = time;
+ new_entry.mFlags = 0x0;
+ mBanList[new_entry.mID] = new_entry;
+ return TRUE;
+}
+
+BOOL remove_from_access_array(std::map<LLUUID,LLAccessEntry>* list,
+ const LLUUID& agent_id)
+{
+ BOOL removed = FALSE;
+ access_map_iterator itor = list->begin();
+ while (itor != list->end())
+ {
+ const LLAccessEntry& entry = (*itor).second;
+ if (entry.mID == agent_id)
+ {
+ list->erase(itor++);
+ removed = TRUE;
+ }
+ else
+ {
+ ++itor;
+ }
+ }
+ return removed;
+}
+
+BOOL LLParcel::removeFromAccessList(const LLUUID& agent_id)
+{
+ return remove_from_access_array(&mAccessList, agent_id);
+}
+
+BOOL LLParcel::removeFromBanList(const LLUUID& agent_id)
+{
+ return remove_from_access_array(&mBanList, agent_id);
+}
+
+// static
+const char* LLParcel::getOwnershipStatusString(EOwnershipStatus status)
+{
+ return ownership_status_to_string(status);
+}
+
+// static
+const char* LLParcel::getCategoryString(ECategory category)
+{
+ return category_to_string(category);
+}
+
+// static
+const char* LLParcel::getCategoryUIString(ECategory category)
+{
+ return category_to_ui_string(category);
+}
+
+// static
+LLParcel::ECategory LLParcel::getCategoryFromString(const char* string)
+{
+ return category_string_to_category(string);
+}
+
+// static
+LLParcel::ECategory LLParcel::getCategoryFromUIString(const char* string)
+{
+ return category_ui_string_to_category(string);
+}
+
+// static
+const char* LLParcel::getActionString(LLParcel::EAction action)
+{
+ S32 index = 0;
+ if((action >= 0) && (action < LLParcel::A_COUNT))
+ {
+ index = action;
+ }
+ else
+ {
+ index = A_COUNT;
+ }
+ return PARCEL_ACTION_STRING[index];
+}
+
+BOOL LLParcel::isSaleTimerExpired(const U64& time)
+{
+ if (mSaleTimerExpires.getStarted() == FALSE)
+ {
+ return FALSE;
+ }
+ BOOL expired = mSaleTimerExpires.checkExpirationAndReset(0.0);
+ if (expired)
+ {
+ mSaleTimerExpires.stop();
+ }
+ return expired;
+}
+
+
+void LLParcel::startSale(const LLUUID& buyer_id, BOOL is_buyer_group)
+{
+ // TODO -- this and all Sale related methods need to move out of the LLParcel
+ // base class and into server-side-only LLSimParcel class
+ setPreviousOwnerID(mOwnerID);
+ setPreviouslyGroupOwned(mGroupOwned);
+
+ mOwnerID = buyer_id;
+ mGroupOwned = is_buyer_group;
+ if(mGroupOwned)
+ {
+ mGroupID = mOwnerID;
+ }
+ else
+ {
+ mGroupID.setNull();
+ }
+ mSaleTimerExpires.start();
+ mSaleTimerExpires.setTimerExpirySec(DEFAULT_USEC_SALE_TIMEOUT / SEC_TO_MICROSEC);
+ mStatus = OS_LEASE_PENDING;
+ mClaimDate = time(NULL);
+ mAuctionID = 0;
+ // clear the autoreturn whenever land changes hands
+ setCleanOtherTime(0);
+}
+
+void LLParcel::expireSale(U32& type, U8& flags, LLUUID& from_id, LLUUID& to_id)
+{
+ mSaleTimerExpires.setTimerExpirySec(0.0);
+ mSaleTimerExpires.stop();
+ setPreviousOwnerID(LLUUID::null);
+ setPreviouslyGroupOwned(FALSE);
+ setSellWithObjects(FALSE);
+ type = TRANS_LAND_RELEASE;
+ mStatus = OS_NONE;
+ mIsReservedForNewbie = FALSE;
+ flags = pack_transaction_flags(mGroupOwned, FALSE);
+ mAuthBuyerID.setNull();
+ from_id = mOwnerID;
+ mOwnerID.setNull();
+ to_id.setNull();
+}
+
+void LLParcel::completeSale(U32& type, U8& flags,
+ LLUUID& to_id)
+{
+ mSaleTimerExpires.setTimerExpirySec(0.0);
+ mSaleTimerExpires.stop();
+ mStatus = OS_LEASED;
+ type = TRANS_LAND_SALE;
+ flags = pack_transaction_flags(mGroupOwned, mGroupOwned);
+ to_id = mOwnerID;
+ mAuthBuyerID.setNull();
+ mIsReservedForNewbie = FALSE;
+
+ // Purchased parcels are assumed to no longer be for sale.
+ // Otherwise someone can snipe the sale.
+ setForSale(FALSE);
+
+ // Turn off show directory, since it's a recurring fee that
+ // the buyer may not want.
+ setParcelFlag(PF_SHOW_DIRECTORY, FALSE);
+
+ //should be cleared on sale.
+ mAccessList.clear();
+ mBanList.clear();
+
+}
+
+void LLParcel::clearSale()
+{
+ mSaleTimerExpires.setTimerExpirySec(0.0);
+ mSaleTimerExpires.stop();
+ if(isPublic())
+ {
+ mStatus = OS_NONE;
+ }
+ else
+ {
+ mStatus = OS_LEASED;
+ }
+ mAuthBuyerID.setNull();
+ setForSale(FALSE);
+ setPreviousOwnerID(LLUUID::null);
+ setPreviouslyGroupOwned(FALSE);
+ setSellWithObjects(FALSE);
+ mIsReservedForNewbie = FALSE;
+}
+
+BOOL LLParcel::isPublic() const
+{
+ return (mOwnerID.isNull());
+}
+
+BOOL LLParcel::isBuyerAuthorized(const LLUUID& buyer_id) const
+{
+ if(mAuthBuyerID.isNull())
+ {
+ return TRUE;
+ }
+ return (mAuthBuyerID == buyer_id);
+}
+
+void LLParcel::clearParcel()
+{
+ overrideParcelFlags(PF_DEFAULT);
+ setName(NULL);
+ setDesc(NULL);
+ setMusicURL(NULL);
+ setMediaURL(NULL);
+ setMediaID(LLUUID::null);
+ setMediaAutoScale(0);
+ setInEscrow(FALSE);
+ setAuthorizedBuyerID(LLUUID::null);
+ setCategory(C_NONE);
+ setSnapshotID(LLUUID::null);
+ setUserLocation(LLVector3::zero);
+ setUserLookAt(LLVector3::x_axis);
+ setLandingType(L_LANDING_POINT);
+ setAuctionID(0);
+ setReservedForNewbie(FALSE);
+ setGroupID(LLUUID::null);
+ setPassPrice(0);
+ setPassHours(0.f);
+ mAccessList.clear();
+ mBanList.clear();
+ //mRenterList.reset();
+}
+
+void LLParcel::dump()
+{
+ llinfos << "parcel " << mLocalID << " area " << mArea << llendl;
+ llinfos << " name <" << mName << ">" << llendl;
+ llinfos << " desc <" << mDesc << ">" << llendl;
+}
+
+const char* ownership_status_to_string(LLParcel::EOwnershipStatus status)
+{
+ if(status >= 0 && status < LLParcel::OS_COUNT)
+ {
+ return PARCEL_OWNERSHIP_STATUS_STRING[status];
+ }
+ return "none";
+}
+
+LLParcel::EOwnershipStatus ownership_string_to_status(const char* s)
+{
+ for(S32 i = 0; i < LLParcel::OS_COUNT; ++i)
+ {
+ if(0 == strcmp(s, PARCEL_OWNERSHIP_STATUS_STRING[i]))
+ {
+ return (LLParcel::EOwnershipStatus)i;
+ }
+ }
+ return LLParcel::OS_NONE;
+}
+
+//const char* revert_action_to_string(LLParcel::ESaleTimerExpireAction action)
+//{
+// S32 index = 0;
+// if(action >= 0 && action < LLParcel::STEA_COUNT)
+// {
+// index = action;
+// }
+// return PARCEL_SALE_TIMER_ACTION[index];
+//}
+
+//LLParcel::ESaleTimerExpireAction revert_string_to_action(const char* s)
+//{
+// for(S32 i = 0; i < LLParcel::STEA_COUNT; ++i)
+// {
+// if(0 == strcmp(s, PARCEL_SALE_TIMER_ACTION[i]))
+// {
+// return (LLParcel::ESaleTimerExpireAction)i;
+// }
+// }
+// return LLParcel::STEA_REVERT;
+//}
+
+const char* category_to_string(LLParcel::ECategory category)
+{
+ S32 index = 0;
+ if((category >= 0) && (category < LLParcel::C_COUNT))
+ {
+ index = category;
+ }
+ return PARCEL_CATEGORY_STRING[index];
+}
+
+const char* category_to_ui_string(LLParcel::ECategory category)
+{
+ S32 index = 0;
+ if((category >= 0) && (category < LLParcel::C_COUNT))
+ {
+ index = category;
+ }
+ else
+ {
+ // C_ANY = -1 , but the "Any" string is at the end of the list
+ index = ((S32) LLParcel::C_COUNT) + 1;
+ }
+ return PARCEL_CATEGORY_UI_STRING[index];
+}
+
+LLParcel::ECategory category_string_to_category(const char* s)
+{
+ for(S32 i = 0; i < LLParcel::C_COUNT; ++i)
+ {
+ if(0 == strcmp(s, PARCEL_CATEGORY_STRING[i]))
+ {
+ return (LLParcel::ECategory)i;
+ }
+ }
+ llwarns << "Parcel category outside of possibilities " << s << llendl;
+ return LLParcel::C_NONE;
+}
+
+LLParcel::ECategory category_ui_string_to_category(const char* s)
+{
+ for(S32 i = 0; i < LLParcel::C_COUNT; ++i)
+ {
+ if(0 == strcmp(s, PARCEL_CATEGORY_UI_STRING[i]))
+ {
+ return (LLParcel::ECategory)i;
+ }
+ }
+ // "Any" is a valid category for searches, and
+ // is a distinct option from "None" and "Other"
+ return LLParcel::C_ANY;
+}
+
diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h
new file mode 100644
index 0000000000..16d3cb01e5
--- /dev/null
+++ b/indra/llinventory/llparcel.h
@@ -0,0 +1,576 @@
+/**
+ * @file llparcel.h
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLPARCEL_H
+#define LL_LLPARCEL_H
+
+#include <time.h>
+#include <iostream>
+
+#include "lldarray.h"
+#include "lluuid.h"
+#include "llparcelflags.h"
+#include "llpermissions.h"
+#include "v3math.h"
+
+
+// Grid out of which parcels taken is stepped every 4 meters.
+const F32 PARCEL_GRID_STEP_METERS = 4.f;
+
+// Area of one "square" of parcel
+const S32 PARCEL_UNIT_AREA = 16;
+
+// Height _above_ground_ that parcel boundary ends
+const F32 PARCEL_HEIGHT = 50.f;
+
+//Height above ground which parcel boundries exist for explicitly banned avatars
+const F32 BAN_HEIGHT = 768.f;
+
+// Maximum number of entries in an access list
+const S32 PARCEL_MAX_ACCESS_LIST = 300;
+//Maximum number of entires in an update packet
+//for access/ban lists.
+const F32 PARCEL_MAX_ENTRIES_PER_PACKET = 48.f;
+
+// Weekly charge for listing a parcel in the directory
+const S32 PARCEL_DIRECTORY_FEE = 30;
+
+const S32 PARCEL_PASS_PRICE_DEFAULT = 10;
+const F32 PARCEL_PASS_HOURS_DEFAULT = 1.f;
+
+// Number of "chunks" in which parcel overlay data is sent
+// Chunk 0 = southern rows, entire width
+const S32 PARCEL_OVERLAY_CHUNKS = 4;
+
+// Bottom three bits are a color index for the land overlay
+const U8 PARCEL_COLOR_MASK = 0x07;
+const U8 PARCEL_PUBLIC = 0x00;
+const U8 PARCEL_OWNED = 0x01;
+const U8 PARCEL_GROUP = 0x02;
+const U8 PARCEL_SELF = 0x03;
+const U8 PARCEL_FOR_SALE = 0x04;
+const U8 PARCEL_AUCTION = 0x05;
+// unused 0x06
+// unused 0x07
+// flag, unused 0x08
+// flag, unused 0x10
+const U8 PARCEL_SOUND_LOCAL = 0x20;
+const U8 PARCEL_WEST_LINE = 0x40; // flag, property line on west edge
+const U8 PARCEL_SOUTH_LINE = 0x80; // flag, property line on south edge
+
+// Transmission results for parcel properties
+const S32 PARCEL_RESULT_NO_DATA = -1;
+const S32 PARCEL_RESULT_SUCCESS = 0; // got exactly one parcel
+const S32 PARCEL_RESULT_MULTIPLE = 1; // got multiple parcels
+
+const S32 SELECTED_PARCEL_SEQ_ID = -10000;
+const S32 COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID = -20000;
+const S32 COLLISION_BANNED_PARCEL_SEQ_ID = -30000;
+const S32 COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID = -40000;
+const S32 HOVERED_PARCEL_SEQ_ID = -50000;
+
+const U32 RT_NONE = 0x1 << 0;
+const U32 RT_OWNER = 0x1 << 1;
+const U32 RT_GROUP = 0x1 << 2;
+const U32 RT_OTHER = 0x1 << 3;
+const U32 RT_LIST = 0x1 << 4;
+const U32 RT_SELL = 0x1 << 5;
+
+class LLMessageSystem;
+
+class LLAccessEntry
+{
+public:
+ LLUUID mID;
+ S32 mTime;
+ U32 mFlags;
+};
+
+typedef std::map<LLUUID,LLAccessEntry>::iterator access_map_iterator;
+typedef std::map<LLUUID,LLAccessEntry>::const_iterator access_map_const_iterator;
+
+class LLParcel
+{
+public:
+ enum EOwnershipStatus
+ {
+ OS_LEASED = 0,
+ OS_LEASE_PENDING = 1,
+ OS_ABANDONED = 2,
+ OS_COUNT = 3,
+ OS_NONE = -1
+ };
+ enum ECategory
+ {
+ C_NONE = 0,
+ C_LINDEN,
+ C_ADULT,
+ C_ARTS, // "arts & culture"
+ C_BUSINESS, // was "store"
+ C_EDUCATIONAL,
+ C_GAMING, // was "game"
+ C_HANGOUT, // was "gathering place"
+ C_NEWCOMER,
+ C_PARK, // "parks & nature"
+ C_RESIDENTIAL, // was "homestead"
+ C_SHOPPING,
+ C_STAGE,
+ C_OTHER,
+ C_COUNT,
+ C_ANY = -1 // only useful in queries
+ };
+ enum EAction
+ {
+ A_CREATE = 0,
+ A_RELEASE = 1,
+ A_ABSORB = 2,
+ A_ABSORBED = 3,
+ A_DIVIDE = 4,
+ A_DIVISION = 5,
+ A_ACQUIRE = 6,
+ A_RELINQUISH = 7,
+ A_CONFIRM = 8,
+ A_COUNT = 9,
+ A_UNKNOWN = -1
+ };
+
+ enum ELandingType
+ {
+ L_NONE = 0,
+ L_LANDING_POINT = 1,
+ L_DIRECT = 2
+ };
+
+ // CREATORS
+ LLParcel();
+ LLParcel( const LLUUID &owner_id,
+ BOOL modify, BOOL terraform, BOOL damage,
+ time_t claim_date, S32 claim_price, S32 rent_price, S32 area, S32 sim_object_limit, F32 parcel_object_bonus,
+ BOOL is_group_owned = FALSE);
+ virtual ~LLParcel();
+
+ void init( const LLUUID &owner_id,
+ BOOL modify, BOOL terraform, BOOL damage,
+ time_t claim_date, S32 claim_price, S32 rent_price,
+ S32 area, S32 sim_object_limit, F32 parcel_object_bonus, BOOL is_group_owned = FALSE);
+
+ // TODO: make an actual copy constructor for this
+ void overrideParcelFlags(U32 flags);
+ // if you specify an agent id here, the group id will be zeroed
+ void overrideOwner(const LLUUID& owner_id, BOOL is_group_owned = FALSE);
+ void overrideSaleTimerExpires(F32 secs_left) { mSaleTimerExpires.setTimerExpirySec(secs_left); }
+
+ // MANIPULATORS
+ void generateNewID() { mID.generate(); }
+ void setName(const char* name);
+ void setDesc(const char* desc);
+ void setMusicURL(const char* url);
+ void setMediaURL(const char* url);
+ void setMediaID(const LLUUID& id) { mMediaID = id; }
+ void setMediaAutoScale ( U8 flagIn ) { mMediaAutoScale = flagIn; }
+ virtual void setLocalID(S32 local_id);
+
+ // blow away all the extra crap lurking in parcels, including urls, access lists, etc
+ void clearParcel();
+
+ // This value is not persisted out to the parcel file, it is only
+ // a per-process blocker for attempts to purchase.
+ void setInEscrow(bool in_escrow) { mInEscrow = in_escrow; }
+
+ void setAuthorizedBuyerID(const LLUUID& id) { mAuthBuyerID = id; }
+ //void overrideBuyerID(const LLUUID& id) { mBuyerID = id; }
+ void setCategory(ECategory category) { mCategory = category; }
+ void setSnapshotID(const LLUUID& id) { mSnapshotID = id; }
+ void setUserLocation(const LLVector3& pos) { mUserLocation = pos; }
+ void setUserLookAt(const LLVector3& rot) { mUserLookAt = rot; }
+ void setLandingType(const ELandingType type) { mLandingType = type; }
+
+ void setAuctionID(U32 auction_id) { mAuctionID = auction_id;}
+ void setReservedForNewbie(BOOL reserve) { mIsReservedForNewbie = reserve; }
+
+ void setAllParcelFlags(U32 flags) { mParcelFlags = flags; }
+ void setParcelFlag(U32 flag, BOOL b);
+
+ void setArea(S32 area, S32 sim_object_limit);
+ void setDiscountRate(F32 rate);
+
+ void setAllowModify(BOOL b) { setParcelFlag(PF_CREATE_OBJECTS, b); }
+ void setAllowGroupModify(BOOL b) { setParcelFlag(PF_CREATE_GROUP_OBJECTS, b); }
+ void setAllowAllObjectEntry(BOOL b) { setParcelFlag(PF_ALLOW_ALL_OBJECT_ENTRY, b); }
+ void setAllowGroupObjectEntry(BOOL b) { setParcelFlag(PF_ALLOW_GROUP_OBJECT_ENTRY, b); }
+ void setAllowTerraform(BOOL b){setParcelFlag(PF_ALLOW_TERRAFORM, b); }
+ void setAllowDamage(BOOL b) { setParcelFlag(PF_ALLOW_DAMAGE, b); }
+ void setAllowFly(BOOL b) { setParcelFlag(PF_ALLOW_FLY, b); }
+ void setAllowLandmark(BOOL b){ setParcelFlag(PF_ALLOW_LANDMARK, b); }
+ void setAllowGroupScripts(BOOL b) { setParcelFlag(PF_ALLOW_GROUP_SCRIPTS, b); }
+ void setAllowOtherScripts(BOOL b) { setParcelFlag(PF_ALLOW_OTHER_SCRIPTS, b); }
+ void setAllowDeedToGroup(BOOL b) { setParcelFlag(PF_ALLOW_DEED_TO_GROUP, b); }
+ void setContributeWithDeed(BOOL b) { setParcelFlag(PF_CONTRIBUTE_WITH_DEED, b); }
+ void setForSale(BOOL b) { setParcelFlag(PF_FOR_SALE, b); }
+ void setSoundOnly(BOOL b) { setParcelFlag(PF_SOUND_LOCAL, b); }
+ void setDenyAnonymous(BOOL b) { setParcelFlag(PF_DENY_ANONYMOUS, b); }
+ void setDenyIdentified(BOOL b) { setParcelFlag(PF_DENY_IDENTIFIED, b); }
+ void setDenyTransacted(BOOL b) { setParcelFlag(PF_DENY_TRANSACTED, b); }
+ void setRestrictPushObject(BOOL b) { setParcelFlag(PF_RESTRICT_PUSHOBJECT, b); }
+
+ void setDrawDistance(F32 dist) { mDrawDistance = dist; }
+ void setSalePrice(S32 price) { mSalePrice = price; }
+ void setGroupID(const LLUUID& id) { mGroupID = id; }
+ //void setGroupName(const char* s) { mGroupName.assign(s); }
+ void setPassPrice(S32 price) { mPassPrice = price; }
+ void setPassHours(F32 hours) { mPassHours = hours; }
+
+ BOOL importStream(std::istream& input_stream);
+ BOOL importAccessEntry(std::istream& input_stream, LLAccessEntry* entry);
+ BOOL exportStream(std::ostream& output_stream);
+
+ void packMessage(LLMessageSystem* msg);
+ void unpackMessage(LLMessageSystem* msg);
+
+ void packAccessEntries(LLMessageSystem* msg,
+ const std::map<LLUUID,LLAccessEntry>& list);
+ void unpackAccessEntries(LLMessageSystem* msg,
+ std::map<LLUUID,LLAccessEntry>* list);
+
+ void setAABBMin(const LLVector3& min) { mAABBMin = min; }
+ void setAABBMax(const LLVector3& max) { mAABBMax = max; }
+
+ // Extend AABB to include rectangle from min to max.
+ void extendAABB(const LLVector3& box_min, const LLVector3& box_max);
+
+ void dump();
+
+ // Scans the pass list and removes any items with an expiration
+ // time earlier than "now".
+ void expirePasses(S32 now);
+
+ // Add to list, suppressing duplicates. Returns TRUE if added.
+ BOOL addToAccessList(const LLUUID& agent_id, S32 time);
+ BOOL addToBanList(const LLUUID& agent_id, S32 time);
+ BOOL removeFromAccessList(const LLUUID& agent_id);
+ BOOL removeFromBanList(const LLUUID& agent_id);
+
+ // ACCESSORS
+ const LLUUID& getID() { return mID; }
+ const char* getName() const { return mName.c_str(); }
+ const char* getDesc() const { return mDesc.c_str(); }
+ const char* getMusicURL() const { return mMusicURL.c_str(); }
+ const char* getMediaURL() const { return mMediaURL.c_str(); }
+ const LLUUID& getMediaID() const { return mMediaID; }
+ const U8 getMediaAutoScale() const { return mMediaAutoScale; }
+ S32 getLocalID() const { return mLocalID; }
+ const LLUUID& getOwnerID() const { return mOwnerID; }
+ const LLUUID& getGroupID() const { return mGroupID; }
+ //const char* getGroupName() const { return mGroupName.c_str(); }
+ S32 getPassPrice() const { return mPassPrice; }
+ F32 getPassHours() const { return mPassHours; }
+ BOOL getIsGroupOwned() const { return mGroupOwned; }
+
+ U32 getAuctionID() { return mAuctionID; }
+ BOOL getReservedForNewbie() { return mIsReservedForNewbie; }
+ bool isInEscrow() const { return mInEscrow; }
+
+ BOOL isPublic() const;
+
+ // Region-local user-specified position
+ const LLVector3& getUserLocation() const { return mUserLocation; }
+ const LLVector3& getUserLookAt() const { return mUserLookAt; }
+ ELandingType getLandingType() const { return mLandingType; }
+
+ // User-specified snapshot
+ const LLUUID& getSnapshotID() const { return mSnapshotID; }
+
+ // the authorized buyer id is the person who is the only
+ // agent/group that has authority to purchase. (ie, ui specified a
+ // particular agent could buy the plot).
+ const LLUUID& getAuthorizedBuyerID() const { return mAuthBuyerID; }
+
+ // helper function
+ BOOL isBuyerAuthorized(const LLUUID& buyer_id) const;
+
+ // The buyer of a plot is set when someone indicates they want to
+ // buy the plot, and the system is simply waiting for tier-up
+ // approval
+ //const LLUUID& getBuyerID() const { return mBuyerID; }
+
+ // functions to deal with ownership status.
+ EOwnershipStatus getOwnershipStatus() const { return mStatus; }
+ static const char* getOwnershipStatusString(EOwnershipStatus status);
+ void setOwnershipStatus(EOwnershipStatus status) { mStatus = status; }
+
+ // dealing with parcel category information
+ ECategory getCategory() const {return mCategory; }
+ static const char* getCategoryString(ECategory category);
+ static const char* getCategoryUIString(ECategory category);
+ static ECategory getCategoryFromString(const char* string);
+ static ECategory getCategoryFromUIString(const char* string);
+
+ // functions for parcel action (used for logging)
+ static const char* getActionString(EAction action);
+
+ // dealing with sales and parcel conversion.
+ //
+ // the isSaleTimerExpired will trivially return FALSE if there is
+ // no sale going on. Pass in the current time in usec which will
+ // be used for comparison.
+ BOOL isSaleTimerExpired(const U64& time);
+
+ F32 getSaleTimerExpires() { return mSaleTimerExpires.getRemainingTimeF32(); }
+
+ // should the parcel join on complete?
+ //U32 getJoinNeighbors() const { return mJoinNeighbors; }
+
+ // need to record a few things with the parcel when a sale
+ // starts.
+ void startSale(const LLUUID& buyer_id, BOOL is_buyer_group);
+
+ // do the expiration logic, which needs to return values usable in
+ // a money transaction.
+ void expireSale(U32& type, U8& flags, LLUUID& from_id, LLUUID& to_id);
+ void completeSale(U32& type, U8& flags, LLUUID& to_id);
+ void clearSale();
+
+ // this function returns TRUE if the parcel needs conversion to a
+ // lease from a non-owned-status state.
+ BOOL getRecordTransaction() const { return mRecordTransaction; }
+ void setRecordTransaction(BOOL record) { mRecordTransaction = record; }
+
+
+ // more accessors
+ U32 getParcelFlags() const { return mParcelFlags; }
+
+ BOOL getParcelFlag(U32 flag) const
+ { return (mParcelFlags & flag) ? TRUE : FALSE; }
+
+ // objects can be added or modified by anyone (only parcel owner if disabled)
+ BOOL getAllowModify() const
+ { return (mParcelFlags & PF_CREATE_OBJECTS) ? TRUE : FALSE; }
+
+ // objects can be added or modified by group members
+ BOOL getAllowGroupModify() const
+ { return (mParcelFlags & PF_CREATE_GROUP_OBJECTS) ? TRUE : FALSE; }
+
+ // the parcel can be deeded to the group
+ BOOL getAllowDeedToGroup() const
+ { return (mParcelFlags & PF_ALLOW_DEED_TO_GROUP) ? TRUE : FALSE; }
+
+ // Does the owner want to make a contribution along with the deed.
+ BOOL getContributeWithDeed() const
+ { return (mParcelFlags & PF_CONTRIBUTE_WITH_DEED) ? TRUE : FALSE; }
+
+ // heightfield can be modified
+ BOOL getAllowTerraform() const
+ { return (mParcelFlags & PF_ALLOW_TERRAFORM) ? TRUE : FALSE; }
+
+ // avatars can be hurt here
+ BOOL getAllowDamage() const
+ { return (mParcelFlags & PF_ALLOW_DAMAGE) ? TRUE : FALSE; }
+
+ BOOL getAllowFly() const
+ { return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
+
+ BOOL getAllowLandmark() const
+ { return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
+
+ BOOL getAllowGroupScripts() const
+ { return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
+
+ BOOL getAllowOtherScripts() const
+ { return (mParcelFlags & PF_ALLOW_OTHER_SCRIPTS) ? TRUE : FALSE; }
+
+ BOOL getAllowAllObjectEntry() const
+ { return (mParcelFlags & PF_ALLOW_ALL_OBJECT_ENTRY) ? TRUE : FALSE; }
+
+ BOOL getAllowGroupObjectEntry() const
+ { return (mParcelFlags & PF_ALLOW_GROUP_OBJECT_ENTRY) ? TRUE : FALSE; }
+
+ BOOL getForSale() const
+ { return (mParcelFlags & PF_FOR_SALE) ? TRUE : FALSE; }
+ BOOL getSoundLocal() const
+ { return (mParcelFlags & PF_SOUND_LOCAL) ? TRUE : FALSE; }
+ BOOL getAllowPublish() const
+ { return (mParcelFlags & PF_ALLOW_PUBLISH) ? TRUE : FALSE; }
+ BOOL getMaturePublish() const
+ { return (mParcelFlags & PF_MATURE_PUBLISH) ? TRUE : FALSE; }
+ BOOL getRestrictPushObject() const
+ { return (mParcelFlags & PF_RESTRICT_PUSHOBJECT) ? TRUE : FALSE; }
+ BOOL getRegionPushOverride() const
+ { return mRegionPushOverride; }
+ BOOL getRegionDenyAnonymousOverride() const
+ { return mRegionDenyAnonymousOverride; }
+ BOOL getRegionDenyIdentifiedOverride() const
+ { return mRegionDenyIdentifiedOverride; }
+ BOOL getRegionDenyTransactedOverride() const
+ { return mRegionDenyTransactedOverride; }
+
+ F32 getDrawDistance() const { return mDrawDistance; }
+ S32 getSalePrice() const { return mSalePrice; }
+ time_t getClaimDate() const { return mClaimDate; }
+ S32 getClaimPricePerMeter() const { return mClaimPricePerMeter; }
+ S32 getRentPricePerMeter() const { return mRentPricePerMeter; }
+
+ // Area is NOT automatically calculated. You must calculate it
+ // and store it with setArea.
+ S32 getArea() const { return mArea; }
+
+ // deprecated 12/11/2003
+ //F32 getDiscountRate() const { return mDiscountRate; }
+
+ S32 getClaimPrice() const { return mClaimPricePerMeter * mArea; }
+
+ // Can this agent create objects here?
+ BOOL allowModifyBy(const LLUUID &agent_id, const LLUUID &group_id) const;
+
+ // Can this agent change the shape of the land?
+ BOOL allowTerraformBy(const LLUUID &agent_id) const;
+
+ // Returns 0 if access is OK, otherwise a BA_ return code above.
+ S32 blockAccess(const LLUUID& agent_id, const LLUUID& group_id, const BOOL is_agent_identified, const BOOL is_agent_transacted) const;
+
+ // Only checks if the agent is explicitly banned from this parcel
+ BOOL isAgentBanned(const LLUUID& agent_id) const;
+
+ static bool isAgentBlockedFromParcel(LLParcel* parcelp,
+ const LLUUID& agent_id,
+ const std::vector<LLUUID>& group_ids,
+ const BOOL is_agent_identified,
+ const BOOL is_agent_transacted);
+
+ bool operator==(const LLParcel &rhs) const;
+
+ // Calculate rent - area * rent * discount rate
+ S32 getTotalRent() const;
+ F32 getAdjustedRentPerMeter() const;
+
+ const LLVector3& getAABBMin() const { return mAABBMin; }
+ const LLVector3& getAABBMax() const { return mAABBMax; }
+ LLVector3 getCenterpoint() const;
+
+ // simwide
+ S32 getSimWideMaxPrimCapacity() const { return mSimWideMaxPrimCapacity; }
+ S32 getSimWidePrimCount() const { return mSimWidePrimCount; }
+
+ // this parcel only (not simwide)
+ S32 getMaxPrimCapacity() const { return mMaxPrimCapacity; }
+ S32 getPrimCount() const { return mOwnerPrimCount + mGroupPrimCount + mOtherPrimCount + mSelectedPrimCount; }
+ S32 getOwnerPrimCount() const { return mOwnerPrimCount; }
+ S32 getGroupPrimCount() const { return mGroupPrimCount; }
+ S32 getOtherPrimCount() const { return mOtherPrimCount; }
+ S32 getSelectedPrimCount() const{ return mSelectedPrimCount; }
+ S32 getTempPrimCount() const { return mTempPrimCount; }
+ F32 getParcelPrimBonus() const { return mParcelPrimBonus; }
+
+ S32 getCleanOtherTime() const { return mCleanOtherTime; }
+
+ void setMaxPrimCapacity(S32 max) { mMaxPrimCapacity = max; }
+ // simwide
+ void setSimWideMaxPrimCapacity(S32 current) { mSimWideMaxPrimCapacity = current; }
+ void setSimWidePrimCount(S32 current) { mSimWidePrimCount = current; }
+
+ // this parcel only (not simwide)
+ void setOwnerPrimCount(S32 current) { mOwnerPrimCount = current; }
+ void setGroupPrimCount(S32 current) { mGroupPrimCount = current; }
+ void setOtherPrimCount(S32 current) { mOtherPrimCount = current; }
+ void setSelectedPrimCount(S32 current) { mSelectedPrimCount = current; }
+ void setTempPrimCount(S32 current) { mTempPrimCount = current; }
+ void setParcelPrimBonus(F32 bonus) { mParcelPrimBonus = bonus; }
+
+ void setCleanOtherTime(S32 time) { mCleanOtherTime = time; }
+ void setRegionPushOverride(BOOL override) {mRegionPushOverride = override; }
+ void setRegionDenyAnonymousOverride(BOOL override) { mRegionDenyAnonymousOverride = override; }
+ void setRegionDenyIdentifiedOverride(BOOL override) { mRegionDenyIdentifiedOverride = override; }
+ void setRegionDenyTransactedOverride(BOOL override) { mRegionDenyTransactedOverride = override; }
+
+ // Accessors for parcel sellWithObjects
+ void setPreviousOwnerID(LLUUID prev_owner) { mPreviousOwnerID = prev_owner; }
+ void setPreviouslyGroupOwned(BOOL b) { mPreviouslyGroupOwned = b; }
+ void setSellWithObjects(BOOL b) { setParcelFlag(PF_SELL_PARCEL_OBJECTS, b); }
+
+ LLUUID getPreviousOwnerID() const { return mPreviousOwnerID; }
+ BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; }
+ BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; }
+
+protected:
+ LLUUID mID;
+ LLUUID mOwnerID;
+ LLUUID mGroupID;
+ BOOL mGroupOwned; // TRUE if mOwnerID is a group_id
+ LLUUID mPreviousOwnerID;
+ BOOL mPreviouslyGroupOwned;
+
+ EOwnershipStatus mStatus;
+ ECategory mCategory;
+ LLUUID mAuthBuyerID;
+ LLUUID mSnapshotID;
+ LLVector3 mUserLocation;
+ LLVector3 mUserLookAt;
+ ELandingType mLandingType;
+ LLTimer mSaleTimerExpires;
+ S32 mGraceExtension;
+ BOOL mRecordTransaction;
+
+
+ // This value is non-zero if there is an auction associated with
+ // the parcel.
+ U32 mAuctionID;
+
+ // This value is TRUE if the land is reserved for a newbie.
+ BOOL mIsReservedForNewbie;
+
+ // value used to temporarily lock attempts to purchase the parcel.
+ bool mInEscrow;
+
+ time_t mClaimDate; // UTC Unix-format time
+ S32 mClaimPricePerMeter; // meter squared
+ S32 mRentPricePerMeter; // meter squared
+ S32 mArea; // meter squared
+ F32 mDiscountRate; // 0.0-1.0
+ F32 mDrawDistance;
+ U32 mParcelFlags;
+ S32 mSalePrice; // linden dollars
+ std::string mName;
+ std::string mDesc;
+ std::string mMusicURL;
+ std::string mMediaURL;
+ U8 mMediaAutoScale;
+ LLUUID mMediaID;
+ S32 mPassPrice;
+ F32 mPassHours;
+ LLVector3 mAABBMin;
+ LLVector3 mAABBMax;
+ S32 mMaxPrimCapacity;
+ S32 mSimWidePrimCount;
+ S32 mSimWideMaxPrimCapacity;
+ //S32 mSimWidePrimCorrection;
+ S32 mOwnerPrimCount;
+ S32 mGroupPrimCount;
+ S32 mOtherPrimCount;
+ S32 mSelectedPrimCount;
+ S32 mTempPrimCount;
+ F32 mParcelPrimBonus;
+ S32 mCleanOtherTime;
+ BOOL mRegionPushOverride;
+ BOOL mRegionDenyAnonymousOverride;
+ BOOL mRegionDenyIdentifiedOverride;
+ BOOL mRegionDenyTransactedOverride;
+
+
+public:
+ // HACK, make private
+ S32 mLocalID;
+ LLUUID mBanListTransactionID;
+ LLUUID mAccessListTransactionID;
+ std::map<LLUUID,LLAccessEntry> mAccessList;
+ std::map<LLUUID,LLAccessEntry> mBanList;
+ std::map<LLUUID,LLAccessEntry> mTempBanList;
+ std::map<LLUUID,LLAccessEntry> mTempAccessList;
+
+ //LLDynamicArray<LLAccessEntry> mRenterList;
+};
+
+
+#endif
diff --git a/indra/llinventory/llparcelflags.h b/indra/llinventory/llparcelflags.h
new file mode 100644
index 0000000000..43571abe77
--- /dev/null
+++ b/indra/llinventory/llparcelflags.h
@@ -0,0 +1,105 @@
+/**
+ * @file llparcelflags.h
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLPARCEL_FLAGS_H
+#define LL_LLPARCEL_FLAGS_H
+
+//---------------------------------------------------------------------------
+// Parcel Flags (PF) constants
+//---------------------------------------------------------------------------
+const U32 PF_ALLOW_FLY = 1 << 0;// Can start flying
+const U32 PF_ALLOW_OTHER_SCRIPTS= 1 << 1;// Scripts by others can run.
+const U32 PF_FOR_SALE = 1 << 2;// Can buy this land
+const U32 PF_FOR_SALE_OBJECTS = 1 << 7;// Can buy all objects on this land
+const U32 PF_ALLOW_LANDMARK = 1 << 3;
+const U32 PF_ALLOW_TERRAFORM = 1 << 4;
+const U32 PF_ALLOW_DAMAGE = 1 << 5;
+const U32 PF_CREATE_OBJECTS = 1 << 6;
+// 7 is moved above
+const U32 PF_USE_ACCESS_GROUP = 1 << 8;
+const U32 PF_USE_ACCESS_LIST = 1 << 9;
+const U32 PF_USE_BAN_LIST = 1 << 10;
+const U32 PF_USE_PASS_LIST = 1 << 11;
+const U32 PF_SHOW_DIRECTORY = 1 << 12;
+const U32 PF_ALLOW_DEED_TO_GROUP = 1 << 13;
+const U32 PF_CONTRIBUTE_WITH_DEED = 1 << 14;
+const U32 PF_SOUND_LOCAL = 1 << 15; // Hear sounds in this parcel only
+const U32 PF_SELL_PARCEL_OBJECTS = 1 << 16; // Objects on land are included as part of the land when the land is sold
+const U32 PF_ALLOW_PUBLISH = 1 << 17; // Allow publishing of parcel information on the web
+const U32 PF_MATURE_PUBLISH = 1 << 18; // The information on this parcel is mature
+const U32 PF_URL_WEB_PAGE = 1 << 19; // The "media URL" is an HTML page
+const U32 PF_URL_RAW_HTML = 1 << 20; // The "media URL" is a raw HTML string like <H1>Foo</H1>
+const U32 PF_RESTRICT_PUSHOBJECT = 1 << 21; // Restrict push object to either on agent or on scripts owned by parcel owner
+const U32 PF_DENY_ANONYMOUS = 1 << 22; // Deny all non identified/transacted accounts
+const U32 PF_DENY_IDENTIFIED = 1 << 23; // Deny identified accounts
+const U32 PF_DENY_TRANSACTED = 1 << 24; // Deny identified accounts
+const U32 PF_ALLOW_GROUP_SCRIPTS = 1 << 25; // Allow scripts owned by group
+const U32 PF_CREATE_GROUP_OBJECTS = 1 << 26; // Allow object creation by group members or objects
+const U32 PF_ALLOW_ALL_OBJECT_ENTRY = 1 << 27; // Allow all objects to enter a parcel
+const U32 PF_ALLOW_GROUP_OBJECT_ENTRY = 1 << 28; // Only allow group (and owner) objects to enter the parcel
+
+
+const U32 PF_RESERVED = 1 << 31;
+
+// If any of these are true the parcel is restricting access in some maner.
+const U32 PF_USE_RESTRICTED_ACCESS = PF_USE_ACCESS_GROUP
+ | PF_USE_ACCESS_LIST
+ | PF_USE_BAN_LIST
+ | PF_USE_PASS_LIST
+ | PF_DENY_ANONYMOUS
+ | PF_DENY_IDENTIFIED
+ | PF_DENY_TRANSACTED;
+const U32 PF_NONE = 0x00000000;
+const U32 PF_ALL = 0x7FFFFFFF;
+const U32 PF_DEFAULT = PF_ALLOW_FLY
+ | PF_ALLOW_OTHER_SCRIPTS
+ | PF_ALLOW_GROUP_SCRIPTS
+ | PF_ALLOW_LANDMARK
+ | PF_CREATE_OBJECTS
+ | PF_CREATE_GROUP_OBJECTS
+ | PF_USE_BAN_LIST
+ | PF_ALLOW_ALL_OBJECT_ENTRY
+ | PF_ALLOW_GROUP_OBJECT_ENTRY;
+
+// Access list flags
+const U32 AL_ACCESS = (1 << 0);
+const U32 AL_BAN = (1 << 1);
+//const U32 AL_RENTER = (1 << 2);
+
+// Block access return values. BA_ALLOWED is the only success case
+// since some code in the simulator relies on that assumption. All
+// other BA_ values should be reasons why you are not allowed.
+const S32 BA_ALLOWED = 0;
+const S32 BA_NOT_IN_GROUP = 1;
+const S32 BA_NOT_ON_LIST = 2;
+const S32 BA_BANNED = 3;
+const S32 BA_NO_ACCESS_LEVEL = 4;
+
+// ParcelRelease flags
+const U32 PR_NONE = 0x0;
+const U32 PR_GOD_FORCE = (1 << 0);
+
+enum EObjectCategory
+{
+ OC_INVALID = -1,
+ OC_NONE = 0,
+ OC_TOTAL = 0, // yes zero, like OC_NONE
+ OC_OWNER,
+ OC_GROUP,
+ OC_OTHER,
+ OC_SELECTED,
+ OC_TEMP,
+ OC_COUNT
+};
+
+const S32 PARCEL_DETAILS_NAME = 0;
+const S32 PARCEL_DETAILS_DESC = 1;
+const S32 PARCEL_DETAILS_OWNER = 2;
+const S32 PARCEL_DETAILS_GROUP = 3;
+const S32 PARCEL_DETAILS_AREA = 4;
+
+#endif
diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp
new file mode 100644
index 0000000000..2063ac33d6
--- /dev/null
+++ b/indra/llinventory/llpermissions.cpp
@@ -0,0 +1,1171 @@
+/**
+ * @file llpermissions.cpp
+ * @author Phoenix
+ * @brief Permissions for objects and inventory.
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llpermissions.h"
+
+// library includes
+#include "message.h"
+#include "metapropertyt.h"
+
+///----------------------------------------------------------------------------
+/// Class LLPermissions
+///----------------------------------------------------------------------------
+
+const LLPermissions LLPermissions::DEFAULT;
+
+// No creator = created by system
+LLPermissions::LLPermissions()
+{
+ init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null);
+}
+
+
+// Default to created by system
+void LLPermissions::init(const LLUUID& creator, const LLUUID& owner, const LLUUID& last_owner, const LLUUID& group)
+{
+ mCreator = creator;
+ mOwner = owner;
+ mLastOwner = last_owner;
+ mGroup = group;
+
+ mMaskBase = PERM_ALL;
+ mMaskOwner = PERM_ALL;
+ mMaskEveryone = PERM_ALL;
+ mMaskGroup = PERM_ALL;
+ mMaskNextOwner = PERM_ALL;
+ fixOwnership();
+}
+
+
+void LLPermissions::initMasks(PermissionMask base, PermissionMask owner,
+ PermissionMask everyone, PermissionMask group,
+ PermissionMask next)
+{
+ mMaskBase = base;
+ mMaskOwner = owner;
+ mMaskEveryone = everyone;
+ mMaskGroup = group;
+ mMaskNextOwner = next;
+ fixFairUse();
+ fix();
+}
+
+BOOL LLPermissions::getOwnership(LLUUID& owner_id, BOOL& is_group_owned) const
+{
+ if(mOwner.notNull())
+ {
+ owner_id = mOwner;
+ is_group_owned = FALSE;
+ return TRUE;
+ }
+ else if(mIsGroupOwned)
+ {
+ owner_id = mGroup;
+ is_group_owned = TRUE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+LLUUID LLPermissions::getSafeOwner() const
+{
+ if(mOwner.notNull())
+ {
+ return mOwner;
+ }
+ else if(mIsGroupOwned)
+ {
+ return mGroup;
+ }
+ else
+ {
+ llwarns << "LLPermissions::getSafeOwner() called with no valid owner!" << llendl;
+ LLUUID unused_uuid;
+ unused_uuid.generate();
+
+ return unused_uuid;
+ }
+}
+
+U32 LLPermissions::getCRC32() const
+{
+ U32 rv = mCreator.getCRC32();
+ rv += mOwner.getCRC32();
+ rv += mLastOwner.getCRC32();
+ rv += mGroup.getCRC32();
+ rv += mMaskBase + mMaskOwner + mMaskEveryone + mMaskGroup;
+ return rv;
+}
+
+void LLPermissions::set(const LLPermissions& from)
+{
+ mCreator = from.mCreator;
+ mOwner = from.mOwner;
+ mLastOwner = from.mLastOwner;
+ mGroup = from.mGroup;
+
+ mMaskBase = from.mMaskBase;
+ mMaskOwner = from.mMaskOwner;
+ mMaskEveryone = from.mMaskEveryone;
+ mMaskGroup = from.mMaskGroup;
+ mMaskNextOwner = from.mMaskNextOwner;
+ mIsGroupOwned = from.mIsGroupOwned;
+}
+
+// Fix hierarchy of permissions.
+void LLPermissions::fix()
+{
+ mMaskOwner &= mMaskBase;
+ mMaskGroup &= mMaskOwner;
+ // next owner uses base, since you may want to sell locked objects.
+ mMaskNextOwner &= mMaskBase;
+ mMaskEveryone &= mMaskOwner;
+ mMaskEveryone &= ~PERM_MODIFY;
+ if(!(mMaskBase & PERM_TRANSFER) && !mIsGroupOwned)
+ {
+ mMaskGroup &= ~PERM_COPY;
+ mMaskEveryone &= ~PERM_COPY;
+ // Do not set mask next owner to too restrictive because if we
+ // rez an object, it may require an ownership transfer during
+ // rez, which will note the overly restrictive perms, and then
+ // fix them to allow fair use, which may be different than the
+ // original intention.
+ }
+}
+
+// Correct for fair use - you can never take away the right to move
+// stuff you own, and you can never take away the right to transfer
+// something you cannot otherwise copy.
+void LLPermissions::fixFairUse()
+{
+ mMaskBase |= PERM_MOVE;
+ if(!(mMaskBase & PERM_COPY))
+ {
+ mMaskBase |= PERM_TRANSFER;
+ }
+ // (mask next owner == PERM_NONE) iff mask base is no transfer
+ if(mMaskNextOwner != PERM_NONE)
+ {
+ mMaskNextOwner |= PERM_MOVE;
+ }
+}
+
+void LLPermissions::fixOwnership()
+{
+ if(mOwner.isNull() && mGroup.notNull())
+ {
+ mIsGroupOwned = true;
+ }
+ else
+ {
+ mIsGroupOwned = false;
+ }
+}
+
+// Allow accumulation of permissions. Results in the tightest
+// permissions possible. In the case of clashing UUIDs, it sets the ID
+// to LLUUID::null.
+void LLPermissions::accumulate(const LLPermissions& perm)
+{
+ if(perm.mCreator != mCreator)
+ {
+ mCreator = LLUUID::null;
+ }
+ if(perm.mOwner != mOwner)
+ {
+ mOwner = LLUUID::null;
+ }
+ if(perm.mLastOwner != mLastOwner)
+ {
+ mLastOwner = LLUUID::null;
+ }
+ if(perm.mGroup != mGroup)
+ {
+ mGroup = LLUUID::null;
+ }
+
+ mMaskBase &= perm.mMaskBase;
+ mMaskOwner &= perm.mMaskOwner;
+ mMaskGroup &= perm.mMaskGroup;
+ mMaskEveryone &= perm.mMaskEveryone;
+ mMaskNextOwner &= perm.mMaskNextOwner;
+ fix();
+}
+
+// saves last owner, sets current owner, and sets the group. note
+// that this function has to more cleverly apply the fair use
+// permissions.
+BOOL LLPermissions::setOwnerAndGroup(
+ const LLUUID& agent,
+ const LLUUID& owner,
+ const LLUUID& group,
+ bool is_atomic)
+{
+ BOOL allowed = FALSE;
+
+ if( agent.isNull() || mOwner.isNull()
+ || ((agent == mOwner) && ((owner == mOwner) || (mMaskOwner & PERM_TRANSFER)) ) )
+ {
+ // ...system can alway set owner
+ // ...public objects can be claimed by anyone
+ // ...otherwise, agent must own it and have transfer ability
+ allowed = TRUE;
+ }
+
+ if (allowed)
+ {
+ if(mLastOwner.isNull() || (!mOwner.isNull() && (owner != mLastOwner)))
+ {
+ mLastOwner = mOwner;
+ }
+ if((mOwner != owner)
+ || (mOwner.isNull() && owner.isNull() && (mGroup != group)))
+ {
+ mMaskBase = mMaskNextOwner;
+ mOwner = owner;
+ // this is a selective use of fair use for atomic
+ // permissions.
+ if(is_atomic && !(mMaskBase & PERM_COPY))
+ {
+ mMaskBase |= PERM_TRANSFER;
+ }
+ }
+ mGroup = group;
+ fixOwnership();
+ // if it's not atomic and we fix fair use, it blows away
+ //objects as inventory items which have different permissions
+ //than it's contents. :(
+ // fixFairUse();
+ mMaskBase |= PERM_MOVE;
+ if(mMaskNextOwner != PERM_NONE) mMaskNextOwner |= PERM_MOVE;
+ fix();
+ }
+
+ return allowed;
+}
+
+BOOL LLPermissions::deedToGroup(const LLUUID& agent, const LLUUID& group)
+{
+ if(group.notNull() && (agent.isNull() || ((group == mGroup)
+ && (mMaskOwner & PERM_TRANSFER)
+ && (mMaskGroup & PERM_MOVE))))
+ {
+ if(mOwner.notNull())
+ {
+ mLastOwner = mOwner;
+ mOwner.setNull();
+ }
+ mMaskBase = mMaskNextOwner;
+ mGroup = group;
+ mIsGroupOwned = true;
+ fixFairUse();
+ fix();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL LLPermissions::setBaseBits(const LLUUID& agent, BOOL set, PermissionMask bits)
+{
+ BOOL ownership = FALSE;
+ if(agent.isNull())
+ {
+ // only the system is always allowed to change base bits
+ ownership = TRUE;
+ }
+
+ if (ownership)
+ {
+ if (set)
+ {
+ mMaskBase |= bits; // turn on bits
+ }
+ else
+ {
+ mMaskBase &= ~bits; // turn off bits
+ }
+ fix();
+ }
+
+ return ownership;
+}
+
+
+// Note: If you attempt to set bits that the base bits doesn't allow,
+// the function will succeed, but those bits will not be set.
+BOOL LLPermissions::setOwnerBits(const LLUUID& agent, BOOL set, PermissionMask bits)
+{
+ BOOL ownership = FALSE;
+
+ if(agent.isNull())
+ {
+ // ...system always allowed to change things
+ ownership = TRUE;
+ }
+ else if (agent == mOwner)
+ {
+ // ...owner bits can only be set by owner
+ ownership = TRUE;
+ }
+
+ // If we have correct ownership and
+ if (ownership)
+ {
+ if (set)
+ {
+ mMaskOwner |= bits; // turn on bits
+ }
+ else
+ {
+ mMaskOwner &= ~bits; // turn off bits
+ }
+ fix();
+ }
+
+ return (ownership);
+}
+
+BOOL LLPermissions::setGroupBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits)
+{
+ BOOL ownership = FALSE;
+ if((agent.isNull()) || (agent == mOwner)
+ || ((group == mGroup) && (!mGroup.isNull())))
+ {
+ // The group bits can be set by the system, the owner, or a
+ // group member.
+ ownership = TRUE;
+ }
+
+ if (ownership)
+ {
+ if (set)
+ {
+ mMaskGroup |= bits;
+ }
+ else
+ {
+ mMaskGroup &= ~bits;
+ }
+ fix();
+ }
+ return ownership;
+}
+
+
+// Note: If you attempt to set bits that the creator or owner doesn't allow,
+// the function will succeed, but those bits will not be set.
+BOOL LLPermissions::setEveryoneBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits)
+{
+ BOOL ownership = FALSE;
+ if((agent.isNull()) || (agent == mOwner)
+ || ((group == mGroup) && (!mGroup.isNull())))
+ {
+ // The everyone bits can be set by the system, the owner, or a
+ // group member.
+ ownership = TRUE;
+ }
+ if (ownership)
+ {
+ if (set)
+ {
+ mMaskEveryone |= bits;
+ }
+ else
+ {
+ mMaskEveryone &= ~bits;
+ }
+
+ // Fix hierarchy of permissions
+ fix();
+ }
+ return ownership;
+}
+
+// Note: If you attempt to set bits that the creator or owner doesn't allow,
+// the function will succeed, but those bits will not be set.
+BOOL LLPermissions::setNextOwnerBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits)
+{
+ BOOL ownership = FALSE;
+ if((agent.isNull()) || (agent == mOwner)
+ || ((group == mGroup) && (!mGroup.isNull())))
+ {
+ // The next owner bits can be set by the system, the owner, or
+ // a group member.
+ ownership = TRUE;
+ }
+ if (ownership)
+ {
+ if (set)
+ {
+ mMaskNextOwner |= bits;
+ }
+ else
+ {
+ mMaskNextOwner &= ~bits;
+ }
+
+ // Fix-up permissions
+ if(!(mMaskNextOwner & PERM_COPY))
+ {
+ mMaskNextOwner |= PERM_TRANSFER;
+ }
+ fix();
+ }
+ return ownership;
+}
+
+BOOL LLPermissions::allowOperationBy(PermissionBit op, const LLUUID& requester, const LLUUID& group) const
+{
+ if(requester.isNull())
+ {
+ // ...system making request
+ // ...not owned
+ return TRUE;
+ }
+ else if (mIsGroupOwned && (mGroup == requester))
+ {
+ // group checking ownership permissions
+ return (mMaskOwner & op);
+ }
+ else if (!mIsGroupOwned && (mOwner == requester))
+ {
+ // ...owner making request
+ return (mMaskOwner & op);
+ }
+ else if(mGroup.notNull() && (mGroup == group))
+ {
+ // group member making request
+ return ((mMaskGroup & op) || (mMaskEveryone & op));
+ }
+ return (mMaskEveryone & op);
+}
+
+//
+// Messaging support
+//
+void LLPermissions::packMessage(LLMessageSystem* msg) const
+{
+ msg->addUUIDFast(_PREHASH_CreatorID, mCreator);
+ msg->addUUIDFast(_PREHASH_OwnerID, mOwner);
+ msg->addUUIDFast(_PREHASH_GroupID, mGroup);
+
+ msg->addU32Fast(_PREHASH_BaseMask, mMaskBase );
+ msg->addU32Fast(_PREHASH_OwnerMask, mMaskOwner );
+ msg->addU32Fast(_PREHASH_GroupMask, mMaskGroup );
+ msg->addU32Fast(_PREHASH_EveryoneMask, mMaskEveryone );
+ msg->addU32Fast(_PREHASH_NextOwnerMask, mMaskNextOwner );
+ msg->addBOOLFast(_PREHASH_GroupOwned, (BOOL)mIsGroupOwned);
+}
+
+
+void LLPermissions::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
+{
+ msg->getUUIDFast(block, _PREHASH_CreatorID, mCreator, block_num);
+ msg->getUUIDFast(block, _PREHASH_OwnerID, mOwner, block_num);
+ msg->getUUIDFast(block, _PREHASH_GroupID, mGroup, block_num);
+
+ msg->getU32Fast(block, _PREHASH_BaseMask, mMaskBase, block_num );
+ msg->getU32Fast(block, _PREHASH_OwnerMask, mMaskOwner, block_num );
+ msg->getU32Fast(block, _PREHASH_GroupMask, mMaskGroup, block_num );
+ msg->getU32Fast(block, _PREHASH_EveryoneMask, mMaskEveryone, block_num );
+ msg->getU32Fast(block, _PREHASH_NextOwnerMask, mMaskNextOwner, block_num );
+ BOOL tmp;
+ msg->getBOOLFast(block, _PREHASH_GroupOwned, tmp, block_num);
+ mIsGroupOwned = (bool)tmp;
+}
+
+
+//
+// File support
+//
+
+BOOL LLPermissions::importFile(FILE *fp)
+{
+ init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null);
+ const S32 BUFSIZE = 16384;
+
+ char buffer[BUFSIZE];
+ char keyword[256];
+ char valuestr[256];
+ char uuid_str[256];
+ U32 mask;
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+
+ while (!feof(fp))
+ {
+ fgets(buffer, BUFSIZE, fp);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if (!keyword)
+ {
+ continue;
+ }
+ if (!strcmp("{", keyword))
+ {
+ continue;
+ }
+ if (!strcmp("}",keyword))
+ {
+ break;
+ }
+ else if (!strcmp("creator_mask", keyword))
+ {
+ // legacy support for "creator" masks
+ sscanf(valuestr, "%x", &mask);
+ mMaskBase = mask;
+ fixFairUse();
+ }
+ else if (!strcmp("base_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskBase = mask;
+ //fixFairUse();
+ }
+ else if (!strcmp("owner_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskOwner = mask;
+ }
+ else if (!strcmp("group_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskGroup = mask;
+ }
+ else if (!strcmp("everyone_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskEveryone = mask;
+ }
+ else if (!strcmp("next_owner_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskNextOwner = mask;
+ }
+ else if (!strcmp("creator_id", keyword))
+ {
+ sscanf(valuestr, "%s", uuid_str);
+ mCreator.set(uuid_str);
+ }
+ else if (!strcmp("owner_id", keyword))
+ {
+ sscanf(valuestr, "%s", uuid_str);
+ mOwner.set(uuid_str);
+ }
+ else if (!strcmp("last_owner_id", keyword))
+ {
+ sscanf(valuestr, "%s", uuid_str);
+ mLastOwner.set(uuid_str);
+ }
+ else if (!strcmp("group_id", keyword))
+ {
+ sscanf(valuestr, "%s", uuid_str);
+ mGroup.set(uuid_str);
+ }
+ else if (!strcmp("group_owned", keyword))
+ {
+ sscanf(valuestr, "%d", &mask);
+ if(mask) mIsGroupOwned = true;
+ else mIsGroupOwned = false;
+ }
+ else
+ {
+ llinfos << "unknown keyword " << keyword << " in permissions import" << llendl;
+ }
+ }
+ fix();
+ return TRUE;
+}
+
+
+BOOL LLPermissions::exportFile(FILE *fp) const
+{
+ char uuid_str[256];
+
+ fprintf(fp, "\tpermissions 0\n");
+ fprintf(fp, "\t{\n");
+
+ fprintf(fp, "\t\tbase_mask\t%08x\n", mMaskBase);
+ fprintf(fp, "\t\towner_mask\t%08x\n", mMaskOwner);
+ fprintf(fp, "\t\tgroup_mask\t%08x\n", mMaskGroup);
+ fprintf(fp, "\t\teveryone_mask\t%08x\n", mMaskEveryone);
+ fprintf(fp, "\t\tnext_owner_mask\t%08x\n", mMaskNextOwner);
+
+ mCreator.toString(uuid_str);
+ fprintf(fp, "\t\tcreator_id\t%s\n", uuid_str);
+
+ mOwner.toString(uuid_str);
+ fprintf(fp, "\t\towner_id\t%s\n", uuid_str);
+
+ mLastOwner.toString(uuid_str);
+ fprintf(fp, "\t\tlast_owner_id\t%s\n", uuid_str);
+
+ mGroup.toString(uuid_str);
+ fprintf(fp, "\t\tgroup_id\t%s\n", uuid_str);
+
+ if(mIsGroupOwned)
+ {
+ fprintf(fp, "\t\tgroup_owned\t1\n");
+ }
+ fprintf(fp,"\t}\n");
+ return TRUE;
+}
+
+
+BOOL LLPermissions::importLegacyStream(std::istream& input_stream)
+{
+ init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null);
+ const S32 BUFSIZE = 16384;
+
+ char buffer[BUFSIZE];
+ char keyword[256];
+ char valuestr[256];
+ char uuid_str[256];
+ U32 mask;
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+
+ while (input_stream.good())
+ {
+ input_stream.getline(buffer, BUFSIZE);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if (!keyword)
+ {
+ continue;
+ }
+ if (!strcmp("{", keyword))
+ {
+ continue;
+ }
+ if (!strcmp("}",keyword))
+ {
+ break;
+ }
+ else if (!strcmp("creator_mask", keyword))
+ {
+ // legacy support for "creator" masks
+ sscanf(valuestr, "%x", &mask);
+ mMaskBase = mask;
+ fixFairUse();
+ }
+ else if (!strcmp("base_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskBase = mask;
+ //fixFairUse();
+ }
+ else if (!strcmp("owner_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskOwner = mask;
+ }
+ else if (!strcmp("group_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskGroup = mask;
+ }
+ else if (!strcmp("everyone_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskEveryone = mask;
+ }
+ else if (!strcmp("next_owner_mask", keyword))
+ {
+ sscanf(valuestr, "%x", &mask);
+ mMaskNextOwner = mask;
+ }
+ else if (!strcmp("creator_id", keyword))
+ {
+ sscanf(valuestr, "%s", uuid_str);
+ mCreator.set(uuid_str);
+ }
+ else if (!strcmp("owner_id", keyword))
+ {
+ sscanf(valuestr, "%s", uuid_str);
+ mOwner.set(uuid_str);
+ }
+ else if (!strcmp("last_owner_id", keyword))
+ {
+ sscanf(valuestr, "%s", uuid_str);
+ mLastOwner.set(uuid_str);
+ }
+ else if (!strcmp("group_id", keyword))
+ {
+ sscanf(valuestr, "%s", uuid_str);
+ mGroup.set(uuid_str);
+ }
+ else if (!strcmp("group_owned", keyword))
+ {
+ sscanf(valuestr, "%d", &mask);
+ if(mask) mIsGroupOwned = true;
+ else mIsGroupOwned = false;
+ }
+ else
+ {
+ llinfos << "unknown keyword " << keyword << " in permissions import" << llendl;
+ }
+ }
+ fix();
+ return TRUE;
+}
+
+
+BOOL LLPermissions::exportLegacyStream(std::ostream& output_stream) const
+{
+ char uuid_str[256];
+
+ output_stream << "\tpermissions 0\n";
+ output_stream << "\t{\n";
+
+ char buffer[256];
+ sprintf(buffer, "\t\tbase_mask\t%08x\n", mMaskBase);
+ output_stream << buffer;
+ sprintf(buffer, "\t\towner_mask\t%08x\n", mMaskOwner);
+ output_stream << buffer;
+ sprintf(buffer, "\t\tgroup_mask\t%08x\n", mMaskGroup);
+ output_stream << buffer;
+ sprintf(buffer, "\t\teveryone_mask\t%08x\n", mMaskEveryone);
+ output_stream << buffer;
+ sprintf(buffer, "\t\tnext_owner_mask\t%08x\n", mMaskNextOwner);
+ output_stream << buffer;
+
+ mCreator.toString(uuid_str);
+ output_stream << "\t\tcreator_id\t" << uuid_str << "\n";
+
+ mOwner.toString(uuid_str);
+ output_stream << "\t\towner_id\t" << uuid_str << "\n";
+
+ mLastOwner.toString(uuid_str);
+ output_stream << "\t\tlast_owner_id\t" << uuid_str << "\n";
+
+ mGroup.toString(uuid_str);
+ output_stream << "\t\tgroup_id\t" << uuid_str << "\n";
+
+ if(mIsGroupOwned)
+ {
+ output_stream << "\t\tgroup_owned\t1\n";
+ }
+ output_stream << "\t}\n";
+ return TRUE;
+}
+
+
+LLXMLNode *LLPermissions::exportFileXML() const
+{
+ LLXMLNode *ret = new LLXMLNode("permissions", FALSE);
+
+ ret->createChild("group_owned", TRUE)->setBoolValue(1, (const BOOL*)&mIsGroupOwned);
+
+ ret->createChild("base_mask", FALSE)->setByteValue(4, (U8*)&mMaskBase, LLXMLNode::ENCODING_HEX);
+ ret->createChild("owner_mask", FALSE)->setByteValue(4, (U8*)&mMaskOwner, LLXMLNode::ENCODING_HEX);
+ ret->createChild("group_mask", FALSE)->setByteValue(4, (U8*)&mMaskGroup, LLXMLNode::ENCODING_HEX);
+ ret->createChild("everyone_mask", FALSE)->setByteValue(4, (U8*)&mMaskEveryone, LLXMLNode::ENCODING_HEX);
+ ret->createChild("next_owner_mask", FALSE)->setByteValue(4, (U8*)&mMaskNextOwner, LLXMLNode::ENCODING_HEX);
+
+ ret->createChild("creator_id", FALSE)->setUUIDValue(1, &mCreator);
+ ret->createChild("owner_id", FALSE)->setUUIDValue(1, &mOwner);
+ ret->createChild("last_owner_id", FALSE)->setUUIDValue(1, &mLastOwner);
+ ret->createChild("group_id", FALSE)->setUUIDValue(1, &mGroup);
+
+ return ret;
+}
+
+bool LLPermissions::importXML(LLXMLNode* node)
+{
+ bool success = false;
+ if (node)
+ {
+ success = true;
+ LLXMLNodePtr sub_node;
+ if (node->getChild("base_mask", sub_node))
+ success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskBase));
+ if (node->getChild("owner_mask", sub_node))
+ success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskOwner));
+ if (node->getChild("group_mask", sub_node))
+ success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskGroup));
+ if (node->getChild("everyone_mask", sub_node))
+ success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskEveryone));
+ if (node->getChild("next_owner_mask", sub_node))
+ success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskNextOwner));
+
+ if (node->getChild("creator_id", sub_node))
+ success = success && (1 == sub_node->getUUIDValue(1, &mCreator));
+ if (node->getChild("owner_id", sub_node))
+ success = success && (1 == sub_node->getUUIDValue(1, &mOwner));
+ if (node->getChild("last_owner_id", sub_node))
+ success = success && (1 == sub_node->getUUIDValue(1, &mLastOwner));
+ if (node->getChild("group_id", sub_node))
+ success = success && (1 == sub_node->getUUIDValue(1, &mGroup));
+ if (node->getChild("group_owned", sub_node))
+ success = success && (1 == sub_node->getBoolValue(1, (BOOL*)&mIsGroupOwned));
+ if (!success)
+ {
+ lldebugs << "LLPermissions::importXML() failed for node named '"
+ << node->getName() << "'" << llendl;
+ }
+ }
+ return success;
+}
+
+bool LLPermissions::operator==(const LLPermissions &rhs) const
+{
+ return
+ (mCreator == rhs.mCreator) &&
+ (mOwner == rhs.mOwner) &&
+ (mLastOwner == rhs.mLastOwner ) &&
+ (mGroup == rhs.mGroup ) &&
+ (mMaskBase == rhs.mMaskBase ) &&
+ (mMaskOwner == rhs.mMaskOwner ) &&
+ (mMaskGroup == rhs.mMaskGroup ) &&
+ (mMaskEveryone == rhs.mMaskEveryone ) &&
+ (mMaskNextOwner == rhs.mMaskNextOwner ) &&
+ (mIsGroupOwned == rhs.mIsGroupOwned);
+}
+
+
+bool LLPermissions::operator!=(const LLPermissions &rhs) const
+{
+ return
+ (mCreator != rhs.mCreator) ||
+ (mOwner != rhs.mOwner) ||
+ (mLastOwner != rhs.mLastOwner ) ||
+ (mGroup != rhs.mGroup ) ||
+ (mMaskBase != rhs.mMaskBase ) ||
+ (mMaskOwner != rhs.mMaskOwner ) ||
+ (mMaskGroup != rhs.mMaskGroup ) ||
+ (mMaskEveryone != rhs.mMaskEveryone ) ||
+ (mMaskNextOwner != rhs.mMaskNextOwner) ||
+ (mIsGroupOwned != rhs.mIsGroupOwned);
+}
+
+std::ostream& operator<<(std::ostream &s, const LLPermissions &perm)
+{
+ s << "{Creator=" << perm.getCreator();
+ s << ", Owner=" << perm.getOwner();
+ s << ", Group=" << perm.getGroup();
+ s << std::hex << ", BaseMask=0x" << perm.getMaskBase();
+ s << ", OwnerMask=0x" << perm.getMaskOwner();
+ s << ", EveryoneMask=0x" << perm.getMaskEveryone();
+ s << ", GroupMask=0x" << perm.getMaskGroup();
+ s << ", NextOwnerMask=0x" << perm.getMaskNextOwner() << std::dec;
+ s << "}";
+ return s;
+}
+
+template <>
+void LLMetaClassT<LLPermissions>::reflectProperties(LLMetaClass& meta_class)
+{
+ reflectProperty(meta_class, "mCreator", &LLPermissions::mCreator);
+ reflectProperty(meta_class, "mOwner", &LLPermissions::mOwner);
+}
+
+// virtual
+const LLMetaClass& LLPermissions::getMetaClass() const
+{
+ return LLMetaClassT<LLPermissions>::instance();
+}
+
+///----------------------------------------------------------------------------
+/// Class LLAggregatePermissions
+///----------------------------------------------------------------------------
+
+const LLAggregatePermissions LLAggregatePermissions::empty;
+
+
+LLAggregatePermissions::LLAggregatePermissions()
+{
+ for(S32 i = 0; i < PI_COUNT; ++i)
+ {
+ mBits[i] = AP_EMPTY;
+ }
+}
+
+LLAggregatePermissions::EValue LLAggregatePermissions::getValue(PermissionBit bit) const
+{
+ EPermIndex idx = perm2PermIndex(bit);
+ EValue rv = AP_EMPTY;
+ if(idx != PI_END)
+ {
+ rv = (LLAggregatePermissions::EValue)(mBits[idx]);
+ }
+ return rv;
+}
+
+// returns the bits compressed into a single byte: 00TTMMCC
+// where TT = transfer, MM = modify, and CC = copy
+// LSB is to the right
+U8 LLAggregatePermissions::getU8() const
+{
+ U8 byte = mBits[PI_TRANSFER];
+ byte <<= 2;
+ byte |= mBits[PI_MODIFY];
+ byte <<= 2;
+ byte |= mBits[PI_COPY];
+ return byte;
+}
+
+BOOL LLAggregatePermissions::isEmpty() const
+{
+ for(S32 i = 0; i < PI_END; ++i)
+ {
+ if(mBits[i] != AP_EMPTY)
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+void LLAggregatePermissions::aggregate(PermissionMask mask)
+{
+ BOOL is_allowed = mask & PERM_COPY;
+ aggregateBit(PI_COPY, is_allowed);
+ is_allowed = mask & PERM_MODIFY;
+ aggregateBit(PI_MODIFY, is_allowed);
+ is_allowed = mask & PERM_TRANSFER;
+ aggregateBit(PI_TRANSFER, is_allowed);
+}
+
+void LLAggregatePermissions::aggregate(const LLAggregatePermissions& ag)
+{
+ for(S32 idx = PI_COPY; idx != PI_END; ++idx)
+ {
+ aggregateIndex((EPermIndex)idx, ag.mBits[idx]);
+ }
+}
+
+void LLAggregatePermissions::aggregateBit(EPermIndex idx, BOOL allowed)
+{
+ //if(AP_SOME == mBits[idx]) return; // P4 branch prediction optimization
+ switch(mBits[idx])
+ {
+ case AP_EMPTY:
+ mBits[idx] = allowed ? AP_ALL : AP_NONE;
+ break;
+ case AP_NONE:
+ mBits[idx] = allowed ? AP_SOME: AP_NONE;
+ break;
+ case AP_SOME:
+ // no-op
+ break;
+ case AP_ALL:
+ mBits[idx] = allowed ? AP_ALL : AP_SOME;
+ break;
+ default:
+ llwarns << "Bad aggregateBit " << (S32)idx << " "
+ << (allowed ? "true" : "false") << llendl;
+ break;
+ }
+}
+
+void LLAggregatePermissions::aggregateIndex(EPermIndex idx, U8 bits)
+{
+ switch(mBits[idx])
+ {
+ case AP_EMPTY:
+ mBits[idx] = bits;
+ break;
+ case AP_NONE:
+ switch(bits)
+ {
+ case AP_SOME:
+ case AP_ALL:
+ mBits[idx] = AP_SOME;
+ break;
+ case AP_EMPTY:
+ case AP_NONE:
+ default:
+ // no-op
+ break;
+ }
+ break;
+ case AP_SOME:
+ // no-op
+ break;
+ case AP_ALL:
+ switch(bits)
+ {
+ case AP_NONE:
+ case AP_SOME:
+ mBits[idx] = AP_SOME;
+ break;
+ case AP_EMPTY:
+ case AP_ALL:
+ default:
+ // no-op
+ break;
+ }
+ break;
+ default:
+ llwarns << "Bad aggregate index " << (S32)idx << " "
+ << (S32)bits << llendl;
+ break;
+ }
+}
+
+// static
+LLAggregatePermissions::EPermIndex LLAggregatePermissions::perm2PermIndex(PermissionBit bit)
+{
+ EPermIndex idx = PI_END; // past any good value.
+ switch(bit)
+ {
+ case PERM_COPY:
+ idx = PI_COPY;
+ break;
+ case PERM_MODIFY:
+ idx = PI_MODIFY;
+ break;
+ case PERM_TRANSFER:
+ idx = PI_TRANSFER;
+ break;
+ default:
+ break;
+ }
+ return idx;
+}
+
+
+void LLAggregatePermissions::packMessage(LLMessageSystem* msg, const char* field) const
+{
+ msg->addU8Fast(field, getU8());
+}
+
+void LLAggregatePermissions::unpackMessage(LLMessageSystem* msg, const char* block, const char* field, S32 block_num)
+{
+ const U8 TWO_BITS = 0x3; // binary 00000011
+ U8 bits = 0;
+ msg->getU8Fast(block, field, bits, block_num);
+ mBits[PI_COPY] = bits & TWO_BITS;
+ bits >>= 2;
+ mBits[PI_MODIFY] = bits & TWO_BITS;
+ bits >>= 2;
+ mBits[PI_TRANSFER] = bits & TWO_BITS;
+}
+
+const LLString AGGREGATE_VALUES[4] =
+ {
+ LLString( "Empty" ),
+ LLString( "None" ),
+ LLString( "Some" ),
+ LLString( "All" )
+ };
+
+std::ostream& operator<<(std::ostream &s, const LLAggregatePermissions &perm)
+{
+ s << "{PI_COPY=" << AGGREGATE_VALUES[perm.mBits[LLAggregatePermissions::PI_COPY]];
+ s << ", PI_MODIFY=" << AGGREGATE_VALUES[perm.mBits[LLAggregatePermissions::PI_MODIFY]];
+ s << ", PI_TRANSFER=" << AGGREGATE_VALUES[perm.mBits[LLAggregatePermissions::PI_TRANSFER]];
+ s << "}";
+ return s;
+}
+
+// This converts a permissions mask into a string for debugging use.
+void mask_to_string(U32 mask, char* str)
+{
+ if (mask & PERM_MOVE)
+ {
+ *str = 'V';
+ }
+ else
+ {
+ *str = ' ';
+ }
+ str++;
+
+ if (mask & PERM_MODIFY)
+ {
+ *str = 'M';
+ }
+ else
+ {
+ *str = ' ';
+ }
+ str++;
+
+ if (mask & PERM_COPY)
+ {
+ *str = 'C';
+ }
+ else
+ {
+ *str = ' ';
+ }
+ str++;
+
+ if (mask & PERM_TRANSFER)
+ {
+ *str = 'T';
+ }
+ else
+ {
+ *str = ' ';
+ }
+ str++;
+ *str = '\0';
+}
+
+
+///----------------------------------------------------------------------------
+/// exported functions
+///----------------------------------------------------------------------------
+static const std::string PERM_CREATOR_ID_LABEL("creator_id");
+static const std::string PERM_OWNER_ID_LABEL("owner_id");
+static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id");
+static const std::string PERM_GROUP_ID_LABEL("group_id");
+static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group");
+static const std::string PERM_BASE_MASK_LABEL("base_mask");
+static const std::string PERM_OWNER_MASK_LABEL("owner_mask");
+static const std::string PERM_GROUP_MASK_LABEL("group_mask");
+static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask");
+static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask");
+
+LLSD ll_create_sd_from_permissions(const LLPermissions& perm)
+{
+ LLSD rv;
+ rv[PERM_CREATOR_ID_LABEL] = perm.getCreator();
+ rv[PERM_OWNER_ID_LABEL] = perm.getOwner();
+ rv[PERM_LAST_OWNER_ID_LABEL] = perm.getLastOwner();
+ rv[PERM_GROUP_ID_LABEL] = perm.getGroup();
+ rv[PERM_IS_OWNER_GROUP_LABEL] = perm.isGroupOwned();
+ rv[PERM_BASE_MASK_LABEL] = (S32)perm.getMaskBase();
+ rv[PERM_OWNER_MASK_LABEL] = (S32)perm.getMaskOwner();
+ rv[PERM_GROUP_MASK_LABEL] = (S32)perm.getMaskGroup();
+ rv[PERM_EVERYONE_MASK_LABEL] = (S32)perm.getMaskEveryone();
+ rv[PERM_NEXT_OWNER_MASK_LABEL] = (S32)perm.getMaskNextOwner();
+ return rv;
+}
+
+LLPermissions ll_permissions_from_sd(const LLSD& sd_perm)
+{
+ LLPermissions rv;
+ rv.init(
+ sd_perm[PERM_CREATOR_ID_LABEL].asUUID(),
+ sd_perm[PERM_OWNER_ID_LABEL].asUUID(),
+ sd_perm[PERM_LAST_OWNER_ID_LABEL].asUUID(),
+ sd_perm[PERM_GROUP_ID_LABEL].asUUID());
+
+ // We do a cast to U32 here since LLSD does not attempt to
+ // represent unsigned ints.
+ PermissionMask mask;
+ mask = (U32)(sd_perm[PERM_BASE_MASK_LABEL].asInteger());
+ rv.setMaskBase(mask);
+ mask = (U32)(sd_perm[PERM_OWNER_MASK_LABEL].asInteger());
+ rv.setMaskOwner(mask);
+ mask = (U32)(sd_perm[PERM_EVERYONE_MASK_LABEL].asInteger());
+ rv.setMaskEveryone(mask);
+ mask = (U32)(sd_perm[PERM_GROUP_MASK_LABEL].asInteger());
+ rv.setMaskGroup(mask);
+ mask = (U32)(sd_perm[PERM_NEXT_OWNER_MASK_LABEL].asInteger());
+ rv.setMaskNext(mask);
+ rv.fix();
+ return rv;
+}
diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h
new file mode 100644
index 0000000000..76794e1ed9
--- /dev/null
+++ b/indra/llinventory/llpermissions.h
@@ -0,0 +1,426 @@
+/**
+ * @file llpermissions.h
+ * @brief Permissions structures for objects.
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLPERMISSIONS_H
+#define LL_LLPERMISSIONS_H
+
+#include <stdio.h>
+#include <iostream>
+
+#include "llpermissionsflags.h"
+#include "llsd.h"
+#include "lluuid.h"
+#include "llxmlnode.h"
+#include "reflective.h"
+
+// prototypes
+class LLMessageSystem;
+extern void mask_to_string(U32 mask, char* str);
+template<class T> class LLMetaClassT;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLPermissions
+//
+// Class which encapsulates object and inventory permissions/ownership/etc.
+//
+// Permissions where originally a static state creator/owner and set
+// of cap bits. Since then, it has grown to include group information,
+// last owner, masks for different people. The implementation has been
+// chosen such that a uuid is stored for each current/past owner, and
+// a bitmask is stored for the base permissions, owner permissions,
+// group permissions, and everyone else permissions.
+//
+// The base permissions represent the most permissive state that the
+// permissions can possibly be in. Thus, if the base permissions do
+// not allow copying, no one can ever copy the object. The permissions
+// also maintain a tree-like hierarchy of permissions, thus, if we
+// (for sake of discussions) denote more permissive as '>', then this
+// is invariant:
+//
+// base mask >= owner mask >= group mask
+// >= everyone mask
+// >= next owner mask
+// NOTE: the group mask does not effect everyone or next, everyone
+// does not effect group or next, etc.
+//
+// It is considered a fair use right to move or delete any object you
+// own. Another fair use right is the ability to give away anything
+// which you cannot copy. One way to look at that is that if you have
+// a unique item, you can always give that one copy you have to
+// someone else.
+//
+// Most of the bitmask is easy to understand, PERM_COPY means you can
+// copy !PERM_TRANSFER means you cannot transfer, etc. Given that we
+// now track the concept of 'next owner' inside of the permissions
+// object, we can describe some new meta-meaning to the PERM_MODIFY
+// flag. PERM_MODIFY is usually meant to note if you can change an
+// item, but since we record next owner permissions, we can interpret
+// a no-modify object as 'you cannot modify this object and you cannot
+// make derivative works.' When evaluating functionality, and
+// comparisons against permissions, keep this concept in mind for
+// logical consistency.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLPermissions : public LLReflective
+{
+private:
+ LLUUID mCreator; // null if object created by system
+ LLUUID mOwner; // null if object "unowned" (owned by system)
+ LLUUID mLastOwner; // object's last owner
+ LLUUID mGroup; // The group association
+
+ PermissionMask mMaskBase; // initially permissive, progressively AND restricted by each owner
+
+ PermissionMask mMaskOwner; // set by owner, applies to owner only, restricts lower permissions
+ PermissionMask mMaskEveryone; // set by owner, applies to everyone else
+
+ PermissionMask mMaskGroup; // set by owner, applies to group that is associated with permissions
+
+ PermissionMask mMaskNextOwner; // set by owner, applied to base on transfer.
+
+ // Usually set in the fixOwnership() method based on current uuid
+ // values.
+ bool mIsGroupOwned;
+
+ // Correct for fair use - you can never take away the right to
+ // move stuff you own, and you can never take away the right to
+ // transfer something you cannot otherwise copy.
+ void fixFairUse();
+
+ // Fix internal consistency for group/agent ownership
+ void fixOwnership();
+
+public:
+ static const LLPermissions DEFAULT;
+
+ LLPermissions(); // defaults to created by system
+ //~LLPermissions();
+
+ // base initialization code
+ void init(const LLUUID& creator, const LLUUID& owner,
+ const LLUUID& last_owner, const LLUUID& group);
+ void initMasks(PermissionMask base, PermissionMask owner,
+ PermissionMask everyone, PermissionMask group,
+ PermissionMask next);
+
+ //
+ // ACCESSORS
+ //
+
+ // return the agent_id of the agent that created the item
+ const LLUUID& getCreator() const { return mCreator; }
+
+ // return the agent_id of the owner. returns LLUUID::null if group
+ // owned or public (a really big group).
+ const LLUUID& getOwner() const { return mOwner; }
+
+ // return the group_id of the group associated with the
+ // object. group_id == owner_id if the object is group owned.
+ const LLUUID& getGroup() const { return mGroup; }
+
+ // return the agent_id of the last agent owner. Only returns
+ // LLUUID::null if there has never been a previous owner.
+ const LLUUID& getLastOwner() const { return mLastOwner; }
+
+ U32 getMaskBase() const { return mMaskBase; }
+ U32 getMaskOwner() const { return mMaskOwner; }
+ U32 getMaskGroup() const { return mMaskGroup; }
+ U32 getMaskEveryone() const { return mMaskEveryone; }
+ U32 getMaskNextOwner() const { return mMaskNextOwner; }
+
+ // return TRUE if the object has any owner
+ bool isOwned() const { return (mOwner.notNull() || mIsGroupOwned); }
+
+ // return TRUE if group_id is owner.
+ bool isGroupOwned() const { return mIsGroupOwned; }
+
+ // This API returns TRUE if the object is owned at all, and FALSE
+ // otherwise. If it is owned at all, owner id is filled with
+ // either the owner id or the group id, and the is_group_owned
+ // parameter is appropriately filled. The values of owner_id and
+ // is_group_owned are not changed if the object is not owned.
+ BOOL getOwnership(LLUUID& owner_id, BOOL& is_group_owned) const;
+
+ // Gets the 'safe' owner. This should never return LLUUID::null.
+ // If no group owned, return the agent owner id normally.
+ // If group owned, return the group id.
+ // If not owned, return a random uuid which should have no power.
+ LLUUID getSafeOwner() const;
+
+ // return a cheap crc
+ U32 getCRC32() const;
+
+
+ //
+ // MANIPULATORS
+ //
+
+ // Fix hierarchy of permissions, applies appropriate permissions
+ // at each level to ensure that base permissions are respected,
+ // and also ensures that if base cannot transfer, then group and
+ // other cannot copy.
+ void fix();
+
+ // All of these methods just do exactly what they say. There is no
+ // permissions checking to see if the operation is allowed, and do
+ // not fix the permissions hierarchy. So please only use these
+ // methods when you are know what you're doing and coding on
+ // behalf of the system - ie, acting as god.
+ void set(const LLPermissions& permissions);
+ void setMaskBase(U32 mask) { mMaskBase = mask; }
+ void setMaskOwner(U32 mask) { mMaskOwner = mask; }
+ void setMaskEveryone(U32 mask) { mMaskEveryone = mask;}
+ void setMaskGroup(U32 mask) { mMaskGroup = mask;}
+ void setMaskNext(U32 mask) { mMaskNextOwner = mask; }
+
+ // Allow accumulation of permissions. Results in the tightest
+ // permissions possible. In the case of clashing UUIDs, it sets
+ // the ID to LLUUID::null.
+ void accumulate(const LLPermissions& perm);
+
+ //
+ // CHECKED MANIPULATORS
+ //
+
+ // These functions return true on success. They return false if
+ // the given agent isn't allowed to make the change. You can pass
+ // LLUUID::null as the agent id if the change is being made by the
+ // simulator itself, not on behalf of any agent - this will always
+ // succeed. Passing in group id of LLUUID:null means no group, and
+ // does not offer special permission to do anything.
+
+ // saves last owner, sets current owner, and sets the group.
+ // set is_atomic = true means that this permission represents
+ // an atomic permission and not a collection of permissions.
+ // Currently, the only way to have a collection is when an object
+ // has inventory and is then itself rolled up into an inventory
+ // item.
+ BOOL setOwnerAndGroup(const LLUUID& agent, const LLUUID& owner, const LLUUID& group, bool is_atomic);
+
+ // saves last owner, sets owner to uuid null, sets group
+ // owned. group_id must be the group of the object (that's who it
+ // is being deeded to) and the object must be group
+ // modify. Technically, the agent id and group id are not
+ // necessary, but I wanted this function to look like the other
+ // checked manipulators (since that is how it is used.) If the
+ // agent is the system or (group == mGroup and group modify and
+ // owner transfer) then this function will deed the permissions,
+ // set the next owner mask, and return TRUE. Otherwise, no change
+ // is effected, and the function returns FALSE.
+ BOOL deedToGroup(const LLUUID& agent, const LLUUID& group);
+ // Attempt to set or clear the given bitmask. Returns TRUE if you
+ // are allowed to modify the permissions. If you attempt to turn
+ // on bits not allowed by the base bits, the function will return
+ // TRUE, but those bits will not be set.
+ BOOL setBaseBits( const LLUUID& agent, BOOL set, PermissionMask bits);
+ BOOL setOwnerBits( const LLUUID& agent, BOOL set, PermissionMask bits);
+ BOOL setGroupBits( const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits);
+ BOOL setEveryoneBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits);
+ BOOL setNextOwnerBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits);
+
+ //
+ // METHODS
+ //
+
+ // All the allow* functions return true if the given agent or
+ // group can perform the function. Prefer using this set of
+ // operations to check permissions on an object. These return
+ // true if the given agent or group can perform the function.
+ // They also return true if the object isn't owned, or the
+ // requesting agent is a system agent. See llpermissionsflags.h
+ // for bits.
+ BOOL allowOperationBy(PermissionBit op, const LLUUID& agent, const LLUUID& group = LLUUID::null) const;
+
+ inline BOOL allowModifyBy(const LLUUID &agent_id) const;
+ inline BOOL allowCopyBy(const LLUUID& agent_id) const;
+ inline BOOL allowMoveBy(const LLUUID& agent_id) const;
+ inline BOOL allowModifyBy(const LLUUID &agent_id, const LLUUID& group) const;
+ inline BOOL allowCopyBy(const LLUUID& agent_id, const LLUUID& group) const;
+ inline BOOL allowMoveBy(const LLUUID &agent_id, const LLUUID &group) const;
+
+ // This somewhat specialized function is meant for testing if the
+ // current owner is allowed to transfer to the specified agent id.
+ inline BOOL allowTransferTo(const LLUUID &agent_id) const;
+
+ //
+ // DEPRECATED.
+ //
+ // These return true if the given agent can perform the function.
+ // They also return true if the object isn't owned, or the
+ // requesting agent is a system agent. See llpermissionsflags.h
+ // for bits.
+ //BOOL allowDeleteBy(const LLUUID& agent_id) const { return allowModifyBy(agent_id); }
+ //BOOL allowEditBy(const LLUUID& agent_id) const { return allowModifyBy(agent_id); }
+ // saves last owner and sets current owner
+ //BOOL setOwner(const LLUUID& agent, const LLUUID& owner);
+ // This method saves the last owner, sets the current owner to the
+ // one provided, and sets the base mask as indicated.
+ //BOOL setOwner(const LLUUID& agent, const LLUUID& owner, U32 new_base_mask);
+
+ // Attempt to set or clear the given bitmask. Returns TRUE if you
+ // are allowed to modify the permissions. If you attempt to turn
+ // on bits not allowed by the base bits, the function will return
+ // TRUE, but those bits will not be set.
+ //BOOL setGroupBits( const LLUUID& agent, BOOL set, PermissionMask bits);
+ //BOOL setEveryoneBits(const LLUUID& agent, BOOL set, PermissionMask bits);
+
+ //
+ // MISC METHODS and OPERATORS
+ //
+
+ // For messaging system support
+ void packMessage(LLMessageSystem* msg) const;
+ void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
+
+ // Load/save support
+ BOOL importFile(FILE* fp);
+ BOOL exportFile(FILE* fp) const;
+
+ BOOL importLegacyStream(std::istream& input_stream);
+ BOOL exportLegacyStream(std::ostream& output_stream) const;
+
+ LLXMLNode *exportFileXML() const;
+ bool importXML(LLXMLNode* node);
+
+ bool operator==(const LLPermissions &rhs) const;
+ bool operator!=(const LLPermissions &rhs) const;
+
+ friend std::ostream& operator<<(std::ostream &s, const LLPermissions &perm);
+
+ // Reflection.
+ friend class LLMetaClassT<LLPermissions>;
+ virtual const LLMetaClass& getMetaClass() const;
+};
+
+// Inlines
+BOOL LLPermissions::allowModifyBy(const LLUUID& agent, const LLUUID& group) const
+{
+ return allowOperationBy(PERM_MODIFY, agent, group);
+}
+
+BOOL LLPermissions::allowCopyBy(const LLUUID& agent, const LLUUID& group) const
+{
+ return allowOperationBy(PERM_COPY, agent, group);
+}
+
+
+BOOL LLPermissions::allowMoveBy(const LLUUID& agent, const LLUUID& group) const
+{
+ return allowOperationBy(PERM_MOVE, agent, group);
+}
+
+BOOL LLPermissions::allowModifyBy(const LLUUID& agent) const
+{
+ return allowOperationBy(PERM_MODIFY, agent, LLUUID::null);
+}
+
+BOOL LLPermissions::allowCopyBy(const LLUUID& agent) const
+{
+ return allowOperationBy(PERM_COPY, agent, LLUUID::null);
+}
+
+BOOL LLPermissions::allowMoveBy(const LLUUID& agent) const
+{
+ return allowOperationBy(PERM_MOVE, agent, LLUUID::null);
+}
+
+BOOL LLPermissions::allowTransferTo(const LLUUID &agent_id) const
+{
+ if (mIsGroupOwned)
+ {
+ return allowOperationBy(PERM_TRANSFER, mGroup, mGroup);
+ }
+ else
+ {
+ return ((mOwner == agent_id) ? TRUE : allowOperationBy(PERM_TRANSFER, mOwner));
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLAggregatePermissions
+//
+// Class which encapsulates object and inventory permissions,
+// ownership, etc. Currently, it only aggregates PERM_COPY,
+// PERM_MODIFY, and PERM_TRANSFER.
+//
+// Usually you will construct an instance and hand the object several
+// permissions masks to aggregate the copy, modify, and
+// transferability into a nice trinary value.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLAggregatePermissions
+{
+public:
+ enum EValue
+ {
+ AP_EMPTY = 0x00,
+ AP_NONE = 0x01,
+ AP_SOME = 0x02,
+ AP_ALL = 0x03
+ };
+
+ // construct an empty aggregate permissions
+ LLAggregatePermissions();
+
+ // pass in a PERM_COPY, PERM_TRANSFER, etc, and get out a EValue
+ // enumeration describing the current aggregate permissions.
+ EValue getValue(PermissionBit bit) const;
+
+ // returns the permissions packed into the 6 LSB of a U8:
+ // 00TTMMCC
+ // where TT = transfer, MM = modify, and CC = copy
+ // LSB is to the right
+ U8 getU8() const;
+
+ // return TRUE is the aggregate permissions are empty, otherwise FALSE.
+ BOOL isEmpty() const ;
+
+ // pass in a PERM_COPY, PERM_TRANSFER, etc, and an EValue
+ // enumeration to specifically set that value. Not implemented
+ // because I'm not sure it's a useful api.
+ //void setValue(PermissionBit bit, EValue);
+
+ // Given a mask, aggregate the useful permissions.
+ void aggregate(PermissionMask mask);
+
+ // Aggregate aggregates
+ void aggregate(const LLAggregatePermissions& ag);
+
+ // message handling
+ void packMessage(LLMessageSystem* msg, const char* field) const;
+ void unpackMessage(LLMessageSystem* msg, const char* block, const char *field, S32 block_num = 0);
+
+ static const LLAggregatePermissions empty;
+
+ friend std::ostream& operator<<(std::ostream &s, const LLAggregatePermissions &perm);
+
+protected:
+ enum EPermIndex
+ {
+ PI_COPY = 0,
+ PI_MODIFY = 1,
+ PI_TRANSFER = 2,
+ PI_END = 3,
+ PI_COUNT = 3
+ };
+ void aggregateBit(EPermIndex idx, BOOL allowed);
+ void aggregateIndex(EPermIndex idx, U8 bits);
+ static EPermIndex perm2PermIndex(PermissionBit bit);
+
+ // structure used to store the aggregate so far.
+ U8 mBits[PI_COUNT];
+};
+
+// These functions convert between structured data and permissions as
+// appropriate for serialization. The permissions are a map of things
+// like 'creator_id', 'owner_id', etc, with the value copied from the
+// permission object.
+LLSD ll_create_sd_from_permissions(const LLPermissions& perm);
+LLPermissions ll_permissions_from_sd(const LLSD& sd_perm);
+
+#endif
diff --git a/indra/llinventory/llpermissionsflags.h b/indra/llinventory/llpermissionsflags.h
new file mode 100644
index 0000000000..f45758c501
--- /dev/null
+++ b/indra/llinventory/llpermissionsflags.h
@@ -0,0 +1,78 @@
+/**
+ * @file llpermissionsflags.h
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLPERMISSIONSFLAGS_H
+#define LL_LLPERMISSIONSFLAGS_H
+
+// llpermissionsflags.h
+// Copyright 2002, Linden Research, Inc.
+//
+// Flags for various permissions bits.
+// Shared between viewer and simulator.
+
+// permission bits
+typedef U32 PermissionMask;
+typedef U32 PermissionBit;
+
+
+// Do you have permission to transfer ownership of the object or
+// item. Fair use rules dictate that if you cannot copy, you can
+// always transfer.
+const PermissionBit PERM_TRANSFER = (1 << 13); // 0x00002000
+
+// objects, scale or change textures
+// parcels, allow building on it
+const PermissionBit PERM_MODIFY = (1 << 14); // 0x00004000
+
+// objects, allow copy
+const PermissionBit PERM_COPY = (1 << 15); // 0x00008000
+
+// parcels, allow entry, deprecated
+//const PermissionBit PERM_ENTER = (1 << 16); // 0x00010000
+
+// parcels, allow terraform, deprecated
+//const PermissionBit PERM_TERRAFORM = (1 << 17); // 0x00020000
+
+// NOTA BENE: This flag is NO LONGER USED!!! However, it is possible that some
+// objects in the universe have it set so DON"T USE IT going forward.
+//const PermissionBit PERM_OWNER_DEBIT = (1 << 18); // 0x00040000
+
+// objects, can grab/translate/rotate
+const PermissionBit PERM_MOVE = (1 << 19); // 0x00080000
+
+// parcels, avatars take damage, deprecated
+//const PermissionBit PERM_DAMAGE = (1 << 20); // 0x00100000
+
+// don't use bit 31 -- printf/scanf with "%x" assume signed numbers
+const PermissionBit PERM_RESERVED = ((U32)1) << 31;
+
+const PermissionMask PERM_NONE = 0x00000000;
+const PermissionMask PERM_ALL = 0x7FFFFFFF;
+//const PermissionMask PERM_ALL_PARCEL = PERM_MODIFY | PERM_ENTER | PERM_TERRAFORM | PERM_DAMAGE;
+const PermissionMask PERM_ITEM_UNRESTRICTED = PERM_MODIFY | PERM_COPY | PERM_TRANSFER;
+
+
+// Useful stuff for transmission.
+// Which permissions field are we trying to change?
+const U8 PERM_BASE = 0x01;
+// TODO: Add another PERM_OWNER operation type for allowOperationBy DK 04/03/06
+const U8 PERM_OWNER = 0x02;
+const U8 PERM_GROUP = 0x04;
+const U8 PERM_EVERYONE = 0x08;
+const U8 PERM_NEXT_OWNER = 0x10;
+
+// This is just a quickie debugging key
+// no modify: PERM_ALL & ~PERM_MODIFY = 0x7fffbfff
+// no copy: PERM_ALL & ~PERM_COPY = 0x7fff7fff
+// no modify or copy: = 0x7fff3fff
+// no transfer: PERM_ALL & ~PERM_TRANSFER = 0x7fffdfff
+// no modify, no transfer = 0x7fff9fff
+// no copy, no transfer (INVALID!) = 0x7fff5fff
+// no modify, no copy, no transfer (INVALID!) = 0x7fff1fff
+
+
+#endif
diff --git a/indra/llinventory/llsaleinfo.cpp b/indra/llinventory/llsaleinfo.cpp
new file mode 100644
index 0000000000..7e2b293d42
--- /dev/null
+++ b/indra/llinventory/llsaleinfo.cpp
@@ -0,0 +1,356 @@
+/**
+ * @file llsaleinfo.cpp
+ * @brief
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include <iostream>
+#include "linden_common.h"
+
+#include "llsaleinfo.h"
+
+#include "llerror.h"
+#include "message.h"
+#include "llsdutil.h"
+
+// use this to avoid temporary object creation
+const LLSaleInfo LLSaleInfo::DEFAULT;
+
+///----------------------------------------------------------------------------
+/// Local function declarations, constants, enums, and typedefs
+///----------------------------------------------------------------------------
+
+const char* FOR_SALE_NAMES[] =
+{
+ "not",
+ "orig",
+ "copy",
+ "cntn"
+};
+
+///----------------------------------------------------------------------------
+/// Class llsaleinfo
+///----------------------------------------------------------------------------
+
+// Default constructor
+LLSaleInfo::LLSaleInfo() :
+ mSaleType(LLSaleInfo::FS_NOT),
+ mSalePrice(DEFAULT_PRICE)
+{
+}
+
+LLSaleInfo::LLSaleInfo(EForSale sale_type, S32 sale_price) :
+ mSaleType(sale_type),
+ mSalePrice(sale_price)
+{
+ mSalePrice = llclamp(mSalePrice, 0, S32_MAX);
+}
+
+BOOL LLSaleInfo::isForSale() const
+{
+ return (FS_NOT != mSaleType);
+}
+
+U32 LLSaleInfo::getCRC32() const
+{
+ U32 rv = (U32)mSalePrice;
+ rv += (mSaleType * 0x07073096);
+ return rv;
+}
+
+
+BOOL LLSaleInfo::exportFile(FILE* fp) const
+{
+ fprintf(fp, "\tsale_info\t0\n\t{\n");
+ fprintf(fp, "\t\tsale_type\t%s\n", lookup(mSaleType));
+ fprintf(fp, "\t\tsale_price\t%d\n", mSalePrice);
+ fprintf(fp,"\t}\n");
+ return TRUE;
+}
+
+BOOL LLSaleInfo::exportLegacyStream(std::ostream& output_stream) const
+{
+ output_stream << "\tsale_info\t0\n\t{\n";
+ output_stream << "\t\tsale_type\t" << lookup(mSaleType) << "\n";
+ output_stream << "\t\tsale_price\t" << mSalePrice << "\n";
+ output_stream <<"\t}\n";
+ return TRUE;
+}
+
+LLSD LLSaleInfo::asLLSD() const
+{
+ LLSD sd = LLSD();
+ sd["sale_type"] = lookup(mSaleType);
+ sd["sale_price"] = mSalePrice;
+ return sd;
+}
+
+bool LLSaleInfo::fromLLSD(LLSD& sd, BOOL& has_perm_mask, U32& perm_mask)
+{
+ const char *w;
+
+ mSaleType = lookup(sd["sale_type"].asString().c_str());
+ mSalePrice = llclamp(sd["sale_price"].asInteger(), 0, S32_MAX);
+ w = "perm_mask";
+ if (sd.has(w))
+ {
+ has_perm_mask = TRUE;
+ perm_mask = ll_U32_from_sd(sd[w]);
+ }
+ return true;
+}
+
+LLXMLNode *LLSaleInfo::exportFileXML() const
+{
+ LLXMLNode *ret = new LLXMLNode("sale_info", FALSE);
+ LLString type_str = lookup(mSaleType);
+ ret->createChild("type", TRUE)->setStringValue(1, &type_str);
+ ret->createChild("price", TRUE)->setIntValue(1, &mSalePrice);
+ return ret;
+}
+
+BOOL LLSaleInfo::importXML(LLXMLNode* node)
+{
+ BOOL success = FALSE;
+ if (node)
+ {
+ success = TRUE;
+ LLXMLNodePtr sub_node;
+ if (node->getChild("type", sub_node))
+ {
+ mSaleType = lookup(sub_node->getValue().c_str());
+ }
+ if (node->getChild("price", sub_node))
+ {
+ success &= (1 == sub_node->getIntValue(1, &mSalePrice));
+ }
+ if (!success)
+ {
+ lldebugs << "LLSaleInfo::importXML() failed for node named '"
+ << node->getName() << "'" << llendl;
+ }
+ }
+ return success;
+}
+
+BOOL LLSaleInfo::importFile(FILE* fp, BOOL& has_perm_mask, U32& perm_mask)
+{
+ has_perm_mask = FALSE;
+
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+ BOOL success = TRUE;
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+ while(success && (!feof(fp)))
+ {
+ fgets(buffer, MAX_STRING, fp);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("sale_type", keyword))
+ {
+ mSaleType = lookup(valuestr);
+ }
+ else if(0 == strcmp("sale_price", keyword))
+ {
+ sscanf(valuestr, "%d", &mSalePrice);
+ mSalePrice = llclamp(mSalePrice, 0, S32_MAX);
+ }
+ else if (!strcmp("perm_mask", keyword))
+ {
+ //llinfos << "found deprecated keyword perm_mask" << llendl;
+ has_perm_mask = TRUE;
+ sscanf(valuestr, "%x", &perm_mask);
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in sale info import" << llendl;
+ }
+ }
+ return success;
+}
+
+BOOL LLSaleInfo::importLegacyStream(std::istream& input_stream, BOOL& has_perm_mask, U32& perm_mask)
+{
+ has_perm_mask = FALSE;
+
+ char buffer[MAX_STRING];
+ char keyword[MAX_STRING];
+ char valuestr[MAX_STRING];
+ BOOL success = TRUE;
+
+ keyword[0] = '\0';
+ valuestr[0] = '\0';
+ while(success && input_stream.good())
+ {
+ input_stream.getline(buffer, MAX_STRING);
+ sscanf(buffer, " %s %s", keyword, valuestr);
+ if(!keyword)
+ {
+ continue;
+ }
+ if(0 == strcmp("{",keyword))
+ {
+ continue;
+ }
+ if(0 == strcmp("}", keyword))
+ {
+ break;
+ }
+ else if(0 == strcmp("sale_type", keyword))
+ {
+ mSaleType = lookup(valuestr);
+ }
+ else if(0 == strcmp("sale_price", keyword))
+ {
+ sscanf(valuestr, "%d", &mSalePrice);
+ mSalePrice = llclamp(mSalePrice, 0, S32_MAX);
+ }
+ else if (!strcmp("perm_mask", keyword))
+ {
+ //llinfos << "found deprecated keyword perm_mask" << llendl;
+ has_perm_mask = TRUE;
+ sscanf(valuestr, "%x", &perm_mask);
+ }
+ else
+ {
+ llwarns << "unknown keyword '" << keyword
+ << "' in sale info import" << llendl;
+ }
+ }
+ return success;
+}
+
+void LLSaleInfo::setSalePrice(S32 price)
+{
+ mSalePrice = price;
+ mSalePrice = llclamp(mSalePrice, 0, S32_MAX);
+}
+
+void LLSaleInfo::packMessage(LLMessageSystem* msg) const
+{
+ U8 sale_type = static_cast<U8>(mSaleType);
+ msg->addU8Fast(_PREHASH_SaleType, sale_type);
+ msg->addS32Fast(_PREHASH_SalePrice, mSalePrice);
+ //msg->addU32Fast(_PREHASH_NextOwnerMask, mNextOwnerPermMask);
+}
+
+void LLSaleInfo::unpackMessage(LLMessageSystem* msg, const char* block)
+{
+ U8 sale_type;
+ msg->getU8Fast(block, _PREHASH_SaleType, sale_type);
+ mSaleType = static_cast<EForSale>(sale_type);
+ msg->getS32Fast(block, _PREHASH_SalePrice, mSalePrice);
+ mSalePrice = llclamp(mSalePrice, 0, S32_MAX);
+ //msg->getU32Fast(block, _PREHASH_NextOwnerMask, mNextOwnerPermMask);
+}
+
+void LLSaleInfo::unpackMultiMessage(LLMessageSystem* msg, const char* block,
+ S32 block_num)
+{
+ U8 sale_type;
+ msg->getU8Fast(block, _PREHASH_SaleType, sale_type, block_num);
+ mSaleType = static_cast<EForSale>(sale_type);
+ msg->getS32Fast(block, _PREHASH_SalePrice, mSalePrice, block_num);
+ mSalePrice = llclamp(mSalePrice, 0, S32_MAX);
+ //msg->getU32Fast(block, _PREHASH_NextOwnerMask, mNextOwnerPermMask, block_num);
+}
+
+LLSaleInfo::EForSale LLSaleInfo::lookup(const char* name)
+{
+ for(S32 i = 0; i < FS_COUNT; i++)
+ {
+ if(0 == strcmp(name, FOR_SALE_NAMES[i]))
+ {
+ // match
+ return (EForSale)i;
+ }
+ }
+ return FS_NOT;
+}
+
+const char* LLSaleInfo::lookup(EForSale type)
+{
+ if((type >= 0) && (type < FS_COUNT))
+ {
+ return FOR_SALE_NAMES[S32(type)];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// Allow accumulation of sale info. The price of each is added,
+// conflict in sale type results in FS_NOT, and the permissions are
+// tightened.
+void LLSaleInfo::accumulate(const LLSaleInfo& sale_info)
+{
+ if(mSaleType != sale_info.mSaleType)
+ {
+ mSaleType = FS_NOT;
+ }
+ mSalePrice += sale_info.mSalePrice;
+ //mNextOwnerPermMask &= sale_info.mNextOwnerPermMask;
+}
+
+bool LLSaleInfo::operator==(const LLSaleInfo &rhs) const
+{
+ return (
+ (mSaleType == rhs.mSaleType) &&
+ (mSalePrice == rhs.mSalePrice)
+ );
+}
+
+bool LLSaleInfo::operator!=(const LLSaleInfo &rhs) const
+{
+ return (
+ (mSaleType != rhs.mSaleType) ||
+ (mSalePrice != rhs.mSalePrice)
+ );
+}
+
+
+///----------------------------------------------------------------------------
+/// Local function definitions
+///----------------------------------------------------------------------------
+
+///----------------------------------------------------------------------------
+/// exported functions
+///----------------------------------------------------------------------------
+static const std::string ST_TYPE_LABEL("sale_type");
+static const std::string ST_PRICE_LABEL("sale_price");
+
+LLSD ll_create_sd_from_sale_info(const LLSaleInfo& sale)
+{
+ LLSD rv;
+ const char* type = LLSaleInfo::lookup(sale.getSaleType());
+ if(!type) type = LLSaleInfo::lookup(LLSaleInfo::FS_NOT);
+ rv[ST_TYPE_LABEL] = type;
+ rv[ST_PRICE_LABEL] = sale.getSalePrice();
+ return rv;
+}
+
+LLSaleInfo ll_sale_info_from_sd(const LLSD& sd)
+{
+ LLSaleInfo rv;
+ rv.setSaleType(LLSaleInfo::lookup(sd[ST_TYPE_LABEL].asString().c_str()));
+ rv.setSalePrice(llclamp((S32)sd[ST_PRICE_LABEL], 0, S32_MAX));
+ return rv;
+}
diff --git a/indra/llinventory/llsaleinfo.h b/indra/llinventory/llsaleinfo.h
new file mode 100644
index 0000000000..2eceea87ef
--- /dev/null
+++ b/indra/llinventory/llsaleinfo.h
@@ -0,0 +1,110 @@
+/**
+ * @file llsaleinfo.h
+ * @brief LLSaleInfo class header file.
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLSALEINFO_H
+#define LL_LLSALEINFO_H
+
+#include <stdio.h>
+#include <iostream>
+
+#include "llpermissionsflags.h"
+#include "llsd.h"
+#include "llxmlnode.h"
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLSaleInfo
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// L$ default price for objects
+const S32 DEFAULT_PRICE = 10;
+
+class LLMessageSystem;
+
+class LLSaleInfo
+{
+public:
+ // use this to avoid temporary object creation
+ static const LLSaleInfo DEFAULT;
+
+ enum EForSale
+ {
+ // item is not to be considered for transactions
+ FS_NOT = 0,
+
+ // the origional is on sale
+ FS_ORIGINAL = 1,
+
+ // A copy is for sale
+ FS_COPY = 2,
+
+ // Valid only for tasks, the inventory is for sale
+ // at the price in this structure.
+ FS_CONTENTS = 3,
+
+ FS_COUNT
+ };
+
+protected:
+ EForSale mSaleType;
+ S32 mSalePrice;
+
+public:
+ // default constructor is fine usually
+ LLSaleInfo();
+ LLSaleInfo(EForSale sale_type, S32 sale_price);
+
+ // accessors
+ BOOL isForSale() const;
+ EForSale getSaleType() const { return mSaleType; }
+ S32 getSalePrice() const { return mSalePrice; }
+ U32 getCRC32() const;
+
+ // mutators
+ void setSaleType(EForSale type) { mSaleType = type; }
+ void setSalePrice(S32 price);
+ //void setNextOwnerPermMask(U32 mask) { mNextOwnerPermMask = mask; }
+
+
+ // file serialization
+ BOOL exportFile(FILE* fp) const;
+ BOOL importFile(FILE* fp, BOOL& has_perm_mask, U32& perm_mask);
+
+ BOOL exportLegacyStream(std::ostream& output_stream) const;
+ LLSD asLLSD() const;
+ operator LLSD() const { return asLLSD(); }
+ bool fromLLSD(LLSD& sd, BOOL& has_perm_mask, U32& perm_mask);
+ BOOL importLegacyStream(std::istream& input_stream, BOOL& has_perm_mask, U32& perm_mask);
+
+ LLXMLNode *exportFileXML() const;
+ BOOL importXML(LLXMLNode* node);
+
+ // message serialization
+ void packMessage(LLMessageSystem* msg) const;
+ void unpackMessage(LLMessageSystem* msg, const char* block);
+ void unpackMultiMessage(LLMessageSystem* msg, const char* block,
+ S32 block_num);
+
+ // static functionality for determine for sale status.
+ static EForSale lookup(const char* name);
+ static const char* lookup(EForSale type);
+
+ // Allow accumulation of sale info. The price of each is added,
+ // conflict in sale type results in FS_NOT, and the permissions
+ // are tightened.
+ void accumulate(const LLSaleInfo& sale_info);
+
+ bool operator==(const LLSaleInfo &rhs) const;
+ bool operator!=(const LLSaleInfo &rhs) const;
+};
+
+// These functions convert between structured data and sale info as
+// appropriate for serialization.
+LLSD ll_create_sd_from_sale_info(const LLSaleInfo& sale);
+LLSaleInfo ll_sale_info_from_sd(const LLSD& sd);
+
+#endif // LL_LLSALEINFO_H
diff --git a/indra/llinventory/lltransactionflags.cpp b/indra/llinventory/lltransactionflags.cpp
new file mode 100644
index 0000000000..3f1aa14959
--- /dev/null
+++ b/indra/llinventory/lltransactionflags.cpp
@@ -0,0 +1,43 @@
+/**
+ * @file lltransactionflags.cpp
+ * @brief Some exported symbols and functions for dealing with
+ * transaction flags.
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "lltransactionflags.h"
+
+const U8 TRANSACTION_FLAGS_NONE = 0;
+const U8 TRANSACTION_FLAG_SOURCE_GROUP = 1;
+const U8 TRANSACTION_FLAG_DEST_GROUP = 2;
+const U8 TRANSACTION_FLAG_OWNER_GROUP = 4;
+const U8 TRANSACTION_FLAG_SIMULTANEOUS_CONTRIBUTION = 8;
+const U8 TRANSACTION_FLAG_SIMULTANEOUS_CONTRIBUTION_REMOVAL = 16;
+
+U8 pack_transaction_flags(BOOL is_source_group, BOOL is_dest_group)
+{
+ U8 rv = 0;
+ if(is_source_group) rv |= TRANSACTION_FLAG_SOURCE_GROUP;
+ if(is_dest_group) rv |= TRANSACTION_FLAG_DEST_GROUP;
+ return rv;
+}
+
+BOOL is_tf_source_group(TransactionFlags flags)
+{
+ return ((flags & TRANSACTION_FLAG_SOURCE_GROUP) == TRANSACTION_FLAG_SOURCE_GROUP);
+}
+
+BOOL is_tf_dest_group(TransactionFlags flags)
+{
+ return ((flags & TRANSACTION_FLAG_DEST_GROUP) == TRANSACTION_FLAG_DEST_GROUP);
+}
+
+BOOL is_tf_owner_group(TransactionFlags flags)
+{
+ return ((flags & TRANSACTION_FLAG_OWNER_GROUP) == TRANSACTION_FLAG_OWNER_GROUP);
+}
+
diff --git a/indra/llinventory/lltransactionflags.h b/indra/llinventory/lltransactionflags.h
new file mode 100644
index 0000000000..eaa138fef7
--- /dev/null
+++ b/indra/llinventory/lltransactionflags.h
@@ -0,0 +1,27 @@
+/**
+ * @file lltransactionflags.h
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLTRANSACTIONFLAGS_H
+#define LL_LLTRANSACTIONFLAGS_H
+
+typedef U8 TransactionFlags;
+
+// defined in common/llinventory/lltransactionflags.cpp
+extern const TransactionFlags TRANSACTION_FLAGS_NONE;
+extern const TransactionFlags TRANSACTION_FLAG_SOURCE_GROUP;
+extern const TransactionFlags TRANSACTION_FLAG_DEST_GROUP;
+extern const TransactionFlags TRANSACTION_FLAG_OWNER_GROUP;
+extern const TransactionFlags TRANSACTION_FLAG_SIMULTANEOUS_CONTRIBUTION;
+extern const TransactionFlags TRANSACTION_FLAG_SIMULTANEOUS_CONTRIBUTION_REMOVAL;
+
+// very simple helper functions
+TransactionFlags pack_transaction_flags(BOOL is_source_group, BOOL is_dest_group);
+BOOL is_tf_source_group(TransactionFlags flags);
+BOOL is_tf_dest_group(TransactionFlags flags);
+BOOL is_tf_owner_group(TransactionFlags flags);
+
+#endif // LL_LLTRANSACTIONFLAGS_H
diff --git a/indra/llinventory/lltransactiontypes.h b/indra/llinventory/lltransactiontypes.h
new file mode 100644
index 0000000000..d7894b2fdb
--- /dev/null
+++ b/indra/llinventory/lltransactiontypes.h
@@ -0,0 +1,93 @@
+/**
+ * @file lltransactiontypes.h
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLTRANSACTIONTYPES_H
+#define LL_LLTRANSACTIONTYPES_H
+
+// *NOTE: The constants in this file are also in the
+// transaction_description table in the database. If you add a
+// constant here, please add it to the database. eg:
+//
+// insert into transaction_description
+// set type = 1000, description = 'Object Claim';
+//
+// Also add it to the various money string lookups on the dataserver
+// in lldatamoney
+
+// Money transaction failure codes
+const U8 TRANS_FAIL_SIMULATOR_TIMEOUT = 1;
+const U8 TRANS_FAIL_DATASERVER_TIMEOUT = 2;
+
+// Codes up to 999 for error conditions
+const S32 TRANS_NULL = 0;
+
+// Codes 1000-1999 reserved for one-time charges
+const S32 TRANS_OBJECT_CLAIM = 1000;
+const S32 TRANS_LAND_CLAIM = 1001;
+const S32 TRANS_GROUP_CREATE = 1002;
+const S32 TRANS_OBJECT_PUBLIC_CLAIM = 1003;
+const S32 TRANS_GROUP_JOIN = 1004; // May be moved to group transactions eventually
+const S32 TRANS_TELEPORT_CHARGE = 1100; // FF not sure why this jumps to 1100...
+const S32 TRANS_UPLOAD_CHARGE = 1101;
+const S32 TRANS_LAND_AUCTION = 1102;
+const S32 TRANS_CLASSIFIED_CHARGE = 1103;
+
+// Codes 2000-2999 reserved for recurrent charges
+const S32 TRANS_OBJECT_TAX = 2000;
+const S32 TRANS_LAND_TAX = 2001;
+const S32 TRANS_LIGHT_TAX = 2002;
+const S32 TRANS_PARCEL_DIR_FEE = 2003;
+const S32 TRANS_GROUP_TAX = 2004; // Taxes incurred as part of group membership
+const S32 TRANS_CLASSIFIED_RENEW = 2005;
+
+// Codes 3000-3999 reserved for inventory transactions
+const S32 TRANS_GIVE_INVENTORY = 3000;
+
+// Codes 5000-5999 reserved for transfers between users
+const S32 TRANS_OBJECT_SALE = 5000;
+const S32 TRANS_GIFT = 5001;
+const S32 TRANS_LAND_SALE = 5002;
+const S32 TRANS_REFER_BONUS = 5003;
+const S32 TRANS_INVENTORY_SALE = 5004;
+const S32 TRANS_REFUND_PURCHASE = 5005;
+const S32 TRANS_LAND_PASS_SALE = 5006;
+const S32 TRANS_DWELL_BONUS = 5007;
+const S32 TRANS_PAY_OBJECT = 5008;
+const S32 TRANS_OBJECT_PAYS = 5009;
+
+// Codes 6000-6999 reserved for group transactions
+//const S32 TRANS_GROUP_JOIN = 6000; //reserved for future use
+const S32 TRANS_GROUP_LAND_DEED = 6001;
+const S32 TRANS_GROUP_OBJECT_DEED = 6002;
+const S32 TRANS_GROUP_LIABILITY = 6003;
+const S32 TRANS_GROUP_DIVIDEND = 6004;
+const S32 TRANS_MEMBERSHIP_DUES = 6005;
+
+// Codes 8000-8999 reserved for one-type credits
+const S32 TRANS_OBJECT_RELEASE = 8000;
+const S32 TRANS_LAND_RELEASE = 8001;
+const S32 TRANS_OBJECT_DELETE = 8002;
+const S32 TRANS_OBJECT_PUBLIC_DECAY = 8003;
+const S32 TRANS_OBJECT_PUBLIC_DELETE= 8004;
+
+// Code 9000-9099 reserved for usertool transactions
+const S32 TRANS_LINDEN_ADJUSTMENT = 9000;
+const S32 TRANS_LINDEN_GRANT = 9001;
+const S32 TRANS_LINDEN_PENALTY = 9002;
+const S32 TRANS_EVENT_FEE = 9003;
+const S32 TRANS_EVENT_PRIZE = 9004;
+
+// These must match entries in money_stipend table in MySQL
+// Codes 10000-10999 reserved for stipend credits
+const S32 TRANS_STIPEND_BASIC = 10000;
+const S32 TRANS_STIPEND_DEVELOPER = 10001;
+const S32 TRANS_STIPEND_ALWAYS = 10002;
+const S32 TRANS_STIPEND_DAILY = 10003;
+const S32 TRANS_STIPEND_RATING = 10004;
+const S32 TRANS_STIPEND_DELTA = 10005;
+
+#endif
diff --git a/indra/llinventory/lluserrelations.cpp b/indra/llinventory/lluserrelations.cpp
new file mode 100644
index 0000000000..c10f6f610a
--- /dev/null
+++ b/indra/llinventory/lluserrelations.cpp
@@ -0,0 +1,89 @@
+/**
+ * @file lluserrealations.cpp
+ * @author Phoenix
+ * @date 2006-10-12
+ * @brief Implementation of a simple cache of user relations.
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+#include "lluserrelations.h"
+
+// static
+const U8 LLRelationship::GRANTED_VISIBLE_MASK = LLRelationship::GRANT_MODIFY_OBJECTS | LLRelationship::GRANT_MAP_LOCATION;
+const LLRelationship LLRelationship::DEFAULT_RELATIONSHIP = LLRelationship(GRANT_ONLINE_STATUS, GRANT_ONLINE_STATUS, false);
+
+LLRelationship::LLRelationship() :
+ mGrantToAgent(0),
+ mGrantFromAgent(0),
+ mIsOnline(false)
+{
+}
+
+LLRelationship::LLRelationship(S32 grant_to, S32 grant_from, bool is_online) :
+ mGrantToAgent(grant_to),
+ mGrantFromAgent(grant_from),
+ mIsOnline(is_online)
+{
+}
+
+bool LLRelationship::isOnline() const
+{
+ return mIsOnline;
+}
+
+void LLRelationship::online(bool is_online)
+{
+ mIsOnline = is_online;
+}
+
+bool LLRelationship::isRightGrantedTo(S32 rights) const
+{
+ return ((mGrantToAgent & rights) == rights);
+}
+
+bool LLRelationship::isRightGrantedFrom(S32 rights) const
+{
+ return ((mGrantFromAgent & rights) == rights);
+}
+
+S32 LLRelationship::getRightsGrantedTo() const
+{
+ return mGrantToAgent;
+}
+
+S32 LLRelationship::getRightsGrantedFrom() const
+{
+ return mGrantFromAgent;
+}
+
+void LLRelationship::grantRights(S32 to_agent, S32 from_agent)
+{
+ mGrantToAgent |= to_agent;
+ mGrantFromAgent |= from_agent;
+}
+
+void LLRelationship::revokeRights(S32 to_agent, S32 from_agent)
+{
+ mGrantToAgent &= ~to_agent;
+ mGrantFromAgent &= ~from_agent;
+}
+
+
+
+/*
+bool LLGrantedRights::getNextRights(
+ LLUUID& agent_id,
+ S32& to_agent,
+ S32& from_agent) const
+{
+ rights_map_t::const_iterator iter = mRights.upper_bound(agent_id);
+ if(iter == mRights.end()) return false;
+ agent_id = (*iter).first;
+ to_agent = (*iter).second.mToAgent;
+ from_agent = (*iter).second.mFromAgent;
+ return true;
+}
+*/
diff --git a/indra/llinventory/lluserrelations.h b/indra/llinventory/lluserrelations.h
new file mode 100644
index 0000000000..7c24254339
--- /dev/null
+++ b/indra/llinventory/lluserrelations.h
@@ -0,0 +1,154 @@
+/**
+ * @file llluserrelations.h
+ * @author Phoenix
+ * @date 2006-10-12
+ * @brief Declaration of a class for handling granted rights.
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLUSERRELAIONS_H
+#define LL_LLUSERRELAIONS_H
+
+#include <map>
+#include "lluuid.h"
+
+/**
+ * @class LLRelationship
+ *
+ * This class represents a relationship between two agents, where the
+ * related agent is stored and the other agent is the relationship is
+ * implicit by container ownership.
+ * This is merely a cache of this information used by the sim
+ * and viewer.
+ *
+ * You are expected to use this in a map or similar structure, eg:
+ * typedef std::map<LLUUID, LLRelationship> agent_relationship_map;
+ */
+class LLRelationship
+{
+public:
+ /**
+ * @brief Constructors.
+ */
+ LLRelationship();
+ LLRelationship(S32 grant_to, S32 grant_from, bool is_online);
+
+ static const LLRelationship DEFAULT_RELATIONSHIP;
+
+ /**
+ * @name Status functionality
+ *
+ * I thought it would be keen to have a generic status interface,
+ * but the only thing we currently cache is online status. As this
+ * assumption changes, this API may evolve.
+ */
+ //@{
+ /**
+ * @brief Does this instance believe the related agent is currently
+ * online or available.
+ *
+ * NOTE: This API may be deprecated if there is any transient status
+ * other than online status, for example, away/busy/etc.
+ *
+ * This call does not check any kind of central store or make any
+ * deep information calls - it simply checks a cache of online
+ * status.
+ * @return Returns true if this relationship believes the agent is
+ * online.
+ */
+ bool isOnline() const;
+
+ /**
+ * @brief Set the online status.
+ *
+ * NOTE: This API may be deprecated if there is any transient status
+ * other than online status.
+ * @param is_online Se the online status
+ */
+ void online(bool is_online);
+ //@}
+
+ /* @name Granted rights
+ */
+ //@{
+ /**
+ * @brief Anonymous enumeration for specifying rights.
+ */
+ enum
+ {
+ GRANT_NONE = 0x0,
+ GRANT_ONLINE_STATUS = 0x1,
+ GRANT_MAP_LOCATION = 0x2,
+ GRANT_MODIFY_OBJECTS = 0x4,
+ };
+
+ /**
+ * ???
+ */
+ static const U8 GRANTED_VISIBLE_MASK;
+
+ /**
+ * @brief Check for a set of rights granted to agent.
+ *
+ * @param rights A bitfield to check for rights.
+ * @return Returns true if all rights have been granted.
+ */
+ bool isRightGrantedTo(S32 rights) const;
+
+ /**
+ * @brief Check for a set of rights granted from an agent.
+ *
+ * @param rights A bitfield to check for rights.
+ * @return Returns true if all rights have been granted.
+ */
+ bool isRightGrantedFrom(S32 rights) const;
+
+ /**
+ * @brief Get the rights granted to the other agent.
+ *
+ * @return Returns the bitmask of granted rights.
+ */
+ S32 getRightsGrantedTo() const;
+
+ /**
+ * @brief Get the rights granted from the other agent.
+ *
+ * @return Returns the bitmask of granted rights.
+ */
+ S32 getRightsGrantedFrom() const;
+
+ void setRightsTo(S32 to_agent) { mGrantToAgent = to_agent; }
+ void setRightsFrom(S32 from_agent) { mGrantFromAgent = from_agent; }
+
+ /**
+ * @brief Grant a set of rights.
+ *
+ * Any bit which is set will grant that right if it is set in the
+ * instance. You can pass in LLGrantedRights::NONE to not change
+ * that field.
+ * @param to_agent The rights to grant to agent_id.
+ * @param from_agent The rights granted from agent_id.
+ */
+ void grantRights(S32 to_agent, S32 from_agent);
+
+ /**
+ * @brief Revoke a set of rights.
+ *
+ * Any bit which is set will revoke that right if it is set in the
+ * instance. You can pass in LLGrantedRights::NONE to not change
+ * that field.
+ * @param to_agent The rights to grant to agent_id.
+ * @param from_agent The rights granted from agent_id.
+ */
+ void revokeRights(S32 to_agent, S32 from_agent);
+ //@}
+
+protected:
+ S32 mGrantToAgent;
+ S32 mGrantFromAgent;
+ bool mIsOnline;
+};
+
+#endif // LL_LLUSERRELAIONS_H