llavatarproperties.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. /**
  2. * @file llavatarproperties.cpp
  3. * @brief Class for requesting and storing avatar properties.
  4. *
  5. * $LicenseInfo:firstyear=2004&license=viewergpl$
  6. *
  7. * Copyright (c) 2004-2022, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llavatarproperties.h"
  34. #include "lldate.h"
  35. #include "llcorehttputil.h"
  36. #include "llagent.h"
  37. #include "llappviewer.h" // For gFrameTimeSeconds
  38. #include "llviewermessage.h" // For send_generic_message()
  39. #include "llviewercontrol.h"
  40. // Static member variables
  41. LLAvatarProperties::observers_set_t LLAvatarProperties::sObservers;
  42. LLAvatarProperties::pending_map_t LLAvatarProperties::sPendingRequests;
  43. //static
  44. void LLAvatarProperties::addPendingRequest(const LLUUID& id, S32 type)
  45. {
  46. pending_map_t::key_type key = std::make_pair(id, type);
  47. sPendingRequests[key] = gFrameTimeSeconds;
  48. }
  49. //static
  50. void LLAvatarProperties::removePendingRequest(const LLUUID& id, S32 type)
  51. {
  52. pending_map_t::key_type key = std::make_pair(id, type);
  53. sPendingRequests.erase(key);
  54. }
  55. //static
  56. bool LLAvatarProperties::isPendingRequest(const LLUUID& id, S32 type)
  57. {
  58. pending_map_t::key_type key = std::make_pair(id, type);
  59. pending_map_t::iterator it = sPendingRequests.find(key);
  60. if (it == sPendingRequests.end())
  61. {
  62. return false;
  63. }
  64. constexpr F32 REQUEST_EXPIRE_SECS = 5.f; // 5s timeout.
  65. return it->second + REQUEST_EXPIRE_SECS > gFrameTimeSeconds;
  66. }
  67. //static
  68. void LLAvatarProperties::notifyObservers(const LLUUID& id, S32 type,
  69. void* data)
  70. {
  71. // This request is no more pending. Do this before calling observers, so
  72. // that they may relaunch a request immediately if needed, and it *is*
  73. // needed to recover the Interests data via UDP when using the capability
  74. // to get the main porperties: see LLPanelAvatar::processProperties(). HB
  75. if (type > APT_NONE)
  76. {
  77. removePendingRequest(id, type);
  78. }
  79. // Note: observers could remove themselves following a call to their
  80. // processProperties() method, so we need to build the list of the
  81. // observers to call *before* calling each observer method... HB
  82. std::vector<LLAvatarPropertiesObserver*> observers;
  83. for (observers_set_t::iterator it = sObservers.begin(),
  84. end = sObservers.end();
  85. it != end; ++it)
  86. {
  87. LLAvatarPropertiesObserver* obsp = *it;
  88. // Check if of the right observed update type.
  89. S32 update_type = obsp->getUpdateType();
  90. if (update_type == APT_NONE ||
  91. (update_type != APT_ALL && update_type != type))
  92. {
  93. continue;
  94. }
  95. // Add to the list of observers to call if the avatar Id matches.
  96. const LLUUID& observed_id = obsp->getAvatarId();
  97. if (observed_id.isNull() || observed_id == id)
  98. {
  99. observers.push_back(obsp);
  100. }
  101. }
  102. // Now, do call the interested observers.
  103. for (U32 i = 0, count = observers.size(); i < count; ++i)
  104. {
  105. observers[i]->processProperties(type, data);
  106. }
  107. }
  108. //static
  109. void LLAvatarProperties::sendGenericRequest(const LLUUID& avatar_id, S32 type)
  110. {
  111. if (type != APT_AVATAR_INFO && (type < APT_GROUPS || type > APT_NOTES))
  112. {
  113. llerrs << "Invalid request type: " << type << llendl;
  114. }
  115. if (isPendingRequest(avatar_id, type))
  116. {
  117. LL_DEBUGS("AvatarProperties") << "Skipping duplicate request type "
  118. << type << " for avatar " << avatar_id
  119. << LL_ENDL;
  120. return;
  121. }
  122. if (type != APT_CLASSIFIEDS &&
  123. gSavedSettings.getBool("UseAgentProfileCap"))
  124. {
  125. std::string url = gAgent.getRegionCapability("AgentProfile");
  126. if (!url.empty())
  127. {
  128. LL_DEBUGS("AvatarProperties") << "Using AgentProfile capability to retrieve data for avatar: "
  129. << avatar_id << LL_ENDL;
  130. addPendingRequest(avatar_id, APT_GROUPS);
  131. addPendingRequest(avatar_id, APT_PICKS);
  132. addPendingRequest(avatar_id, APT_NOTES);
  133. addPendingRequest(avatar_id, APT_AVATAR_INFO);
  134. url += "/" + avatar_id.asString();
  135. gCoros.launch("requestAgentUserInfoCoro",
  136. boost::bind(requestAvatarPropertiesCoro, avatar_id,
  137. url));
  138. // Also request an agent groups list refresh for LLAgent. HB
  139. if (avatar_id == gAgentID)
  140. {
  141. gAgent.sendAgentDataUpdateRequest();
  142. }
  143. return;
  144. }
  145. }
  146. if (type == APT_AVATAR_INFO)
  147. {
  148. sendAvatarPropertiesRequest(avatar_id);
  149. return;
  150. }
  151. addPendingRequest(avatar_id, type);
  152. // Must match the order defined in EAvatarPropertiesUpdateType
  153. static const char* udp_methods[] =
  154. {
  155. "avatargroupsrequest", // APT_GROUPS
  156. "avatarpicksrequest", // APT_PICKS
  157. "avatarclassifiedsrequest", // APT_CLASSIFIEDS
  158. "avatarnotesrequest", // APT_NOTES
  159. };
  160. const char* method = udp_methods[type - APT_GROUPS];
  161. LL_DEBUGS("AvatarProperties") << "Sending UDP request \"" << method
  162. << "\" for avatar: " << avatar_id << LL_ENDL;
  163. std::vector<std::string> params;
  164. params.emplace_back(avatar_id.asString());
  165. send_generic_message(method, params);
  166. // When requesting groups data for our agent, also request an agent groups
  167. // list refresh for LLAgent. HB
  168. if (type == APT_GROUPS && avatar_id == gAgentID)
  169. {
  170. gAgent.sendAgentDataUpdateRequest();
  171. }
  172. }
  173. //static
  174. void LLAvatarProperties::requestAvatarPropertiesCoro(LLUUID avatar_id,
  175. const std::string& url)
  176. {
  177. LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions);
  178. options->setFollowRedirects(true);
  179. LLCoreHttpUtil::HttpCoroutineAdapter adapter("requestAvatarPropertiesCoro");
  180. LLSD result = adapter.getAndSuspend(url, options);
  181. LLCore::HttpStatus status =
  182. LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
  183. if (!status || !result.has("id") || result["id"].asUUID() != avatar_id)
  184. {
  185. llwarns << "Failed to retrieve data for avatar: " << avatar_id
  186. << llendl;
  187. if (!status)
  188. {
  189. llwarns << "Error: " << status.toString() << llendl;
  190. }
  191. removePendingRequest(avatar_id, APT_GROUPS);
  192. removePendingRequest(avatar_id, APT_PICKS);
  193. removePendingRequest(avatar_id, APT_NOTES);
  194. removePendingRequest(avatar_id, APT_AVATAR_INFO);
  195. // *TODO: fall back to UDP methods ?
  196. return;
  197. }
  198. LL_DEBUGS("AvatarProperties") << "Received properties via capability for avatar: "
  199. << avatar_id << LL_ENDL;
  200. // Generic avatar data
  201. LLAvatarInfo avatar_data;
  202. avatar_data.mReceivedViaCap = true;
  203. avatar_data.mAvatarId = avatar_id;
  204. avatar_data.mImageId = result["sl_image_id"].asUUID();
  205. avatar_data.mFLImageId = result["fl_image_id"].asUUID();
  206. avatar_data.mPartnerId = result["partner_id"].asUUID();
  207. avatar_data.mBirthDate = result["member_since"].asDate().asString();
  208. tm t;
  209. if (sscanf(avatar_data.mBirthDate.c_str(), "%u-%u-%u",
  210. &t.tm_year, &t.tm_mon, &t.tm_mday) == 3 && t.tm_year > 1900)
  211. {
  212. t.tm_year -= 1900;
  213. --t.tm_mon;
  214. t.tm_hour = t.tm_min = t.tm_sec = 0;
  215. timeStructToFormattedString(&t,
  216. gSavedSettings.getString("ShortDateFormat"),
  217. avatar_data.mBirthDate);
  218. }
  219. avatar_data.mAbout = result["sl_about_text"].asString();
  220. avatar_data.mFLAbout = result["fl_about_text"].asString();
  221. // The Web URL is not provided by the new capability... HB
  222. avatar_data.mProfileUrl.clear();
  223. avatar_data.mFlags = 0;
  224. if (result["online"].asBoolean())
  225. {
  226. avatar_data.mFlags |= AVATAR_ONLINE;
  227. }
  228. if (result["allow_publish"].asBoolean())
  229. {
  230. avatar_data.mFlags |= AVATAR_ALLOW_PUBLISH;
  231. avatar_data.mAllowPublish = true;
  232. }
  233. else
  234. {
  235. avatar_data.mAllowPublish = false;
  236. }
  237. if (result["online"].asBoolean())
  238. {
  239. avatar_data.mFlags |= AVATAR_ONLINE;
  240. }
  241. if (result["identified"].asBoolean())
  242. {
  243. avatar_data.mFlags |= AVATAR_IDENTIFIED;
  244. }
  245. if (result["transacted"].asBoolean())
  246. {
  247. avatar_data.mFlags |= AVATAR_TRANSACTED;
  248. }
  249. if (result.has("charter_member")) // Not present when "caption" is set
  250. {
  251. avatar_data.mCaptionIndex = result["charter_member"].asInteger();
  252. }
  253. else if (result.has("caption"))
  254. {
  255. avatar_data.mCaptionText = result["caption"].asString();
  256. avatar_data.mCaptionIndex = 0;
  257. }
  258. notifyObservers(avatar_id, APT_AVATAR_INFO, (void*)&avatar_data);
  259. // Avatar picks
  260. LLAvatarPicks avatar_picks;
  261. avatar_picks.mReceivedViaCap = true;
  262. avatar_picks.mAvatarId = avatar_id;
  263. LLSD picks_array = result["picks"];
  264. for (LLSD::array_const_iterator it = picks_array.beginArray(),
  265. end = picks_array.endArray();
  266. it != end; ++it)
  267. {
  268. const LLSD& pick_data = *it;
  269. avatar_picks.mMap.emplace(pick_data["id"].asUUID(),
  270. pick_data["name"].asString());
  271. }
  272. notifyObservers(avatar_id, APT_PICKS, (void*)&avatar_picks);
  273. // Avatar groups
  274. LLAvatarGroups avatar_groups;
  275. avatar_groups.mAvatarId = avatar_id;
  276. LLSD groups_array = result["groups"];
  277. for (LLSD::array_const_iterator it = groups_array.beginArray(),
  278. end = groups_array.endArray();
  279. it != end; ++it)
  280. {
  281. const LLSD& group_info = *it;
  282. LLGroupData group_data(group_info["id"].asUUID(),
  283. group_info["name"].asString(), 0);
  284. group_data.mInsigniaID = group_info["image_id"].asUUID();
  285. avatar_groups.mGroups.emplace_back(group_data);
  286. }
  287. notifyObservers(avatar_id, APT_GROUPS, (void*)&avatar_groups);
  288. // Notes
  289. LLAvatarNotes avatar_notes;
  290. avatar_notes.mReceivedViaCap = true;
  291. avatar_notes.mAvatarId = avatar_id;
  292. avatar_notes.mNotes = result["notes"].asString();
  293. notifyObservers(avatar_id, APT_NOTES, (void*)&avatar_notes);
  294. }
  295. //static
  296. void LLAvatarProperties::sendAvatarPropertiesRequest(const LLUUID& avatar_id)
  297. {
  298. LLMessageSystem* msg = gMessageSystemp;
  299. if (!msg) return; // Paranoia
  300. if (isPendingRequest(avatar_id, APT_AVATAR_INFO))
  301. {
  302. LL_DEBUGS("AvatarProperties") << "Skipping duplicate request for avatar "
  303. << avatar_id << LL_ENDL;
  304. return;
  305. }
  306. addPendingRequest(avatar_id, APT_AVATAR_INFO);
  307. msg->newMessageFast(_PREHASH_AvatarPropertiesRequest);
  308. msg->nextBlockFast(_PREHASH_AgentData);
  309. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  310. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  311. msg->addUUIDFast(_PREHASH_AvatarID, avatar_id);
  312. gAgent.sendReliableMessage();
  313. }
  314. //static
  315. void LLAvatarProperties::processAvatarPropertiesReply(LLMessageSystem* msg,
  316. void**)
  317. {
  318. if (!msg) return; // Paranoia
  319. LLUUID agent_id;
  320. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  321. if (agent_id != gAgentID)
  322. {
  323. llwarns << "Agent ID mismatch. Got: " << agent_id << llendl;
  324. return;
  325. }
  326. LLAvatarInfo data;
  327. data.mReceivedViaCap = false;
  328. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, data.mAvatarId);
  329. LL_DEBUGS("AvatarProperties") << "Received properties via UDP for avatar: "
  330. << data.mAvatarId << LL_ENDL;
  331. msg->getUUIDFast(_PREHASH_PropertiesData, _PREHASH_ImageID, data.mImageId);
  332. msg->getUUIDFast(_PREHASH_PropertiesData, _PREHASH_FLImageID,
  333. data.mFLImageId);
  334. msg->getUUIDFast(_PREHASH_PropertiesData, _PREHASH_PartnerID,
  335. data.mPartnerId);
  336. msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_AboutText,
  337. data.mAbout);
  338. msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_FLAboutText,
  339. data.mFLAbout);
  340. msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_BornOn,
  341. data.mBirthDate);
  342. tm t;
  343. if (sscanf(data.mBirthDate.c_str(), "%u/%u/%u",
  344. &t.tm_mon, &t.tm_mday, &t.tm_year) == 3 && t.tm_year > 1900)
  345. {
  346. t.tm_year -= 1900;
  347. --t.tm_mon;
  348. t.tm_hour = t.tm_min = t.tm_sec = 0;
  349. timeStructToFormattedString(&t,
  350. gSavedSettings.getString("ShortDateFormat"),
  351. data.mBirthDate);
  352. }
  353. msg->getString(_PREHASH_PropertiesData, _PREHASH_ProfileURL,
  354. data.mProfileUrl);
  355. msg->getU32Fast(_PREHASH_PropertiesData, _PREHASH_Flags, data.mFlags);
  356. data.mCaptionIndex = 0;
  357. data.mCaptionText.clear();
  358. S32 charter_member_size = msg->getSize(_PREHASH_PropertiesData,
  359. _PREHASH_CharterMember);
  360. if (charter_member_size == 1)
  361. {
  362. msg->getBinaryData(_PREHASH_PropertiesData, _PREHASH_CharterMember,
  363. &data.mCaptionIndex, 1);
  364. }
  365. else if (charter_member_size > 1)
  366. {
  367. msg->getString(_PREHASH_PropertiesData, _PREHASH_CharterMember,
  368. data.mCaptionText);
  369. }
  370. notifyObservers(data.mAvatarId, APT_AVATAR_INFO, (void*)&data);
  371. }
  372. //static
  373. void LLAvatarProperties::sendAvatarPropertiesUpdate(const LLAvatarInfo& data)
  374. {
  375. constexpr size_t MAX_UDP_TEXT_SIZE = 510;
  376. bool try_cap = gSavedSettings.getBool("UseAgentProfileCap");
  377. bool large_sl_about = data.mAbout.size() > MAX_UDP_TEXT_SIZE;
  378. bool large_fl_about = data.mFLAbout.size() > MAX_UDP_TEXT_SIZE;
  379. if (!try_cap && (large_sl_about || large_fl_about))
  380. {
  381. llinfos << "Large About text detected; attempting to use the AgentProfile capability..."
  382. << llendl;
  383. try_cap = true;
  384. }
  385. if (try_cap)
  386. {
  387. std::string url = gAgent.getRegionCapability("AgentProfile");
  388. if (!url.empty())
  389. {
  390. llinfos << "Using AgentProfile capability to update agent info"
  391. << llendl;
  392. LLSD updates;
  393. updates["sl_about_text"] = data.mAbout;
  394. updates["fl_about_text"] = data.mFLAbout;
  395. updates["sl_image_id"] = data.mImageId;
  396. updates["fl_image_id"] = data.mFLImageId;
  397. updates["allow_publish"] = data.mAllowPublish;
  398. url += "/" + gAgentID.asString();
  399. gCoros.launch("sendAvatarPropertiesUpdateCoro",
  400. boost::bind(sendAvatarPropertiesUpdateCoro,
  401. updates, url));
  402. return;
  403. }
  404. }
  405. llinfos << "Using legacy UDP messaging to update agent info." << llendl;
  406. LLMessageSystem* msg = gMessageSystemp;
  407. if (!msg) return; // Paranoia
  408. msg->newMessageFast(_PREHASH_AvatarPropertiesUpdate);
  409. msg->nextBlockFast(_PREHASH_AgentData);
  410. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  411. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  412. msg->nextBlockFast(_PREHASH_PropertiesData);
  413. msg->addUUIDFast(_PREHASH_ImageID, data.mImageId);
  414. msg->addUUIDFast(_PREHASH_FLImageID, data.mFLImageId);
  415. std::string text = data.mAbout;
  416. if (large_sl_about)
  417. {
  418. llwarns << "Second Life 'About' text truncated to 510 characters."
  419. << llendl;
  420. text.erase(MAX_UDP_TEXT_SIZE);
  421. }
  422. msg->addStringFast(_PREHASH_AboutText, text);
  423. text = data.mFLAbout;
  424. if (large_fl_about)
  425. {
  426. llwarns << "First Life 'About' text truncated to 510 characters."
  427. << llendl;
  428. text.erase(MAX_UDP_TEXT_SIZE);
  429. }
  430. msg->addStringFast(_PREHASH_FLAboutText, text);
  431. msg->addBool(_PREHASH_AllowPublish, data.mAllowPublish);
  432. // A profile should never be mature
  433. msg->addBool(_PREHASH_MaturePublish, false);
  434. msg->addString(_PREHASH_ProfileURL, data.mProfileUrl);
  435. gAgent.sendReliableMessage();
  436. }
  437. //static
  438. void LLAvatarProperties::sendAvatarPropertiesUpdateCoro(LLSD data,
  439. const std::string& url)
  440. {
  441. LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions);
  442. options->setFollowRedirects(true);
  443. LLCoreHttpUtil::HttpCoroutineAdapter adapter("sendAvatarPropertiesUpdateCoro");
  444. LLSD result = adapter.putAndSuspend(url, data, options);
  445. LLCore::HttpStatus status =
  446. LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
  447. if (!status)
  448. {
  449. llwarns << "Error: " << status.toString() << llendl;
  450. }
  451. }
  452. //static
  453. void LLAvatarProperties::processAvatarGroupsReply(LLMessageSystem* msg, void**)
  454. {
  455. if (!msg) return; // Paranoia
  456. LL_DEBUGS("AvatarProperties") << "Groups packet size: "
  457. << msg->getReceiveSize()
  458. << LL_ENDL;
  459. LLUUID agent_id;
  460. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  461. if (agent_id != gAgentID)
  462. {
  463. llwarns << "Agent ID mismatch. Got: " << agent_id << llendl;
  464. return;
  465. }
  466. LLAvatarGroups groups;
  467. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, groups.mAvatarId);
  468. S32 group_count = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
  469. std::string name;
  470. LLUUID group_id, insignia;
  471. U64 powers;
  472. for (S32 i = 0; i < group_count; ++i)
  473. {
  474. msg->getU64(_PREHASH_GroupData, _PREHASH_GroupPowers, powers, i);
  475. #if 0 // Not used
  476. msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupTitle, title, i);
  477. #endif
  478. msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id, i);
  479. msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, name, i);
  480. msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupInsigniaID,
  481. insignia, i);
  482. if (group_id.isNull())
  483. {
  484. name.clear();
  485. }
  486. LLGroupData data(group_id, name, powers);
  487. data.mInsigniaID = insignia;
  488. groups.mGroups.emplace_back(data);
  489. }
  490. notifyObservers(groups.mAvatarId, APT_GROUPS, (void*)&groups);
  491. }
  492. //static
  493. void LLAvatarProperties::processAvatarInterestsReply(LLMessageSystem* msg,
  494. void**)
  495. {
  496. if (!msg) return; // Paranoia
  497. LLUUID agent_id;
  498. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  499. if (agent_id != gAgentID)
  500. {
  501. llwarns << "Agent ID mismatch. Got: " << agent_id << llendl;
  502. return;
  503. }
  504. LLAvatarInterests data;
  505. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, data.mAvatarId);
  506. msg->getU32Fast(_PREHASH_PropertiesData, _PREHASH_WantToMask,
  507. data.mWantsMask);
  508. msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_WantToText,
  509. data.mWantsText);
  510. msg->getU32Fast(_PREHASH_PropertiesData, _PREHASH_SkillsMask,
  511. data.mSkillsMask);
  512. msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_SkillsText,
  513. data.mSkillsText);
  514. msg->getString(_PREHASH_PropertiesData, _PREHASH_LanguagesText,
  515. data.mLanguages);
  516. notifyObservers(data.mAvatarId, APT_INTERESTS, (void*)&data);
  517. }
  518. //static
  519. void LLAvatarProperties::sendInterestsInfoUpdate(const LLAvatarInterests& data)
  520. {
  521. LLMessageSystem* msg = gMessageSystemp;
  522. if (!msg) return; // Paranoia
  523. llinfos << "Sending agent interests update" << llendl;
  524. msg->newMessage(_PREHASH_AvatarInterestsUpdate);
  525. msg->nextBlockFast(_PREHASH_AgentData);
  526. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  527. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  528. msg->nextBlockFast(_PREHASH_PropertiesData);
  529. msg->addU32Fast(_PREHASH_WantToMask, data.mWantsMask);
  530. msg->addStringFast(_PREHASH_WantToText, data.mWantsText);
  531. msg->addU32Fast(_PREHASH_SkillsMask, data.mSkillsMask);
  532. msg->addStringFast(_PREHASH_SkillsText, data.mSkillsText);
  533. msg->addString(_PREHASH_LanguagesText, data.mLanguages);
  534. gAgent.sendReliableMessage();
  535. }
  536. //static
  537. void LLAvatarProperties::processAvatarPicksReply(LLMessageSystem* msg, void**)
  538. {
  539. if (!msg) return; // Paranoia
  540. LLUUID agent_id;
  541. msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  542. if (agent_id != gAgentID)
  543. {
  544. llwarns << "Agent ID mismatch. Got: " << agent_id << llendl;
  545. return;
  546. }
  547. LLAvatarPicks picks;
  548. picks.mReceivedViaCap = false;
  549. msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, picks.mAvatarId);
  550. LLUUID pick_id;
  551. std::string pick_name;
  552. S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data);
  553. for (S32 i = 0; i < block_count; ++i)
  554. {
  555. msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_id, i);
  556. msg->getString(_PREHASH_Data, _PREHASH_PickName, pick_name, i);
  557. picks.mMap.emplace(pick_id, pick_name);
  558. }
  559. notifyObservers(picks.mAvatarId, APT_PICKS, (void*)&picks);
  560. }
  561. //static
  562. void LLAvatarProperties::sendPickInfoRequest(const LLUUID& avatar_id,
  563. const LLUUID& pick_id)
  564. {
  565. // We must ask for a pick based on the creator Id because the pick database
  566. // is distributed to the inventory cluster. JC
  567. std::vector<std::string> params;
  568. params.emplace_back(avatar_id.asString());
  569. params.emplace_back(pick_id.asString());
  570. send_generic_message("pickinforequest", params);
  571. }
  572. //static
  573. void LLAvatarProperties::processPickInfoReply(LLMessageSystem* msg, void**)
  574. {
  575. if (!msg) return; // Paranoia
  576. // Extract the agent id and verify the message is for this client.
  577. LLUUID agent_id;
  578. msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  579. if (agent_id != gAgentID)
  580. {
  581. llwarns << "Agent ID mismatch. Got agent ID " << agent_id << llendl;
  582. return;
  583. }
  584. LLAvatarPickInfo data;
  585. msg->getUUID(_PREHASH_Data, _PREHASH_PickID, data.mPickId);
  586. msg->getUUID(_PREHASH_Data, _PREHASH_CreatorID, data.mAvatarId);
  587. // Legacy. Not used any more server-side.
  588. msg->getBool(_PREHASH_Data, _PREHASH_TopPick, data.mTopPick);
  589. msg->getUUID(_PREHASH_Data, _PREHASH_ParcelID, data.mParcelId);
  590. msg->getString(_PREHASH_Data, _PREHASH_Name, data.mName);
  591. msg->getString(_PREHASH_Data, _PREHASH_Desc, data.mDesc);
  592. msg->getUUID(_PREHASH_Data, _PREHASH_SnapshotID, data.mSnapshotId);
  593. msg->getString(_PREHASH_Data, _PREHASH_User, data.mUserName);
  594. msg->getString(_PREHASH_Data, _PREHASH_OriginalName, data.mParcelName);
  595. msg->getString(_PREHASH_Data, _PREHASH_SimName, data.mSimName);
  596. msg->getVector3d(_PREHASH_Data, _PREHASH_PosGlobal, data.mPosGlobal);
  597. msg->getS32(_PREHASH_Data, _PREHASH_SortOrder, data.mSortOrder);
  598. msg->getBool(_PREHASH_Data, _PREHASH_Enabled, data.mEnabled);
  599. notifyObservers(data.mAvatarId, APT_PICK_INFO, (void*)&data);
  600. }
  601. //static
  602. void LLAvatarProperties::sendPickInfoUpdate(const LLAvatarPickInfo& data)
  603. {
  604. LLMessageSystem* msg = gMessageSystemp;
  605. if (!msg) return; // Paranoia
  606. msg->newMessage(_PREHASH_PickInfoUpdate);
  607. msg->nextBlock(_PREHASH_AgentData);
  608. msg->addUUID(_PREHASH_AgentID, gAgentID);
  609. msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
  610. msg->nextBlock(_PREHASH_Data);
  611. msg->addUUID(_PREHASH_PickID, data.mPickId);
  612. msg->addUUID(_PREHASH_CreatorID, data.mAvatarId);
  613. // Legacy, no more used server-side.
  614. msg->addBool(_PREHASH_TopPick, false);
  615. // Fills in on simulator if null
  616. msg->addUUID(_PREHASH_ParcelID, data.mParcelId);
  617. msg->addString(_PREHASH_Name, data.mName);
  618. msg->addString(_PREHASH_Desc, data.mDesc);
  619. msg->addUUID(_PREHASH_SnapshotID, data.mSnapshotId);
  620. msg->addVector3d(_PREHASH_PosGlobal, data.mPosGlobal);
  621. msg->addS32(_PREHASH_SortOrder, data.mSortOrder);
  622. msg->addBool(_PREHASH_Enabled, data.mEnabled);
  623. gAgent.sendReliableMessage();
  624. }
  625. //static
  626. void LLAvatarProperties::sendPickDelete(const LLUUID& avatar_id,
  627. const LLUUID& pick_id)
  628. {
  629. LLMessageSystem* msg = gMessageSystemp;
  630. if (!msg) return; // Paranoia
  631. if (avatar_id != gAgentID)
  632. {
  633. if (gAgent.isGodlikeWithoutAdminMenuFakery())
  634. {
  635. llinfos << "Attempting to delete a pick not pertaining to us. Owner Id: "
  636. << avatar_id << " - Pick Id: " << pick_id << llendl;
  637. msg->newMessage(_PREHASH_PickGodDelete);
  638. msg->nextBlock(_PREHASH_AgentData);
  639. msg->addUUID(_PREHASH_AgentID, gAgentID);
  640. msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
  641. msg->nextBlock(_PREHASH_Data);
  642. msg->addUUID(_PREHASH_PickID, pick_id);
  643. // *HACK: we need to send the pick's creator id to accomplish the
  644. // delete, and we do not use the query id for anything. JC
  645. msg->addUUID(_PREHASH_QueryID, avatar_id);
  646. gAgent.sendReliableMessage();
  647. }
  648. else
  649. {
  650. llwarns << "Attempting to delete a pick not pertaining to us. Aborted."
  651. << llendl;
  652. }
  653. return;
  654. }
  655. msg->newMessage(_PREHASH_PickDelete);
  656. msg->nextBlock(_PREHASH_AgentData);
  657. msg->addUUID(_PREHASH_AgentID, gAgentID);
  658. msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
  659. msg->nextBlock(_PREHASH_Data);
  660. msg->addUUID(_PREHASH_PickID, pick_id);
  661. gAgent.sendReliableMessage();
  662. }
  663. //static
  664. void LLAvatarProperties::processAvatarClassifiedReply(LLMessageSystem* msg,
  665. void**)
  666. {
  667. if (!msg) return; // Paranoia
  668. LLUUID agent_id;
  669. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  670. if (agent_id != gAgentID)
  671. {
  672. llwarns << "Agent ID mismatch. Got: " << agent_id << llendl;
  673. return;
  674. }
  675. LLAvatarClassifieds data;
  676. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TargetID, data.mAvatarId);
  677. LLUUID id;
  678. std::string name;
  679. S32 block_count = msg->getNumberOfBlocksFast(_PREHASH_Data);
  680. for (S32 i = 0; i < block_count; ++i)
  681. {
  682. msg->getUUIDFast(_PREHASH_Data, _PREHASH_ClassifiedID, id, i);
  683. msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, i);
  684. data.mMap.emplace(id, name);
  685. }
  686. notifyObservers(data.mAvatarId, APT_CLASSIFIEDS, (void*)&data);
  687. }
  688. //static
  689. void LLAvatarProperties::sendClassifiedInfoRequest(const LLUUID& classified_id)
  690. {
  691. LLMessageSystem* msg = gMessageSystemp;
  692. if (!msg) return; // Paranoia
  693. msg->newMessageFast(_PREHASH_ClassifiedInfoRequest);
  694. msg->nextBlockFast(_PREHASH_AgentData);
  695. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  696. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  697. msg->nextBlockFast(_PREHASH_Data);
  698. msg->addUUIDFast(_PREHASH_ClassifiedID, classified_id);
  699. gAgent.sendReliableMessage();
  700. }
  701. //static
  702. void LLAvatarProperties::processClassifiedInfoReply(LLMessageSystem* msg,
  703. void**)
  704. {
  705. if (!msg) return; // Paranoia
  706. // Extract the agent id and verify the message is for this client.
  707. LLUUID agent_id;
  708. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  709. if (agent_id != gAgentID)
  710. {
  711. llwarns << "Agent Id mismatch. Got: " << agent_id << llendl;
  712. return;
  713. }
  714. LLAvatarClassifiedInfo info;
  715. msg->getUUIDFast(_PREHASH_Data, _PREHASH_ClassifiedID, info.mClassifiedId);
  716. msg->getUUIDFast(_PREHASH_Data, _PREHASH_CreatorID, info.mAvatarId);
  717. msg->getU32Fast(_PREHASH_Data, _PREHASH_CreationDate, info.mCreationDate);
  718. msg->getU32(_PREHASH_Data, _PREHASH_ExpirationDate, info.mExpirationDate);
  719. msg->getU32Fast(_PREHASH_Data, _PREHASH_Category, info.mCategory);
  720. msg->getStringFast(_PREHASH_Data, _PREHASH_Name, info.mName);
  721. msg->getStringFast(_PREHASH_Data, _PREHASH_Desc, info.mDesc);
  722. msg->getUUIDFast(_PREHASH_Data, _PREHASH_ParcelID, info.mParcelId);
  723. msg->getU32(_PREHASH_Data, _PREHASH_ParentEstate, info.mParentEstate);
  724. msg->getUUIDFast(_PREHASH_Data, _PREHASH_SnapshotID, info.mSnapshotId);
  725. msg->getStringFast(_PREHASH_Data, _PREHASH_SimName, info.mSimName);
  726. msg->getVector3dFast(_PREHASH_Data, _PREHASH_PosGlobal, info.mPosGlobal);
  727. msg->getStringFast(_PREHASH_Data, _PREHASH_ParcelName, info.mParcelName);
  728. msg->getU8Fast(_PREHASH_Data, _PREHASH_ClassifiedFlags, info.mFlags);
  729. msg->getS32(_PREHASH_Data, _PREHASH_PriceForListing, info.mListingPrice);
  730. notifyObservers(info.mAvatarId, APT_CLASSIFIED_INFO, (void*)&info);
  731. }
  732. //static
  733. void LLAvatarProperties::sendClassifiedInfoUpdate(const LLAvatarClassifiedInfo& data)
  734. {
  735. LLMessageSystem* msg = gMessageSystemp;
  736. if (!msg) return; // Paranoia
  737. llinfos << "Sending update for agent classified: " << data.mName
  738. << llendl;
  739. msg->newMessageFast(_PREHASH_ClassifiedInfoUpdate);
  740. msg->nextBlockFast(_PREHASH_AgentData);
  741. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  742. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  743. msg->nextBlockFast(_PREHASH_Data);
  744. msg->addUUIDFast(_PREHASH_ClassifiedID, data.mClassifiedId);
  745. msg->addU32Fast(_PREHASH_Category, data.mCategory);
  746. msg->addStringFast(_PREHASH_Name, data.mName);
  747. msg->addStringFast(_PREHASH_Desc, data.mDesc);
  748. // Fills in on simulator if null
  749. msg->addUUIDFast(_PREHASH_ParcelID, data.mParcelId);
  750. msg->addU32Fast(_PREHASH_ParentEstate, 0); // Fills in on simulator
  751. msg->addUUIDFast(_PREHASH_SnapshotID, data.mSnapshotId);
  752. msg->addVector3dFast(_PREHASH_PosGlobal, data.mPosGlobal);
  753. msg->addU8Fast(_PREHASH_ClassifiedFlags, data.mFlags);
  754. msg->addS32(_PREHASH_PriceForListing,data.mListingPrice);
  755. gAgent.sendReliableMessage();
  756. }
  757. //static
  758. void LLAvatarProperties::sendClassifiedDelete(const LLUUID& classified_id)
  759. {
  760. LLMessageSystem* msg = gMessageSystemp;
  761. if (!msg) return; // Paranoia
  762. msg->newMessageFast(_PREHASH_ClassifiedDelete);
  763. msg->nextBlockFast(_PREHASH_AgentData);
  764. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  765. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  766. msg->nextBlockFast(_PREHASH_Data);
  767. msg->addUUIDFast(_PREHASH_ClassifiedID, classified_id);
  768. gAgent.sendReliableMessage();
  769. }
  770. //static
  771. void LLAvatarProperties::sendAvatarNotesUpdate(const LLUUID& avatar_id,
  772. const std::string& notes)
  773. {
  774. if (gSavedSettings.getBool("UseAgentProfileCap"))
  775. {
  776. std::string url = gAgent.getRegionCapability("AgentProfile");
  777. if (!url.empty())
  778. {
  779. LL_DEBUGS("AvatarProperties") << "Using AgentProfile capability to update notes for avatar: "
  780. << avatar_id << LL_ENDL;
  781. LLSD data;
  782. data["notes"] = notes;
  783. url += "/" + avatar_id.asString();
  784. gCoros.launch("sendAvatarPropertiesUpdateCoro",
  785. boost::bind(sendAvatarPropertiesUpdateCoro,
  786. data, url));
  787. return;
  788. }
  789. }
  790. LLMessageSystem* msg = gMessageSystemp;
  791. if (!msg) return; // Paranoia
  792. msg->newMessage(_PREHASH_AvatarNotesUpdate);
  793. msg->nextBlock(_PREHASH_AgentData);
  794. msg->addUUID(_PREHASH_AgentID, gAgentID);
  795. msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
  796. msg->nextBlock(_PREHASH_Data);
  797. msg->addUUID(_PREHASH_TargetID, avatar_id);
  798. msg->addString(_PREHASH_Notes, notes);
  799. gAgent.sendReliableMessage();
  800. }
  801. //static
  802. void LLAvatarProperties::processAvatarNotesReply(LLMessageSystem* msg, void**)
  803. {
  804. if (!msg) return; // Paranoia
  805. // Extract the agent id and verify the message is for this client.
  806. LLUUID agent_id;
  807. msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  808. if (agent_id != gAgentID)
  809. {
  810. llwarns << "Agent Id mismatch. Got: " << agent_id << llendl;
  811. return;
  812. }
  813. LLAvatarNotes notes;
  814. notes.mReceivedViaCap = false;
  815. msg->getUUID(_PREHASH_Data, _PREHASH_TargetID, notes.mAvatarId);
  816. msg->getString(_PREHASH_Data, _PREHASH_Notes, notes.mNotes);
  817. notifyObservers(notes.mAvatarId, APT_NOTES, (void*)&notes);
  818. }