PageRenderTime 102ms CodeModel.GetById 17ms app.highlight 76ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llinventory/llparcel.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1375 lines | 1070 code | 155 blank | 150 comment | 166 complexity | a55df9cf061afce071d966d52c4d65e5 MD5 | raw file
   1/** 
   2 * @file llparcel.cpp
   3 * @brief A land parcel.
   4 *
   5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "linden_common.h"
  28
  29#include "indra_constants.h"
  30#include <iostream>
  31
  32#include "llparcel.h"
  33#include "llstreamtools.h"
  34
  35#include "llmath.h"
  36#include "llsd.h"
  37#include "llsdutil.h"
  38#include "lltransactiontypes.h"
  39#include "lltransactionflags.h"
  40#include "llsdutil_math.h"
  41#include "message.h"
  42#include "u64.h"
  43
  44static const F32 SOME_BIG_NUMBER = 1000.0f;
  45static const F32 SOME_BIG_NEG_NUMBER = -1000.0f;
  46static const std::string PARCEL_OWNERSHIP_STATUS_STRING[LLParcel::OS_COUNT+1] =
  47{
  48    "leased",
  49    "lease_pending",
  50    "abandoned",
  51    "none"
  52};
  53
  54// NOTE: Adding parcel categories also requires updating:
  55// * floater_about_land.xml category combobox
  56// * Web site "create event" tools
  57// DO NOT DELETE ITEMS FROM THIS LIST WITHOUT DEEPLY UNDERSTANDING WHAT YOU'RE DOING.
  58//
  59static const std::string PARCEL_CATEGORY_STRING[LLParcel::C_COUNT] =
  60{
  61    "none",
  62    "linden",
  63    "adult",
  64    "arts",
  65    "store", // "business" legacy name
  66    "educational",
  67    "game",	 // "gaming" legacy name
  68    "gather", // "hangout" legacy name
  69    "newcomer",
  70    "park",
  71    "home",	 // "residential" legacy name
  72    "shopping",
  73    "stage",
  74    "other",
  75	"rental"
  76};
  77static const std::string PARCEL_CATEGORY_UI_STRING[LLParcel::C_COUNT + 1] =
  78{
  79    "None",
  80    "Linden Location",
  81    "Adult",
  82    "Arts and Culture",
  83    "Business",
  84    "Educational",
  85    "Gaming",
  86    "Hangout",
  87    "Newcomer Friendly",
  88    "Parks and Nature",
  89    "Residential",
  90    "Shopping",
  91    "Stage",
  92    "Other",
  93	"Rental",
  94    "Any",	 // valid string for parcel searches
  95};
  96
  97static const std::string PARCEL_ACTION_STRING[LLParcel::A_COUNT + 1] =
  98{
  99    "create",
 100    "release",
 101    "absorb",
 102    "absorbed",
 103    "divide",
 104    "division",
 105    "acquire",
 106    "relinquish",
 107    "confirm",
 108    "unknown"
 109};
 110
 111
 112
 113//const char* revert_action_to_string(LLParcel::ESaleTimerExpireAction action);
 114//LLParcel::ESaleTimerExpireAction revert_string_to_action(const char* s);
 115const std::string& category_to_ui_string(LLParcel::ECategory category);
 116LLParcel::ECategory category_ui_string_to_category(const std::string& s);
 117
 118LLParcel::LLParcel()
 119{
 120    init(LLUUID::null, TRUE, FALSE, FALSE, 0, 0, 0, 0, 0, 1.f, 0);
 121}
 122
 123
 124LLParcel::LLParcel(const LLUUID &owner_id,
 125                   BOOL modify, BOOL terraform, BOOL damage,
 126                   time_t claim_date, S32 claim_price_per_meter,
 127                   S32 rent_price_per_meter, S32 area, S32 sim_object_limit, F32 parcel_object_bonus,
 128                   BOOL is_group_owned)
 129{
 130    init( owner_id, modify, terraform, damage, claim_date,
 131          claim_price_per_meter, rent_price_per_meter, area, sim_object_limit, parcel_object_bonus,
 132          is_group_owned);
 133}
 134
 135
 136// virtual
 137LLParcel::~LLParcel()
 138{
 139    // user list cleaned up by LLDynamicArray destructor.
 140}
 141
 142void LLParcel::init(const LLUUID &owner_id,
 143                    BOOL modify, BOOL terraform, BOOL damage,
 144                    time_t claim_date, S32 claim_price_per_meter,
 145                    S32 rent_price_per_meter, S32 area, S32 sim_object_limit, F32 parcel_object_bonus,
 146                    BOOL is_group_owned)
 147{
 148	mID.setNull();
 149	mOwnerID			= owner_id;
 150	mGroupOwned			= is_group_owned;
 151	mClaimDate			= claim_date;
 152	mClaimPricePerMeter	= claim_price_per_meter;
 153	mRentPricePerMeter	= rent_price_per_meter;
 154	mArea				= area;
 155	mDiscountRate		= 1.0f;
 156	mDrawDistance		= 512.f;
 157
 158	mUserLookAt.setVec(0.0f, 0.f, 0.f);
 159	// Default to using the parcel's landing point, if any.
 160	mLandingType = L_LANDING_POINT;
 161
 162	// *FIX: if owner_id != null, should be owned or sale pending,
 163	// investigate init callers.
 164	mStatus = OS_NONE;
 165	mCategory = C_NONE;
 166	mAuthBuyerID.setNull();
 167	//mBuyerID.setNull();
 168	//mJoinNeighbors = 0x0;
 169	mSaleTimerExpires.setTimerExpirySec(0);
 170	mSaleTimerExpires.stop();
 171	mGraceExtension = 0;
 172	//mExpireAction = STEA_REVERT;
 173	//mRecordTransaction = FALSE;
 174
 175	mAuctionID = 0;
 176	mInEscrow = false;
 177
 178	mParcelFlags = PF_DEFAULT;
 179	setParcelFlag(PF_CREATE_OBJECTS,  modify);
 180	setParcelFlag(PF_ALLOW_TERRAFORM, terraform);
 181	setParcelFlag(PF_ALLOW_DAMAGE,    damage);
 182
 183	mSalePrice			= 10000;
 184	setName(LLStringUtil::null);
 185	setDesc(LLStringUtil::null);
 186	setMusicURL(LLStringUtil::null);
 187	setMediaURL(LLStringUtil::null);
 188	setMediaDesc(LLStringUtil::null);
 189	setMediaType(LLStringUtil::null);
 190	mMediaID.setNull();
 191	mMediaAutoScale = 0;
 192	mMediaLoop = TRUE;
 193	mMediaWidth = 0;
 194	mMediaHeight = 0;
 195	setMediaCurrentURL(LLStringUtil::null);
 196	mMediaURLFilterEnable = FALSE;
 197	mMediaURLFilterList = LLSD::emptyArray();
 198	mMediaAllowNavigate = TRUE;
 199	mMediaURLTimeout = 0.0f;
 200	mMediaPreventCameraZoom = FALSE;
 201
 202	mGroupID.setNull();
 203
 204	mPassPrice = PARCEL_PASS_PRICE_DEFAULT;
 205	mPassHours = PARCEL_PASS_HOURS_DEFAULT;
 206
 207	mAABBMin.setVec(SOME_BIG_NUMBER, SOME_BIG_NUMBER, SOME_BIG_NUMBER);
 208	mAABBMax.setVec(SOME_BIG_NEG_NUMBER, SOME_BIG_NEG_NUMBER, SOME_BIG_NEG_NUMBER);
 209
 210	mLocalID = 0;
 211
 212	//mSimWidePrimCorrection = 0;
 213	setMaxPrimCapacity((S32)(sim_object_limit * area / (F32)(REGION_WIDTH_METERS * REGION_WIDTH_METERS)));
 214	setSimWideMaxPrimCapacity(0);
 215	setSimWidePrimCount(0);
 216	setOwnerPrimCount(0);
 217	setGroupPrimCount(0);
 218	setOtherPrimCount(0);
 219	setSelectedPrimCount(0);
 220	setTempPrimCount(0);
 221	setCleanOtherTime(0);
 222    setRegionPushOverride(FALSE);
 223    setRegionDenyAnonymousOverride(FALSE);
 224    setRegionDenyAgeUnverifiedOverride(FALSE);
 225	setParcelPrimBonus(parcel_object_bonus);
 226
 227	setPreviousOwnerID(LLUUID::null);
 228	setPreviouslyGroupOwned(FALSE);
 229
 230	setSeeAVs(TRUE);
 231	setAllowGroupAVSounds(TRUE);
 232	setAllowAnyAVSounds(TRUE);
 233	setHaveNewParcelLimitData(FALSE);
 234}
 235
 236void LLParcel::overrideOwner(const LLUUID& owner_id, BOOL is_group_owned)
 237{
 238    // Override with system permission (LLUUID::null)
 239    // Overridden parcels have no group
 240    mOwnerID = owner_id;
 241    mGroupOwned = is_group_owned;
 242    if(mGroupOwned)
 243    {
 244        mGroupID = mOwnerID;
 245    }
 246    else
 247    {
 248        mGroupID.setNull();
 249    }
 250    mInEscrow = false;
 251}
 252
 253void LLParcel::overrideParcelFlags(U32 flags)
 254{
 255    mParcelFlags = flags;
 256}
 257void LLParcel::setName(const std::string& name)
 258{
 259    // The escaping here must match the escaping in the database
 260    // abstraction layer.
 261    mName = name;
 262    LLStringFn::replace_nonprintable_in_ascii(mName, LL_UNKNOWN_CHAR);
 263}
 264
 265void LLParcel::setDesc(const std::string& desc)
 266{
 267    // The escaping here must match the escaping in the database
 268    // abstraction layer.
 269    mDesc = desc;
 270    mDesc = rawstr_to_utf8(mDesc);
 271}
 272
 273void LLParcel::setMusicURL(const std::string& url)
 274{
 275    mMusicURL = url;
 276    // The escaping here must match the escaping in the database
 277    // abstraction layer.
 278    // This should really filter the url in some way. Other than
 279    // simply requiring non-printable.
 280    LLStringFn::replace_nonprintable_in_ascii(mMusicURL, LL_UNKNOWN_CHAR);
 281}
 282
 283void LLParcel::setMediaURL(const std::string& url)
 284{
 285    mMediaURL = url;
 286    // The escaping here must match the escaping in the database
 287    // abstraction layer if it's ever added.
 288    // This should really filter the url in some way. Other than
 289    // simply requiring non-printable.
 290    LLStringFn::replace_nonprintable_in_ascii(mMediaURL, LL_UNKNOWN_CHAR);
 291}
 292
 293void LLParcel::setMediaDesc(const std::string& desc)
 294{
 295	// The escaping here must match the escaping in the database
 296	// abstraction layer.
 297	mMediaDesc = desc;
 298	mMediaDesc = rawstr_to_utf8(mMediaDesc);
 299}
 300void LLParcel::setMediaType(const std::string& type)
 301{
 302	// The escaping here must match the escaping in the database
 303	// abstraction layer.
 304	mMediaType = type;
 305	mMediaType = rawstr_to_utf8(mMediaType);
 306
 307	// This code attempts to preserve legacy movie functioning
 308	if(mMediaType.empty() && ! mMediaURL.empty())
 309	{
 310		setMediaType(std::string("video/vnd.secondlife.qt.legacy"));
 311	}
 312}
 313void LLParcel::setMediaWidth(S32 width)
 314{
 315	mMediaWidth = width;
 316}
 317void LLParcel::setMediaHeight(S32 height)
 318{
 319	mMediaHeight = height;
 320}
 321
 322void LLParcel::setMediaCurrentURL(const std::string& url)
 323{
 324    mMediaCurrentURL = url;
 325    // The escaping here must match the escaping in the database
 326    // abstraction layer if it's ever added.
 327    // This should really filter the url in some way. Other than
 328    // simply requiring non-printable.
 329    LLStringFn::replace_nonprintable_in_ascii(mMediaCurrentURL, LL_UNKNOWN_CHAR);
 330	
 331}
 332
 333void LLParcel::setMediaURLResetTimer(F32 time)
 334{
 335	mMediaResetTimer.start();
 336	mMediaResetTimer.setTimerExpirySec(time);
 337}
 338
 339void LLParcel::setMediaURLFilterList(LLSD list)
 340{
 341	// sanity check LLSD
 342	// must be array of strings
 343	if (!list.isArray())
 344	{
 345		return;
 346	}
 347
 348	for (S32 i = 0; i < list.size(); i++)
 349	{
 350		if (!list[i].isString())
 351			return;
 352	}
 353
 354	// can't be too big
 355	const S32 MAX_SIZE = 50;
 356	if (list.size() > MAX_SIZE)
 357	{
 358		LLSD new_list = LLSD::emptyArray();
 359
 360		for (S32 i = 0; i < llmin(list.size(), MAX_SIZE); i++)
 361		{
 362			new_list.append(list[i]);
 363		}
 364
 365		list = new_list;
 366	}
 367	
 368	mMediaURLFilterList = list;
 369}
 370
 371// virtual
 372void LLParcel::setLocalID(S32 local_id)
 373{
 374    mLocalID = local_id;
 375}
 376
 377void LLParcel::setAllParcelFlags(U32 flags)
 378{
 379    mParcelFlags = flags;
 380}
 381
 382void LLParcel::setParcelFlag(U32 flag, BOOL b)
 383{
 384    if (b)
 385    {
 386        mParcelFlags |= flag;
 387    }
 388    else
 389    {
 390        mParcelFlags &= ~flag;
 391    }
 392}
 393
 394
 395BOOL LLParcel::allowModifyBy(const LLUUID &agent_id, const LLUUID &group_id) const
 396{
 397    if (agent_id == LLUUID::null)
 398    {
 399        // system always can enter
 400        return TRUE;
 401    }
 402    else if (isPublic())
 403    {
 404        return TRUE;
 405    }
 406    else if (agent_id == mOwnerID)
 407    {
 408        // owner can always perform operations
 409        return TRUE;
 410    }
 411    else if (mParcelFlags & PF_CREATE_OBJECTS)
 412    {
 413        return TRUE;
 414    }
 415    else if ((mParcelFlags & PF_CREATE_GROUP_OBJECTS)
 416             && group_id.notNull() )
 417    {
 418        return (getGroupID() == group_id);
 419    }
 420    
 421    return FALSE;
 422}
 423
 424BOOL LLParcel::allowTerraformBy(const LLUUID &agent_id) const
 425{
 426    if (agent_id == LLUUID::null)
 427    {
 428        // system always can enter
 429        return TRUE;
 430    }
 431    else if(OS_LEASED == mStatus)
 432    {
 433        if(agent_id == mOwnerID)
 434        {
 435            // owner can modify leased land
 436            return TRUE;
 437        }
 438        else
 439        {
 440            // otherwise check other people
 441            return mParcelFlags & PF_ALLOW_TERRAFORM;
 442        }
 443    }
 444    else
 445    {
 446        return FALSE;
 447    }
 448}
 449
 450
 451bool LLParcel::isAgentBlockedFromParcel(LLParcel* parcelp,
 452                                        const LLUUID& agent_id,
 453                                        const uuid_vec_t& group_ids,
 454                                        const BOOL is_agent_identified,
 455                                        const BOOL is_agent_transacted,
 456                                        const BOOL is_agent_ageverified)
 457{
 458    S32 current_group_access = parcelp->blockAccess(agent_id, LLUUID::null, is_agent_identified, is_agent_transacted, is_agent_ageverified);
 459    S32 count;
 460    bool is_allowed = (current_group_access == BA_ALLOWED) ? true: false;
 461    LLUUID group_id;
 462    
 463    count = group_ids.size();
 464    for (int i = 0; i < count && !is_allowed; i++)
 465    {
 466        group_id = group_ids[i];
 467        current_group_access = parcelp->blockAccess(agent_id, group_id, is_agent_identified, is_agent_transacted, is_agent_ageverified);
 468        
 469        if (current_group_access == BA_ALLOWED) is_allowed = true;
 470    }
 471    
 472    return !is_allowed;
 473}
 474
 475BOOL LLParcel::isAgentBanned(const LLUUID& agent_id) const
 476{
 477	// Test ban list
 478	if (mBanList.find(agent_id) != mBanList.end())
 479	{
 480		return TRUE;
 481	}
 482    
 483    return FALSE;
 484}
 485
 486S32 LLParcel::blockAccess(const LLUUID& agent_id, const LLUUID& group_id,
 487                          const BOOL is_agent_identified,
 488                          const BOOL is_agent_transacted,
 489                          const BOOL is_agent_ageverified) const
 490{
 491    // Test ban list
 492    if (isAgentBanned(agent_id))
 493    {
 494        return BA_BANNED;
 495    }
 496    
 497    // Always allow owner on (unless he banned himself, useful for
 498    // testing). We will also allow estate owners/managers in if they 
 499    // are not explicitly banned.
 500    if (agent_id == mOwnerID)
 501    {
 502        return BA_ALLOWED;
 503    }
 504    
 505    // Special case when using pass list where group access is being restricted but not 
 506    // using access list.	 In this case group members are allowed only if they buy a pass.
 507    // We return BA_NOT_IN_LIST if not in list
 508    BOOL passWithGroup = getParcelFlag(PF_USE_PASS_LIST) && !getParcelFlag(PF_USE_ACCESS_LIST) 
 509    && getParcelFlag(PF_USE_ACCESS_GROUP) && !mGroupID.isNull() && group_id == mGroupID;
 510    
 511    
 512    // Test group list
 513    if (getParcelFlag(PF_USE_ACCESS_GROUP)
 514        && !mGroupID.isNull()
 515        && group_id == mGroupID
 516        && !passWithGroup)
 517    {
 518        return BA_ALLOWED;
 519    }
 520    
 521    // Test access list
 522    if (getParcelFlag(PF_USE_ACCESS_LIST) || passWithGroup )
 523    {
 524        if (mAccessList.find(agent_id) != mAccessList.end())
 525        {
 526            return BA_ALLOWED;
 527        }
 528        
 529        return BA_NOT_ON_LIST; 
 530    }
 531    
 532    // If we're not doing any other limitations, all users
 533    // can enter, unless
 534    if (		 !getParcelFlag(PF_USE_ACCESS_GROUP)
 535                 && !getParcelFlag(PF_USE_ACCESS_LIST))
 536    { 
 537        //If the land is group owned, and you are in the group, bypass these checks
 538        if(getIsGroupOwned() && group_id == mGroupID)
 539        {
 540            return BA_ALLOWED;
 541        }
 542        
 543        // Test for "payment" access levels
 544        // Anonymous - No Payment Info on File
 545        if(getParcelFlag(PF_DENY_ANONYMOUS) && !is_agent_identified && !is_agent_transacted)
 546        {
 547            return BA_NO_ACCESS_LEVEL;
 548        }
 549        // AgeUnverified - Not Age Verified
 550        if(getParcelFlag(PF_DENY_AGEUNVERIFIED) && !is_agent_ageverified)
 551        {
 552			return BA_NOT_AGE_VERIFIED;
 553        }
 554    
 555        return BA_ALLOWED;
 556    }
 557    
 558    return BA_NOT_IN_GROUP;
 559    
 560}
 561
 562
 563void LLParcel::setArea(S32 area, S32 sim_object_limit)
 564{
 565    mArea = area;
 566    setMaxPrimCapacity((S32)(sim_object_limit * area / (F32)(REGION_WIDTH_METERS * REGION_WIDTH_METERS)));
 567}
 568
 569void LLParcel::setDiscountRate(F32 rate)
 570{
 571    // this is to make sure that the rate is at least sane - this is
 572    // not intended to enforce economy rules. It only enfoces that the
 573    // rate is a scaler between 0 and 1.
 574    mDiscountRate = llclampf(rate);
 575}
 576
 577
 578//-----------------------------------------------------------
 579// File input and output
 580//-----------------------------------------------------------
 581
 582BOOL LLParcel::importAccessEntry(std::istream& input_stream, LLAccessEntry* entry)
 583{
 584    skip_to_end_of_next_keyword("{", input_stream);
 585    while (input_stream.good())
 586    {
 587        skip_comments_and_emptyspace(input_stream);
 588        std::string line, keyword, value;
 589        get_line(line, input_stream, MAX_STRING);
 590        get_keyword_and_value(keyword, value, line);
 591        
 592        if ("}" == keyword)
 593        {
 594            break;
 595        }
 596        else if ("id" == keyword)
 597        {
 598            entry->mID.set( value );
 599        }
 600        else if ("name" == keyword)
 601        {
 602            // deprecated
 603        }
 604        else if ("time" == keyword)
 605        {
 606            S32 when;
 607            LLStringUtil::convertToS32(value, when);
 608            entry->mTime = when;
 609        }
 610        else if ("flags" == keyword)
 611        {
 612            U32 setting;
 613            LLStringUtil::convertToU32(value, setting);
 614            entry->mFlags = setting;
 615        }
 616        else
 617        {
 618            llwarns << "Unknown keyword in parcel access entry section: <" 
 619            << keyword << ">" << llendl;
 620        }
 621    }
 622    return input_stream.good();
 623}
 624
 625BOOL LLParcel::importMediaURLFilter(std::istream& input_stream, std::string& url)
 626{
 627	skip_to_end_of_next_keyword("{", input_stream);
 628
 629	while(input_stream.good())
 630	{
 631		skip_comments_and_emptyspace(input_stream);
 632		std::string line, keyword, value;
 633		get_line(line, input_stream, MAX_STRING);
 634		get_keyword_and_value(keyword, value, line);
 635
 636		if ("}" == keyword)
 637		{
 638			break;
 639		}
 640		else if ("url" == keyword)
 641		{
 642			url = value;
 643		}
 644		else
 645		{
 646			llwarns << "Unknown keyword in parcel media url filter section: <"
 647					<< keyword << ">" << llendl;
 648		}
 649	}
 650	return input_stream.good();
 651}
 652
 653// Assumes we are in a block "ParcelData"
 654void LLParcel::packMessage(LLMessageSystem* msg)
 655{
 656    msg->addU32Fast( _PREHASH_ParcelFlags, getParcelFlags() );
 657    msg->addS32Fast( _PREHASH_SalePrice, getSalePrice() );
 658    msg->addStringFast( _PREHASH_Name,		 getName() );
 659    msg->addStringFast( _PREHASH_Desc,		 getDesc() );
 660    msg->addStringFast( _PREHASH_MusicURL,	 getMusicURL() );
 661    msg->addStringFast( _PREHASH_MediaURL,	 getMediaURL() );
 662    msg->addU8 ( "MediaAutoScale", getMediaAutoScale () );
 663    msg->addUUIDFast( _PREHASH_MediaID,	 getMediaID() );
 664    msg->addUUIDFast( _PREHASH_GroupID,	 getGroupID() );
 665    msg->addS32Fast( _PREHASH_PassPrice, mPassPrice );
 666    msg->addF32Fast( _PREHASH_PassHours, mPassHours );
 667    msg->addU8Fast(	 _PREHASH_Category,	 (U8)mCategory);
 668    msg->addUUIDFast( _PREHASH_AuthBuyerID, mAuthBuyerID);
 669    msg->addUUIDFast( _PREHASH_SnapshotID, mSnapshotID);
 670    msg->addVector3Fast(_PREHASH_UserLocation, mUserLocation);
 671    msg->addVector3Fast(_PREHASH_UserLookAt, mUserLookAt);
 672    msg->addU8Fast(	 _PREHASH_LandingType, (U8)mLandingType);
 673}
 674
 675// Assumes we are in a block "ParcelData"
 676void LLParcel::packMessage(LLSD& msg)
 677{
 678	// used in the viewer, the sim uses it's own packer
 679	msg["local_id"] = getLocalID();
 680	msg["parcel_flags"] = ll_sd_from_U32(getParcelFlags());
 681	msg["sale_price"] = getSalePrice();
 682	msg["name"] = getName();
 683	msg["description"] = getDesc();
 684	msg["music_url"] = getMusicURL();
 685	msg["media_url"] = getMediaURL();
 686	msg["media_desc"] = getMediaDesc();
 687	msg["media_type"] = getMediaType();
 688	msg["media_width"] = getMediaWidth();
 689	msg["media_height"] = getMediaHeight();
 690	msg["auto_scale"] = getMediaAutoScale();
 691	msg["media_loop"] = getMediaLoop();
 692	msg["media_current_url"] = getMediaCurrentURL();
 693	msg["obscure_media"] = false; // OBSOLETE - no longer used
 694	msg["obscure_music"] = false; // OBSOLETE - no longer used
 695	msg["media_id"] = getMediaID();
 696	msg["media_allow_navigate"] = getMediaAllowNavigate();
 697	msg["media_prevent_camera_zoom"] = getMediaPreventCameraZoom();
 698	msg["media_url_timeout"] = getMediaURLTimeout();
 699	msg["media_url_filter_enable"] = getMediaURLFilterEnable();
 700	msg["media_url_filter_list"] = getMediaURLFilterList();
 701	msg["group_id"] = getGroupID();
 702	msg["pass_price"] = mPassPrice;
 703	msg["pass_hours"] = mPassHours;
 704	msg["category"] = (U8)mCategory;
 705	msg["auth_buyer_id"] = mAuthBuyerID;
 706	msg["snapshot_id"] = mSnapshotID;
 707	msg["user_location"] = ll_sd_from_vector3(mUserLocation);
 708	msg["user_look_at"] = ll_sd_from_vector3(mUserLookAt);
 709	msg["landing_type"] = (U8)mLandingType;
 710	msg["see_avs"] = (LLSD::Boolean) getSeeAVs();
 711	msg["group_av_sounds"] = (LLSD::Boolean) getAllowGroupAVSounds();
 712	msg["any_av_sounds"] = (LLSD::Boolean) getAllowAnyAVSounds();
 713}
 714
 715
 716void LLParcel::unpackMessage(LLMessageSystem* msg)
 717{
 718	std::string buffer;
 719	
 720    msg->getU32Fast( _PREHASH_ParcelData,_PREHASH_ParcelFlags, mParcelFlags );
 721    msg->getS32Fast( _PREHASH_ParcelData,_PREHASH_SalePrice, mSalePrice );
 722    msg->getStringFast( _PREHASH_ParcelData,_PREHASH_Name, buffer );
 723    setName(buffer);
 724    msg->getStringFast( _PREHASH_ParcelData,_PREHASH_Desc, buffer );
 725    setDesc(buffer);
 726    msg->getStringFast( _PREHASH_ParcelData,_PREHASH_MusicURL, buffer );
 727    setMusicURL(buffer);
 728    msg->getStringFast( _PREHASH_ParcelData,_PREHASH_MediaURL, buffer );
 729    setMediaURL(buffer);
 730    
 731	BOOL see_avs = TRUE;			// All default to true for legacy server behavior
 732	BOOL any_av_sounds = TRUE;
 733	BOOL group_av_sounds = TRUE;
 734	bool have_new_parcel_limit_data = (msg->getSizeFast(_PREHASH_ParcelData, _PREHASH_SeeAVs) > 0);		// New version of server should send all 3 of these values
 735	have_new_parcel_limit_data &= (msg->getSizeFast(_PREHASH_ParcelData, _PREHASH_AnyAVSounds) > 0);
 736	have_new_parcel_limit_data &= (msg->getSizeFast(_PREHASH_ParcelData, _PREHASH_GroupAVSounds) > 0);
 737	if (have_new_parcel_limit_data)
 738	{
 739		msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_SeeAVs, see_avs);
 740		msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_AnyAVSounds, any_av_sounds);
 741		msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_GroupAVSounds, group_av_sounds);
 742	}
 743	setSeeAVs((bool) see_avs);
 744	setAllowAnyAVSounds((bool) any_av_sounds);
 745	setAllowGroupAVSounds((bool) group_av_sounds);
 746
 747	setHaveNewParcelLimitData(have_new_parcel_limit_data);
 748
 749    // non-optimized version
 750    msg->getU8 ( "ParcelData", "MediaAutoScale", mMediaAutoScale );
 751    
 752    msg->getUUIDFast( _PREHASH_ParcelData,_PREHASH_MediaID, mMediaID );
 753    msg->getUUIDFast( _PREHASH_ParcelData,_PREHASH_GroupID, mGroupID );
 754    msg->getS32Fast( _PREHASH_ParcelData,_PREHASH_PassPrice, mPassPrice );
 755    msg->getF32Fast( _PREHASH_ParcelData,_PREHASH_PassHours, mPassHours );
 756    U8 category;
 757    msg->getU8Fast(	 _PREHASH_ParcelData,_PREHASH_Category, category);
 758    mCategory = (ECategory)category;
 759    msg->getUUIDFast( _PREHASH_ParcelData,_PREHASH_AuthBuyerID, mAuthBuyerID);
 760    msg->getUUIDFast( _PREHASH_ParcelData,_PREHASH_SnapshotID, mSnapshotID);
 761    msg->getVector3Fast(_PREHASH_ParcelData,_PREHASH_UserLocation, mUserLocation);
 762    msg->getVector3Fast(_PREHASH_ParcelData,_PREHASH_UserLookAt, mUserLookAt);
 763    U8 landing_type;
 764    msg->getU8Fast(	 _PREHASH_ParcelData,_PREHASH_LandingType, landing_type);
 765    mLandingType = (ELandingType)landing_type;
 766
 767	// New Media Data
 768	// Note: the message has been converted to TCP
 769	if(msg->has("MediaData"))
 770	{
 771		msg->getString("MediaData", "MediaDesc", buffer);
 772		setMediaDesc(buffer);
 773		msg->getString("MediaData", "MediaType", buffer);
 774		setMediaType(buffer);
 775		msg->getS32("MediaData", "MediaWidth", mMediaWidth);
 776		msg->getS32("MediaData", "MediaHeight", mMediaHeight);
 777		msg->getU8 ( "MediaData", "MediaLoop", mMediaLoop );
 778		// the ObscureMedia and ObscureMusic flags previously set here are no longer used
 779	}
 780	else
 781	{
 782		setMediaType(std::string("video/vnd.secondlife.qt.legacy"));
 783		setMediaDesc(std::string("No Description available without Server Upgrade"));
 784		mMediaLoop = true;
 785	}
 786
 787	if(msg->getNumberOfBlocks("MediaLinkSharing") > 0)
 788	{
 789		msg->getString("MediaLinkSharing", "MediaCurrentURL", buffer);
 790		setMediaCurrentURL(buffer);
 791		msg->getU8 ( "MediaLinkSharing", "MediaAllowNavigate", mMediaAllowNavigate );
 792		msg->getU8 ( "MediaLinkSharing", "MediaURLFilterEnable", mMediaURLFilterEnable );
 793		msg->getU8 ( "MediaLinkSharing", "MediaPreventCameraZoom", mMediaPreventCameraZoom );
 794		msg->getF32( "MediaLinkSharing", "MediaURLTimeout", mMediaURLTimeout);
 795	}
 796	else
 797	{
 798		setMediaCurrentURL(LLStringUtil::null);
 799	}
 800	
 801}
 802
 803void LLParcel::packAccessEntries(LLMessageSystem* msg,
 804								 const std::map<LLUUID,LLAccessEntry>& list)
 805{
 806    access_map_const_iterator cit = list.begin();
 807    access_map_const_iterator end = list.end();
 808    
 809    if (cit == end)
 810    {
 811        msg->nextBlockFast(_PREHASH_List);
 812        msg->addUUIDFast(_PREHASH_ID, LLUUID::null );
 813        msg->addS32Fast(_PREHASH_Time, 0 );
 814        msg->addU32Fast(_PREHASH_Flags, 0 );
 815        return;
 816    }
 817    
 818    for ( ; cit != end; ++cit)
 819    {
 820        const LLAccessEntry& entry = (*cit).second;
 821        
 822        msg->nextBlockFast(_PREHASH_List);
 823        msg->addUUIDFast(_PREHASH_ID,	 entry.mID );
 824        msg->addS32Fast(_PREHASH_Time,	 entry.mTime );
 825        msg->addU32Fast(_PREHASH_Flags, entry.mFlags );
 826    }
 827}
 828
 829
 830void LLParcel::unpackAccessEntries(LLMessageSystem* msg,
 831                                   std::map<LLUUID,LLAccessEntry>* list)
 832{
 833    LLUUID id;
 834    S32 time;
 835    U32 flags;
 836    
 837    S32 i;
 838    S32 count = msg->getNumberOfBlocksFast(_PREHASH_List);
 839    for (i = 0; i < count; i++)
 840    {
 841        msg->getUUIDFast(_PREHASH_List, _PREHASH_ID, id, i);
 842        msg->getS32Fast(		 _PREHASH_List, _PREHASH_Time, time, i);
 843        msg->getU32Fast(		 _PREHASH_List, _PREHASH_Flags, flags, i);
 844        
 845        if (id.notNull())
 846        {
 847            LLAccessEntry entry;
 848            entry.mID = id;
 849            entry.mTime = time;
 850            entry.mFlags = flags;
 851            
 852            (*list)[entry.mID] = entry;
 853        }
 854    }
 855}
 856
 857
 858void LLParcel::expirePasses(S32 now)
 859{
 860    access_map_iterator itor = mAccessList.begin();
 861    while (itor != mAccessList.end())
 862    {
 863        const LLAccessEntry& entry = (*itor).second;
 864        
 865        if (entry.mTime != 0 && entry.mTime < now)
 866        {
 867            mAccessList.erase(itor++);
 868        }
 869        else
 870        {
 871            ++itor;
 872        }
 873    }
 874}
 875
 876
 877bool LLParcel::operator==(const LLParcel &rhs) const
 878{
 879    if (mOwnerID != rhs.mOwnerID)
 880        return FALSE;
 881    
 882    if (mParcelFlags != rhs.mParcelFlags)
 883        return FALSE;
 884    
 885    if (mClaimDate != rhs.mClaimDate)
 886        return FALSE;
 887    
 888    if (mClaimPricePerMeter != rhs.mClaimPricePerMeter)
 889        return FALSE;
 890    
 891    if (mRentPricePerMeter != rhs.mRentPricePerMeter)
 892        return FALSE;
 893    
 894    return TRUE;
 895}
 896
 897// Calculate rent
 898S32 LLParcel::getTotalRent() const
 899{
 900    return (S32)floor(0.5f + (F32)mArea * (F32)mRentPricePerMeter * (1.0f - mDiscountRate));
 901}
 902
 903F32 LLParcel::getAdjustedRentPerMeter() const
 904{
 905    return ((F32)mRentPricePerMeter * (1.0f - mDiscountRate));
 906}
 907
 908LLVector3 LLParcel::getCenterpoint() const
 909{
 910    LLVector3 rv;
 911    rv.mV[VX] = (getAABBMin().mV[VX] + getAABBMax().mV[VX]) * 0.5f;
 912    rv.mV[VY] = (getAABBMin().mV[VY] + getAABBMax().mV[VY]) * 0.5f;
 913    rv.mV[VZ] = 0.0f;
 914    return rv;
 915}
 916
 917void LLParcel::extendAABB(const LLVector3& box_min, const LLVector3& box_max)
 918{
 919    // Patch up min corner of AABB
 920    S32 i;
 921    for (i=0; i<3; i++)
 922    {
 923        if (box_min.mV[i] < mAABBMin.mV[i])
 924        {
 925            mAABBMin.mV[i] = box_min.mV[i];
 926        }
 927    }
 928    
 929    // Patch up max corner of AABB
 930    for (i=0; i<3; i++)
 931    {
 932        if (box_max.mV[i] > mAABBMax.mV[i])
 933        {
 934            mAABBMax.mV[i] = box_max.mV[i];
 935        }
 936    }
 937}
 938
 939BOOL LLParcel::addToAccessList(const LLUUID& agent_id, S32 time)
 940{
 941	if (mAccessList.size() >= (U32) PARCEL_MAX_ACCESS_LIST)
 942	{
 943		return FALSE;
 944	}
 945	if (agent_id == getOwnerID())
 946	{
 947		// Can't add owner to these lists
 948		return FALSE;
 949	}
 950	access_map_iterator itor = mAccessList.begin();
 951	while (itor != mAccessList.end())
 952	{
 953		const LLAccessEntry& entry = (*itor).second;
 954		if (entry.mID == agent_id)
 955		{
 956			if (time == 0 || (entry.mTime != 0 && entry.mTime < time))
 957			{
 958				mAccessList.erase(itor++);
 959			}
 960			else
 961			{
 962				// existing one expires later
 963				return FALSE;
 964			}
 965		}
 966		else
 967		{
 968			++itor;
 969		}
 970	}
 971    
 972    removeFromBanList(agent_id);
 973    
 974    LLAccessEntry new_entry;
 975    new_entry.mID			 = agent_id;
 976    new_entry.mTime	 = time;
 977    new_entry.mFlags = 0x0;
 978    mAccessList[new_entry.mID] = new_entry;
 979    return TRUE;
 980}
 981
 982BOOL LLParcel::addToBanList(const LLUUID& agent_id, S32 time)
 983{
 984	if (mBanList.size() >= (U32) PARCEL_MAX_ACCESS_LIST)
 985	{
 986		// Not using ban list, so not a rational thing to do
 987		return FALSE;
 988	}
 989	if (agent_id == getOwnerID())
 990	{
 991		// Can't add owner to these lists
 992		return FALSE;
 993	}
 994    
 995    access_map_iterator itor = mBanList.begin();
 996    while (itor != mBanList.end())
 997    {
 998        const LLAccessEntry& entry = (*itor).second;
 999        if (entry.mID == agent_id)
1000        {
1001            if (time == 0 || (entry.mTime != 0 && entry.mTime < time))
1002            {
1003                mBanList.erase(itor++);
1004            }
1005            else
1006            {
1007                // existing one expires later
1008                return FALSE;
1009            }
1010        }
1011        else
1012        {
1013            ++itor;
1014        }
1015    }
1016    
1017    removeFromAccessList(agent_id);
1018    
1019    LLAccessEntry new_entry;
1020    new_entry.mID			 = agent_id;
1021    new_entry.mTime	 = time;
1022    new_entry.mFlags = 0x0;
1023    mBanList[new_entry.mID] = new_entry;
1024    return TRUE;
1025}
1026
1027BOOL remove_from_access_array(std::map<LLUUID,LLAccessEntry>* list,
1028                              const LLUUID& agent_id)
1029{
1030    BOOL removed = FALSE;
1031    access_map_iterator itor = list->begin();
1032    while (itor != list->end())
1033    {
1034        const LLAccessEntry& entry = (*itor).second;
1035        if (entry.mID == agent_id)
1036        {
1037            list->erase(itor++);
1038            removed = TRUE;
1039        }
1040        else
1041        {
1042            ++itor;
1043        }
1044    }
1045    return removed;
1046}
1047
1048BOOL LLParcel::removeFromAccessList(const LLUUID& agent_id)
1049{
1050    return remove_from_access_array(&mAccessList, agent_id);
1051}
1052
1053BOOL LLParcel::removeFromBanList(const LLUUID& agent_id)
1054{
1055    return remove_from_access_array(&mBanList, agent_id);
1056}
1057
1058// static
1059const std::string& LLParcel::getOwnershipStatusString(EOwnershipStatus status)
1060{
1061    return ownership_status_to_string(status);
1062}
1063
1064// static
1065const std::string& LLParcel::getCategoryString(ECategory category)
1066{
1067    return category_to_string(category);
1068}
1069
1070// static
1071const std::string& LLParcel::getCategoryUIString(ECategory category)
1072{
1073    return category_to_ui_string(category);
1074}
1075
1076// static
1077LLParcel::ECategory LLParcel::getCategoryFromString(const std::string& string)
1078{
1079    return category_string_to_category(string);
1080}
1081
1082// static
1083LLParcel::ECategory LLParcel::getCategoryFromUIString(const std::string& string)
1084{
1085    return category_ui_string_to_category(string);
1086}
1087
1088// static
1089const std::string& LLParcel::getActionString(LLParcel::EAction action)
1090{
1091    S32 index = 0;
1092    if((action >= 0) && (action < LLParcel::A_COUNT))
1093    {
1094        index = action;
1095    }
1096    else
1097    {
1098        index = A_COUNT;
1099    }
1100    return PARCEL_ACTION_STRING[index];
1101}
1102
1103BOOL LLParcel::isSaleTimerExpired(const U64& time)
1104{
1105    if (mSaleTimerExpires.getStarted() == FALSE)
1106    {
1107        return FALSE;
1108    }
1109    BOOL expired = mSaleTimerExpires.checkExpirationAndReset(0.0);
1110    if (expired)
1111    {
1112        mSaleTimerExpires.stop();
1113    }
1114    return expired;
1115}
1116
1117BOOL LLParcel::isMediaResetTimerExpired(const U64& time)
1118{
1119    if (mMediaResetTimer.getStarted() == FALSE)
1120    {
1121        return FALSE;
1122    }
1123    BOOL expired = mMediaResetTimer.checkExpirationAndReset(0.0);
1124    if (expired)
1125    {
1126        mMediaResetTimer.stop();
1127    }
1128    return expired;
1129}
1130
1131
1132void LLParcel::startSale(const LLUUID& buyer_id, BOOL is_buyer_group)
1133{
1134	// TODO -- this and all Sale related methods need to move out of the LLParcel 
1135	// base class and into server-side-only LLSimParcel class
1136	setPreviousOwnerID(mOwnerID);
1137	setPreviouslyGroupOwned(mGroupOwned);
1138
1139	mOwnerID = buyer_id;
1140	mGroupOwned = is_buyer_group;
1141	if(mGroupOwned)
1142	{
1143		mGroupID = mOwnerID;
1144	}
1145	else
1146	{
1147		mGroupID.setNull();
1148	}
1149	mSaleTimerExpires.start();
1150	mSaleTimerExpires.setTimerExpirySec(DEFAULT_USEC_SALE_TIMEOUT / SEC_TO_MICROSEC);
1151	mStatus = OS_LEASE_PENDING;
1152	mClaimDate = time(NULL);
1153	setAuctionID(0);
1154	// clear the autoreturn whenever land changes hands
1155	setCleanOtherTime(0);
1156}
1157
1158void LLParcel::expireSale(
1159	U32& type,
1160	U8& flags,
1161	LLUUID& from_id,
1162	LLUUID& to_id)
1163{
1164    mSaleTimerExpires.setTimerExpirySec(0.0);
1165    mSaleTimerExpires.stop();
1166    setPreviousOwnerID(LLUUID::null);
1167    setPreviouslyGroupOwned(FALSE);
1168    setSellWithObjects(FALSE);
1169    type = TRANS_LAND_RELEASE;
1170    mStatus = OS_NONE;
1171    flags = pack_transaction_flags(mGroupOwned, FALSE);
1172    mAuthBuyerID.setNull();
1173    from_id = mOwnerID;
1174    mOwnerID.setNull();
1175    to_id.setNull();
1176}
1177
1178void LLParcel::completeSale(
1179	U32& type,
1180	U8& flags,
1181	LLUUID& to_id)
1182{
1183	mSaleTimerExpires.setTimerExpirySec(0.0);
1184	mSaleTimerExpires.stop();
1185	mStatus = OS_LEASED;
1186	type = TRANS_LAND_SALE;
1187	flags = pack_transaction_flags(mGroupOwned, mGroupOwned);
1188	to_id = mOwnerID;
1189	mAuthBuyerID.setNull();
1190
1191	// Purchased parcels are assumed to no longer be for sale.
1192	// Otherwise someone can snipe the sale.
1193	setForSale(FALSE);
1194	setAuctionID(0);
1195
1196	// Turn off show directory, since it's a recurring fee that
1197	// the buyer may not want.
1198	setParcelFlag(PF_SHOW_DIRECTORY, FALSE);
1199
1200	//should be cleared on sale.
1201	mAccessList.clear();
1202	mBanList.clear();
1203}
1204
1205void LLParcel::clearSale()
1206{
1207	mSaleTimerExpires.setTimerExpirySec(0.0);
1208	mSaleTimerExpires.stop();
1209	if(isPublic())
1210	{
1211		mStatus = OS_NONE;
1212	}
1213	else
1214	{
1215		mStatus = OS_LEASED;
1216	}
1217	mAuthBuyerID.setNull();
1218	setForSale(FALSE);
1219	setAuctionID(0);
1220	setPreviousOwnerID(LLUUID::null);
1221	setPreviouslyGroupOwned(FALSE);
1222	setSellWithObjects(FALSE);
1223}
1224
1225BOOL LLParcel::isPublic() const
1226{
1227    return (mOwnerID.isNull());
1228}
1229
1230BOOL LLParcel::isBuyerAuthorized(const LLUUID& buyer_id) const
1231{
1232    if(mAuthBuyerID.isNull())
1233    {
1234        return TRUE;
1235    }
1236    return (mAuthBuyerID == buyer_id);
1237}
1238
1239void LLParcel::clearParcel()
1240{
1241	overrideParcelFlags(PF_DEFAULT);
1242	setName(LLStringUtil::null);
1243	setDesc(LLStringUtil::null);
1244	setMediaURL(LLStringUtil::null);
1245	setMediaType(LLStringUtil::null);
1246	setMediaID(LLUUID::null);
1247    setMediaDesc(LLStringUtil::null);
1248	setMediaAutoScale(0);
1249	setMediaLoop(TRUE);
1250	mMediaWidth = 0;
1251	mMediaHeight = 0;
1252	setMediaCurrentURL(LLStringUtil::null);
1253	setMediaURLFilterList(LLSD::emptyArray());
1254	setMediaURLFilterEnable(FALSE);
1255	setMediaAllowNavigate(TRUE);
1256	setMediaPreventCameraZoom(FALSE);
1257	setMediaURLTimeout(0.0f);
1258	setMusicURL(LLStringUtil::null);
1259	setInEscrow(FALSE);
1260	setAuthorizedBuyerID(LLUUID::null);
1261	setCategory(C_NONE);
1262	setSnapshotID(LLUUID::null);
1263	setUserLocation(LLVector3::zero);
1264	setUserLookAt(LLVector3::x_axis);
1265	setLandingType(L_LANDING_POINT);
1266	setAuctionID(0);
1267	setGroupID(LLUUID::null);
1268	setPassPrice(0);
1269	setPassHours(0.f);
1270	mAccessList.clear();
1271	mBanList.clear();
1272	//mRenterList.reset();
1273}
1274
1275void LLParcel::dump()
1276{
1277    llinfos << "parcel " << mLocalID << " area " << mArea << llendl;
1278    llinfos << "	 name <" << mName << ">" << llendl;
1279    llinfos << "	 desc <" << mDesc << ">" << llendl;
1280}
1281
1282const std::string& ownership_status_to_string(LLParcel::EOwnershipStatus status)
1283{
1284    if(status >= 0 && status < LLParcel::OS_COUNT)
1285    {
1286        return PARCEL_OWNERSHIP_STATUS_STRING[status];
1287    }
1288    return PARCEL_OWNERSHIP_STATUS_STRING[LLParcel::OS_COUNT];
1289}
1290
1291LLParcel::EOwnershipStatus ownership_string_to_status(const std::string& s)
1292{
1293    for(S32 i = 0; i < LLParcel::OS_COUNT; ++i)
1294    {
1295        if(s == PARCEL_OWNERSHIP_STATUS_STRING[i])
1296        {
1297            return (LLParcel::EOwnershipStatus)i;
1298        }
1299    }
1300    return LLParcel::OS_NONE;
1301}
1302
1303//const char* revert_action_to_string(LLParcel::ESaleTimerExpireAction action)
1304//{
1305// S32 index = 0;
1306// if(action >= 0 && action < LLParcel::STEA_COUNT)
1307// {
1308//	 index = action;
1309// }
1310// return PARCEL_SALE_TIMER_ACTION[index];
1311//}
1312    
1313//LLParcel::ESaleTimerExpireAction revert_string_to_action(const char* s)
1314//{
1315// for(S32 i = 0; i < LLParcel::STEA_COUNT; ++i)
1316// {
1317//	 if(0 == strcmp(s, PARCEL_SALE_TIMER_ACTION[i]))
1318//	 {
1319//		 return (LLParcel::ESaleTimerExpireAction)i;
1320//	 }
1321// }
1322// return LLParcel::STEA_REVERT;
1323//}
1324    
1325const std::string& category_to_string(LLParcel::ECategory category)
1326{
1327    S32 index = 0;
1328    if((category >= 0) && (category < LLParcel::C_COUNT))
1329    {
1330        index = category;
1331    }
1332    return PARCEL_CATEGORY_STRING[index];
1333}
1334
1335const std::string& category_to_ui_string(LLParcel::ECategory category)
1336{
1337    S32 index = 0;
1338    if((category >= 0) && (category < LLParcel::C_COUNT))
1339    {
1340        index = category;
1341    }
1342    else
1343    {
1344        // C_ANY = -1 , but the "Any" string is at the end of the list
1345        index = ((S32) LLParcel::C_COUNT);
1346    }
1347    return PARCEL_CATEGORY_UI_STRING[index];
1348}
1349
1350LLParcel::ECategory category_string_to_category(const std::string& s)
1351{
1352    for(S32 i = 0; i < LLParcel::C_COUNT; ++i)
1353    {
1354        if(s == PARCEL_CATEGORY_STRING[i])
1355        {
1356            return (LLParcel::ECategory)i;
1357        }
1358    }
1359    llwarns << "Parcel category outside of possibilities " << s << llendl;
1360    return LLParcel::C_NONE;
1361}
1362
1363LLParcel::ECategory category_ui_string_to_category(const std::string& s)
1364{
1365    for(S32 i = 0; i < LLParcel::C_COUNT; ++i)
1366    {
1367        if(s == PARCEL_CATEGORY_UI_STRING[i])
1368        {
1369            return (LLParcel::ECategory)i;
1370        }
1371    }
1372    // "Any" is a valid category for searches, and
1373    // is a distinct option from "None" and "Other"
1374    return LLParcel::C_ANY;
1375}