1 #include <QEventLoop>
2 #include <QFile>
3 #include <QFileInfo>
4 #include <QTextStream>
5 #include <QRegExp>
6 #include <QString>
7 #include <QStringList>
8 
9 #ifdef __QTKEYCHAIN__
10 #include <qt5keychain/keychain.h>
11 using namespace QKeychain;
12 #endif // __QTKEYCHAIN__
13 
14 #include "broadcast/defs_broadcast.h"
15 #include "broadcastprofile.h"
16 #include "defs_urls.h"
17 #include "moc_broadcastprofile.cpp"
18 #include "recording/defs_recording.h"
19 #include "util/compatibility.h"
20 #include "util/logger.h"
21 #include "util/memory.h"
22 #include "util/xml.h"
23 
24 namespace {
25 constexpr const char* kDoctype = "broadcastprofile";
26 constexpr const char* kDocumentRoot = "BroadcastProfile";
27 constexpr const char* kSecureCredentials = "SecureCredentialsStorage";
28 constexpr const char* kBitrate = "Bitrate";
29 constexpr const char* kChannels = "Channels";
30 constexpr const char* kCustomArtist = "CustomArtist";
31 constexpr const char* kCustomTitle = "CustomTitle";
32 constexpr const char* kEnableMetadata = "EnableMetadata";
33 constexpr const char* kEnableReconnect = "EnableReconnect";
34 constexpr const char* kEnabled = "Enabled";
35 constexpr const char* kFormat = "Format";
36 constexpr const char* kHost = "Host";
37 constexpr const char* kLimitReconnects = "LimitReconnects";
38 constexpr const char* kLogin = "Login";
39 constexpr const char* kMaximumRetries = "MaximumRetries";
40 constexpr const char* kMetadataCharset = "MetadataCharset";
41 constexpr const char* kMetadataFormat = "MetadataFormat";
42 constexpr const char* kMountPoint = "Mountpoint";
43 constexpr const char* kNoDelayFirstReconnect = "NoDelayFirstReconnect";
44 constexpr const char* kOggDynamicUpdate = "OggDynamicUpdate";
45 constexpr const char* kPassword = "Password";
46 constexpr const char* kPort = "Port";
47 constexpr const char* kProfileName = "ProfileName";
48 constexpr const char* kReconnectFirstDelay = "ReconnectFirstDelay";
49 constexpr const char* kReconnectPeriod = "ReconnectPeriod";
50 constexpr const char* kServertype = "Servertype";
51 constexpr const char* kStreamDesc = "StreamDesc";
52 constexpr const char* kStreamGenre = "StreamGenre";
53 constexpr const char* kStreamName = "StreamName";
54 constexpr const char* kStreamIRC = "StreamIRC";
55 constexpr const char* kStreamAIM = "StreamAIM";
56 constexpr const char* kStreamICQ = "StreamICQ";
57 constexpr const char* kStreamPublic = "StreamPublic";
58 constexpr const char* kStreamWebsite = "StreamWebsite";
59 
60 #ifdef __QTKEYCHAIN__
61 constexpr const char* kKeychainPrefix = "Mixxx - ";
62 #endif
63 
64 constexpr int kDefaultBitrate = 128;
65 constexpr int kDefaultChannels = 2;
66 constexpr bool kDefaultEnableMetadata = false;
67 constexpr bool kDefaultEnableReconnect = true;
68 constexpr bool kDefaultLimitReconnects = true;
69 constexpr int kDefaultMaximumRetries = 10;
70 // No tr() here, see https://bugs.launchpad.net/mixxx/+bug/1419500
71 const QString kDefaultMetadataFormat("$artist - $title");
72 constexpr bool kDefaultNoDelayFirstReconnect = true;
73 constexpr bool kDefaultOggDynamicupdate = false;
74 constexpr double kDefaultReconnectFirstDelay = 0.0;
75 constexpr double kDefaultReconnectPeriod = 5.0;
76 const QString kDefaultStreamName = QStringLiteral("Mixxx");
77 const QString kDefaultStreamDesc =
78         QObject::tr("This stream is online for testing purposes!");
79 const QString kDefaultStreamGenre = QObject::tr("Live Mix");
80 constexpr bool kDefaultStreamPublic = false;
81 
82 const QRegExp kForbiddenChars =
83         QRegExp("[<>:\"\\/|?*\\\\]|(\\.\\.)"
84                 "|CON|AUX|PRN|COM(\\d+)|LPT(\\d+)|NUL");
85 
86 const mixxx::Logger kLogger("BroadcastProfile");
87 } // anonymous namespace
88 
BroadcastProfile(const QString & profileName,QObject * parent)89 BroadcastProfile::BroadcastProfile(const QString& profileName,
90                                    QObject* parent)
91     : QObject(parent) {
92     adoptDefaultValues();
93 
94     // Direct assignment to avoid triggering the
95     // profileNameChanged signal
96     m_profileName = QString(profileName);
97 }
98 
validName(const QString & str)99 bool BroadcastProfile::validName(const QString& str) {
100     return !str.contains(kForbiddenChars);
101 }
102 
stripForbiddenChars(const QString & str)103 QString BroadcastProfile::stripForbiddenChars(const QString& str) {
104     QString sourceText(str);
105     return sourceText.replace(kForbiddenChars, " ");
106 }
107 
loadFromFile(const QString & filename)108 BroadcastProfilePtr BroadcastProfile::loadFromFile(
109         const QString& filename) {
110     QFileInfo xmlFile(filename);
111     if (!xmlFile.exists()) {
112         return BroadcastProfilePtr(nullptr);
113     }
114 
115     QString profileFilename = xmlFile.baseName();
116     // The profile filename (without extension) is used to create the instance
117     // but the real profile name (with forbidden chars but suitable for
118     // non-filesystem uses) will be fetched from the XML file and set in the
119     // object during the call to loadValues()
120     BroadcastProfilePtr profile(new BroadcastProfile(profileFilename));
121     profile->loadValues(filename);
122     return profile;
123 }
124 
getLastFilename() const125 QString BroadcastProfile::getLastFilename() const {
126     return m_filename;
127 }
128 
equals(BroadcastProfilePtr other)129 bool BroadcastProfile::equals(BroadcastProfilePtr other) {
130     return ((getProfileName() == other->getProfileName())
131             && valuesEquals(other));
132 }
133 
valuesEquals(BroadcastProfilePtr other)134 bool BroadcastProfile::valuesEquals(BroadcastProfilePtr other) {
135     if (getEnabled() == other->getEnabled()
136             && secureCredentialStorage() == other->secureCredentialStorage()
137             && getHost() == other->getHost()
138             && getPort() == other->getPort()
139             && getServertype() == other->getServertype()
140             && getLogin() == other->getLogin()
141             && getPassword() == other->getPassword()
142             && getEnableReconnect() == other->getEnableReconnect()
143             && getReconnectPeriod() == other->getReconnectPeriod()
144             && getLimitReconnects() == other->getLimitReconnects()
145             && getMaximumRetries() == other->getMaximumRetries()
146             && getNoDelayFirstReconnect() == other->getNoDelayFirstReconnect()
147             && getReconnectFirstDelay() == other->getReconnectFirstDelay()
148             && getFormat() == other->getFormat()
149             && getBitrate() == other->getBitrate()
150             && getChannels() == other->getChannels()
151             && getMountpoint() == other->getMountpoint()
152             && getStreamName() == other->getStreamName()
153             && getStreamDesc() == other->getStreamDesc()
154             && getStreamGenre() == other->getStreamGenre()
155             && getStreamPublic() == other->getStreamPublic()
156             && getStreamWebsite() == other->getStreamWebsite()
157             && getStreamIRC() == other->getStreamIRC()
158             && getStreamAIM() == other->getStreamAIM()
159             && getStreamICQ() == other->getStreamICQ()
160             && getEnableMetadata() == other->getEnableMetadata()
161             && getMetadataCharset() == other->getMetadataCharset()
162             && getCustomArtist() == other->getCustomArtist()
163             && getCustomTitle() == other->getCustomTitle()
164             && getMetadataFormat() == other->getMetadataFormat()
165             && getOggDynamicUpdate() == other->getOggDynamicUpdate()) {
166         return true;
167     }
168 
169     return false;
170 }
171 
valuesCopy()172 BroadcastProfilePtr BroadcastProfile::valuesCopy() {
173     BroadcastProfilePtr newProfile(
174             new BroadcastProfile(getProfileName()));
175     copyValuesTo(newProfile);
176     return newProfile;
177 }
178 
copyValuesTo(BroadcastProfilePtr other)179 void BroadcastProfile::copyValuesTo(BroadcastProfilePtr other) {
180     other->setSecureCredentialStorage(this->secureCredentialStorage());
181 
182     other->setHost(this->getHost());
183     other->setPort(this->getPort());
184 
185     other->setServertype(this->getServertype());
186     other->setLogin(this->getLogin());
187     other->setPassword(this->getPassword());
188 
189     other->setEnableReconnect(this->getEnableReconnect());
190     other->setReconnectPeriod(this->getReconnectPeriod());
191 
192     other->setLimitReconnects(this->getLimitReconnects());
193     other->setMaximumRetries(this->getMaximumRetries());
194 
195     other->setNoDelayFirstReconnect(this->getNoDelayFirstReconnect());
196     other->setReconnectFirstDelay(this->getReconnectFirstDelay());
197 
198     other->setFormat(this->getFormat());
199     other->setBitrate(this->getBitrate());
200     other->setChannels(this->getChannels());
201 
202     other->setMountPoint(this->getMountpoint());
203     other->setStreamName(this->getStreamName());
204     other->setStreamDesc(this->getStreamDesc());
205     other->setStreamGenre(this->getStreamGenre());
206     other->setStreamPublic(this->getStreamPublic());
207     other->setStreamWebsite(this->getStreamWebsite());
208     other->setStreamIRC(this->getStreamIRC());
209     other->setStreamAIM(this->getStreamAIM());
210     other->setStreamICQ(this->getStreamICQ());
211 
212     other->setEnableMetadata(this->getEnableMetadata());
213     other->setMetadataCharset(this->getMetadataCharset());
214     other->setCustomArtist(this->getCustomArtist());
215     other->setCustomTitle(this->getCustomTitle());
216     other->setMetadataFormat(this->getMetadataFormat());
217     other->setOggDynamicUpdate(this->getOggDynamicUpdate());
218 
219     other->setEnabled(this->getEnabled());
220 }
221 
adoptDefaultValues()222 void BroadcastProfile::adoptDefaultValues() {
223     m_secureCredentials = false;
224     m_enabled = false;
225 
226     m_host = QString();
227     m_port = BROADCAST_DEFAULT_PORT;
228     m_serverType = QString();
229     m_login = QString();
230     m_password = QString();
231 
232     m_enableReconnect = kDefaultEnableReconnect;
233     m_reconnectPeriod = kDefaultReconnectPeriod;
234     m_limitReconnects = kDefaultLimitReconnects;
235 
236     m_mountpoint = QString();
237     m_streamDesc = kDefaultStreamDesc;
238     m_streamGenre = kDefaultStreamGenre;
239     m_streamName = kDefaultStreamName;
240     m_streamPublic = kDefaultStreamPublic;
241     m_streamWebsite = MIXXX_WEBSITE_URL;
242     m_streamIRC.clear();
243     m_streamAIM.clear();
244     m_streamICQ.clear();
245 
246     m_enableMetadata = kDefaultEnableMetadata;
247     m_metadataCharset = QString();
248     m_customArtist = QString();
249     m_customTitle = QString();
250     m_metadataFormat = kDefaultMetadataFormat;
251     m_oggDynamicUpdate = kDefaultOggDynamicupdate;
252 
253     m_bitrate = kDefaultBitrate;
254     m_channels = kDefaultChannels;
255     m_format = QString();
256 
257     m_noDelayFirstReconnect = kDefaultNoDelayFirstReconnect;
258     m_reconnectFirstDelay = kDefaultReconnectFirstDelay;
259     m_maximumRetries = kDefaultMaximumRetries;
260 }
261 
loadValues(const QString & filename)262 bool BroadcastProfile::loadValues(const QString& filename) {
263     QDomElement doc = XmlParse::openXMLFile(filename, kDoctype);
264     if (doc.childNodes().size() < 1) {
265         return false;
266     }
267 
268     m_filename = filename;
269 
270 #ifdef __QTKEYCHAIN__
271     m_secureCredentials = (bool)XmlParse::selectNodeInt(doc, kSecureCredentials);
272 #else
273     // Secure credentials storage can't be enabled nor disabled from the UI,
274     // so force it to disabled to avoid issues if enabled.
275     m_secureCredentials = false;
276 #endif
277 
278     // ProfileName is special because it was not previously saved in the file.
279     // When loading old files, we need to use the file name (set in the
280     // constructor) as the profile name and only load it if present in the
281     // file.
282     QDomNode node = XmlParse::selectNode(doc, kProfileName);
283     if (!node.isNull()) {
284         m_profileName = node.toElement().text();
285     }
286 
287     m_enabled = (bool)XmlParse::selectNodeInt(doc, kEnabled);
288 
289     m_host = XmlParse::selectNodeQString(doc, kHost);
290     m_port = XmlParse::selectNodeInt(doc, kPort);
291     m_serverType = XmlParse::selectNodeQString(doc, kServertype);
292 
293     m_login = XmlParse::selectNodeQString(doc, kLogin);
294     if (m_secureCredentials) {
295         m_password = getSecurePassword(m_login);
296     } else {
297         m_password = XmlParse::selectNodeQString(doc, kPassword);
298     }
299 
300     m_enableReconnect =
301             (bool)XmlParse::selectNodeInt(doc, kEnableReconnect);
302     m_reconnectPeriod =
303             XmlParse::selectNodeDouble(doc, kReconnectPeriod);
304 
305     m_limitReconnects =
306             (bool)XmlParse::selectNodeInt(doc, kLimitReconnects);
307     m_maximumRetries =
308             XmlParse::selectNodeInt(doc, kMaximumRetries);
309 
310     m_noDelayFirstReconnect =
311             (bool)XmlParse::selectNodeInt(doc, kNoDelayFirstReconnect);
312     m_reconnectFirstDelay =
313             XmlParse::selectNodeDouble(doc, kReconnectFirstDelay);
314 
315     m_mountpoint = XmlParse::selectNodeQString(doc, kMountPoint);
316     m_streamName = XmlParse::selectNodeQString(doc, kStreamName);
317     m_streamDesc = XmlParse::selectNodeQString(doc, kStreamDesc);
318     m_streamGenre = XmlParse::selectNodeQString(doc, kStreamGenre);
319     m_streamPublic = (bool)XmlParse::selectNodeInt(doc, kStreamPublic);
320     m_streamWebsite = XmlParse::selectNodeQString(doc, kStreamWebsite);
321     m_streamIRC = XmlParse::selectNodeQString(doc, kStreamIRC);
322     m_streamAIM = XmlParse::selectNodeQString(doc, kStreamAIM);
323     m_streamICQ = XmlParse::selectNodeQString(doc, kStreamICQ);
324 
325     m_format = XmlParse::selectNodeQString(doc, kFormat);
326     if (m_format == BROADCAST_FORMAT_OV_LEGACY) {
327         // Upgrade to have the same codec name than the recording define.
328         m_format = ENCODING_OGG;
329     }
330     m_bitrate = XmlParse::selectNodeInt(doc, kBitrate);
331     m_channels = XmlParse::selectNodeInt(doc, kChannels);
332 
333     m_enableMetadata = (bool)XmlParse::selectNodeInt(doc, kEnableMetadata);
334     m_metadataCharset = XmlParse::selectNodeQString(doc, kMetadataCharset);
335     m_customArtist = XmlParse::selectNodeQString(doc, kCustomArtist);
336     m_customTitle = XmlParse::selectNodeQString(doc, kCustomTitle);
337     m_metadataFormat = XmlParse::selectNodeQString(doc, kMetadataFormat);
338     m_oggDynamicUpdate =
339             (bool)XmlParse::selectNodeInt(doc, kOggDynamicUpdate);
340 
341     return true;
342 }
343 
save(const QString & filename)344 bool BroadcastProfile::save(const QString& filename) {
345     QDomDocument doc(kDoctype);
346     QDomElement docRoot = doc.createElement(kDocumentRoot);
347 
348     XmlParse::addElement(doc, docRoot, kProfileName, m_profileName);
349 
350     XmlParse::addElement(doc, docRoot,
351                          kSecureCredentials, QString::number((int)m_secureCredentials));
352     XmlParse::addElement(doc, docRoot,
353                          kEnabled, QString::number((int)m_enabled));
354 
355     XmlParse::addElement(doc, docRoot, kHost, m_host);
356     XmlParse::addElement(doc, docRoot, kPort, QString::number(m_port));
357     XmlParse::addElement(doc, docRoot, kServertype, m_serverType);
358 
359     XmlParse::addElement(doc, docRoot, kLogin, m_login);
360     if (m_secureCredentials) {
361         setSecurePassword(m_login, m_password);
362     } else {
363         XmlParse::addElement(doc, docRoot, kPassword, m_password);
364     }
365 
366     XmlParse::addElement(doc, docRoot, kEnableReconnect,
367                          QString::number((int)m_enableReconnect));
368     XmlParse::addElement(doc, docRoot, kReconnectPeriod,
369                          QString::number(m_reconnectPeriod));
370 
371     XmlParse::addElement(doc, docRoot, kLimitReconnects,
372                          QString::number((int)m_limitReconnects));
373     XmlParse::addElement(doc, docRoot, kMaximumRetries,
374                          QString::number(m_maximumRetries));
375 
376     XmlParse::addElement(doc, docRoot, kNoDelayFirstReconnect,
377                          QString::number((int)m_noDelayFirstReconnect));
378     XmlParse::addElement(doc, docRoot, kReconnectFirstDelay,
379                          QString::number(m_reconnectFirstDelay));
380 
381     XmlParse::addElement(doc, docRoot, kMountPoint, m_mountpoint);
382     XmlParse::addElement(doc, docRoot, kStreamName, m_streamName);
383     XmlParse::addElement(doc, docRoot, kStreamDesc, m_streamDesc);
384     XmlParse::addElement(doc, docRoot, kStreamGenre, m_streamGenre);
385     XmlParse::addElement(doc, docRoot, kStreamPublic,
386                          QString::number((int)m_streamPublic));
387     XmlParse::addElement(doc, docRoot, kStreamWebsite, m_streamWebsite);
388     XmlParse::addElement(doc, docRoot, kStreamIRC, m_streamIRC);
389     XmlParse::addElement(doc, docRoot, kStreamAIM, m_streamAIM);
390     XmlParse::addElement(doc, docRoot, kStreamICQ, m_streamICQ);
391 
392     XmlParse::addElement(doc, docRoot, kFormat, m_format);
393     XmlParse::addElement(doc, docRoot, kBitrate,
394                          QString::number(m_bitrate));
395     XmlParse::addElement(doc, docRoot, kChannels,
396                          QString::number(m_channels));
397 
398     XmlParse::addElement(doc, docRoot, kEnableMetadata,
399                          QString::number((int)m_enableMetadata));
400     XmlParse::addElement(doc, docRoot, kMetadataCharset, m_metadataCharset);
401     XmlParse::addElement(doc, docRoot, kCustomArtist, m_customArtist);
402     XmlParse::addElement(doc, docRoot, kCustomTitle, m_customTitle);
403     XmlParse::addElement(doc, docRoot, kMetadataFormat, m_metadataFormat);
404     XmlParse::addElement(doc, docRoot, kOggDynamicUpdate,
405                          QString::number((int)m_oggDynamicUpdate));
406 
407     doc.appendChild(docRoot);
408 
409     QFile xmlFile(filename);
410     if (xmlFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
411         m_filename = filename;
412         QTextStream fileStream(&xmlFile);
413         doc.save(fileStream, 4);
414         xmlFile.close();
415 
416         return true;
417     }
418     return false;
419 }
420 
setProfileName(const QString & profileName)421 void BroadcastProfile::setProfileName(const QString &profileName) {
422     QString oldName(m_profileName);
423     m_profileName = QString(profileName);
424 
425     emit profileNameChanged(oldName, m_profileName);
426 }
427 
getProfileName() const428 QString BroadcastProfile::getProfileName() const {
429     return m_profileName;
430 }
431 
setConnectionStatus(int newState)432 void BroadcastProfile::setConnectionStatus(int newState) {
433     m_connectionStatus = newState;
434     emit connectionStatusChanged(connectionStatus());
435 }
436 
connectionStatus()437 int BroadcastProfile::connectionStatus() {
438     return atomicLoadRelaxed(m_connectionStatus);
439 }
440 
setSecureCredentialStorage(bool value)441 void BroadcastProfile::setSecureCredentialStorage(bool value) {
442     m_secureCredentials = value;
443 }
444 
secureCredentialStorage()445 bool BroadcastProfile::secureCredentialStorage() {
446     return m_secureCredentials;
447 }
448 
setSecurePassword(const QString & login,const QString & password)449 bool BroadcastProfile::setSecurePassword(const QString& login, const QString& password) {
450 #ifdef __QTKEYCHAIN__
451     QString serviceName = QString(kKeychainPrefix) + getProfileName();
452 
453     WritePasswordJob writeJob(serviceName);
454     writeJob.setAutoDelete(false);
455     writeJob.setKey(login);
456     writeJob.setTextData(password);
457 
458     QEventLoop loop;
459     writeJob.connect(&writeJob, &WritePasswordJob::finished, &loop, &QEventLoop::quit);
460     writeJob.start();
461     loop.exec();
462 
463     if (writeJob.error() == Error::NoError) {
464         kLogger.debug() << "setSecureValue: write successful";
465         return true;
466     } else {
467         kLogger.warning() << "setSecureValue: write job failed with error:"
468                 << writeJob.errorString();
469         errorDialog(tr("Can't use secure password storage: keychain access failed."),
470                 writeJob.errorString());
471         return false;
472     }
473 #else
474     Q_UNUSED(login);
475     Q_UNUSED(password);
476     return false;
477 #endif
478 }
479 
getSecurePassword(const QString & login)480 QString BroadcastProfile::getSecurePassword(const QString& login) {
481 #ifdef __QTKEYCHAIN__
482     QString serviceName = QString(kKeychainPrefix) + getProfileName();
483 
484     ReadPasswordJob readJob(serviceName);
485     readJob.setAutoDelete(false);
486     readJob.setKey(login);
487 
488     QEventLoop loop;
489     readJob.connect(&readJob, &ReadPasswordJob::finished, &loop, &QEventLoop::quit);
490     readJob.start();
491     loop.exec();
492 
493     if (readJob.error() == Error::NoError) {
494         kLogger.debug() << "getSecureValue: read successful";
495         return readJob.textData();
496     } else {
497         kLogger.warning() << "getSecureValue: read job failed with error:"
498                         << readJob.errorString();
499         errorDialog(tr("Secure password retrieval unsuccessful: keychain access failed."),
500                         readJob.errorString());
501     }
502 #else
503     Q_UNUSED(login);
504 #endif
505     return QString();
506 }
507 
errorDialog(const QString & text,const QString & detailedError)508 void BroadcastProfile::errorDialog(const QString& text, const QString& detailedError) {
509     ErrorDialogProperties* props = ErrorDialogHandler::instance()->newDialogProperties();
510     props->setType(DLG_WARNING);
511     props->setTitle(tr("Settings error"));
512     props->setText(tr("<b>Error with settings for '%1':</b><br>")
513             .arg(getProfileName()) + text);
514     props->setDetails(detailedError);
515     props->setKey(detailedError);   // To prevent multiple windows for the same error
516     props->setDefaultButton(QMessageBox::Close);
517     props->setModal(false);
518     ErrorDialogHandler::instance()->requestErrorDialog(props);
519 }
520 
relayStatus(bool newStatus)521 void BroadcastProfile::relayStatus(bool newStatus) {
522     setEnabled(newStatus);
523 }
524 
525 // Used by BroadcastSettings to relay connection status
526 // to copies in BroadcastSettingsModel
relayConnectionStatus(int newConnectionStatus)527 void BroadcastProfile::relayConnectionStatus(int newConnectionStatus) {
528     setConnectionStatus(newConnectionStatus);
529 }
530 
531 // This was useless before, but now comes in handy for multi-broadcasting,
532 // where it means "this connection is enabled and will be started by Mixxx"
getEnabled() const533 bool BroadcastProfile::getEnabled() const {
534     return m_enabled;
535 }
536 
setEnabled(bool value)537 void BroadcastProfile::setEnabled(bool value) {
538     m_enabled = value;
539     emit statusChanged(m_enabled);
540 }
541 
getHost() const542 QString BroadcastProfile::getHost() const {
543     return m_host;
544 }
545 
setHost(const QString & value)546 void BroadcastProfile::setHost(const QString& value) {
547     m_host = QString(value);
548 }
549 
getPort() const550 int BroadcastProfile::getPort() const {
551     // Valid port numbers are 0 .. 65535 (16 bit unsigned)
552     if (m_port < 0 || m_port > 0xFFFF) {
553         return BROADCAST_DEFAULT_PORT;
554     }
555 
556     return m_port;
557 }
558 
setPort(int value)559 void BroadcastProfile::setPort(int value) {
560     m_port = value;
561 }
562 
getServertype() const563 QString BroadcastProfile::getServertype() const {
564     return m_serverType;
565 }
566 
setServertype(const QString & value)567 void BroadcastProfile::setServertype(const QString& value) {
568     m_serverType = QString(value);
569 }
570 
getLogin() const571 QString BroadcastProfile::getLogin() const {
572     return m_login;
573 }
574 
setLogin(const QString & value)575 void BroadcastProfile::setLogin(const QString& value) {
576     m_login = QString(value);
577 }
578 
579 // TODO(Palakis, June 2nd 2017): implement secure password storage
getPassword() const580 QString BroadcastProfile::getPassword() const {
581     return m_password;
582 }
583 
setPassword(const QString & value)584 void BroadcastProfile::setPassword(const QString& value) {
585     m_password = QString(value);
586 }
587 
getEnableReconnect() const588 bool BroadcastProfile::getEnableReconnect() const {
589     return m_enableReconnect;
590 }
591 
setEnableReconnect(bool value)592 void BroadcastProfile::setEnableReconnect(bool value) {
593     m_enableReconnect = value;
594 }
595 
getReconnectPeriod() const596 double BroadcastProfile::getReconnectPeriod() const {
597     return m_reconnectPeriod;
598 }
599 
setReconnectPeriod(double value)600 void BroadcastProfile::setReconnectPeriod(double value) {
601     m_reconnectPeriod = value;
602 }
603 
getLimitReconnects() const604 bool BroadcastProfile::getLimitReconnects() const {
605     return m_limitReconnects;
606 }
607 
setLimitReconnects(bool value)608 void BroadcastProfile::setLimitReconnects(bool value) {
609     m_limitReconnects = value;
610 }
611 
getMaximumRetries() const612 int BroadcastProfile::getMaximumRetries() const {
613     return m_maximumRetries;
614 }
615 
setMaximumRetries(int value)616 void BroadcastProfile::setMaximumRetries(int value) {
617     m_maximumRetries = value;
618 }
619 
getNoDelayFirstReconnect() const620 bool BroadcastProfile::getNoDelayFirstReconnect() const {
621     return m_noDelayFirstReconnect;
622 }
623 
setNoDelayFirstReconnect(bool value)624 void BroadcastProfile::setNoDelayFirstReconnect(bool value) {
625     m_noDelayFirstReconnect = value;
626 }
627 
getReconnectFirstDelay() const628 double BroadcastProfile::getReconnectFirstDelay() const {
629     return m_reconnectFirstDelay;
630 }
631 
setReconnectFirstDelay(double value)632 void BroadcastProfile::setReconnectFirstDelay(double value) {
633     m_reconnectFirstDelay = value;
634 }
635 
getMountpoint() const636 QString BroadcastProfile::getMountpoint() const {
637     return m_mountpoint;
638 }
639 
setMountPoint(const QString & value)640 void BroadcastProfile::setMountPoint(const QString& value) {
641     m_mountpoint = QString(value);
642 }
643 
getStreamName() const644 QString BroadcastProfile::getStreamName() const {
645     return m_streamName;
646 }
647 
setStreamName(const QString & value)648 void BroadcastProfile::setStreamName(const QString& value) {
649     m_streamName = QString(value);
650 }
651 
getStreamDesc() const652 QString BroadcastProfile::getStreamDesc() const {
653     return m_streamDesc;
654 }
655 
setStreamDesc(const QString & value)656 void BroadcastProfile::setStreamDesc(const QString& value) {
657     m_streamDesc = QString(value);
658 }
659 
getStreamGenre() const660 QString BroadcastProfile::getStreamGenre() const {
661     return m_streamGenre;
662 }
663 
setStreamGenre(const QString & value)664 void BroadcastProfile::setStreamGenre(const QString& value) {
665     m_streamGenre = QString(value);
666 }
667 
getStreamPublic() const668 bool BroadcastProfile::getStreamPublic() const {
669     return m_streamPublic;
670 }
671 
setStreamPublic(bool value)672 void BroadcastProfile::setStreamPublic(bool value) {
673     m_streamPublic = value;
674 }
675 
getStreamWebsite() const676 QString BroadcastProfile::getStreamWebsite() const {
677     return m_streamWebsite;
678 }
679 
setStreamWebsite(const QString & value)680 void BroadcastProfile::setStreamWebsite(const QString& value) {
681     m_streamWebsite = QString(value);
682 }
683 
getStreamIRC() const684 QString BroadcastProfile::getStreamIRC() const {
685     return m_streamIRC;
686 }
687 
setStreamIRC(const QString & value)688 void BroadcastProfile::setStreamIRC(const QString& value) {
689     m_streamIRC = value;
690 }
691 
getStreamAIM() const692 QString BroadcastProfile::getStreamAIM() const {
693     return m_streamAIM;
694 }
695 
setStreamAIM(const QString & value)696 void BroadcastProfile::setStreamAIM(const QString& value) {
697     m_streamAIM = value;
698 }
699 
getStreamICQ() const700 QString BroadcastProfile::getStreamICQ() const {
701     return m_streamICQ;
702 }
703 
setStreamICQ(const QString & value)704 void BroadcastProfile::setStreamICQ(const QString& value) {
705     m_streamICQ = value;
706 }
707 
getFormat() const708 QString BroadcastProfile::getFormat() const {
709     return m_format;
710 }
711 
setFormat(const QString & value)712 void BroadcastProfile::setFormat(const QString& value) {
713     m_format = QString(value);
714 }
715 
getBitrate() const716 int BroadcastProfile::getBitrate() const {
717     return m_bitrate;
718 }
719 
setBitrate(int value)720 void BroadcastProfile::setBitrate(int value) {
721     m_bitrate = value;
722 }
723 
getChannels() const724 int BroadcastProfile::getChannels() const {
725     return m_channels;
726 }
727 
setChannels(int value)728 void BroadcastProfile::setChannels(int value) {
729     m_channels = value;
730 }
731 
getEnableMetadata() const732 bool BroadcastProfile::getEnableMetadata() const {
733     return m_enableMetadata;
734 }
735 
setEnableMetadata(bool value)736 void BroadcastProfile::setEnableMetadata(bool value) {
737     m_enableMetadata = value;
738 }
739 
getMetadataCharset() const740 QString BroadcastProfile::getMetadataCharset() const {
741     return m_metadataCharset;
742 }
743 
setMetadataCharset(const QString & value)744 void BroadcastProfile::setMetadataCharset(const QString& value) {
745     m_metadataCharset = QString(value);
746 }
747 
getCustomArtist() const748 QString BroadcastProfile::getCustomArtist() const {
749     return m_customArtist;
750 }
751 
setCustomArtist(const QString & value)752 void BroadcastProfile::setCustomArtist(const QString& value) {
753     m_customArtist = QString(value);
754 }
755 
getCustomTitle() const756 QString BroadcastProfile::getCustomTitle() const {
757     return m_customTitle;
758 }
759 
setCustomTitle(const QString & value)760 void BroadcastProfile::setCustomTitle(const QString& value) {
761     m_customTitle = QString(value);
762 }
763 
getMetadataFormat() const764 QString BroadcastProfile::getMetadataFormat() const {
765     return m_metadataFormat;
766 }
767 
setMetadataFormat(const QString & value)768 void BroadcastProfile::setMetadataFormat(const QString& value) {
769     m_metadataFormat = QString(value);
770 }
771 
getOggDynamicUpdate() const772 bool BroadcastProfile::getOggDynamicUpdate() const {
773     return m_oggDynamicUpdate;
774 }
775 
setOggDynamicUpdate(bool value)776 void BroadcastProfile::setOggDynamicUpdate(bool value) {
777     m_oggDynamicUpdate = value;
778 }
779