diff options
Diffstat (limited to 'indra/llinventory/llparcel.cpp')
-rw-r--r-- | indra/llinventory/llparcel.cpp | 1813 |
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; +} + |