aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--linden/etc/message.xml20
-rw-r--r--linden/indra/llcommon/CMakeLists.txt2
-rw-r--r--linden/indra/llcommon/llavatarname.cpp150
-rw-r--r--linden/indra/llcommon/llavatarname.h105
-rw-r--r--linden/indra/llmessage/CMakeLists.txt2
-rw-r--r--linden/indra/llmessage/llavatarnamecache.cpp859
-rw-r--r--linden/indra/llmessage/llavatarnamecache.h105
-rw-r--r--linden/indra/llmessage/llcachename.h2
-rw-r--r--linden/indra/newview/CMakeLists.txt4
-rw-r--r--linden/indra/newview/app_settings/settings.xml36
-rw-r--r--linden/indra/newview/llappviewer.cpp73
-rw-r--r--linden/indra/newview/llappviewer.h1
-rw-r--r--linden/indra/newview/llcallingcard.cpp50
-rw-r--r--linden/indra/newview/llcallingcard.h3
-rw-r--r--linden/indra/newview/llfloateractivespeakers.cpp7
-rw-r--r--linden/indra/newview/llfloateractivespeakers.h3
-rw-r--r--linden/indra/newview/llfloateravatarinfo.cpp10
-rw-r--r--linden/indra/newview/llfloateravatarinfo.h4
-rw-r--r--linden/indra/newview/llfloaterchatterbox.cpp3
-rw-r--r--linden/indra/newview/llfloaterdisplayname.cpp224
-rw-r--r--linden/indra/newview/llfloaterdisplayname.h48
-rw-r--r--linden/indra/newview/llfloaterfriends.cpp75
-rw-r--r--linden/indra/newview/llfloaternewim.cpp20
-rw-r--r--linden/indra/newview/llhoverview.cpp21
-rw-r--r--linden/indra/newview/llimpanel.cpp66
-rw-r--r--linden/indra/newview/llimpanel.h6
-rw-r--r--linden/indra/newview/llnamelistctrl.cpp46
-rw-r--r--linden/indra/newview/llnamelistctrl.h5
-rw-r--r--linden/indra/newview/llnetmap.cpp25
-rw-r--r--linden/indra/newview/llpanelavatar.cpp42
-rw-r--r--linden/indra/newview/llpanelavatar.h4
-rw-r--r--linden/indra/newview/llstartup.cpp6
-rw-r--r--linden/indra/newview/llviewercontrol.cpp27
-rw-r--r--linden/indra/newview/llviewerdisplayname.cpp208
-rw-r--r--linden/indra/newview/llviewerdisplayname.h53
-rw-r--r--linden/indra/newview/llviewermenu.cpp17
-rwxr-xr-xlinden/indra/newview/llviewermessage.cpp27
-rw-r--r--linden/indra/newview/llviewerregion.cpp17
-rw-r--r--linden/indra/newview/llviewerregion.h6
-rw-r--r--linden/indra/newview/llvoavatar.cpp80
-rw-r--r--linden/indra/newview/llvoavatar.h5
-rw-r--r--linden/indra/newview/skins/default/xui/en-us/floater_display_name.xml42
-rw-r--r--linden/indra/newview/skins/default/xui/en-us/floater_new_im.xml5
-rw-r--r--linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml5
-rw-r--r--linden/indra/newview/skins/default/xui/en-us/notifications.xml86
-rw-r--r--linden/indra/newview/skins/default/xui/en-us/panel_avatar.xml5
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
35bool LLAvatarName::sOmitResidentAsLastName = false;
36
37// Store these in pre-built std::strings to avoid memory allocations in
38// LLSD map lookups
39static const std::string USERNAME("username");
40static const std::string DISPLAY_NAME("display_name");
41static const std::string LEGACY_FIRST_NAME("legacy_first_name");
42static const std::string LEGACY_LAST_NAME("legacy_last_name");
43static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default");
44static const std::string DISPLAY_NAME_EXPIRES("display_name_expires");
45static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update");
46
47LLAvatarName::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
58bool 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
66LLSD 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
79void 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
92std::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
107std::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
120std::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
33class LLSD;
34
35class LL_COMMON_API LLAvatarName
36{
37public:
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(
22set(llmessage_SOURCE_FILES 22set(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
42namespace 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
164class LLAvatarNameResponder : public LLHTTPClient::Responder
165{
166private:
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
174public:
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
328void 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
353void 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
412void 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
428void 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
449void LLAvatarNameCache::initClass(bool running)
450{
451 sRunning = running;
452}
453
454void LLAvatarNameCache::cleanupClass()
455{
456}
457
458void 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
483void 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
502void LLAvatarNameCache::setNameLookupURL(const std::string& name_lookup_url)
503{
504 sNameLookupURL = name_lookup_url;
505}
506
507bool LLAvatarNameCache::hasNameLookupURL()
508{
509 return !sNameLookupURL.empty();
510}
511
512void 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
554bool 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
569void 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
585void 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
598bool 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
643void 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
652void 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
712void 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
731U32 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
744void LLAvatarNameCache::erase(const LLUUID& agent_id)
745{
746 sCache.erase(agent_id);
747}
748
749void LLAvatarNameCache::fetch(const LLUUID& agent_id)
750{
751 // re-request, even if request is already pending
752 sAskQueue.insert(agent_id);
753}
754
755void 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
761F64 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
777bool 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
796void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb)
797{
798 mUseDisplayNamesSignal.connect(cb);
799}
800
801
802static const std::string MAX_AGE("max-age");
803static const boost::char_separator<char> EQUALS_SEPARATOR("=");
804static const boost::char_separator<char> COMMA_SEPARATOR(",");
805
806bool 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
38class LLSD;
39class LLUUID;
40
41namespace 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.
103bool 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
36class LLMessageSystem; 38class LLMessageSystem;
37class LLHost; 39class LLHost;
38class LLUUID; 40class 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
3301void LLAppViewer::loadNameCache() 3302void 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
3323void LLAppViewer::saveNameCache() 3332void 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
3929void 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
792void 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
93void LLSpeaker::lookupName() 93void 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
99void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* user_data) 99void 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
244void LLFloaterAvatarInfo::callbackLoadAvatarName(const LLUUID& id, 244void 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
98private: 98private:
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()
218void LLFloaterChatterBox::onOpen() 219void 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
223void LLFloaterChatterBox::onClose(bool app_quitting) 226void 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
44LLFloaterDisplayName* LLFloaterDisplayName::sInstance = NULL;
45
46LLFloaterDisplayName::LLFloaterDisplayName() : LLFloater(std::string("Display Name"))
47{
48 LLUICtrlFactory::getInstance()->buildFloater(this, "floater_display_name.xml");
49 LLFloaterDisplayName::sInstance = this;
50}
51
52LLFloaterDisplayName::~LLFloaterDisplayName()
53{
54 LLFloaterDisplayName::sInstance = NULL;
55}
56
57void LLFloaterDisplayName::show()
58{
59 if (!LLFloaterDisplayName::sInstance)
60 {
61 LLFloaterDisplayName::sInstance = new LLFloaterDisplayName();
62 }
63 LLFloaterDisplayName::sInstance->open();
64}
65
66void 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
109BOOL 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
120void 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
166void LLFloaterDisplayName::onCancel(void* data)
167{
168 LLFloaterDisplayName* self = (LLFloaterDisplayName*)data;
169 self->setVisible(false);
170}
171
172void 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
190void 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
30class LLFloaterDisplayName : public LLFloater
31{
32public:
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
42private:
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
41S32 COL_1_WIDTH = 200; 41S32 COL_1_WIDTH = 400;
42 42
43static std::string sOnlineDescriptor = "*"; 43static std::string sOnlineDescriptor = "*";
44static std::string sNameFormat = "[FIRST] [LAST]";
45 44
46LLFloaterNewIM::LLFloaterNewIM() 45LLFloaterNewIM::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
136void LLFloaterNewIM::addAgent(const LLUUID& uuid, void* data, BOOL online) 134void 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
107BOOL LLVoiceChannel::sSuspended = FALSE; 107BOOL LLVoiceChannel::sSuspended = FALSE;
108 108
109std::set<LLFloaterIMPanel*> LLFloaterIMPanel::sFloaterIMPanels;
110
109void session_starter_helper( 111void 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(
1149void LLFloaterIMPanel::init(const std::string& session_label) 1152void 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
1264void LLFloaterIMPanel::lookupName()
1265{
1266 LLAvatarNameCache::get(mOtherParticipantUUID, boost::bind(&LLFloaterIMPanel::onAvatarNameLookup, _1, _2, this));
1267}
1268
1269//static
1270void 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
1257LLFloaterIMPanel::~LLFloaterIMPanel() 1286LLFloaterIMPanel::~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
1553void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4& color, bool log_to_file, const LLUUID& source, const std::string& name) 1584void 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
43static LLRegisterWidget<LLNameListCtrl> r("name_list"); 44static 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 467bool 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
87private: 89private:
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
1509void 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
1484void LLPanelAvatar::resetGroupList() 1526void 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
431static bool handleDisplayNamesUsageChanged(const LLSD& newvalue)
432{
433 LLAvatarNameCache::setUseDisplayNames((U32)newvalue.asInteger());
434 LLVOAvatar::invalidateNameTags();
435 LLAvatarTracker::instance().dirtyBuddies();
436 return true;
437}
438
439static bool handleOmitResidentAsLastNameChanged(const LLSD& newvalue)
440{
441 LLAvatarName::sOmitResidentAsLastName =(bool)newvalue.asBoolean();
442 LLVOAvatar::invalidateNameTags();
443 LLAvatarTracker::instance().dirtyBuddies();
444 return true;
445}
446
447static bool handleLegacyNamesForFriendsChanged(const LLSD& newvalue)
448{
449 LLAvatarTracker::instance().dirtyBuddies();
450 return true;
451}
452
429static bool handleRenderDebugGLChanged(const LLSD& newvalue) 453static 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
43namespace 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
58class LLSetDisplayNameResponder : public LLHTTPClient::Responder
59{
60public:
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
69void 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
116class LLSetDisplayNameReply : public LLHTTPNode
117{
118 LOG_CLASS(LLSetDisplayNameReply);
119public:
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
156class 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
202LLHTTPRegistration<LLSetDisplayNameReply>
203 gHTTPRegistrationMessageSetDisplayNameReply(
204 "/message/SetDisplayNameReply");
205
206LLHTTPRegistration<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
32class LLSD;
33class LLUUID;
34
35namespace 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
3439class 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
3438bool handle_sit_or_stand() 3450bool 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
1517bool LLViewerRegion::capabilitiesReceived() const
1518{
1519 return mCapabilitiesReceived;
1520}
1521
1522void LLViewerRegion::setCapabilitiesReceived(bool received)
1523{
1524 mCapabilitiesReceived = received;
1525}
1526
1512void LLViewerRegion::logActiveCapabilities() const 1527void 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
400private: 405private:
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
3857void LLVOAvatar::clearNameTag()
3858{
3859 mNameString.clear();
3860 if (mNameText)
3861 {
3862 mNameText->setLabel("");
3863 mNameText->setString(mNameString);
3864 }
3865}
3866
3867//static
3868void 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
3880void 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
3827void LLVOAvatar::idleUpdateTractorBeam() 3893void 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">
5243Hi [DISPLAY_NAME]!
5244
5245Just 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">
5252Sorry, 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">
5259Sorry, that name is too long. Display names can have a maximum of [LENGTH] characters.
5260
5261Please 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">
5283Sorry, you have to wait longer before you can change your display name.
5284
5285See http://wiki.secondlife.com/wiki/Setting_your_display_name
5286
5287Please 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
6880For information about this feature, click "More Info". 6962For 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
6909For information about this feature, click "More Info". 6991For 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" />