1 /* This file is part of Clementine.
2    Copyright 2011, 2013, Alan Briolat <alan.briolat@gmail.com>
3    Copyright 2013, Ross Wolfson <ross.wolfson@gmail.com>
4    Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
5    Copyright 2014, John Maguire <john.maguire@gmail.com>
6 
7    Clementine is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11 
12    Clementine is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "subsonicsettingspage.h"
22 #include "ui_subsonicsettingspage.h"
23 
24 #include <QSettings>
25 
26 #include "core/logging.h"
27 #include "internet/core/internetmodel.h"
28 #include "ui/iconloader.h"
29 
SubsonicSettingsPage(SettingsDialog * dialog)30 SubsonicSettingsPage::SubsonicSettingsPage(SettingsDialog* dialog)
31     : SettingsPage(dialog),
32       ui_(new Ui_SubsonicSettingsPage),
33       service_(InternetModel::Service<SubsonicService>()) {
34   ui_->setupUi(this);
35   setWindowIcon(IconLoader::Load("subsonic", IconLoader::Provider));
36 
37   connect(ui_->server, SIGNAL(editingFinished()),
38           SLOT(ServerEditingFinished()));
39   connect(ui_->login, SIGNAL(clicked()), SLOT(Login()));
40   connect(ui_->login_state, SIGNAL(LogoutClicked()), SLOT(Logout()));
41   connect(service_, SIGNAL(LoginStateChanged(SubsonicService::LoginState)),
42           SLOT(LoginStateChanged(SubsonicService::LoginState)));
43 
44   ui_->login_state->AddCredentialField(ui_->server);
45   ui_->login_state->AddCredentialField(ui_->username);
46   ui_->login_state->AddCredentialField(ui_->password);
47   ui_->login_state->AddCredentialField(ui_->usesslv3);
48   ui_->login_state->AddCredentialField(ui_->verifycert);
49   ui_->login_state->AddCredentialGroup(ui_->server_group);
50 
51   ui_->login_state->SetAccountTypeText(
52       tr("Streaming from a Subsonic server requires a valid server license "
53          "after the 30-day trial period."));
54   ui_->login_state->SetAccountTypeVisible(true);
55 }
56 
~SubsonicSettingsPage()57 SubsonicSettingsPage::~SubsonicSettingsPage() { delete ui_; }
58 
Load()59 void SubsonicSettingsPage::Load() {
60   QSettings s;
61   s.beginGroup(SubsonicService::kSettingsGroup);
62 
63   ui_->server->setText(s.value("server").toString());
64   ui_->username->setText(s.value("username").toString());
65   ui_->password->setText(s.value("password").toString());
66   ui_->usesslv3->setChecked(s.value("usesslv3").toBool());
67   ui_->verifycert->setChecked(s.value("verifycert", true).toBool());
68 
69   // If the settings are complete, SubsonicService will have used them already
70   // and
71   // we can tell the user if they worked
72   if (ui_->server->text() != "" && ui_->username->text() != "") {
73     LoginStateChanged(service_->login_state());
74   }
75 }
76 
Save()77 void SubsonicSettingsPage::Save() {
78   QSettings s;
79   s.beginGroup(SubsonicService::kSettingsGroup);
80 
81   s.setValue("server", ui_->server->text());
82   s.setValue("username", ui_->username->text());
83   s.setValue("password", ui_->password->text());
84   s.setValue("usesslv3", ui_->usesslv3->isChecked());
85   s.setValue("verifycert", ui_->verifycert->isChecked());
86 }
87 
LoginStateChanged(SubsonicService::LoginState newstate)88 void SubsonicSettingsPage::LoginStateChanged(
89     SubsonicService::LoginState newstate) {
90   const bool logged_in = newstate == SubsonicService::LoginState_Loggedin;
91 
92   ui_->login_state->SetLoggedIn(
93       logged_in ? LoginStateWidget::LoggedIn : LoginStateWidget::LoggedOut,
94       QString("%1 (%2)").arg(ui_->username->text()).arg(ui_->server->text()));
95   ui_->login_state->SetAccountTypeVisible(!logged_in);
96 
97   switch (newstate) {
98     case SubsonicService::LoginState_BadServer:
99       ui_->login_state->SetAccountTypeText(
100           tr("Could not connect to Subsonic, check server URL. "
101              "Example: http://localhost:4040/"));
102       break;
103 
104     case SubsonicService::LoginState_BadCredentials:
105       ui_->login_state->SetAccountTypeText(tr("Wrong username or password."));
106       break;
107 
108     case SubsonicService::LoginState_OutdatedClient:
109       ui_->login_state->SetAccountTypeText(tr(
110           "Incompatible Subsonic REST protocol version. Client must upgrade."));
111       break;
112 
113     case SubsonicService::LoginState_OutdatedServer:
114       ui_->login_state->SetAccountTypeText(tr(
115           "Incompatible Subsonic REST protocol version. Server must upgrade."));
116       break;
117 
118     case SubsonicService::LoginState_Unlicensed:
119       ui_->login_state->SetAccountTypeText(
120           tr("The trial period for the Subsonic server is over. "
121              "Please donate to get a license key. Visit subsonic.org for "
122              "details."));
123       break;
124 
125     case SubsonicService::LoginState_OtherError:
126       ui_->login_state->SetAccountTypeText(
127           tr("An unspecified error occurred."));
128       break;
129 
130     case SubsonicService::LoginState_ConnectionRefused:
131       ui_->login_state->SetAccountTypeText(
132           tr("Connection refused by server, check server URL. "
133              "Example: http://localhost:4040/"));
134       break;
135 
136     case SubsonicService::LoginState_HostNotFound:
137       ui_->login_state->SetAccountTypeText(
138           tr("Host not found, check server URL. "
139              "Example: http://localhost:4040/"));
140       break;
141 
142     case SubsonicService::LoginState_Timeout:
143       ui_->login_state->SetAccountTypeText(
144           tr("Connection timed out, check server URL. "
145              "Example: http://localhost:4040/"));
146       break;
147 
148     case SubsonicService::LoginState_SslError:
149       ui_->login_state->SetAccountTypeText(
150           tr("SSL handshake error, verify server configuration. "
151              "SSLv3 option below may workaround some issues."));
152       break;
153 
154     case SubsonicService::LoginState_IncompleteCredentials:
155       ui_->login_state->SetAccountTypeText(tr(
156           "Incomplete configuration, please ensure all fields are populated."));
157       break;
158 
159     case SubsonicService::LoginState_RedirectLimitExceeded:
160       ui_->login_state->SetAccountTypeText(
161           tr("Redirect limit exceeded, verify server configuration."));
162       break;
163 
164     case SubsonicService::LoginState_RedirectNoUrl:
165       ui_->login_state->SetAccountTypeText(
166           tr("HTTP 3xx status code received without URL, "
167              "verify server configuration."));
168       break;
169 
170     default:
171       break;
172   }
173 }
174 
ServerEditingFinished()175 void SubsonicSettingsPage::ServerEditingFinished() {
176   QString input = ui_->server->text();
177   QUrl url = QUrl::fromUserInput(input);
178 
179   // Veto things that don't get guessed as an HTTP URL, the result will be
180   // unhelpful
181   if (!url.scheme().startsWith("http")) {
182     return;
183   }
184 
185   // If the user specified a /rest location, remove it since we're going to
186   // re-add it later
187   url = SubsonicService::ScrubUrl(url);
188 
189   ui_->server->setText(url.toString());
190   qLog(Debug) << "URL fixed:" << input << "to" << url;
191 }
192 
Login()193 void SubsonicSettingsPage::Login() {
194   ui_->login_state->SetLoggedIn(LoginStateWidget::LoginInProgress);
195   service_->Login(ui_->server->text(), ui_->username->text(),
196                   ui_->password->text(), ui_->usesslv3->isChecked(),
197                   ui_->verifycert->isChecked());
198 }
199 
Logout()200 void SubsonicSettingsPage::Logout() {
201   ui_->username->setText("");
202   ui_->password->setText("");
203 }
204