diff options
Diffstat (limited to 'indra/llmessage/llcachename.cpp')
-rw-r--r-- | indra/llmessage/llcachename.cpp | 527 |
1 files changed, 268 insertions, 259 deletions
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 274bf5cc04..4a66a31c35 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -2,30 +2,25 @@ * @file llcachename.cpp * @brief A hierarchical cache of first and last names queried based on UUID. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * 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://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,11 +36,7 @@ #include "llsdserialize.h" #include "lluuid.h" #include "message.h" - -// Constants -const char* CN_WAITING = "(waiting)"; -const char* CN_NOBODY = "(nobody)"; -const char* CN_NONE = "(none)"; +#include "llmemtype.h" // llsd serialization constants static const std::string AGENTS("agents"); @@ -64,6 +55,7 @@ const S32 CN_FILE_VERSION = 2; // Globals LLCacheName* gCacheName = NULL; +std::map<std::string, std::string> LLCacheName::sCacheName; /// --------------------------------------------------------------------------- /// class LLCacheNameEntry @@ -77,16 +69,17 @@ public: public: bool mIsGroup; U32 mCreateTime; // unix time_t - char mFirstName[DB_FIRST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/ - char mLastName[DB_LAST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/ - char mGroupName[DB_GROUP_NAME_BUF_SIZE]; /*Flawfinder: ignore*/ + // IDEVO TODO collapse names to one field, which will eliminate + // many string compares on "Resident" + std::string mFirstName; + std::string mLastName; + std::string mGroupName; }; LLCacheNameEntry::LLCacheNameEntry() + : mIsGroup(false), + mCreateTime(0) { - mFirstName[0] = '\0'; - mLastName[0] = '\0'; - mGroupName[0] = '\0'; } @@ -94,17 +87,19 @@ class PendingReply { public: LLUUID mID; - LLCacheNameCallback mCallback; + LLCacheNameSignal mSignal; LLHost mHost; - void* mData; - PendingReply(const LLUUID& id, LLCacheNameCallback callback, void* data = NULL) - : mID(id), mCallback(callback), mData(data) - { } - + PendingReply(const LLUUID& id, const LLHost& host) - : mID(id), mCallback(0), mHost(host) - { } - + : mID(id), mHost(host) + { + } + + boost::signals2::connection setCallback(const LLCacheNameCallback& cb) + { + return mSignal.connect(cb); + } + void done() { mID.setNull(); } bool isDone() const { return mID.isNull() != FALSE; } }; @@ -128,7 +123,7 @@ private: }; ReplySender::ReplySender(LLMessageSystem* msg) - : mMsg(msg), mPending(false) + : mMsg(msg), mPending(false), mCurrIsGroup(false) { } ReplySender::~ReplySender() @@ -189,10 +184,10 @@ void ReplySender::flush() typedef std::set<LLUUID> AskQueue; -typedef std::vector<PendingReply> ReplyQueue; +typedef std::list<PendingReply*> ReplyQueue; typedef std::map<LLUUID,U32> PendingQueue; typedef std::map<LLUUID, LLCacheNameEntry*> Cache; -typedef std::vector<LLCacheNameCallback> Observers; +typedef std::map<std::string, LLUUID> ReverseCache; class LLCacheName::Impl { @@ -202,7 +197,9 @@ public: Cache mCache; // the map of UUIDs to names - + ReverseCache mReverseCache; + // map of names to UUIDs + AskQueue mAskNameQueue; AskQueue mAskGroupQueue; // UUIDs to ask our upstream host about @@ -213,13 +210,18 @@ public: ReplyQueue mReplyQueue; // requests awaiting replies from us - Observers mObservers; + LLCacheNameSignal mSignal; LLFrameTimer mProcessTimer; Impl(LLMessageSystem* msg); ~Impl(); + BOOL getName(const LLUUID& id, std::string& first, std::string& last); + + boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback); + void addPending(const LLUUID& id, const LLHost& host); + void processPendingAsks(); void processPendingReplies(); void sendRequest(const char* msg_name, const AskQueue& queue); @@ -233,8 +235,6 @@ public: static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata); static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata); static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata); - - void notifyObservers(const LLUUID& id, const char* first, const char* last, BOOL group); }; @@ -249,6 +249,9 @@ LLCacheName::LLCacheName(LLMessageSystem* msg) LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host) : impl(* new Impl(msg)) { + sCacheName["waiting"] = "(Loading...)"; + sCacheName["nobody"] = "(nobody)"; + sCacheName["none"] = "(none)"; setUpstream(upstream_host); } @@ -274,135 +277,37 @@ LLCacheName::Impl::Impl(LLMessageSystem* msg) LLCacheName::Impl::~Impl() { for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); + for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer()); } - -void LLCacheName::setUpstream(const LLHost& upstream_host) +boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id, const LLCacheNameCallback& callback) { - impl.mUpstreamHost = upstream_host; + PendingReply* reply = new PendingReply(id, LLHost()); + boost::signals2::connection res = reply->setCallback(callback); + mReplyQueue.push_back(reply); + return res; } -void LLCacheName::addObserver(LLCacheNameCallback callback) +void LLCacheName::Impl::addPending(const LLUUID& id, const LLHost& host) { - impl.mObservers.push_back(callback); + PendingReply* reply = new PendingReply(id, host); + mReplyQueue.push_back(reply); } -void LLCacheName::removeObserver(LLCacheNameCallback callback) -{ - Observers::iterator it = impl.mObservers.begin(); - Observers::iterator end = impl.mObservers.end(); - - for ( ; it != end; ++it) - { - const LLCacheNameCallback& cb = (*it); - if (cb == callback) - { - impl.mObservers.erase(it); - return; - } - } -} - -void LLCacheName::cancelCallback(const LLUUID& id, LLCacheNameCallback callback, void* user_data) +void LLCacheName::setUpstream(const LLHost& upstream_host) { - ReplyQueue::iterator it = impl.mReplyQueue.begin(); - ReplyQueue::iterator end = impl.mReplyQueue.end(); - - for(; it != end; ++it) - { - const PendingReply& reply = (*it); - - if ((callback == reply.mCallback) - && (id == reply.mID) - && (user_data == reply.mData) ) - { - impl.mReplyQueue.erase(it); - return; - } - } + impl.mUpstreamHost = upstream_host; } -void LLCacheName::importFile(FILE* fp) +boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback& callback) { - S32 count = 0; - - const S32 BUFFER_SIZE = 1024; - char buffer[BUFFER_SIZE]; /*Flawfinder: ignore*/ - - // *NOTE: These buffer sizes are hardcoded into sscanf() below - char id_string[MAX_STRING]; /*Flawfinder: ignore*/ - char firstname[MAX_STRING]; /*Flawfinder: ignore*/ - char lastname[MAX_STRING]; /*Flawfinder: ignore*/ - U32 create_time; - - // This is OK if the first line is actually a name. We just don't load it. - char* valid = fgets(buffer, BUFFER_SIZE, fp); - if (!valid) return; - - // *NOTE: This buffer size is hardcoded into sscanf() below - char version_string[BUFFER_SIZE]; /*Flawfinder: ignore*/ - S32 version = 0; - S32 match = sscanf( /* Flawfinder: ignore */ - buffer, - "%1023s %d", - version_string, &version); - if ( match != 2 - || strcmp(version_string, "version") - || version != CN_FILE_VERSION) - { - llwarns << "Ignoring old cache name file format" << llendl; - return; - } - - // We'll expire entries more than a week old - U32 now = (U32)time(NULL); - const U32 SECS_PER_DAY = 60 * 60 * 24; - U32 delete_before_time = now - (7 * SECS_PER_DAY); - - while(!feof(fp)) - { - valid = fgets(buffer, BUFFER_SIZE, fp); - if (!valid) break; - - match = sscanf( /* Flawfinder: ignore */ - buffer, - "%254s %u %254s %254s", - id_string, - &create_time, - firstname, - lastname); - if (4 != match) continue; - - LLUUID id(id_string); - if (id.isNull()) continue; - - // undo trivial XOR - S32 i; - for (i = 0; i < UUID_BYTES; i++) - { - id.mData[i] ^= 0x33; - } - - // Don't load entries that are more than a week old - if (create_time < delete_before_time) continue; - - LLCacheNameEntry* entry = new LLCacheNameEntry(); - entry->mIsGroup = false; - entry->mCreateTime = create_time; - LLString::copy(entry->mFirstName, firstname, DB_FIRST_NAME_BUF_SIZE); - LLString::copy(entry->mLastName, lastname, DB_LAST_NAME_BUF_SIZE); - impl.mCache[id] = entry; - - count++; - } - - llinfos << "LLCacheName loaded " << count << " names" << llendl; + return impl.mSignal.connect(callback); } bool LLCacheName::importFile(std::istream& istr) { LLSD data; - if(LLSDSerialize::fromXML(data, istr) < 1) + if(LLSDSerialize::fromXMLDocument(data, istr) < 1) return false; // We'll expire entries more than a week old @@ -425,13 +330,12 @@ bool LLCacheName::importFile(std::istream& istr) LLCacheNameEntry* entry = new LLCacheNameEntry(); entry->mIsGroup = false; entry->mCreateTime = ctime; - std::string first = agent[FIRST].asString(); - first.copy(entry->mFirstName, DB_FIRST_NAME_BUF_SIZE, 0); - entry->mFirstName[llmin(first.size(),(std::string::size_type)DB_FIRST_NAME_BUF_SIZE-1)] = '\0'; - std::string last = agent[LAST].asString(); - last.copy(entry->mLastName, DB_LAST_NAME_BUF_SIZE, 0); - entry->mLastName[llmin(last.size(),(std::string::size_type)DB_LAST_NAME_BUF_SIZE-1)] = '\0'; + entry->mFirstName = agent[FIRST].asString(); + entry->mLastName = agent[LAST].asString(); impl.mCache[id] = entry; + std::string fullname = buildFullName(entry->mFirstName, entry->mLastName); + impl.mReverseCache[fullname] = id; + ++count; } llinfos << "LLCacheName loaded " << count << " agent names" << llendl; @@ -450,10 +354,9 @@ bool LLCacheName::importFile(std::istream& istr) LLCacheNameEntry* entry = new LLCacheNameEntry(); entry->mIsGroup = true; entry->mCreateTime = ctime; - std::string name = group[NAME].asString(); - name.copy(entry->mGroupName, DB_GROUP_NAME_BUF_SIZE, 0); - entry->mGroupName[llmin(name.size(), (std::string::size_type)DB_GROUP_NAME_BUF_SIZE-1)] = '\0'; + entry->mGroupName = group[NAME].asString(); impl.mCache[id] = entry; + impl.mReverseCache[entry->mGroupName] = id; ++count; } llinfos << "LLCacheName loaded " << count << " group names" << llendl; @@ -470,8 +373,8 @@ void LLCacheName::exportFile(std::ostream& ostr) // Only write entries for which we have valid data. LLCacheNameEntry* entry = iter->second; if(!entry - || (NULL != strchr(entry->mFirstName, '?')) - || (NULL != strchr(entry->mGroupName, '?'))) + || (std::string::npos != entry->mFirstName.find('?')) + || (std::string::npos != entry->mGroupName.find('?'))) { continue; } @@ -479,13 +382,14 @@ void LLCacheName::exportFile(std::ostream& ostr) // store it LLUUID id = iter->first; std::string id_str = id.asString(); - if(entry->mFirstName[0] && entry->mLastName[0]) + // IDEVO TODO: Should we store SLIDs with last name "Resident" or not? + if(!entry->mFirstName.empty() && !entry->mLastName.empty()) { data[AGENTS][id_str][FIRST] = entry->mFirstName; data[AGENTS][id_str][LAST] = entry->mLastName; data[AGENTS][id_str][CTIME] = (S32)entry->mCreateTime; } - else if(entry->mIsGroup && entry->mGroupName[0]) + else if(entry->mIsGroup && !entry->mGroupName.empty()) { data[GROUPS][id_str][NAME] = entry->mGroupName; data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime; @@ -496,16 +400,16 @@ void LLCacheName::exportFile(std::ostream& ostr) } -BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& last) +BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last) { if(id.isNull()) { - first = CN_NOBODY; + first = sCacheName["nobody"]; last.clear(); - return FALSE; + return TRUE; } - LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); + LLCacheNameEntry* entry = get_ptr_in_map(mCache, id ); if (entry) { first = entry->mFirstName; @@ -514,45 +418,46 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las } else { - first = CN_WAITING; + first = sCacheName["waiting"]; last.clear(); - if (!impl.isRequestPending(id)) + if (!isRequestPending(id)) { - impl.mAskNameQueue.insert(id); + mAskNameQueue.insert(id); } return FALSE; } } -BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname) +// static +void LLCacheName::localizeCacheName(std::string key, std::string value) { - std::string first_name, last_name; - BOOL res = getName(id, first_name, last_name); - fullname = first_name + " " + last_name; - return res; + if (key!="" && value!= "" ) + sCacheName[key]=value; + else + llwarns<< " Error localizing cache key " << key << " To "<< value<<llendl; } -// *TODO: Deprecate -BOOL LLCacheName::getName(const LLUUID& id, char* first, char* last) +BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname) { std::string first_name, last_name; - BOOL res = getName(id, first_name, last_name); - strcpy(first, first_name.c_str()); - strcpy(last, last_name.c_str()); + BOOL res = impl.getName(id, first_name, last_name); + fullname = buildFullName(first_name, last_name); return res; } + + BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) { if(id.isNull()) { - group = CN_NONE; - return FALSE; + group = sCacheName["none"]; + return TRUE; } LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id); - if (entry && !entry->mGroupName[0]) + if (entry && entry->mGroupName.empty()) { // COUNTER-HACK to combat James' HACK in exportFile()... // this group name was loaded from a name cache that did not @@ -568,7 +473,7 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) } else { - group = CN_WAITING; + group = sCacheName["waiting"]; if (!impl.isRequestPending(id)) { impl.mAskGroupQueue.insert(id); @@ -577,36 +482,109 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) } } -// *TODO: Deprecate -BOOL LLCacheName::getGroupName(const LLUUID& id, char* group) +BOOL LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id) { - std::string group_name; - BOOL res = getGroupName(id, group_name); - strcpy(group, group_name.c_str()); - return res; + std::string full_name = buildFullName(first, last); + return getUUID(full_name, id); +} + +BOOL LLCacheName::getUUID(const std::string& full_name, LLUUID& id) +{ + ReverseCache::iterator iter = impl.mReverseCache.find(full_name); + if (iter != impl.mReverseCache.end()) + { + id = iter->second; + return TRUE; + } + else + { + return FALSE; + } +} + +//static +std::string LLCacheName::buildFullName(const std::string& first, const std::string& last) +{ + std::string fullname = first; + if (!last.empty() + && last != "Resident") + { + fullname += ' '; + fullname += last; + } + return fullname; } +//static +std::string LLCacheName::cleanFullName(const std::string& full_name) +{ + return full_name.substr(0, full_name.find(" Resident")); +} -// TODO: Make the cache name callback take a SINGLE std::string, -// not a separate first and last name. -void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data) +//static +std::string LLCacheName::buildUsername(const std::string& full_name) { + // rare, but handle hard-coded error names returned from server + if (full_name == "(\?\?\?) (\?\?\?)") + { + return "(\?\?\?)"; + } + + std::string::size_type index = full_name.find(' '); + + if (index != std::string::npos) + { + std::string username; + username = full_name.substr(0, index); + std::string lastname = full_name.substr(index+1); + + if (lastname != "Resident") + { + username = username + "." + lastname; + } + + LLStringUtil::toLower(username); + return username; + } + + // if the input wasn't a correctly formatted legacy name just return it unchanged + return full_name; +} + +// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer. +// The reason it is a slot is so that the legacy get() function below can bind an old callback +// and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior +// doesn't get lost. As a result, we have to bind the slot to a signal to call it, even when +// we call it immediately. -Steve +// NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the +// potential need for any parsing should any code need to handle first and last name independently. +boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback) +{ + boost::signals2::connection res; + if(id.isNull()) { - callback(id, CN_NOBODY, "", is_group, user_data); + LLCacheNameSignal signal; + signal.connect(callback); + signal(id, sCacheName["nobody"], is_group); + return res; } LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); if (entry) { + LLCacheNameSignal signal; + signal.connect(callback); // id found in map therefore we can call the callback immediately. if (entry->mIsGroup) { - callback(id, entry->mGroupName, "", entry->mIsGroup, user_data); + signal(id, entry->mGroupName, entry->mIsGroup); } else { - callback(id, entry->mFirstName, entry->mLastName, entry->mIsGroup, user_data); + std::string fullname = + buildFullName(entry->mFirstName, entry->mLastName); + signal(id, fullname, entry->mIsGroup); } } else @@ -623,12 +601,25 @@ void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callb impl.mAskNameQueue.insert(id); } } - impl.mReplyQueue.push_back(PendingReply(id, callback, user_data)); + res = impl.addPending(id, callback); } + return res; +} + +boost::signals2::connection LLCacheName::getGroup(const LLUUID& group_id, + const LLCacheNameCallback& callback) +{ + return get(group_id, true, callback); +} + +boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data) +{ + return get(id, is_group, boost::bind(callback, _1, _2, _3, user_data)); } void LLCacheName::processPending() { + LLMemType mt_pp(LLMemType::MTYPE_CACHE_PROCESS_PENDING); const F32 SECS_BETWEEN_PROCESS = 0.1f; if(!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS)) { @@ -695,7 +686,7 @@ void LLCacheName::dump() { llinfos << iter->first << " = " - << entry->mFirstName << " " << entry->mLastName + << buildFullName(entry->mFirstName, entry->mLastName) << " @ " << entry->mCreateTime << llendl; } @@ -710,18 +701,31 @@ void LLCacheName::dumpStats() << " AskGroup=" << impl.mAskGroupQueue.size() << " Pending=" << impl.mPendingQueue.size() << " Reply=" << impl.mReplyQueue.size() - << " Observers=" << impl.mObservers.size() +// << " Observers=" << impl.mSignal.size() << llendl; } +void LLCacheName::clear() +{ + for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer()); + impl.mCache.clear(); +} + //static -LLString LLCacheName::getDefaultName() +std::string LLCacheName::getDefaultName() { - return LLString(CN_WAITING); + return sCacheName["waiting"]; +} + +//static +std::string LLCacheName::getDefaultLastName() +{ + return "Resident"; } void LLCacheName::Impl::processPendingAsks() { + LLMemType mt_ppa(LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS); sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue); sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue); mAskNameQueue.clear(); @@ -730,50 +734,52 @@ void LLCacheName::Impl::processPendingAsks() void LLCacheName::Impl::processPendingReplies() { - ReplyQueue::iterator it = mReplyQueue.begin(); - ReplyQueue::iterator end = mReplyQueue.end(); - + LLMemType mt_ppr(LLMemType::MTYPE_CACHE_PROCESS_PENDING_REPLIES); // First call all the callbacks, because they might send messages. - for(; it != end; ++it) + for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it) { - LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID); + PendingReply* reply = *it; + LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID); if(!entry) continue; - if (it->mCallback) + if (!entry->mIsGroup) { - if (!entry->mIsGroup) - { - (it->mCallback)(it->mID, - entry->mFirstName, entry->mLastName, - FALSE, it->mData); - } - else { - (it->mCallback)(it->mID, - entry->mGroupName, "", - TRUE, it->mData); - } + std::string fullname = + LLCacheName::buildFullName(entry->mFirstName, entry->mLastName); + (reply->mSignal)(reply->mID, fullname, false); + } + else + { + (reply->mSignal)(reply->mID, entry->mGroupName, true); } } // Forward on all replies, if needed. ReplySender sender(mMsg); - for (it = mReplyQueue.begin(); it != end; ++it) + for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it) { - LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID); + PendingReply* reply = *it; + LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID); if(!entry) continue; - if (it->mHost.isOk()) + if (reply->mHost.isOk()) { - sender.send(it->mID, *entry, it->mHost); + sender.send(reply->mID, *entry, reply->mHost); } - it->done(); + reply->done(); + } + + for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ) + { + ReplyQueue::iterator curit = it++; + PendingReply* reply = *curit; + if (reply->isDone()) + { + delete reply; + mReplyQueue.erase(curit); + } } - - mReplyQueue.erase( - remove_if(mReplyQueue.begin(), mReplyQueue.end(), - std::mem_fun_ref(&PendingReply::isDone)), - mReplyQueue.end()); } @@ -811,18 +817,6 @@ void LLCacheName::Impl::sendRequest( } } -void LLCacheName::Impl::notifyObservers(const LLUUID& id, - const char* first, const char* last, BOOL is_group) -{ - for (Observers::const_iterator i = mObservers.begin(), - end = mObservers.end(); - i != end; - ++i) - { - (**i)(id, first, last, is_group, NULL); - } -} - bool LLCacheName::Impl::isRequestPending(const LLUUID& id) { U32 now = (U32)time(NULL); @@ -889,7 +883,7 @@ void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup) } } - mReplyQueue.push_back(PendingReply(id, fromHost)); + addPending(id, fromHost); } } } @@ -916,23 +910,39 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup) entry->mCreateTime = (U32)time(NULL); if (!isGroup) { - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, DB_FIRST_NAME_BUF_SIZE, entry->mFirstName, i); - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, DB_LAST_NAME_BUF_SIZE, entry->mLastName, i); + msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, entry->mFirstName, i); + msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, entry->mLastName, i); } else - { - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, DB_GROUP_NAME_BUF_SIZE, entry->mGroupName, i); + { // is group + msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, entry->mGroupName, i); + LLStringFn::replace_ascii_controlchars(entry->mGroupName, LL_UNKNOWN_CHAR); } if (!isGroup) { - notifyObservers(id, - entry->mFirstName, entry->mLastName, - FALSE); + // NOTE: Very occasionally the server sends down a full name + // in the first name field with an empty last name, for example, + // first = "Ladanie1 Resident", last = "". + // I cannot reproduce this, nor can I find a bug in the server code. + // Ensure "Resident" does not appear via cleanFullName, because + // buildFullName only checks last name. JC + std::string full_name; + if (entry->mLastName.empty()) + { + full_name = cleanFullName(entry->mFirstName); + } + else + { + full_name = LLCacheName::buildFullName(entry->mFirstName, entry->mLastName); + } + mSignal(id, full_name, false); + mReverseCache[full_name] = id; } else { - notifyObservers(id, entry->mGroupName, "", TRUE); + mSignal(id, entry->mGroupName, true); + mReverseCache[entry->mGroupName] = id; } } } @@ -960,4 +970,3 @@ void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** us { ((LLCacheName::Impl*)userData)->processUUIDReply(msg, true); } - |