passwordscfg.cpp
1 //------------------------------------------------------------------------------
2 // passwordscfg.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2013 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "passwordscfg.h"
24 
25 #include "configuration/doomseekerconfig.h"
26 #include "configuration/serverpassword.h"
27 #include "configuration/serverpasswordsummary.h"
28 #include "ini/ini.h"
29 #include "ini/inisection.h"
30 #include "ini/inivariable.h"
31 #include "ini/settingsproviderqt.h"
32 #include "serverapi/server.h"
33 #include "serverapi/serversummary.h"
34 #include <cassert>
35 #include <QDebug>
36 
37 const QString SECTION_NAME = "Passwords";
38 
39 const QString MAX_NUMBER_OF_SERVERS_PER_PASSWORD_KEY = "MaxNumberOfServersPerPassword";
40 const QString REMEMBER_CONNECT_PASSWORD = "RememberConnectPassword";
41 const QString SERVER_PASSWORDS_KEY = "ServerPasswords";
42 
43 // TODO: [Zalewa] We have 3 different ini files, all instantiated
44 // in Main and kept in different places. Perhaps we should move them
45 // out to a separate singleton? If not, then perhaps we could at least
46 // move the instantiation out of Main.
47 Ini* PasswordsCfg::ini = NULL;
48 QSettings *PasswordsCfg::settings = NULL;
49 
50 
51 DClass<PasswordsCfg>
52 {
53  public:
54  IniSection section;
55 };
56 
57 DPointered(PasswordsCfg)
58 
60 {
61  assert(ini != NULL && "instantiated PasswordsCfg() without initing ini");
62  d->section = ini->section(SECTION_NAME);
63 }
64 
65 PasswordsCfg::~PasswordsCfg()
66 {
67 }
68 
69 void PasswordsCfg::cutServers(QList<ServerPassword>& passwords) const
70 {
71  QMutableListIterator<ServerPassword> it(passwords);
72  while (it.hasNext())
73  {
74  ServerPassword& password = it.next();
75  QList<ServerPasswordSummary> sortedServers = password.servers();
76  qSort(sortedServers.begin(), sortedServers.end(), serverDateDescending);
77  password.setServers(sortedServers.mid(0, maxNumberOfServersPerPassword()));
78  }
79 }
80 
81 void PasswordsCfg::cutStoredServers()
82 {
83  QList<ServerPassword> passwords = serverPasswords();
84  cutServers(passwords);
85  storeServerPasswords(passwords);
86 }
87 
88 void PasswordsCfg::initIni(const QString& path)
89 {
90  assert(ini == NULL && "tried to re-init password ini");
91  if (ini != NULL)
92  {
93  qDebug() << "Error: tried to re-init password ini";
94  return;
95  }
96  settings = new QSettings(path, QSettings::IniFormat);
97  // SettingsProviderQt won't be deleted. Not really a memory leak, as
98  // this is expected to remain memory for whole program runtime.
99  ini = new Ini(new SettingsProviderQt(settings));
100 }
101 
102 bool PasswordsCfg::isHidingPasswords() const
103 {
104  return gConfig.doomseeker.bHidePasswords;
105 }
106 
107 bool PasswordsCfg::isRememberingConnectPhrase() const
108 {
109  return d->section.value(REMEMBER_CONNECT_PASSWORD, false).toBool();
110 }
111 
112 int PasswordsCfg::maxNumberOfServersPerPassword() const
113 {
114  return d->section.value(MAX_NUMBER_OF_SERVERS_PER_PASSWORD_KEY, 5).toInt();
115 }
116 
117 void PasswordsCfg::removeServerPhrase(const QString& phrase)
118 {
119  QList<ServerPassword> allPasswords = serverPasswords();
120  QMutableListIterator<ServerPassword> it(allPasswords);
121  while (it.hasNext())
122  {
123  ServerPassword existingPass = it.next();
124  if (existingPass.phrase() == phrase)
125  {
126  it.remove();
127  }
128  }
129  storeServerPasswords(allPasswords);
130 }
131 
132 void PasswordsCfg::saveServerPhrase(const QString& phrase, const Server* server,
133  const QString &type)
134 {
135  if (phrase.isEmpty())
136  {
137  return;
138  }
139 
140  ServerPasswordSummary serverInfo;
141  if (server != NULL)
142  {
143  ServerSummary serverSummary(server);
144  serverSummary.setTime(QDateTime::currentDateTime());
145  serverInfo.setServerSummary(serverSummary);
146  }
147  serverInfo.setType(type);
148  QList<ServerPassword> allPasswords = serverPasswords();
149  QMutableListIterator<ServerPassword> it(allPasswords);
150  while (it.hasNext())
151  {
152  // Try to add server to existing password.
153  ServerPassword& existingPass = it.next();
154  if (existingPass.phrase() == phrase)
155  {
156  if (serverInfo.isValid())
157  {
158  existingPass.addServer(serverInfo);
159  }
160  setServerPasswords(allPasswords);
161  return;
162  }
163  }
164  // Add new.
165  ServerPassword pass;
166  pass.setPhrase(phrase);
167  pass.addServer(serverInfo);
168  allPasswords << pass;
169  storeServerPasswords(allPasswords);
170 }
171 
172 bool PasswordsCfg::serverDateDescending(ServerPasswordSummary& s1, ServerPasswordSummary& s2)
173 {
174  return s1.time() > s2.time();
175 }
176 
177 void PasswordsCfg::setHidePasswords(bool val)
178 {
179  gConfig.doomseeker.bHidePasswords = val;
180 }
181 
182 QList<ServerPassword> PasswordsCfg::serverPasswords() const
183 {
184  QList<ServerPassword> result;
185  QVariantList vars = d->section[SERVER_PASSWORDS_KEY].value().toList();
186  foreach (const QVariant& var, vars)
187  {
188  result << ServerPassword::deserializeQVariant(var);
189  }
190  return result;
191 }
192 
193 QStringList PasswordsCfg::serverPhrases() const
194 {
195  QStringList result;
196  foreach (const ServerPassword& pass, serverPasswords())
197  {
198  result << pass.phrase();
199  }
200  return result;
201 }
202 
203 void PasswordsCfg::setMaxNumberOfServersPerPassword(int val)
204 {
205  bool shallCut = val < maxNumberOfServersPerPassword();
206  d->section.setValue(MAX_NUMBER_OF_SERVERS_PER_PASSWORD_KEY, val);
207  if (shallCut)
208  {
209  cutStoredServers();
210  }
211 }
212 
213 void PasswordsCfg::setRememberConnectPhrase(bool val)
214 {
215  return d->section.setValue(REMEMBER_CONNECT_PASSWORD, val);
216 }
217 
218 void PasswordsCfg::setServerPasswords(const QList<ServerPassword>& val)
219 {
220  QList<ServerPassword> passwords = val;
221  cutServers(passwords);
222  storeServerPasswords(passwords);
223 }
224 
225 void PasswordsCfg::storeServerPasswords(const QList<ServerPassword>& val)
226 {
227  QVariantList vars;
228  foreach (const ServerPassword obj, val)
229  {
230  vars << obj.serializeQVariant();
231  }
232  d->section.setValue(SERVER_PASSWORDS_KEY, vars);
233 }
234 
235 ServerPassword PasswordsCfg::suggestPassword(const Server* server, const QString &type)
236 {
237  // This method would probably work better as a separate class.
238  // If there's ever any need to expand it, extract it
239  // to a PasswordSuggester or something like that first.
240  ServerPasswordSummary serverSummary(server, type);
241 
242  ServerPassword password;
243  ServerPasswordSummary bestFit;
244  foreach (const ServerPassword& potentialPassword, serverPasswords())
245  {
246  float newSimilarity;
247  ServerPasswordSummary candidate = potentialPassword.mostSimilarServer(serverSummary, &newSimilarity);
248  if (candidate.isValid())
249  {
250  if (newSimilarity > bestFit.similarity(serverSummary))
251  {
252  bestFit = candidate;
253  password = potentialPassword;
254  }
255  else if (qFuzzyCompare(newSimilarity, bestFit.similarity(serverSummary))
256  && candidate.time() > bestFit.time())
257  {
258  bestFit = candidate;
259  password = potentialPassword;
260  }
261  }
262  }
263  return password;
264 }
265 
A representation of a server for a given game.
Definition: server.h:93
void setType(const QString &val)
One of ServerPasswordType consts or custom.
Configuration handler.
Definition: ini.h:69
float similarity(const ServerPasswordSummary &other) const
Similarity to the &#39;other&#39; server; between 0.0 and 1.0.
INI section representation.
Definition: inisection.h:40
void saveServerPhrase(const QString &phrase, const Server *server, const QString &type)
Stores server phrase in persistence along its use case.
ServerPassword suggestPassword(const Server *server, const QString &type)
Suggests best password basing on several criteria.