hbpanelgrids.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  1. /**
  2. * @file hbpanelgrids.cpp
  3. * @author Henri Beauchamp
  4. * @brief Grid parameters configuration panel
  5. *
  6. * $LicenseInfo:firstyear=2011&license=viewergpl$
  7. *
  8. * Copyright (c) 2011, Henri Beauchamp.
  9. * Note: XML parser code borrowed from Hippo Viewer (c) unknown author
  10. *
  11. * Second Life Viewer Source Code
  12. * The source code in this file ("Source Code") is provided by Linden Lab
  13. * to you under the terms of the GNU General Public License, version 2.0
  14. * ("GPL"), unless you have obtained a separate licensing agreement
  15. * ("Other License"), formally executed by you and Linden Lab. Terms of
  16. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18. *
  19. * There are special exceptions to the terms and conditions of the GPL as
  20. * it is applied to this Source Code. View the full text of the exception
  21. * in the file doc/FLOSS-exception.txt in this software distribution, or
  22. * online at
  23. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24. *
  25. * By copying, modifying or distributing this software, you acknowledge
  26. * that you have read and understood your obligations described above,
  27. * and agree to abide by those obligations.
  28. *
  29. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31. * COMPLETENESS OR PERFORMANCE.
  32. * $/LicenseInfo$
  33. */
  34. #include "llviewerprecompiledheaders.h"
  35. #include <regex>
  36. #include "hbpanelgrids.h"
  37. #include "llcheckboxctrl.h"
  38. #include "llcorehttputil.h"
  39. #include "lldir.h"
  40. #include "lllineeditor.h"
  41. #include "llnotifications.h"
  42. #include "llradiogroup.h"
  43. #include "llscrolllistctrl.h"
  44. #include "llsdserialize.h"
  45. #include "lltextbox.h"
  46. #include "lluictrlfactory.h"
  47. #include "llgridmanager.h"
  48. #include "llstartup.h"
  49. class HBPanelGridsImpl final : public LLPanel
  50. {
  51. protected:
  52. LOG_CLASS(HBPanelGridsImpl);
  53. public:
  54. HBPanelGridsImpl();
  55. ~HBPanelGridsImpl() override;
  56. void draw() override;
  57. void apply();
  58. void cancel();
  59. enum XmlState
  60. {
  61. XML_VOID,
  62. XML_GRIDNAME,
  63. XML_GRIDNICK,
  64. XML_LOGINURI,
  65. XML_HELPERURI,
  66. XML_LOGINPAGE,
  67. XML_WEBSITE,
  68. XML_SUPPORT,
  69. XML_ACCOUNT,
  70. XML_PASSWORD,
  71. };
  72. XmlState mXmlState;
  73. void getParams();
  74. void clearParams(bool clear_name = true);
  75. void updateGridParameters(std::string& result);
  76. void copyParams();
  77. void saveParams();
  78. void deleteGrid();
  79. void addGrid();
  80. void setDirty() { mIsDirty = mIsDirtyGrid = true; }
  81. void setQueryActive(bool active) { mQueryActive = active; mIsDirty = true; }
  82. private:
  83. static void getParamsCoro(std::string uri);
  84. static void onXmlElementStart(void* data, const XML_Char* name,
  85. const XML_Char** atts);
  86. static void onXmlElementEnd(void* data, const XML_Char* name);
  87. static void onXmlCharacterData(void* data, const XML_Char* s, int len);
  88. static void onClickGetParams(void* data);
  89. static void onClickClearParams(void* data);
  90. static void onClickUpdateGrid(void* data);
  91. static void onClickDeleteGrid(void* data);
  92. static void onClickAddGrid(void* data);
  93. static void onEditorKeystroke(LLLineEditor*, void* data);
  94. static void onNameEditorKeystroke(LLLineEditor* caller, void* data);
  95. static void onCommitCheckBoxLoginURI(LLUICtrl* ctrl, void* data);
  96. static void onCommitRadioPreferredName(LLUICtrl* ctrl, void* data);
  97. static void onSelectGrid(LLUICtrl* ctrl, void* data);
  98. private:
  99. LLScrollListCtrl* mGridsScrollList;
  100. bool mIsDirty;
  101. bool mIsDirtyList;
  102. bool mIsDirtyGrid;
  103. bool mGridNeedsUpdate;
  104. bool mQueryActive;
  105. bool mListChanged;
  106. std::string mGridDomain;
  107. std::string mGridCustomName;
  108. std::string mGridName;
  109. std::string mGridNick;
  110. std::string mEnteredLoginURI;
  111. std::string mLoginURI;
  112. std::string mHelperURI;
  113. std::string mLoginPage;
  114. std::string mWebsiteURL;
  115. std::string mSupportURL;
  116. std::string mAccountURL;
  117. std::string mPasswordURL;
  118. LLSD mSavedGridsList;
  119. static LLSD sGridsList;
  120. static HBPanelGridsImpl* sInstance;
  121. };
  122. HBPanelGridsImpl* HBPanelGridsImpl::sInstance = NULL;
  123. LLSD HBPanelGridsImpl::sGridsList;
  124. HBPanelGridsImpl::HBPanelGridsImpl()
  125. : LLPanel(std::string("Grids parameters")),
  126. mIsDirty(true),
  127. mIsDirtyList(true),
  128. mQueryActive(false),
  129. mListChanged(false),
  130. mIsDirtyGrid(false),
  131. mGridNeedsUpdate(false)
  132. {
  133. LLUICtrlFactory::getInstance()->buildPanel(this,
  134. "panel_preferences_grids.xml");
  135. sInstance = this;
  136. if (sGridsList.beginMap() == sGridsList.endMap())
  137. {
  138. const LLSD& grids = LLGridManager::getInstance()->getGridsList();
  139. for (LLSD::map_const_iterator it = grids.beginMap(),
  140. end = grids.endMap();
  141. it != end; ++it)
  142. {
  143. LLSD::String key_name = it->first;
  144. LLSD grid_array = it->second;
  145. if (key_name == "grids" && grid_array.isArray())
  146. {
  147. for (size_t i = 0; i < grid_array.size(); ++i)
  148. {
  149. LLSD gmap = grid_array[i];
  150. if (gmap.has("can_edit") &&
  151. gmap["can_edit"].asString() != "never")
  152. {
  153. sGridsList["grids"].append(gmap);
  154. LL_DEBUGS("GetGridParameters") << "Retained grid: "
  155. << gmap.get("name")
  156. << LL_ENDL;
  157. }
  158. else
  159. {
  160. LL_DEBUGS("GetGridParameters") << "Rejected non-editable grid: "
  161. << gmap.get("name")
  162. << LL_ENDL;
  163. }
  164. }
  165. }
  166. }
  167. }
  168. mSavedGridsList = sGridsList;
  169. mGridsScrollList = getChild<LLScrollListCtrl>("grid_selector");
  170. mGridsScrollList->setCommitOnSelectionChange(true);
  171. mGridsScrollList->setCommitCallback(onSelectGrid);
  172. mGridsScrollList->setCallbackUserData(this);
  173. childSetAction("update_button", onClickUpdateGrid, this);
  174. childSetAction("delete_button", onClickDeleteGrid, this);
  175. childSetAction("add_button", onClickAddGrid, this);
  176. childSetAction("get_param_button", onClickGetParams, this);
  177. childSetAction("clear_param_button", onClickClearParams, this);
  178. LLLineEditor* editor = getChild<LLLineEditor>("login_uri_editor");
  179. editor->setKeystrokeCallback(onEditorKeystroke);
  180. editor->setCallbackUserData(this);
  181. editor = getChild<LLLineEditor>("grid_name_editor");
  182. editor->setKeystrokeCallback(onNameEditorKeystroke);
  183. editor->setCallbackUserData(this);
  184. editor = getChild<LLLineEditor>("helper_uri_editor");
  185. editor->setKeystrokeCallback(onEditorKeystroke);
  186. editor->setCallbackUserData(this);
  187. editor = getChild<LLLineEditor>("login_page_editor");
  188. editor->setKeystrokeCallback(onEditorKeystroke);
  189. editor->setCallbackUserData(this);
  190. editor = getChild<LLLineEditor>("website_editor");
  191. editor->setKeystrokeCallback(onEditorKeystroke);
  192. editor->setCallbackUserData(this);
  193. editor = getChild<LLLineEditor>("support_editor");
  194. editor->setKeystrokeCallback(onEditorKeystroke);
  195. editor->setCallbackUserData(this);
  196. editor = getChild<LLLineEditor>("new_account_editor");
  197. editor->setKeystrokeCallback(onEditorKeystroke);
  198. editor->setCallbackUserData(this);
  199. editor = getChild<LLLineEditor>("forgotten_password_editor");
  200. editor->setKeystrokeCallback(onEditorKeystroke);
  201. editor->setCallbackUserData(this);
  202. childSetCommitCallback("retrieved_loginuri_check",
  203. onCommitCheckBoxLoginURI, this);
  204. childSetCommitCallback("prefer_nickname_radio",
  205. onCommitRadioPreferredName, this);
  206. }
  207. HBPanelGridsImpl::~HBPanelGridsImpl()
  208. {
  209. sInstance = NULL;
  210. }
  211. //virtual
  212. void HBPanelGridsImpl::draw()
  213. {
  214. if (mIsDirty)
  215. {
  216. // Grids list
  217. if (mIsDirtyList)
  218. {
  219. S32 old_count = mGridsScrollList->getItemCount();
  220. S32 scrollpos = mGridsScrollList->getScrollPos();
  221. S32 selected = mGridsScrollList->getFirstSelectedIndex();
  222. mGridsScrollList->deleteAllItems();
  223. for (LLSD::map_const_iterator it = sGridsList.beginMap(),
  224. end = sGridsList.endMap();
  225. it != end; ++it)
  226. {
  227. LLSD::String key_name = it->first;
  228. LLSD grid_array = it->second;
  229. if (key_name == "grids" && grid_array.isArray())
  230. {
  231. for (size_t i = 0; i < grid_array.size(); ++i)
  232. {
  233. LLSD gmap = grid_array[i];
  234. LLSD element;
  235. std::string style = "NORMAL";
  236. std::string grid_id = gmap["name"].asString();
  237. if (gmap.has("can_edit") &&
  238. gmap["can_edit"].asString() == "false")
  239. {
  240. style = "BOLD";
  241. grid_id = "@@|" + grid_id;
  242. }
  243. element["id"] = grid_id;
  244. element["columns"][0]["value"] = gmap["label"].asString();
  245. element["columns"][0]["type"] = "text";
  246. element["columns"][0]["font"] = "SANSSERIF";
  247. element["columns"][0]["font-style"] = style;
  248. mGridsScrollList->addElement(element);
  249. }
  250. }
  251. }
  252. S32 new_count = mGridsScrollList->getItemCount();
  253. if (old_count > new_count)
  254. {
  255. // A grid was just deleted
  256. if (selected > 0)
  257. {
  258. scrollpos = --selected;
  259. }
  260. else
  261. {
  262. scrollpos = selected = 0;
  263. }
  264. }
  265. else if (old_count < new_count &&
  266. // count == 0 when first initializing the list
  267. old_count > 0)
  268. {
  269. // An item was just added. Let's select it and scroll to it.
  270. selected = scrollpos = new_count - 1;
  271. }
  272. mGridsScrollList->setScrollPos(scrollpos);
  273. if (selected >= 0)
  274. {
  275. mGridsScrollList->selectNthItem(selected);
  276. }
  277. mIsDirtyList = false;
  278. }
  279. mGridsScrollList->setEnabled(!mQueryActive);
  280. // Enable/disable the various UI elements as appropriate
  281. bool uri_ok = !childGetValue("login_uri_editor").asString().empty();
  282. bool name_ok = !childGetValue("grid_name_editor").asString().empty();
  283. bool grid_ok = !mIsDirtyList &&
  284. mGridsScrollList->getFirstSelected() != NULL;
  285. mGridNeedsUpdate = mIsDirtyGrid && !mQueryActive && uri_ok &&
  286. name_ok && grid_ok;
  287. childSetEnabled("update_button", mGridNeedsUpdate);
  288. if (grid_ok)
  289. {
  290. grid_ok = mGridsScrollList->getValue().asString().find("@@|") ==
  291. std::string::npos;
  292. }
  293. childSetEnabled("delete_button", !mQueryActive && grid_ok);
  294. childSetEnabled("add_button", !mQueryActive && uri_ok && name_ok);
  295. childSetEnabled("get_param_button", !mQueryActive && uri_ok);
  296. childSetEnabled("clear_param_button", !mQueryActive);
  297. childSetVisible("retreiving", mQueryActive);
  298. if (mQueryActive)
  299. {
  300. childSetVisible("domain", false);
  301. }
  302. else if (!mGridDomain.empty())
  303. {
  304. LLTextBox* domain_text = getChild<LLTextBox>("domain");
  305. domain_text->setTextArg("[DOMAIN]", mGridDomain);
  306. domain_text->setVisible(true);
  307. }
  308. else
  309. {
  310. childSetVisible("domain", false);
  311. }
  312. // Updates done
  313. mIsDirty = false;
  314. }
  315. LLPanel::draw();
  316. }
  317. void HBPanelGridsImpl::getParams()
  318. {
  319. mEnteredLoginURI = childGetValue("login_uri_editor").asString();
  320. if (mEnteredLoginURI.empty())
  321. {
  322. gNotifications.add("MandatoryLoginUri");
  323. return;
  324. }
  325. clearParams(false);
  326. gCoros.launch("HBPanelGridsImpl::getParamsCoro",
  327. boost::bind(&HBPanelGridsImpl::getParamsCoro,
  328. mEnteredLoginURI));
  329. }
  330. //static
  331. void HBPanelGridsImpl::getParamsCoro(std::string uri)
  332. {
  333. if (!sInstance) return; // Paranoia
  334. sInstance->setQueryActive(true);
  335. std::string url = uri;
  336. if (uri.compare(url.length() - 1, 1, "/") != 0)
  337. {
  338. url += '/';
  339. }
  340. url += "get_grid_info";
  341. llinfos << "Fetching grid parameters from: " << url << llendl;
  342. LLCoreHttpUtil::HttpCoroutineAdapter adapter("getParamsCoro");
  343. LLSD result = adapter.getRawAndSuspend(url);
  344. if (!sInstance)
  345. {
  346. llwarns << "Panel closed, grid parameters response from " << url
  347. << " discarded." << llendl;
  348. return;
  349. }
  350. sInstance->setQueryActive(false);
  351. LLCore::HttpStatus status =
  352. LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
  353. if (!status)
  354. {
  355. LLSD args;
  356. args["URI"] = uri;
  357. args["STATUS"] = llformat("%d", status.getType());
  358. args["REASON"] = status.toString();
  359. gNotifications.add("GetGridParametersFailure", args);
  360. return;
  361. }
  362. const LLSD::Binary& raw =
  363. result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary();
  364. S32 size = raw.size();
  365. if (size <= 0)
  366. {
  367. llwarns << "Empty parameters received from: " << url << llendl;
  368. return;
  369. }
  370. std::string parameters((char*)raw.data(), size);
  371. LL_DEBUGS("GetGridParameters") << "\n" << parameters << LL_ENDL;
  372. sInstance->updateGridParameters(parameters);
  373. }
  374. void HBPanelGridsImpl::clearParams(bool clear_name)
  375. {
  376. if (clear_name)
  377. {
  378. childSetValue("grid_name_editor", "");
  379. }
  380. childSetValue("helper_uri_editor", "");
  381. childSetValue("login_page_editor", "");
  382. childSetValue("website_editor", "");
  383. childSetValue("new_account_editor", "");
  384. childSetValue("support_editor", "");
  385. childSetValue("forgotten_password_editor", "");
  386. mGridDomain = "";
  387. mIsDirty = mIsDirtyGrid = true;
  388. }
  389. //static
  390. void HBPanelGridsImpl::onXmlElementStart(void* data, const XML_Char* name,
  391. const XML_Char** atts)
  392. {
  393. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  394. if (stricmp(name, "gridnick") == 0)
  395. {
  396. self->mXmlState = XML_GRIDNICK;
  397. }
  398. else if (stricmp(name, "gridname") == 0)
  399. {
  400. self->mXmlState = XML_GRIDNAME;
  401. }
  402. else if (stricmp(name, "loginuri") == 0 || stricmp(name, "login") == 0)
  403. {
  404. self->mXmlState = XML_LOGINURI;
  405. }
  406. else if (stricmp(name, "helperuri") == 0 || stricmp(name, "economy") == 0)
  407. {
  408. self->mXmlState = XML_HELPERURI;
  409. }
  410. else if (stricmp(name, "loginpage") == 0 || stricmp(name, "welcome") == 0)
  411. {
  412. self->mXmlState = XML_LOGINPAGE;
  413. }
  414. else if (stricmp(name, "website") == 0 || stricmp(name, "about") == 0)
  415. {
  416. self->mXmlState = XML_WEBSITE;
  417. }
  418. else if (stricmp(name, "support") == 0 || stricmp(name, "help") == 0)
  419. {
  420. self->mXmlState = XML_SUPPORT;
  421. }
  422. else if (stricmp(name, "account") == 0 || stricmp(name, "register") == 0)
  423. {
  424. self->mXmlState = XML_ACCOUNT;
  425. }
  426. else if (stricmp(name, "password") == 0)
  427. {
  428. self->mXmlState = XML_PASSWORD;
  429. }
  430. }
  431. //static
  432. void HBPanelGridsImpl::onXmlElementEnd(void* data, const XML_Char* name)
  433. {
  434. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  435. if (self)
  436. {
  437. self->mXmlState = XML_VOID;
  438. }
  439. }
  440. //static
  441. void HBPanelGridsImpl::onXmlCharacterData(void* data, const XML_Char* s,
  442. int len)
  443. {
  444. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  445. switch (self->mXmlState)
  446. {
  447. case XML_GRIDNAME: self->mGridName.assign(s, len); break;
  448. case XML_GRIDNICK: self->mGridNick.assign(s, len); break;
  449. case XML_LOGINURI: self->mLoginURI.assign(s, len); break;
  450. case XML_HELPERURI: self->mHelperURI.assign(s, len); break;
  451. case XML_LOGINPAGE: self->mLoginPage.assign(s, len); break;
  452. case XML_WEBSITE: self->mWebsiteURL.assign(s, len); break;
  453. case XML_SUPPORT: self->mSupportURL.assign(s, len); break;
  454. case XML_ACCOUNT: self->mAccountURL.assign(s, len); break;
  455. case XML_PASSWORD: self->mPasswordURL.assign(s, len); break;
  456. case XML_VOID:
  457. default:
  458. break;
  459. }
  460. }
  461. void HBPanelGridsImpl::updateGridParameters(std::string& result)
  462. {
  463. mGridName.clear();
  464. mGridNick.clear();
  465. mLoginURI.clear();
  466. mHelperURI.clear();
  467. mLoginPage.clear();
  468. mWebsiteURL.clear();
  469. mSupportURL.clear();
  470. mAccountURL.clear();
  471. mPasswordURL.clear();
  472. XML_Parser parser = XML_ParserCreate(0);
  473. XML_SetUserData(parser, this);
  474. XML_SetElementHandler(parser, onXmlElementStart, onXmlElementEnd);
  475. XML_SetCharacterDataHandler(parser, onXmlCharacterData);
  476. mXmlState = XML_VOID;
  477. if (!XML_Parse(parser, result.data(), result.size(), true))
  478. {
  479. llwarns << "XML Parse Error: "
  480. << XML_ErrorString(XML_GetErrorCode(parser)) << llendl;
  481. }
  482. XML_ParserFree(parser);
  483. if (mGridName.empty() && !mGridNick.empty())
  484. {
  485. mGridName = mGridNick;
  486. }
  487. if (mGridCustomName.empty())
  488. {
  489. mGridCustomName = mGridName;
  490. }
  491. if (mGridName.empty())
  492. {
  493. mGridName = mGridCustomName;
  494. }
  495. if (mGridNick.empty())
  496. {
  497. mGridNick = mGridName;
  498. }
  499. S32 choice = childGetValue("prefer_nickname_radio").asInteger();
  500. std::string name;
  501. switch (choice)
  502. {
  503. case 1:
  504. name = mGridName;
  505. break;
  506. case 2:
  507. name = mGridNick;
  508. break;
  509. default:
  510. name = mGridCustomName;
  511. }
  512. childSetValue("grid_name_editor", name);
  513. if (mLoginURI.empty())
  514. {
  515. mLoginURI = mEnteredLoginURI;
  516. }
  517. std::string login_uri =
  518. childGetValue("retrieved_loginuri_check").asBoolean() ? mLoginURI
  519. : mEnteredLoginURI;
  520. childSetValue("login_uri_editor", login_uri);
  521. childSetValue("helper_uri_editor", mHelperURI);
  522. childSetValue("login_page_editor", mLoginPage);
  523. childSetValue("website_editor", mWebsiteURL);
  524. childSetValue("new_account_editor", mAccountURL);
  525. childSetValue("support_editor", mSupportURL);
  526. childSetValue("forgotten_password_editor", mPasswordURL);
  527. mIsDirty = mIsDirtyGrid = true;
  528. }
  529. void HBPanelGridsImpl::copyParams()
  530. {
  531. mGridDomain = mGridsScrollList->getValue().asString();
  532. if (mGridDomain.empty()) return;
  533. if (mGridDomain.find("@@|") == 0)
  534. {
  535. mGridDomain = mGridDomain.substr(3);
  536. }
  537. EGridInfo i = LLGridManager::getInstance()->gridIndexInList(sGridsList,
  538. mGridDomain);
  539. if (i != -1)
  540. {
  541. mGridCustomName = mGridName = mGridNick =
  542. sGridsList["grids"][i].get("label").asString();
  543. childSetValue("grid_name_editor", mGridCustomName);
  544. mLoginURI = mEnteredLoginURI =
  545. sGridsList["grids"][i].get("login_uri").asString();
  546. childSetValue("login_uri_editor", mLoginURI);
  547. mHelperURI = sGridsList["grids"][i].get("helper_uri").asString();
  548. childSetValue("helper_uri_editor", mHelperURI);
  549. mLoginPage = sGridsList["grids"][i].get("login_page").asString();
  550. childSetValue("login_page_editor", mLoginPage);
  551. mWebsiteURL = sGridsList["grids"][i].get("website_url").asString();
  552. childSetValue("website_editor", mWebsiteURL);
  553. mSupportURL = sGridsList["grids"][i].get("support_url").asString();
  554. childSetValue("support_editor", mSupportURL);
  555. mAccountURL = sGridsList["grids"][i].get("register_url").asString();
  556. childSetValue("new_account_editor", mAccountURL);
  557. mPasswordURL = sGridsList["grids"][i].get("password_url").asString();
  558. childSetValue("forgotten_password_editor", mPasswordURL);
  559. mIsDirty = true;
  560. mIsDirtyGrid = mGridNeedsUpdate = false;
  561. }
  562. }
  563. void HBPanelGridsImpl::saveParams()
  564. {
  565. mGridDomain = mGridsScrollList->getValue().asString();
  566. if (mGridDomain.empty()) return;
  567. if (mGridDomain.find("@@|") == 0)
  568. {
  569. mGridDomain = mGridDomain.substr(3);
  570. }
  571. EGridInfo i = LLGridManager::getInstance()->gridIndexInList(sGridsList,
  572. mGridDomain);
  573. if (i != -1)
  574. {
  575. std::string name = childGetValue("grid_name_editor").asString();
  576. LLStringUtil::trim(name);
  577. if (name.empty())
  578. {
  579. gNotifications.add("MandatoryGridName");
  580. return;
  581. }
  582. std::string uri = childGetValue("login_uri_editor").asString();
  583. LLStringUtil::trim(uri);
  584. if (uri.empty())
  585. {
  586. gNotifications.add("MandatoryLoginUri");
  587. return;
  588. }
  589. sGridsList["grids"][i]["label"] = mGridCustomName = mGridName =
  590. mGridNick = name;
  591. sGridsList["grids"][i]["login_uri"] = mLoginURI =
  592. mEnteredLoginURI = uri;
  593. mHelperURI = childGetValue("helper_uri_editor").asString();
  594. LLStringUtil::trim(mHelperURI);
  595. sGridsList["grids"][i]["helper_uri"] = mHelperURI;
  596. mLoginPage = childGetValue("login_page_editor").asString();
  597. LLStringUtil::trim(mLoginPage);
  598. sGridsList["grids"][i]["login_page"] = mLoginPage;
  599. mWebsiteURL = childGetValue("website_editor").asString();
  600. LLStringUtil::trim(mWebsiteURL);
  601. sGridsList["grids"][i]["website_url"] = mWebsiteURL;
  602. mSupportURL = childGetValue("support_editor").asString();
  603. LLStringUtil::trim(mSupportURL);
  604. sGridsList["grids"][i]["support_url"] = mSupportURL;
  605. mAccountURL = childGetValue("new_account_editor").asString();
  606. LLStringUtil::trim(mAccountURL);
  607. sGridsList["grids"][i]["register_url"] = mAccountURL;
  608. mPasswordURL = childGetValue("forgotten_password_editor").asString();
  609. LLStringUtil::trim(mPasswordURL);
  610. sGridsList["grids"][i]["password_url"] = mPasswordURL;
  611. sGridsList["grids"][i]["can_edit"] = "true";
  612. mIsDirty = mIsDirtyList = mListChanged = true;
  613. mIsDirtyGrid = mGridNeedsUpdate = false;
  614. }
  615. }
  616. void HBPanelGridsImpl::deleteGrid()
  617. {
  618. mGridDomain = mGridsScrollList->getValue().asString();
  619. if (mGridDomain.empty()) return;
  620. if (mGridDomain.find("@@|") == 0) // Should never happen
  621. {
  622. mGridDomain = mGridDomain.substr(3);
  623. return;
  624. }
  625. // First, check to see if we have that grid listed in the original
  626. // grids list
  627. LLGridManager* gm = LLGridManager::getInstance();
  628. LLSD grids;
  629. gm->loadGridsLLSD(grids,
  630. gDirUtil.getFullPath(LL_PATH_APP_SETTINGS, "grids.xml"));
  631. EGridInfo i = gm->gridIndexInList(grids, mGridDomain);
  632. if (i == -1)
  633. {
  634. // No such grid: just delete it
  635. i = gm->gridIndexInList(sGridsList, mGridDomain);
  636. sGridsList["grids"].erase(i);
  637. mGridDomain.clear();
  638. }
  639. else
  640. {
  641. // Copy back the grid parameters
  642. EGridInfo j = gm->gridIndexInList(sGridsList, mGridDomain);
  643. if (j != -1)
  644. {
  645. sGridsList["grids"][j]["label"] = mGridCustomName = mGridName =
  646. mGridNick = grids["grids"][i].get("label").asString();
  647. sGridsList["grids"][j]["login_uri"] =
  648. mLoginURI = mEnteredLoginURI =
  649. grids["grids"][i].get("login_uri").asString();
  650. sGridsList["grids"][j]["helper_uri"] = mHelperURI =
  651. grids["grids"][i].get("helper_uri").asString();
  652. sGridsList["grids"][j]["login_page"] = mLoginPage =
  653. grids["grids"][i].get("login_page").asString();
  654. sGridsList["grids"][j]["website_url"] = mWebsiteURL =
  655. grids["grids"][i].get("website_url").asString();
  656. sGridsList["grids"][j]["support_url"] = mSupportURL =
  657. grids["grids"][i].get("support_url").asString();
  658. sGridsList["grids"][j]["register_url"] = mAccountURL =
  659. grids["grids"][i].get("register_url").asString();
  660. sGridsList["grids"][j]["password_url"] = mPasswordURL =
  661. grids["grids"][i].get("password_url").asString();
  662. sGridsList["grids"][j]["can_edit"] = "false";
  663. }
  664. }
  665. mIsDirty = mIsDirtyList = mListChanged = true;
  666. mIsDirtyGrid = mGridNeedsUpdate = false;
  667. }
  668. // Helper functions for addGrid()
  669. bool is_ip_address(const std::string& domain)
  670. {
  671. if (domain.empty())
  672. {
  673. return true; // Pretend an empty string is an IP (saves tests).
  674. }
  675. bool result = false;
  676. try
  677. {
  678. std::regex ipv4_format("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
  679. result = std::regex_match(domain, ipv4_format);
  680. }
  681. catch (std::regex_error& e)
  682. {
  683. llwarns << "Regex error: " << e.what() << llendl;
  684. }
  685. return result;
  686. }
  687. std::string sanitize(std::string str)
  688. {
  689. LLStringUtil::trim(str);
  690. std::string temp;
  691. size_t len = str.size();
  692. for (size_t i = 0; i < len; ++i)
  693. {
  694. char c = str[i];
  695. if (c == '_' || c == '-' || isalnum(c))
  696. {
  697. temp += tolower(c);
  698. }
  699. else if (c == ' ')
  700. {
  701. temp += '.';
  702. }
  703. }
  704. return temp;
  705. }
  706. void grid_exists_error(const std::string& name)
  707. {
  708. LLSD args;
  709. args["NAME"] = name;
  710. gNotifications.add("ExistingGridName", args);
  711. return;
  712. }
  713. void HBPanelGridsImpl::addGrid()
  714. {
  715. std::string uri = childGetValue("login_uri_editor").asString();
  716. LLStringUtil::trim(uri);
  717. if (uri.empty())
  718. {
  719. gNotifications.add("MandatoryLoginUri");
  720. return;
  721. }
  722. std::string name = childGetValue("grid_name_editor").asString();
  723. LLStringUtil::trim(name);
  724. if (name.empty())
  725. {
  726. gNotifications.add("MandatoryGridName");
  727. return;
  728. }
  729. mLoginURI = mEnteredLoginURI = uri;
  730. mGridCustomName = mGridName = mGridNick = name;
  731. mHelperURI = childGetValue("helper_uri_editor").asString();
  732. LLStringUtil::trim(mHelperURI);
  733. mLoginPage = childGetValue("login_page_editor").asString();
  734. LLStringUtil::trim(mLoginPage);
  735. mWebsiteURL = childGetValue("website_editor").asString();
  736. LLStringUtil::trim(mWebsiteURL);
  737. mAccountURL = childGetValue("new_account_editor").asString();
  738. LLStringUtil::trim(mAccountURL);
  739. mSupportURL = childGetValue("support_editor").asString();
  740. LLStringUtil::trim(mSupportURL);
  741. mPasswordURL = childGetValue("forgotten_password_editor").asString();
  742. LLStringUtil::trim(mPasswordURL);
  743. // Create an unique "domain" name that will be used as the key of this
  744. // grid in the grids map: this name can also be used as a grid name after
  745. // the --grid option in the command line of the viewer.
  746. mGridDomain = LLGridManager::getDomain(mLoginURI);
  747. if (is_ip_address(mGridDomain))
  748. {
  749. mGridDomain = LLGridManager::getDomain(mHelperURI);
  750. if (is_ip_address(mGridDomain))
  751. {
  752. mGridDomain = LLGridManager::getDomain(mLoginPage);
  753. if (is_ip_address(mGridDomain))
  754. {
  755. mGridDomain = LLGridManager::getDomain(mAccountURL);
  756. if (is_ip_address(mGridDomain))
  757. {
  758. mGridDomain = LLGridManager::getDomain(mSupportURL);
  759. if (is_ip_address(mGridDomain))
  760. {
  761. mGridDomain = LLGridManager::getDomain(mPasswordURL);
  762. if (is_ip_address(mGridDomain))
  763. {
  764. mGridDomain = sanitize(mGridName);
  765. if (is_ip_address(mGridDomain))
  766. {
  767. gNotifications.add("AddGridFailure");
  768. return;
  769. }
  770. mGridDomain += ".net";
  771. }
  772. }
  773. }
  774. }
  775. }
  776. }
  777. LLStringUtil::toLower(mGridDomain);
  778. // Remove some meaningless common prefixes to try and get a cleaner
  779. // domain name
  780. if (mGridDomain.find("grid.") == 0 && mGridDomain.length() > 8)
  781. {
  782. mGridDomain = mGridDomain.substr(5);
  783. }
  784. else if (mGridDomain.find("login.") == 0 && mGridDomain.length() > 9)
  785. {
  786. mGridDomain = mGridDomain.substr(6);
  787. }
  788. else if (mGridDomain.find("www.") == 0 && mGridDomain.length() > 7)
  789. {
  790. mGridDomain = mGridDomain.substr(4);
  791. }
  792. // Verify that we do not add a grid that already exists.
  793. if (mGridDomain == "agni.lindenlab.com" ||
  794. mGridDomain == "aditi.lindenlab.com")
  795. {
  796. grid_exists_error(mGridDomain);
  797. return;
  798. }
  799. std::string lc_name = mGridName;
  800. LLStringUtil::toLower(lc_name);
  801. if (lc_name == "secondlife" || lc_name == "secondlife beta" ||
  802. lc_name == "other" || lc_name == "none")
  803. {
  804. grid_exists_error(name);
  805. return;
  806. }
  807. EGridInfo i = LLGridManager::getInstance()->gridIndexInList(sGridsList,
  808. mGridDomain);
  809. if (i != -1)
  810. {
  811. grid_exists_error(mGridDomain);
  812. return;
  813. }
  814. i = LLGridManager::getInstance()->gridIndexInList(sGridsList, "", name);
  815. if (i != -1)
  816. {
  817. grid_exists_error(name);
  818. return;
  819. }
  820. // All OK: we can now add it !
  821. LLSD entry = sGridsList.emptyMap();
  822. entry.insert("name", mGridDomain);
  823. entry.insert("label", mGridName);
  824. entry.insert("login_uri", mLoginURI);
  825. entry.insert("helper_uri", mHelperURI);
  826. entry.insert("login_page", mLoginPage);
  827. entry.insert("website_url", mWebsiteURL);
  828. entry.insert("register_url", mAccountURL);
  829. entry.insert("support_url", mSupportURL);
  830. entry.insert("password_url", mPasswordURL);
  831. entry.insert("can_edit", "true");
  832. sGridsList["grids"].append(entry);
  833. mIsDirty = mIsDirtyList = mListChanged = true;
  834. mIsDirtyGrid = mGridNeedsUpdate = false;
  835. }
  836. void HBPanelGridsImpl::apply()
  837. {
  838. if (mGridNeedsUpdate)
  839. {
  840. saveParams();
  841. }
  842. // Create a custom grids list out of listed editable grids
  843. LLSD grids;
  844. for (LLSD::map_const_iterator it = sGridsList.beginMap(),
  845. end = sGridsList.endMap();
  846. it != end; ++it)
  847. {
  848. LLSD::String key_name = it->first;
  849. LLSD grid_array = it->second;
  850. if (key_name == "grids" && grid_array.isArray())
  851. {
  852. for (size_t i = 0; i < grid_array.size(); ++i)
  853. {
  854. LLSD gmap = grid_array[i];
  855. if (gmap.has("can_edit") &&
  856. gmap["can_edit"].asString() == "true")
  857. {
  858. grids["grids"].append(gmap);
  859. }
  860. }
  861. }
  862. }
  863. // Save the custom grids list
  864. std::string filename = gDirUtil.getFullPath(LL_PATH_USER_SETTINGS,
  865. "grids_custom.xml");
  866. llofstream list_file(filename.c_str());
  867. if (!list_file.is_open())
  868. {
  869. llwarns << "Could not open file '" << filename << "' for writing."
  870. << llendl;
  871. return;
  872. }
  873. LLSDSerialize::toPrettyXML(grids, list_file);
  874. list_file.close();
  875. llinfos << "Saved file: " << filename << llendl;
  876. if (mListChanged && !LLStartUp::isLoggedIn())
  877. {
  878. LLGridManager::getInstance()->loadGridsList();
  879. LLStartUp::refreshLoginPanel();
  880. }
  881. // All changes saved
  882. mSavedGridsList.clear();
  883. mSavedGridsList = sGridsList;
  884. mListChanged = false;
  885. }
  886. void HBPanelGridsImpl::cancel()
  887. {
  888. // Beware: cancel() is *also* called after apply() when pressing "OK" to
  889. // close the Preferences floater.
  890. sGridsList.clear();
  891. sGridsList = mSavedGridsList;
  892. mIsDirty = mIsDirtyList = true;
  893. }
  894. //static
  895. void HBPanelGridsImpl::onClickGetParams(void *data)
  896. {
  897. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  898. if (self)
  899. {
  900. self->getParams();
  901. }
  902. }
  903. //static
  904. void HBPanelGridsImpl::onClickClearParams(void *data)
  905. {
  906. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  907. if (self)
  908. {
  909. self->clearParams();
  910. }
  911. }
  912. // static
  913. void HBPanelGridsImpl::onEditorKeystroke(LLLineEditor*, void* data)
  914. {
  915. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  916. if (self)
  917. {
  918. self->setDirty();
  919. }
  920. }
  921. //static
  922. void HBPanelGridsImpl::onCommitCheckBoxLoginURI(LLUICtrl* ctrl, void* data)
  923. {
  924. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  925. if (!self || !ctrl) return;
  926. LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)ctrl;
  927. self->childSetValue("login_uri_editor", check->get() ? self->mLoginURI
  928. : self->mEnteredLoginURI);
  929. self->mIsDirtyGrid = true;
  930. }
  931. // static
  932. void HBPanelGridsImpl::onNameEditorKeystroke(LLLineEditor* caller, void* data)
  933. {
  934. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  935. if (self && caller)
  936. {
  937. self->setDirty();
  938. S32 choice = self->childGetValue("prefer_nickname_radio").asInteger();
  939. if (choice != 0)
  940. {
  941. self->getChild<LLRadioGroup>("prefer_nickname_radio")->selectFirstItem();
  942. }
  943. self->mGridCustomName = caller->getValue().asString();
  944. }
  945. }
  946. //static
  947. void HBPanelGridsImpl::onCommitRadioPreferredName(LLUICtrl* ctrl, void* data)
  948. {
  949. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  950. LLRadioGroup* radio = (LLRadioGroup*)ctrl;
  951. if (self && radio)
  952. {
  953. S32 choice = radio->getValue().asInteger();
  954. std::string name;
  955. switch (choice)
  956. {
  957. case 1:
  958. name = self->mGridName;
  959. break;
  960. case 2:
  961. name = self->mGridNick;
  962. break;
  963. default:
  964. name = self->mGridCustomName;
  965. }
  966. self->childSetValue("grid_name_editor", name);
  967. }
  968. }
  969. // static
  970. void HBPanelGridsImpl::onSelectGrid(LLUICtrl* ctrl, void* data)
  971. {
  972. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  973. if (self)
  974. {
  975. self->copyParams();
  976. }
  977. }
  978. //static
  979. void HBPanelGridsImpl::onClickUpdateGrid(void *data)
  980. {
  981. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  982. if (self)
  983. {
  984. self->saveParams();
  985. }
  986. }
  987. //static
  988. void HBPanelGridsImpl::onClickDeleteGrid(void *data)
  989. {
  990. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  991. if (self)
  992. {
  993. self->deleteGrid();
  994. }
  995. }
  996. //static
  997. void HBPanelGridsImpl::onClickAddGrid(void *data)
  998. {
  999. HBPanelGridsImpl* self = (HBPanelGridsImpl*)data;
  1000. if (self)
  1001. {
  1002. self->addGrid();
  1003. }
  1004. }
  1005. //---------------------------------------------------------------------------
  1006. HBPanelGrids::HBPanelGrids()
  1007. : impl(* new HBPanelGridsImpl())
  1008. {
  1009. }
  1010. HBPanelGrids::~HBPanelGrids()
  1011. {
  1012. delete &impl;
  1013. }
  1014. void HBPanelGrids::apply()
  1015. {
  1016. impl.apply();
  1017. }
  1018. void HBPanelGrids::cancel()
  1019. {
  1020. impl.cancel();
  1021. }
  1022. LLPanel* HBPanelGrids::getPanel()
  1023. {
  1024. return &impl;
  1025. }