summaryrefslogtreecommitdiff
path: root/indra/llinventory/llparcel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llinventory/llparcel.cpp')
-rw-r--r--indra/llinventory/llparcel.cpp1813
1 files changed, 1813 insertions, 0 deletions
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;
+}
+