1 //////////////////////////////////////////////////////////////////////
2 //
3 // BeeBEEP Copyright (C) 2010-2021 Marco Mastroddi
4 //
5 // BeeBEEP is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published
7 // by the Free Software Foundation, either version 3 of the License,
8 // or (at your option) any later version.
9 //
10 // BeeBEEP 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
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with BeeBEEP. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // Author: Marco Mastroddi <marco.mastroddi(AT)gmail.com>
19 //
20 // $Id: Settings.cpp 1476 2021-01-07 10:43:54Z mastroddi $
21 //
22 //////////////////////////////////////////////////////////////////////
23 
24 #include "BeeApplication.h"
25 #include "BeeUtils.h"
26 #include "ChatMessage.h"
27 #include "NetworkAddress.h"
28 #include "Random.h"
29 #include "Settings.h"
30 #include "Version.h"
31 
32 
33 Settings* Settings::mp_instance = Q_NULLPTR;
34 
Settings()35 Settings::Settings()
36  : m_localUser( ID_LOCAL_USER )
37 {
38   m_settingsVersion = BEEBEEP_SETTINGS_VERSION;
39   m_currentFilePath = "";
40 
41   /* Default RC start */
42   m_enableSaveData = true;
43   m_useChatWithAllUsers = true;
44   m_useSettingsFileIni = true;
45   m_broadcastOnlyToHostsIni = false;
46   m_allowOnlyHostAddressesFromHostsIni = false;
47   m_useOnlyMulticast = false;
48   m_defaultBroadcastPort = DEFAULT_BROADCAST_PORT;
49   m_defaultListenerPort = DEFAULT_LISTENER_PORT;
50   m_defaultFileTransferPort = DEFAULT_FILE_TRANSFER_PORT;
51 
52   m_resetGeometryAtStartup = false;
53   m_saveGeometryOnExit = false;
54   m_saveDataInDocumentsFolder = false;
55   m_disableMenuSettings = false;
56 
57   // In windows native dialogs are application modal and the connection goes in timeout...
58   // In MacOSX instead it seems to work... I have changed the connection timeout...
59   m_useNativeDialogs = true;
60   m_useFontEmoticons = false;
61 #if QT_VERSION >= 0x050000
62   m_useHiResEmoticons = true;
63 #else
64   m_useHiResEmoticons = false;
65 #endif
66 
67 #ifdef MAKE_BEEBEEP_PORTABLE
68   m_saveDataInUserApplicationFolder = false;
69 #else
70   m_saveDataInUserApplicationFolder = true;
71 #endif
72 
73 #ifdef BEEBEEP_USE_MULTICAST_DNS
74   #ifdef Q_OS_MAC
75     m_useMulticastDns = true;
76   #else
77     m_useMulticastDns = false;
78   #endif
79 #else
80   m_useMulticastDns = false;
81 #endif
82 
83   m_allowMultipleInstances = false;
84   m_dataFolderInRC = "";
85   m_addAccountNameToDataFolder = false;
86   m_addNicknameToDataFolder = false;
87   m_preferredSubnets = "";
88   m_disableSystemProxyForConnections = true;
89   m_useDefaultMulticastGroupAddress = true;
90   m_ipMulticastTtl = DEFAULT_IPV4_MULTICAST_TTL_OPTION;
91   m_useIPv6 = false;
92   m_useHive = false;
93   m_checkNewVersionAtStartup = true;
94   m_postUsageStatistics = true;
95   m_useHostnameForDefaultUsername = false;
96   m_useEasyConnection = false;
97   m_useUserFullName = false;
98   m_appendHostNameToUserName = false;
99   m_useCompactDataSaving = true;
100 
101 #ifdef BEEBEEP_DISABLE_FILE_TRANSFER
102   m_disableFileTransfer = true;
103   m_disableFileSharing = true;
104 #else
105   m_disableFileTransfer = false;
106   m_disableFileSharing = false;
107 #endif
108 #ifdef BEEBEEP_DISABLE_SEND_MESSAGE
109   m_disableSendMessage = true;
110 #else
111   m_disableSendMessage = false;
112 #endif
113 #ifdef BEEBEEP_USE_SHAREDESKTOP
114   m_disableDesktopSharing = false;
115 #else
116   m_disableDesktopSharing = true;
117 #endif
118 #ifdef BEEBEEP_USE_VOICE_CHAT
119   m_disableVoiceMessages = false;
120 #else
121   m_disableVoiceMessages = true;
122 #endif
123 
124   m_startMinimized = false;
125   m_signature = "";
126   m_useOnlyTextEmoticons = false;
127   m_disablePrivateChats = false;
128   m_disableMulticast = false;
129   m_userRecognitionMethod = RecognizeByDefaultMethod;
130   m_canAddMembersToGroup = true;
131   m_canRemoveMembersFromGroup = true;
132   m_allowEditNickname = true;
133   m_disableCreateMessage = false;
134   m_clearCacheAfterDays = 96;
135   m_removePartiallyDownloadedFilesAfterDays = 5;
136 
137   m_checkUserConnectedFromDatagramIp = false;
138   m_skipLocalHardwareAddresses = QStringList();
139 
140   m_disableConnectionSocketEncryption = false;
141   m_allowNotEncryptedConnectionsAlso = false;
142   m_allowEncryptedConnectionsAlso = true;
143   m_disableConnectionSocketDataCompression = false;
144 
145   m_allowedFileExtensionsInFileTransfer = QStringList();
146 
147   m_rcFileExists = false;
148 
149   m_connectionKeyExchangeMethod = ConnectionKeyExchangeAuto;
150   /* Default RC end */
151 
152   m_emoticonSizeInEdit = 16;
153 
154   QFont f = QApplication::font();
155   setChatFont( f );
156   m_emoticonSizeInMenu = 24;
157   m_emoticonInRecentMenu = 48;
158   m_confirmOnDownloadFile = false;
159   m_resetMinimumWidthForStyle = true;
160   m_onExistingFileAction = GenerateNewFileName;
161   m_resumeFileTransfer = true;
162   m_promptOnCloseEvent = true;
163   m_saveUserList = true;
164   m_saveGroupList = true;
165   m_localUser.setStatus( User::Online );
166   m_localUser.setVersion( version( false, false, false ) );
167   setPassword( defaultPassword() );
168 
169   m_resourceFolder = ".";
170 #if QT_VERSION >= 0x050400
171   m_dataFolder = Bee::convertToNativeFolderSeparator( QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ) );
172 #elif QT_VERSION >= 0x050000
173   m_dataFolder = Bee::convertToNativeFolderSeparator( QString( "%1/%2" )
174                    .arg( QStandardPaths::writableLocation( QStandardPaths::DataLocation ) )
175                    .arg( programName() ) );
176 #else
177   m_dataFolder = Bee::convertToNativeFolderSeparator( QDesktopServices::storageLocation( QDesktopServices::DataLocation ) );
178 #endif
179   m_cacheFolder = defaultCacheFolderPath();
180 
181   m_lastSave = QDateTime::currentDateTime();
182 
183   m_preventMultipleConnectionsFromSingleHostAddress = true;
184   m_acceptConnectionsOnlyFromWorkgroups = false;
185   m_maxUserStatusDescriptionInList = 10;
186 
187   m_tickIntervalConnectionTimeout = TICK_INTERVAL_CONNECTION_TIMEOUT;
188   m_useReturnToSendMessage = true;
189   m_tickIntervalCheckIdle = 13;
190   m_tickIntervalCheckNetwork = 5;
191   m_tickIntervalBroadcasting = 0;
192   m_broadcastToOfflineUsers = false;
193   m_broadcastToLocalSubnetAlways = true;
194 
195   m_chatMessageFilter = QBitArray( static_cast<int>(ChatMessage::NumTypes) );
196   for( int i = 0; i < ChatMessage::NumTypes; i++ )
197     m_chatMessageFilter.setBit( i, false );
198 
199 #ifdef Q_OS_WIN
200   m_usePreviewFileDialog = true;
201 #else
202   m_usePreviewFileDialog = false;
203 #endif
204   m_previewFileDialogGeometry = "";
205   m_previewFileDialogImageSize = 200;
206   m_maxUsersToConnectInATick = 25;
207   m_showTextInModeRTL = false;
208   m_showChatsInOneWindow = false;
209   m_maxLogLines = 5000;
210   m_enableDefaultChatNotifications = true;
211 
212   m_enableFileTransfer = true;
213   m_enableFileSharing = false;
214 
215   m_iconSourcePath = "";
216   m_emoticonSourcePath = "";
217 
218   m_maxDaysOfUserInactivity = 31;
219 
220   m_shareDesktopCaptureDelay = 2100;
221 
222   m_delayConnectionAtStartup = 5000;
223 
224   m_maxChatsToOpenAfterSendingMessage = 6;
225   m_showUsersOnConnection = false;
226   m_showChatsOnConnection = false;
227   m_hideEmptyChatsInList = true;
228 
229   m_chatActiveWindowOpacityLevel = 100;
230   m_chatInactiveWindowOpacityLevel = chatInactiveWindowDefaultOpacityLevel();
231 
232   m_tickIntervalChatAutoSave = 61;
233 
234   m_useMessageTimestampWithAP = false;
235   m_useDarkStyle = false;
236 
237   m_saveMessagesTimestamp = QDateTime::currentDateTime();
238 
239   m_voiceMessageMaxDuration = 120;
240   m_useVoicePlayer = true;
241   m_useCustomVoiceEncoderSettings = false;
242   m_useSystemVoiceEncoderSettings = false;
243 
244   m_keepModificationDateOnFileTransferred = true;
245 
246   m_allowedFileExtensionsInFileTransfer = QStringList();
247 
248   resetAllColors();
249 }
250 
resourceFolders() const251 QStringList Settings::resourceFolders() const
252 {
253   QStringList system_folders;
254   system_folders.append( dataFolder() );
255   system_folders.append( resourceFolder() );
256 #ifdef Q_OS_MAC
257   QDir mac_plugin_dir( QApplication::applicationDirPath() );
258   if( mac_plugin_dir.cdUp() && mac_plugin_dir.cd( "PlugIns" ) )
259     system_folders.append( Bee::convertToNativeFolderSeparator( mac_plugin_dir.absolutePath() ) );
260 #endif
261 #ifdef Q_OS_UNIX
262   system_folders.append( QLatin1String( "/etc/beebeep/" ) );
263   system_folders.append( QLatin1String( "/usr/local/etc/beebeep/" ) );
264   system_folders.append( QLatin1String( "/usr/lib/beebeep/" ) );
265   system_folders.append( QLatin1String( "/usr/local/lib/beebeep/" ) );
266 #endif
267   system_folders.removeDuplicates();
268   return system_folders;
269 }
270 
dataFolders() const271 QStringList Settings::dataFolders() const
272 {
273   QStringList data_folders;
274   data_folders.append( dataFolder() );
275 #if QT_VERSION >= 0x050400
276   data_folders.append( Bee::convertToNativeFolderSeparator( QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ) ) );
277 #elif QT_VERSION >= 0x050000
278   data_folders.append( Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( QStandardPaths::writableLocation( QStandardPaths::DataLocation ) ).arg( programName() ) ) );
279 #else
280   data_folders.append( Bee::convertToNativeFolderSeparator( QDesktopServices::storageLocation( QDesktopServices::DataLocation ) ) );
281 #endif
282 #ifdef Q_OS_UNIX
283   data_folders.append( QLatin1String( "/usr/share/beebeep/" ) );
284   data_folders.append( QLatin1String( "/usr/local/share/beebeep/" ) );
285 #endif
286   data_folders.append( cacheFolder() );
287   data_folders.removeDuplicates();
288   return data_folders;
289 }
290 
findFileInFolders(const QString & file_name,const QStringList & folder_list,bool return_folder_path) const291 QString Settings::findFileInFolders( const QString& file_name, const QStringList& folder_list, bool return_folder_path ) const
292 {
293   foreach( QString folder_path, folder_list )
294   {
295     if( folder_path.trimmed().isEmpty() )
296       continue;
297     folder_path = Bee::convertToNativeFolderSeparator( folder_path );
298     QString file_path = folder_path;
299     if( !file_path.endsWith( Bee::nativeFolderSeparator() ) )
300       file_path.append( Bee::nativeFolderSeparator() );
301     file_path += file_name;
302     QFileInfo fi( file_path );
303     if( fi.exists() )
304     {
305       if( !fi.isReadable() )
306         qWarning() << "Skip file" << qPrintable( file_path ) << "because is not readable";
307       else
308         return return_folder_path ? folder_path : file_path;
309     }
310   }
311   return QString();
312 }
313 
setDefaultFolders()314 void Settings::setDefaultFolders()
315 {
316   QString app_folder = Bee::convertToNativeFolderSeparator( QApplication::applicationDirPath() );
317   qDebug() << "Applicaction folder:" << qPrintable( app_folder );
318 
319 #ifdef Q_OS_MAC
320   QDir macos_dir( app_folder );
321   if( macos_dir.cdUp() && macos_dir.cd( "Resources" ) )
322     m_resourceFolder = Bee::convertToNativeFolderSeparator( macos_dir.absolutePath() );
323   else
324     m_resourceFolder = app_folder;
325 #else
326   m_resourceFolder = app_folder;
327 #endif
328   qDebug() << "Resource folder:" << qPrintable( m_resourceFolder );
329 
330   if( !Bee::folderIsWriteable( m_resourceFolder, false ) )
331   {
332 #if QT_VERSION >= 0x050400
333     m_dataFolder = Bee::convertToNativeFolderSeparator( QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ) );
334 #elif QT_VERSION >= 0x050000
335     m_dataFolder = Bee::convertToNativeFolderSeparator( QString( "%1/%2" )
336                      .arg( QStandardPaths::writableLocation( QStandardPaths::DataLocation ) )
337                      .arg( programName() ) );
338 #else
339     m_dataFolder = Bee::convertToNativeFolderSeparator( QDesktopServices::storageLocation( QDesktopServices::DataLocation ) );
340 #endif
341   }
342   else
343     m_dataFolder = m_resourceFolder;
344   m_cacheFolder = defaultCacheFolderPath();
345 }
346 
defaultListBackgroundColor() const347 QString Settings::defaultListBackgroundColor() const
348 {
349   return m_useDarkStyle ? Bee::colorDarkGrey().name() : QLatin1String( "#ffffff" );
350 }
351 
defaultSystemBackgroundColor() const352 QString Settings::defaultSystemBackgroundColor() const
353 {
354   return m_useDarkStyle ? Bee::colorBlack().name() : QLatin1String( "#e0e0e0" );
355 }
356 
resetAllColors()357 void Settings::resetAllColors()
358 {
359   m_chatDefaultUserNameColor = m_useDarkStyle ? "#ffffff" : "#000000";
360   m_homeBackgroundColor = defaultSystemBackgroundColor();
361   m_defaultChatBackgroundColor = defaultSystemBackgroundColor();
362   m_userListBackgroundColor = defaultListBackgroundColor();
363   m_chatListBackgroundColor = defaultListBackgroundColor();
364   m_groupListBackgroundColor = defaultListBackgroundColor();
365   m_savedChatListBackgroundColor = defaultListBackgroundColor();
366   m_chatFontColor = m_useDarkStyle ? "#ffffff" : "#000000";
367   m_chatBackgroundColor = m_useDarkStyle ? Bee::colorDarkGrey().name() : "#ffffff";
368   m_chatDefaultTextColor = m_useDarkStyle ? "#ffffff" : "#000000";
369   m_chatSystemTextColor = m_useDarkStyle ? Bee::colorGrey().name() : "#555555";
370   m_chatQuoteBackgroundColor = Bee::colorGrey().name();
371   m_chatQuoteTextColor = Bee::colorBlack().name();
372 }
373 
createApplicationUuid()374 void Settings::createApplicationUuid()
375 {
376   if( m_applicationUuid.isEmpty() )
377   {
378     m_applicationUuid = QUuid::createUuid().toString();
379     m_applicationUuidCreationDate = QDate::currentDate();
380     qDebug() << "Create new application uuid" << qPrintable( m_applicationUuid );
381   }
382   else
383   {
384     qint64 uuid_days_life = m_applicationUuidCreationDate.daysTo( QDate::currentDate() );
385 #ifdef BEEBEEP_DEBUG
386     qDebug() << "Application uuid is created" << uuid_days_life << "days ago";
387 #endif
388     if( uuid_days_life > 31 )
389     {
390       m_applicationUuid = QUuid::createUuid().toString();
391       m_applicationUuidCreationDate = QDate::currentDate();
392       qDebug() << "Renew application uuid" << qPrintable( m_applicationUuid ) << "after" << uuid_days_life << "days";
393     }
394     else
395       qDebug() << "Continue to use application uuid" << qPrintable( m_applicationUuid ) << "created in date" << qPrintable( m_applicationUuidCreationDate.toString( "yyyy-MM-dd" ) );
396   }
397 }
398 
systemNetworkProxy(const QNetworkProxyQuery & npq) const399 QNetworkProxy Settings::systemNetworkProxy( const QNetworkProxyQuery& npq ) const
400 {
401   QList<QNetworkProxy> proxy_list = QNetworkProxyFactory::systemProxyForQuery( npq );
402   if( proxy_list.isEmpty() )
403     return QNetworkProxy( QNetworkProxy::NoProxy );
404   else
405     return proxy_list.first();
406 }
407 
setChatFont(const QFont & new_value)408 void Settings::setChatFont( const QFont& new_value )
409 {
410   m_chatFont = new_value;
411   QFontMetrics fm( m_chatFont );
412   m_emoticonSizeInChat = qMax( 24, qMin( 160, fm.height() ) );
413   m_emoticonSizeInEdit = qMax( 16, qMin( 48, fm.height() ) );
414   if( m_emoticonSizeInChat % 2 )
415     m_emoticonSizeInChat++;
416   if( m_emoticonSizeInEdit % 2 )
417     m_emoticonSizeInEdit++;
418 }
419 
accountNameFromSystemEnvinroment() const420 QString Settings::accountNameFromSystemEnvinroment() const
421 {
422   QProcessEnvironment pe = QProcessEnvironment::systemEnvironment();
423   QString host_name = QHostInfo::localHostName();
424   QString account_name = pe.value( "USERNAME", "" );
425   if( account_name.isEmpty() )
426     account_name = pe.value( "USER", "" );
427   return m_useHostnameForDefaultUsername ? host_name.simplified() : account_name.simplified();
428 }
429 
createLocalUser(const QString & user_name)430 void Settings::createLocalUser( const QString& user_name )
431 {
432   m_localUser = User( ID_LOCAL_USER );
433 
434   QString account_name = accountNameFromSystemEnvinroment();
435   if( account_name.isEmpty() )
436   {
437     qWarning() << "USERNAME and USER variabile not found in system environment";
438     account_name = QString( "Bee %1" ).arg( QTime::currentTime().toString( "zzzsmh" ) );
439   }
440   m_localUser.setAccountName( account_name.toLower() );
441   if( user_name.isEmpty() )
442     m_localUser.setName( account_name );
443   else
444     m_localUser.setName( user_name );
445 
446   m_localUser.setQtVersion( qtMajorVersion() );
447   m_localUser.setProtocolVersion( protocolVersion() );
448   m_localUser.setDomainName( QHostInfo::localDomainName() );
449   m_localUser.setHash( Settings::instance().createLocalUserHash() );
450   m_localUser.setLocalHostName( QHostInfo::localHostName() );
451 
452   qDebug() << "System - user name:" << qPrintable( m_localUser.name() );
453   qDebug() << "System - account:" << qPrintable( m_localUser.accountName() );
454   qDebug() << "System - domain name:" << qPrintable( m_localUser.domainName() );
455   qDebug() << "System - host name:" << qPrintable( m_localUser.localHostName() );
456 #ifdef BEEBEEP_DEBUG
457   qDebug() << "Local user hash:" << qPrintable( m_localUser.hash() );
458 #endif
459 
460   if( user_name.isEmpty() && m_addNicknameToDataFolder )
461     setDataFolder();
462 }
463 
createLocalUserHash()464 QString Settings::createLocalUserHash()
465 {
466   QString hash_parameters = QString( "%1%2%3%4%5%6%7%8" )
467                               .arg( QString::number( Random::number32( 6475, 36475 ) ) )
468                               .arg( m_localUser.accountName() ).arg( m_localUser.name() )
469                               .arg( QString::number( Random::number32( 6475, 36475 ) ) )
470                               .arg( m_localUser.domainName() ).arg( m_localUser.localHostName() ).arg( version( true, true, true ) )
471                               .arg( QDateTime::currentDateTime().toString( "dd.MM.yyyy-hh:mm:ss.zzz" ) );
472   QString local_user_hash = simpleHash( hash_parameters );
473 #ifdef BEEBEEP_DEBUG
474   qDebug() << "Local user HASH created:" << qPrintable( local_user_hash );
475 #endif
476   return local_user_hash;
477 }
478 
createDefaultRcFile()479 bool Settings::createDefaultRcFile()
480 {
481   QFileInfo rc_file_info( dataFolder() + Bee::nativeFolderSeparator() + QLatin1String( "beebeep.rc" ) );
482   if( rc_file_info.exists() )
483   {
484     qDebug() << "RC default configuration file exists in" << qPrintable( rc_file_info.absoluteFilePath() );
485     return false;
486   }
487 
488   QSettings* sets = new QSettings( rc_file_info.absoluteFilePath(), QSettings::IniFormat );
489   bool rc_file_created = false;
490   if( sets->isWritable() )
491   {
492     sets->beginGroup( "BeeBEEP" );
493     sets->setValue( "EnableSaveData", m_enableSaveData );
494     sets->setValue( "UseConfigurationFileIni", m_useSettingsFileIni );
495     sets->setValue( "BroadcastOnlyToHostsIni", m_broadcastOnlyToHostsIni );
496     sets->setValue( "AllowOnlyHostAddressesFromHostsIni", m_allowOnlyHostAddressesFromHostsIni );
497     sets->setValue( "UseOnlyMulticast", m_useOnlyMulticast );
498     sets->setValue( "BroadcastPort", m_defaultBroadcastPort );
499     sets->setValue( "DefaultListenerPort", m_defaultListenerPort );
500     sets->setValue( "DefaultFileTransferPort", m_defaultFileTransferPort );
501     sets->setValue( "SaveDataInDocumentsFolder", m_saveDataInDocumentsFolder );
502     sets->setValue( "SaveDataInUserApplicationFolder", m_saveDataInUserApplicationFolder );
503     sets->setValue( "AllowMultipleInstances", m_allowMultipleInstances );
504     sets->setValue( "DataFolderPath", m_dataFolderInRC );
505     sets->setValue( "AddAccountNameToDataFolder", m_addAccountNameToDataFolder );
506     sets->setValue( "AddNicknameToDataFolder", m_addNicknameToDataFolder );
507   #ifdef BEEBEEP_USE_MULTICAST_DNS
508     sets->setValue( "UseMulticastDns", m_useMulticastDns );
509   #endif
510     sets->setValue( "PreventMultipleConnectionsFromSingleHostAddress", m_preventMultipleConnectionsFromSingleHostAddress );
511     sets->setValue( "PreferredSubnets", m_preferredSubnets );
512     sets->setValue( "UseIPv6", m_useIPv6 );
513     if( m_multicastGroupAddress.isNull() )
514       sets->setValue( "MulticastGroupAddress", "" );
515     else
516       sets->setValue( "MulticastGroupAddress", m_multicastGroupAddress.toString() );
517     sets->setValue( "EnableChatWithAllUsers", m_useChatWithAllUsers );
518     sets->setValue( "UseHive", m_useHive );
519     sets->setValue( "UseHostnameForDefaultUsername", m_useHostnameForDefaultUsername );
520     sets->setValue( "DisableFileTransfer", m_disableFileTransfer );
521     sets->setValue( "DisableFileSharing", m_disableFileSharing );
522     sets->setValue( "DisableDesktopSharing", m_disableDesktopSharing );
523     sets->setValue( "DisableSendMessage", m_disableSendMessage );
524     sets->setValue( "DisableVoiceMessages", m_disableVoiceMessages );
525     sets->setValue( "UseEasyConnection", m_useEasyConnection );
526     sets->setValue( "UseCompactDataSaving", m_useCompactDataSaving );
527     sets->setValue( "StartMinimized", m_startMinimized );
528     sets->setValue( "Signature", m_signature );
529     sets->setValue( "UseOnlyTextEmoticons", m_useOnlyTextEmoticons );
530     sets->setValue( "DisablePrivateChats", m_disablePrivateChats );
531     sets->setValue( "DisableMulticast", m_disableMulticast );
532     sets->setValue( "UserRecognitionMethod", m_userRecognitionMethod );
533     sets->setValue( "AllowAddMembersToGroup", m_canAddMembersToGroup );
534     sets->setValue( "AllowRemoveMembersFromGroup", m_canRemoveMembersFromGroup );
535     sets->setValue( "AllowEditNickname", m_allowEditNickname );
536     sets->setValue( "DisableCreateMessage", m_disableCreateMessage );
537     sets->setValue( "DisableMenuSettings", m_disableMenuSettings );
538     sets->setValue( "CheckUserConnectedFromDatagramIp", m_checkUserConnectedFromDatagramIp );
539     sets->setValue( "SkipLocalHardwareAddresses", m_skipLocalHardwareAddresses.isEmpty() ? QString( "" ) : m_skipLocalHardwareAddresses.join( ", " ) );
540     sets->setValue( "DisableEncryptedConnections", m_disableConnectionSocketEncryption );
541     sets->setValue( "AllowNotEncryptedConnectionsAlso", m_allowNotEncryptedConnectionsAlso );
542     sets->setValue( "AllowEncryptedConnectionsAlso", m_allowEncryptedConnectionsAlso );
543     sets->setValue( "UseUserFullName", m_useUserFullName );
544     sets->setValue( "AppendHostNameToUserName", m_appendHostNameToUserName );
545     sets->setValue( "DisableConnectionSocketDataCompression", m_disableConnectionSocketDataCompression );
546     sets->setValue( "AllowedFileExtensionsInFileTransfer", m_allowedFileExtensionsInFileTransfer.isEmpty() ? QString( "" ) : m_allowedFileExtensionsInFileTransfer.join( ", " ) );
547     sets->setValue( "ConnectionKeyExchangeMethod", m_connectionKeyExchangeMethod );
548     sets->setValue( "TickIntervalChatAutoSave", m_tickIntervalChatAutoSave );
549     sets->endGroup();
550     sets->sync();
551     qDebug() << "RC default configuration file created in" << qPrintable( Bee::convertToNativeFolderSeparator( sets->fileName() ) );
552     rc_file_created = true;
553   }
554   else
555     qWarning() << "Unable to create RC default configuration file in" << qPrintable( Bee::convertToNativeFolderSeparator( sets->fileName() ) );
556 
557   sets->deleteLater();
558   return rc_file_created;
559 }
560 
objectRcSettings() const561 QSettings* Settings::objectRcSettings() const
562 {
563   QString rc_file_path = findFileInFolders( QLatin1String( "beebeep.rc" ), resourceFolders() );
564   if( rc_file_path.isEmpty() )
565     return Q_NULLPTR;
566   QSettings* sets = new QSettings( rc_file_path, QSettings::IniFormat );
567   sets->setFallbacksEnabled( false );
568   return sets;
569 }
570 
loadRcFile()571 void Settings::loadRcFile()
572 {
573   QSettings *sets = objectRcSettings();
574   if( sets )
575   {
576     qDebug() << "Loading settings from RC configuration file" << qPrintable( sets->fileName() );
577     m_rcFileExists = true;
578   }
579   else
580   {
581     qDebug() << "RC configuration file not found";
582     m_rcFileExists = false;
583     return;
584   }
585 
586   bool ok = false;
587   sets->beginGroup( "Groups" );
588   bool trust_system_account = sets->value( "TrustSystemAccount", false ).toBool(); // for compatibility
589   sets->endGroup();
590 
591   sets->beginGroup( "BeeBEEP" );
592   m_enableSaveData = sets->value( "EnableSaveData", m_enableSaveData ).toBool();
593   m_useSettingsFileIni = sets->value( "UseConfigurationFileIni", m_useSettingsFileIni ).toBool();
594   m_broadcastOnlyToHostsIni = sets->value( "BroadcastOnlyToHostsIni", m_broadcastOnlyToHostsIni ).toBool();
595   m_allowOnlyHostAddressesFromHostsIni = sets->value( "AllowOnlyHostAddressesFromHostsIni", m_allowOnlyHostAddressesFromHostsIni ).toBool();
596   m_useOnlyMulticast = sets->value( "UseOnlyMulticast", m_useOnlyMulticast ).toBool();
597   m_defaultBroadcastPort = sets->value( "BroadcastPort", m_defaultBroadcastPort ).toInt();
598   m_defaultListenerPort = sets->value( "DefaultListenerPort", m_defaultListenerPort ).toInt();
599   m_defaultFileTransferPort = sets->value( "DefaultFileTransferPort", m_defaultFileTransferPort ).toInt();
600   m_saveDataInDocumentsFolder = sets->value( "SaveDataInDocumentsFolder", m_saveDataInDocumentsFolder ).toBool();
601   m_saveDataInUserApplicationFolder = sets->value( "SaveDataInUserApplicationFolder", m_saveDataInUserApplicationFolder ).toBool();
602   m_allowMultipleInstances = sets->value( "AllowMultipleInstances", m_allowMultipleInstances ).toBool();
603   m_dataFolderInRC = Bee::convertToNativeFolderSeparator( sets->value( "DataFolderPath", m_dataFolderInRC ).toString() );
604   m_addAccountNameToDataFolder = sets->value( "AddAccountNameToDataFolder", m_addAccountNameToDataFolder ).toBool();
605   m_addNicknameToDataFolder = sets->value( "AddNicknameToDataFolder", m_addNicknameToDataFolder ).toBool();
606 #ifdef BEEBEEP_USE_MULTICAST_DNS
607   m_useMulticastDns = sets->value( "UseMulticastDns", m_useMulticastDns ).toBool();
608 #endif
609   m_preventMultipleConnectionsFromSingleHostAddress = sets->value( "PreventMultipleConnectionsFromSingleHostAddress", m_preventMultipleConnectionsFromSingleHostAddress ).toBool();
610   m_preferredSubnets = sets->value( "PreferredSubnets", m_preferredSubnets ).toString();
611   m_useIPv6 = sets->value( "UseIPv6", m_useIPv6 ).toBool();
612   QString multicast_group_address = sets->value( "MulticastGroupAddress", "" ).toString();
613   if( multicast_group_address.isEmpty() )
614     m_multicastGroupAddress = QHostAddress();
615   else
616     m_multicastGroupAddress = QHostAddress( multicast_group_address );
617   m_useChatWithAllUsers = sets->value( "EnableChatWithAllUsers", m_useChatWithAllUsers ).toBool();
618   m_useHive = sets->value( "UseHive", m_useHive ).toBool();
619   m_useHostnameForDefaultUsername = sets->value( "UseHostnameForDefaultUsername", m_useHostnameForDefaultUsername ).toBool();
620 #ifdef BEEBEEP_DISABLE_FILE_TRANSFER
621   m_disableFileTransfer = true;
622   m_disableFileSharing = true;
623 #else
624   m_disableFileTransfer = sets->value( "DisableFileTransfer", m_disableFileTransfer ).toBool();
625   if( m_disableFileTransfer )
626     m_disableFileSharing = true;
627   else
628     m_disableFileSharing = sets->value( "DisableFileSharing", m_disableFileSharing ).toBool();
629 #endif
630   m_disableDesktopSharing = sets->value( "DisableDesktopSharing", m_disableDesktopSharing ).toBool();
631   m_disableSendMessage = sets->value( "DisableSendMessage", m_disableSendMessage ).toBool();
632   m_disableVoiceMessages = sets->value( "DisableVoiceMessages", m_disableVoiceMessages ).toBool();
633   m_useEasyConnection = sets->value( "UseEasyConnection", m_useEasyConnection ).toBool();
634   m_useCompactDataSaving = sets->value( "UseCompactDataSaving", m_useCompactDataSaving ).toBool();
635   m_startMinimized = sets->value( "StartMinimized", m_startMinimized ).toBool();
636   m_signature = sets->value( "Signature", m_signature ).toString();
637   m_useOnlyTextEmoticons = sets->value( "UseOnlyTextEmoticons", m_useOnlyTextEmoticons ).toBool();
638   m_disablePrivateChats = sets->value( "DisablePrivateChats", m_disablePrivateChats ).toBool();
639   m_disableMulticast = sets->value( "DisableMulticast", m_disableMulticast ).toBool();
640   int user_recognition_method = sets->value( "UserRecognitionMethod", -1 ).toInt();
641   setUserRecognitionMethod( (user_recognition_method < 0 ? (trust_system_account ? RecognizeByAccount : m_userRecognitionMethod) : user_recognition_method) );
642 
643   m_canAddMembersToGroup = sets->value( "AllowAddMembersToGroup", m_canAddMembersToGroup ).toBool();
644   m_canRemoveMembersFromGroup = sets->value( "AllowRemoveMembersFromGroup", m_canRemoveMembersFromGroup ).toBool();
645   m_allowEditNickname = sets->value( "AllowEditNickname", m_allowEditNickname ).toBool();
646   m_disableCreateMessage = sets->value( "DisableCreateMessage", m_disableCreateMessage ).toBool();
647   m_disableMenuSettings = sets->value( "DisableMenuSettings", m_disableMenuSettings ).toBool();
648   m_clearCacheAfterDays = qMax( -1, sets->value( "ClearCacheAfterDays", m_clearCacheAfterDays ).toInt() );
649   m_removePartiallyDownloadedFilesAfterDays = qMax( -1, sets->value( "RemovePartiallyDownloadedFilesAfterDays", m_removePartiallyDownloadedFilesAfterDays ).toInt() );
650   m_checkUserConnectedFromDatagramIp = sets->value( "CheckUserConnectedFromDatagramIp", m_checkUserConnectedFromDatagramIp ).toBool();
651   // Remember to use "" for the string in INI files
652   QString local_hw_addresses = sets->value( "SkipLocalHardwareAddresses", m_skipLocalHardwareAddresses.join( "," ) ).toString().simplified();
653   m_skipLocalHardwareAddresses.clear();
654   if( !local_hw_addresses.isEmpty() )
655   {
656     QStringList local_hw_address_list = local_hw_addresses.split( "," );
657     foreach( QString hw_value, local_hw_address_list )
658     {
659       hw_value = hw_value.trimmed();
660       if( !hw_value.isEmpty() )
661         m_skipLocalHardwareAddresses.append( hw_value );
662     }
663     m_skipLocalHardwareAddresses.removeDuplicates();
664   }
665   m_disableConnectionSocketEncryption = sets->value( "DisableEncryptedConnections", m_disableConnectionSocketEncryption ).toBool();
666   m_allowNotEncryptedConnectionsAlso = sets->value( "AllowNotEncryptedConnectionsAlso", m_allowNotEncryptedConnectionsAlso ).toBool();
667   m_allowEncryptedConnectionsAlso = sets->value( "AllowEncryptedConnectionsAlso", m_allowEncryptedConnectionsAlso ).toBool();
668   m_useUserFullName = sets->value( "UseUserFullName", m_useUserFullName ).toBool();
669   m_appendHostNameToUserName = sets->value( "AppendHostNameToUserName", m_appendHostNameToUserName ).toBool();
670   m_disableConnectionSocketDataCompression = sets->value( "DisableConnectionSocketDataCompression", m_disableConnectionSocketDataCompression ).toBool();
671   // Remember to use "" for the string in INI files
672   QString allowed_file_extensions = sets->value( "AllowedFileExtensionsInFileTransfer", m_allowedFileExtensionsInFileTransfer.join( "," ) ).toString().simplified();
673   m_allowedFileExtensionsInFileTransfer.clear();
674   if( !allowed_file_extensions.trimmed().isEmpty() )
675   {
676     QStringList allowed_file_extensions_list = allowed_file_extensions.split( "," );
677     foreach( QString file_ext, allowed_file_extensions_list )
678     {
679       file_ext = file_ext.trimmed();
680       if( !file_ext.isEmpty() )
681       {
682         if( file_ext.startsWith( "*" ) )
683           file_ext.remove( 0, 1 );
684         if( file_ext.startsWith( "." ) )
685           file_ext.remove( 0, 1 );
686         if( !file_ext.isEmpty() )
687           m_allowedFileExtensionsInFileTransfer.append( file_ext.toLower() );
688       }
689     }
690     m_allowedFileExtensionsInFileTransfer.removeDuplicates();
691   }
692 
693   m_connectionKeyExchangeMethod = sets->value( "ConnectionKeyExchangeMethod", m_connectionKeyExchangeMethod ).toInt( &ok );
694   if( !ok || m_connectionKeyExchangeMethod < 0 || m_connectionKeyExchangeMethod >= NumConnectionKeyExchangeMethods )
695     m_connectionKeyExchangeMethod = ConnectionKeyExchangeAuto;
696   sets->endGroup();
697 
698   QStringList key_list = sets->allKeys();
699   foreach( QString key, key_list )
700   {
701     QString sets_value = sets->value( key ).toString();
702     if( sets_value.isEmpty() )
703       sets_value = sets->value( key ).toStringList().join( ", " );
704     qDebug() << "RC read ->" << qPrintable( key ) << "=" << qPrintable( sets_value );
705   }
706   qDebug() << "RC configuration file read";
707   if( !m_skipLocalHardwareAddresses.isEmpty() )
708   {
709     foreach( QString hw_value, m_skipLocalHardwareAddresses )
710       qDebug() << "Skip local hardware address:" << qPrintable( hw_value );
711   }
712   if( !m_allowedFileExtensionsInFileTransfer.isEmpty() )
713     qWarning() << "File transfer allows only these extensions:" << qPrintable( m_allowedFileExtensionsInFileTransfer.join( ", " ).toUpper() );
714   delete sets;
715 }
716 
createDefaultHostsFile()717 bool Settings::createDefaultHostsFile()
718 {
719   QStringList sl;
720 
721   sl << "# This is a sample HOSTS file used by BeeBEEP.";
722   sl << "#";
723   sl << "# This file contains the IP addresses (something like 10.0.0.123)";
724   sl << "# or subnet (10.0.0.255 means that BeeBEEP tries to connect every";
725   sl << "# client from the IP 10.0.0.1 to IP 10.0.0.254).";
726   sl << "# Each entry should be kept on an individual line.";
727   sl << "#";
728   sl << "# Additionally, comments (such as these) may be inserted";
729   sl << "# on individual line denoted by a '#', '*' or '/' symbol.";
730   sl << "#";
731   sl << "# For example:";
732   sl << "#";
733   sl << "# 10.184.9.132";
734   sl << "# 192.168.2.17";
735   sl << "# 10.184.5.255";
736   sl << "# 10.2.4.255";
737   sl << "# 2001:db8:1f70::999:de8:7648:6e8";
738   sl << "#";
739   sl << "# From version 3.0.1 you can also add port to the host addresses";
740   sl << "# (ipv4 and ipv6 supported). For example:";
741   sl << "#";
742   sl << "# 10.184.9.132:6475";
743   sl << "# [2001:db8:1f70::999:de8:7648:6e8]:6475";
744   sl << "#";
745   sl << " ";
746 
747   QString file_hosts_path = dataFolder() + Bee::nativeFolderSeparator() + QLatin1String( "beehosts.ini" );
748   QFile file_hosts_ini( file_hosts_path );
749   if( file_hosts_ini.exists() )
750   {
751     qDebug() << "HOSTS default configuration file exists in" << qPrintable( file_hosts_path );
752     return false;
753   }
754 
755   if( file_hosts_ini.open( QIODevice::WriteOnly ) )
756   {
757     QTextStream ts( &file_hosts_ini );
758     foreach( QString line, sl )
759       ts << line << "\n";
760     ts.flush();
761     file_hosts_ini.close();
762     qDebug() << "HOSTS default configuration file created in" << qPrintable( file_hosts_path );
763     return true;
764   }
765   else
766   {
767     qWarning() << "Unable to create the HOSTS default configuration file in" << qPrintable( file_hosts_path );
768     return false;
769   }
770 }
771 
setUserRecognitionMethod(int new_value)772 void Settings::setUserRecognitionMethod( int new_value )
773 {
774   if( new_value <= 0 || new_value >= NumUserRecognitionMethods )
775     m_userRecognitionMethod = RecognizeByDefaultMethod;
776   else
777     m_userRecognitionMethod = new_value;
778 }
779 
isDevelopmentVersion(const QString & v) const780 bool Settings::isDevelopmentVersion( const QString& v ) const
781 {
782   QString s_version;
783   if( v.isEmpty() )
784     s_version = QString( BEEBEEP_VERSION );
785   else
786     s_version = v;
787 
788   QStringList sl = s_version.split( "." );
789   if( sl.isEmpty() )
790   {
791     qWarning() << "INVALID BEEBEEP VERSION FOUND";
792     return true;
793   }
794   int v_num = sl.last().toInt();
795   return v_num % 2 == 1;
796 }
797 
version(bool build_version,bool qt_version,bool debug_info) const798 QString Settings::version( bool build_version, bool qt_version, bool debug_info ) const
799 {
800   QString s_version = QString( BEEBEEP_VERSION );
801   if( build_version )
802     s_version += QString( "-%1" ).arg( BEEBEEP_BUILD );
803 
804   if( debug_info )
805   {
806     s_version += QString( "-p%2" ).arg( BEEBEEP_PROTO_VERSION );
807 #ifdef BEEBEEP_DISABLE_FILE_TRANSFER
808     s_version += QLatin1String( "-noft" );
809 #endif
810 #ifdef BEEBEEP_DISABLE_SEND_MESSAGE
811     s_version += QLatin1String( "-nosm" );
812 #endif
813   }
814 
815   if( qt_version )
816   {
817     s_version += QString( "-qt%1" ).arg( qtMajorVersion() );
818 #if defined( Q_PROCESSOR_X86_64 )
819     s_version += QString( "-64bit" );
820 #else
821     s_version += QString( "-32bit" );
822 #endif
823   }
824   return s_version;
825 }
826 
httpUserAgent() const827 QString Settings::httpUserAgent() const
828 {
829   return QString( "%1 %2" ).arg( programName() ).arg( version( false, false, false ) );
830 }
831 
protocolVersion() const832 int Settings::protocolVersion() const
833 {
834   return BEEBEEP_PROTO_VERSION;
835 }
836 
defaultMulticastGroupAddress() const837 QHostAddress Settings::defaultMulticastGroupAddress() const
838 {
839   return m_useIPv6 ? QHostAddress( QString( DEFAULT_IPV6_MULTICAST_ADDRESS ) ) : QHostAddress( QString( DEFAULT_IPV4_MULTICAST_ADDRESS ) );
840 }
841 
programName() const842 QString Settings::programName() const
843 {
844   return QString( BEEBEEP_NAME );
845 }
846 
organizationName() const847 QString Settings::organizationName() const
848 {
849   return QString( BEEBEEP_ORGANIZATION );
850 }
851 
organizationDomain() const852 QString Settings::organizationDomain() const
853 {
854   return QString( BEEBEEP_ORGANIZATION_DOMAIN );
855 }
856 
officialWebSite() const857 QString Settings::officialWebSite() const
858 {
859   return QString( BEEBEEP_WEBSITE );
860 }
861 
pluginWebSite() const862 QString Settings::pluginWebSite() const
863 {
864   return officialWebSite() + QString( BEEBEEP_DOWNLOAD_WEBSITE ) + "#plugin";
865 }
866 
downloadWebSite() const867 QString Settings::downloadWebSite() const
868 {
869   return officialWebSite() + QString( BEEBEEP_DOWNLOAD_WEBSITE );
870 }
871 
donationWebSite() const872 QString Settings::donationWebSite() const
873 {
874   return officialWebSite() + QString( BEEBEEP_DONATE_WEBSITE );
875 }
876 
helpWebSite() const877 QString Settings::helpWebSite() const
878 {
879   QString web_url = officialWebSite() + QString( BEEBEEP_HELP_WEBSITE );
880   if( m_language == "it" )
881     web_url += QString( "?lang=it_IT" );
882   else
883     web_url += QString( "?lang=en_US" );
884   return web_url;
885 }
886 
languageWebSite() const887 QString Settings::languageWebSite() const
888 {
889   return officialWebSite() + QString( BEEBEEP_LANGUAGE_WEBSITE );
890 }
891 
lastVersionUrl() const892 QString Settings::lastVersionUrl() const
893 {
894   return officialWebSite() + QString( BEEBEEP_LAST_VERSION_FILE );
895 }
896 
newsWebSite() const897 QString Settings::newsWebSite() const
898 {
899   return officialWebSite() + QString( BEEBEEP_NEWS_WEBSITE );
900 }
901 
developerWebSite() const902 QString Settings::developerWebSite() const
903 {
904   QString web_url = QString::fromLatin1( QByteArray::fromBase64( "aHR0cHM6Ly93d3cubWFyY29tYXN0cm9kZGkuY29tL2Fib3V0X21lLnBocD9sYW5nPQ==" ) );
905   if( m_language == "it" )
906     web_url += QString( "it_IT" );
907   else
908     web_url += QString( "en_US" );
909   return web_url;
910 }
911 
tipsWebSite() const912 QString Settings::tipsWebSite() const
913 {
914   QString web_url = officialWebSite() + QString( BEEBEEP_TIPS_WEBSITE );
915   if( m_language == "it" )
916     web_url += QString( "?lang=it_IT" );
917   else
918     web_url += QString( "?lang=en_US" );
919   return web_url;
920 }
921 
factWebSite() const922 QString Settings::factWebSite() const
923 {
924   QString web_url = officialWebSite() + QString( BEEBEEP_FACT_WEBSITE );
925   if( m_language == "it" )
926     web_url += QString( "?lang=it_IT" );
927   else
928     web_url += QString( "?lang=en_US" );
929   return web_url;
930 }
931 
faqWebSite() const932 QString Settings::faqWebSite() const
933 {
934   QString web_url = officialWebSite() + QString( BEEBEEP_FAQ_WEBSITE );
935   if( m_language == "it" )
936     web_url += QString( "?lang=it_IT" );
937   else
938     web_url += QString( "?lang=en_US" );
939   return web_url;
940 }
941 
hunspellVersion() const942 QString Settings::hunspellVersion() const
943 {
944   return QString( HUNSPELL_VERSION );
945 }
946 
operatingSystem(bool use_long_name) const947 QString Settings::operatingSystem( bool use_long_name ) const
948 {
949   QString os_name_long = "Unknown OS";
950   QString os_name_short = "unknown";
951 #ifdef Q_OS_WIN
952   os_name_long = "Microsoft Windows";
953   os_name_short = "Windows";
954 #endif
955 #ifdef Q_OS_LINUX
956   os_name_long = "Linux";
957   os_name_short = "Linux";
958 #endif
959 #ifdef Q_OS_MAC
960   os_name_long = "Apple MacOSX";
961   os_name_short = "MacOSX";
962 #endif
963 #ifdef Q_OS_OS2
964   os_name_long = "OS/2";
965   os_name_short = "OS2";
966 #endif
967 #ifdef BEEBEEP_FOR_RASPBERRY_PI
968   os_name_long = "Raspberry PI";
969   os_name_short = "PI";
970 #endif
971   return use_long_name ? os_name_long : os_name_short;
972 }
973 
operatingSystemIconPath() const974 QString Settings::operatingSystemIconPath() const
975 {
976   QString os_icon_path = "beebeep.png";
977 
978 #ifdef Q_OS_WIN
979   os_icon_path = "windows.png";
980 #endif
981 #ifdef Q_OS_LINUX
982   os_icon_path = "linux.png";
983 #endif
984 #ifdef Q_OS_MAC
985   os_icon_path = "macosx.png";
986 #endif
987 #ifdef Q_OS_OS2
988   os_icon_path = "os2.png";
989 #endif
990 #ifdef BEEBEEP_FOR_RASPBERRY_PI
991   os_icon_path = "raspberry-pi.png";
992 #endif
993   return os_icon_path;
994 }
995 
checkVersionWebSite() const996 QString Settings::checkVersionWebSite() const
997 {
998   QString os_type = operatingSystem( false ).toLower();
999   return officialWebSite() + QString( "%1?beebeep-version=%2&beebeep-os=%3" ).arg( QString( BEEBEEP_CHECK_VERSION_WEBSITE ) ).arg( QString( BEEBEEP_VERSION ) ).arg( os_type );
1000 }
1001 
languageFilePath(const QString & language_folder,const QString & language_selected) const1002 QString Settings::languageFilePath( const QString& language_folder, const QString& language_selected ) const
1003 {
1004   return Bee::convertToNativeFolderSeparator( QString( "%1/%2_%3.qm" ).arg( language_folder, Settings::instance().programName().toLower(), language_selected ) );
1005 }
1006 
dnsRecord() const1007 QString Settings::dnsRecord() const
1008 {
1009   return QString( BEEBEEP_DNS_RECORD );
1010 }
1011 
gaTrackingId() const1012 QString Settings::gaTrackingId() const
1013 {
1014   return QString( BEEBEEP_GA_TRACKING_ID );
1015 }
1016 
gaUrl() const1017 QString Settings::gaUrl() const
1018 {
1019   return QString( BEEBEEP_GA_URL );
1020 }
1021 
gaEventVersion() const1022 QString Settings::gaEventVersion() const
1023 {
1024   return QString( BEEBEEP_GA_EVENT_VERSION );
1025 }
1026 
hash(const QString & string_to_hash) const1027 QByteArray Settings::hash( const QString& string_to_hash ) const
1028 {
1029   QByteArray hash_pre = string_to_hash.toUtf8() + m_password;
1030   if( !m_signature.isEmpty() )
1031     hash_pre += m_signature.toUtf8();
1032   QByteArray hash_generated = QCryptographicHash::hash( hash_pre, QCryptographicHash::Sha1 );
1033   return hash_generated.toHex();
1034 }
1035 
simpleHash(const QString & string_to_hash) const1036 QString Settings::simpleHash( const QString& string_to_hash ) const
1037 {
1038 #if QT_VERSION >= 0x050000
1039   QByteArray hash_generated = QCryptographicHash::hash( string_to_hash.toUtf8(), QCryptographicHash::Sha256 );
1040 #else
1041   QByteArray hash_generated = QCryptographicHash::hash( string_to_hash.toUtf8(), QCryptographicHash::Sha1 );
1042 #endif
1043   return QString::fromLatin1( hash_generated.toHex() );
1044 }
1045 
setPassword(const QString & new_value)1046 void Settings::setPassword( const QString& new_value )
1047 {
1048   m_passwordBeforeHash = new_value;
1049   QString pwd_tmp = new_value.isEmpty() || new_value == defaultPassword() ? QString( "*6475*" ) : new_value;
1050   if( !m_signature.isEmpty() )
1051     pwd_tmp.prepend( m_signature );
1052   m_password = QCryptographicHash::hash( pwd_tmp.toUtf8(), QCryptographicHash::Sha1 ).toHex();
1053 }
1054 
currentHash() const1055 QString Settings::currentHash() const
1056 {
1057   return QString::fromUtf8( hash( m_localUser.name() ) );
1058 }
1059 
hostAddressToListen()1060 QHostAddress Settings::hostAddressToListen()
1061 {
1062 #if QT_VERSION >= 0x050000
1063   return m_useIPv6 ? QHostAddress::Any : QHostAddress::AnyIPv4;
1064 #else
1065   return m_useIPv6 ? QHostAddress::AnyIPv6 : QHostAddress::Any;
1066 #endif
1067 }
1068 
setLocalUserHost(const QHostAddress & host_address,quint16 host_port)1069 void Settings::setLocalUserHost( const QHostAddress& host_address, quint16 host_port )
1070 {
1071   if( host_address.isNull() || host_address.toString() == QString( "0.0.0.0" ) )
1072     m_localUser.setNetworkAddress( NetworkAddress( m_useIPv6 ? QHostAddress::LocalHostIPv6 : QHostAddress::LocalHost, host_port ) );
1073   else
1074     m_localUser.setNetworkAddress( NetworkAddress( host_address, host_port ) );
1075 }
1076 
defaultHostsFilePath() const1077 QString Settings::defaultHostsFilePath() const
1078 {
1079   return findFileInFolders( QLatin1String( "beehosts.ini" ), resourceFolders() );
1080 }
1081 
loadBroadcastAddressesFromFileHosts()1082 void Settings::loadBroadcastAddressesFromFileHosts()
1083 {
1084   if( !m_broadcastAddressesInFileHosts.isEmpty() )
1085     m_broadcastAddressesInFileHosts.clear();
1086 
1087   QString hosts_file_path = defaultHostsFilePath();
1088   if( hosts_file_path.isNull() )
1089   {
1090     qDebug() << "File beehosts.ini not found";
1091     return;
1092   }
1093 
1094   QFile file( hosts_file_path );
1095   if( !file.open( QIODevice::ReadOnly ) )
1096   {
1097     qWarning() << "Cannot open file HOSTS in path" << qPrintable( hosts_file_path );
1098     return;
1099   }
1100 
1101   qDebug() << "Reading HOSTS from file" << qPrintable( hosts_file_path );
1102   QString address_string;
1103   QString line_read;
1104   int num_lines = 0;
1105   char c;
1106   int hosts_found = 0;
1107 
1108   while( !file.atEnd() )
1109   {
1110     num_lines++;
1111     line_read = file.readLine();
1112     if( line_read.size() > 0 )
1113     {
1114       address_string = line_read.simplified();
1115 
1116       if( address_string.size() > 0 )
1117       {
1118         c = address_string.at( 0 ).toLatin1();
1119         if( c == '#' || c == '/' || c == '*' )
1120           continue;
1121 
1122         NetworkAddress na = NetworkAddress::fromString( address_string );
1123         if( !na.isHostAddressValid() )
1124         {
1125           qWarning() << "Invalid broadcast address found in line" << num_lines << ":" << address_string;
1126           continue;
1127         }
1128 
1129         if( m_broadcastAddressesInFileHosts.contains( address_string ) )
1130         {
1131           qDebug() << "Broadcast address is already in list";
1132           continue;
1133         }
1134 
1135         qDebug() << "Adding broadcast address:" << address_string;
1136         m_broadcastAddressesInFileHosts << address_string;
1137         hosts_found++;
1138       }
1139     }
1140   }
1141 
1142   qDebug() << "HOSTS file read:" << hosts_found << "IP addresses found";
1143   file.close();
1144 }
1145 
currentSettingsFilePath() const1146 QString Settings::currentSettingsFilePath() const
1147 {
1148   if( m_useSettingsFileIni )
1149     return defaultSettingsFilePath();
1150   else
1151     return QLatin1String( "Native OS Settings" );
1152 }
1153 
checkFilePath(const QString & file_path,const QString & default_value)1154 QString Settings::checkFilePath( const QString& file_path, const QString& default_value )
1155 {
1156   QFile file( file_path );
1157   return file.exists() ? file_path : default_value;
1158 }
1159 
checkFolderPath(const QString & folder_path,const QString & default_value,bool check_writable)1160 QString Settings::checkFolderPath( const QString& folder_path, const QString& default_value, bool check_writable )
1161 {
1162   if( folder_path.isEmpty() )
1163     return default_value;
1164 
1165   if( check_writable )
1166   {
1167     if( Bee::folderIsWriteable( folder_path, false ) )
1168       return folder_path;
1169   }
1170   else
1171   {
1172     if( QFile::exists( folder_path ) )
1173       return folder_path;
1174   }
1175 
1176   qWarning() << "The folder" << folder_path << "load in settings is not usable and" << default_value << "is taken by default";
1177   return default_value;
1178 }
1179 
objectSettings() const1180 QSettings* Settings::objectSettings() const
1181 {
1182   QSettings *sets;
1183 
1184   if( m_useSettingsFileIni )
1185   {
1186     sets = new QSettings( defaultSettingsFilePath(), QSettings::IniFormat );
1187     sets->setFallbacksEnabled( false );
1188   }
1189   else
1190     sets = new QSettings( QSettings::NativeFormat, QSettings::UserScope, organizationName(), programName() );
1191 
1192   if( !sets->isWritable() )
1193     qWarning() << sets->fileName() << "is not a writable path. Settings cannot be saved.";
1194   // remember to delete it
1195   return sets;
1196 }
1197 
load()1198 void Settings::load()
1199 {
1200   qDebug() << "Loading settings";
1201   QSettings *sets = objectSettings();
1202 #ifdef Q_OS_WIN
1203   if( m_useSettingsFileIni )
1204     m_currentFilePath = Bee::convertToNativeFolderSeparator( sets->fileName() );
1205   else
1206     m_currentFilePath = ""; // registry path
1207 #else
1208   m_currentFilePath = Bee::convertToNativeFolderSeparator( sets->fileName() );
1209 #endif
1210   beeApp->setSettingsFilePath( m_currentFilePath );
1211 
1212   m_firstTime = sets->allKeys().isEmpty();
1213   sets->beginGroup( "Version" );
1214   m_settingsVersion = sets->value( "Settings", BEEBEEP_SETTINGS_VERSION ).toInt();
1215   m_dataStreamVersion = sets->value( "DataStream", static_cast<int>(DATASTREAM_VERSION_1) ).toInt();
1216   m_settingsCreationDate = sets->value( "BeeBang", QDate() ).toDate();
1217   if( m_settingsCreationDate.isNull() )
1218     m_settingsCreationDate = QDate::currentDate();
1219   QString qt_version_in_settings = sets->value( "Qt", qtMajorMinorVersion() ).toString();
1220   sets->endGroup();
1221 
1222   bool qt_is_compatible = qt_version_in_settings == qtMajorMinorVersion();
1223   loadCommonSettings( sets );
1224 
1225   sets->beginGroup( "VCard" );
1226   VCard vc;
1227   vc.setNickName( sets->value( "NickName",  m_localUser.vCard().nickName() ).toString() );
1228   vc.setFirstName( sets->value( "FirstName", m_localUser.vCard().firstName() ).toString() );
1229   vc.setLastName( sets->value( "LastName", m_localUser.vCard().lastName() ).toString() );
1230   QDate dt = sets->value( "Birthday", m_localUser.vCard().birthday() ).toDate();
1231   if( dt.isValid() )
1232     vc.setBirthday( dt );
1233   vc.setEmail( sets->value( "Email", m_localUser.vCard().email() ).toString() );
1234   QPixmap pix = sets->value( "Photo", m_localUser.vCard().photo() ).value<QPixmap>();
1235   if( !pix.isNull() )
1236     vc.setPhoto( pix );
1237   vc.setPhoneNumber( sets->value( "Phone", m_localUser.vCard().phoneNumber() ).toString() );
1238   vc.setInfo( sets->value( "Info", m_localUser.vCard().info() ).toString() );
1239   m_localUser.setVCard( vc );
1240   sets->endGroup();
1241 
1242   sets->beginGroup( "Gui" );
1243   if( m_resetGeometryAtStartup || m_settingsVersion < 9 || !qt_is_compatible )
1244   {
1245     m_guiGeometry = "";
1246     m_guiState = "";
1247     m_floatingChatGeometry = "";
1248     m_floatingChatState = "";
1249     m_floatingChatSplitterState = "";
1250     m_mainBarIconSize = QSize( 24, 24 );
1251     m_avatarIconSize = QSize( 28, 28 );
1252     m_previewFileDialogGeometry = "";
1253     m_createMessageGeometry = "";
1254     m_fileSharingGeometry = "";
1255     qDebug() << "The geometry has been reset at startup";
1256   }
1257   else
1258   {
1259     m_guiGeometry = sets->value( "MainWindowGeometry", "" ).toByteArray();
1260     m_guiState = sets->value( "MainWindowState", "" ).toByteArray();
1261     m_floatingChatGeometry = sets->value( "FloatingChatGeometry", "" ).toByteArray();
1262     m_floatingChatState = sets->value( "FloatingChatState", "" ).toByteArray();
1263     m_floatingChatSplitterState = sets->value( "FloatingChatSplitterState", "" ).toByteArray();
1264     m_previewFileDialogGeometry = sets->value( "PreviewFileDialogGeometry", "" ).toByteArray();
1265     m_createMessageGeometry = sets->value( "CreateMessageGeometry", "" ).toByteArray();
1266     m_fileSharingGeometry = sets->value( "FileSharingGeometry", "" ).toByteArray();
1267   }
1268 
1269 #if QT_VERSION == 0x050906
1270   if( m_settingsVersion < 11 )
1271   {
1272     // Bug in restore state for QDockWidgets
1273     // https://bugreports.qt.io/browse/QTBUG-68939
1274     m_guiState = "";
1275     m_floatingChatState = "";
1276   }
1277 #endif
1278 
1279 #if QT_VERSION >= 0x050000
1280   m_lastDirectorySelected = Bee::convertToNativeFolderSeparator( sets->value( "LastDirectorySelected", QStandardPaths::writableLocation( QStandardPaths::DocumentsLocation ) ).toString() );
1281   m_downloadDirectory = Bee::convertToNativeFolderSeparator( sets->value( "DownloadDirectory", QStandardPaths::writableLocation( QStandardPaths::DownloadLocation ) ).toString() );
1282 #else
1283   m_lastDirectorySelected = Bee::convertToNativeFolderSeparator( sets->value( "LastDirectorySelected", QDesktopServices::storageLocation( QDesktopServices::DocumentsLocation ) ).toString() );
1284   m_downloadDirectory = Bee::convertToNativeFolderSeparator( sets->value( "DownloadDirectory", QDesktopServices::storageLocation( QDesktopServices::DocumentsLocation ) ).toString() );
1285 #endif
1286   m_downloadDirectory = checkFolderPath( m_downloadDirectory, defaultDownloadFolderPath(), true );
1287   m_lastDirectorySelected = checkFolderPath( m_lastDirectorySelected, dataFolder(), false );
1288   m_logPath = checkFolderPath( Bee::convertToNativeFolderSeparator( sets->value( "LogFolderPath", dataFolder() ).toString() ), dataFolder(), true );
1289   QString plugin_folder_path = defaultPluginFolderPath();
1290   m_pluginPath = checkFolderPath( Bee::convertToNativeFolderSeparator( sets->value( "PluginPath", plugin_folder_path ).toString() ), plugin_folder_path, false );
1291   QString language_folder_path = defaultLanguageFolderPath();
1292   m_languagePath = checkFolderPath( Bee::convertToNativeFolderSeparator( sets->value( "LanguagePath", language_folder_path ).toString() ), language_folder_path, false );
1293   m_beepFilePath = checkFilePath( Bee::convertToNativeFolderSeparator( sets->value( "BeepFilePath", defaultBeepFilePath() ).toString() ), defaultBeepFilePath() );
1294   sets->endGroup();
1295 
1296   sets->beginGroup( "Plugin" );
1297   QStringList key_list = sets->value( "List", QStringList() ).toStringList();
1298   if( !key_list.isEmpty() )
1299   {
1300     QStringList plugin_settings_tmp;
1301     QStringList::const_iterator it = key_list.constBegin();
1302     while( it != key_list.constEnd() )
1303     {
1304       plugin_settings_tmp = sets->value( *it, QStringList() ).toStringList();
1305       if( !plugin_settings_tmp.isEmpty() )
1306         setPluginSettings( *it, plugin_settings_tmp );
1307       ++it;
1308     }
1309   }
1310   sets->endGroup();
1311 
1312   if( !m_allowEditNickname && userRecognitionMethod() != Settings::RecognizeByNickname )
1313   {
1314     if( m_localUser.name() != m_localUser.accountName() )
1315     {
1316       qWarning() << "AllowEditNickname is disabled but nickname changed to" << qPrintable( m_localUser.name() );
1317       qDebug() << "Restoring system account name:" << qPrintable( m_localUser.accountName() );
1318       m_localUser.setName( m_localUser.accountName() );
1319     }
1320   }
1321 
1322   m_lastSave = QDateTime::currentDateTime();
1323   qDebug() << "Loading host addresses from file HOSTS";
1324   Settings::instance().loadBroadcastAddressesFromFileHosts();
1325   qDebug() << "Loading settings completed";
1326   delete sets;
1327 }
1328 
1329 
beginCommonGroup(QSettings * system_rc,QSettings * user_ini,const QString & group_name)1330 void Settings::beginCommonGroup( QSettings* system_rc, QSettings* user_ini, const QString& group_name )
1331 {
1332   if( system_rc )
1333     system_rc->beginGroup( group_name );
1334   if( user_ini )
1335     user_ini->beginGroup( group_name );
1336 }
1337 
endCommonGroup(QSettings * system_rc,QSettings * user_ini)1338 void Settings::endCommonGroup( QSettings* system_rc, QSettings* user_ini )
1339 {
1340   if( system_rc )
1341     system_rc->endGroup();
1342   if( user_ini )
1343     user_ini->endGroup();
1344 }
1345 
commonValue(QSettings * system_rc,QSettings * user_ini,const QString & key,const QVariant & default_value)1346 QVariant Settings::commonValue( QSettings* system_rc, QSettings* user_ini, const QString& key, const QVariant& default_value )
1347 {
1348   if( system_rc && user_ini )
1349     return system_rc->value( key, user_ini->value( key, default_value ) );
1350   else if( system_rc )
1351     return system_rc->value( key, default_value );
1352   else if( user_ini )
1353     return user_ini->value( key, default_value );
1354   else
1355     return default_value;
1356 }
1357 
loadCommonSettings(QSettings * user_ini)1358 void Settings::loadCommonSettings( QSettings* user_ini )
1359 {
1360   qDebug() << "Loading settings eventually overruled by RC file";
1361   QSettings* system_rc = objectRcSettings();
1362   beginCommonGroup( system_rc, user_ini, "Chat" );
1363   QString chat_font_string = commonValue( system_rc, user_ini,  "Font", "" ).toString();
1364 
1365   if( !chat_font_string.isEmpty() )
1366   {
1367     QFont f;
1368     if( f.fromString( chat_font_string ) )
1369       setChatFont( f );
1370     else
1371       qWarning() << "Invalid font string found in ChatFont setting value:" << chat_font_string;
1372   }
1373   else
1374     setChatFont( QApplication::font() );
1375   m_chatFontColor = commonValue( system_rc, user_ini, "FontColor", QColor( Qt::black ).name() ).toString();
1376   m_defaultChatBackgroundColor = commonValue( system_rc, user_ini, "DefaultChatBackgroundColor", m_defaultChatBackgroundColor ).toString();
1377   m_chatCompact = commonValue( system_rc, user_ini, "CompactMessage", true ).toBool();
1378   m_chatShowMessageTimestamp = commonValue( system_rc, user_ini, "ShowMessageTimestamp", true ).toBool();
1379   m_beepOnNewMessageArrived = commonValue( system_rc, user_ini, "BeepOnNewMessageArrived", true ).toBool();
1380   m_disableBeepInUserStatusBusy = commonValue( system_rc, user_ini, "DisableBeepInUserStatusBusy", false ).toBool();
1381   m_beepInActiveWindowAlso = commonValue( system_rc, user_ini, "EnableBeepInActiveWindow", false ).toBool();
1382   m_chatUseHtmlTags = commonValue( system_rc, user_ini, "UseHtmlTags", false ).toBool();
1383   m_chatUseClickableLinks = commonValue( system_rc, user_ini, "UseClickableLinks", true ).toBool();
1384   m_chatMessageHistorySize = commonValue( system_rc, user_ini, "MessageHistorySize", 10 ).toInt();
1385   m_showEmoticons = commonValue( system_rc, user_ini, "ShowEmoticons", true ).toBool();
1386   m_showMessagesGroupByUser = commonValue( system_rc, user_ini, "ShowMessagesGroupByUsers", true ).toBool();
1387   m_chatMessageFilter = commonValue( system_rc, user_ini, "MessageFilter", m_chatMessageFilter ).toBitArray();
1388   if( m_chatMessageFilter.size() < static_cast<int>(ChatMessage::NumTypes) )
1389     m_chatMessageFilter.resize( static_cast<int>(ChatMessage::NumTypes) );
1390   m_showOnlyMessagesInDefaultChat = commonValue( system_rc, user_ini, "ShowOnlyMessagesInDefaultChat", true ).toBool();
1391   m_chatMessagesToShow = commonValue( system_rc, user_ini, "MaxMessagesToShow", defaultChatMessagesToShow() ).toInt();
1392   m_imagePreviewHeight = qMax( 48, commonValue( system_rc, user_ini, "ImagePreviewHeight", 160 ).toInt() );
1393   m_useReturnToSendMessage = commonValue( system_rc, user_ini, "UseKeyReturnToSendMessage", m_useReturnToSendMessage ).toBool();
1394   m_chatUseYourNameInsteadOfYou = commonValue( system_rc, user_ini, "UseYourNameInsteadOfYou", false ).toBool();
1395   m_chatClearAllReadMessages = commonValue( system_rc, user_ini, "ClearAllReadMessages", false ).toBool();
1396   m_chatUseColoredUserNames = commonValue( system_rc, user_ini, "UseColoredUserNames", true ).toBool();
1397   m_chatDefaultUserNameColor = commonValue( system_rc, user_ini, "DefaultUserNameColor", "#000" ).toString();
1398   m_chatActiveWindowOpacityLevel = qMax( 10, qMin( 100, commonValue( system_rc, user_ini, "ActiveWindowOpacityLevel", m_chatActiveWindowOpacityLevel ).toInt() ) );
1399   m_chatInactiveWindowOpacityLevel = qMax( 10, qMin( 100, commonValue( system_rc, user_ini, "InactiveWindowOpacityLevel", m_chatInactiveWindowOpacityLevel ).toInt() ) );
1400   m_chatBackgroundColor = commonValue( system_rc, user_ini, "BackgroundColor", m_chatBackgroundColor ).toString();
1401   m_chatDefaultTextColor = commonValue( system_rc, user_ini, "DefaultTextColor", m_chatDefaultTextColor ).toString();
1402   m_chatSystemTextColor = commonValue( system_rc, user_ini, "SystemTextColor", m_chatSystemTextColor ).toString();
1403   m_enableDefaultChatNotifications = commonValue( system_rc, user_ini, "EnableDefaultChatNotifications", m_enableDefaultChatNotifications ).toBool();
1404   m_useMessageTimestampWithAP = commonValue( system_rc, user_ini, "UseMessageTimestampWithAP", m_useMessageTimestampWithAP ).toBool();
1405   m_chatQuoteBackgroundColor = commonValue( system_rc, user_ini, "QuoteBackgroundColor", m_chatQuoteBackgroundColor ).toString();
1406   m_chatQuoteTextColor = commonValue( system_rc, user_ini, "QuoteTextColor", m_chatQuoteTextColor ).toString();
1407   m_chatOnSendingMessage = commonValue( system_rc, user_ini, "CloseOnSendingMessage", SkipOnSendingMessage ).toInt();
1408   if( m_chatOnSendingMessage < 0 || m_chatOnSendingMessage >= NumChatOnSendingMessageTypes )
1409     m_chatOnSendingMessage = SkipOnSendingMessage;
1410   endCommonGroup( system_rc, user_ini );
1411 
1412   beginCommonGroup( system_rc, user_ini, "User" );
1413   setUserRecognitionMethod( commonValue( system_rc, user_ini, "RecognitionMethod", m_userRecognitionMethod ).toInt() );
1414   m_localUser.setHash( user_ini->value( "LocalHash", m_localUser.hash() ).toString() );
1415   m_localUser.setName( user_ini->value( "LocalName", m_localUser.name() ).toString() );
1416   m_localUser.setColor( user_ini->value( "LocalColor", m_localUser.color() ).toString() );
1417   m_localUser.setStatusDescription( user_ini->value( "LocalLastStatusDescription", m_localUser.statusDescription() ).toString() );
1418   m_autoUserAway = commonValue( system_rc, user_ini, "AutoAwayStatus", false ).toBool();
1419   m_userAwayTimeout = qMax( commonValue( system_rc, user_ini, "UserAwayTimeout", 10 ).toInt(), 1 ); // minutes
1420   if( m_useEasyConnection )
1421   {
1422     m_useDefaultPassword = true;
1423     m_askChangeUserAtStartup = false;
1424     m_askPasswordAtStartup = false;
1425   }
1426   else
1427   {
1428     m_useDefaultPassword = user_ini->value( "UseDefaultPassword", true ).toBool();
1429     m_askChangeUserAtStartup = user_ini->value( "AskChangeUserAtStartup", m_firstTime ).toBool();
1430     m_askPasswordAtStartup = user_ini->value( "AskPasswordAtStartup", false ).toBool();
1431   }
1432 
1433   m_savePassword = user_ini->value( "SavePassword", false ).toBool();
1434   QString enc_pass = "";
1435   if( m_savePassword )
1436     enc_pass = simpleDecrypt( user_ini->value( "EncPwd", "" ).toString() );
1437   setPassword( enc_pass );
1438   m_saveUserList = commonValue( system_rc, user_ini, "SaveUsers", m_saveUserList ).toBool();
1439   QString user_list = user_ini->value( "List", "" ).toString();
1440   if( !user_list.isEmpty() )
1441     m_userList = simpleDecrypt( user_list ).split( QString( "\n" ) );
1442   else
1443     m_userList = QStringList();
1444   QString user_status_list = user_ini->value( "StatusList", "" ).toString();
1445   if( !user_status_list.isEmpty() )
1446     m_userStatusList = simpleDecrypt( user_status_list ).split( QString( "\n" ) );
1447   else
1448     m_userStatusList = QStringList();
1449    m_refusedChats = user_ini->value( "RefusedChats", QStringList() ).toStringList();
1450 
1451   m_maxUserStatusDescriptionInList = commonValue( system_rc, user_ini, "MaxStatusDescriptionInList", m_maxUserStatusDescriptionInList ).toInt();
1452   m_presetMessages = commonValue( system_rc, user_ini, "PresetMessages", QMap<QString,QVariant>() ).toMap();
1453   m_maxDaysOfUserInactivity = commonValue( system_rc, user_ini, "MaxDaysOfUserInactivity", m_maxDaysOfUserInactivity ).toInt();
1454   m_removeInactiveUsers = commonValue( system_rc, user_ini, "RemoveInactiveUsers", true ).toBool();
1455   endCommonGroup( system_rc, user_ini );
1456 
1457   beginCommonGroup( system_rc, user_ini, "Gui" );
1458   m_mainBarIconSize = commonValue( system_rc, user_ini, "MainBarIconSize", QSize( 24, 24 ) ).toSize();
1459   m_avatarIconSize = commonValue( system_rc, user_ini, "AvatarIconSize", QSize( 28, 28 ) ).toSize();
1460   m_resetGeometryAtStartup = commonValue( system_rc, user_ini, "ResetWindowGeometryAtStartup", m_resetGeometryAtStartup ).toBool();
1461   m_saveGeometryOnExit = commonValue( system_rc, user_ini, "SaveGeometryOnExit", m_saveGeometryOnExit ).toBool();
1462   m_language = commonValue( system_rc, user_ini, "Language", QLocale::system().name() ).toString();
1463   if( m_language.size() > 2 )
1464     m_language.resize( 2 );
1465   m_keyEscapeMinimizeInTray = commonValue( system_rc, user_ini, "KeyEscapeMinimizeInTray", true ).toBool();
1466 #ifdef Q_OS_MAC
1467   m_closeMinimizeInTray = false;
1468 #else
1469   if( m_settingsVersion < 18 )
1470     m_closeMinimizeInTray = commonValue( system_rc, user_ini, "MinimizeInTray", true ).toBool();
1471   else
1472     m_closeMinimizeInTray = commonValue( system_rc, user_ini, "CloseMinimizeInTray", true ).toBool();
1473 #endif
1474   m_stayOnTop = commonValue( system_rc, user_ini, "StayOnTop", false ).toBool();
1475   m_raiseOnNewMessageArrived = commonValue( system_rc, user_ini, "RaiseOnNewMessageArrived", false ).toBool();
1476   m_raiseMainWindowOnNewMessageArrived = commonValue( system_rc, user_ini, "RaiseMainWindowOnNewMessageArrived", false ).toBool();
1477   m_alwaysShowFileTransferProgress = commonValue( system_rc, user_ini, "AlwaysShowFileTransferProgress", false ).toBool();
1478   m_alwaysOpenChatOnNewMessageArrived = commonValue( system_rc, user_ini, "AlwaysOpenChatOnNewMessageArrived", true ).toBool();
1479   m_loadOnTrayAtStartup = commonValue( system_rc, user_ini, "LoadOnTrayAtStartup", false ).toBool();
1480   m_showNotificationOnTray = commonValue( system_rc, user_ini, "ShowNotificationOnTray", true ).toBool();
1481   m_showOnlyMessageNotificationOnTray = commonValue( system_rc, user_ini, "ShowOnlyMessageNotificationOnTray", true ).toBool();
1482   m_trayMessageTimeout = qMax( commonValue( system_rc, user_ini, "ShowNotificationOnTrayTimeout", 10000 ).toInt(), 1000 );
1483   m_showChatMessageOnTray = commonValue( system_rc, user_ini, "ShowChatMessageOnTray", false ).toBool();
1484   m_textSizeInChatMessagePreviewOnTray = commonValue( system_rc, user_ini, "TextSizeInChatMessagePreviewOnTray", 40 ).toInt();
1485   m_showFileTransferCompletedOnTray = commonValue( system_rc, user_ini, "ShowFileTransferCompletedOnTray", true ).toBool();
1486   m_chatAutoSave = commonValue( system_rc, user_ini, "ChatAutoSave", true ).toBool();
1487   m_tickIntervalChatAutoSave = commonValue( system_rc, user_ini, "TickIntervalChatAutoSave", m_tickIntervalChatAutoSave ).toInt();
1488   m_chatSaveUnsentMessages = commonValue( system_rc, user_ini, "ChatSaveUnsentMessages", true ).toBool();
1489   m_chatMaxLineSaved = commonValue( system_rc, user_ini, "ChatMaxLineSaved", 9000 ).toInt();
1490   m_chatSaveFileTransfers = commonValue( system_rc, user_ini, "ChatSaveFileTransfers", m_chatAutoSave ).toBool();
1491   m_chatSaveSystemMessages = commonValue( system_rc, user_ini, "ChatSaveSystemMessages", false ).toBool();
1492   m_showChatToolbar = commonValue( system_rc, user_ini, "ShowChatToolbar", true ).toBool();
1493   m_showOnlyOnlineUsers = commonValue( system_rc, user_ini, "ShowOnlyOnlineUsers", false ).toBool();
1494   m_showUserPhoto = commonValue( system_rc, user_ini, "ShowUserPhoto", true ).toBool();
1495   m_showVCardOnRightClick = commonValue( system_rc, user_ini, "ShowVCardOnRightClick", true ).toBool();
1496   m_showEmoticonMenu = commonValue( system_rc, user_ini, "ShowEmoticonMenu", false ).toBool();
1497   m_showPresetMessages = commonValue( system_rc, user_ini, "ShowPresetMessages", false ).toBool();
1498   m_emoticonSizeInEdit = qMax( 12, commonValue( system_rc, user_ini, "EmoticonSizeInEdit", m_emoticonSizeInEdit ).toInt() );
1499   m_emoticonSizeInChat = qMax( 12, commonValue( system_rc, user_ini, "EmoticonSizeInChat", m_emoticonSizeInChat ).toInt() );
1500   m_emoticonSizeInMenu = commonValue( system_rc, user_ini, "EmoticonSizeInMenu", m_emoticonSizeInMenu ).toInt();
1501   m_emoticonInRecentMenu = commonValue( system_rc, user_ini, "EmoticonsInRecentMenu", m_emoticonInRecentMenu ).toInt();
1502   m_favoriteEmoticons = user_ini->value( "FavoriteEmoticons", QStringList() ).toStringList();
1503   m_recentEmoticons = user_ini->value( "RecentEmoticons", QStringList() ).toStringList();
1504   m_useFontEmoticons = commonValue( system_rc, user_ini, "UseFontEmoticons", m_useFontEmoticons ).toBool();
1505 #if QT_VERSION >= 0x050000
1506   m_useHiResEmoticons = commonValue( system_rc, user_ini, "UseHighResolutionEmoticons", m_useHiResEmoticons ).toBool();
1507 #else
1508   m_useHiResEmoticons = false;
1509 #endif
1510   m_showMinimizedAtStartup = commonValue( system_rc, user_ini, "ShowMinimizedAtStartup", m_startMinimized ).toBool();
1511   m_promptOnCloseEvent = commonValue( system_rc, user_ini, "PromptOnCloseEvent", m_promptOnCloseEvent ).toBool();
1512   m_showUserStatusBackgroundColor = commonValue( system_rc, user_ini, "ShowUserStatusBackgroundColor", false ).toBool();
1513   m_showUserStatusDescription = commonValue( system_rc, user_ini, "ShowUserStatusDescription", true ).toBool();
1514   m_shortcuts = commonValue( system_rc, user_ini, "Shortcuts", QStringList() ).toStringList();
1515   m_useShortcuts = commonValue( system_rc, user_ini, "UseShortcuts", false ).toBool();
1516   m_useNativeDialogs = commonValue( system_rc, user_ini, "UseNativeFileDialogs", m_useNativeDialogs ).toBool();
1517   m_homeShowMessageTimestamp = commonValue( system_rc, user_ini, "ShowActivitiesTimestamp", false ).toBool();
1518   m_homeBackgroundColor = commonValue( system_rc, user_ini, "HomeBackgroundColor", m_homeBackgroundColor ).toString();
1519   m_userListBackgroundColor = commonValue( system_rc, user_ini, "UserListBackgroundColor", m_userListBackgroundColor ).toString();
1520   m_chatListBackgroundColor = commonValue( system_rc, user_ini, "ChatListBackgroundColor", m_chatListBackgroundColor ).toString();
1521   m_groupListBackgroundColor = commonValue( system_rc, user_ini, "GroupListBackgroundColor", m_groupListBackgroundColor ).toString();
1522   m_savedChatListBackgroundColor = commonValue( system_rc, user_ini, "SavedChatListBackgroundColor", m_savedChatListBackgroundColor ).toString();
1523   m_usePreviewFileDialog = commonValue( system_rc, user_ini, "UsePreviewFileDialog", m_usePreviewFileDialog ).toBool();
1524   m_previewFileDialogImageSize = qMax( 100, commonValue( system_rc, user_ini, "PreviewFileDialogImageSize", m_previewFileDialogImageSize ).toInt() );
1525   m_userSortingMode = qMax( 0, commonValue( system_rc, user_ini, "UserSortingMode", 0 ).toInt() );
1526   m_sortUsersAscending = commonValue( system_rc, user_ini, "SortUsersAscending", true ).toBool();
1527   m_showTextInModeRTL = commonValue( system_rc, user_ini, "ShowChatTextInModeRTL", m_showTextInModeRTL ).toBool();
1528   m_playBuzzSound = commonValue( system_rc, user_ini, "PlayBuzzSound", true ).toBool();
1529   bool open_chat_in_new_window = commonValue( system_rc, user_ini, "AlwaysOpenNewFloatingChat", !m_showChatsInOneWindow ).toBool();
1530   m_showChatsInOneWindow = commonValue( system_rc, user_ini, "ShowChatsInOneWindow", !open_chat_in_new_window ).toBool();
1531   m_iconSourcePath = commonValue( system_rc, user_ini, "IconSourcePath", m_iconSourcePath ).toString();
1532   m_emoticonSourcePath = commonValue( system_rc, user_ini, "EmoticonSourcePath", m_emoticonSourcePath ).toString();
1533   m_maxChatsToOpenAfterSendingMessage = commonValue( system_rc, user_ini, "MaxChatsToOpenAfterSendingMessage", m_maxChatsToOpenAfterSendingMessage ).toInt();
1534   m_showUsersOnConnection = commonValue( system_rc, user_ini, "ShowUsersOnConnection", m_showUsersOnConnection ).toBool();
1535   m_showChatsOnConnection = commonValue( system_rc, user_ini, "ShowChatsOnConnection", m_showChatsOnConnection ).toBool();
1536   if( m_showChatsOnConnection && m_showUsersOnConnection )
1537     m_showUsersOnConnection = false;
1538   m_hideEmptyChatsInList = commonValue( system_rc, user_ini, "HideEmptyChatsInList", m_hideEmptyChatsInList ).toBool();
1539   m_enableMaximizeButton = commonValue( system_rc, user_ini, "EnableMaximizeButton", false ).toBool();
1540 #if QT_VERSION > 0x050000
1541   m_useDarkStyle = user_ini->value( "UseDarkStyle", m_useDarkStyle ).toBool();
1542 #else
1543   m_useDarkStyle = false;
1544 #endif
1545   m_showUsersInWorkgroups = commonValue( system_rc, user_ini, "ShowUsersInWorkgroups", false ).toBool();
1546   m_openChatWhenSendNewMessage = user_ini->value( "OpenChatWhenSendNewMessage", true ).toBool();
1547   m_sendNewMessageIndividually = user_ini->value( "SendNewMessageIndividually", false ).toBool();
1548   m_useUserFirstNameFirstInFullName = commonValue( system_rc, user_ini, "ShowUserFirstNameFirstInFullName", useUserFirstNameFirstInFullNameFromLanguage() ).toBool();
1549   m_resetMinimumWidthForStyle = commonValue( system_rc, user_ini, "ResetMinimumWidthForStyle", m_resetMinimumWidthForStyle ).toBool();
1550   endCommonGroup( system_rc, user_ini );
1551 
1552   beginCommonGroup( system_rc, user_ini, "Tools" );
1553   m_logToFile = commonValue( system_rc, user_ini, "LogToFile", false ).toBool();
1554   m_maxLogLines = commonValue( system_rc, user_ini, "MaxLogLines", m_maxLogLines ).toInt();
1555   m_useSpellChecker = commonValue( system_rc, user_ini, "UseSpellChecker", true ).toBool();
1556   m_useWordCompleter = commonValue( system_rc, user_ini, "UseWordCompleter", false ).toBool();
1557   m_checkNewVersionAtStartup = commonValue( system_rc, user_ini, "SearchForNewVersionAtStartup", m_checkNewVersionAtStartup ).toBool();
1558   m_postUsageStatistics = commonValue( system_rc, user_ini, "SendAnonymousUsageStatistics", m_postUsageStatistics ).toBool();
1559   m_dictionaryPath = checkFilePath( user_ini->value( "DictionaryPath", "" ).toString(), "" );
1560   m_applicationUuid = user_ini->value( "Uuid", "" ).toString();
1561   m_applicationUuidCreationDate = user_ini->value( "UuidCreationDate", QDate::currentDate() ).toDate();
1562   m_statsPostDate = user_ini->value( "StatsPostDate", QDate() ).toDate();
1563   endCommonGroup( system_rc, user_ini );
1564 
1565   beginCommonGroup( system_rc, user_ini, "Misc" );
1566   m_tickIntervalCheckIdle = qMax( commonValue( system_rc, user_ini, "TickIntervalCheckIdle", m_tickIntervalCheckIdle ).toInt(), 2 );
1567   m_tickIntervalCheckNetwork = qMax( commonValue( system_rc, user_ini, "TickIntervalCheckNetwork", m_tickIntervalCheckNetwork ).toInt(), 5 );
1568   m_tickIntervalBroadcasting = qMax( commonValue( system_rc, user_ini, "TickIntervalBroadcasting", m_tickIntervalBroadcasting ).toInt(), 0 );
1569   NetworkAddress local_user_network_address = m_localUser.networkAddress();
1570   local_user_network_address.setHostPort( static_cast<quint16>(commonValue( system_rc, user_ini, "ListenerPort", DEFAULT_LISTENER_PORT ).toUInt()) );
1571   m_localUser.setNetworkAddress( local_user_network_address );
1572   m_pongTimeout = qMax( commonValue( system_rc, user_ini, "ConnectionActivityTimeout_ms", PONG_DEFAULT_TIMEOUT ).toInt(), 13000 );
1573   if( m_pongTimeout > 40000 )
1574     m_pongTimeout = 40000;
1575   m_writingTimeout = qMax( commonValue( system_rc, user_ini, "WritingTimeout_ms", 3000 ).toInt(), 3000 );
1576   m_tickIntervalConnectionTimeout = qMax( commonValue( system_rc, user_ini, "TickIntervalConnectionTimeout", m_tickIntervalConnectionTimeout ).toInt(), 5 );
1577   if( m_settingsVersion < 6 && m_tickIntervalConnectionTimeout < TICK_INTERVAL_CONNECTION_TIMEOUT )
1578     m_tickIntervalConnectionTimeout = TICK_INTERVAL_CONNECTION_TIMEOUT;
1579   m_useLowDelayOptionOnSocket = commonValue( system_rc, user_ini, "UseLowDelayOptionOnSocket", false ).toBool();
1580   m_delayConnectionAtStartup = qMax( 3000, commonValue( system_rc, user_ini, "DelayConnectionAtStartup_ms", m_delayConnectionAtStartup ).toInt() );
1581   if( m_delayConnectionAtStartup > 50000 )
1582     m_delayConnectionAtStartup = 50000;
1583   m_delayContactUsers = qMax( 7000, commonValue( system_rc, user_ini, "DelayContactUsers_ms", DELAY_CONTACT_USERS ).toInt() );
1584   if( m_delayContactUsers > 30000 )
1585     m_delayContactUsers = 30000;
1586   m_sendOfflineMessagesToDefaultChat = commonValue( system_rc, user_ini, "SendOfflineMessagesToDefaultChat", false ).toBool();
1587   m_saveMessagesTimestamp = user_ini->value( "SaveMessagesTimestamp", QDateTime() ).toDateTime();
1588   if( m_saveMessagesTimestamp.isNull() )
1589   {
1590     qDebug() << "Generating new save messages timestamp";
1591     m_saveMessagesTimestamp = QDateTime::currentDateTime();
1592   }
1593   m_clearCacheAfterDays = qMax( -1, commonValue( system_rc, user_ini, "ClearCacheAfterDays", m_clearCacheAfterDays ).toInt() );
1594   m_removePartiallyDownloadedFilesAfterDays = qMax( -1, commonValue( system_rc, user_ini, "RemovePartiallyDownloadedFilesAfterDays", m_removePartiallyDownloadedFilesAfterDays ).toInt() );
1595   endCommonGroup( system_rc, user_ini );
1596 
1597   beginCommonGroup( system_rc, user_ini, "Network");
1598   QString local_host_address = user_ini->value( "LocalHostAddressForced", "" ).toString();
1599   if( !local_host_address.isEmpty() )
1600     m_localHostAddressForced = QHostAddress( local_host_address );
1601   m_networkAddressList = commonValue( system_rc, user_ini, "UserPathList", QStringList() ).toStringList();
1602   m_localSubnetForced = commonValue( system_rc, user_ini, "LocalSubnetForced", "" ).toString();
1603   m_localUser.setWorkgroups( commonValue( system_rc, user_ini, "Workgroups", QStringList() ).toStringList() );
1604   m_acceptConnectionsOnlyFromWorkgroups = commonValue( system_rc, user_ini, "AcceptConnectionsOnlyFromWorkgroups", m_acceptConnectionsOnlyFromWorkgroups ).toBool();
1605 
1606 #ifdef BEEBEEP_USE_MULTICAST_DNS
1607   m_useMulticastDns = commonValue( system_rc, user_ini, "UseMulticastDns", m_useMulticastDns ).toBool();
1608 #endif
1609   m_maxUsersToConnectInATick = commonValue( system_rc, user_ini, "MaxUsersToConnectInATick", m_maxUsersToConnectInATick ).toInt();
1610   m_preventMultipleConnectionsFromSingleHostAddress = commonValue( system_rc, user_ini, "PreventMultipleConnectionsFromSingleHostAddress", m_preventMultipleConnectionsFromSingleHostAddress ).toBool();
1611   m_useHive = commonValue( system_rc, user_ini, "UseHiveProtocol", m_useHive ).toBool();
1612   m_disableSystemProxyForConnections = commonValue( system_rc, user_ini, "DisableSystemProxyForConnections", m_disableSystemProxyForConnections ).toBool();
1613   m_useDefaultMulticastGroupAddress = commonValue( system_rc, user_ini, "UseDefaultMulticastGroupAddress", m_useDefaultMulticastGroupAddress ).toBool();
1614   m_broadcastToOfflineUsers = commonValue( system_rc, user_ini, "BroadcastToOfflineUsers", m_broadcastToOfflineUsers ).toBool();
1615   m_broadcastToLocalSubnetAlways = commonValue( system_rc, user_ini, "BroadcastToLocalSubnet", m_broadcastToLocalSubnetAlways ).toBool();
1616   m_ipMulticastTtl = commonValue( system_rc, user_ini, "IpMulticastTtl", m_ipMulticastTtl ).toInt();
1617   endCommonGroup( system_rc, user_ini );
1618 
1619   beginCommonGroup( system_rc, user_ini, "FileShare" );
1620   if( m_disableFileTransfer )
1621     m_enableFileTransfer = false;
1622   else
1623     m_enableFileTransfer = user_ini->value( "EnableFileTransfer", true ).toBool();
1624 
1625   if( m_enableFileTransfer )
1626   {
1627     if( m_disableFileSharing )
1628       m_enableFileSharing = false;
1629     else
1630       m_enableFileSharing = user_ini->value( "EnableFileSharing", false ).toBool();
1631 
1632     if( m_enableFileSharing )
1633       m_useShareBox = user_ini->value( "UseShareBox", false ).toBool();
1634     else
1635       m_useShareBox = false;
1636   }
1637   else
1638   {
1639     m_enableFileSharing = false;
1640     m_useShareBox = false;
1641   }
1642 
1643   m_maxFileShared = qMax( 1024, commonValue( system_rc, user_ini, "MaxSharedFiles", 8192 ).toInt() );
1644   m_shareBoxPath = checkFolderPath( user_ini->value( "ShareBoxPath", "" ).toString(), "", false );
1645   m_maxSimultaneousDownloads = commonValue( system_rc, user_ini, "MaxSimultaneousDownloads", 3 ).toInt();
1646   m_maxQueuedDownloads = qMax( 1, commonValue( system_rc, user_ini, "MaxQueuedDownloads", 400 ).toInt() );
1647   m_fileTransferConfirmTimeout = qMax( commonValue( system_rc, user_ini, "FileTransferConfirmTimeout", 30000 ).toInt(), 1000 );
1648   m_fileTransferBufferSize = qMax( commonValue( system_rc, user_ini, "FileTransferBufferSize", 65456 ).toInt(), 2048 );
1649   int mod_buffer_size = m_fileTransferBufferSize % ENCRYPTED_DATA_BLOCK_SIZE; // For a corrected encryption
1650   if( mod_buffer_size > 0 )
1651     m_fileTransferBufferSize -= mod_buffer_size;
1652   if( m_fileTransferBufferSize < 2048 )
1653     m_fileTransferBufferSize = 2048;
1654   bool automatic_file_name = commonValue( system_rc, user_ini, "SetAutomaticFileNameOnSave", false ).toBool();
1655   if( automatic_file_name )
1656     m_onExistingFileAction = GenerateNewFileName;
1657   bool overwrite_existing_files = commonValue( system_rc, user_ini, "OverwriteExistingFiles", false ).toBool();
1658   if( overwrite_existing_files )
1659     m_onExistingFileAction = OverwriteExistingFile;
1660   m_onExistingFileAction = commonValue( system_rc, user_ini, "OnExistingFileAction", (int)m_onExistingFileAction ).toInt();
1661   if( m_onExistingFileAction < 0 || m_onExistingFileAction >= NumOnExistingFileActionTypes )
1662     m_onExistingFileAction = OverwriteOlderExistingFile;
1663   m_resumeFileTransfer = commonValue( system_rc, user_ini, "ResumeFileTransfer", m_resumeFileTransfer ).toBool();
1664   m_confirmOnDownloadFile = commonValue( system_rc, user_ini, "ConfirmOnDownloadFile", m_confirmOnDownloadFile ).toBool();
1665   m_downloadInUserFolder = commonValue( system_rc, user_ini, "DownloadInUserFolder", false ).toBool();
1666   m_keepModificationDateOnFileTransferred = commonValue( system_rc, user_ini, "KeepModificationDateOnFileTransferred", m_keepModificationDateOnFileTransferred ).toBool();
1667   QStringList local_share = user_ini->value( "ShareList", QStringList() ).toStringList();
1668   if( !local_share.isEmpty() )
1669   {
1670     foreach( QString share_path, local_share )
1671       m_localShare.append( Bee::convertToNativeFolderSeparator( share_path ) );
1672   }
1673   else
1674     m_localShare = local_share;
1675   endCommonGroup( system_rc, user_ini );
1676 
1677   beginCommonGroup( system_rc, user_ini, "Group" );
1678   m_saveGroupList = commonValue( system_rc, user_ini, "SaveGroups", m_saveGroupList ).toBool();
1679   m_groupSilenced = user_ini->value( "Silenced", QStringList() ).toStringList();
1680   m_groupList = user_ini->value( "List", QStringList() ).toStringList();
1681   endCommonGroup( system_rc, user_ini );
1682 
1683   beginCommonGroup( system_rc, user_ini, "ShareDesktop" );
1684   if( m_disableDesktopSharing )
1685     m_enableShareDesktop = false;
1686   else
1687     m_enableShareDesktop = commonValue( system_rc, user_ini, "Enable", m_enableShareDesktop ).toBool();
1688   m_shareDesktopCaptureDelay = qMax( 1000, commonValue( system_rc, user_ini, "CaptureScreenInterval", m_shareDesktopCaptureDelay ).toInt() );
1689   m_shareDesktopFitToScreen = commonValue( system_rc, user_ini, "FitToScreen", false ).toBool();
1690   m_shareDesktopImageType = commonValue( system_rc, user_ini, "ImageType", "png" ).toString();
1691   m_shareDesktopImageQuality = commonValue( system_rc, user_ini, "ImageQuality", 20 ).toInt();
1692   endCommonGroup( system_rc, user_ini );
1693 
1694   beginCommonGroup( system_rc, user_ini, "VoiceMessage" );
1695   m_voiceMessageMaxDuration = qMax( 5, commonValue( system_rc, user_ini, "MaxDuration", m_voiceMessageMaxDuration ).toInt() );
1696   m_useVoicePlayer = commonValue( system_rc, user_ini, "UseVoicePlayer", m_useVoicePlayer ).toBool();
1697   m_voiceInputDeviceName = user_ini->value( "VoiceInputDeviceName", QString() ).toString();
1698   m_voiceFileMessageContainer = commonValue( system_rc, user_ini, "VoiceFileMessageContainer", QString() ).toString();
1699   m_voiceCodec = commonValue( system_rc, user_ini, "VoiceCodec", QString() ).toString();
1700   m_voiceSampleRate = commonValue( system_rc, user_ini, "VoiceSampleRate", 0 ).toInt();
1701   m_voiceBitRate = commonValue( system_rc, user_ini, "VoiceBitRate", 0 ).toInt();
1702   m_voiceChannels = commonValue( system_rc, user_ini, "VoiceChannels", -1 ).toInt();
1703   m_voiceEncodingMode = commonValue( system_rc, user_ini, "VoiceEncodingMode", -1 ).toInt();
1704   m_voiceEncodingQuality = commonValue( system_rc, user_ini, "VoiceEncodingQuality", -1 ).toInt();
1705   m_useCustomVoiceEncoderSettings = commonValue( system_rc, user_ini, "UseCustomVoiceEncoderSettings", m_useCustomVoiceEncoderSettings ).toBool();
1706   m_useSystemVoiceEncoderSettings = commonValue( system_rc, user_ini, "UseSystemVoiceEncoderSettings", m_useSystemVoiceEncoderSettings ).toBool();
1707   endCommonGroup( system_rc, user_ini );
1708   delete system_rc;
1709 }
1710 
qtMajorVersion() const1711 QString Settings::qtMajorVersion() const
1712 {
1713   QString qt_version( qVersion() );
1714   QStringList sl_version = qt_version.split( "." );
1715   if( sl_version.isEmpty() )
1716     return QString( "0" );
1717   else
1718     return sl_version.at( 0 );
1719 }
1720 
qtMajorMinorVersion() const1721 QString Settings::qtMajorMinorVersion() const
1722 {
1723   QString qt_version( qVersion() );
1724   QStringList sl_version = qt_version.split( "." );
1725   if( sl_version.isEmpty() )
1726     return QString( "0" );
1727   else if( sl_version.size() < 2 )
1728     return sl_version.at( 0 );
1729   else
1730     return QString( "%1.%2" ).arg( sl_version.at( 0 ) ).arg( sl_version.at( 1 ) );
1731 }
1732 
save()1733 void Settings::save()
1734 {
1735   if( !m_enableSaveData )
1736   {
1737     qWarning() << "Skip savings settings because you have disabled it in RC file";
1738     return;
1739   }
1740 
1741   beeApp->setCheckSettingsFilePath( false );
1742   QSettings *sets = objectSettings();
1743   sets->clear();
1744 
1745   sets->beginGroup( "Version" );
1746   sets->setValue( "Program", version( true, false, true ) );
1747   sets->setValue( "Proto", protocolVersion() );
1748   sets->setValue( "Settings", BEEBEEP_SETTINGS_VERSION );
1749   sets->setValue( "DataStream", dataStreamVersion( false ) );
1750   sets->setValue( "BeeBang", m_settingsCreationDate );
1751   sets->setValue( "Qt", qtMajorMinorVersion() );
1752   sets->endGroup();
1753   sets->beginGroup( "Chat" );
1754   sets->setValue( "Font", m_chatFont.toString() );
1755   sets->setValue( "FontColor", m_chatFontColor );
1756   sets->setValue( "DefaultChatBackgroundColor", m_defaultChatBackgroundColor );
1757   sets->setValue( "CompactMessage", m_chatCompact );
1758   sets->setValue( "ShowMessageTimestamp", m_chatShowMessageTimestamp );
1759   sets->setValue( "BeepOnNewMessageArrived", m_beepOnNewMessageArrived );
1760   sets->setValue( "DisableBeepInUserStatusBusy", m_disableBeepInUserStatusBusy );
1761   sets->setValue( "EnableBeepInActiveWindow", m_beepInActiveWindowAlso );
1762   sets->setValue( "UseHtmlTags", m_chatUseHtmlTags );
1763   sets->setValue( "UseClickableLinks", m_chatUseClickableLinks );
1764   sets->setValue( "MessageHistorySize", m_chatMessageHistorySize );
1765   sets->setValue( "ShowEmoticons", m_showEmoticons );
1766   sets->setValue( "ShowMessagesGroupByUsers", m_showMessagesGroupByUser );
1767   sets->setValue( "MessageFilter", m_chatMessageFilter );
1768   sets->setValue( "ShowOnlyMessagesInDefaultChat", m_showOnlyMessagesInDefaultChat );
1769   sets->setValue( "MaxMessagesToShow", m_chatMessagesToShow );
1770   sets->setValue( "ImagePreviewHeight", m_imagePreviewHeight );
1771   sets->setValue( "UseKeyReturnToSendMessage", m_useReturnToSendMessage );
1772   sets->setValue( "UseYourNameInsteadOfYou", m_chatUseYourNameInsteadOfYou );
1773   sets->setValue( "ClearAllReadMessages", m_chatClearAllReadMessages );
1774   sets->setValue( "UseColoredUserNames", m_chatUseColoredUserNames );
1775   sets->setValue( "DefaultUserNameColor", m_chatDefaultUserNameColor );
1776   sets->setValue( "ActiveWindowOpacityLevel", m_chatActiveWindowOpacityLevel  );
1777   sets->setValue( "InactiveWindowOpacityLevel", m_chatInactiveWindowOpacityLevel );
1778   sets->setValue( "BackgroundColor", m_chatBackgroundColor );
1779   sets->setValue( "DefaultTextColor", m_chatDefaultTextColor );
1780   sets->setValue( "SystemTextColor", m_chatSystemTextColor );
1781   sets->setValue( "EnableDefaultChatNotifications", m_enableDefaultChatNotifications );
1782   sets->setValue( "UseMessageTimestampWithAP", m_useMessageTimestampWithAP );
1783   sets->setValue( "QuoteBackgroundColor", m_chatQuoteBackgroundColor );
1784   sets->setValue( "QuoteTextColor", m_chatQuoteTextColor );
1785   sets->setValue( "CloseOnSendingMessage", m_chatOnSendingMessage );
1786   sets->endGroup();
1787   sets->beginGroup( "User" );
1788   if( m_userRecognitionMethod != RecognizeByDefaultMethod )
1789     sets->setValue( "RecognitionMethod", m_userRecognitionMethod );
1790   sets->setValue( "LocalHash", m_localUser.hash() );
1791   sets->setValue( "LocalColor", m_localUser.color() );
1792   sets->setValue( "LocalLastStatusDescription", m_localUser.statusDescription() );
1793   sets->setValue( "AutoAwayStatus", m_autoUserAway );
1794   sets->setValue( "UserAwayTimeout", m_userAwayTimeout ); // minutes
1795   sets->setValue( "AskChangeUserAtStartup", m_askChangeUserAtStartup );
1796   sets->setValue( "UseDefaultPassword", m_useDefaultPassword );
1797   sets->setValue( "AskPasswordAtStartup", m_askPasswordAtStartup );
1798   if( m_savePassword )
1799   {
1800     sets->setValue( "SavePassword", true );
1801     sets->setValue( "EncPwd", simpleEncrypt( m_passwordBeforeHash ) );
1802   }
1803   else
1804   {
1805     sets->remove( "SavePassword" );
1806     sets->remove( "EncPwd" );
1807   }
1808 
1809   sets->setValue( "SaveUsers", m_saveUserList );
1810   if( m_saveUserList )
1811   {
1812     // I need a QString to avoid " in file ini
1813     QString user_list_to_save = simpleEncrypt( m_userList.join( QString( "\n" ) ) );
1814     sets->setValue( "List", user_list_to_save );
1815   }
1816   else
1817     sets->remove( "List" );
1818 
1819   if( !m_userStatusList.isEmpty() )
1820   {
1821     QString user_status_list_to_save = simpleEncrypt( m_userStatusList.join( QString( "\n" ) ) );
1822     sets->setValue( "StatusList", user_status_list_to_save );
1823   }
1824   else
1825     sets->remove( "StatusList" );
1826 
1827   sets->setValue( "MaxStatusDescriptionInList", m_maxUserStatusDescriptionInList );
1828   sets->setValue( "PresetMessages", m_presetMessages );
1829   sets->setValue( "RefusedChats", m_refusedChats );
1830   sets->setValue( "MaxDaysOfUserInactivity", m_maxDaysOfUserInactivity );
1831   sets->setValue( "RemoveInactiveUsers", m_removeInactiveUsers );
1832   sets->endGroup();
1833 
1834   sets->beginGroup( "VCard" );
1835   sets->setValue( "NickName", m_localUser.vCard().nickName() );
1836   sets->setValue( "FirstName", m_localUser.vCard().firstName() );
1837   sets->setValue( "LastName", m_localUser.vCard().lastName() );
1838   sets->setValue( "Birthday", m_localUser.vCard().birthday() );
1839   sets->setValue( "Email", m_localUser.vCard().email() );
1840   sets->setValue( "Photo", m_localUser.vCard().photo() );
1841   sets->setValue( "Phone", m_localUser.vCard().phoneNumber() );
1842   sets->setValue( "Info", m_localUser.vCard().info() );
1843   sets->endGroup();
1844   sets->beginGroup( "Gui" );
1845   sets->setValue( "MainWindowGeometry", m_guiGeometry );
1846   sets->setValue( "MainWindowState", m_guiState );
1847   sets->setValue( "FloatingChatGeometry", m_floatingChatGeometry );
1848   sets->setValue( "FloatingChatState", m_floatingChatState );
1849   sets->setValue( "FloatingChatSplitterState", m_floatingChatSplitterState );
1850   sets->setValue( "CreateMessageGeometry", m_createMessageGeometry );
1851   sets->setValue( "FileSharingGeometry", m_fileSharingGeometry );
1852   sets->setValue( "MainBarIconSize", m_mainBarIconSize );
1853   sets->setValue( "AvatarIconSize", m_avatarIconSize );
1854   sets->setValue( "Language", m_language );
1855   sets->setValue( "LastDirectorySelected", m_lastDirectorySelected );
1856   sets->setValue( "DownloadDirectory", m_downloadDirectory );
1857   sets->setValue( "LogFolderPath", m_logPath );
1858   sets->setValue( "PluginPath", m_pluginPath );
1859   sets->setValue( "LanguagePath", m_languagePath );
1860   sets->setValue( "KeyEscapeMinimizeInTray", m_keyEscapeMinimizeInTray );
1861   sets->setValue( "CloseMinimizeInTray", m_closeMinimizeInTray );
1862   sets->setValue( "StayOnTop", m_stayOnTop );
1863   sets->setValue( "BeepFilePath", m_beepFilePath );
1864   sets->setValue( "RaiseOnNewMessageArrived", m_raiseOnNewMessageArrived );
1865   sets->setValue( "RaiseMainWindowOnNewMessageArrived", m_raiseMainWindowOnNewMessageArrived );
1866   sets->setValue( "AlwaysShowFileTransferProgress", m_alwaysShowFileTransferProgress );
1867   sets->setValue( "AlwaysOpenChatOnNewMessageArrived", m_alwaysOpenChatOnNewMessageArrived );
1868   sets->setValue( "LoadOnTrayAtStartup", m_loadOnTrayAtStartup );
1869   sets->setValue( "ShowNotificationOnTray", m_showNotificationOnTray );
1870   sets->setValue( "ShowOnlyMessageNotificationOnTray", m_showOnlyMessageNotificationOnTray );
1871   sets->setValue( "ShowNotificationOnTrayTimeout", m_trayMessageTimeout );
1872   sets->setValue( "ShowChatMessageOnTray", m_showChatMessageOnTray );
1873   sets->setValue( "TextSizeInChatMessagePreviewOnTray", m_textSizeInChatMessagePreviewOnTray );
1874   sets->setValue( "ShowFileTransferCompletedOnTray", m_showFileTransferCompletedOnTray );
1875   sets->setValue( "ChatAutoSave", m_chatAutoSave );
1876   sets->setValue( "TickIntervalChatAutoSave", m_tickIntervalChatAutoSave );
1877   sets->setValue( "ChatMaxLineSaved", m_chatMaxLineSaved );
1878   sets->setValue( "ChatSaveUnsentMessages", m_chatSaveUnsentMessages );
1879   sets->setValue( "ChatSaveFileTransfers", m_chatSaveFileTransfers );
1880   sets->setValue( "ChatSaveSystemMessages", m_chatSaveSystemMessages );
1881   sets->setValue( "ShowChatToolbar", m_showChatToolbar );
1882   sets->setValue( "ShowOnlyOnlineUsers", m_showOnlyOnlineUsers );
1883   sets->setValue( "ShowUserPhoto", m_showUserPhoto );
1884   sets->setValue( "ShowVCardOnRightClick", m_showVCardOnRightClick );
1885   sets->setValue( "ResetWindowGeometryAtStartup", m_resetGeometryAtStartup );
1886   sets->setValue( "SaveGeometryOnExit", m_saveGeometryOnExit );
1887   sets->setValue( "ShowEmoticonMenu", m_showEmoticonMenu );
1888   sets->setValue( "ShowPresetMessages", m_showPresetMessages );
1889   sets->setValue( "EmoticonSizeInEdit", m_emoticonSizeInEdit );
1890   sets->setValue( "EmoticonSizeInChat", m_emoticonSizeInChat );
1891   sets->setValue( "EmoticonSizeInMenu", m_emoticonSizeInMenu );
1892   sets->setValue( "EmoticonsInRecentMenu", m_emoticonInRecentMenu );
1893   sets->setValue( "FavoriteEmoticons", m_favoriteEmoticons );
1894   sets->setValue( "RecentEmoticons", m_recentEmoticons );
1895   sets->setValue( "UseFontEmoticons", m_useFontEmoticons );
1896   sets->setValue( "UseHighResolutionEmoticons", m_useHiResEmoticons );
1897   sets->setValue( "ShowMinimizedAtStartup", m_showMinimizedAtStartup );
1898   sets->setValue( "PromptOnCloseEvent", m_promptOnCloseEvent );
1899   sets->setValue( "ShowUserStatusBackgroundColor", m_showUserStatusBackgroundColor );
1900   sets->setValue( "ShowUserStatusDescription", m_showUserStatusDescription );
1901   sets->setValue( "Shortcuts", m_shortcuts );
1902   sets->setValue( "UseShortcuts", m_useShortcuts );
1903   sets->setValue( "UseNativeFileDialogs", m_useNativeDialogs );
1904   sets->setValue( "ShowActivitiesTimestamp", m_homeShowMessageTimestamp );
1905   sets->setValue( "HomeBackgroundColor", m_homeBackgroundColor );
1906   sets->setValue( "UserListBackgroundColor", m_userListBackgroundColor );
1907   sets->setValue( "ChatListBackgroundColor", m_chatListBackgroundColor );
1908   sets->setValue( "GroupListBackgroundColor", m_groupListBackgroundColor );
1909   sets->setValue( "SavedChatListBackgroundColor", m_savedChatListBackgroundColor );
1910   sets->setValue( "UsePreviewFileDialog", m_usePreviewFileDialog );
1911   sets->setValue( "PreviewFileDialogGeometry", m_previewFileDialogGeometry );
1912   sets->setValue( "PreviewFileDialogImageSize", m_previewFileDialogImageSize );
1913   sets->setValue( "UserSortingMode", m_userSortingMode );
1914   sets->setValue( "SortUsersAscending", m_sortUsersAscending );
1915   sets->setValue( "ShowChatTextInModeRTL", m_showTextInModeRTL );
1916   sets->setValue( "PlayBuzzSound", m_playBuzzSound );
1917   sets->setValue( "ShowChatsInOneWindow", m_showChatsInOneWindow );
1918   sets->setValue( "IconSourcePath", m_iconSourcePath );
1919   sets->setValue( "EmoticonSourcePath", m_emoticonSourcePath );
1920   sets->setValue( "MaxChatsToOpenAfterSendingMessage", m_maxChatsToOpenAfterSendingMessage );
1921   sets->setValue( "ShowUsersOnConnection", m_showUsersOnConnection );
1922   sets->setValue( "ShowChatsOnConnection", m_showChatsOnConnection );
1923   sets->setValue( "HideEmptyChatsInList", m_hideEmptyChatsInList );
1924   sets->setValue( "EnableMaximizeButton", m_enableMaximizeButton );
1925   sets->setValue( "UseDarkStyle", m_useDarkStyle );
1926   sets->setValue( "ShowUsersInWorkgroups", m_showUsersInWorkgroups );
1927   sets->setValue( "OpenChatWhenSendNewMessage", m_openChatWhenSendNewMessage );
1928   sets->setValue( "SendNewMessageIndividually", m_sendNewMessageIndividually );
1929   sets->setValue( "ShowUserFirstNameFirstInFullName", m_useUserFirstNameFirstInFullName );
1930   sets->setValue( "ResetMinimumWidthForStyle", m_resetMinimumWidthForStyle );
1931   sets->endGroup();
1932   sets->beginGroup( "Tools" );
1933   sets->setValue( "LogToFile", m_logToFile );
1934   sets->setValue( "UseSpellChecker", m_useSpellChecker );
1935   sets->setValue( "UseWordCompleter", m_useWordCompleter );
1936   sets->setValue( "DictionaryPath", m_dictionaryPath );
1937   sets->setValue( "SearchForNewVersionAtStartup", m_checkNewVersionAtStartup );
1938   sets->setValue( "SendAnonymousUsageStatistics", m_postUsageStatistics );
1939   sets->setValue( "Uuid", m_applicationUuid );
1940   sets->setValue( "UuidCreationDate", m_applicationUuidCreationDate );
1941   sets->setValue( "StatsPostDate", m_statsPostDate );
1942   sets->endGroup();
1943   sets->beginGroup( "Misc" );
1944   sets->setValue( "TickIntervalCheckIdle", m_tickIntervalCheckIdle );
1945   sets->setValue( "TickIntervalCheckNetwork", m_tickIntervalCheckNetwork );
1946   sets->setValue( "ListenerPort", m_localUser.networkAddress().hostPort() );
1947   sets->setValue( "ConnectionActivityTimeout_ms", m_pongTimeout );
1948   sets->setValue( "WritingTimeout_ms", m_writingTimeout );
1949   sets->setValue( "DelayContactUsers_ms", m_delayContactUsers );
1950   sets->setValue( "TickIntervalConnectionTimeout", m_tickIntervalConnectionTimeout );
1951   sets->setValue( "UseLowDelayOptionOnSocket", m_useLowDelayOptionOnSocket );
1952   sets->setValue( "TickIntervalBroadcasting", m_tickIntervalBroadcasting );
1953   sets->setValue( "DelayConnectionAtStartup_ms", m_delayConnectionAtStartup );
1954   sets->setValue( "SendOfflineMessagesToDefaultChat", m_sendOfflineMessagesToDefaultChat );
1955   sets->setValue( "SaveMessagesTimestamp", m_saveMessagesTimestamp );
1956   sets->setValue( "ClearCacheAfterDays", m_clearCacheAfterDays );
1957   sets->setValue( "RemovePartiallyDownloadedFilesAfterDays", m_removePartiallyDownloadedFilesAfterDays );
1958   sets->endGroup();
1959   sets->beginGroup( "Network");
1960 #ifdef BEEBEEP_USE_MULTICAST_DNS
1961   sets->setValue( "UseMulticastDns", m_useMulticastDns );
1962 #endif
1963   sets->setValue( "PreventMultipleConnectionsFromSingleHostAddress", m_preventMultipleConnectionsFromSingleHostAddress );
1964   if( !m_localHostAddressForced.isNull() )
1965     sets->setValue( "LocalHostAddressForced", m_localHostAddressForced.toString() );
1966   else
1967     sets->setValue( "LocalHostAddressForced", QString( "" ) );
1968   sets->setValue( "LocalSubnetForced", m_localSubnetForced );
1969   sets->setValue( "UserPathList", m_networkAddressList );
1970   sets->setValue( "AcceptConnectionsOnlyFromWorkgroups", m_acceptConnectionsOnlyFromWorkgroups );
1971   sets->setValue( "Workgroups", m_localUser.workgroups() );
1972   sets->setValue( "MaxUsersToConnectInATick", m_maxUsersToConnectInATick );
1973   sets->setValue( "UseHiveProtocol", m_useHive );
1974   sets->setValue( "DisableSystemProxyForConnections", m_disableSystemProxyForConnections );
1975   sets->setValue( "UseDefaultMulticastGroupAddress", m_useDefaultMulticastGroupAddress );
1976   sets->setValue( "BroadcastToOfflineUsers", m_broadcastToOfflineUsers );
1977   sets->setValue( "BroadcastToLocalSubnet", m_broadcastToLocalSubnetAlways );
1978   sets->setValue( "IpMulticastTtl", m_ipMulticastTtl );
1979   sets->endGroup();
1980   sets->beginGroup( "FileShare" );
1981   sets->setValue( "EnableFileTransfer", m_enableFileTransfer );
1982   sets->setValue( "EnableFileSharing", m_enableFileSharing );
1983   sets->setValue( "UseShareBox", m_useShareBox );
1984   sets->setValue( "MaxSharedFiles", m_maxFileShared );
1985   sets->setValue( "ShareBoxPath", m_shareBoxPath );
1986   sets->setValue( "OnExistingFileAction", m_onExistingFileAction );
1987   sets->setValue( "ResumeFileTransfer", m_resumeFileTransfer );
1988   sets->setValue( "FileTransferConfirmTimeout", m_fileTransferConfirmTimeout );
1989   sets->setValue( "FileTransferBufferSize", m_fileTransferBufferSize );
1990   sets->setValue( "MaxSimultaneousDownloads", m_maxSimultaneousDownloads );
1991   sets->setValue( "MaxQueuedDownloads", m_maxQueuedDownloads );
1992   sets->setValue( "ConfirmOnDownloadFile", m_confirmOnDownloadFile );
1993   sets->setValue( "ShareList", m_localShare );
1994   sets->setValue( "DownloadInUserFolder", m_downloadInUserFolder );
1995   sets->setValue( "KeepModificationDateOnFileTransferred", m_keepModificationDateOnFileTransferred );
1996   sets->endGroup();
1997 
1998   sets->beginGroup( "Group" );
1999   sets->setValue( "SaveGroups", m_saveGroupList );
2000   if( m_saveGroupList && !m_groupList.isEmpty() )
2001   {
2002     sets->setValue( "Silenced", m_groupSilenced );
2003     sets->setValue( "List", m_groupList );
2004   }
2005   sets->endGroup();
2006 
2007   sets->beginGroup( "ShareDesktop" );
2008   sets->setValue( "Enable", m_enableShareDesktop );
2009   sets->setValue( "CaptureScreenInterval", m_shareDesktopCaptureDelay );
2010   sets->setValue( "FitToScreen", m_shareDesktopFitToScreen );
2011   sets->setValue( "ImageType", m_shareDesktopImageType );
2012   sets->setValue( "ImageQuality", m_shareDesktopImageQuality );
2013   sets->endGroup();
2014 
2015   sets->beginGroup( "VoiceMessage" );
2016   sets->setValue( "MaxDuration", m_voiceMessageMaxDuration );
2017   sets->setValue( "UseVoicePlayer", m_useVoicePlayer );
2018   sets->setValue( "VoiceInputDeviceName", m_voiceInputDeviceName );
2019   sets->setValue( "VoiceFileMessageContainer", m_voiceFileMessageContainer );
2020   sets->setValue( "VoiceCodec", m_voiceCodec );
2021   sets->setValue( "VoiceSampleRate", m_voiceSampleRate );
2022   sets->setValue( "VoiceBitRate", m_voiceBitRate );
2023   sets->setValue( "VoiceChannels", m_voiceChannels );
2024   sets->setValue( "VoiceEncodingMode", m_voiceEncodingMode );
2025   sets->setValue( "VoiceEncodingQuality", m_voiceEncodingQuality );
2026   sets->setValue( "UseCustomVoiceEncoderSettings", m_useCustomVoiceEncoderSettings );
2027   sets->setValue( "UseSystemVoiceEncoderSettings", m_useSystemVoiceEncoderSettings );
2028   sets->endGroup();
2029 
2030   if( !m_pluginSettings.isEmpty() )
2031   {
2032     sets->beginGroup( "Plugin" );
2033     QStringList key_list( m_pluginSettings.keys() );
2034     sets->setValue( "List", key_list );
2035     QMap<QString, QStringList>::const_iterator it = m_pluginSettings.constBegin();
2036     while( it !=  m_pluginSettings.constEnd() )
2037     {
2038       sets->setValue( it.key(), it.value() );
2039       ++it;
2040     }
2041     sets->endGroup();
2042   }
2043 
2044   if( sets->isWritable() )
2045   {
2046     sets->sync();
2047     qDebug() << "Settings saved in" << qPrintable( Bee::convertToNativeFolderSeparator( sets->fileName() ) );
2048     m_lastSave = QDateTime::currentDateTime();
2049   }
2050 
2051 #ifdef Q_OS_WIN
2052   if( m_useSettingsFileIni )
2053     m_currentFilePath = Bee::convertToNativeFolderSeparator( sets->fileName() );
2054   else
2055     m_currentFilePath = ""; // registry path
2056 #else
2057   m_currentFilePath = Bee::convertToNativeFolderSeparator( sets->fileName() );
2058 #endif
2059 
2060   beeApp->setSettingsFilePath( m_currentFilePath );
2061   beeApp->setCheckSettingsFilePath( true );
2062   sets->deleteLater();
2063 }
2064 
askPassword() const2065 bool Settings::askPassword() const
2066 {
2067   if( askPasswordAtStartup() )
2068     return true;
2069 
2070   if( useDefaultPassword() )
2071     return false;
2072 
2073   if( !savePassword() )
2074     return true;
2075 
2076   if( m_passwordBeforeHash.isEmpty() )
2077     return true;
2078 
2079   return false;
2080 }
2081 
setLastDirectorySelectedFromFile(const QString & file_path)2082 void Settings::setLastDirectorySelectedFromFile( const QString& file_path )
2083 {
2084   QFileInfo file_info( file_path );
2085   setLastDirectorySelected( file_info.absoluteDir().absolutePath() );
2086 }
2087 
addTemporaryFilePath(const QString & file_path)2088 void Settings::addTemporaryFilePath( const QString& file_path )
2089 {
2090   if( file_path.isEmpty() )
2091     return;
2092   if( !m_tempFilePathList.contains( file_path ) )
2093   {
2094     if( QFile::exists( file_path ) )
2095     {
2096       m_tempFilePathList.append( file_path );
2097       qDebug() << "Temporary file added:" << qPrintable( file_path );
2098     }
2099   }
2100 }
2101 
isFileImageInCache(const QString & file_path) const2102 bool Settings::isFileImageInCache( const QString& file_path ) const
2103 {
2104   QFileInfo file_info( file_path );
2105   if( !Bee::isFileTypeImage( file_info.suffix() ) )
2106     return false;
2107   QString base_folder_path = Bee::convertToNativeFolderSeparator( file_info.absoluteDir().path() );
2108   if( base_folder_path == m_cacheFolder )
2109   {
2110 #ifdef BEEBEEP_DEBUG
2111     qDebug() << qPrintable( file_path ) << "is in cache";
2112 #endif
2113     return true;
2114   }
2115   else
2116   {
2117 #ifdef BEEBEEP_DEBUG
2118     qDebug() << qPrintable( file_path ) << "is NOT in cache but in:" << qPrintable( base_folder_path );
2119 #endif
2120     return false;
2121   }
2122 }
2123 
partiallyDownloadedFileExtension() const2124 QString Settings::partiallyDownloadedFileExtension() const
2125 {
2126 #ifdef Q_OS_OS2
2127   return QString( "par" );
2128 #else
2129   return QString( "part" );
2130 #endif
2131 }
2132 
clearTemporaryFiles()2133 void Settings::clearTemporaryFiles()
2134 {
2135   if( m_tempFilePathList.isEmpty() )
2136     return;
2137 
2138   foreach( QString file_path, m_tempFilePathList )
2139   {
2140     if( m_chatSaveFileTransfers && isFileImageInCache( file_path ) )
2141       continue;
2142 
2143     if( QFile::exists( file_path ) )
2144     {
2145       if( !QFile::remove( file_path ) )
2146         qWarning() << "Unable to remove temporary file:" << qPrintable( file_path );
2147       else
2148         qDebug() << "Temporary file removed:" << qPrintable( file_path );
2149     }
2150   }
2151 
2152   m_tempFilePathList.clear();
2153 }
2154 
setNotificationEnabledForGroup(const QString & group_id,bool enable_notification)2155 void Settings::setNotificationEnabledForGroup( const QString& group_id, bool enable_notification )
2156 {
2157   if( group_id.isEmpty() )
2158   {
2159     qWarning() << "Empty private group id in set notification enabled";
2160     return;
2161   }
2162 
2163   if( enable_notification )
2164   {
2165     m_groupSilenced.removeOne( group_id );
2166   }
2167   else
2168   {
2169     if( !m_groupSilenced.contains( group_id ) )
2170       m_groupSilenced.append( group_id );
2171   }
2172 }
2173 
addStartOnSystemBoot()2174 bool Settings::addStartOnSystemBoot()
2175 {
2176 #ifdef Q_OS_WIN
2177   QString program_path = Bee::convertToNativeFolderSeparator( qApp->applicationFilePath() );
2178   QSettings sets( "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat );
2179   if( sets.isWritable() )
2180   {
2181     sets.setValue( programName(), program_path );
2182     sets.sync();
2183     return true;
2184   }
2185   qWarning() << "Unable to add auto start in registry key:" << qPrintable( sets.fileName() );
2186 #endif
2187   return false;
2188 }
2189 
removeStartOnSystemBoot()2190 bool Settings::removeStartOnSystemBoot()
2191 {
2192 #ifdef Q_OS_WIN
2193   QSettings sets( "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat );
2194   if( sets.isWritable() )
2195   {
2196     sets.remove( programName() );
2197     sets.sync();
2198     return true;
2199   }
2200   qWarning() << "Unable to remove auto start from registry key:" << sets.fileName();
2201 #endif
2202   return false;
2203 }
2204 
hasStartOnSystemBoot() const2205 bool Settings::hasStartOnSystemBoot() const
2206 {
2207 #ifdef Q_OS_WIN
2208   QString program_path = qApp->applicationFilePath().replace( "/", "\\" );
2209   QSettings sets( "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat );
2210   return sets.value( programName(), "" ).toString() == program_path;
2211 #else
2212   return false;
2213 #endif
2214 }
2215 
clearNativeSettings()2216 void Settings::clearNativeSettings()
2217 {
2218   QSettings sets( QSettings::NativeFormat, QSettings::UserScope, organizationName(), programName() );
2219   if( !sets.allKeys().isEmpty() )
2220     sets.clear();
2221 }
2222 
searchDataFolder()2223 bool Settings::searchDataFolder()
2224 {
2225   qDebug() << "Searching data folder...";
2226   QString data_folder = m_addAccountNameToDataFolder ? Bee::removeInvalidCharactersForFilePath( accountNameFromSystemEnvinroment() ) : QLatin1String( "beebeep-data" );
2227   QString root_folder;
2228 #ifdef Q_OS_MAC
2229   bool rc_folder_is_writable = false;
2230 #else
2231   bool rc_folder_is_writable = Bee::folderIsWriteable( m_resourceFolder, false );
2232   #ifdef Q_OS_WIN
2233     QProcessEnvironment pe = QProcessEnvironment::systemEnvironment();
2234     QString env_program_files = pe.value( "PROGRAMFILES", QLatin1String( ":\\Program File" ) );
2235     if( !env_program_files.isEmpty() )
2236       qDebug() << "Checking if BeeBEEP is installed in system folder:" << qPrintable( env_program_files ) << "...";
2237     if( m_resourceFolder.contains( "Program Files", Qt::CaseInsensitive ) || m_resourceFolder.contains( env_program_files, Qt::CaseInsensitive ) )
2238     {
2239       qDebug() << "BeeBEEP is installed in system folder:" << qPrintable( m_resourceFolder );
2240       qDebug() << "Resource folder is default Windows Program Files and will not be used as data folder";
2241       rc_folder_is_writable = false;
2242     }
2243     else
2244       qDebug() << "BeeBEEP is installed in custom folder:" << qPrintable( m_resourceFolder );
2245   #endif
2246 #endif
2247 
2248 #if QT_VERSION >= 0x050400
2249   if( !m_dataFolderInRC.isEmpty() )
2250     root_folder = m_dataFolderInRC;
2251   else if( m_saveDataInUserApplicationFolder )
2252     root_folder = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation );
2253   else if( m_saveDataInDocumentsFolder )
2254     root_folder = QStandardPaths::writableLocation( QStandardPaths::DocumentsLocation );
2255   else
2256     root_folder = rc_folder_is_writable ? m_resourceFolder : QStandardPaths::writableLocation( QStandardPaths::AppDataLocation );
2257 #elif QT_VERSION >= 0x050000
2258   if( !m_dataFolderInRC.isEmpty() )
2259     root_folder = m_dataFolderInRC;
2260   else if( m_saveDataInUserApplicationFolder )
2261     root_folder = QString( "%1/%2" ).arg( QStandardPaths::writableLocation( QStandardPaths::DataLocation ) ).arg( programName() );
2262   else if( m_saveDataInDocumentsFolder )
2263     root_folder = QStandardPaths::writableLocation( QStandardPaths::DocumentsLocation );
2264   else
2265     root_folder = QString( "%1/%2" ).arg( rc_folder_is_writable ? m_resourceFolder : QStandardPaths::writableLocation( QStandardPaths::DataLocation ) ).arg( programName() );
2266 #else
2267   if( !m_dataFolderInRC.isEmpty() )
2268     root_folder = m_dataFolderInRC;
2269   else if( m_saveDataInUserApplicationFolder )
2270     root_folder = QDesktopServices::storageLocation( QDesktopServices::DataLocation );
2271   else if( m_saveDataInDocumentsFolder )
2272     root_folder = QDesktopServices::storageLocation( QDesktopServices::DocumentsLocation );
2273   else
2274     root_folder = rc_folder_is_writable ? m_resourceFolder : QDesktopServices::storageLocation( QDesktopServices::DataLocation );
2275 #endif
2276 
2277   if( m_addAccountNameToDataFolder || m_saveDataInDocumentsFolder )
2278     m_dataFolder = Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( root_folder, data_folder ) );
2279   else
2280     m_dataFolder = Bee::convertToNativeFolderSeparator( root_folder );
2281 
2282   QDir folder( m_dataFolder );
2283   if( !folder.exists() )
2284   {
2285     qWarning() << "Data folder not found in" << qPrintable( folder.absolutePath() );
2286     if( !folder.mkpath( m_dataFolder ) )
2287     {
2288       qWarning() << "Unable to create data folder" << qPrintable( folder.absolutePath() ) ;
2289       m_dataFolder = root_folder;
2290     }
2291     else
2292       qDebug() << "Data folder created in" << qPrintable( m_dataFolder );
2293   }
2294 
2295   if( !Bee::folderIsWriteable( m_dataFolder, false ) )
2296   {
2297     qWarning() << "Data folder" << qPrintable( m_dataFolder ) << "is not writeable";
2298     return false;
2299   }
2300   qDebug() << "Data folder (found):" << qPrintable( m_dataFolder );
2301   return true;
2302 }
2303 
setDataFolder()2304 bool Settings::setDataFolder()
2305 {
2306   if( !rcFileExists() )
2307   {
2308     QStringList default_data_folders;
2309     default_data_folders.append( m_dataFolder );
2310     if( m_dataFolder != m_resourceFolder )
2311       default_data_folders.append( m_resourceFolder );
2312     m_dataFolder = findFileInFolders( "beebeep.ini", default_data_folders, true );
2313   }
2314   else
2315     m_dataFolder = "";
2316 
2317   if( m_dataFolder.isEmpty() )
2318   {
2319     if( !searchDataFolder() )
2320       qWarning() << "Unable to save data. Check your FS permissions";
2321   }
2322 
2323   if( m_addNicknameToDataFolder )
2324     m_dataFolder = Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( m_dataFolder ).arg( Bee::removeInvalidCharactersForFilePath( m_localUser.name() ) ) );
2325   qDebug() << "Data folder:" << qPrintable( m_dataFolder );
2326 
2327   m_cacheFolder = defaultCacheFolderPath();
2328   QDir cache_folder( m_cacheFolder );
2329   if( !cache_folder.exists() )
2330   {
2331     if( !cache_folder.mkpath( m_cacheFolder ) )
2332     {
2333       qWarning() << "Unable to create cache folder" << qPrintable( cache_folder.absolutePath() ) ;
2334       m_cacheFolder = m_dataFolder;
2335     }
2336     else
2337       qDebug() << "Cache folder created in" << qPrintable( m_cacheFolder );
2338   }
2339   qDebug() << "Cache folder:" << qPrintable( m_cacheFolder );
2340 
2341   QStringList folder_list = resourceFolders();
2342   if( folder_list.size() > 1 )
2343     qDebug() << "System files will be searched in the following folders:\n -" << qPrintable( resourceFolders().join( "\n - " ) );
2344   else if( folder_list.size() == 1 )
2345     qDebug() << "System files will be searched in the following folder:\n -" << qPrintable( folder_list.first() );
2346   else
2347     qDebug() << "System files will not be searched";
2348 
2349   folder_list = dataFolders();
2350   if( folder_list.size() > 1 )
2351     qDebug() << "Configuration and data files will be searched in the following folders:\n -" << qPrintable( folder_list.join( "\n - " ) );
2352   else if( folder_list.size() == 1 )
2353     qDebug() << "Configuration and data files will be searched in the following folder:\n -" << qPrintable( folder_list.first() );
2354   else
2355     qDebug() << "Configuration and data files will not be searched";
2356   return true;
2357 }
2358 
defaultDownloadFolderPath() const2359 QString Settings::defaultDownloadFolderPath() const
2360 {
2361 #if QT_VERSION >= 0x050000
2362   QString default_download_folder = Bee::convertToNativeFolderSeparator( QStandardPaths::writableLocation( QStandardPaths::DownloadLocation ) );
2363 #else
2364   QString default_download_folder = Bee::convertToNativeFolderSeparator( QDesktopServices::storageLocation( QDesktopServices::DocumentsLocation ) );
2365 #endif
2366   if( Bee::folderIsWriteable( default_download_folder, false ) )
2367     return default_download_folder;
2368 
2369   default_download_folder = Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( dataFolder() ).arg( "download" ) );
2370   if( Bee::folderIsWriteable( default_download_folder, true ) )
2371     return default_download_folder;
2372   else
2373     return dataFolder();
2374 }
2375 
defaultCacheFolderPath() const2376 QString Settings::defaultCacheFolderPath() const
2377 {
2378   return Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( dataFolder() ).arg( "cache" ) );
2379 }
2380 
savedChatsFilePath() const2381 QString Settings::savedChatsFilePath() const
2382 {
2383   return Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( dataFolder() ).arg( "beebeep.dat" ) );
2384 }
2385 
autoSavedChatsFilePath() const2386 QString Settings::autoSavedChatsFilePath() const
2387 {
2388   return Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( dataFolder() ).arg( "beebeep.bak" ) );
2389 }
2390 
unsentMessagesFilePath() const2391 QString Settings::unsentMessagesFilePath() const
2392 {
2393   return Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( dataFolder() ).arg( "beebeep.off" ) );
2394 }
2395 
defaultSettingsFilePath() const2396 QString Settings::defaultSettingsFilePath() const
2397 {
2398   return Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( dataFolder() ).arg( QLatin1String( "beebeep.ini" ) ) );
2399 }
2400 
defaultBeepFilePath()2401 QString Settings::defaultBeepFilePath()
2402 {
2403   if( m_beepDefaultFilePath.isEmpty() )
2404   {
2405     QStringList data_folders;
2406     data_folders.append( Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( dataFolder() ).arg( QLatin1String( "resources" ) ) ) );
2407     data_folders.append( dataFolders() );
2408 #ifndef Q_OS_MAC
2409     data_folders.append( Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( resourceFolder() ).arg( QLatin1String( "resources" ) ) ) );
2410 #endif
2411     data_folders.append( resourceFolders() );
2412     data_folders.removeDuplicates();
2413     QString beep_file_path = findFileInFolders( QLatin1String( "beep.wav" ), data_folders );
2414     if( beep_file_path.isNull() )
2415       m_beepDefaultFilePath = Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( resourceFolder() ).arg( QLatin1String( "beep.wav" ) ) );
2416     else
2417       m_beepDefaultFilePath = beep_file_path;
2418   }
2419   return m_beepDefaultFilePath;
2420 }
2421 
defaultPluginFolderPath() const2422 QString Settings::defaultPluginFolderPath() const
2423 {
2424   QStringList data_folders;
2425   data_folders.append( Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( dataFolder() ).arg( QLatin1String( "plugins" ) ) ) );
2426   data_folders.append( dataFolders() );
2427 #ifndef Q_OS_MAC
2428   data_folders.append( Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( resourceFolder() ).arg( QLatin1String( "plugins" ) ) ) );
2429 #endif
2430   data_folders.append( resourceFolders() );
2431   data_folders.removeDuplicates();
2432   QString test_plugin_file = QLatin1String( "libnumbertextmarker." ) + Bee::pluginFileExtension();
2433   QString test_plugin_path = findFileInFolders( test_plugin_file, data_folders, true );
2434   return test_plugin_path.isNull() ? resourceFolder() : test_plugin_path;
2435 }
2436 
defaultLanguageFolderPath() const2437 QString Settings::defaultLanguageFolderPath() const
2438 {
2439   QStringList data_folders;
2440   data_folders.append( Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( dataFolder() ).arg( QLatin1String( "languages" ) ) ) );
2441   data_folders.append( dataFolders() );
2442 #ifndef Q_OS_MAC
2443   data_folders.append( Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( resourceFolder() ).arg( QLatin1String( "languages" ) ) ) );
2444 #endif
2445   data_folders.append( resourceFolders() );
2446   data_folders.removeDuplicates();
2447   QString test_language_file = QLatin1String( "beebeep_it.qm" );
2448   QString test_language_path = findFileInFolders( test_language_file, data_folders, true );
2449   return test_language_path.isNull() ? resourceFolder() : test_language_path;
2450 }
2451 
simpleEncrypt(const QString & text_to_encrypt)2452 QString Settings::simpleEncrypt( const QString& text_to_encrypt )
2453 {
2454   if( text_to_encrypt.size() <= 0 )
2455     return QLatin1String( "" );
2456 
2457   QByteArray byte_array_encrypted = text_to_encrypt.toUtf8().toBase64();
2458 
2459   return QString::fromLatin1( byte_array_encrypted );
2460 }
2461 
simpleDecrypt(const QString & text_to_decrypt)2462 QString Settings::simpleDecrypt( const QString& text_to_decrypt )
2463 {
2464   if( text_to_decrypt.size() <= 0 )
2465     return QLatin1String( "" );
2466 
2467   QString text_decrypted = "";
2468 
2469   if( m_settingsVersion < 5 )
2470   {
2471     // Old Decryption
2472     char key = 'k';
2473     foreach( QChar c, text_to_decrypt )
2474       text_decrypted += c.toLatin1() ^ key;
2475   }
2476   else
2477   {
2478     QByteArray byte_array_to_decrypt = text_to_decrypt.toLatin1();
2479     text_decrypted = QString::fromUtf8( QByteArray::fromBase64( byte_array_to_decrypt ) );
2480   }
2481 
2482   return text_decrypted;
2483 }
2484 
guiCustomListStyleSheet(const QString & background_color,const QString & background_image_path) const2485 QString Settings::guiCustomListStyleSheet( const QString& background_color, const QString& background_image_path ) const
2486 {
2487   return QString( "#GuiCustomList { background: %1 url(%2);"
2488                   "background-repeat: no-repeat;"
2489                   "background-position: bottom center;"
2490                   "background-attachment: fixed;"
2491                   "padding-bottom: 32px;"
2492                   "}" ).arg( background_color ).arg( background_image_path );
2493 }
2494 
autoresponderName() const2495 QString Settings::autoresponderName() const
2496 {
2497   return QT_TRANSLATE_NOOP( "Settings", "Autoresponder" );
2498 }
2499 
defaultChatMessagesToShow() const2500 int Settings::defaultChatMessagesToShow() const
2501 {
2502 #if QT_VERSION >= 0x050000
2503   return 800;
2504 #else
2505   return 400;
2506 #endif
2507 }
2508 
downloadDirectoryForUser(const User & u) const2509 QString Settings::downloadDirectoryForUser( const User& u ) const
2510 {
2511   if( Settings::instance().downloadInUserFolder() )
2512   {
2513     QString user_name = Bee::removeInvalidCharactersForFilePath( u.name() );
2514     return Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( downloadDirectory() ).arg( user_name ) );
2515   }
2516   else
2517     return downloadDirectory();
2518 }
2519 
useUserFirstNameFirstInFullNameFromLanguage() const2520 bool Settings::useUserFirstNameFirstInFullNameFromLanguage() const
2521 {
2522   if( m_language == "ja" ) // japanese
2523     return false;
2524   else
2525     return true;
2526 }
2527 
isFileExtensionAllowedInFileTransfer(const QString & file_ext) const2528 bool Settings::isFileExtensionAllowedInFileTransfer( const QString& file_ext ) const
2529 {
2530   if( m_allowedFileExtensionsInFileTransfer.isEmpty() )
2531     return true;
2532   if( file_ext.toLower() == partiallyDownloadedFileExtension().toLower() )
2533     return true;
2534   return file_ext.isEmpty() ? false : m_allowedFileExtensionsInFileTransfer.contains( file_ext, Qt::CaseInsensitive );
2535 }
2536