llviewerdisplayname.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. #include "llviewerprecompiledheaders.h"
  27. #include "llviewerdisplayname.h"
  28. #include "llavatarnamecache.h"
  29. #include "llcorehttputil.h"
  30. #include "llhttpnode.h"
  31. #include "llnotifications.h"
  32. #include "llagent.h"
  33. #include "llvoavatar.h"
  34. namespace LLViewerDisplayName
  35. {
  36. // Fired when viewer receives server response to display name change
  37. set_name_signal_t sSetDisplayNameSignal;
  38. void setCoro(const std::string& url, const LLSD& change_array);
  39. }
  40. void LLViewerDisplayName::setCoro(const std::string& url,
  41. const LLSD& change_array)
  42. {
  43. LLSD body;
  44. body["display_name"] = change_array;
  45. LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions);
  46. // People API can return localized error messages. Indicate our language
  47. // preference via header.
  48. LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders);
  49. headers->append(HTTP_OUT_HEADER_ACCEPT_LANGUAGE, LLUI::getLanguage());
  50. LLCoreHttpUtil::HttpCoroutineAdapter adapter("setDisplayName");
  51. LLSD result = adapter.postAndSuspend(url, body, options, headers);
  52. LLCore::HttpStatus status =
  53. LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
  54. // We only care about errors
  55. if (!status)
  56. {
  57. llwarns << "Error: " << status.toString() << llendl;
  58. sSetDisplayNameSignal(false, "", LLSD());
  59. sSetDisplayNameSignal.disconnect_all_slots();
  60. }
  61. }
  62. void LLViewerDisplayName::set(const std::string& display_name,
  63. const set_name_slot_t& slot)
  64. {
  65. const std::string& cap_url = gAgent.getRegionCapability("SetDisplayName");
  66. if (cap_url.empty())
  67. {
  68. // This server does not support display names, report error
  69. slot(false, "unsupported", LLSD());
  70. return;
  71. }
  72. // People API requires both the old and new value to change a variable.
  73. // Our display name will be in cache before the viewer's UI is available
  74. // to request a change, so we can use direct lookup without callback.
  75. LLAvatarName av_name;
  76. if (!LLAvatarNameCache::get(gAgentID, &av_name))
  77. {
  78. slot(false, "name unavailable", LLSD());
  79. return;
  80. }
  81. // People API expects array of [ "old value", "new value" ]
  82. LLSD change_array = LLSD::emptyArray();
  83. change_array.append(av_name.mDisplayName);
  84. change_array.append(display_name);
  85. llinfos << "Set name POST to " << cap_url << llendl;
  86. // Record our caller for when the server sends back a reply
  87. sSetDisplayNameSignal.connect(slot);
  88. // POST the requested change. The sim will not send a response back to
  89. // this request directly, rather it will send a separate message after it
  90. // communicates with the back-end.
  91. gCoros.launch("setDisplayNameCoro",
  92. boost::bind(&LLViewerDisplayName::setCoro, cap_url,
  93. change_array));
  94. }
  95. class LLSetDisplayNameReply final : public LLHTTPNode
  96. {
  97. protected:
  98. LOG_CLASS(LLSetDisplayNameReply);
  99. public:
  100. void post(LLHTTPNode::ResponsePtr response, const LLSD& context,
  101. const LLSD& input) const override
  102. {
  103. LLSD body = input["body"];
  104. S32 status = body["status"].asInteger();
  105. std::string reason = body["reason"].asString();
  106. LLSD content = body["content"];
  107. bool success = status == HTTP_OK;
  108. if (!success)
  109. {
  110. llwarns << "Status: " << status << " - Reason: " << reason
  111. << llendl;
  112. }
  113. // If viewer's concept of display name is out-of-date, the set request
  114. // will fail with 409 Conflict. If that happens, fetch up-to-date name
  115. // information.
  116. if (status == HTTP_CONFLICT)
  117. {
  118. LLUUID agent_id = gAgentID;
  119. // Flush stale data
  120. LLAvatarNameCache::erase(agent_id);
  121. // Queue request for new data
  122. LLAvatarName ignored;
  123. LLAvatarNameCache::get(agent_id, &ignored);
  124. // Kill name tag, as it is wrong
  125. LLVOAvatar::invalidateNameTag(agent_id);
  126. }
  127. // inform caller of result
  128. LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content);
  129. LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
  130. }
  131. };
  132. class LLDisplayNameUpdate final : public LLHTTPNode
  133. {
  134. protected:
  135. LOG_CLASS(LLDisplayNameUpdate);
  136. public:
  137. void post(LLHTTPNode::ResponsePtr response, const LLSD& context,
  138. const LLSD& input) const override
  139. {
  140. LLSD body = input["body"];
  141. LLUUID agent_id = body["agent_id"];
  142. std::string old_display_name = body["old_display_name"];
  143. // By convention this record is called "agent" in the People API
  144. LLSD name_data = body["agent"];
  145. // Inject the new name data into cache
  146. LLAvatarName av_name;
  147. av_name.fromLLSD(name_data);
  148. if (agent_id == gAgentID)
  149. {
  150. llinfos << "Next display name change allowed after: "
  151. << LLDate(av_name.mNextUpdate) << llendl;
  152. }
  153. // Name expiration time may be provided in headers, or we may use a
  154. // default value
  155. // *TODO: get actual headers out of ResponsePtr
  156. //LLSD headers = response->mHeaders;
  157. LLSD headers;
  158. av_name.mExpires = LLAvatarNameCache::nameExpirationFromHeaders(headers);
  159. LLAvatarNameCache::insert(agent_id, av_name);
  160. // force name tag to update
  161. LLVOAvatar::invalidateNameTag(agent_id);
  162. LLSD args;
  163. args["OLD_NAME"] = old_display_name;
  164. args["LEGACY_NAME"] = av_name.getLegacyName();
  165. args["NEW_NAME"] = av_name.mDisplayName;
  166. gNotifications.add("DisplayNameUpdate", args);
  167. }
  168. };
  169. LLHTTPRegistration<LLSetDisplayNameReply>
  170. gHTTPRegistrationMessageSetDisplayNameReply("/message/SetDisplayNameReply");
  171. LLHTTPRegistration<LLDisplayNameUpdate>
  172. gHTTPRegistrationMessageDisplayNameUpdate("/message/DisplayNameUpdate");