378 lines
11 KiB
C++
378 lines
11 KiB
C++
// Copyright 2007-2023 The Mumble Developers. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license
|
|
// that can be found in the LICENSE file at the root of the
|
|
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
|
|
|
|
#ifndef MUMBLE_MUMBLE_CONNECTDIALOG_H_
|
|
#define MUMBLE_MUMBLE_CONNECTDIALOG_H_
|
|
|
|
#ifndef Q_MOC_RUN
|
|
# include <boost/accumulators/accumulators.hpp>
|
|
# include <boost/accumulators/statistics/stats.hpp>
|
|
#endif
|
|
|
|
#include <QtCore/QString>
|
|
#include <QtCore/QUrl>
|
|
#include <QtCore/QtGlobal>
|
|
#include <QtWidgets/QStyledItemDelegate>
|
|
#include <QtWidgets/QTreeView>
|
|
#include <QtWidgets/QTreeWidgetItem>
|
|
|
|
#include <QtNetwork/QHostInfo>
|
|
|
|
#ifdef USE_ZEROCONF
|
|
# include "BonjourRecord.h"
|
|
# include <dns_sd.h>
|
|
#endif
|
|
|
|
#include "HostAddress.h"
|
|
#include "MumbleProtocol.h"
|
|
#include "Net.h"
|
|
#include "ServerAddress.h"
|
|
#include "Timer.h"
|
|
#include "UnresolvedServerAddress.h"
|
|
#include "Version.h"
|
|
|
|
struct FavoriteServer;
|
|
class QUdpSocket;
|
|
|
|
struct PublicInfo {
|
|
QString qsName;
|
|
QUrl quUrl;
|
|
QString qsIp;
|
|
QString qsCountry;
|
|
QString qsCountryCode;
|
|
QString qsContinentCode;
|
|
unsigned short usPort;
|
|
bool bCA;
|
|
};
|
|
|
|
struct PingStats {
|
|
private:
|
|
Q_DISABLE_COPY(PingStats)
|
|
protected:
|
|
void init();
|
|
|
|
public:
|
|
Version::full_t m_version;
|
|
quint32 uiPing;
|
|
quint32 uiPingSort;
|
|
quint32 uiUsers;
|
|
quint32 uiMaxUsers;
|
|
quint32 uiBandwidth;
|
|
quint32 uiSent;
|
|
quint32 uiRecv;
|
|
|
|
double dPing;
|
|
|
|
typedef boost::accumulators::accumulator_set<
|
|
double,
|
|
boost::accumulators::stats< boost::accumulators::tag::count, boost::accumulators::tag::extended_p_square > >
|
|
asQuantileType;
|
|
asQuantileType *asQuantile;
|
|
|
|
void reset();
|
|
|
|
PingStats();
|
|
~PingStats();
|
|
};
|
|
|
|
class ServerItem;
|
|
|
|
class ServerViewDelegate : public QStyledItemDelegate {
|
|
Q_OBJECT
|
|
Q_DISABLE_COPY(ServerViewDelegate)
|
|
public:
|
|
ServerViewDelegate(QObject *p = nullptr);
|
|
~ServerViewDelegate();
|
|
|
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
|
|
};
|
|
|
|
class ServerView : public QTreeWidget {
|
|
Q_OBJECT
|
|
Q_DISABLE_COPY(ServerView)
|
|
public:
|
|
ServerItem *siFavorite, *siLAN, *siPublic;
|
|
|
|
ServerView(QWidget *);
|
|
~ServerView() Q_DECL_OVERRIDE;
|
|
|
|
void fixupName(ServerItem *si);
|
|
|
|
protected:
|
|
QMimeData *mimeData(const QList< QTreeWidgetItem * >) const Q_DECL_OVERRIDE;
|
|
QStringList mimeTypes() const Q_DECL_OVERRIDE;
|
|
Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE;
|
|
bool dropMimeData(QTreeWidgetItem *, int, const QMimeData *, Qt::DropAction) Q_DECL_OVERRIDE;
|
|
};
|
|
|
|
#include "ui_ConnectDialog.h"
|
|
#include "ui_ConnectDialogEdit.h"
|
|
|
|
class ServerItem : public QTreeWidgetItem, public PingStats {
|
|
Q_DISABLE_COPY(ServerItem)
|
|
protected:
|
|
void init();
|
|
|
|
public:
|
|
enum ItemType { FavoriteType, LANType, PublicType };
|
|
|
|
static QMap< QString, QIcon > qmIcons;
|
|
|
|
bool bParent;
|
|
ServerItem *siParent;
|
|
QList< ServerItem * > qlChildren;
|
|
|
|
QString qsName;
|
|
|
|
QString qsHostname;
|
|
unsigned short usPort;
|
|
bool bCA;
|
|
|
|
QString qsUsername;
|
|
QString qsPassword;
|
|
|
|
QString qsCountry;
|
|
QString qsCountryCode;
|
|
QString qsContinentCode;
|
|
|
|
QString qsUrl;
|
|
#ifdef USE_ZEROCONF
|
|
QString zeroconfHost;
|
|
BonjourRecord zeroconfRecord;
|
|
#endif
|
|
/// Contains the resolved addresses for
|
|
/// this ServerItem.
|
|
QList< ServerAddress > qlAddresses;
|
|
|
|
ItemType itType;
|
|
|
|
ServerItem(const FavoriteServer &fs);
|
|
ServerItem(const PublicInfo &pi);
|
|
ServerItem(const QString &name, const QString &host, unsigned short port, const QString &uname,
|
|
const QString &password = QString());
|
|
#ifdef USE_ZEROCONF
|
|
ServerItem(const BonjourRecord &br);
|
|
#endif
|
|
ServerItem(const QString &name, ItemType itype);
|
|
ServerItem(const ServerItem *si);
|
|
~ServerItem();
|
|
|
|
/// Converts given mime data into a ServerItem object
|
|
///
|
|
/// This function checks the clipboard for a valid mumble:// style
|
|
/// URL and converts it into a ServerItem ready to add to the connect
|
|
/// dialog. It also parses .lnk files of InternetShortcut/URL type
|
|
/// to enable those to be dropped onto the clipboard.
|
|
///
|
|
/// @note If needed can query the user for a user name using a modal dialog.
|
|
/// @note If a server item is returned it's the callers responsibility to delete it.
|
|
///
|
|
/// @param mime Mime data to analyze
|
|
/// @param default_name If true the hostname is set as item name if none is given
|
|
/// @param p Parent widget to use in case the user has to be queried
|
|
/// @return Server item or nullptr if mime data invalid.
|
|
///
|
|
static ServerItem *fromMimeData(const QMimeData *mime, bool default_name = true, QWidget *p = nullptr,
|
|
bool convertHttpUrls = false);
|
|
/// Create a ServerItem from a mumble:// URL
|
|
static ServerItem *fromUrl(QUrl url, QWidget *p);
|
|
|
|
void addServerItem(ServerItem *child);
|
|
|
|
FavoriteServer toFavoriteServer() const;
|
|
QMimeData *toMimeData() const;
|
|
static QMimeData *toMimeData(const QString &name, const QString &host, unsigned short port,
|
|
const QString &channel = QString());
|
|
|
|
static QIcon loadIcon(const QString &name);
|
|
|
|
void setDatas(double ping = 0.0, quint32 users = 0, quint32 maxusers = 0);
|
|
bool operator<(const QTreeWidgetItem &) const Q_DECL_OVERRIDE;
|
|
|
|
QVariant data(int column, int role) const Q_DECL_OVERRIDE;
|
|
};
|
|
|
|
class ConnectDialogEdit : public QDialog, protected Ui::ConnectDialogEdit {
|
|
private:
|
|
Q_OBJECT
|
|
Q_DISABLE_COPY(ConnectDialogEdit)
|
|
|
|
void init();
|
|
|
|
protected:
|
|
bool bOk;
|
|
bool bCustomLabel;
|
|
ServerItem *m_si;
|
|
|
|
public slots:
|
|
void validate();
|
|
void accept();
|
|
|
|
void on_qbFill_clicked();
|
|
void on_qbDiscard_clicked();
|
|
void on_qcbShowPassword_toggled(bool);
|
|
void on_qleName_textEdited(const QString &);
|
|
void on_qleServer_textEdited(const QString &);
|
|
void showNotice(const QString &text);
|
|
bool updateFromClipboard();
|
|
|
|
public:
|
|
QString qsName, qsHostname, qsUsername, qsPassword;
|
|
unsigned short usPort;
|
|
ConnectDialogEdit(QWidget *parent, const QString &name, const QString &host, const QString &user,
|
|
unsigned short port, const QString &password);
|
|
/// Add a new Server
|
|
/// Prefills from clipboard content or the connected to server if available
|
|
ConnectDialogEdit(QWidget *parent);
|
|
virtual ~ConnectDialogEdit();
|
|
};
|
|
|
|
class ConnectDialog : public QDialog, public Ui::ConnectDialog {
|
|
friend class ServerView;
|
|
|
|
private:
|
|
Q_OBJECT
|
|
Q_DISABLE_COPY(ConnectDialog)
|
|
protected:
|
|
static QList< PublicInfo > qlPublicServers;
|
|
static QString qsUserCountry, qsUserCountryCode, qsUserContinentCode;
|
|
static Timer tPublicServers;
|
|
|
|
QMenu *qmPopup;
|
|
QPushButton *qpbEdit;
|
|
|
|
bool bPublicInit;
|
|
bool bAutoConnect;
|
|
|
|
Timer tPing;
|
|
Timer tCurrent, tHover, tRestart;
|
|
QUdpSocket *qusSocket4;
|
|
QUdpSocket *qusSocket6;
|
|
QTimer *qtPingTick;
|
|
QList< ServerItem * > qlItems;
|
|
|
|
ServerItem *siAutoConnect;
|
|
|
|
QList< UnresolvedServerAddress > qlDNSLookup;
|
|
QSet< UnresolvedServerAddress > qsDNSActive;
|
|
QHash< UnresolvedServerAddress, QSet< ServerItem * > > qhDNSWait;
|
|
QHash< UnresolvedServerAddress, QList< ServerAddress > > qhDNSCache;
|
|
|
|
QHash< ServerAddress, quint64 > qhPingRand;
|
|
QHash< ServerAddress, QSet< ServerItem * > > qhPings;
|
|
|
|
QMap< UnresolvedServerAddress, unsigned int > qmPingCache;
|
|
|
|
QString qsSearchServername;
|
|
QString qsSearchLocation;
|
|
|
|
bool bIPv4;
|
|
bool bIPv6;
|
|
int iPingIndex;
|
|
Mumble::Protocol::UDPPingEncoder< Mumble::Protocol::Role::Client > m_udpPingEncoder;
|
|
Mumble::Protocol::UDPDecoder< Mumble::Protocol::Role::Client > m_udpDecoder;
|
|
|
|
bool bLastFound;
|
|
|
|
/// bAllowPing determines whether ConnectDialog can use
|
|
/// UDP packets to ping remote hosts to be able to show a
|
|
/// ping latency and user count.
|
|
bool bAllowPing;
|
|
/// bAllowHostLookup determines whether ConnectDialog can
|
|
/// resolve hosts via DNS, Bonjour, and so on.
|
|
bool bAllowHostLookup;
|
|
/// bAllowZeroconf determines whether ConfigDialog can use
|
|
/// zeroconf to find nearby servers on the local network.
|
|
bool bAllowZeroconf;
|
|
/// bAllowFilters determines whether filters are available
|
|
/// in the ConfigDialog. If this option is disabled, the
|
|
/// 'Show All' filter is forced, and no other filter can
|
|
/// be chosen.
|
|
bool bAllowFilters;
|
|
|
|
|
|
void sendPing(const QHostAddress &, unsigned short port, Version::full_t protocolVersion);
|
|
bool writePing(const QHostAddress &host, unsigned short port, Version::full_t protocolVersion,
|
|
const Mumble::Protocol::PingData &pingData);
|
|
|
|
void initList();
|
|
void fillList();
|
|
|
|
void startDns(ServerItem *);
|
|
void stopDns(ServerItem *);
|
|
|
|
/// Calls ConnectDialog::filterServer for each server in
|
|
/// the public server list
|
|
void filterPublicServerList() const;
|
|
/// Hides the given ServerItem according to the current
|
|
/// filter settings. It is checked that the name of the
|
|
/// given server matches ConnectDialog#qsSearchServername
|
|
/// and the location is equal to ConnectDialog#qsSearchLocation.
|
|
/// Lastly it is checked that the server is reachable or
|
|
/// populated, should the respective filters be set.
|
|
///
|
|
/// \param si ServerItem that should be filtered
|
|
void filterServer(ServerItem *const si) const;
|
|
|
|
/// Enumerates all countries in ConnectDialog#qlPublicServers
|
|
/// and adds an entry to the location filter Combobox with
|
|
/// with the country name as text, the countrycode as
|
|
/// data and the flag of the country as the icon.
|
|
void addCountriesToSearchLocation() const;
|
|
public slots:
|
|
void accept();
|
|
void fetched(QByteArray xmlData, QUrl, QMap< QString, QString >);
|
|
|
|
void udpReply();
|
|
void lookedUp();
|
|
void timeTick();
|
|
|
|
void on_qaFavoriteAdd_triggered();
|
|
void on_qaFavoriteAddNew_triggered();
|
|
void on_qaFavoriteEdit_triggered();
|
|
void on_qaFavoriteRemove_triggered();
|
|
void on_qaFavoriteCopy_triggered();
|
|
void on_qaFavoritePaste_triggered();
|
|
void on_qaUrl_triggered();
|
|
void on_qtwServers_currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *);
|
|
void on_qtwServers_itemDoubleClicked(QTreeWidgetItem *, int);
|
|
void on_qtwServers_customContextMenuRequested(const QPoint &);
|
|
/// If the expanded item is the public server list
|
|
/// the user is asked (only once) for consent to transmit
|
|
/// the IP to all public servers. If the user does not
|
|
/// consent the public server list is disabled. If
|
|
/// the user does consent the public server list is
|
|
/// filled and the search dialog is shown.
|
|
/// Finally name resolution is triggered for all child
|
|
/// items of the expanded item.
|
|
void on_qtwServers_itemExpanded(QTreeWidgetItem *item);
|
|
/// Hides the search dialog if the collapsed item is
|
|
/// the public server list
|
|
void on_qtwServers_itemCollapsed(QTreeWidgetItem *item);
|
|
void OnSortChanged(int, Qt::SortOrder);
|
|
|
|
public:
|
|
QString qsServer, qsUsername, qsPassword;
|
|
unsigned short usPort;
|
|
ConnectDialog(QWidget *parent, bool autoconnect);
|
|
~ConnectDialog();
|
|
|
|
#ifdef USE_ZEROCONF
|
|
protected:
|
|
QList< BonjourRecord > qlBonjourActive;
|
|
public slots:
|
|
void onUpdateLanList(const QList< BonjourRecord > &);
|
|
|
|
void onResolved(const BonjourRecord, const QString, const uint16_t);
|
|
void onLanResolveError(const BonjourRecord);
|
|
#endif
|
|
private slots:
|
|
void on_qleSearchServername_textChanged(const QString &searchServername);
|
|
void on_qcbSearchLocation_currentIndexChanged(int searchLocationIndex);
|
|
void on_qcbFilter_currentIndexChanged(int filterIndex);
|
|
};
|
|
|
|
#endif
|