The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

340 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #include "../Application/jucer_Headers.h"
  20. #include "../Application/jucer_Application.h"
  21. #include "../ProjectSaving/jucer_ProjectExporter.h"
  22. #include "../Project/UI/jucer_HeaderComponent.h"
  23. #include "jucer_LicenseController.h"
  24. #if ! JUCER_ENABLE_GPL_MODE
  25. #include "jucer_LicenseWebview.h"
  26. #include "jucer_LicenseThread.h"
  27. #endif
  28. //==============================================================================
  29. const char* LicenseState::licenseTypeToString (LicenseState::Type type)
  30. {
  31. switch (type)
  32. {
  33. case Type::notLoggedIn: return "<notLoggedIn>";
  34. case Type::noLicenseChosenYet: return "<noLicenseChosenYet>";
  35. case Type::GPL: return "JUCE GPL";
  36. case Type::personal: return "JUCE Personal";
  37. case Type::edu: return "JUCE Education";
  38. case Type::indie: return "JUCE Indie";
  39. case Type::pro: return "JUCE Pro";
  40. default: return "<unknown>";
  41. }
  42. }
  43. static const char* getLicenseStateValue (LicenseState::Type type)
  44. {
  45. switch (type)
  46. {
  47. case LicenseState::Type::GPL: return "GPL";
  48. case LicenseState::Type::personal: return "personal";
  49. case LicenseState::Type::edu: return "edu";
  50. case LicenseState::Type::indie: return "indie";
  51. case LicenseState::Type::pro: return "pro";
  52. default: return nullptr;
  53. }
  54. }
  55. static LicenseState::Type getLicenseTypeFromValue (const String& d)
  56. {
  57. if (d == getLicenseStateValue (LicenseState::Type::GPL)) return LicenseState::Type::GPL;
  58. if (d == getLicenseStateValue (LicenseState::Type::personal)) return LicenseState::Type::personal;
  59. if (d == getLicenseStateValue (LicenseState::Type::edu)) return LicenseState::Type::edu;
  60. if (d == getLicenseStateValue (LicenseState::Type::indie)) return LicenseState::Type::indie;
  61. if (d == getLicenseStateValue (LicenseState::Type::pro)) return LicenseState::Type::pro;
  62. return LicenseState::Type::noLicenseChosenYet;
  63. }
  64. static const char* getApplicationUsageDataStateValue (LicenseState::ApplicationUsageData type)
  65. {
  66. switch (type)
  67. {
  68. case LicenseState::ApplicationUsageData::enabled: return "enabled";
  69. case LicenseState::ApplicationUsageData::disabled: return "disabled";
  70. default: return "notChosen";
  71. }
  72. }
  73. static LicenseState::ApplicationUsageData getApplicationUsageDataTypeFromValue (const String& value)
  74. {
  75. if (value == getApplicationUsageDataStateValue (LicenseState::ApplicationUsageData::enabled)) return LicenseState::ApplicationUsageData::enabled;
  76. if (value == getApplicationUsageDataStateValue (LicenseState::ApplicationUsageData::disabled)) return LicenseState::ApplicationUsageData::disabled;
  77. return LicenseState::ApplicationUsageData::notChosenYet;
  78. }
  79. #if !JUCER_ENABLE_GPL_MODE
  80. struct LicenseController::ModalCompletionCallback : ModalComponentManager::Callback
  81. {
  82. ModalCompletionCallback (LicenseController& controller) : owner (controller) {}
  83. void modalStateFinished (int returnValue) override { owner.modalStateFinished (returnValue); }
  84. LicenseController& owner;
  85. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModalCompletionCallback)
  86. };
  87. #endif
  88. //==============================================================================
  89. LicenseController::LicenseController()
  90. : state (licenseStateFromSettings (ProjucerApplication::getApp().settings->getGlobalProperties()))
  91. {
  92. #if JUCER_ENABLE_GPL_MODE
  93. state.type = LicenseState::Type::GPL;
  94. state.username = "GPL mode";
  95. #endif
  96. }
  97. LicenseController::~LicenseController()
  98. {
  99. #if !JUCER_ENABLE_GPL_MODE
  100. thread.reset();
  101. closeWebview (-1);
  102. #endif
  103. }
  104. LicenseState LicenseController::getState() const noexcept
  105. {
  106. LicenseState projucerState = state;
  107. // if the user has never logged in before and the user is running from command line
  108. // then we have no way to ask the user to log in, so fallback to GPL mode
  109. if (guiNotInitialisedYet
  110. && (state.type == LicenseState::Type::notLoggedIn
  111. || state.type == LicenseState::Type::noLicenseChosenYet))
  112. {
  113. projucerState.type = LicenseState::Type::GPL;
  114. projucerState.username = "GPL mode";
  115. }
  116. return projucerState;
  117. }
  118. void LicenseController::startWebviewIfNeeded()
  119. {
  120. if (guiNotInitialisedYet)
  121. {
  122. guiNotInitialisedYet = false;
  123. auto stateParam = getState();
  124. listeners.call ([&] (StateChangedCallback& l) { l.licenseStateChanged (stateParam); });
  125. }
  126. #if ! JUCER_ENABLE_GPL_MODE
  127. if (thread == nullptr)
  128. thread = new LicenseThread (*this, false);
  129. #endif
  130. }
  131. void LicenseController::logout()
  132. {
  133. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  134. #if ! JUCER_ENABLE_GPL_MODE
  135. thread.reset();
  136. updateState ({});
  137. #if ! JUCE_LINUX
  138. WebBrowserComponent::clearCookies();
  139. #endif
  140. thread = new LicenseThread (*this, false);
  141. #endif
  142. }
  143. void LicenseController::chooseNewLicense()
  144. {
  145. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  146. #if ! JUCER_ENABLE_GPL_MODE
  147. thread.reset();
  148. thread = new LicenseThread (*this, true);
  149. #endif
  150. }
  151. void LicenseController::setApplicationUsageDataState (LicenseState::ApplicationUsageData newState)
  152. {
  153. if (state.applicationUsageDataState != newState)
  154. {
  155. state.applicationUsageDataState = newState;
  156. updateState (state);
  157. }
  158. }
  159. //==============================================================================
  160. #if ! JUCER_ENABLE_GPL_MODE
  161. void LicenseController::closeWebview (int result)
  162. {
  163. if (licenseWebview != nullptr)
  164. licenseWebview->exitModalState (result);
  165. }
  166. void LicenseController::modalStateFinished (int result)
  167. {
  168. licenseWebview = nullptr;
  169. if (result == -1 && (state.type == LicenseState::Type::notLoggedIn
  170. || state.type == LicenseState::Type::noLicenseChosenYet))
  171. JUCEApplication::getInstance()->systemRequestedQuit();
  172. }
  173. void LicenseController::ensureLicenseWebviewIsOpenWithPage (const String& param)
  174. {
  175. if (licenseWebview != nullptr)
  176. {
  177. licenseWebview->goToURL (param);
  178. licenseWebview->toFront (true);
  179. }
  180. else
  181. {
  182. #if ! JUCE_LINUX
  183. WebBrowserComponent::clearCookies();
  184. #endif
  185. licenseWebview = new LicenseWebview (new ModalCompletionCallback (*this), param);
  186. }
  187. }
  188. void LicenseController::queryWebview (const String& startURL, const String& valueToQuery,
  189. HashMap<String, String>& result)
  190. {
  191. ensureLicenseWebviewIsOpenWithPage (startURL);
  192. licenseWebview->setPageCallback ([this,valueToQuery,&result] (const String& cmd, const HashMap<String, String>& params)
  193. {
  194. if (valueToQuery.isEmpty() || cmd == valueToQuery)
  195. {
  196. result.clear();
  197. for (HashMap<String, String>::Iterator it = params.begin(); it != params.end(); ++it)
  198. result.set (it.getKey(), it.getValue());
  199. if (thread != nullptr && ! thread->threadShouldExit())
  200. thread->finished.signal();
  201. }
  202. });
  203. licenseWebview->setNewWindowCallback ([this, &result] (const String& url)
  204. {
  205. if (url.endsWith ("get-juce/indie") || url.endsWith ("get-juce/pro"))
  206. {
  207. result.clear();
  208. result.set ("page-redirect", url);
  209. if (thread != nullptr && ! thread->threadShouldExit())
  210. thread->finished.signal();
  211. }
  212. });
  213. }
  214. #endif
  215. void LicenseController::updateState (const LicenseState& newState)
  216. {
  217. auto& props = ProjucerApplication::getApp().settings->getGlobalProperties();
  218. state = newState;
  219. licenseStateToSettings (state, props);
  220. auto stateParam = getState();
  221. listeners.call ([&] (StateChangedCallback& l) { l.licenseStateChanged (stateParam); });
  222. }
  223. LicenseState LicenseController::licenseStateFromOldSettings (XmlElement* licenseXml)
  224. {
  225. LicenseState result;
  226. result.type = getLicenseTypeFromValue (licenseXml->getChildElementAllSubText ("type", {}));
  227. result.applicationUsageDataState = getApplicationUsageDataTypeFromValue (licenseXml->getChildElementAllSubText ("applicationUsageData", {}));
  228. result.username = licenseXml->getChildElementAllSubText ("username", {});
  229. result.email = licenseXml->getChildElementAllSubText ("email", {});
  230. result.authToken = licenseXml->getChildElementAllSubText ("authToken", {});
  231. MemoryOutputStream imageData;
  232. Base64::convertFromBase64 (imageData, licenseXml->getChildElementAllSubText ("avatar", {}));
  233. result.avatar = ImageFileFormat::loadFrom (imageData.getData(), imageData.getDataSize());
  234. return result;
  235. }
  236. LicenseState LicenseController::licenseStateFromSettings (PropertiesFile& props)
  237. {
  238. ScopedPointer<XmlElement> licenseXml = props.getXmlValue ("license");
  239. if (licenseXml != nullptr)
  240. {
  241. // this is here for backwards compatibility with old-style settings files using XML text elements
  242. if (licenseXml->getChildElementAllSubText ("type", {}) != String())
  243. {
  244. auto stateFromOldSettings = licenseStateFromOldSettings (licenseXml);
  245. licenseStateToSettings (stateFromOldSettings, props);
  246. return stateFromOldSettings;
  247. }
  248. LicenseState result;
  249. result.type = getLicenseTypeFromValue (licenseXml->getStringAttribute ("type", {}));
  250. result.applicationUsageDataState = getApplicationUsageDataTypeFromValue (licenseXml->getStringAttribute ("applicationUsageData", {}));
  251. result.username = licenseXml->getStringAttribute ("username", {});
  252. result.email = licenseXml->getStringAttribute ("email", {});
  253. result.authToken = licenseXml->getStringAttribute ("authToken", {});
  254. MemoryOutputStream imageData;
  255. Base64::convertFromBase64 (imageData, licenseXml->getStringAttribute ("avatar", {}));
  256. result.avatar = ImageFileFormat::loadFrom (imageData.getData(), imageData.getDataSize());
  257. return result;
  258. }
  259. return {};
  260. }
  261. void LicenseController::licenseStateToSettings (const LicenseState& state, PropertiesFile& props)
  262. {
  263. props.removeValue ("license");
  264. if (state.type != LicenseState::Type::notLoggedIn && state.username.isNotEmpty())
  265. {
  266. XmlElement licenseXml ("license");
  267. if (auto* typeString = getLicenseStateValue (state.type))
  268. licenseXml.setAttribute ("type", typeString);
  269. licenseXml.setAttribute ("applicationUsageData", getApplicationUsageDataStateValue (state.applicationUsageDataState));
  270. licenseXml.setAttribute ("username", state.username);
  271. licenseXml.setAttribute ("email", state.email);
  272. licenseXml.setAttribute ("authToken", state.authToken);
  273. MemoryOutputStream imageData;
  274. if (state.avatar.isValid() && PNGImageFormat().writeImageToStream (state.avatar, imageData))
  275. licenseXml.setAttribute ("avatar", Base64::toBase64 (imageData.getData(), imageData.getDataSize()));
  276. props.setValue ("license", &licenseXml);
  277. }
  278. props.saveIfNeeded();
  279. }