diff options
Diffstat (limited to 'indra/newview/llavatarpropertiesprocessor.cpp')
-rw-r--r-- | indra/newview/llavatarpropertiesprocessor.cpp | 303 |
1 files changed, 244 insertions, 59 deletions
diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index ecd67e44ae..edf6e84b68 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -34,10 +34,16 @@ #include "llavatarpropertiesprocessor.h" -#include "message.h" +// Viewer includes #include "llagent.h" #include "llviewergenericmessage.h" +// Linden library includes +#include "llavatarconstants.h" // AVATAR_TRANSACTED, etc. +#include "lldate.h" +#include "lltrans.h" +#include "message.h" + LLAvatarPropertiesProcessor::LLAvatarPropertiesProcessor() { } @@ -87,35 +93,18 @@ void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvat } } -void LLAvatarPropertiesProcessor::sendDataRequest(const LLUUID& avatar_id, EAvatarProcessorType type, - const void * data) + +void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string method) { - switch(type) + // Suppress duplicate requests while waiting for a response from the network + if (isPendingRequest(avatar_id, type)) { - case APT_PROPERTIES: - sendAvatarPropertiesRequest(avatar_id); - break; - case APT_PICKS: - sendGenericRequest(avatar_id, "avatarpicksrequest"); - break; - case APT_PICK_INFO: - if (data) { - sendPickInfoRequest(avatar_id, *static_cast<const LLUUID*>(data)); - } - break; - case APT_NOTES: - sendGenericRequest(avatar_id, "avatarnotesrequest"); - break; - case APT_GROUPS: - sendGenericRequest(avatar_id, "avatargroupsrequest"); - break; - default: - break; + // waiting for a response, don't re-request + return; } -} + // indicate we're going to make a request + addPendingRequest(avatar_id, type); -void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, const std::string method) -{ std::vector<std::string> strings; strings.push_back( avatar_id.asString() ); send_generic_message(method, strings); @@ -123,6 +112,14 @@ void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, co void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id) { + if (isPendingRequest(avatar_id, APT_PROPERTIES)) + { + // waiting for a response, don't re-request + return; + } + // indicate we're going to make a request + addPendingRequest(avatar_id, APT_PROPERTIES); + LLMessageSystem *msg = gMessageSystem; msg->newMessageFast(_PREHASH_AvatarPropertiesRequest); @@ -133,40 +130,29 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avat gAgent.sendReliableMessage(); } -void LLAvatarPropertiesProcessor::sendDataUpdate(const void* data, EAvatarProcessorType type) +void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id) { - switch(type) - { - case APT_PROPERTIES: - sendAvatarPropertiesUpdate(data); - break; - case APT_PICK_INFO: - sendPicInfoUpdate(data); - case APT_PICKS: -// sendGenericRequest(avatar_id, "avatarpicksrequest"); - break; - case APT_NOTES: -// sendGenericRequest(avatar_id, "avatarnotesrequest"); - break; - case APT_GROUPS: -// sendGenericRequest(avatar_id, "avatargroupsrequest"); - break; - default: - break; - } + sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest"); +} +void LLAvatarPropertiesProcessor::sendAvatarNotesRequest(const LLUUID& avatar_id) +{ + sendGenericRequest(avatar_id, APT_NOTES, "avatarnotesrequest"); +} + +void LLAvatarPropertiesProcessor::sendAvatarGroupsRequest(const LLUUID& avatar_id) +{ + sendGenericRequest(avatar_id, APT_GROUPS, "avatargroupsrequest"); } -void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const void* data) + +void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData* avatar_props) { llinfos << "Sending avatarinfo update" << llendl; - const LLAvatarData* avatar_props = static_cast<const LLAvatarData*>(data); // This value is required by sendAvatarPropertiesUpdate method. //A profile should never be mature. (From the original code) BOOL mature = FALSE; - - LLMessageSystem *msg = gMessageSystem; msg->newMessageFast(_PREHASH_AvatarPropertiesUpdate); @@ -186,6 +172,156 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const void* data) gAgent.sendReliableMessage(); } +//static +std::string LLAvatarPropertiesProcessor::ageFromDate(const std::string& date_string) +{ + // Convert string date to malleable representation + S32 month, day, year; + S32 matched = sscanf(date_string.c_str(), "%d/%d/%d", &month, &day, &year); + if (matched != 3) return "???"; + + // Create ISO-8601 date string + std::string iso8601_date_string = + llformat("%04d-%02d-%02dT00:00:00Z", year, month, day); + LLDate date(iso8601_date_string); + + // Correct for the fact that account creation dates are in Pacific time, + // == UTC - 8 + F64 date_secs_since_epoch = date.secondsSinceEpoch(); + date_secs_since_epoch += 8.0 * 60.0 * 60.0; + + // Convert seconds from epoch to seconds from now + F64 now_secs_since_epoch = LLDate::now().secondsSinceEpoch(); + F64 age_secs = now_secs_since_epoch - date_secs_since_epoch; + + // We don't care about sub-day times + const F64 SEC_PER_DAY = 24.0 * 60.0 * 60.0; + S32 age_days = lltrunc(age_secs / SEC_PER_DAY); + + // Assume most values won't be used to fill in the format string: + // "[AGEYEARS][AGEMONTHS][AGEWEEKS][AGEDAYS]old" + LLStringUtil::format_map_t final_args; + final_args["[AGEYEARS]"] = ""; + final_args["[AGEMONTHS]"] = ""; + final_args["[AGEWEEKS]"] = ""; + final_args["[AGEDAYS]"] = ""; + + // Try for age in round number of years + LLStringUtil::format_map_t args; + S32 age_years = age_days / 365; + age_days = age_days % 365; + if (age_years > 1) + { + args["[YEARS]"] = llformat("%d", age_years); + final_args["[AGEYEARS]"] = LLTrans::getString("AgeYears", args); + } + else if (age_years == 1) + { + final_args["[AGEYEARS]"] = LLTrans::getString("Age1Year"); + } + // fall through because we show years + months for ages > 1 year + + S32 age_months = age_days / 30; + age_days = age_days % 30; + if (age_months > 1) + { + args["[MONTHS]"] = llformat("%d", age_months); + final_args["[AGEMONTHS]"] = LLTrans::getString("AgeMonths", args); + // Either N years M months, or just M months, + // so we can exit. + return LLTrans::getString("YearsMonthsOld", final_args); + } + else if (age_months == 1) + { + final_args["[AGEMONTHS]"] = LLTrans::getString("Age1Month"); + return LLTrans::getString("YearsMonthsOld", final_args); + } + + // Now for age in weeks + S32 age_weeks = age_days / 7; + age_days = age_days % 7; + if (age_weeks > 1) + { + args["[WEEKS]"] = llformat("%d", age_weeks); + final_args["[AGEWEEKS]"] = LLTrans::getString("AgeWeeks", args); + return LLTrans::getString("WeeksOld", final_args); + } + else if (age_weeks == 1) + { + final_args["[AGEWEEKS]"] = LLTrans::getString("Age1Week"); + return LLTrans::getString("WeeksOld", final_args); + } + + // Down to days now + if (age_days > 1) + { + args["[DAYS]"] = llformat("%d", age_days); + final_args["[AGEDAYS]"] = LLTrans::getString("AgeDays", args); + return LLTrans::getString("DaysOld", final_args); + } + else if (age_days == 1) + { + final_args["[AGEDAYS]"] = LLTrans::getString("Age1Day"); + return LLTrans::getString("DaysOld", final_args); + } + else + { + return LLTrans::getString("TodayOld"); + } +} + + +//static +std::string LLAvatarPropertiesProcessor::accountType(const LLAvatarData* avatar_data) +{ + // If you have a special account, like M Linden ("El Jefe!") + // return an untranslated "special" string + if (!avatar_data->caption_text.empty()) + { + return avatar_data->caption_text; + } + const char* const ACCT_TYPE[] = { + "AcctTypeResident", + "AcctTypeTrial", + "AcctTypeCharterMember", + "AcctTypeEmployee" + }; + U8 caption_max = (U8)LL_ARRAY_SIZE(ACCT_TYPE)-1; + U8 caption_index = llclamp(avatar_data->caption_index, (U8)0, caption_max); + return LLTrans::getString(ACCT_TYPE[caption_index]); +} + +//static +std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_data) +{ + // Special accounts like M Linden don't have payment info revealed. + if (!avatar_data->caption_text.empty()) return ""; + + // Linden employees don't have payment info revealed + const S32 LINDEN_EMPLOYEE_INDEX = 3; + if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return ""; + + BOOL transacted = (avatar_data->flags & AVATAR_TRANSACTED); + BOOL identified = (avatar_data->flags & AVATAR_IDENTIFIED); + // Not currently getting set in dataserver/lldataavatar.cpp for privacy considerations + //BOOL age_verified = (avatar_data->flags & AVATAR_AGEVERIFIED); + + const char* payment_text; + if(transacted) + { + payment_text = "PaymentInfoUsed"; + } + else if (identified) + { + payment_text = "PaymentInfoOnFile"; + } + else + { + payment_text = "NoPaymentInfoOnFile"; + } + return LLTrans::getString(payment_text); +} + void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**) { LLAvatarData avatar_data; @@ -214,7 +350,10 @@ void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* { msg->getString(_PREHASH_PropertiesData, _PREHASH_CharterMember, avatar_data.caption_text); } - notifyObservers(avatar_data.avatar_id,&avatar_data,APT_PROPERTIES); + LLAvatarPropertiesProcessor* self = getInstance(); + // Request processed, no longer pending + self->removePendingRequest(avatar_data.avatar_id, APT_PROPERTIES); + self->notifyObservers(avatar_data.avatar_id,&avatar_data,APT_PROPERTIES); } void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* msg, void**) @@ -228,11 +367,13 @@ void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* m WARNING: LLTemplateMessageReader::decodeData: Message from 216.82.37.237:13000 with no handler function received: AvatarInterestsReply */ } + void LLAvatarPropertiesProcessor::processAvatarClassifiedReply(LLMessageSystem* msg, void**) { // avatarclassifiedsrequest is not sent according to new UI design but // keep this method according to resolved issues. } + void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg, void**) { LLAvatarNotes avatar_notes; @@ -241,7 +382,10 @@ void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg, msg->getUUID(_PREHASH_Data, _PREHASH_TargetID, avatar_notes.target_id); msg->getString(_PREHASH_Data, _PREHASH_Notes, avatar_notes.notes); - notifyObservers(avatar_notes.target_id,&avatar_notes,APT_NOTES); + LLAvatarPropertiesProcessor* self = getInstance(); + // Request processed, no longer pending + self->removePendingRequest(avatar_notes.target_id, APT_NOTES); + self->notifyObservers(avatar_notes.target_id,&avatar_notes,APT_NOTES); } void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, void**) @@ -261,7 +405,10 @@ void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, avatar_picks.picks_list.push_back(std::make_pair(pick_id,pick_name)); } - notifyObservers(avatar_picks.target_id,&avatar_picks,APT_PICKS); + LLAvatarPropertiesProcessor* self = getInstance(); + // Request processed, no longer pending + self->removePendingRequest(avatar_picks.target_id, APT_PICKS); + self->notifyObservers(avatar_picks.target_id,&avatar_picks,APT_PICKS); } void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, void**) @@ -306,7 +453,9 @@ void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, voi msg->getS32(_PREHASH_Data, _PREHASH_SortOrder, pick_data.sort_order); msg->getBOOL(_PREHASH_Data, _PREHASH_Enabled, pick_data.enabled); - notifyObservers(pick_data.creator_id, &pick_data, APT_PICK_INFO); + LLAvatarPropertiesProcessor* self = getInstance(); + // don't need to remove pending request as we don't track pick info + self->notifyObservers(pick_data.creator_id, &pick_data, APT_PICK_INFO); } void LLAvatarPropertiesProcessor::processAvatarGroupsReply(LLMessageSystem* msg, void**) @@ -329,12 +478,15 @@ void LLAvatarPropertiesProcessor::processAvatarGroupsReply(LLMessageSystem* msg, avatar_groups.group_list.push_back(group_data); } - notifyObservers(avatar_groups.avatar_id,&avatar_groups,APT_GROUPS); + LLAvatarPropertiesProcessor* self = getInstance(); + self->removePendingRequest(avatar_groups.avatar_id, APT_GROUPS); + self->notifyObservers(avatar_groups.avatar_id,&avatar_groups,APT_GROUPS); } void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type) { - LLAvatarPropertiesProcessor::observer_multimap_t observers = LLAvatarPropertiesProcessor::getInstance()->mObservers; + // Copy the map (because observers may delete themselves when updated?) + LLAvatarPropertiesProcessor::observer_multimap_t observers = mObservers; observer_multimap_t::iterator oi = observers.lower_bound(id); observer_multimap_t::iterator end = observers.upper_bound(id); @@ -397,10 +549,8 @@ void LLAvatarPropertiesProcessor::sendPickDelete( const LLUUID& pick_id ) gAgent.sendReliableMessage(); } -void LLAvatarPropertiesProcessor::sendPicInfoUpdate(const void* pick_data) +void LLAvatarPropertiesProcessor::sendPickInfoUpdate(const LLPickData* new_pick) { - if (!pick_data) return; - const LLPickData *new_pick = static_cast<const LLPickData*>(pick_data); if (!new_pick) return; LLMessageSystem* msg = gMessageSystem; @@ -440,3 +590,38 @@ void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id, request_params.push_back(pick_id.asString() ); send_generic_message("pickinforequest", request_params); } + + +bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) +{ + timestamp_map_t::key_type key = std::make_pair(avatar_id, type); + timestamp_map_t::iterator it = mRequestTimestamps.find(key); + + // Is this a new request? + if (it == mRequestTimestamps.end()) return false; + + // We found a request, check if it has timed out + U32 now = time(NULL); + const U32 REQUEST_EXPIRE_SECS = 5; + U32 expires = it->second + REQUEST_EXPIRE_SECS; + + // Request is still pending if it hasn't expired yet + // *NOTE: Expired requests will accumulate in this map, but they are rare, + // the data is small, and they will be updated if the same data is + // re-requested + return (now < expires); +} + +void LLAvatarPropertiesProcessor::addPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) +{ + timestamp_map_t::key_type key = std::make_pair(avatar_id, type); + U32 now = time(NULL); + // Add or update existing (expired) request + mRequestTimestamps[ key ] = now; +} + +void LLAvatarPropertiesProcessor::removePendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) +{ + timestamp_map_t::key_type key = std::make_pair(avatar_id, type); + mRequestTimestamps.erase(key); +} |