Files
SingularityViewer/indra/llinventory/llparcel.cpp

1357 lines
35 KiB
C++

/**
* @file llparcel.cpp
* @brief A land parcel.
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "indra_constants.h"
#include <iostream>
#include "llparcel.h"
#include "llstreamtools.h"
#include "llmath.h"
#include "llsd.h"
#include "llsdutil.h"
#include "lltransactiontypes.h"
#include "lltransactionflags.h"
#include "llsdutil_math.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 std::string PARCEL_OWNERSHIP_STATUS_STRING[LLParcel::OS_COUNT+1] =
{
"leased",
"lease_pending",
"abandoned",
"none"
};
// NOTE: Adding parcel categories also requires updating:
// * floater_directory.xml category combobox
// * floater_about_land.xml category combobox
// * Web site "create event" tools
// DO NOT DELETE ITEMS FROM THIS LIST WITHOUT DEEPLY UNDERSTANDING WHAT YOU'RE DOING.
//
static const std::string 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",
"rental"
};
static const std::string PARCEL_CATEGORY_UI_STRING[LLParcel::C_COUNT + 1] =
{
"None",
"Linden Location",
"Adult",
"Arts and Culture",
"Business",
"Educational",
"Gaming",
"Hangout",
"Newcomer Friendly",
"Parks and Nature",
"Residential",
"Shopping",
"Stage",
"Other",
"Rental",
"Any", // valid string for parcel searches
};
static const std::string PARCEL_ACTION_STRING[LLParcel::A_COUNT + 1] =
{
"create",
"release",
"absorb",
"absorbed",
"divide",
"division",
"acquire",
"relinquish",
"confirm",
"unknown"
};
//const char* revert_action_to_string(LLParcel::ESaleTimerExpireAction action);
//LLParcel::ESaleTimerExpireAction revert_string_to_action(const char* s);
const std::string& category_to_ui_string(LLParcel::ECategory category);
LLParcel::ECategory category_ui_string_to_category(const std::string& 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;
mInEscrow = false;
mParcelFlags = PF_DEFAULT;
setParcelFlag(PF_CREATE_OBJECTS, modify);
setParcelFlag(PF_ALLOW_TERRAFORM, terraform);
setParcelFlag(PF_ALLOW_DAMAGE, damage);
mSalePrice = 10000;
setName(LLStringUtil::null);
setDesc(LLStringUtil::null);
setMusicURL(LLStringUtil::null);
setMediaURL(LLStringUtil::null);
setMediaDesc(LLStringUtil::null);
setMediaType(LLStringUtil::null);
mMediaID.setNull();
mMediaAutoScale = 0;
mMediaLoop = TRUE;
mMediaWidth = 0;
mMediaHeight = 0;
setMediaCurrentURL(LLStringUtil::null);
mMediaURLFilterEnable = FALSE;
mMediaURLFilterList = LLSD::emptyArray();
mMediaAllowNavigate = TRUE;
mMediaURLTimeout = 0.0f;
mMediaPreventCameraZoom = FALSE;
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);
setRegionPushOverride(FALSE);
setRegionDenyAnonymousOverride(FALSE);
setRegionDenyAgeUnverifiedOverride(FALSE);
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 LLParcel::setName(const std::string& name)
{
// The escaping here must match the escaping in the database
// abstraction layer.
mName = name;
LLStringFn::replace_nonprintable_in_ascii(mName, LL_UNKNOWN_CHAR);
}
void LLParcel::setDesc(const std::string& desc)
{
// The escaping here must match the escaping in the database
// abstraction layer.
mDesc = desc;
mDesc = rawstr_to_utf8(mDesc);
}
void LLParcel::setMusicURL(const std::string& url)
{
mMusicURL = url;
// 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_in_ascii(mMusicURL, LL_UNKNOWN_CHAR);
}
void LLParcel::setMediaURL(const std::string& url)
{
mMediaURL = url;
// 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_in_ascii(mMediaURL, LL_UNKNOWN_CHAR);
}
void LLParcel::setMediaDesc(const std::string& desc)
{
// The escaping here must match the escaping in the database
// abstraction layer.
mMediaDesc = desc;
mMediaDesc = rawstr_to_utf8(mMediaDesc);
}
void LLParcel::setMediaType(const std::string& type)
{
// The escaping here must match the escaping in the database
// abstraction layer.
mMediaType = type;
mMediaType = rawstr_to_utf8(mMediaType);
// This code attempts to preserve legacy movie functioning
if(mMediaType.empty() && ! mMediaURL.empty())
{
setMediaType(std::string("video/vnd.secondlife.qt.legacy"));
}
}
void LLParcel::setMediaWidth(S32 width)
{
mMediaWidth = width;
}
void LLParcel::setMediaHeight(S32 height)
{
mMediaHeight = height;
}
void LLParcel::setMediaCurrentURL(const std::string& url)
{
mMediaCurrentURL = url;
// 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_in_ascii(mMediaCurrentURL, LL_UNKNOWN_CHAR);
}
void LLParcel::setMediaURLResetTimer(F32 time)
{
mMediaResetTimer.start();
mMediaResetTimer.setTimerExpirySec(time);
}
void LLParcel::setMediaURLFilterList(LLSD list)
{
// sanity check LLSD
// must be array of strings
if (!list.isArray())
{
return;
}
for (S32 i = 0; i < list.size(); i++)
{
if (!list[i].isString())
return;
}
// can't be too big
const S32 MAX_SIZE = 50;
if (list.size() > MAX_SIZE)
{
LLSD new_list = LLSD::emptyArray();
for (S32 i = 0; i < llmin(list.size(), MAX_SIZE); i++)
{
new_list.append(list[i]);
}
list = new_list;
}
mMediaURLFilterList = list;
}
// virtual
void LLParcel::setLocalID(S32 local_id)
{
mLocalID = local_id;
}
void LLParcel::setAllParcelFlags(U32 flags)
{
mParcelFlags = flags;
}
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 uuid_vec_t& group_ids,
const BOOL is_agent_identified,
const BOOL is_agent_transacted,
const BOOL is_agent_ageverified)
{
S32 current_group_access = parcelp->blockAccess(agent_id, LLUUID::null, is_agent_identified, is_agent_transacted, is_agent_ageverified);
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, is_agent_ageverified);
if (current_group_access == BA_ALLOWED) is_allowed = true;
}
return !is_allowed;
}
BOOL LLParcel::isAgentBanned(const LLUUID& agent_id) const
{
// Test ban list
if (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 BOOL is_agent_ageverified) 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;
}
// AgeUnverified - Not Age Verified
if(getParcelFlag(PF_DENY_AGEUNVERIFIED) && !is_agent_ageverified)
{
return BA_NOT_AGE_VERIFIED;
}
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
//-----------------------------------------------------------
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);
std::string 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 );
}
else if ("name" == keyword)
{
// deprecated
}
else if ("time" == keyword)
{
S32 when = -1;
LLStringUtil::convertToS32(value, when);
entry->mTime = when;
}
else if ("flags" == keyword)
{
U32 setting = 0xFFFFFFFF;
LLStringUtil::convertToU32(value, setting);
entry->mFlags = setting;
}
else
{
llwarns << "Unknown keyword in parcel access entry section: <"
<< keyword << ">" << llendl;
}
}
return input_stream.good();
}
BOOL LLParcel::importMediaURLFilter(std::istream& input_stream, std::string& url)
{
skip_to_end_of_next_keyword("{", input_stream);
while(input_stream.good())
{
skip_comments_and_emptyspace(input_stream);
std::string line, keyword, value;
get_line(line, input_stream, MAX_STRING);
get_keyword_and_value(keyword, value, line);
if ("}" == keyword)
{
break;
}
else if ("url" == keyword)
{
url = value;
}
else
{
llwarns << "Unknown keyword in parcel media url filter section: <"
<< keyword << ">" << llendl;
}
}
return input_stream.good();
}
// 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);
}
// Assumes we are in a block "ParcelData"
void LLParcel::packMessage(LLSD& msg)
{
// used in the viewer, the sim uses it's own packer
msg["local_id"] = getLocalID();
msg["parcel_flags"] = ll_sd_from_U32(getParcelFlags());
msg["sale_price"] = getSalePrice();
msg["name"] = getName();
msg["description"] = getDesc();
msg["music_url"] = getMusicURL();
msg["media_url"] = getMediaURL();
msg["media_desc"] = getMediaDesc();
msg["media_type"] = getMediaType();
msg["media_width"] = getMediaWidth();
msg["media_height"] = getMediaHeight();
msg["auto_scale"] = getMediaAutoScale();
msg["media_loop"] = getMediaLoop();
msg["media_current_url"] = getMediaCurrentURL();
msg["obscure_media"] = false; // OBSOLETE - no longer used
msg["obscure_music"] = false; // OBSOLETE - no longer used
msg["media_id"] = getMediaID();
msg["media_allow_navigate"] = getMediaAllowNavigate();
msg["media_prevent_camera_zoom"] = getMediaPreventCameraZoom();
msg["media_url_timeout"] = getMediaURLTimeout();
msg["media_url_filter_enable"] = getMediaURLFilterEnable();
msg["media_url_filter_list"] = getMediaURLFilterList();
msg["group_id"] = getGroupID();
msg["pass_price"] = mPassPrice;
msg["pass_hours"] = mPassHours;
msg["category"] = (U8)mCategory;
msg["auth_buyer_id"] = mAuthBuyerID;
msg["snapshot_id"] = mSnapshotID;
msg["user_location"] = ll_sd_from_vector3(mUserLocation);
msg["user_look_at"] = ll_sd_from_vector3(mUserLookAt);
msg["landing_type"] = (U8)mLandingType;
}
void LLParcel::unpackMessage(LLMessageSystem* msg)
{
std::string buffer;
msg->getU32Fast( _PREHASH_ParcelData,_PREHASH_ParcelFlags, mParcelFlags );
msg->getS32Fast( _PREHASH_ParcelData,_PREHASH_SalePrice, mSalePrice );
msg->getStringFast( _PREHASH_ParcelData,_PREHASH_Name, buffer );
setName(buffer);
msg->getStringFast( _PREHASH_ParcelData,_PREHASH_Desc, buffer );
setDesc(buffer);
msg->getStringFast( _PREHASH_ParcelData,_PREHASH_MusicURL, buffer );
setMusicURL(buffer);
msg->getStringFast( _PREHASH_ParcelData,_PREHASH_MediaURL, 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;
// New Media Data
// Note: the message has been converted to TCP
if(msg->has("MediaData"))
{
msg->getString("MediaData", "MediaDesc", buffer);
setMediaDesc(buffer);
msg->getString("MediaData", "MediaType", buffer);
setMediaType(buffer);
msg->getS32("MediaData", "MediaWidth", mMediaWidth);
msg->getS32("MediaData", "MediaHeight", mMediaHeight);
msg->getU8 ( "MediaData", "MediaLoop", mMediaLoop );
}
else
{
setMediaType(std::string("video/vnd.secondlife.qt.legacy"));
setMediaDesc(std::string("No Description available without Server Upgrade"));
mMediaLoop = true;
}
if(msg->getNumberOfBlocks("MediaLinkSharing") > 0)
{
msg->getString("MediaLinkSharing", "MediaCurrentURL", buffer);
setMediaCurrentURL(buffer);
msg->getU8 ( "MediaLinkSharing", "MediaAllowNavigate", mMediaAllowNavigate );
msg->getU8 ( "MediaLinkSharing", "MediaURLFilterEnable", mMediaURLFilterEnable );
msg->getU8 ( "MediaLinkSharing", "MediaPreventCameraZoom", mMediaPreventCameraZoom );
msg->getF32( "MediaLinkSharing", "MediaURLTimeout", mMediaURLTimeout);
}
else
{
setMediaCurrentURL(LLStringUtil::null);
}
}
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 (mAccessList.size() >= (U32) PARCEL_MAX_ACCESS_LIST)
{
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 (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 std::string& LLParcel::getOwnershipStatusString(EOwnershipStatus status)
{
return ownership_status_to_string(status);
}
// static
const std::string& LLParcel::getCategoryString(ECategory category)
{
return category_to_string(category);
}
// static
const std::string& LLParcel::getCategoryUIString(ECategory category)
{
return category_to_ui_string(category);
}
// static
LLParcel::ECategory LLParcel::getCategoryFromString(const std::string& string)
{
return category_string_to_category(string);
}
// static
LLParcel::ECategory LLParcel::getCategoryFromUIString(const std::string& string)
{
return category_ui_string_to_category(string);
}
// static
const std::string& 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;
}
BOOL LLParcel::isMediaResetTimerExpired(const U64& time)
{
if (mMediaResetTimer.getStarted() == FALSE)
{
return FALSE;
}
BOOL expired = mMediaResetTimer.checkExpirationAndReset(0.0);
if (expired)
{
mMediaResetTimer.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);
setAuctionID(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;
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();
// Purchased parcels are assumed to no longer be for sale.
// Otherwise someone can snipe the sale.
setForSale(FALSE);
setAuctionID(0);
// 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);
setAuctionID(0);
setPreviousOwnerID(LLUUID::null);
setPreviouslyGroupOwned(FALSE);
setSellWithObjects(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(LLStringUtil::null);
setDesc(LLStringUtil::null);
setMediaURL(LLStringUtil::null);
setMediaType(LLStringUtil::null);
setMediaID(LLUUID::null);
setMediaDesc(LLStringUtil::null);
setMediaAutoScale(0);
setMediaLoop(TRUE);
mMediaWidth = 0;
mMediaHeight = 0;
setMediaCurrentURL(LLStringUtil::null);
setMediaURLFilterList(LLSD::emptyArray());
setMediaURLFilterEnable(FALSE);
setMediaAllowNavigate(TRUE);
setMediaPreventCameraZoom(FALSE);
setMediaURLTimeout(0.0f);
setMusicURL(LLStringUtil::null);
setInEscrow(FALSE);
setAuthorizedBuyerID(LLUUID::null);
setCategory(C_NONE);
setSnapshotID(LLUUID::null);
setUserLocation(LLVector3::zero);
setUserLookAt(LLVector3::x_axis);
setLandingType(L_LANDING_POINT);
setAuctionID(0);
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 std::string& ownership_status_to_string(LLParcel::EOwnershipStatus status)
{
if(status >= 0 && status < LLParcel::OS_COUNT)
{
return PARCEL_OWNERSHIP_STATUS_STRING[status];
}
return PARCEL_OWNERSHIP_STATUS_STRING[LLParcel::OS_COUNT];
}
LLParcel::EOwnershipStatus ownership_string_to_status(const std::string& s)
{
for(S32 i = 0; i < LLParcel::OS_COUNT; ++i)
{
if(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 std::string& category_to_string(LLParcel::ECategory category)
{
S32 index = 0;
if((category >= 0) && (category < LLParcel::C_COUNT))
{
index = category;
}
return PARCEL_CATEGORY_STRING[index];
}
const std::string& 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);
}
return PARCEL_CATEGORY_UI_STRING[index];
}
LLParcel::ECategory category_string_to_category(const std::string& s)
{
for(S32 i = 0; i < LLParcel::C_COUNT; ++i)
{
if(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 std::string& s)
{
for(S32 i = 0; i < LLParcel::C_COUNT; ++i)
{
if(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;
}