diff options
46 files changed, 2564 insertions, 46 deletions
diff --git a/linden/etc/message.xml b/linden/etc/message.xml index 0fdf364..8d34dd8 100644 --- a/linden/etc/message.xml +++ b/linden/etc/message.xml | |||
@@ -386,7 +386,17 @@ | |||
386 | <boolean>true</boolean> | 386 | <boolean>true</boolean> |
387 | </map> | 387 | </map> |
388 | 388 | ||
389 | <key>ParcelVoiceInfo</key> | 389 | <!-- Server to client --> |
390 | <key>DisplayNameUpdate</key> | ||
391 | <map> | ||
392 | <key>flavor</key> | ||
393 | <string>llsd</string> | ||
394 | <key>trusted-sender</key> | ||
395 | <boolean>true</boolean> | ||
396 | </map> | ||
397 | |||
398 | |||
399 | <key>ParcelVoiceInfo</key> | ||
390 | <map> | 400 | <map> |
391 | <key>flavor</key> | 401 | <key>flavor</key> |
392 | <string>llsd</string> | 402 | <string>llsd</string> |
@@ -442,6 +452,14 @@ | |||
442 | <boolean>true</boolean> | 452 | <boolean>true</boolean> |
443 | </map> | 453 | </map> |
444 | 454 | ||
455 | <key>SetDisplayNameReply</key> | ||
456 | <map> | ||
457 | <key>flavor</key> | ||
458 | <string>llsd</string> | ||
459 | <key>trusted-sender</key> | ||
460 | <boolean>true</boolean> | ||
461 | </map> | ||
462 | |||
445 | <key>DirLandReply</key> | 463 | <key>DirLandReply</key> |
446 | <map> | 464 | <map> |
447 | <key>flavor</key> | 465 | <key>flavor</key> |
diff --git a/linden/indra/llcommon/CMakeLists.txt b/linden/indra/llcommon/CMakeLists.txt index 5d590a9..af9b247 100644 --- a/linden/indra/llcommon/CMakeLists.txt +++ b/linden/indra/llcommon/CMakeLists.txt | |||
@@ -18,6 +18,7 @@ set(llcommon_SOURCE_FILES | |||
18 | llapp.cpp | 18 | llapp.cpp |
19 | llapr.cpp | 19 | llapr.cpp |
20 | llassettype.cpp | 20 | llassettype.cpp |
21 | llavatarname.cpp | ||
21 | llbase32.cpp | 22 | llbase32.cpp |
22 | llbase64.cpp | 23 | llbase64.cpp |
23 | llcommon.cpp | 24 | llcommon.cpp |
@@ -87,6 +88,7 @@ set(llcommon_HEADER_FILES | |||
87 | llassettype.h | 88 | llassettype.h |
88 | llassoclist.h | 89 | llassoclist.h |
89 | llavatarconstants.h | 90 | llavatarconstants.h |
91 | llavatarname.h | ||
90 | llbase32.h | 92 | llbase32.h |
91 | llbase64.h | 93 | llbase64.h |
92 | llboost.h | 94 | llboost.h |
diff --git a/linden/indra/llcommon/llavatarname.cpp b/linden/indra/llcommon/llavatarname.cpp new file mode 100644 index 0000000..ebe8c88 --- /dev/null +++ b/linden/indra/llcommon/llavatarname.cpp | |||
@@ -0,0 +1,150 @@ | |||
1 | /** | ||
2 | * @file llavatarname.cpp | ||
3 | * @brief Represents name-related data for an avatar, such as the | ||
4 | * username/SLID ("bobsmith123" or "james.linden") and the display | ||
5 | * name ("James Cook") | ||
6 | * | ||
7 | * $LicenseInfo:firstyear=2010&license=viewerlgpl$ | ||
8 | * Second Life Viewer Source Code | ||
9 | * Copyright (C) 2010, Linden Research, Inc. | ||
10 | * | ||
11 | * This library is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU Lesser General Public | ||
13 | * License as published by the Free Software Foundation; | ||
14 | * version 2.1 of the License only. | ||
15 | * | ||
16 | * This library is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * Lesser General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU Lesser General Public | ||
22 | * License along with this library; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA | ||
26 | * $/LicenseInfo$ | ||
27 | */ | ||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include "llavatarname.h" | ||
31 | |||
32 | #include "lldate.h" | ||
33 | #include "llsd.h" | ||
34 | |||
35 | bool LLAvatarName::sOmitResidentAsLastName = false; | ||
36 | |||
37 | // Store these in pre-built std::strings to avoid memory allocations in | ||
38 | // LLSD map lookups | ||
39 | static const std::string USERNAME("username"); | ||
40 | static const std::string DISPLAY_NAME("display_name"); | ||
41 | static const std::string LEGACY_FIRST_NAME("legacy_first_name"); | ||
42 | static const std::string LEGACY_LAST_NAME("legacy_last_name"); | ||
43 | static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default"); | ||
44 | static const std::string DISPLAY_NAME_EXPIRES("display_name_expires"); | ||
45 | static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update"); | ||
46 | |||
47 | LLAvatarName::LLAvatarName() | ||
48 | : mUsername(), | ||
49 | mDisplayName(), | ||
50 | mLegacyFirstName(), | ||
51 | mLegacyLastName(), | ||
52 | mIsDisplayNameDefault(false), | ||
53 | mIsDummy(false), | ||
54 | mExpires(F64_MAX), | ||
55 | mNextUpdate(0.0) | ||
56 | { } | ||
57 | |||
58 | bool LLAvatarName::operator<(const LLAvatarName& rhs) const | ||
59 | { | ||
60 | if (mUsername == rhs.mUsername) | ||
61 | return mDisplayName < rhs.mDisplayName; | ||
62 | else | ||
63 | return mUsername < rhs.mUsername; | ||
64 | } | ||
65 | |||
66 | LLSD LLAvatarName::asLLSD() const | ||
67 | { | ||
68 | LLSD sd; | ||
69 | sd[USERNAME] = mUsername; | ||
70 | sd[DISPLAY_NAME] = mDisplayName; | ||
71 | sd[LEGACY_FIRST_NAME] = mLegacyFirstName; | ||
72 | sd[LEGACY_LAST_NAME] = mLegacyLastName; | ||
73 | sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault; | ||
74 | sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires); | ||
75 | sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate); | ||
76 | return sd; | ||
77 | } | ||
78 | |||
79 | void LLAvatarName::fromLLSD(const LLSD& sd) | ||
80 | { | ||
81 | mUsername = sd[USERNAME].asString(); | ||
82 | mDisplayName = sd[DISPLAY_NAME].asString(); | ||
83 | mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString(); | ||
84 | mLegacyLastName = sd[LEGACY_LAST_NAME].asString(); | ||
85 | mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean(); | ||
86 | LLDate expires = sd[DISPLAY_NAME_EXPIRES]; | ||
87 | mExpires = expires.secondsSinceEpoch(); | ||
88 | LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE]; | ||
89 | mNextUpdate = next_update.secondsSinceEpoch(); | ||
90 | } | ||
91 | |||
92 | std::string LLAvatarName::getCompleteName() const | ||
93 | { | ||
94 | std::string name; | ||
95 | if (!mUsername.empty()) | ||
96 | { | ||
97 | name = mDisplayName + " (" + mUsername + ")"; | ||
98 | } | ||
99 | else | ||
100 | { | ||
101 | // ...display names are off, legacy name is in mDisplayName | ||
102 | name = mDisplayName; | ||
103 | } | ||
104 | return name; | ||
105 | } | ||
106 | |||
107 | std::string LLAvatarName::getLegacyName() const | ||
108 | { | ||
109 | std::string name; | ||
110 | name.reserve(mLegacyFirstName.size() + 1 + mLegacyLastName.size()); | ||
111 | name = mLegacyFirstName; | ||
112 | if (!sOmitResidentAsLastName || mLegacyLastName != "Resident") | ||
113 | { | ||
114 | name += " "; | ||
115 | name += mLegacyLastName; | ||
116 | } | ||
117 | return name; | ||
118 | } | ||
119 | |||
120 | std::string LLAvatarName::getNames(bool linefeed) const | ||
121 | { | ||
122 | std::string name; | ||
123 | |||
124 | if (mUsername.empty()) | ||
125 | { | ||
126 | // ...display names are off, legacy name is in mDisplayName | ||
127 | name = mDisplayName; | ||
128 | if (sOmitResidentAsLastName) | ||
129 | { | ||
130 | LLStringUtil::replaceString(name, " Resident", ""); | ||
131 | } | ||
132 | } | ||
133 | else | ||
134 | { | ||
135 | name = getLegacyName(); | ||
136 | if (name != mDisplayName) | ||
137 | { | ||
138 | if (linefeed) | ||
139 | { | ||
140 | name = mDisplayName + "\n[" + name + "]"; | ||
141 | } | ||
142 | else | ||
143 | { | ||
144 | name = mDisplayName + " [" + name + "]"; | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | return name; | ||
150 | } | ||
diff --git a/linden/indra/llcommon/llavatarname.h b/linden/indra/llcommon/llavatarname.h new file mode 100644 index 0000000..3b6c6ea --- /dev/null +++ b/linden/indra/llcommon/llavatarname.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /** | ||
2 | * @file llavatarname.h | ||
3 | * @brief Represents name-related data for an avatar, such as the | ||
4 | * username/SLID ("bobsmith123" or "james.linden") and the display | ||
5 | * name ("James Cook") | ||
6 | * | ||
7 | * $LicenseInfo:firstyear=2010&license=viewerlgpl$ | ||
8 | * Second Life Viewer Source Code | ||
9 | * Copyright (C) 2010, Linden Research, Inc. | ||
10 | * | ||
11 | * This library is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU Lesser General Public | ||
13 | * License as published by the Free Software Foundation; | ||
14 | * version 2.1 of the License only. | ||
15 | * | ||
16 | * This library is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * Lesser General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU Lesser General Public | ||
22 | * License along with this library; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA | ||
26 | * $/LicenseInfo$ | ||
27 | */ | ||
28 | #ifndef LLAVATARNAME_H | ||
29 | #define LLAVATARNAME_H | ||
30 | |||
31 | #include <string> | ||
32 | |||
33 | class LLSD; | ||
34 | |||
35 | class LL_COMMON_API LLAvatarName | ||
36 | { | ||
37 | public: | ||
38 | LLAvatarName(); | ||
39 | |||
40 | bool operator<(const LLAvatarName& rhs) const; | ||
41 | |||
42 | LLSD asLLSD() const; | ||
43 | |||
44 | void fromLLSD(const LLSD& sd); | ||
45 | |||
46 | // For normal names, returns "James Linden (james.linden)" | ||
47 | // When display names are disabled returns just "James Linden" | ||
48 | std::string getCompleteName() const; | ||
49 | |||
50 | // For normal names, returns "Whatever Display Name (John Doe)" when | ||
51 | // display name and legacy name are different, or just "John Doe" | ||
52 | // when they are equal or when display names are disabled. | ||
53 | // When linefeed == true, the space between the display name and | ||
54 | // the opening parenthesis for the legacy name is replaced with a | ||
55 | // line feed. | ||
56 | std::string getNames(bool linefeed = false) const; | ||
57 | |||
58 | // Returns "James Linden" or "bobsmith123 Resident" for backwards | ||
59 | // compatibility with systems like voice and muting | ||
60 | std::string getLegacyName() const; | ||
61 | |||
62 | // "bobsmith123" or "james.linden", US-ASCII only | ||
63 | std::string mUsername; | ||
64 | |||
65 | // "Jose' Sanchez" or "James Linden", UTF-8 encoded Unicode | ||
66 | // Contains data whether or not user has explicitly set | ||
67 | // a display name; may duplicate their username. | ||
68 | std::string mDisplayName; | ||
69 | |||
70 | // For "James Linden", "James" | ||
71 | // For "bobsmith123", "bobsmith123" | ||
72 | // Used to communicate with legacy systems like voice and muting which | ||
73 | // rely on old-style names. | ||
74 | std::string mLegacyFirstName; | ||
75 | |||
76 | // For "James Linden", "Linden" | ||
77 | // For "bobsmith123", "Resident" | ||
78 | // see above for rationale | ||
79 | std::string mLegacyLastName; | ||
80 | |||
81 | // If true, both display name and SLID were generated from | ||
82 | // a legacy first and last name, like "James Linden (james.linden)" | ||
83 | bool mIsDisplayNameDefault; | ||
84 | |||
85 | // Under error conditions, we may insert "dummy" records with | ||
86 | // names equal to legacy name into caches as placeholders. | ||
87 | // These can be shown in UI, but are not serialized. | ||
88 | bool mIsDummy; | ||
89 | |||
90 | // Names can change, so need to keep track of when name was | ||
91 | // last checked. | ||
92 | // Unix time-from-epoch seconds for efficiency | ||
93 | F64 mExpires; | ||
94 | |||
95 | // You can only change your name every N hours, so record | ||
96 | // when the next update is allowed | ||
97 | // Unix time-from-epoch seconds | ||
98 | F64 mNextUpdate; | ||
99 | |||
100 | // true to prevent the displaying of "Resident" as a last name | ||
101 | // in legacy names | ||
102 | static bool sOmitResidentAsLastName; | ||
103 | }; | ||
104 | |||
105 | #endif | ||
diff --git a/linden/indra/llmessage/CMakeLists.txt b/linden/indra/llmessage/CMakeLists.txt index a5e4249..9965191 100644 --- a/linden/indra/llmessage/CMakeLists.txt +++ b/linden/indra/llmessage/CMakeLists.txt | |||
@@ -22,6 +22,7 @@ include_directories( | |||
22 | set(llmessage_SOURCE_FILES | 22 | set(llmessage_SOURCE_FILES |
23 | llares.cpp | 23 | llares.cpp |
24 | llassetstorage.cpp | 24 | llassetstorage.cpp |
25 | llavatarnamecache.cpp | ||
25 | llblowfishcipher.cpp | 26 | llblowfishcipher.cpp |
26 | llbuffer.cpp | 27 | llbuffer.cpp |
27 | llbufferstream.cpp | 28 | llbufferstream.cpp |
@@ -105,6 +106,7 @@ set(llmessage_HEADER_FILES | |||
105 | 106 | ||
106 | llares.h | 107 | llares.h |
107 | llassetstorage.h | 108 | llassetstorage.h |
109 | llavatarnamecache.h | ||
108 | llblowfishcipher.h | 110 | llblowfishcipher.h |
109 | llbuffer.h | 111 | llbuffer.h |
110 | llbufferstream.h | 112 | llbufferstream.h |
diff --git a/linden/indra/llmessage/llavatarnamecache.cpp b/linden/indra/llmessage/llavatarnamecache.cpp new file mode 100644 index 0000000..45048e1 --- /dev/null +++ b/linden/indra/llmessage/llavatarnamecache.cpp | |||
@@ -0,0 +1,859 @@ | |||
1 | /** | ||
2 | * @file llavatarnamecache.cpp | ||
3 | * @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names | ||
4 | * ("James Cook") from avatar UUIDs. | ||
5 | * | ||
6 | * $LicenseInfo:firstyear=2010&license=viewerlgpl$ | ||
7 | * Second Life Viewer Source Code | ||
8 | * Copyright (C) 2010, Linden Research, Inc. | ||
9 | * | ||
10 | * This library is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU Lesser General Public | ||
12 | * License as published by the Free Software Foundation; | ||
13 | * version 2.1 of the License only. | ||
14 | * | ||
15 | * This library is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * Lesser General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU Lesser General Public | ||
21 | * License along with this library; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
23 | * | ||
24 | * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA | ||
25 | * $/LicenseInfo$ | ||
26 | */ | ||
27 | #include "linden_common.h" | ||
28 | |||
29 | #include "llavatarnamecache.h" | ||
30 | |||
31 | #include "llcachename.h" // we wrap this system | ||
32 | #include "llframetimer.h" | ||
33 | #include "llhttpclient.h" | ||
34 | #include "llsd.h" | ||
35 | #include "llsdserialize.h" | ||
36 | |||
37 | #include <boost/tokenizer.hpp> | ||
38 | |||
39 | #include <map> | ||
40 | #include <set> | ||
41 | |||
42 | namespace LLAvatarNameCache | ||
43 | { | ||
44 | use_display_name_signal_t mUseDisplayNamesSignal; | ||
45 | |||
46 | // Manual override for display names: 0 = legacy names, | ||
47 | // 1 = display name and legacy name, 2 = display name (legacy if absent) | ||
48 | U32 sUseDisplayNames = 0; | ||
49 | |||
50 | // Cache starts in a paused state until we can determine if the | ||
51 | // current region supports display names. | ||
52 | bool sRunning = false; | ||
53 | |||
54 | // Base lookup URL for name service. | ||
55 | // On simulator, loaded from indra.xml | ||
56 | // On viewer, usually a simulator capability (at People API team's request) | ||
57 | // Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/" | ||
58 | std::string sNameLookupURL; | ||
59 | |||
60 | // accumulated agent IDs for next query against service | ||
61 | typedef std::set<LLUUID> ask_queue_t; | ||
62 | ask_queue_t sAskQueue; | ||
63 | |||
64 | // agent IDs that have been requested, but with no reply | ||
65 | // maps agent ID to frame time request was made | ||
66 | typedef std::map<LLUUID, F64> pending_queue_t; | ||
67 | pending_queue_t sPendingQueue; | ||
68 | |||
69 | // Callbacks to fire when we received a name. | ||
70 | // May have multiple callbacks for a single ID, which are | ||
71 | // represented as multiple slots bound to the signal. | ||
72 | // Avoid copying signals via pointers. | ||
73 | typedef std::map<LLUUID, callback_signal_t*> signal_map_t; | ||
74 | signal_map_t sSignalMap; | ||
75 | |||
76 | // names we know about | ||
77 | typedef std::map<LLUUID, LLAvatarName> cache_t; | ||
78 | cache_t sCache; | ||
79 | |||
80 | // Send bulk lookup requests a few times a second at most | ||
81 | // only need per-frame timing resolution | ||
82 | LLFrameTimer sRequestTimer; | ||
83 | |||
84 | // Periodically clean out expired entries from the cache | ||
85 | //LLFrameTimer sEraseExpiredTimer; | ||
86 | |||
87 | //----------------------------------------------------------------------- | ||
88 | // Internal methods | ||
89 | //----------------------------------------------------------------------- | ||
90 | |||
91 | // Handle name response off network. | ||
92 | // Optionally skip adding to cache, used when this is a fallback to the | ||
93 | // legacy name system. | ||
94 | void processName(const LLUUID& agent_id, | ||
95 | const LLAvatarName& av_name, | ||
96 | bool add_to_cache); | ||
97 | |||
98 | void requestNamesViaCapability(); | ||
99 | |||
100 | // Legacy name system callback | ||
101 | void legacyNameCallback(const LLUUID& agent_id, | ||
102 | const std::string& first, const std::string& last, | ||
103 | BOOL is_group, void* data); | ||
104 | |||
105 | void requestNamesViaLegacy(); | ||
106 | |||
107 | // Fill in an LLAvatarName with the legacy name data | ||
108 | void buildLegacyName(const std::string& full_name, | ||
109 | LLAvatarName* av_name); | ||
110 | |||
111 | // Do a single callback to a given slot | ||
112 | void fireSignal(const LLUUID& agent_id, | ||
113 | const callback_slot_t& slot, | ||
114 | const LLAvatarName& av_name); | ||
115 | |||
116 | // Is a request in-flight over the network? | ||
117 | bool isRequestPending(const LLUUID& agent_id); | ||
118 | |||
119 | // Erase expired names from cache | ||
120 | void eraseExpired(); | ||
121 | |||
122 | bool expirationFromCacheControl(LLSD headers, F64 *expires); | ||
123 | } | ||
124 | |||
125 | /* Sample response: | ||
126 | <?xml version="1.0"?> | ||
127 | <llsd> | ||
128 | <map> | ||
129 | <key>agents</key> | ||
130 | <array> | ||
131 | <map> | ||
132 | <key>display_name_next_update</key> | ||
133 | <date>2010-04-16T21:34:02+00:00Z</date> | ||
134 | <key>display_name_expires</key> | ||
135 | <date>2010-04-16T21:32:26.142178+00:00Z</date> | ||
136 | <key>display_name</key> | ||
137 | <string>MickBot390 LLQABot</string> | ||
138 | <key>sl_id</key> | ||
139 | <string>mickbot390.llqabot</string> | ||
140 | <key>id</key> | ||
141 | <string>0012809d-7d2d-4c24-9609-af1230a37715</string> | ||
142 | <key>is_display_name_default</key> | ||
143 | <boolean>false</boolean> | ||
144 | </map> | ||
145 | <map> | ||
146 | <key>display_name_next_update</key> | ||
147 | <date>2010-04-16T21:34:02+00:00Z</date> | ||
148 | <key>display_name_expires</key> | ||
149 | <date>2010-04-16T21:32:26.142178+00:00Z</date> | ||
150 | <key>display_name</key> | ||
151 | <string>Bjork Gudmundsdottir</string> | ||
152 | <key>sl_id</key> | ||
153 | <string>sardonyx.linden</string> | ||
154 | <key>id</key> | ||
155 | <string>3941037e-78ab-45f0-b421-bd6e77c1804d</string> | ||
156 | <key>is_display_name_default</key> | ||
157 | <boolean>true</boolean> | ||
158 | </map> | ||
159 | </array> | ||
160 | </map> | ||
161 | </llsd> | ||
162 | */ | ||
163 | |||
164 | class LLAvatarNameResponder : public LLHTTPClient::Responder | ||
165 | { | ||
166 | private: | ||
167 | // need to store agent ids that are part of this request in case of | ||
168 | // an error, so we can flag them as unavailable | ||
169 | std::vector<LLUUID> mAgentIDs; | ||
170 | |||
171 | // Need the headers to look up Expires: and Retry-After: | ||
172 | LLSD mHeaders; | ||
173 | |||
174 | public: | ||
175 | LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids) | ||
176 | : mAgentIDs(agent_ids), | ||
177 | mHeaders() | ||
178 | { } | ||
179 | |||
180 | /*virtual*/ void completedHeader(U32 status, const std::string& reason, | ||
181 | const LLSD& headers) | ||
182 | { | ||
183 | mHeaders = headers; | ||
184 | } | ||
185 | |||
186 | /*virtual*/ void result(const LLSD& content) | ||
187 | { | ||
188 | // Pull expiration out of headers if available | ||
189 | F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders); | ||
190 | |||
191 | LLSD agents = content["agents"]; | ||
192 | LLSD::array_const_iterator it; | ||
193 | for (it = agents.beginArray(); it != agents.endArray(); ++it) | ||
194 | { | ||
195 | const LLSD& row = *it; | ||
196 | LLUUID agent_id = row["id"].asUUID(); | ||
197 | |||
198 | LLAvatarName av_name; | ||
199 | av_name.fromLLSD(row); | ||
200 | |||
201 | // Use expiration time from header | ||
202 | av_name.mExpires = expires; | ||
203 | |||
204 | // Some avatars don't have explicit display names set | ||
205 | if (av_name.mDisplayName.empty()) | ||
206 | { | ||
207 | av_name.mDisplayName = av_name.mUsername; | ||
208 | } | ||
209 | |||
210 | // cache it and fire signals | ||
211 | LLAvatarNameCache::processName(agent_id, av_name, true); | ||
212 | } | ||
213 | |||
214 | // Same logic as error response case | ||
215 | LLSD unresolved_agents = content["bad_ids"]; | ||
216 | if (unresolved_agents.size() > 0) | ||
217 | { | ||
218 | std::string first, last; | ||
219 | LLAvatarName av_name; | ||
220 | av_name.mIsDisplayNameDefault = false; | ||
221 | av_name.mIsDummy = true; | ||
222 | av_name.mExpires = expires; | ||
223 | |||
224 | for (it = unresolved_agents.beginArray(); it != unresolved_agents.endArray(); ++it) | ||
225 | { | ||
226 | const LLUUID& agent_id = *it; | ||
227 | gCacheName->getName(agent_id, first, last); | ||
228 | av_name.mLegacyFirstName = first; | ||
229 | av_name.mLegacyLastName = last; | ||
230 | av_name.mDisplayName = first; | ||
231 | if (last == "Resident") | ||
232 | { | ||
233 | av_name.mDisplayName = first; | ||
234 | av_name.mUsername = first; | ||
235 | } | ||
236 | else | ||
237 | { | ||
238 | av_name.mDisplayName = first + " " + last; | ||
239 | av_name.mUsername = first + "." + last; | ||
240 | } | ||
241 | LLStringUtil::toLower(av_name.mUsername); | ||
242 | // cache it and fire signals | ||
243 | LLAvatarNameCache::processName(agent_id, av_name, true); | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /*virtual*/ void error(U32 status, const std::string& reason) | ||
249 | { | ||
250 | // We're going to construct a dummy record and cache it for a while, | ||
251 | // either briefly for a 503 Service Unavailable, or longer for other | ||
252 | // errors. | ||
253 | F64 retry_timestamp = errorRetryTimestamp(status); | ||
254 | |||
255 | std::string first, last; | ||
256 | LLAvatarName av_name; | ||
257 | av_name.mIsDisplayNameDefault = false; | ||
258 | av_name.mIsDummy = true; | ||
259 | av_name.mExpires = retry_timestamp; | ||
260 | |||
261 | // Add dummy records for all agent IDs in this request | ||
262 | std::vector<LLUUID>::const_iterator it; | ||
263 | for (it = mAgentIDs.begin(); it != mAgentIDs.end(); ++it) | ||
264 | { | ||
265 | const LLUUID& agent_id = *it; | ||
266 | gCacheName->getName(agent_id, first, last); | ||
267 | av_name.mLegacyFirstName = first; | ||
268 | av_name.mLegacyLastName = last; | ||
269 | av_name.mDisplayName = first; | ||
270 | if (last == "Resident") | ||
271 | { | ||
272 | av_name.mDisplayName = first; | ||
273 | av_name.mUsername = first; | ||
274 | } | ||
275 | else | ||
276 | { | ||
277 | av_name.mDisplayName = first + " " + last; | ||
278 | av_name.mUsername = first + "." + last; | ||
279 | } | ||
280 | LLStringUtil::toLower(av_name.mUsername); | ||
281 | // cache it and fire signals | ||
282 | LLAvatarNameCache::processName(agent_id, av_name, true); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | // Return time to retry a request that generated an error, based on | ||
287 | // error type and headers. Return value is seconds-since-epoch. | ||
288 | F64 errorRetryTimestamp(S32 status) | ||
289 | { | ||
290 | F64 now = LLFrameTimer::getTotalSeconds(); | ||
291 | |||
292 | // Retry-After takes priority | ||
293 | LLSD retry_after = mHeaders["retry-after"]; | ||
294 | if (retry_after.isDefined()) | ||
295 | { | ||
296 | // We only support the delta-seconds type | ||
297 | S32 delta_seconds = retry_after.asInteger(); | ||
298 | if (delta_seconds > 0) | ||
299 | { | ||
300 | // ...valid delta-seconds | ||
301 | return now + F64(delta_seconds); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | // If no Retry-After, look for Cache-Control max-age | ||
306 | F64 expires = 0.0; | ||
307 | if (LLAvatarNameCache::expirationFromCacheControl(mHeaders, &expires)) | ||
308 | { | ||
309 | return expires; | ||
310 | } | ||
311 | |||
312 | // No information in header, make a guess | ||
313 | if (status == 503) | ||
314 | { | ||
315 | // ...service unavailable, retry soon | ||
316 | const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min | ||
317 | return now + SERVICE_UNAVAILABLE_DELAY; | ||
318 | } | ||
319 | else | ||
320 | { | ||
321 | // ...other unexpected error | ||
322 | const F64 DEFAULT_DELAY = 3600.0; // 1 hour | ||
323 | return now + DEFAULT_DELAY; | ||
324 | } | ||
325 | } | ||
326 | }; | ||
327 | |||
328 | void LLAvatarNameCache::processName(const LLUUID& agent_id, | ||
329 | const LLAvatarName& av_name, | ||
330 | bool add_to_cache) | ||
331 | { | ||
332 | if (add_to_cache) | ||
333 | { | ||
334 | sCache[agent_id] = av_name; | ||
335 | } | ||
336 | |||
337 | sPendingQueue.erase(agent_id); | ||
338 | |||
339 | // signal everyone waiting on this name | ||
340 | signal_map_t::iterator sig_it = sSignalMap.find(agent_id); | ||
341 | if (sig_it != sSignalMap.end()) | ||
342 | { | ||
343 | callback_signal_t* signal = sig_it->second; | ||
344 | (*signal)(agent_id, av_name); | ||
345 | |||
346 | sSignalMap.erase(agent_id); | ||
347 | |||
348 | delete signal; | ||
349 | signal = NULL; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | void LLAvatarNameCache::requestNamesViaCapability() | ||
354 | { | ||
355 | F64 now = LLFrameTimer::getTotalSeconds(); | ||
356 | |||
357 | // URL format is like: | ||
358 | // http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0 | ||
359 | // | ||
360 | // Apache can handle URLs of 4096 chars, but let's be conservative | ||
361 | const U32 NAME_URL_MAX = 4096; | ||
362 | const U32 NAME_URL_SEND_THRESHOLD = 3000; | ||
363 | std::string url; | ||
364 | url.reserve(NAME_URL_MAX); | ||
365 | |||
366 | std::vector<LLUUID> agent_ids; | ||
367 | agent_ids.reserve(128); | ||
368 | |||
369 | ask_queue_t::const_iterator it = sAskQueue.begin(); | ||
370 | for ( ; it != sAskQueue.end(); ++it) | ||
371 | { | ||
372 | const LLUUID& agent_id = *it; | ||
373 | |||
374 | if (url.empty()) | ||
375 | { | ||
376 | // ...starting new request | ||
377 | url += sNameLookupURL; | ||
378 | url += "?ids="; | ||
379 | } | ||
380 | else | ||
381 | { | ||
382 | // ...continuing existing request | ||
383 | url += "&ids="; | ||
384 | } | ||
385 | url += agent_id.asString(); | ||
386 | agent_ids.push_back(agent_id); | ||
387 | |||
388 | // mark request as pending | ||
389 | sPendingQueue[agent_id] = now; | ||
390 | |||
391 | if (url.size() > NAME_URL_SEND_THRESHOLD) | ||
392 | { | ||
393 | //llinfos << "requestNames " << url << llendl; | ||
394 | LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); | ||
395 | url.clear(); | ||
396 | agent_ids.clear(); | ||
397 | } | ||
398 | } | ||
399 | |||
400 | if (!url.empty()) | ||
401 | { | ||
402 | //llinfos << "requestNames " << url << llendl; | ||
403 | LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); | ||
404 | url.clear(); | ||
405 | agent_ids.clear(); | ||
406 | } | ||
407 | |||
408 | // We've moved all asks to the pending request queue | ||
409 | sAskQueue.clear(); | ||
410 | } | ||
411 | |||
412 | void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, | ||
413 | const std::string& first, const std::string& last, | ||
414 | BOOL is_group, void* data) | ||
415 | { | ||
416 | std::string full_name = first + " " + last; | ||
417 | // Construct a dummy record for this name. By convention, SLID is blank | ||
418 | // Never expires, but not written to disk, so lasts until end of session. | ||
419 | LLAvatarName av_name; | ||
420 | buildLegacyName(full_name, &av_name); | ||
421 | |||
422 | // Don't add to cache, the data already exists in the legacy name system | ||
423 | // cache and we don't want or need duplicate storage, because keeping the | ||
424 | // two copies in sync is complex. | ||
425 | processName(agent_id, av_name, false); | ||
426 | } | ||
427 | |||
428 | void LLAvatarNameCache::requestNamesViaLegacy() | ||
429 | { | ||
430 | F64 now = LLFrameTimer::getTotalSeconds(); | ||
431 | std::string full_name; | ||
432 | ask_queue_t::const_iterator it = sAskQueue.begin(); | ||
433 | for (; it != sAskQueue.end(); ++it) | ||
434 | { | ||
435 | const LLUUID& agent_id = *it; | ||
436 | |||
437 | // Mark as pending first, just in case the callback is immediately | ||
438 | // invoked below. This should never happen in practice. | ||
439 | sPendingQueue[agent_id] = now; | ||
440 | |||
441 | gCacheName->get(agent_id, false, legacyNameCallback); | ||
442 | } | ||
443 | |||
444 | // We've either answered immediately or moved all asks to the | ||
445 | // pending queue | ||
446 | sAskQueue.clear(); | ||
447 | } | ||
448 | |||
449 | void LLAvatarNameCache::initClass(bool running) | ||
450 | { | ||
451 | sRunning = running; | ||
452 | } | ||
453 | |||
454 | void LLAvatarNameCache::cleanupClass() | ||
455 | { | ||
456 | } | ||
457 | |||
458 | void LLAvatarNameCache::importFile(std::istream& istr) | ||
459 | { | ||
460 | LLSD data; | ||
461 | S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr); | ||
462 | if (parse_count < 1) return; | ||
463 | |||
464 | // by convention LLSD storage is a map | ||
465 | // we only store one entry in the map | ||
466 | LLSD agents = data["agents"]; | ||
467 | |||
468 | LLUUID agent_id; | ||
469 | LLAvatarName av_name; | ||
470 | LLSD::map_const_iterator it = agents.beginMap(); | ||
471 | for ( ; it != agents.endMap(); ++it) | ||
472 | { | ||
473 | agent_id.set(it->first); | ||
474 | av_name.fromLLSD( it->second ); | ||
475 | sCache[agent_id] = av_name; | ||
476 | } | ||
477 | // entries may have expired since we last ran the viewer, just | ||
478 | // clean them out now | ||
479 | eraseExpired(); | ||
480 | llinfos << "loaded " << sCache.size() << llendl; | ||
481 | } | ||
482 | |||
483 | void LLAvatarNameCache::exportFile(std::ostream& ostr) | ||
484 | { | ||
485 | LLSD agents; | ||
486 | cache_t::const_iterator it = sCache.begin(); | ||
487 | for ( ; it != sCache.end(); ++it) | ||
488 | { | ||
489 | const LLUUID& agent_id = it->first; | ||
490 | const LLAvatarName& av_name = it->second; | ||
491 | if (!av_name.mIsDummy) | ||
492 | { | ||
493 | // key must be a string | ||
494 | agents[agent_id.asString()] = av_name.asLLSD(); | ||
495 | } | ||
496 | } | ||
497 | LLSD data; | ||
498 | data["agents"] = agents; | ||
499 | LLSDSerialize::toPrettyXML(data, ostr); | ||
500 | } | ||
501 | |||
502 | void LLAvatarNameCache::setNameLookupURL(const std::string& name_lookup_url) | ||
503 | { | ||
504 | sNameLookupURL = name_lookup_url; | ||
505 | } | ||
506 | |||
507 | bool LLAvatarNameCache::hasNameLookupURL() | ||
508 | { | ||
509 | return !sNameLookupURL.empty(); | ||
510 | } | ||
511 | |||
512 | void LLAvatarNameCache::idle() | ||
513 | { | ||
514 | // By convention, start running at first idle() call | ||
515 | sRunning = true; | ||
516 | |||
517 | // *TODO: Possibly re-enabled this based on People API load measurements | ||
518 | // 100 ms is the threshold for "user speed" operations, so we can | ||
519 | // stall for about that long to batch up requests. | ||
520 | //const F32 SECS_BETWEEN_REQUESTS = 0.1f; | ||
521 | //if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS)) | ||
522 | //{ | ||
523 | // return; | ||
524 | //} | ||
525 | |||
526 | // Must be large relative to above | ||
527 | |||
528 | // No longer deleting expired entries, just re-requesting in the get | ||
529 | // this way first synchronous get call on an expired entry won't return | ||
530 | // legacy name. LF | ||
531 | |||
532 | //const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds | ||
533 | //if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) | ||
534 | //{ | ||
535 | // eraseExpired(); | ||
536 | //} | ||
537 | |||
538 | if (sAskQueue.empty()) | ||
539 | { | ||
540 | return; | ||
541 | } | ||
542 | |||
543 | if (useDisplayNames()) | ||
544 | { | ||
545 | requestNamesViaCapability(); | ||
546 | } | ||
547 | else | ||
548 | { | ||
549 | // ...fall back to legacy name cache system | ||
550 | requestNamesViaLegacy(); | ||
551 | } | ||
552 | } | ||
553 | |||
554 | bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id) | ||
555 | { | ||
556 | const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; | ||
557 | F64 now = LLFrameTimer::getTotalSeconds(); | ||
558 | F64 expire_time = now - PENDING_TIMEOUT_SECS; | ||
559 | |||
560 | pending_queue_t::const_iterator it = sPendingQueue.find(agent_id); | ||
561 | if (it != sPendingQueue.end()) | ||
562 | { | ||
563 | bool request_expired = (it->second < expire_time); | ||
564 | return !request_expired; | ||
565 | } | ||
566 | return false; | ||
567 | } | ||
568 | |||
569 | void LLAvatarNameCache::eraseExpired() | ||
570 | { | ||
571 | F64 now = LLFrameTimer::getTotalSeconds(); | ||
572 | cache_t::iterator it = sCache.begin(); | ||
573 | while (it != sCache.end()) | ||
574 | { | ||
575 | cache_t::iterator cur = it; | ||
576 | ++it; | ||
577 | const LLAvatarName& av_name = cur->second; | ||
578 | if (av_name.mExpires < now) | ||
579 | { | ||
580 | sCache.erase(cur); | ||
581 | } | ||
582 | } | ||
583 | } | ||
584 | |||
585 | void LLAvatarNameCache::buildLegacyName(const std::string& full_name, | ||
586 | LLAvatarName* av_name) | ||
587 | { | ||
588 | llassert(av_name); | ||
589 | av_name->mUsername = ""; | ||
590 | av_name->mDisplayName = full_name; | ||
591 | av_name->mIsDisplayNameDefault = true; | ||
592 | av_name->mIsDummy = true; | ||
593 | av_name->mExpires = F64_MAX; | ||
594 | } | ||
595 | |||
596 | // fills in av_name if it has it in the cache, even if expired (can check expiry time) | ||
597 | // returns bool specifying if av_name was filled, false otherwise | ||
598 | bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) | ||
599 | { | ||
600 | if (sRunning) | ||
601 | { | ||
602 | // ...only do immediate lookups when cache is running | ||
603 | if (useDisplayNames()) | ||
604 | { | ||
605 | // ...use display names cache | ||
606 | std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id); | ||
607 | if (it != sCache.end()) | ||
608 | { | ||
609 | *av_name = it->second; | ||
610 | |||
611 | // re-request name if entry is expired | ||
612 | if (av_name->mExpires < LLFrameTimer::getTotalSeconds()) | ||
613 | { | ||
614 | if (!isRequestPending(agent_id)) | ||
615 | { | ||
616 | sAskQueue.insert(agent_id); | ||
617 | } | ||
618 | } | ||
619 | |||
620 | return true; | ||
621 | } | ||
622 | } | ||
623 | else | ||
624 | { | ||
625 | // ...use legacy names cache | ||
626 | std::string full_name; | ||
627 | if (gCacheName->getFullName(agent_id, full_name)) | ||
628 | { | ||
629 | buildLegacyName(full_name, av_name); | ||
630 | return true; | ||
631 | } | ||
632 | } | ||
633 | } | ||
634 | |||
635 | if (!isRequestPending(agent_id)) | ||
636 | { | ||
637 | sAskQueue.insert(agent_id); | ||
638 | } | ||
639 | |||
640 | return false; | ||
641 | } | ||
642 | |||
643 | void LLAvatarNameCache::fireSignal(const LLUUID& agent_id, | ||
644 | const callback_slot_t& slot, | ||
645 | const LLAvatarName& av_name) | ||
646 | { | ||
647 | callback_signal_t signal; | ||
648 | signal.connect(slot); | ||
649 | signal(agent_id, av_name); | ||
650 | } | ||
651 | |||
652 | void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) | ||
653 | { | ||
654 | if (sRunning) | ||
655 | { | ||
656 | // ...only do immediate lookups when cache is running | ||
657 | if (useDisplayNames()) | ||
658 | { | ||
659 | // ...use new cache | ||
660 | std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id); | ||
661 | if (it != sCache.end()) | ||
662 | { | ||
663 | const LLAvatarName& av_name = it->second; | ||
664 | |||
665 | if (av_name.mExpires > LLFrameTimer::getTotalSeconds()) | ||
666 | { | ||
667 | // ...name already exists in cache, fire callback now | ||
668 | fireSignal(agent_id, slot, av_name); | ||
669 | |||
670 | return; | ||
671 | } | ||
672 | } | ||
673 | } | ||
674 | else | ||
675 | { | ||
676 | // ...use old name system | ||
677 | std::string full_name; | ||
678 | if (gCacheName->getFullName(agent_id, full_name)) | ||
679 | { | ||
680 | LLAvatarName av_name; | ||
681 | buildLegacyName(full_name, &av_name); | ||
682 | fireSignal(agent_id, slot, av_name); | ||
683 | return; | ||
684 | } | ||
685 | } | ||
686 | } | ||
687 | |||
688 | // schedule a request | ||
689 | if (!isRequestPending(agent_id)) | ||
690 | { | ||
691 | sAskQueue.insert(agent_id); | ||
692 | } | ||
693 | |||
694 | // always store additional callback, even if request is pending | ||
695 | signal_map_t::iterator sig_it = sSignalMap.find(agent_id); | ||
696 | if (sig_it == sSignalMap.end()) | ||
697 | { | ||
698 | // ...new callback for this id | ||
699 | callback_signal_t* signal = new callback_signal_t(); | ||
700 | signal->connect(slot); | ||
701 | sSignalMap[agent_id] = signal; | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | // ...existing callback, bind additional slot | ||
706 | callback_signal_t* signal = sig_it->second; | ||
707 | signal->connect(slot); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | |||
712 | void LLAvatarNameCache::setUseDisplayNames(U32 use) | ||
713 | { | ||
714 | if (use != sUseDisplayNames) | ||
715 | { | ||
716 | if (use > 2) | ||
717 | { | ||
718 | sUseDisplayNames = 1; | ||
719 | } | ||
720 | else | ||
721 | { | ||
722 | sUseDisplayNames = use; | ||
723 | } | ||
724 | // flush our cache | ||
725 | sCache.clear(); | ||
726 | |||
727 | mUseDisplayNamesSignal(); | ||
728 | } | ||
729 | } | ||
730 | |||
731 | U32 LLAvatarNameCache::useDisplayNames() | ||
732 | { | ||
733 | // Must be both manually set on and able to look up names. | ||
734 | if (sNameLookupURL.empty()) | ||
735 | { | ||
736 | return 0; | ||
737 | } | ||
738 | else | ||
739 | { | ||
740 | return sUseDisplayNames; | ||
741 | } | ||
742 | } | ||
743 | |||
744 | void LLAvatarNameCache::erase(const LLUUID& agent_id) | ||
745 | { | ||
746 | sCache.erase(agent_id); | ||
747 | } | ||
748 | |||
749 | void LLAvatarNameCache::fetch(const LLUUID& agent_id) | ||
750 | { | ||
751 | // re-request, even if request is already pending | ||
752 | sAskQueue.insert(agent_id); | ||
753 | } | ||
754 | |||
755 | void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name) | ||
756 | { | ||
757 | // *TODO: update timestamp if zero? | ||
758 | sCache[agent_id] = av_name; | ||
759 | } | ||
760 | |||
761 | F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) | ||
762 | { | ||
763 | F64 expires = 0.0; | ||
764 | if (expirationFromCacheControl(headers, &expires)) | ||
765 | { | ||
766 | return expires; | ||
767 | } | ||
768 | else | ||
769 | { | ||
770 | // With no expiration info, default to an hour | ||
771 | const F64 DEFAULT_EXPIRES = 60.0 * 60.0; | ||
772 | F64 now = LLFrameTimer::getTotalSeconds(); | ||
773 | return now + DEFAULT_EXPIRES; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) | ||
778 | { | ||
779 | // Allow the header to override the default | ||
780 | LLSD cache_control_header = headers["cache-control"]; | ||
781 | if (cache_control_header.isDefined()) | ||
782 | { | ||
783 | S32 max_age = 0; | ||
784 | std::string cache_control = cache_control_header.asString(); | ||
785 | if (max_age_from_cache_control(cache_control, &max_age)) | ||
786 | { | ||
787 | F64 now = LLFrameTimer::getTotalSeconds(); | ||
788 | *expires = now + (F64)max_age; | ||
789 | return true; | ||
790 | } | ||
791 | } | ||
792 | return false; | ||
793 | } | ||
794 | |||
795 | |||
796 | void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb) | ||
797 | { | ||
798 | mUseDisplayNamesSignal.connect(cb); | ||
799 | } | ||
800 | |||
801 | |||
802 | static const std::string MAX_AGE("max-age"); | ||
803 | static const boost::char_separator<char> EQUALS_SEPARATOR("="); | ||
804 | static const boost::char_separator<char> COMMA_SEPARATOR(","); | ||
805 | |||
806 | bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age) | ||
807 | { | ||
808 | // Split the string on "," to get a list of directives | ||
809 | typedef boost::tokenizer<boost::char_separator<char> > tokenizer; | ||
810 | tokenizer directives(cache_control, COMMA_SEPARATOR); | ||
811 | |||
812 | tokenizer::iterator token_it = directives.begin(); | ||
813 | for ( ; token_it != directives.end(); ++token_it) | ||
814 | { | ||
815 | // Tokens may have leading or trailing whitespace | ||
816 | std::string token = *token_it; | ||
817 | LLStringUtil::trim(token); | ||
818 | |||
819 | if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0) | ||
820 | { | ||
821 | // ...this token starts with max-age, so let's chop it up by "=" | ||
822 | tokenizer subtokens(token, EQUALS_SEPARATOR); | ||
823 | tokenizer::iterator subtoken_it = subtokens.begin(); | ||
824 | |||
825 | // Must have a token | ||
826 | if (subtoken_it == subtokens.end()) return false; | ||
827 | std::string subtoken = *subtoken_it; | ||
828 | |||
829 | // Must exactly equal "max-age" | ||
830 | LLStringUtil::trim(subtoken); | ||
831 | if (subtoken != MAX_AGE) return false; | ||
832 | |||
833 | // Must have another token | ||
834 | ++subtoken_it; | ||
835 | if (subtoken_it == subtokens.end()) return false; | ||
836 | subtoken = *subtoken_it; | ||
837 | |||
838 | // Must be a valid integer | ||
839 | // *NOTE: atoi() returns 0 for invalid values, so we have to | ||
840 | // check the string first. | ||
841 | // *TODO: Do servers ever send "0000" for zero? We don't handle it | ||
842 | LLStringUtil::trim(subtoken); | ||
843 | if (subtoken == "0") | ||
844 | { | ||
845 | *max_age = 0; | ||
846 | return true; | ||
847 | } | ||
848 | S32 val = atoi( subtoken.c_str() ); | ||
849 | if (val > 0 && val < S32_MAX) | ||
850 | { | ||
851 | *max_age = val; | ||
852 | return true; | ||
853 | } | ||
854 | return false; | ||
855 | } | ||
856 | } | ||
857 | return false; | ||
858 | } | ||
859 | |||
diff --git a/linden/indra/llmessage/llavatarnamecache.h b/linden/indra/llmessage/llavatarnamecache.h new file mode 100644 index 0000000..a2519cd --- /dev/null +++ b/linden/indra/llmessage/llavatarnamecache.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /** | ||
2 | * @file llavatarnamecache.h | ||
3 | * @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names | ||
4 | * ("James Cook") from avatar UUIDs. | ||
5 | * | ||
6 | * $LicenseInfo:firstyear=2010&license=viewerlgpl$ | ||
7 | * Second Life Viewer Source Code | ||
8 | * Copyright (C) 2010, Linden Research, Inc. | ||
9 | * | ||
10 | * This library is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU Lesser General Public | ||
12 | * License as published by the Free Software Foundation; | ||
13 | * version 2.1 of the License only. | ||
14 | * | ||
15 | * This library is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * Lesser General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU Lesser General Public | ||
21 | * License along with this library; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
23 | * | ||
24 | * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA | ||
25 | * $/LicenseInfo$ | ||
26 | */ | ||
27 | |||
28 | #ifndef LLAVATARNAMECACHE_H | ||
29 | #define LLAVATARNAMECACHE_H | ||
30 | |||
31 | #include "llavatarname.h" // for convenience | ||
32 | |||
33 | #include <boost/signals2.hpp> | ||
34 | |||
35 | // We have display names support (this is for use by patches) | ||
36 | #define LL_DISPLAY_NAMES | ||
37 | |||
38 | class LLSD; | ||
39 | class LLUUID; | ||
40 | |||
41 | namespace LLAvatarNameCache | ||
42 | { | ||
43 | |||
44 | typedef boost::signals2::signal<void (void)> use_display_name_signal_t; | ||
45 | |||
46 | // Until the cache is set running, immediate lookups will fail and | ||
47 | // async lookups will be queued. This allows us to block requests | ||
48 | // until we know if the first region supports display names. | ||
49 | void initClass(bool running); | ||
50 | void cleanupClass(); | ||
51 | |||
52 | void importFile(std::istream& istr); | ||
53 | void exportFile(std::ostream& ostr); | ||
54 | |||
55 | // On the viewer, usually a simulator capabilitity | ||
56 | // If empty, name cache will fall back to using legacy name | ||
57 | // lookup system | ||
58 | void setNameLookupURL(const std::string& name_lookup_url); | ||
59 | |||
60 | // Do we have a valid lookup URL, hence are we trying to use the | ||
61 | // new display name lookup system? | ||
62 | bool hasNameLookupURL(); | ||
63 | |||
64 | // Periodically makes a batch request for display names not already in | ||
65 | // cache. Call once per frame. | ||
66 | void idle(); | ||
67 | |||
68 | // If name is in cache, returns true and fills in provided LLAvatarName | ||
69 | // otherwise returns false | ||
70 | bool get(const LLUUID& agent_id, LLAvatarName *av_name); | ||
71 | |||
72 | // Callback types for get() below | ||
73 | typedef boost::signals2::signal< | ||
74 | void (const LLUUID& agent_id, const LLAvatarName& av_name)> | ||
75 | callback_signal_t; | ||
76 | typedef callback_signal_t::slot_type callback_slot_t; | ||
77 | |||
78 | // Fetches name information and calls callback. | ||
79 | // If name information is in cache, callback will be called immediately. | ||
80 | void get(const LLUUID& agent_id, callback_slot_t slot); | ||
81 | |||
82 | void setUseDisplayNames(U32 use); | ||
83 | U32 useDisplayNames(); | ||
84 | |||
85 | void erase(const LLUUID& agent_id); | ||
86 | |||
87 | // Force a re-fetch of the most recent data, but keep the current | ||
88 | // data in cache | ||
89 | void fetch(const LLUUID& agent_id); | ||
90 | |||
91 | void insert(const LLUUID& agent_id, const LLAvatarName& av_name); | ||
92 | |||
93 | // Compute name expiration time from HTTP Cache-Control header, | ||
94 | // or return default value, in seconds from epoch. | ||
95 | F64 nameExpirationFromHeaders(LLSD headers); | ||
96 | |||
97 | void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); | ||
98 | } | ||
99 | |||
100 | // Parse a cache-control header to get the max-age delta-seconds. | ||
101 | // Returns true if header has max-age param and it parses correctly. | ||
102 | // Exported here to ease unit testing. | ||
103 | bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age); | ||
104 | |||
105 | #endif | ||
diff --git a/linden/indra/llmessage/llcachename.h b/linden/indra/llmessage/llcachename.h index 2757b86..cb3cc1f 100644 --- a/linden/indra/llmessage/llcachename.h +++ b/linden/indra/llmessage/llcachename.h | |||
@@ -33,6 +33,8 @@ | |||
33 | #ifndef LL_LLCACHENAME_H | 33 | #ifndef LL_LLCACHENAME_H |
34 | #define LL_LLCACHENAME_H | 34 | #define LL_LLCACHENAME_H |
35 | 35 | ||
36 | #include "llavatarnamecache.h" // for convenience | ||
37 | |||
36 | class LLMessageSystem; | 38 | class LLMessageSystem; |
37 | class LLHost; | 39 | class LLHost; |
38 | class LLUUID; | 40 | class LLUUID; |
diff --git a/linden/indra/newview/CMakeLists.txt b/linden/indra/newview/CMakeLists.txt index 4a30be3..0eb5b41 100644 --- a/linden/indra/newview/CMakeLists.txt +++ b/linden/indra/newview/CMakeLists.txt | |||
@@ -173,6 +173,7 @@ set(viewer_SOURCE_FILES | |||
173 | llfloatercustomize.cpp | 173 | llfloatercustomize.cpp |
174 | llfloaterdaycycle.cpp | 174 | llfloaterdaycycle.cpp |
175 | llfloaterdirectory.cpp | 175 | llfloaterdirectory.cpp |
176 | llfloaterdisplayname.cpp | ||
176 | llfloatereditui.cpp | 177 | llfloatereditui.cpp |
177 | llfloaterenvsettings.cpp | 178 | llfloaterenvsettings.cpp |
178 | llfloaterevent.cpp | 179 | llfloaterevent.cpp |
@@ -410,6 +411,7 @@ set(viewer_SOURCE_FILES | |||
410 | llviewercamera.cpp | 411 | llviewercamera.cpp |
411 | llviewercontrol.cpp | 412 | llviewercontrol.cpp |
412 | llviewerdisplay.cpp | 413 | llviewerdisplay.cpp |
414 | llviewerdisplayname.cpp | ||
413 | llviewergenericmessage.cpp | 415 | llviewergenericmessage.cpp |
414 | llviewergesture.cpp | 416 | llviewergesture.cpp |
415 | llviewerimage.cpp | 417 | llviewerimage.cpp |
@@ -632,6 +634,7 @@ set(viewer_HEADER_FILES | |||
632 | llfloatercustomize.h | 634 | llfloatercustomize.h |
633 | llfloaterdaycycle.h | 635 | llfloaterdaycycle.h |
634 | llfloaterdirectory.h | 636 | llfloaterdirectory.h |
637 | llfloaterdisplayname.h | ||
635 | llfloatereditui.h | 638 | llfloatereditui.h |
636 | llfloaterenvsettings.h | 639 | llfloaterenvsettings.h |
637 | llfloaterevent.h | 640 | llfloaterevent.h |
@@ -873,6 +876,7 @@ set(viewer_HEADER_FILES | |||
873 | llviewercamera.h | 876 | llviewercamera.h |
874 | llviewercontrol.h | 877 | llviewercontrol.h |
875 | llviewerdisplay.h | 878 | llviewerdisplay.h |
879 | llviewerdisplayname.h | ||
876 | llviewergenericmessage.h | 880 | llviewergenericmessage.h |
877 | llviewergesture.h | 881 | llviewergesture.h |
878 | llviewerimage.h | 882 | llviewerimage.h |
diff --git a/linden/indra/newview/app_settings/settings.xml b/linden/indra/newview/app_settings/settings.xml index b7d6433..d0db713 100644 --- a/linden/indra/newview/app_settings/settings.xml +++ b/linden/indra/newview/app_settings/settings.xml | |||
@@ -419,6 +419,42 @@ | |||
419 | <key>Value</key> | 419 | <key>Value</key> |
420 | <integer>0</integer> | 420 | <integer>0</integer> |
421 | </map> | 421 | </map> |
422 | |||
423 | <!-- Display Names --> | ||
424 | <key>DisplayNamesUsage</key> | ||
425 | <map> | ||
426 | <key>Comment</key> | ||
427 | <string>Usage type for display names: 0 = Legacy name only, 1 = Display name with legacy name, 2 = display name only (legacy name when absent)</string> | ||
428 | <key>Persist</key> | ||
429 | <integer>1</integer> | ||
430 | <key>Type</key> | ||
431 | <string>U32</string> | ||
432 | <key>Value</key> | ||
433 | <integer>1</integer> | ||
434 | </map> | ||
435 | <key>OmitResidentAsLastName</key> | ||
436 | <map> | ||
437 | <key>Comment</key> | ||
438 | <string>Do not display "Resident" as the last name for new residents in their legacy name</string> | ||
439 | <key>Persist</key> | ||
440 | <integer>1</integer> | ||
441 | <key>Type</key> | ||
442 | <string>Boolean</string> | ||
443 | <key>Value</key> | ||
444 | <integer>1</integer> | ||
445 | </map> | ||
446 | <key>LegacyNamesForFriends</key> | ||
447 | <map> | ||
448 | <key>Comment</key> | ||
449 | <string>When TRUE, forces the use of the legacy names for the friends list and online notifications</string> | ||
450 | <key>Persist</key> | ||
451 | <integer>1</integer> | ||
452 | <key>Type</key> | ||
453 | <string>Boolean</string> | ||
454 | <key>Value</key> | ||
455 | <integer>1</integer> | ||
456 | </map> | ||
457 | |||
422 | <key>EmeraldTemporaryUpload</key> | 458 | <key>EmeraldTemporaryUpload</key> |
423 | <map> | 459 | <map> |
424 | <key>Comment</key> | 460 | <key>Comment</key> |
diff --git a/linden/indra/newview/llappviewer.cpp b/linden/indra/newview/llappviewer.cpp index d920e84..0c3c657 100644 --- a/linden/indra/newview/llappviewer.cpp +++ b/linden/indra/newview/llappviewer.cpp | |||
@@ -1259,6 +1259,7 @@ bool LLAppViewer::cleanup() | |||
1259 | 1259 | ||
1260 | LLPolyMesh::freeAllMeshes(); | 1260 | LLPolyMesh::freeAllMeshes(); |
1261 | 1261 | ||
1262 | LLAvatarNameCache::cleanupClass(); | ||
1262 | delete gCacheName; | 1263 | delete gCacheName; |
1263 | gCacheName = NULL; | 1264 | gCacheName = NULL; |
1264 | 1265 | ||
@@ -3300,6 +3301,14 @@ void LLAppViewer::saveFinalSnapshot() | |||
3300 | 3301 | ||
3301 | void LLAppViewer::loadNameCache() | 3302 | void LLAppViewer::loadNameCache() |
3302 | { | 3303 | { |
3304 | // display names cache | ||
3305 | std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); | ||
3306 | llifstream name_cache_stream(filename); | ||
3307 | if (name_cache_stream.is_open()) | ||
3308 | { | ||
3309 | LLAvatarNameCache::importFile(name_cache_stream); | ||
3310 | } | ||
3311 | |||
3303 | if (!gCacheName) return; | 3312 | if (!gCacheName) return; |
3304 | 3313 | ||
3305 | std::string name_cache; | 3314 | std::string name_cache; |
@@ -3322,6 +3331,14 @@ void LLAppViewer::loadNameCache() | |||
3322 | 3331 | ||
3323 | void LLAppViewer::saveNameCache() | 3332 | void LLAppViewer::saveNameCache() |
3324 | { | 3333 | { |
3334 | // display names cache | ||
3335 | std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); | ||
3336 | llofstream name_cache_stream(filename); | ||
3337 | if (name_cache_stream.is_open()) | ||
3338 | { | ||
3339 | LLAvatarNameCache::exportFile(name_cache_stream); | ||
3340 | } | ||
3341 | |||
3325 | if (!gCacheName) return; | 3342 | if (!gCacheName) return; |
3326 | 3343 | ||
3327 | std::string name_cache; | 3344 | std::string name_cache; |
@@ -3526,6 +3543,8 @@ void LLAppViewer::idle() | |||
3526 | // floating throughout the various object lists. | 3543 | // floating throughout the various object lists. |
3527 | // | 3544 | // |
3528 | 3545 | ||
3546 | idleNameCache(); | ||
3547 | |||
3529 | gFrameStats.start(LLFrameStats::IDLE_NETWORK); | 3548 | gFrameStats.start(LLFrameStats::IDLE_NETWORK); |
3530 | stop_glerror(); | 3549 | stop_glerror(); |
3531 | idleNetwork(); | 3550 | idleNetwork(); |
@@ -3907,6 +3926,60 @@ void LLAppViewer::sendLogoutRequest() | |||
3907 | } | 3926 | } |
3908 | } | 3927 | } |
3909 | 3928 | ||
3929 | void LLAppViewer::idleNameCache() | ||
3930 | { | ||
3931 | // Neither old nor new name cache can function before agent has a region | ||
3932 | LLViewerRegion* region = gAgent.getRegion(); | ||
3933 | if (!region) return; | ||
3934 | |||
3935 | // deal with any queued name requests and replies. | ||
3936 | gCacheName->processPending(); | ||
3937 | |||
3938 | // Can't run the new cache until we have the list of capabilities | ||
3939 | // for the agent region, and can therefore decide whether to use | ||
3940 | // display names or fall back to the old name system. | ||
3941 | if (!region->capabilitiesReceived()) return; | ||
3942 | |||
3943 | // Agent may have moved to a different region, so need to update cap URL | ||
3944 | // for name lookups. Can't do this in the cap grant code, as caps are | ||
3945 | // granted to neighbor regions before the main agent gets there. Can't | ||
3946 | // do it in the move-into-region code because cap not guaranteed to be | ||
3947 | // granted yet, for example on teleport. | ||
3948 | bool had_capability = LLAvatarNameCache::hasNameLookupURL(); | ||
3949 | std::string name_lookup_url; | ||
3950 | name_lookup_url.reserve(128); // avoid a memory allocation below | ||
3951 | name_lookup_url = region->getCapability("GetDisplayNames"); | ||
3952 | bool have_capability = !name_lookup_url.empty(); | ||
3953 | if (have_capability) | ||
3954 | { | ||
3955 | // we have support for display names, use it | ||
3956 | U32 url_size = name_lookup_url.size(); | ||
3957 | // capabilities require URLs with slashes before query params: | ||
3958 | // https://<host>:<port>/cap/<uuid>/?ids=<blah> | ||
3959 | // but the caps are granted like: | ||
3960 | // https://<host>:<port>/cap/<uuid> | ||
3961 | if (url_size > 0 && name_lookup_url[url_size-1] != '/') | ||
3962 | { | ||
3963 | name_lookup_url += '/'; | ||
3964 | } | ||
3965 | LLAvatarNameCache::setNameLookupURL(name_lookup_url); | ||
3966 | } | ||
3967 | else | ||
3968 | { | ||
3969 | // Display names not available on this region | ||
3970 | LLAvatarNameCache::setNameLookupURL( std::string() ); | ||
3971 | } | ||
3972 | |||
3973 | // Error recovery - did we change state? | ||
3974 | if (had_capability != have_capability) | ||
3975 | { | ||
3976 | // name tags are persistant on screen, so make sure they refresh | ||
3977 | LLVOAvatar::invalidateNameTags(); | ||
3978 | } | ||
3979 | |||
3980 | LLAvatarNameCache::idle(); | ||
3981 | } | ||
3982 | |||
3910 | // | 3983 | // |
3911 | // Handle messages, and all message related stuff | 3984 | // Handle messages, and all message related stuff |
3912 | // | 3985 | // |
diff --git a/linden/indra/newview/llappviewer.h b/linden/indra/newview/llappviewer.h index 7b3230a..42c49de 100644 --- a/linden/indra/newview/llappviewer.h +++ b/linden/indra/newview/llappviewer.h | |||
@@ -192,6 +192,7 @@ private: | |||
192 | 192 | ||
193 | void idle(); | 193 | void idle(); |
194 | void idleShutdown(); | 194 | void idleShutdown(); |
195 | void idleNameCache(); | ||
195 | void idleNetwork(); | 196 | void idleNetwork(); |
196 | 197 | ||
197 | void sendLogoutRequest(); | 198 | void sendLogoutRequest(); |
diff --git a/linden/indra/newview/llcallingcard.cpp b/linden/indra/newview/llcallingcard.cpp index 15be0eb..31d7bec 100644 --- a/linden/indra/newview/llcallingcard.cpp +++ b/linden/indra/newview/llcallingcard.cpp | |||
@@ -613,6 +613,25 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg) | |||
613 | LLSD args; | 613 | LLSD args; |
614 | if(gCacheName->getName(agent_id, first, last)) | 614 | if(gCacheName->getName(agent_id, first, last)) |
615 | { | 615 | { |
616 | if (LLAvatarNameCache::useDisplayNames() && !gSavedSettings.getBOOL("LegacyNamesForFriends")) | ||
617 | { | ||
618 | LLAvatarName avatar_name; | ||
619 | if (LLAvatarNameCache::get(agent_id, &avatar_name)) | ||
620 | { | ||
621 | // Always show "Display Name [Legacy Name]" for security reasons | ||
622 | first = avatar_name.getNames(); | ||
623 | size_t i = first.find(" "); | ||
624 | if (i != std::string::npos) | ||
625 | { | ||
626 | last = first.substr(i + 1); | ||
627 | first = first.substr(0, i); | ||
628 | } | ||
629 | else | ||
630 | { | ||
631 | last = ""; | ||
632 | } | ||
633 | } | ||
634 | } | ||
616 | args["FIRST_NAME"] = first; | 635 | args["FIRST_NAME"] = first; |
617 | args["LAST_NAME"] = last; | 636 | args["LAST_NAME"] = last; |
618 | } | 637 | } |
@@ -669,6 +688,31 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) | |||
669 | std::string first, last; | 688 | std::string first, last; |
670 | if(gCacheName->getName(agent_id, first, last)) | 689 | if(gCacheName->getName(agent_id, first, last)) |
671 | { | 690 | { |
691 | if (LLAvatarNameCache::useDisplayNames() && !gSavedSettings.getBOOL("LegacyNamesForFriends")) | ||
692 | { | ||
693 | LLAvatarName avatar_name; | ||
694 | if (LLAvatarNameCache::get(agent_id, &avatar_name)) | ||
695 | { | ||
696 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
697 | { | ||
698 | first = avatar_name.mDisplayName; | ||
699 | } | ||
700 | else | ||
701 | { | ||
702 | first = avatar_name.getNames(); | ||
703 | } | ||
704 | size_t i = first.find(" "); | ||
705 | if (i != std::string::npos) | ||
706 | { | ||
707 | last = first.substr(i + 1); | ||
708 | first = first.substr(0, i); | ||
709 | } | ||
710 | else | ||
711 | { | ||
712 | last = ""; | ||
713 | } | ||
714 | } | ||
715 | } | ||
672 | notify = TRUE; | 716 | notify = TRUE; |
673 | args["FIRST"] = first; | 717 | args["FIRST"] = first; |
674 | args["LAST"] = last; | 718 | args["LAST"] = last; |
@@ -745,6 +789,12 @@ void LLAvatarTracker::processTerminateFriendship(LLMessageSystem* msg, void**) | |||
745 | } | 789 | } |
746 | } | 790 | } |
747 | 791 | ||
792 | void LLAvatarTracker::dirtyBuddies() | ||
793 | { | ||
794 | mModifyMask |= LLFriendObserver::REMOVE | LLFriendObserver::ADD; | ||
795 | notifyObservers(); | ||
796 | } | ||
797 | |||
748 | ///---------------------------------------------------------------------------- | 798 | ///---------------------------------------------------------------------------- |
749 | /// Tracking Data | 799 | /// Tracking Data |
750 | ///---------------------------------------------------------------------------- | 800 | ///---------------------------------------------------------------------------- |
diff --git a/linden/indra/newview/llcallingcard.h b/linden/indra/newview/llcallingcard.h index d3f53c6..d5496ae 100644 --- a/linden/indra/newview/llcallingcard.h +++ b/linden/indra/newview/llcallingcard.h | |||
@@ -122,6 +122,9 @@ public: | |||
122 | // deal with termination of friendhsip | 122 | // deal with termination of friendhsip |
123 | void terminateBuddy(const LLUUID& id); | 123 | void terminateBuddy(const LLUUID& id); |
124 | 124 | ||
125 | // flag the buddy list dirty to force an update | ||
126 | void dirtyBuddies(); | ||
127 | |||
125 | // get full info | 128 | // get full info |
126 | const LLRelationship* getBuddyInfo(const LLUUID& id) const; | 129 | const LLRelationship* getBuddyInfo(const LLUUID& id) const; |
127 | 130 | ||
diff --git a/linden/indra/newview/llfloateractivespeakers.cpp b/linden/indra/newview/llfloateractivespeakers.cpp index 59de717..75cf176 100644 --- a/linden/indra/newview/llfloateractivespeakers.cpp +++ b/linden/indra/newview/llfloateractivespeakers.cpp | |||
@@ -92,18 +92,19 @@ LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerTy | |||
92 | 92 | ||
93 | void LLSpeaker::lookupName() | 93 | void LLSpeaker::lookupName() |
94 | { | 94 | { |
95 | gCacheName->getName(mID, onAvatarNameLookup, new LLHandle<LLSpeaker>(getHandle())); | 95 | LLAvatarNameCache::get(mID, boost::bind(&LLSpeaker::onAvatarNameLookup, _1, _2, new LLHandle<LLSpeaker>(getHandle()))); |
96 | } | 96 | } |
97 | 97 | ||
98 | //static | 98 | //static |
99 | void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* user_data) | 99 | void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const LLAvatarName& avatar_name, void* user_data) |
100 | { | 100 | { |
101 | LLSpeaker* speaker_ptr = ((LLHandle<LLSpeaker>*)user_data)->get(); | 101 | LLSpeaker* speaker_ptr = ((LLHandle<LLSpeaker>*)user_data)->get(); |
102 | delete (LLHandle<LLSpeaker>*)user_data; | 102 | delete (LLHandle<LLSpeaker>*)user_data; |
103 | 103 | ||
104 | if (speaker_ptr) | 104 | if (speaker_ptr) |
105 | { | 105 | { |
106 | speaker_ptr->mDisplayName = first + " " + last; | 106 | // Always show "Display Name [Legacy Name]" for security reasons |
107 | speaker_ptr->mDisplayName = avatar_name.getNames(); | ||
107 | // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-1.0.0g | 108 | // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-1.0.0g |
108 | // TODO-RLVa: this seems to get called per frame which is very likely an LL bug that will eventuall get fixed | 109 | // TODO-RLVa: this seems to get called per frame which is very likely an LL bug that will eventuall get fixed |
109 | if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) | 110 | if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) |
diff --git a/linden/indra/newview/llfloateractivespeakers.h b/linden/indra/newview/llfloateractivespeakers.h index b2c44e2..dc3dd73 100644 --- a/linden/indra/newview/llfloateractivespeakers.h +++ b/linden/indra/newview/llfloateractivespeakers.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #ifndef LL_LLFLOATERACTIVESPEAKERS_H | 33 | #ifndef LL_LLFLOATERACTIVESPEAKERS_H |
34 | #define LL_LLFLOATERACTIVESPEAKERS_H | 34 | #define LL_LLFLOATERACTIVESPEAKERS_H |
35 | 35 | ||
36 | #include "llavatarnamecache.h" | ||
36 | #include "llfloater.h" | 37 | #include "llfloater.h" |
37 | #include "llmemory.h" | 38 | #include "llmemory.h" |
38 | #include "llvoiceclient.h" | 39 | #include "llvoiceclient.h" |
@@ -73,7 +74,7 @@ public: | |||
73 | ~LLSpeaker() {}; | 74 | ~LLSpeaker() {}; |
74 | void lookupName(); | 75 | void lookupName(); |
75 | 76 | ||
76 | static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* user_data); | 77 | static void onAvatarNameLookup(const LLUUID& id, const LLAvatarName& avatar_name, void* user_data); |
77 | 78 | ||
78 | ESpeakerStatus mStatus; // current activity status in speech group | 79 | ESpeakerStatus mStatus; // current activity status in speech group |
79 | F32 mLastSpokeTime; // timestamp when this speaker last spoke | 80 | F32 mLastSpokeTime; // timestamp when this speaker last spoke |
diff --git a/linden/indra/newview/llfloateravatarinfo.cpp b/linden/indra/newview/llfloateravatarinfo.cpp index 0618875..13805fb 100644 --- a/linden/indra/newview/llfloateravatarinfo.cpp +++ b/linden/indra/newview/llfloateravatarinfo.cpp | |||
@@ -122,7 +122,7 @@ LLFloaterAvatarInfo::LLFloaterAvatarInfo(const std::string& name, const LLRect & | |||
122 | } | 122 | } |
123 | 123 | ||
124 | gAvatarInfoInstances.addData(avatar_id, this); // must be done before callback below is called. | 124 | gAvatarInfoInstances.addData(avatar_id, this); // must be done before callback below is called. |
125 | gCacheName->get(avatar_id, FALSE, callbackLoadAvatarName); | 125 | LLAvatarNameCache::get(avatar_id, boost::bind(&LLFloaterAvatarInfo::callbackLoadAvatarName, _1, _2)); |
126 | } | 126 | } |
127 | 127 | ||
128 | // virtual | 128 | // virtual |
@@ -242,18 +242,16 @@ void LLFloaterAvatarInfo::showProfileCallback(S32 option, void *userdata) | |||
242 | 242 | ||
243 | // static | 243 | // static |
244 | void LLFloaterAvatarInfo::callbackLoadAvatarName(const LLUUID& id, | 244 | void LLFloaterAvatarInfo::callbackLoadAvatarName(const LLUUID& id, |
245 | const std::string& first, | 245 | const LLAvatarName& avatar_name) |
246 | const std::string& last, | ||
247 | BOOL is_group, | ||
248 | void* data) | ||
249 | { | 246 | { |
250 | LLFloaterAvatarInfo *floater = gAvatarInfoInstances.getIfThere(id); | 247 | LLFloaterAvatarInfo *floater = gAvatarInfoInstances.getIfThere(id); |
251 | 248 | ||
252 | if (floater) | 249 | if (floater) |
253 | { | 250 | { |
254 | // Build a new title including the avatar name. | 251 | // Build a new title including the avatar name. |
252 | // Always show "Display Name [Legacy Name]" for security reasons | ||
255 | std::ostringstream title; | 253 | std::ostringstream title; |
256 | title << first << " " << last << " - " << floater->getTitle(); | 254 | title << avatar_name.getNames() << " - " << floater->getTitle(); |
257 | floater->setTitle(title.str()); | 255 | floater->setTitle(title.str()); |
258 | } | 256 | } |
259 | } | 257 | } |
diff --git a/linden/indra/newview/llfloateravatarinfo.h b/linden/indra/newview/llfloateravatarinfo.h index 1cc17d1..f65e1f4 100644 --- a/linden/indra/newview/llfloateravatarinfo.h +++ b/linden/indra/newview/llfloateravatarinfo.h | |||
@@ -39,6 +39,7 @@ | |||
39 | #ifndef LL_LLFLOATERAVATARINFO_H | 39 | #ifndef LL_LLFLOATERAVATARINFO_H |
40 | #define LL_LLFLOATERAVATARINFO_H | 40 | #define LL_LLFLOATERAVATARINFO_H |
41 | 41 | ||
42 | #include "llavatarnamecache.h" | ||
42 | #include "llfloater.h" | 43 | #include "llfloater.h" |
43 | #include "llpreview.h" | 44 | #include "llpreview.h" |
44 | #include "lluuid.h" | 45 | #include "lluuid.h" |
@@ -91,8 +92,7 @@ public: | |||
91 | 92 | ||
92 | static LLFloaterAvatarInfo* getInstance(const LLUUID &id); | 93 | static LLFloaterAvatarInfo* getInstance(const LLUUID &id); |
93 | static void showProfileCallback(S32 option, void *userdata); | 94 | static void showProfileCallback(S32 option, void *userdata); |
94 | static void callbackLoadAvatarName(const LLUUID& id, | 95 | static void callbackLoadAvatarName(const LLUUID& agent_id, const LLAvatarName& avatar_name); |
95 | const std::string& first, const std::string& last, BOOL is_group, void* data); | ||
96 | void resetGroupList(); | 96 | void resetGroupList(); |
97 | 97 | ||
98 | private: | 98 | private: |
diff --git a/linden/indra/newview/llfloaterchatterbox.cpp b/linden/indra/newview/llfloaterchatterbox.cpp index 1ef75d1..ba1c83c 100644 --- a/linden/indra/newview/llfloaterchatterbox.cpp +++ b/linden/indra/newview/llfloaterchatterbox.cpp | |||
@@ -43,6 +43,7 @@ | |||
43 | #include "llviewercontrol.h" | 43 | #include "llviewercontrol.h" |
44 | #include "llimview.h" | 44 | #include "llimview.h" |
45 | #include "llimpanel.h" | 45 | #include "llimpanel.h" |
46 | #include "llcallingcard.h" | ||
46 | 47 | ||
47 | // | 48 | // |
48 | // LLFloaterMyFriends | 49 | // LLFloaterMyFriends |
@@ -218,6 +219,8 @@ void LLFloaterChatterBox::draw() | |||
218 | void LLFloaterChatterBox::onOpen() | 219 | void LLFloaterChatterBox::onOpen() |
219 | { | 220 | { |
220 | gSavedSettings.setBOOL("ShowCommunicate", TRUE); | 221 | gSavedSettings.setBOOL("ShowCommunicate", TRUE); |
222 | // Force a refresh to get latest display names in the new IM panel. | ||
223 | LLAvatarTracker::instance().dirtyBuddies(); | ||
221 | } | 224 | } |
222 | 225 | ||
223 | void LLFloaterChatterBox::onClose(bool app_quitting) | 226 | void LLFloaterChatterBox::onClose(bool app_quitting) |
diff --git a/linden/indra/newview/llfloaterdisplayname.cpp b/linden/indra/newview/llfloaterdisplayname.cpp new file mode 100644 index 0000000..31ceda9 --- /dev/null +++ b/linden/indra/newview/llfloaterdisplayname.cpp | |||
@@ -0,0 +1,224 @@ | |||
1 | /** | ||
2 | * @file llfloaterdisplayname.cpp | ||
3 | * @author Leyla Farazha | ||
4 | * @brief Implementation of the LLFloaterDisplayName class. | ||
5 | * | ||
6 | * $LicenseInfo:firstyear=2002&license=viewerlgpl$ | ||
7 | * Second Life Viewer Source Code | ||
8 | * Copyright (C) 2010, Linden Research, Inc. | ||
9 | * | ||
10 | * This library is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU Lesser General Public | ||
12 | * License as published by the Free Software Foundation; | ||
13 | * version 2.1 of the License only. | ||
14 | * | ||
15 | * This library is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * Lesser General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU Lesser General Public | ||
21 | * License along with this library; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
23 | * | ||
24 | * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA | ||
25 | * $/LicenseInfo$ | ||
26 | */ | ||
27 | |||
28 | |||
29 | #include "llviewerprecompiledheaders.h" | ||
30 | #include "llfloater.h" | ||
31 | |||
32 | #include "llnotifications.h" | ||
33 | #include "llviewerdisplayname.h" | ||
34 | |||
35 | #include "llnotify.h" | ||
36 | #include "llfloaterdisplayname.h" | ||
37 | #include "llavatarnamecache.h" | ||
38 | #include "lluictrlfactory.h" | ||
39 | #include "llviewercontrol.h" | ||
40 | |||
41 | #include "llagent.h" | ||
42 | |||
43 | |||
44 | LLFloaterDisplayName* LLFloaterDisplayName::sInstance = NULL; | ||
45 | |||
46 | LLFloaterDisplayName::LLFloaterDisplayName() : LLFloater(std::string("Display Name")) | ||
47 | { | ||
48 | LLUICtrlFactory::getInstance()->buildFloater(this, "floater_display_name.xml"); | ||
49 | LLFloaterDisplayName::sInstance = this; | ||
50 | } | ||
51 | |||
52 | LLFloaterDisplayName::~LLFloaterDisplayName() | ||
53 | { | ||
54 | LLFloaterDisplayName::sInstance = NULL; | ||
55 | } | ||
56 | |||
57 | void LLFloaterDisplayName::show() | ||
58 | { | ||
59 | if (!LLFloaterDisplayName::sInstance) | ||
60 | { | ||
61 | LLFloaterDisplayName::sInstance = new LLFloaterDisplayName(); | ||
62 | } | ||
63 | LLFloaterDisplayName::sInstance->open(); | ||
64 | } | ||
65 | |||
66 | void LLFloaterDisplayName::onOpen() | ||
67 | { | ||
68 | getChild<LLUICtrl>("display_name_editor")->clear(); | ||
69 | getChild<LLUICtrl>("display_name_confirm")->clear(); | ||
70 | |||
71 | LLAvatarName av_name; | ||
72 | LLAvatarNameCache::get(gAgent.getID(), &av_name); | ||
73 | |||
74 | F64 now_secs = LLDate::now().secondsSinceEpoch(); | ||
75 | |||
76 | if (now_secs < av_name.mNextUpdate) | ||
77 | { | ||
78 | // ...can't update until some time in the future | ||
79 | F64 next_update_local_secs = av_name.mNextUpdate; | ||
80 | std::string next_update_string; | ||
81 | #ifdef LOCALIZED_TIME | ||
82 | timeToFormattedString((time_t)next_update_local_secs, | ||
83 | gSavedSettings.getString("LongDateFormat"), | ||
84 | next_update_string); | ||
85 | #else | ||
86 | LLDate next_update_local(next_update_local_secs); | ||
87 | next_update_string = next_update_local.asString(); | ||
88 | #endif | ||
89 | getChild<LLUICtrl>("lockout_text")->setTextArg("[TIME]", next_update_string); | ||
90 | getChild<LLUICtrl>("lockout_text")->setVisible(true); | ||
91 | getChild<LLUICtrl>("now_ok_text")->setVisible(false); | ||
92 | getChild<LLUICtrl>("save_btn")->setEnabled(false); | ||
93 | getChild<LLUICtrl>("display_name_editor")->setEnabled(false); | ||
94 | getChild<LLUICtrl>("display_name_confirm")->setEnabled(false); | ||
95 | getChild<LLUICtrl>("cancel_btn")->setFocus(TRUE); | ||
96 | |||
97 | } | ||
98 | else | ||
99 | { | ||
100 | getChild<LLUICtrl>("lockout_text")->setVisible(false); | ||
101 | getChild<LLUICtrl>("now_ok_text")->setVisible(true); | ||
102 | getChild<LLUICtrl>("save_btn")->setEnabled(true); | ||
103 | getChild<LLUICtrl>("display_name_editor")->setEnabled(true); | ||
104 | getChild<LLUICtrl>("display_name_confirm")->setEnabled(true); | ||
105 | |||
106 | } | ||
107 | } | ||
108 | |||
109 | BOOL LLFloaterDisplayName::postBuild() | ||
110 | { | ||
111 | childSetAction("reset_btn", onReset, this); | ||
112 | childSetAction("cancel_btn", onCancel, this); | ||
113 | childSetAction("save_btn", onSave, this); | ||
114 | |||
115 | center(); | ||
116 | |||
117 | return TRUE; | ||
118 | } | ||
119 | |||
120 | void LLFloaterDisplayName::onCacheSetName(bool success, | ||
121 | const std::string& reason, | ||
122 | const LLSD& content) | ||
123 | { | ||
124 | if (success) | ||
125 | { | ||
126 | // Inform the user that the change took place, but will take a while | ||
127 | // to percolate. | ||
128 | LLSD args; | ||
129 | args["DISPLAY_NAME"] = content["display_name"]; | ||
130 | LLNotifications::instance().add("SetDisplayNameSuccess", args); | ||
131 | |||
132 | // Re-fetch my name, as it may have been sanitized by the service | ||
133 | //LLAvatarNameCache::get(getAvatarId(), | ||
134 | // boost::bind(&LLPanelMyProfileEdit::onNameCache, this, _1, _2)); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | // Request failed, notify the user | ||
139 | std::string error_tag = content["error_tag"].asString(); | ||
140 | llinfos << "set name failure error_tag " << error_tag << llendl; | ||
141 | |||
142 | // We might have a localized string for this message | ||
143 | // error_args will usually be empty from the server. | ||
144 | if (!error_tag.empty() | ||
145 | && LLNotifications::getInstance()->templateExists(error_tag)) | ||
146 | { | ||
147 | LLNotifications::instance().add(error_tag); | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | // The server error might have a localized message for us | ||
152 | std::string lang_code = LLUI::getLanguage(); | ||
153 | LLSD error_desc = content["error_description"]; | ||
154 | if (error_desc.has( lang_code )) | ||
155 | { | ||
156 | LLSD args; | ||
157 | args["MESSAGE"] = error_desc[lang_code].asString(); | ||
158 | LLNotifications::instance().add("GenericAlert", args); | ||
159 | return; | ||
160 | } | ||
161 | |||
162 | // No specific error, throw a generic one | ||
163 | LLNotifications::instance().add("SetDisplayNameFailedGeneric"); | ||
164 | } | ||
165 | |||
166 | void LLFloaterDisplayName::onCancel(void* data) | ||
167 | { | ||
168 | LLFloaterDisplayName* self = (LLFloaterDisplayName*)data; | ||
169 | self->setVisible(false); | ||
170 | } | ||
171 | |||
172 | void LLFloaterDisplayName::onReset(void* data) | ||
173 | { | ||
174 | LLFloaterDisplayName* self = (LLFloaterDisplayName*)data; | ||
175 | |||
176 | if (LLAvatarNameCache::useDisplayNames()) | ||
177 | { | ||
178 | LLViewerDisplayName::set("", | ||
179 | boost::bind(&LLFloaterDisplayName::onCacheSetName, self, _1, _2, _3)); | ||
180 | } | ||
181 | else | ||
182 | { | ||
183 | LLNotifications::instance().add("SetDisplayNameFailedGeneric"); | ||
184 | } | ||
185 | |||
186 | self->setVisible(false); | ||
187 | } | ||
188 | |||
189 | |||
190 | void LLFloaterDisplayName::onSave(void* data) | ||
191 | { | ||
192 | LLFloaterDisplayName* self = (LLFloaterDisplayName*)data; | ||
193 | |||
194 | std::string display_name_utf8 = self->getChild<LLUICtrl>("display_name_editor")->getValue().asString(); | ||
195 | std::string display_name_confirm = self->getChild<LLUICtrl>("display_name_confirm")->getValue().asString(); | ||
196 | |||
197 | if (display_name_utf8.compare(display_name_confirm)) | ||
198 | { | ||
199 | LLNotifications::instance().add("SetDisplayNameMismatch"); | ||
200 | return; | ||
201 | } | ||
202 | |||
203 | const U32 DISPLAY_NAME_MAX_LENGTH = 31; // characters, not bytes | ||
204 | LLWString display_name_wstr = utf8string_to_wstring(display_name_utf8); | ||
205 | if (display_name_wstr.size() > DISPLAY_NAME_MAX_LENGTH) | ||
206 | { | ||
207 | LLSD args; | ||
208 | args["LENGTH"] = llformat("%d", DISPLAY_NAME_MAX_LENGTH); | ||
209 | LLNotifications::instance().add("SetDisplayNameFailedLength", args); | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | if (LLAvatarNameCache::useDisplayNames()) | ||
214 | { | ||
215 | LLViewerDisplayName::set(display_name_utf8, | ||
216 | boost::bind(&LLFloaterDisplayName::onCacheSetName, self, _1, _2, _3)); | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | LLNotifications::instance().add("SetDisplayNameFailedGeneric"); | ||
221 | } | ||
222 | |||
223 | self->setVisible(false); | ||
224 | } | ||
diff --git a/linden/indra/newview/llfloaterdisplayname.h b/linden/indra/newview/llfloaterdisplayname.h new file mode 100644 index 0000000..4b25670 --- /dev/null +++ b/linden/indra/newview/llfloaterdisplayname.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /** | ||
2 | * @file llfloaterdisplayname.h | ||
3 | * | ||
4 | * $LicenseInfo:firstyear=2009&license=viewerlgpl$ | ||
5 | * Second Life Viewer Source Code | ||
6 | * Copyright (C) 2010, Linden Research, Inc. | ||
7 | * | ||
8 | * This library is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU Lesser General Public | ||
10 | * License as published by the Free Software Foundation; | ||
11 | * version 2.1 of the License only. | ||
12 | * | ||
13 | * This library is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * Lesser General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU Lesser General Public | ||
19 | * License along with this library; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | * | ||
22 | * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA | ||
23 | * $/LicenseInfo$ | ||
24 | */ | ||
25 | |||
26 | #ifndef LLFLOATERDISPLAYNAME_H | ||
27 | #define LLFLOATERDISPLAYNAME_H | ||
28 | |||
29 | |||
30 | class LLFloaterDisplayName : public LLFloater | ||
31 | { | ||
32 | public: | ||
33 | LLFloaterDisplayName(); | ||
34 | virtual ~LLFloaterDisplayName(); | ||
35 | /* virtual */ BOOL postBuild(); | ||
36 | /* virtual */ void onOpen(); | ||
37 | static void show(); | ||
38 | static void onSave(void* data); | ||
39 | static void onReset(void* data); | ||
40 | static void onCancel(void* data); | ||
41 | |||
42 | private: | ||
43 | static LLFloaterDisplayName* sInstance; | ||
44 | void onCacheSetName(bool success, const std::string& reason, const LLSD& content); | ||
45 | }; | ||
46 | |||
47 | |||
48 | #endif | ||
diff --git a/linden/indra/newview/llfloaterfriends.cpp b/linden/indra/newview/llfloaterfriends.cpp index c33deae..d3fd9b9 100644 --- a/linden/indra/newview/llfloaterfriends.cpp +++ b/linden/indra/newview/llfloaterfriends.cpp | |||
@@ -39,6 +39,7 @@ | |||
39 | 39 | ||
40 | #include <sstream> | 40 | #include <sstream> |
41 | 41 | ||
42 | #include "llavatarnamecache.h" | ||
42 | #include "lldir.h" | 43 | #include "lldir.h" |
43 | 44 | ||
44 | #include "llagent.h" | 45 | #include "llagent.h" |
@@ -254,6 +255,24 @@ BOOL LLPanelFriends::addFriend(const LLUUID& agent_id) | |||
254 | 255 | ||
255 | std::string fullname; | 256 | std::string fullname; |
256 | BOOL have_name = gCacheName->getFullName(agent_id, fullname); | 257 | BOOL have_name = gCacheName->getFullName(agent_id, fullname); |
258 | if (have_name) | ||
259 | { | ||
260 | if (LLAvatarNameCache::useDisplayNames() && !gSavedSettings.getBOOL("LegacyNamesForFriends")) | ||
261 | { | ||
262 | LLAvatarName avatar_name; | ||
263 | if (LLAvatarNameCache::get(agent_id, &avatar_name)) | ||
264 | { | ||
265 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
266 | { | ||
267 | fullname = avatar_name.mDisplayName; | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | fullname = avatar_name.getNames(); | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | } | ||
257 | 276 | ||
258 | LLSD element; | 277 | LLSD element; |
259 | element["id"] = agent_id; | 278 | element["id"] = agent_id; |
@@ -332,6 +351,24 @@ BOOL LLPanelFriends::updateFriendItem(const LLUUID& agent_id, const LLRelationsh | |||
332 | 351 | ||
333 | std::string fullname; | 352 | std::string fullname; |
334 | BOOL have_name = gCacheName->getFullName(agent_id, fullname); | 353 | BOOL have_name = gCacheName->getFullName(agent_id, fullname); |
354 | if (have_name) | ||
355 | { | ||
356 | if (LLAvatarNameCache::useDisplayNames() && !gSavedSettings.getBOOL("LegacyNamesForFriends")) | ||
357 | { | ||
358 | LLAvatarName avatar_name; | ||
359 | if (LLAvatarNameCache::get(agent_id, &avatar_name)) | ||
360 | { | ||
361 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
362 | { | ||
363 | fullname = avatar_name.mDisplayName; | ||
364 | } | ||
365 | else | ||
366 | { | ||
367 | fullname = avatar_name.getNames(); | ||
368 | } | ||
369 | } | ||
370 | } | ||
371 | } | ||
335 | 372 | ||
336 | // Name of the status icon to use | 373 | // Name of the status icon to use |
337 | std::string statusIcon; | 374 | std::string statusIcon; |
@@ -790,6 +827,25 @@ void LLPanelFriends::onClickRemove(void* user_data) | |||
790 | std::string first, last; | 827 | std::string first, last; |
791 | if(gCacheName->getName(agent_id, first, last)) | 828 | if(gCacheName->getName(agent_id, first, last)) |
792 | { | 829 | { |
830 | if (LLAvatarNameCache::useDisplayNames() && !gSavedSettings.getBOOL("LegacyNamesForFriends")) | ||
831 | { | ||
832 | LLAvatarName avatar_name; | ||
833 | if (LLAvatarNameCache::get(agent_id, &avatar_name)) | ||
834 | { | ||
835 | // Always show "Display Name [Legacy Name]" for security reasons | ||
836 | first = avatar_name.getNames(); | ||
837 | size_t i = first.find(" "); | ||
838 | if (i != std::string::npos) | ||
839 | { | ||
840 | last = first.substr(i + 1); | ||
841 | first = first.substr(0, i); | ||
842 | } | ||
843 | else | ||
844 | { | ||
845 | last = ""; | ||
846 | } | ||
847 | } | ||
848 | } | ||
793 | args["FIRST_NAME"] = first; | 849 | args["FIRST_NAME"] = first; |
794 | args["LAST_NAME"] = last; | 850 | args["LAST_NAME"] = last; |
795 | } | 851 | } |
@@ -854,6 +910,25 @@ void LLPanelFriends::confirmModifyRights(rights_map_t& ids, EGrantRevoke command | |||
854 | std::string first, last; | 910 | std::string first, last; |
855 | if(gCacheName->getName(agent_id, first, last)) | 911 | if(gCacheName->getName(agent_id, first, last)) |
856 | { | 912 | { |
913 | if (LLAvatarNameCache::useDisplayNames() && !gSavedSettings.getBOOL("LegacyNamesForFriends")) | ||
914 | { | ||
915 | LLAvatarName avatar_name; | ||
916 | if (LLAvatarNameCache::get(agent_id, &avatar_name)) | ||
917 | { | ||
918 | // Always show "Display Name [Legacy Name]" for security reasons | ||
919 | first = avatar_name.getNames(); | ||
920 | size_t i = first.find(" "); | ||
921 | if (i != std::string::npos) | ||
922 | { | ||
923 | last = first.substr(i + 1); | ||
924 | first = first.substr(0, i); | ||
925 | } | ||
926 | else | ||
927 | { | ||
928 | last = ""; | ||
929 | } | ||
930 | } | ||
931 | } | ||
857 | args["FIRST_NAME"] = first; | 932 | args["FIRST_NAME"] = first; |
858 | args["LAST_NAME"] = last; | 933 | args["LAST_NAME"] = last; |
859 | } | 934 | } |
diff --git a/linden/indra/newview/llfloaternewim.cpp b/linden/indra/newview/llfloaternewim.cpp index 48920c1..272cb53 100644 --- a/linden/indra/newview/llfloaternewim.cpp +++ b/linden/indra/newview/llfloaternewim.cpp | |||
@@ -38,10 +38,9 @@ | |||
38 | #include "lltabcontainer.h" | 38 | #include "lltabcontainer.h" |
39 | #include "llimview.h" | 39 | #include "llimview.h" |
40 | 40 | ||
41 | S32 COL_1_WIDTH = 200; | 41 | S32 COL_1_WIDTH = 400; |
42 | 42 | ||
43 | static std::string sOnlineDescriptor = "*"; | 43 | static std::string sOnlineDescriptor = "*"; |
44 | static std::string sNameFormat = "[FIRST] [LAST]"; | ||
45 | 44 | ||
46 | LLFloaterNewIM::LLFloaterNewIM() | 45 | LLFloaterNewIM::LLFloaterNewIM() |
47 | { | 46 | { |
@@ -69,7 +68,6 @@ BOOL LLFloaterNewIM::postBuild() | |||
69 | llwarns << "LLUICtrlFactory::getNameListByName() returned NULL for 'user_list'" << llendl; | 68 | llwarns << "LLUICtrlFactory::getNameListByName() returned NULL for 'user_list'" << llendl; |
70 | } | 69 | } |
71 | sOnlineDescriptor = getString("online_descriptor"); | 70 | sOnlineDescriptor = getString("online_descriptor"); |
72 | sNameFormat = getString("name_format"); | ||
73 | setDefaultBtn("start_btn"); | 71 | setDefaultBtn("start_btn"); |
74 | return TRUE; | 72 | return TRUE; |
75 | } | 73 | } |
@@ -135,11 +133,8 @@ void LLFloaterNewIM::addGroup(const LLUUID& uuid, void* data, BOOL bold, BOOL on | |||
135 | 133 | ||
136 | void LLFloaterNewIM::addAgent(const LLUUID& uuid, void* data, BOOL online) | 134 | void LLFloaterNewIM::addAgent(const LLUUID& uuid, void* data, BOOL online) |
137 | { | 135 | { |
138 | std::string first, last; | 136 | std::string fullname; |
139 | gCacheName->getName(uuid, first, last); | 137 | gCacheName->getFullName(uuid, fullname); |
140 | LLUIString fullname = sNameFormat; | ||
141 | fullname.setArg("[FIRST]", first); | ||
142 | fullname.setArg("[LAST]", last); | ||
143 | 138 | ||
144 | LLSD row; | 139 | LLSD row; |
145 | row["id"] = uuid; | 140 | row["id"] = uuid; |
@@ -184,13 +179,20 @@ void LLFloaterNewIM::onStart(void* userdata) | |||
184 | const LLScrollListCell* cell = item->getColumn(0); | 179 | const LLScrollListCell* cell = item->getColumn(0); |
185 | std::string name(cell->getValue()); | 180 | std::string name(cell->getValue()); |
186 | 181 | ||
187 | // *NOTE: Do a live detrmination of what type of session it | 182 | // *NOTE: Do a live determination of what type of session it |
188 | // should be. If we restrict the new im panel to online users, | 183 | // should be. If we restrict the new im panel to online users, |
189 | // then we can remove some of this code. | 184 | // then we can remove some of this code. |
190 | EInstantMessage type; | 185 | EInstantMessage type; |
191 | EInstantMessage* t = (EInstantMessage*)item->getUserdata(); | 186 | EInstantMessage* t = (EInstantMessage*)item->getUserdata(); |
192 | if(t) type = (*t); | 187 | if(t) type = (*t); |
193 | else type = LLIMMgr::defaultIMTypeForAgent(item->getUUID()); | 188 | else type = LLIMMgr::defaultIMTypeForAgent(item->getUUID()); |
189 | if (type != IM_SESSION_GROUP_START) | ||
190 | { | ||
191 | // Needed to avoid catching a display name, which would | ||
192 | // make us use a wrong IM log file... | ||
193 | gCacheName->getFullName(item->getUUID(), name); | ||
194 | } | ||
195 | |||
194 | gIMMgr->addSession(name, type, item->getUUID()); | 196 | gIMMgr->addSession(name, type, item->getUUID()); |
195 | 197 | ||
196 | make_ui_sound("UISndStartIM"); | 198 | make_ui_sound("UISndStartIM"); |
diff --git a/linden/indra/newview/llhoverview.cpp b/linden/indra/newview/llhoverview.cpp index 10d27cd..e8d8428 100644 --- a/linden/indra/newview/llhoverview.cpp +++ b/linden/indra/newview/llhoverview.cpp | |||
@@ -253,10 +253,29 @@ void LLHoverView::updateText() | |||
253 | LLNameValue* lastname = hit_object->getNVPair("LastName"); | 253 | LLNameValue* lastname = hit_object->getNVPair("LastName"); |
254 | if (firstname && lastname) | 254 | if (firstname && lastname) |
255 | { | 255 | { |
256 | std::string complete_name = firstname->getString(); | ||
257 | complete_name += " "; | ||
258 | complete_name += lastname->getString(); | ||
259 | |||
260 | if (LLAvatarNameCache::useDisplayNames()) | ||
261 | { | ||
262 | LLAvatarName avatar_name; | ||
263 | if (LLAvatarNameCache::get(hit_object->getID(), &avatar_name)) | ||
264 | { | ||
265 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
266 | { | ||
267 | complete_name = avatar_name.mDisplayName; | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | complete_name = avatar_name.getNames(); | ||
272 | } | ||
273 | } | ||
274 | } | ||
256 | // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | 275 | // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) |
257 | if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) | 276 | if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) |
258 | { | 277 | { |
259 | line = RlvStrings::getAnonym(line.append(firstname->getString()).append(1, ' ').append(lastname->getString())); | 278 | line = RlvStrings::getAnonym(complete_name); |
260 | } | 279 | } |
261 | else | 280 | else |
262 | { | 281 | { |
diff --git a/linden/indra/newview/llimpanel.cpp b/linden/indra/newview/llimpanel.cpp index 41727f2..54e9bab 100644 --- a/linden/indra/newview/llimpanel.cpp +++ b/linden/indra/newview/llimpanel.cpp | |||
@@ -106,6 +106,8 @@ LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; | |||
106 | 106 | ||
107 | BOOL LLVoiceChannel::sSuspended = FALSE; | 107 | BOOL LLVoiceChannel::sSuspended = FALSE; |
108 | 108 | ||
109 | std::set<LLFloaterIMPanel*> LLFloaterIMPanel::sFloaterIMPanels; | ||
110 | |||
109 | void session_starter_helper( | 111 | void session_starter_helper( |
110 | const LLUUID& temp_session_id, | 112 | const LLUUID& temp_session_id, |
111 | const LLUUID& other_participant_id, | 113 | const LLUUID& other_participant_id, |
@@ -1108,6 +1110,7 @@ LLFloaterIMPanel::LLFloaterIMPanel( | |||
1108 | mFirstKeystrokeTimer(), | 1110 | mFirstKeystrokeTimer(), |
1109 | mLastKeystrokeTimer() | 1111 | mLastKeystrokeTimer() |
1110 | { | 1112 | { |
1113 | sFloaterIMPanels.insert(this); | ||
1111 | init(session_label); | 1114 | init(session_label); |
1112 | } | 1115 | } |
1113 | 1116 | ||
@@ -1149,6 +1152,7 @@ LLFloaterIMPanel::LLFloaterIMPanel( | |||
1149 | void LLFloaterIMPanel::init(const std::string& session_label) | 1152 | void LLFloaterIMPanel::init(const std::string& session_label) |
1150 | { | 1153 | { |
1151 | mSessionLabel = session_label; | 1154 | mSessionLabel = session_label; |
1155 | mProfileButtonEnabled = FALSE; | ||
1152 | 1156 | ||
1153 | std::string xml_filename; | 1157 | std::string xml_filename; |
1154 | switch(mDialog) | 1158 | switch(mDialog) |
@@ -1211,6 +1215,10 @@ void LLFloaterIMPanel::init(const std::string& session_label) | |||
1211 | FALSE); | 1215 | FALSE); |
1212 | 1216 | ||
1213 | setTitle(mSessionLabel); | 1217 | setTitle(mSessionLabel); |
1218 | if (mProfileButtonEnabled) | ||
1219 | { | ||
1220 | lookupName(); | ||
1221 | } | ||
1214 | 1222 | ||
1215 | mInputEditor->setMaxTextLength(DB_IM_MSG_STR_LEN); | 1223 | mInputEditor->setMaxTextLength(DB_IM_MSG_STR_LEN); |
1216 | // enable line history support for instant message bar | 1224 | // enable line history support for instant message bar |
@@ -1253,9 +1261,32 @@ void LLFloaterIMPanel::init(const std::string& session_label) | |||
1253 | } | 1261 | } |
1254 | } | 1262 | } |
1255 | 1263 | ||
1264 | void LLFloaterIMPanel::lookupName() | ||
1265 | { | ||
1266 | LLAvatarNameCache::get(mOtherParticipantUUID, boost::bind(&LLFloaterIMPanel::onAvatarNameLookup, _1, _2, this)); | ||
1267 | } | ||
1268 | |||
1269 | //static | ||
1270 | void LLFloaterIMPanel::onAvatarNameLookup(const LLUUID& id, const LLAvatarName& avatar_name, void* user_data) | ||
1271 | { | ||
1272 | LLFloaterIMPanel* self = (LLFloaterIMPanel*)user_data; | ||
1273 | |||
1274 | if (self && sFloaterIMPanels.count(self) != 0) | ||
1275 | { | ||
1276 | // Always show "Display Name [Legacy Name]" for security reasons | ||
1277 | std::string title = avatar_name.getNames(); | ||
1278 | if (!title.empty()) | ||
1279 | { | ||
1280 | self->setTitle(title); | ||
1281 | } | ||
1282 | } | ||
1283 | } | ||
1284 | |||
1256 | 1285 | ||
1257 | LLFloaterIMPanel::~LLFloaterIMPanel() | 1286 | LLFloaterIMPanel::~LLFloaterIMPanel() |
1258 | { | 1287 | { |
1288 | sFloaterIMPanels.erase(this); | ||
1289 | |||
1259 | delete mSpeakers; | 1290 | delete mSpeakers; |
1260 | mSpeakers = NULL; | 1291 | mSpeakers = NULL; |
1261 | 1292 | ||
@@ -1550,8 +1581,9 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids) | |||
1550 | return TRUE; | 1581 | return TRUE; |
1551 | } | 1582 | } |
1552 | 1583 | ||
1553 | void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4& color, bool log_to_file, const LLUUID& source, const std::string& name) | 1584 | void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4& color, bool log_to_file, const LLUUID& source, const std::string& const_name) |
1554 | { | 1585 | { |
1586 | std::string name = const_name; | ||
1555 | // start tab flashing when receiving im for background session from user | 1587 | // start tab flashing when receiving im for background session from user |
1556 | if (source != LLUUID::null) | 1588 | if (source != LLUUID::null) |
1557 | { | 1589 | { |
@@ -1602,6 +1634,21 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4 | |||
1602 | } | 1634 | } |
1603 | else | 1635 | else |
1604 | { | 1636 | { |
1637 | if (LLAvatarNameCache::useDisplayNames() && source != LLUUID::null) | ||
1638 | { | ||
1639 | LLAvatarName avatar_name; | ||
1640 | if (LLAvatarNameCache::get(source, &avatar_name)) | ||
1641 | { | ||
1642 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
1643 | { | ||
1644 | name = avatar_name.mDisplayName; | ||
1645 | } | ||
1646 | else | ||
1647 | { | ||
1648 | name = avatar_name.getNames(); | ||
1649 | } | ||
1650 | } | ||
1651 | } | ||
1605 | // Convert the name to a hotlink and add to message. | 1652 | // Convert the name to a hotlink and add to message. |
1606 | const LLStyleSP &source_style = LLStyleMap::instance().lookupAgent(source); | 1653 | const LLStyleSP &source_style = LLStyleMap::instance().lookupAgent(source); |
1607 | mHistoryEditor->appendStyledText(name,false,prepend_newline,source_style); | 1654 | mHistoryEditor->appendStyledText(name,false,prepend_newline,source_style); |
@@ -1619,7 +1666,7 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4 | |||
1619 | else | 1666 | else |
1620 | histstr = name + utf8msg; | 1667 | histstr = name + utf8msg; |
1621 | 1668 | ||
1622 | LLLogChat::saveHistory(getTitle(),histstr); | 1669 | LLLogChat::saveHistory(mSessionLabel, histstr); |
1623 | } | 1670 | } |
1624 | 1671 | ||
1625 | if (!isInVisibleChain()) | 1672 | if (!isInVisibleChain()) |
@@ -2168,6 +2215,21 @@ void LLFloaterIMPanel::sendMsg() | |||
2168 | { | 2215 | { |
2169 | std::string history_echo; | 2216 | std::string history_echo; |
2170 | gAgent.buildFullname(history_echo); | 2217 | gAgent.buildFullname(history_echo); |
2218 | if (LLAvatarNameCache::useDisplayNames()) | ||
2219 | { | ||
2220 | LLAvatarName avatar_name; | ||
2221 | if (LLAvatarNameCache::get(gAgent.getID(), &avatar_name)) | ||
2222 | { | ||
2223 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
2224 | { | ||
2225 | history_echo = avatar_name.mDisplayName; | ||
2226 | } | ||
2227 | else | ||
2228 | { | ||
2229 | history_echo = avatar_name.getNames(); | ||
2230 | } | ||
2231 | } | ||
2232 | } | ||
2171 | 2233 | ||
2172 | // Look for IRC-style emotes here. | 2234 | // Look for IRC-style emotes here. |
2173 | std::string prefix = utf8_text.substr(0, 4); | 2235 | std::string prefix = utf8_text.substr(0, 4); |
diff --git a/linden/indra/newview/llimpanel.h b/linden/indra/newview/llimpanel.h index ddcbdc7..b5a0165 100644 --- a/linden/indra/newview/llimpanel.h +++ b/linden/indra/newview/llimpanel.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #ifndef LL_IMPANEL_H | 33 | #ifndef LL_IMPANEL_H |
34 | #define LL_IMPANEL_H | 34 | #define LL_IMPANEL_H |
35 | 35 | ||
36 | #include "llavatarnamecache.h" | ||
36 | #include "llfloater.h" | 37 | #include "llfloater.h" |
37 | #include "lllogchat.h" | 38 | #include "lllogchat.h" |
38 | #include "lluuid.h" | 39 | #include "lluuid.h" |
@@ -194,6 +195,9 @@ public: | |||
194 | EInstantMessage dialog); | 195 | EInstantMessage dialog); |
195 | virtual ~LLFloaterIMPanel(); | 196 | virtual ~LLFloaterIMPanel(); |
196 | 197 | ||
198 | void lookupName(); | ||
199 | static void onAvatarNameLookup(const LLUUID& id, const LLAvatarName& avatar_name, void* user_data); | ||
200 | |||
197 | /*virtual*/ BOOL postBuild(); | 201 | /*virtual*/ BOOL postBuild(); |
198 | 202 | ||
199 | // Check typing timeout timer. | 203 | // Check typing timeout timer. |
@@ -365,6 +369,8 @@ private: | |||
365 | typedef std::map<LLUUID, LLStyleSP> styleMap; | 369 | typedef std::map<LLUUID, LLStyleSP> styleMap; |
366 | static styleMap mStyleMap; | 370 | static styleMap mStyleMap; |
367 | 371 | ||
372 | static std::set<LLFloaterIMPanel*> sFloaterIMPanels; | ||
373 | |||
368 | typedef enum e_im_format | 374 | typedef enum e_im_format |
369 | { | 375 | { |
370 | IM_PANEL_PLAIN, | 376 | IM_PANEL_PLAIN, |
diff --git a/linden/indra/newview/llnamelistctrl.cpp b/linden/indra/newview/llnamelistctrl.cpp index e445df5..8b268c5 100644 --- a/linden/indra/newview/llnamelistctrl.cpp +++ b/linden/indra/newview/llnamelistctrl.cpp | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "llcachename.h" | 39 | #include "llcachename.h" |
40 | #include "llagent.h" | 40 | #include "llagent.h" |
41 | #include "llinventory.h" | 41 | #include "llinventory.h" |
42 | #include "llviewercontrol.h" | ||
42 | 43 | ||
43 | static LLRegisterWidget<LLNameListCtrl> r("name_list"); | 44 | static LLRegisterWidget<LLNameListCtrl> r("name_list"); |
44 | 45 | ||
@@ -56,7 +57,8 @@ LLNameListCtrl::LLNameListCtrl(const std::string& name, | |||
56 | : LLScrollListCtrl(name, rect, cb, userdata, allow_multiple_selection, | 57 | : LLScrollListCtrl(name, rect, cb, userdata, allow_multiple_selection, |
57 | draw_border), | 58 | draw_border), |
58 | mNameColumnIndex(name_column_index), | 59 | mNameColumnIndex(name_column_index), |
59 | mAllowCallingCardDrop(FALSE) | 60 | mAllowCallingCardDrop(FALSE), |
61 | mUseDisplayNames(FALSE) | ||
60 | { | 62 | { |
61 | setToolTip(tooltip); | 63 | setToolTip(tooltip); |
62 | LLNameListCtrl::sInstances.insert(this); | 64 | LLNameListCtrl::sInstances.insert(this); |
@@ -77,7 +79,7 @@ BOOL LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos, | |||
77 | //llinfos << "LLNameListCtrl::addNameItem " << agent_id << llendl; | 79 | //llinfos << "LLNameListCtrl::addNameItem " << agent_id << llendl; |
78 | 80 | ||
79 | std::string fullname; | 81 | std::string fullname; |
80 | BOOL result = gCacheName->getFullName(agent_id, fullname); | 82 | BOOL result = getResidentName(agent_id, fullname); |
81 | 83 | ||
82 | fullname.append(suffix); | 84 | fullname.append(suffix); |
83 | 85 | ||
@@ -164,7 +166,7 @@ BOOL LLNameListCtrl::addNameItem(LLScrollListItem* item, EAddPosition pos) | |||
164 | //llinfos << "LLNameListCtrl::addNameItem " << item->getUUID() << llendl; | 166 | //llinfos << "LLNameListCtrl::addNameItem " << item->getUUID() << llendl; |
165 | 167 | ||
166 | std::string fullname; | 168 | std::string fullname; |
167 | BOOL result = gCacheName->getFullName(item->getUUID(), fullname); | 169 | BOOL result = getResidentName(item->getUUID(), fullname); |
168 | 170 | ||
169 | LLScrollListCell* cell = (LLScrollListCell*)item->getColumn(mNameColumnIndex); | 171 | LLScrollListCell* cell = (LLScrollListCell*)item->getColumn(mNameColumnIndex); |
170 | ((LLScrollListText*)cell)->setText( fullname ); | 172 | ((LLScrollListText*)cell)->setText( fullname ); |
@@ -199,7 +201,7 @@ LLScrollListItem* LLNameListCtrl::addElement(const LLSD& value, EAddPosition pos | |||
199 | else // normal resident | 201 | else // normal resident |
200 | { | 202 | { |
201 | std::string name; | 203 | std::string name; |
202 | if (gCacheName->getFullName(item->getUUID(), name)) | 204 | if (getResidentName(item->getUUID(), name)) |
203 | { | 205 | { |
204 | fullname = name; | 206 | fullname = name; |
205 | } | 207 | } |
@@ -346,6 +348,12 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto | |||
346 | name_list->setAllowCallingCardDrop(allow_calling_card_drop); | 348 | name_list->setAllowCallingCardDrop(allow_calling_card_drop); |
347 | } | 349 | } |
348 | 350 | ||
351 | BOOL use_display_names; | ||
352 | if (node->getAttributeBOOL("use_display_names", use_display_names)) | ||
353 | { | ||
354 | name_list->setUseDisplayNames(use_display_names); | ||
355 | } | ||
356 | |||
349 | name_list->setScrollListParameters(node); | 357 | name_list->setScrollListParameters(node); |
350 | 358 | ||
351 | name_list->initFromXML(node, parent); | 359 | name_list->initFromXML(node, parent); |
@@ -456,5 +464,31 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto | |||
456 | return name_list; | 464 | return name_list; |
457 | } | 465 | } |
458 | 466 | ||
459 | 467 | bool LLNameListCtrl::getResidentName(const LLUUID& agent_id, std::string& fullname) | |
460 | 468 | { | |
469 | std::string name; | ||
470 | if (gCacheName->getFullName(agent_id, name)) | ||
471 | { | ||
472 | fullname = name; | ||
473 | if (mUseDisplayNames && LLAvatarNameCache::useDisplayNames() && !gSavedSettings.getBOOL("LegacyNamesForFriends")) | ||
474 | { | ||
475 | LLAvatarName avatar_name; | ||
476 | if (LLAvatarNameCache::get(agent_id, &avatar_name)) | ||
477 | { | ||
478 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
479 | { | ||
480 | fullname = avatar_name.mDisplayName; | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | fullname = avatar_name.getNames(); | ||
485 | } | ||
486 | } | ||
487 | } | ||
488 | return true; | ||
489 | } | ||
490 | else | ||
491 | { | ||
492 | return false; | ||
493 | } | ||
494 | } | ||
diff --git a/linden/indra/newview/llnamelistctrl.h b/linden/indra/newview/llnamelistctrl.h index beb4ede..d6cf578 100644 --- a/linden/indra/newview/llnamelistctrl.h +++ b/linden/indra/newview/llnamelistctrl.h | |||
@@ -84,7 +84,12 @@ public: | |||
84 | 84 | ||
85 | void setAllowCallingCardDrop(BOOL b) { mAllowCallingCardDrop = b; } | 85 | void setAllowCallingCardDrop(BOOL b) { mAllowCallingCardDrop = b; } |
86 | 86 | ||
87 | void setUseDisplayNames(BOOL b) { mUseDisplayNames = b; } | ||
88 | |||
87 | private: | 89 | private: |
90 | bool getResidentName(const LLUUID& agent_id, std::string& fullname); | ||
91 | BOOL mUseDisplayNames; | ||
92 | |||
88 | static std::set<LLNameListCtrl*> sInstances; | 93 | static std::set<LLNameListCtrl*> sInstances; |
89 | S32 mNameColumnIndex; | 94 | S32 mNameColumnIndex; |
90 | BOOL mAllowCallingCardDrop; | 95 | BOOL mAllowCallingCardDrop; |
diff --git a/linden/indra/newview/llnetmap.cpp b/linden/indra/newview/llnetmap.cpp index b9dc482..438478f 100644 --- a/linden/indra/newview/llnetmap.cpp +++ b/linden/indra/newview/llnetmap.cpp | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "llnetmap.h" | 36 | #include "llnetmap.h" |
37 | 37 | ||
38 | #include "indra_constants.h" | 38 | #include "indra_constants.h" |
39 | #include "llavatarnamecache.h" | ||
39 | #include "llui.h" | 40 | #include "llui.h" |
40 | #include "llmath.h" // clampf() | 41 | #include "llmath.h" // clampf() |
41 | #include "llfocusmgr.h" | 42 | #include "llfocusmgr.h" |
@@ -640,7 +641,29 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rec | |||
640 | { | 641 | { |
641 | msg.assign(""); | 642 | msg.assign(""); |
642 | std::string fullname; | 643 | std::string fullname; |
643 | if(mClosestAgentToCursor.notNull() && gCacheName->getFullName(mClosestAgentToCursor, fullname)) | 644 | BOOL result = FALSE; |
645 | if (!LLAvatarNameCache::useDisplayNames()) | ||
646 | { | ||
647 | result = gCacheName->getFullName(mClosestAgentToCursor, fullname); | ||
648 | } | ||
649 | else | ||
650 | { | ||
651 | LLAvatarName avatar_name; | ||
652 | if (LLAvatarNameCache::get(mClosestAgentToCursor, &avatar_name)) | ||
653 | { | ||
654 | result = TRUE; | ||
655 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
656 | { | ||
657 | fullname = avatar_name.mDisplayName; | ||
658 | } | ||
659 | else | ||
660 | { | ||
661 | fullname = avatar_name.getNames(true); | ||
662 | } | ||
663 | } | ||
664 | } | ||
665 | |||
666 | if(mClosestAgentToCursor.notNull() && result) | ||
644 | { | 667 | { |
645 | // msg.append(fullname); | 668 | // msg.append(fullname); |
646 | // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b | 669 | // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b |
diff --git a/linden/indra/newview/llpanelavatar.cpp b/linden/indra/newview/llpanelavatar.cpp index 6110e44..6b3be29 100644 --- a/linden/indra/newview/llpanelavatar.cpp +++ b/linden/indra/newview/llpanelavatar.cpp | |||
@@ -1357,7 +1357,33 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const std::string &name | |||
1357 | { | 1357 | { |
1358 | name_edit->setText(name); | 1358 | name_edit->setText(name); |
1359 | } | 1359 | } |
1360 | childSetVisible("name", TRUE); | ||
1360 | } | 1361 | } |
1362 | LLNameEditor* complete_name_edit = getChild<LLNameEditor>("complete_name"); | ||
1363 | if (complete_name_edit) | ||
1364 | { | ||
1365 | if (LLAvatarNameCache::useDisplayNames()) | ||
1366 | { | ||
1367 | LLAvatarName avatar_name; | ||
1368 | if (LLAvatarNameCache::get(avatar_id, &avatar_name)) | ||
1369 | { | ||
1370 | // Always show "Display Name [Legacy Name]" for security reasons | ||
1371 | complete_name_edit->setText(avatar_name.getNames()); | ||
1372 | } | ||
1373 | else | ||
1374 | { | ||
1375 | complete_name_edit->setText(name_edit->getText()); | ||
1376 | LLAvatarNameCache::get(avatar_id, boost::bind(&LLPanelAvatar::completeNameCallback, _1, _2, this)); | ||
1377 | } | ||
1378 | childSetVisible("name", FALSE); | ||
1379 | childSetVisible("complete_name", TRUE); | ||
1380 | } | ||
1381 | else | ||
1382 | { | ||
1383 | childSetVisible("complete_name", FALSE); | ||
1384 | } | ||
1385 | } | ||
1386 | |||
1361 | // if (avatar_changed) | 1387 | // if (avatar_changed) |
1362 | { | 1388 | { |
1363 | // While we're waiting for data off the network, clear out the | 1389 | // While we're waiting for data off the network, clear out the |
@@ -1480,6 +1506,22 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const std::string &name | |||
1480 | } | 1506 | } |
1481 | } | 1507 | } |
1482 | 1508 | ||
1509 | void LLPanelAvatar::completeNameCallback(const LLUUID& agent_id, | ||
1510 | const LLAvatarName& avatar_name, | ||
1511 | void *userdata) | ||
1512 | { | ||
1513 | LLPanelAvatar* self = (LLPanelAvatar*)userdata; | ||
1514 | if (!LLAvatarNameCache::useDisplayNames() || agent_id != self->mAvatarID) | ||
1515 | { | ||
1516 | return; | ||
1517 | } | ||
1518 | LLLineEditor* complete_name_edit = self->getChild<LLLineEditor>("complete_name"); | ||
1519 | if (complete_name_edit) | ||
1520 | { | ||
1521 | // Always show "Display Name [Legacy Name]" for security reasons | ||
1522 | complete_name_edit->setText(avatar_name.getNames()); | ||
1523 | } | ||
1524 | } | ||
1483 | 1525 | ||
1484 | void LLPanelAvatar::resetGroupList() | 1526 | void LLPanelAvatar::resetGroupList() |
1485 | { | 1527 | { |
diff --git a/linden/indra/newview/llpanelavatar.h b/linden/indra/newview/llpanelavatar.h index 9a2f450..3a90196 100644 --- a/linden/indra/newview/llpanelavatar.h +++ b/linden/indra/newview/llpanelavatar.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #ifndef LL_LLPANELAVATAR_H | 33 | #ifndef LL_LLPANELAVATAR_H |
34 | #define LL_LLPANELAVATAR_H | 34 | #define LL_LLPANELAVATAR_H |
35 | 35 | ||
36 | #include "llavatarnamecache.h" | ||
36 | #include "llpanel.h" | 37 | #include "llpanel.h" |
37 | #include "v3dmath.h" | 38 | #include "v3dmath.h" |
38 | #include "lluuid.h" | 39 | #include "lluuid.h" |
@@ -335,6 +336,9 @@ private: | |||
335 | static bool finishUnfreeze(const LLSD& notification, const LLSD& response); | 336 | static bool finishUnfreeze(const LLSD& notification, const LLSD& response); |
336 | 337 | ||
337 | static void showProfileCallback(S32 option, void *userdata); | 338 | static void showProfileCallback(S32 option, void *userdata); |
339 | static void completeNameCallback(const LLUUID& agent_id, | ||
340 | const LLAvatarName& avatar_name, | ||
341 | void *userdata); | ||
338 | 342 | ||
339 | static void* createPanelAvatar(void* data); | 343 | static void* createPanelAvatar(void* data); |
340 | static void* createFloaterAvatarInfo(void* data); | 344 | static void* createFloaterAvatarInfo(void* data); |
diff --git a/linden/indra/newview/llstartup.cpp b/linden/indra/newview/llstartup.cpp index 939c2e6..4bfcf52 100644 --- a/linden/indra/newview/llstartup.cpp +++ b/linden/indra/newview/llstartup.cpp | |||
@@ -2034,6 +2034,12 @@ bool idle_startup() | |||
2034 | 2034 | ||
2035 | // Load stored cache if possible | 2035 | // Load stored cache if possible |
2036 | LLAppViewer::instance()->loadNameCache(); | 2036 | LLAppViewer::instance()->loadNameCache(); |
2037 | |||
2038 | // Start cache in not-running state until we figure out if we have | ||
2039 | // capabilities for display name lookup | ||
2040 | LLAvatarNameCache::initClass(false); | ||
2041 | LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getU32("DisplayNamesUsage")); | ||
2042 | LLAvatarName::sOmitResidentAsLastName = (bool)gSavedSettings.getBOOL("OmitResidentAsLastName"); | ||
2037 | } | 2043 | } |
2038 | 2044 | ||
2039 | // *Note: this is where gWorldMap used to be initialized. | 2045 | // *Note: this is where gWorldMap used to be initialized. |
diff --git a/linden/indra/newview/llviewercontrol.cpp b/linden/indra/newview/llviewercontrol.cpp index 00e3a9a..572f64a 100644 --- a/linden/indra/newview/llviewercontrol.cpp +++ b/linden/indra/newview/llviewercontrol.cpp | |||
@@ -41,6 +41,8 @@ | |||
41 | // #include "llaudioengine.h" | 41 | // #include "llaudioengine.h" |
42 | #include "kokuastreamingaudio.h" | 42 | #include "kokuastreamingaudio.h" |
43 | #include "llagent.h" | 43 | #include "llagent.h" |
44 | #include "llavatarnamecache.h" | ||
45 | #include "llcallingcard.h" | ||
44 | #include "llconsole.h" | 46 | #include "llconsole.h" |
45 | #include "lldrawpoolterrain.h" | 47 | #include "lldrawpoolterrain.h" |
46 | #include "llflexibleobject.h" | 48 | #include "llflexibleobject.h" |
@@ -426,6 +428,28 @@ static bool handleAuditTextureChanged(const LLSD& newvalue) | |||
426 | return true; | 428 | return true; |
427 | } | 429 | } |
428 | 430 | ||
431 | static bool handleDisplayNamesUsageChanged(const LLSD& newvalue) | ||
432 | { | ||
433 | LLAvatarNameCache::setUseDisplayNames((U32)newvalue.asInteger()); | ||
434 | LLVOAvatar::invalidateNameTags(); | ||
435 | LLAvatarTracker::instance().dirtyBuddies(); | ||
436 | return true; | ||
437 | } | ||
438 | |||
439 | static bool handleOmitResidentAsLastNameChanged(const LLSD& newvalue) | ||
440 | { | ||
441 | LLAvatarName::sOmitResidentAsLastName =(bool)newvalue.asBoolean(); | ||
442 | LLVOAvatar::invalidateNameTags(); | ||
443 | LLAvatarTracker::instance().dirtyBuddies(); | ||
444 | return true; | ||
445 | } | ||
446 | |||
447 | static bool handleLegacyNamesForFriendsChanged(const LLSD& newvalue) | ||
448 | { | ||
449 | LLAvatarTracker::instance().dirtyBuddies(); | ||
450 | return true; | ||
451 | } | ||
452 | |||
429 | static bool handleRenderDebugGLChanged(const LLSD& newvalue) | 453 | static bool handleRenderDebugGLChanged(const LLSD& newvalue) |
430 | { | 454 | { |
431 | gDebugGL = newvalue.asBoolean(); | 455 | gDebugGL = newvalue.asBoolean(); |
@@ -573,6 +597,9 @@ void settings_setup_listeners() | |||
573 | gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); | 597 | gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); |
574 | gSavedSettings.getControl("AudioStreamingMusic")->getSignal()->connect(boost::bind(&handleAudioStreamMusicChanged, _1)); | 598 | gSavedSettings.getControl("AudioStreamingMusic")->getSignal()->connect(boost::bind(&handleAudioStreamMusicChanged, _1)); |
575 | gSavedSettings.getControl("AuditTexture")->getSignal()->connect(boost::bind(&handleAuditTextureChanged, _1)); | 599 | gSavedSettings.getControl("AuditTexture")->getSignal()->connect(boost::bind(&handleAuditTextureChanged, _1)); |
600 | gSavedSettings.getControl("DisplayNamesUsage")->getSignal()->connect(boost::bind(&handleDisplayNamesUsageChanged, _1)); | ||
601 | gSavedSettings.getControl("OmitResidentAsLastName")->getSignal()->connect(boost::bind(&handleOmitResidentAsLastNameChanged, _1)); | ||
602 | gSavedSettings.getControl("LegacyNamesForFriends")->getSignal()->connect(boost::bind(&handleLegacyNamesForFriendsChanged, _1)); | ||
576 | gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); | 603 | gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); |
577 | gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); | 604 | gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); |
578 | gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); | 605 | gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); |
diff --git a/linden/indra/newview/llviewerdisplayname.cpp b/linden/indra/newview/llviewerdisplayname.cpp new file mode 100644 index 0000000..6a7cab3 --- /dev/null +++ b/linden/indra/newview/llviewerdisplayname.cpp | |||
@@ -0,0 +1,208 @@ | |||
1 | /** | ||
2 | * @file llviewerdisplayname.cpp | ||
3 | * @brief Wrapper for display name functionality | ||
4 | * | ||
5 | * $LicenseInfo:firstyear=2010&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 "llviewerprecompiledheaders.h" | ||
28 | |||
29 | #include "llviewerdisplayname.h" | ||
30 | |||
31 | // viewer includes | ||
32 | #include "llagent.h" | ||
33 | #include "llviewerregion.h" | ||
34 | #include "llvoavatar.h" | ||
35 | |||
36 | // library includes | ||
37 | #include "llavatarnamecache.h" | ||
38 | #include "llhttpclient.h" | ||
39 | #include "llhttpnode.h" | ||
40 | #include "llnotifications.h" | ||
41 | #include "llui.h" // getLanguage() | ||
42 | |||
43 | namespace LLViewerDisplayName | ||
44 | { | ||
45 | // Fired when viewer receives server response to display name change | ||
46 | set_name_signal_t sSetDisplayNameSignal; | ||
47 | |||
48 | // Fired when there is a change in the agent's name | ||
49 | name_changed_signal_t sNameChangedSignal; | ||
50 | |||
51 | void addNameChangedCallback(const name_changed_signal_t::slot_type& cb) | ||
52 | { | ||
53 | sNameChangedSignal.connect(cb); | ||
54 | } | ||
55 | |||
56 | } | ||
57 | |||
58 | class LLSetDisplayNameResponder : public LLHTTPClient::Responder | ||
59 | { | ||
60 | public: | ||
61 | // only care about errors | ||
62 | /*virtual*/ void error(U32 status, const std::string& reason) | ||
63 | { | ||
64 | LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); | ||
65 | LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); | ||
66 | } | ||
67 | }; | ||
68 | |||
69 | void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot) | ||
70 | { | ||
71 | // TODO: simple validation here | ||
72 | |||
73 | LLViewerRegion* region = gAgent.getRegion(); | ||
74 | llassert(region); | ||
75 | std::string cap_url = region->getCapability("SetDisplayName"); | ||
76 | if (cap_url.empty()) | ||
77 | { | ||
78 | // this server does not support display names, report error | ||
79 | slot(false, "unsupported", LLSD()); | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | // People API can return localized error messages. Indicate our | ||
84 | // language preference via header. | ||
85 | LLSD headers; | ||
86 | headers["Accept-Language"] = LLUI::getLanguage(); | ||
87 | |||
88 | // People API requires both the old and new value to change a variable. | ||
89 | // Our display name will be in cache before the viewer's UI is available | ||
90 | // to request a change, so we can use direct lookup without callback. | ||
91 | LLAvatarName av_name; | ||
92 | if (!LLAvatarNameCache::get( gAgent.getID(), &av_name)) | ||
93 | { | ||
94 | slot(false, "name unavailable", LLSD()); | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | // People API expects array of [ "old value", "new value" ] | ||
99 | LLSD change_array = LLSD::emptyArray(); | ||
100 | change_array.append(av_name.mDisplayName); | ||
101 | change_array.append(display_name); | ||
102 | |||
103 | llinfos << "Set name POST to " << cap_url << llendl; | ||
104 | |||
105 | // Record our caller for when the server sends back a reply | ||
106 | sSetDisplayNameSignal.connect(slot); | ||
107 | |||
108 | // POST the requested change. The sim will not send a response back to | ||
109 | // this request directly, rather it will send a separate message after it | ||
110 | // communicates with the back-end. | ||
111 | LLSD body; | ||
112 | body["display_name"] = change_array; | ||
113 | LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); | ||
114 | } | ||
115 | |||
116 | class LLSetDisplayNameReply : public LLHTTPNode | ||
117 | { | ||
118 | LOG_CLASS(LLSetDisplayNameReply); | ||
119 | public: | ||
120 | /*virtual*/ void post( | ||
121 | LLHTTPNode::ResponsePtr response, | ||
122 | const LLSD& context, | ||
123 | const LLSD& input) const | ||
124 | { | ||
125 | LLSD body = input["body"]; | ||
126 | |||
127 | S32 status = body["status"].asInteger(); | ||
128 | bool success = (status == 200); | ||
129 | std::string reason = body["reason"].asString(); | ||
130 | LLSD content = body["content"]; | ||
131 | |||
132 | llinfos << "status " << status << " reason " << reason << llendl; | ||
133 | |||
134 | // If viewer's concept of display name is out-of-date, the set request | ||
135 | // will fail with 409 Conflict. If that happens, fetch up-to-date | ||
136 | // name information. | ||
137 | if (status == 409) | ||
138 | { | ||
139 | LLUUID agent_id = gAgent.getID(); | ||
140 | // Flush stale data | ||
141 | LLAvatarNameCache::erase( agent_id ); | ||
142 | // Queue request for new data | ||
143 | LLAvatarName ignored; | ||
144 | LLAvatarNameCache::get( agent_id, &ignored ); | ||
145 | // Kill name tag, as it is wrong | ||
146 | LLVOAvatar::invalidateNameTag( agent_id ); | ||
147 | } | ||
148 | |||
149 | // inform caller of result | ||
150 | LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content); | ||
151 | LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); | ||
152 | } | ||
153 | }; | ||
154 | |||
155 | |||
156 | class LLDisplayNameUpdate : public LLHTTPNode | ||
157 | { | ||
158 | /*virtual*/ void post( | ||
159 | LLHTTPNode::ResponsePtr response, | ||
160 | const LLSD& context, | ||
161 | const LLSD& input) const | ||
162 | { | ||
163 | LLSD body = input["body"]; | ||
164 | LLUUID agent_id = body["agent_id"]; | ||
165 | std::string old_display_name = body["old_display_name"]; | ||
166 | // By convention this record is called "agent" in the People API | ||
167 | LLSD name_data = body["agent"]; | ||
168 | |||
169 | // Inject the new name data into cache | ||
170 | LLAvatarName av_name; | ||
171 | av_name.fromLLSD( name_data ); | ||
172 | |||
173 | llinfos << "name-update now " << LLDate::now() | ||
174 | << " next_update " << LLDate(av_name.mNextUpdate) | ||
175 | << llendl; | ||
176 | |||
177 | // Name expiration time may be provided in headers, or we may use a | ||
178 | // default value | ||
179 | // *TODO: get actual headers out of ResponsePtr | ||
180 | //LLSD headers = response->mHeaders; | ||
181 | LLSD headers; | ||
182 | av_name.mExpires = | ||
183 | LLAvatarNameCache::nameExpirationFromHeaders(headers); | ||
184 | |||
185 | LLAvatarNameCache::insert(agent_id, av_name); | ||
186 | |||
187 | // force name tag to update | ||
188 | LLVOAvatar::invalidateNameTag(agent_id); | ||
189 | |||
190 | LLSD args; | ||
191 | args["OLD_NAME"] = old_display_name; | ||
192 | args["SLID"] = av_name.mUsername; | ||
193 | args["NEW_NAME"] = av_name.mDisplayName; | ||
194 | LLNotifications::instance().add("DisplayNameUpdate", args); | ||
195 | if (agent_id == gAgent.getID()) | ||
196 | { | ||
197 | LLViewerDisplayName::sNameChangedSignal(); | ||
198 | } | ||
199 | } | ||
200 | }; | ||
201 | |||
202 | LLHTTPRegistration<LLSetDisplayNameReply> | ||
203 | gHTTPRegistrationMessageSetDisplayNameReply( | ||
204 | "/message/SetDisplayNameReply"); | ||
205 | |||
206 | LLHTTPRegistration<LLDisplayNameUpdate> | ||
207 | gHTTPRegistrationMessageDisplayNameUpdate( | ||
208 | "/message/DisplayNameUpdate"); | ||
diff --git a/linden/indra/newview/llviewerdisplayname.h b/linden/indra/newview/llviewerdisplayname.h new file mode 100644 index 0000000..16d59ae --- /dev/null +++ b/linden/indra/newview/llviewerdisplayname.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /** | ||
2 | * @file llviewerdisplayname.h | ||
3 | * @brief Wrapper for display name functionality | ||
4 | * | ||
5 | * $LicenseInfo:firstyear=2010&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 | #ifndef LLVIEWERDISPLAYNAME_H | ||
28 | #define LLVIEWERDISPLAYNAME_H | ||
29 | |||
30 | #include <boost/signals2.hpp> | ||
31 | |||
32 | class LLSD; | ||
33 | class LLUUID; | ||
34 | |||
35 | namespace LLViewerDisplayName | ||
36 | { | ||
37 | typedef boost::signals2::signal< | ||
38 | void (bool success, const std::string& reason, const LLSD& content)> | ||
39 | set_name_signal_t; | ||
40 | typedef set_name_signal_t::slot_type set_name_slot_t; | ||
41 | |||
42 | typedef boost::signals2::signal<void (void)> name_changed_signal_t; | ||
43 | typedef name_changed_signal_t::slot_type name_changed_slot_t; | ||
44 | |||
45 | // Sends an update to the server to change a display name | ||
46 | // and call back when done. May not succeed due to service | ||
47 | // unavailable or name not available. | ||
48 | void set(const std::string& display_name, const set_name_slot_t& slot); | ||
49 | |||
50 | void addNameChangedCallback(const name_changed_signal_t::slot_type& cb); | ||
51 | } | ||
52 | |||
53 | #endif // LLVIEWERDISPLAYNAME_H | ||
diff --git a/linden/indra/newview/llviewermenu.cpp b/linden/indra/newview/llviewermenu.cpp index c5d78d8..777a871 100644 --- a/linden/indra/newview/llviewermenu.cpp +++ b/linden/indra/newview/llviewermenu.cpp | |||
@@ -41,6 +41,7 @@ | |||
41 | 41 | ||
42 | // linden library includes | 42 | // linden library includes |
43 | #include "llaudioengine.h" | 43 | #include "llaudioengine.h" |
44 | #include "llavatarnamecache.h" | ||
44 | #include "indra_constants.h" | 45 | #include "indra_constants.h" |
45 | #include "llassetstorage.h" | 46 | #include "llassetstorage.h" |
46 | #include "llchat.h" | 47 | #include "llchat.h" |
@@ -102,6 +103,7 @@ | |||
102 | #include "llfloatercustomize.h" | 103 | #include "llfloatercustomize.h" |
103 | #include "llfloaterdaycycle.h" | 104 | #include "llfloaterdaycycle.h" |
104 | #include "llfloaterdirectory.h" | 105 | #include "llfloaterdirectory.h" |
106 | #include "llfloaterdisplayname.h" | ||
105 | #include "llfloatereditui.h" | 107 | #include "llfloatereditui.h" |
106 | #include "llfloaterchatterbox.h" | 108 | #include "llfloaterchatterbox.h" |
107 | #include "llfloaterfriends.h" | 109 | #include "llfloaterfriends.h" |
@@ -3434,6 +3436,16 @@ class LLEditEnableCustomizeAvatar : public view_listener_t | |||
3434 | } | 3436 | } |
3435 | }; | 3437 | }; |
3436 | 3438 | ||
3439 | class LLEditEnableDisplayName : public view_listener_t | ||
3440 | { | ||
3441 | bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) | ||
3442 | { | ||
3443 | bool new_value = (LLAvatarNameCache::useDisplayNames() != 0); | ||
3444 | gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); | ||
3445 | return true; | ||
3446 | } | ||
3447 | }; | ||
3448 | |||
3437 | // only works on pie menu | 3449 | // only works on pie menu |
3438 | bool handle_sit_or_stand() | 3450 | bool handle_sit_or_stand() |
3439 | { | 3451 | { |
@@ -5959,6 +5971,10 @@ class LLShowFloater : public view_listener_t | |||
5959 | { | 5971 | { |
5960 | LLToolBar::toggle(NULL); | 5972 | LLToolBar::toggle(NULL); |
5961 | } | 5973 | } |
5974 | else if (floater_name == "displayname") | ||
5975 | { | ||
5976 | LLFloaterDisplayName::show(); | ||
5977 | } | ||
5962 | else if (floater_name == "chat history") | 5978 | else if (floater_name == "chat history") |
5963 | { | 5979 | { |
5964 | LLFloaterChat::toggleInstance(LLSD()); | 5980 | LLFloaterChat::toggleInstance(LLSD()); |
@@ -11132,6 +11148,7 @@ void initialize_menus() | |||
11132 | addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate"); | 11148 | addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate"); |
11133 | addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); | 11149 | addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); |
11134 | addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); | 11150 | addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); |
11151 | addMenu(new LLEditEnableDisplayName(), "Edit.EnableDisplayName"); | ||
11135 | addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); | 11152 | addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); |
11136 | 11153 | ||
11137 | // View menu | 11154 | // View menu |
diff --git a/linden/indra/newview/llviewermessage.cpp b/linden/indra/newview/llviewermessage.cpp index 5f333e9..8cb154e 100755 --- a/linden/indra/newview/llviewermessage.cpp +++ b/linden/indra/newview/llviewermessage.cpp | |||
@@ -2998,6 +2998,33 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) | |||
2998 | 2998 | ||
2999 | if (is_audible) | 2999 | if (is_audible) |
3000 | { | 3000 | { |
3001 | if (chatter && chatter->isAvatar()) | ||
3002 | { | ||
3003 | #ifdef LL_RRINTERFACE_H //MK | ||
3004 | if (!gRRenabled || !gAgent.mRRInterface.mContainsShownames) | ||
3005 | { | ||
3006 | #endif //mk | ||
3007 | if (LLAvatarNameCache::useDisplayNames()) | ||
3008 | { | ||
3009 | LLAvatarName avatar_name; | ||
3010 | if (LLAvatarNameCache::get(from_id, &avatar_name)) | ||
3011 | { | ||
3012 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
3013 | { | ||
3014 | from_name = avatar_name.mDisplayName; | ||
3015 | } | ||
3016 | else | ||
3017 | { | ||
3018 | from_name = avatar_name.getNames(); | ||
3019 | } | ||
3020 | } | ||
3021 | chat.mFromName = from_name; | ||
3022 | } | ||
3023 | #ifdef LL_RRINTERFACE_H //MK | ||
3024 | } | ||
3025 | #endif //mk | ||
3026 | } | ||
3027 | |||
3001 | BOOL visible_in_chat_bubble = FALSE; | 3028 | BOOL visible_in_chat_bubble = FALSE; |
3002 | std::string verb; | 3029 | std::string verb; |
3003 | 3030 | ||
diff --git a/linden/indra/newview/llviewerregion.cpp b/linden/indra/newview/llviewerregion.cpp index d93c425..a8047b8 100644 --- a/linden/indra/newview/llviewerregion.cpp +++ b/linden/indra/newview/llviewerregion.cpp | |||
@@ -127,6 +127,8 @@ public: | |||
127 | } | 127 | } |
128 | } | 128 | } |
129 | 129 | ||
130 | mRegion->setCapabilitiesReceived(true); | ||
131 | |||
130 | if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) | 132 | if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) |
131 | { | 133 | { |
132 | LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); | 134 | LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); |
@@ -172,7 +174,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, | |||
172 | mCacheEntriesCount(0), | 174 | mCacheEntriesCount(0), |
173 | mCacheID(), | 175 | mCacheID(), |
174 | mEventPoll(NULL), | 176 | mEventPoll(NULL), |
175 | mReleaseNotesRequested(FALSE) | 177 | mReleaseNotesRequested(FALSE), |
178 | mCapabilitiesReceived(false) | ||
176 | { | 179 | { |
177 | mWidth = region_width_meters; | 180 | mWidth = region_width_meters; |
178 | mOriginGlobal = from_region_handle(handle); | 181 | mOriginGlobal = from_region_handle(handle); |
@@ -1431,6 +1434,8 @@ void LLViewerRegion::setSeedCapability(const std::string& url) | |||
1431 | capabilityNames.append("FetchInventory"); | 1434 | capabilityNames.append("FetchInventory"); |
1432 | capabilityNames.append("FetchLib"); | 1435 | capabilityNames.append("FetchLib"); |
1433 | capabilityNames.append("FetchLibDescendents"); | 1436 | capabilityNames.append("FetchLibDescendents"); |
1437 | capabilityNames.append("GetDisplayNames"); | ||
1438 | capabilityNames.append("SetDisplayName"); | ||
1434 | capabilityNames.append("GetTexture"); | 1439 | capabilityNames.append("GetTexture"); |
1435 | capabilityNames.append("GroupProposalBallot"); | 1440 | capabilityNames.append("GroupProposalBallot"); |
1436 | capabilityNames.append("HomeLocation"); | 1441 | capabilityNames.append("HomeLocation"); |
@@ -1509,6 +1514,16 @@ std::string LLViewerRegion::getCapability(const std::string& name) const | |||
1509 | return iter->second; | 1514 | return iter->second; |
1510 | } | 1515 | } |
1511 | 1516 | ||
1517 | bool LLViewerRegion::capabilitiesReceived() const | ||
1518 | { | ||
1519 | return mCapabilitiesReceived; | ||
1520 | } | ||
1521 | |||
1522 | void LLViewerRegion::setCapabilitiesReceived(bool received) | ||
1523 | { | ||
1524 | mCapabilitiesReceived = received; | ||
1525 | } | ||
1526 | |||
1512 | void LLViewerRegion::logActiveCapabilities() const | 1527 | void LLViewerRegion::logActiveCapabilities() const |
1513 | { | 1528 | { |
1514 | int count = 0; | 1529 | int count = 0; |
diff --git a/linden/indra/newview/llviewerregion.h b/linden/indra/newview/llviewerregion.h index 8cc80e3..5ce8b2e 100644 --- a/linden/indra/newview/llviewerregion.h +++ b/linden/indra/newview/llviewerregion.h | |||
@@ -229,6 +229,11 @@ public: | |||
229 | void setSeedCapability(const std::string& url); | 229 | void setSeedCapability(const std::string& url); |
230 | void setCapability(const std::string& name, const std::string& url); | 230 | void setCapability(const std::string& name, const std::string& url); |
231 | std::string getCapability(const std::string& name) const; | 231 | std::string getCapability(const std::string& name) const; |
232 | |||
233 | // has region received its final (not seed) capability list? | ||
234 | bool capabilitiesReceived() const; | ||
235 | void setCapabilitiesReceived(bool received); | ||
236 | |||
232 | static bool isSpecialCapabilityName(const std::string &name); | 237 | static bool isSpecialCapabilityName(const std::string &name); |
233 | void logActiveCapabilities() const; | 238 | void logActiveCapabilities() const; |
234 | 239 | ||
@@ -399,6 +404,7 @@ private: | |||
399 | 404 | ||
400 | private: | 405 | private: |
401 | bool mAlive; // can become false if circuit disconnects | 406 | bool mAlive; // can become false if circuit disconnects |
407 | bool mCapabilitiesReceived; | ||
402 | 408 | ||
403 | //spatial partitions for objects in this region | 409 | //spatial partitions for objects in this region |
404 | std::vector<LLSpatialPartition*> mObjectPartition; | 410 | std::vector<LLSpatialPartition*> mObjectPartition; |
diff --git a/linden/indra/newview/llvoavatar.cpp b/linden/indra/newview/llvoavatar.cpp index 35cabc1..a3222df 100644 --- a/linden/indra/newview/llvoavatar.cpp +++ b/linden/indra/newview/llvoavatar.cpp | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <ctype.h> | 38 | #include <ctype.h> |
39 | 39 | ||
40 | #include "llaudioengine.h" | 40 | #include "llaudioengine.h" |
41 | #include "llavatarnamecache.h" | ||
41 | #include "noise.h" | 42 | #include "noise.h" |
42 | 43 | ||
43 | #include "llagent.h" // Get state values from here | 44 | #include "llagent.h" // Get state values from here |
@@ -748,6 +749,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, | |||
748 | mAppearanceAnimating(FALSE), | 749 | mAppearanceAnimating(FALSE), |
749 | mNameString(), | 750 | mNameString(), |
750 | mTitle(), | 751 | mTitle(), |
752 | mCompleteName(), | ||
751 | mNameAway(FALSE), | 753 | mNameAway(FALSE), |
752 | mNameBusy(FALSE), | 754 | mNameBusy(FALSE), |
753 | mNameMute(FALSE), | 755 | mNameMute(FALSE), |
@@ -3609,6 +3611,35 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3609 | 3611 | ||
3610 | if (mNameText.notNull() && firstname && lastname) | 3612 | if (mNameText.notNull() && firstname && lastname) |
3611 | { | 3613 | { |
3614 | std::string complete_name = firstname->getString(); | ||
3615 | if (sRenderGroupTitles) | ||
3616 | { | ||
3617 | complete_name += " "; | ||
3618 | } | ||
3619 | else | ||
3620 | { | ||
3621 | // If all group titles are turned off, stack first name | ||
3622 | // on a line above last name | ||
3623 | complete_name += "\n"; | ||
3624 | } | ||
3625 | complete_name += lastname->getString(); | ||
3626 | |||
3627 | if (LLAvatarNameCache::useDisplayNames()) | ||
3628 | { | ||
3629 | LLAvatarName avatar_name; | ||
3630 | if (LLAvatarNameCache::get(getID(), &avatar_name)) | ||
3631 | { | ||
3632 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
3633 | { | ||
3634 | complete_name = avatar_name.mDisplayName; | ||
3635 | } | ||
3636 | else | ||
3637 | { | ||
3638 | complete_name = avatar_name.getNames(true); | ||
3639 | } | ||
3640 | } | ||
3641 | } | ||
3642 | |||
3612 | BOOL is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end(); | 3643 | BOOL is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end(); |
3613 | BOOL is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end(); | 3644 | BOOL is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end(); |
3614 | BOOL is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); | 3645 | BOOL is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); |
@@ -3623,7 +3654,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3623 | } | 3654 | } |
3624 | 3655 | ||
3625 | if (mNameString.empty() || | 3656 | if (mNameString.empty() || |
3626 | new_name || | 3657 | new_name || complete_name != mCompleteName || |
3627 | (!title && !mTitle.empty()) || | 3658 | (!title && !mTitle.empty()) || |
3628 | (title && mTitle != title->getString()) || | 3659 | (title && mTitle != title->getString()) || |
3629 | (is_away != mNameAway || is_busy != mNameBusy || is_muted != mNameMute) | 3660 | (is_away != mNameAway || is_busy != mNameBusy || is_muted != mNameMute) |
@@ -3639,20 +3670,19 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3639 | line += title->getString(); | 3670 | line += title->getString(); |
3640 | //LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR); IMP-136 -- McCabe | 3671 | //LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR); IMP-136 -- McCabe |
3641 | line += "\n"; | 3672 | line += "\n"; |
3642 | line += firstname->getString(); | 3673 | line += complete_name; |
3643 | } | 3674 | } |
3644 | else | 3675 | else |
3645 | { | 3676 | { |
3646 | line += firstname->getString(); | 3677 | line += complete_name; |
3647 | } | 3678 | } |
3648 | 3679 | ||
3649 | line += " "; | 3680 | |
3650 | line += lastname->getString(); | ||
3651 | // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0b | 3681 | // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0b |
3652 | } | 3682 | } |
3653 | else | 3683 | else |
3654 | { | 3684 | { |
3655 | line = RlvStrings::getAnonym(line.assign(firstname->getString()).append(" ").append(lastname->getString())); | 3685 | line = RlvStrings::getAnonym(complete_name); |
3656 | } | 3686 | } |
3657 | // [/RLVa:KB] | 3687 | // [/RLVa:KB] |
3658 | 3688 | ||
@@ -3662,7 +3692,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3662 | bool show_client = client.length() != 0 && (*sShowClientNameTag); | 3692 | bool show_client = client.length() != 0 && (*sShowClientNameTag); |
3663 | if (is_away || is_muted || is_busy || show_client) | 3693 | if (is_away || is_muted || is_busy || show_client) |
3664 | { | 3694 | { |
3665 | line += " ("; | 3695 | line += "\n("; |
3666 | if (is_away) | 3696 | if (is_away) |
3667 | { | 3697 | { |
3668 | line += "Away"; | 3698 | line += "Away"; |
@@ -3707,6 +3737,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3707 | mNameMute = is_muted; | 3737 | mNameMute = is_muted; |
3708 | mNameAppearance = is_appearance; | 3738 | mNameAppearance = is_appearance; |
3709 | mTitle = title ? title->getString() : ""; | 3739 | mTitle = title ? title->getString() : ""; |
3740 | mCompleteName = complete_name; | ||
3710 | //LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR); IMP-136 -- McCabe | 3741 | //LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR); IMP-136 -- McCabe |
3711 | mNameString = utf8str_to_wstring(line); | 3742 | mNameString = utf8str_to_wstring(line); |
3712 | new_name = TRUE; | 3743 | new_name = TRUE; |
@@ -3823,6 +3854,41 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3823 | } | 3854 | } |
3824 | } | 3855 | } |
3825 | 3856 | ||
3857 | void LLVOAvatar::clearNameTag() | ||
3858 | { | ||
3859 | mNameString.clear(); | ||
3860 | if (mNameText) | ||
3861 | { | ||
3862 | mNameText->setLabel(""); | ||
3863 | mNameText->setString(mNameString); | ||
3864 | } | ||
3865 | } | ||
3866 | |||
3867 | //static | ||
3868 | void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id) | ||
3869 | { | ||
3870 | LLViewerObject* obj = gObjectList.findObject(agent_id); | ||
3871 | if (!obj) return; | ||
3872 | |||
3873 | LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(obj); | ||
3874 | if (!avatar) return; | ||
3875 | |||
3876 | avatar->clearNameTag(); | ||
3877 | } | ||
3878 | |||
3879 | //static | ||
3880 | void LLVOAvatar::invalidateNameTags() | ||
3881 | { | ||
3882 | std::vector<LLCharacter*>::iterator it; | ||
3883 | for (it = LLCharacter::sInstances.begin(); it != LLCharacter::sInstances.end(); ++it) | ||
3884 | { | ||
3885 | LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*it); | ||
3886 | if (!avatar) continue; | ||
3887 | if (avatar->isDead()) continue; | ||
3888 | |||
3889 | avatar->clearNameTag(); | ||
3890 | } | ||
3891 | } | ||
3826 | 3892 | ||
3827 | void LLVOAvatar::idleUpdateTractorBeam() | 3893 | void LLVOAvatar::idleUpdateTractorBeam() |
3828 | { | 3894 | { |
diff --git a/linden/indra/newview/llvoavatar.h b/linden/indra/newview/llvoavatar.h index a23a9df..e585a6a 100644 --- a/linden/indra/newview/llvoavatar.h +++ b/linden/indra/newview/llvoavatar.h | |||
@@ -112,6 +112,10 @@ public: | |||
112 | void idleUpdateWindEffect(); | 112 | void idleUpdateWindEffect(); |
113 | void idleUpdateBoobEffect(); | 113 | void idleUpdateBoobEffect(); |
114 | void idleUpdateNameTag(const LLVector3& root_pos_last); | 114 | void idleUpdateNameTag(const LLVector3& root_pos_last); |
115 | void clearNameTag(); | ||
116 | static void invalidateNameTag(const LLUUID& agent_id); | ||
117 | // force all name tags to rebuild, useful when display names turned on/off | ||
118 | static void invalidateNameTags(); | ||
115 | void idleUpdateRenderCost(); | 119 | void idleUpdateRenderCost(); |
116 | void idleUpdateTractorBeam(); | 120 | void idleUpdateTractorBeam(); |
117 | void idleUpdateBelowWater(); | 121 | void idleUpdateBelowWater(); |
@@ -677,6 +681,7 @@ protected: | |||
677 | 681 | ||
678 | LLWString mNameString; | 682 | LLWString mNameString; |
679 | std::string mTitle; | 683 | std::string mTitle; |
684 | std::string mCompleteName; | ||
680 | BOOL mNameAway; | 685 | BOOL mNameAway; |
681 | BOOL mNameBusy; | 686 | BOOL mNameBusy; |
682 | BOOL mNameMute; | 687 | BOOL mNameMute; |
diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_display_name.xml b/linden/indra/newview/skins/default/xui/en-us/floater_display_name.xml new file mode 100644 index 0000000..5875efb --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/floater_display_name.xml | |||
@@ -0,0 +1,42 @@ | |||
1 | <?xml version="1.0" encoding="utf-8" standalone="yes" ?> | ||
2 | <floater name="Display Name" title="CHANGE DISPLAY NAME" | ||
3 | can_minimize="true" can_close="true" can_resize="false" | ||
4 | enabled="true" mouse_opaque="true" | ||
5 | height="235" width="440"> | ||
6 | <text name="info_text1" font="SansSerif" wrap="true" | ||
7 | height="18" width="380" left="42" bottom_delta="-48" follows="left|top"> | ||
8 | The name you give to your avatar is called your Display Name. | ||
9 | </text> | ||
10 | <text name="info_text2" font="SansSerif" wrap="true" | ||
11 | height="18" width="300" left="120" bottom_delta="-18" follows="left|top"> | ||
12 | You can change it once a week. | ||
13 | </text> | ||
14 | <text name="now_ok_text" font="SansSerif" | ||
15 | height="18" width="320" left="105" bottom_delta="-25" follows="left|top"> | ||
16 | You can change it now if you so wish. | ||
17 | </text> | ||
18 | <text name="lockout_text" font="SansSerif" visible="false" | ||
19 | height="18" width="380" left="20" bottom_delta="0" follows="left|top"> | ||
20 | You cannot change it before: [TIME]. | ||
21 | </text> | ||
22 | <text name="set_name_label" font="SansSerif" | ||
23 | height="20" width="380" left="20" bottom_delta="-25" follows="left|top"> | ||
24 | New Display Name: | ||
25 | </text> | ||
26 | <line_editor name="display_name_editor" max_length="31" | ||
27 | height="20" width="360" left="40" bottom_delta="-20" follows="left|top" /> | ||
28 | <text name="name_confirm_label" font="SansSerif" | ||
29 | height="20" width="380" left="20" bottom_delta="-32" follows="left|top"> | ||
30 | Type your new name again to confirm: | ||
31 | </text> | ||
32 | <line_editor name="display_name_confirm" max_length="31" | ||
33 | height="20" width="360" left="40" bottom_delta="-20" follows="left|top" /> | ||
34 | <button name="save_btn" label="Save" font="SansSerif" | ||
35 | tool_tip="Save your new Display Name" | ||
36 | height="20" width="120" left="30" bottom_delta="-32"/> | ||
37 | <button name="reset_btn" label="Reset" font="SansSerif" | ||
38 | tool_tip="Make Display Name the same as Username" | ||
39 | height="20" width="120" left_delta="130" bottom_delta="0"/> | ||
40 | <button name="cancel_btn" label="Cancel" font="SansSerif" | ||
41 | height="20" width="120" left_delta="130" bottom_delta="0"/> | ||
42 | </floater> | ||
diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_new_im.xml b/linden/indra/newview/skins/default/xui/en-us/floater_new_im.xml index c93b890..5d766be 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_new_im.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_new_im.xml | |||
@@ -8,7 +8,7 @@ | |||
8 | column_padding="5" draw_border="true" draw_heading="false" | 8 | column_padding="5" draw_border="true" draw_heading="false" |
9 | draw_stripes="true" enabled="true" follows="left|top|right|bottom" | 9 | draw_stripes="true" enabled="true" follows="left|top|right|bottom" |
10 | height="290" left="6" mouse_opaque="true" multi_select="false" | 10 | height="290" left="6" mouse_opaque="true" multi_select="false" |
11 | name="user_list" width="421" /> | 11 | name="user_list" use_display_names="true" width="421" /> |
12 | <button bottom="-271" enabled="true" follows="right|bottom" font="SansSerif" | 12 | <button bottom="-271" enabled="true" follows="right|bottom" font="SansSerif" |
13 | halign="center" height="20" label="Start" label_selected="Start" left="435" | 13 | halign="center" height="20" label="Start" label_selected="Start" left="435" |
14 | mouse_opaque="true" name="start_btn" scale_image="true" sound_flags="0" | 14 | mouse_opaque="true" name="start_btn" scale_image="true" sound_flags="0" |
@@ -17,9 +17,6 @@ | |||
17 | halign="center" height="20" label="Close" label_selected="Close" left="435" | 17 | halign="center" height="20" label="Close" label_selected="Close" left="435" |
18 | mouse_opaque="true" name="close_btn" scale_image="true" sound_flags="0" | 18 | mouse_opaque="true" name="close_btn" scale_image="true" sound_flags="0" |
19 | width="60" /> | 19 | width="60" /> |
20 | <string name="name_format"> | ||
21 | [FIRST] [LAST] | ||
22 | </string> | ||
23 | <string name="online_descriptor"> | 20 | <string name="online_descriptor"> |
24 | (online) | 21 | (online) |
25 | </string> | 22 | </string> |
diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml index feeff0c..f737a7e 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml | |||
@@ -259,6 +259,11 @@ | |||
259 | userdata="appearance" /> | 259 | userdata="appearance" /> |
260 | <on_enable function="Edit.EnableCustomizeAvatar" /> | 260 | <on_enable function="Edit.EnableCustomizeAvatar" /> |
261 | </menu_item_call> | 261 | </menu_item_call> |
262 | <menu_item_call bottom="-362" enabled="true" height="19" label="Display Name..." left="0" | ||
263 | mouse_opaque="true" name="Display Name..." width="153"> | ||
264 | <on_click function="ShowFloater" userdata="displayname" /> | ||
265 | <on_enable function="Edit.EnableDisplayName" /> | ||
266 | </menu_item_call> | ||
262 | <menu_item_separator /> | 267 | <menu_item_separator /> |
263 | <menu_item_check name="Friends" label="Friends" | 268 | <menu_item_check name="Friends" label="Friends" |
264 | shortcut="control|shift|F"> | 269 | shortcut="control|shift|F"> |
diff --git a/linden/indra/newview/skins/default/xui/en-us/notifications.xml b/linden/indra/newview/skins/default/xui/en-us/notifications.xml index 63e85c4..d02f1b3 100644 --- a/linden/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/linden/indra/newview/skins/default/xui/en-us/notifications.xml | |||
@@ -5237,6 +5237,88 @@ The string [STRING_NAME] is missing from strings.xml | |||
5237 | </notification> | 5237 | </notification> |
5238 | 5238 | ||
5239 | <notification | 5239 | <notification |
5240 | icon="alertmodal.tga" | ||
5241 | name="SetDisplayNameSuccess" | ||
5242 | type="alert"> | ||
5243 | Hi [DISPLAY_NAME]! | ||
5244 | |||
5245 | Just like in real life, it takes a while for everyone to learn about a new name. Please allow several days for your name to update in objects, scripts, search, etc. | ||
5246 | </notification> | ||
5247 | |||
5248 | <notification | ||
5249 | icon="alertmodal.tga" | ||
5250 | name="SetDisplayNameBlocked" | ||
5251 | type="alert"> | ||
5252 | Sorry, you cannot change your display name. If you feel this is in error, please contact support. | ||
5253 | </notification> | ||
5254 | |||
5255 | <notification | ||
5256 | icon="alertmodal.tga" | ||
5257 | name="SetDisplayNameFailedLength" | ||
5258 | type="alertmodal"> | ||
5259 | Sorry, that name is too long. Display names can have a maximum of [LENGTH] characters. | ||
5260 | |||
5261 | Please try a shorter name. | ||
5262 | </notification> | ||
5263 | |||
5264 | <notification | ||
5265 | icon="alertmodal.tga" | ||
5266 | name="SetDisplayNameFailedGeneric" | ||
5267 | type="alertmodal"> | ||
5268 | Sorry, we could not set your display name. Please try again later. | ||
5269 | </notification> | ||
5270 | |||
5271 | <notification | ||
5272 | icon="alertmodal.tga" | ||
5273 | name="SetDisplayNameMismatch" | ||
5274 | type="alertmodal"> | ||
5275 | The display names you entered do not match. Please re-enter. | ||
5276 | </notification> | ||
5277 | |||
5278 | <!-- *NOTE: This should never happen --> | ||
5279 | <notification | ||
5280 | icon="alertmodal.tga" | ||
5281 | name="AgentDisplayNameUpdateThresholdExceeded" | ||
5282 | type="alertmodal"> | ||
5283 | Sorry, you have to wait longer before you can change your display name. | ||
5284 | |||
5285 | See http://wiki.secondlife.com/wiki/Setting_your_display_name | ||
5286 | |||
5287 | Please try again later. | ||
5288 | </notification> | ||
5289 | |||
5290 | <notification | ||
5291 | icon="alertmodal.tga" | ||
5292 | name="AgentDisplayNameSetBlocked" | ||
5293 | type="alertmodal"> | ||
5294 | Sorry, we could not set your requested name because it contains a banned word. | ||
5295 | |||
5296 | Please try a different name. | ||
5297 | </notification> | ||
5298 | |||
5299 | <notification | ||
5300 | icon="alertmodal.tga" | ||
5301 | name="AgentDisplayNameSetInvalidUnicode" | ||
5302 | type="alertmodal"> | ||
5303 | The display name you wish to set contains invalid characters. | ||
5304 | </notification> | ||
5305 | |||
5306 | <notification | ||
5307 | icon="alertmodal.tga" | ||
5308 | name="AgentDisplayNameSetOnlyPunctuation" | ||
5309 | type="alertmodal"> | ||
5310 | Your display name must contain letters other than punctuation. | ||
5311 | </notification> | ||
5312 | |||
5313 | |||
5314 | <notification | ||
5315 | icon="notifytip.tga" | ||
5316 | name="DisplayNameUpdate" | ||
5317 | type="notifytip"> | ||
5318 | [OLD_NAME] ([SLID]) is now known as [NEW_NAME]. | ||
5319 | </notification> | ||
5320 | |||
5321 | <notification | ||
5240 | icon="notifytip.tga" | 5322 | icon="notifytip.tga" |
5241 | name="Cancelled" | 5323 | name="Cancelled" |
5242 | type="notifytip"> | 5324 | type="notifytip"> |
@@ -6874,7 +6956,7 @@ GRAVITY -- -9.8 | |||
6874 | 6956 | ||
6875 | * -- Multiplication | 6957 | * -- Multiplication |
6876 | \ -- Division | 6958 | \ -- Division |
6877 | + -- Addition | 6959 | -- Addition |
6878 | - -- Subtraction | 6960 | - -- Subtraction |
6879 | 6961 | ||
6880 | For information about this feature, click "More Info". | 6962 | For information about this feature, click "More Info". |
@@ -6903,7 +6985,7 @@ GLOW -- Glow | |||
6903 | 6985 | ||
6904 | * -- Multiplication | 6986 | * -- Multiplication |
6905 | \ -- Division | 6987 | \ -- Division |
6906 | + -- Addition | 6988 | -- Addition |
6907 | - -- Subtraction | 6989 | - -- Subtraction |
6908 | 6990 | ||
6909 | For information about this feature, click "More Info". | 6991 | For information about this feature, click "More Info". |
diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_avatar.xml b/linden/indra/newview/skins/default/xui/en-us/panel_avatar.xml index 0df65e7..f459e6a 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_avatar.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_avatar.xml | |||
@@ -127,6 +127,11 @@ | |||
127 | font="SansSerifSmall" height="16" is_unicode="false" left="12" | 127 | font="SansSerifSmall" height="16" is_unicode="false" left="12" |
128 | max_length="254" mouse_opaque="false" name="name" | 128 | max_length="254" mouse_opaque="false" name="name" |
129 | width="155" /> | 129 | width="155" /> |
130 | <name_editor bevel_style="in" border_style="line" visible="false" | ||
131 | border_thickness="1" bottom="-24" enabled="false" follows="left|top" | ||
132 | font="SansSerifSmall" height="16" is_unicode="false" left_delta="0" | ||
133 | max_length="254" mouse_opaque="false" name="complete_name" | ||
134 | width="155" /> | ||
130 | <button bottom_delta="0" font="SansSerif" halign="center" height="20" | 135 | <button bottom_delta="0" font="SansSerif" halign="center" height="20" |
131 | label="Copy Key" label_selected="Copy Key" | 136 | label="Copy Key" label_selected="Copy Key" |
132 | left_delta="157" mouse_opaque="true" name="btn_copy_uuid" width="80" /> | 137 | left_delta="157" mouse_opaque="true" name="btn_copy_uuid" width="80" /> |