1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5 
6 #ifndef MUMBLE_MUMBLE_CONNECTDIALOG_H_
7 #define MUMBLE_MUMBLE_CONNECTDIALOG_H_
8 
9 #ifndef Q_MOC_RUN
10 # include <boost/accumulators/accumulators.hpp>
11 # include <boost/accumulators/statistics/stats.hpp>
12 #endif
13 
14 #include <QtCore/QtGlobal>
15 #include <QtCore/QString>
16 #include <QtCore/QUrl>
17 #if QT_VERSION >= 0x050000
18 # include <QtWidgets/QStyledItemDelegate>
19 # include <QtWidgets/QTreeView>
20 # include <QtWidgets/QTreeWidgetItem>
21 #else
22 # include <QtGui/QStyledItemDelegate>
23 # include <QtGui/QTreeView>
24 # include <QtGui/QTreeWidgetItem>
25 #endif
26 
27 #include <QtNetwork/QHostInfo>
28 
29 #ifdef USE_BONJOUR
30 #include <dns_sd.h>
31 #endif
32 
33 #include "BonjourRecord.h"
34 #include "Net.h"
35 #include "HostAddress.h"
36 #include "Timer.h"
37 #include "UnresolvedServerAddress.h"
38 #include "ServerAddress.h"
39 
40 struct FavoriteServer;
41 class QUdpSocket;
42 
43 struct PublicInfo {
44 	QString qsName;
45 	QUrl quUrl;
46 	QString qsIp;
47 	QString qsCountry;
48 	QString qsCountryCode;
49 	QString qsContinentCode;
50 	unsigned short usPort;
51 	bool bCA;
52 };
53 
54 struct PingStats {
55 private:
56 	Q_DISABLE_COPY(PingStats)
57 protected:
58 	void init();
59 public:
60 	quint32 uiVersion;
61 	quint32 uiPing;
62 	quint32 uiPingSort;
63 	quint32 uiUsers;
64 	quint32 uiMaxUsers;
65 	quint32 uiBandwidth;
66 	quint32 uiSent;
67 	quint32 uiRecv;
68 
69 	double dPing;
70 
71 	typedef boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::count, boost::accumulators::tag::extended_p_square> > asQuantileType;
72 	asQuantileType *asQuantile;
73 
74 	void reset();
75 
76 	PingStats();
77 	~PingStats();
78 };
79 
80 class ServerItem;
81 
82 class ServerViewDelegate : public QStyledItemDelegate {
83 	Q_OBJECT
84 	Q_DISABLE_COPY(ServerViewDelegate)
85 public:
86 	ServerViewDelegate(QObject *p = NULL);
87 	~ServerViewDelegate();
88 
89 	void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
90 };
91 
92 class ServerView : public QTreeWidget {
93 		Q_OBJECT
94 		Q_DISABLE_COPY(ServerView)
95 	public:
96 		ServerItem *siFavorite, *siLAN, *siPublic;
97 		QMap<QString, QString> qmContinentNames;
98 		QMap<QString, ServerItem *> qmCountry;
99 		QMap<QString, ServerItem *> qmContinent;
100 
101 		ServerView(QWidget *);
102 		~ServerView() Q_DECL_OVERRIDE;
103 
104 		void fixupName(ServerItem *si);
105 
106 		ServerItem *getParent(const QString &continent, const QString &countrycode, const QString &countryname, const QString &usercontinentcode, const QString &usercountrycode);
107 	protected:
108 		QMimeData *mimeData(const QList<QTreeWidgetItem *>) const Q_DECL_OVERRIDE;
109 		QStringList mimeTypes() const Q_DECL_OVERRIDE;
110 		Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE;
111 		bool dropMimeData(QTreeWidgetItem *, int, const QMimeData *, Qt::DropAction) Q_DECL_OVERRIDE;
112 };
113 
114 #include "ui_ConnectDialog.h"
115 #include "ui_ConnectDialogEdit.h"
116 
117 class ServerItem : public QTreeWidgetItem, public PingStats {
118 		Q_DISABLE_COPY(ServerItem)
119 	protected:
120 		void init();
121 	public:
122 		enum ItemType { FavoriteType, LANType, PublicType };
123 
124 		static QMap<QString, QIcon> qmIcons;
125 
126 		bool bParent;
127 		ServerItem *siParent;
128 		QList<ServerItem *> qlChildren;
129 
130 		QString qsName;
131 
132 		QString qsHostname;
133 		unsigned short usPort;
134 		bool bCA;
135 
136 		QString qsUsername;
137 		QString qsPassword;
138 
139 		QString qsCountry;
140 		QString qsCountryCode;
141 		QString qsContinentCode;
142 
143 		QString qsUrl;
144 
145 		QString qsBonjourHost;
146 		BonjourRecord brRecord;
147 
148 		/// Contains the resolved addresses for
149 		/// this ServerItem.
150 		QList<ServerAddress> qlAddresses;
151 
152 		ItemType itType;
153 
154 		ServerItem(const FavoriteServer &fs);
155 		ServerItem(const PublicInfo &pi);
156 		ServerItem(const QString &name, const QString &host, unsigned short port, const QString &uname, const QString &password = QString());
157 		ServerItem(const BonjourRecord &br);
158 		ServerItem(const QString &name, ItemType itype, const QString &continent = QString(), const QString &country = QString());
159 		ServerItem(const ServerItem *si);
160 		~ServerItem();
161 
162 		/// Converts given mime data into a ServerItem object
163 		///
164 		/// This function checks the clipboard for a valid mumble:// style
165 		/// URL and converts it into a ServerItem ready to add to the connect
166 		/// dialog. It also parses .lnk files of InternetShortcut/URL type
167 		/// to enable those to be dropped onto the clipboard.
168 		///
169 		/// @note If needed can query the user for a user name using a modal dialog.
170 		/// @note If a server item is returned it's the callers reponsibility to delete it.
171 		///
172 		/// @param mime Mime data to analyze
173 		/// @param default_name If true the hostname is set as item name if none is given
174 		/// @param p Parent widget to use in case the user has to be queried
175 		/// @return Server item or NULL if mime data invalid.
176 		///
177 		static ServerItem *fromMimeData(const QMimeData *mime, bool default_name = true, QWidget *p = NULL, bool convertHttpUrls=false);
178 		/// Create a ServerItem from a mumble:// URL
179 		static ServerItem *fromUrl(QUrl url, QWidget *p);
180 
181 		void addServerItem(ServerItem *child);
182 
183 		FavoriteServer toFavoriteServer() const;
184 		QMimeData *toMimeData() const;
185 		static QMimeData *toMimeData(const QString &name, const QString &host, unsigned short port, const QString &channel = QString());
186 
187 		static QIcon loadIcon(const QString &name);
188 
189 		void setDatas(double ping = 0.0, quint32 users = 0, quint32 maxusers = 0);
190 		bool operator< (const QTreeWidgetItem &) const Q_DECL_OVERRIDE;
191 
192 		QVariant data(int column, int role) const Q_DECL_OVERRIDE;
193 
194 		void hideCheck();
195 };
196 
197 class ConnectDialogEdit : public QDialog, protected Ui::ConnectDialogEdit {
198 	private:
199 		Q_OBJECT
200 		Q_DISABLE_COPY(ConnectDialogEdit)
201 
202 		void init();
203 	protected:
204 		bool bOk;
205 		bool bCustomLabel;
206 		ServerItem *m_si;
207 
208 	public slots:
209 		void validate();
210 		void accept();
211 
212 		void on_qbFill_clicked();
213 		void on_qbDiscard_clicked();
214 		void on_qcbShowPassword_toggled(bool);
215 		void on_qleName_textEdited(const QString&);
216 		void on_qleServer_textEdited(const QString&);
217 		void showNotice(const QString &text);
218 		bool updateFromClipboard();
219 	public:
220 		QString qsName, qsHostname, qsUsername, qsPassword;
221 		unsigned short usPort;
222 		ConnectDialogEdit(QWidget *parent,
223 		                  const QString &name,
224 		                  const QString &host,
225 		                  const QString &user,
226 		                  unsigned short port,
227 		                  const QString &password);
228 		/// Add a new Server
229 		/// Prefills from clipboard content or the connected to server if available
230 		ConnectDialogEdit(QWidget *parent);
231 		virtual ~ConnectDialogEdit();
232 };
233 
234 class ConnectDialog : public QDialog, public Ui::ConnectDialog {
235 		friend class ServerView;
236 	private:
237 		Q_OBJECT
238 		Q_DISABLE_COPY(ConnectDialog)
239 	protected:
240 		static QList<PublicInfo> qlPublicServers;
241 		static QString qsUserCountry, qsUserCountryCode, qsUserContinentCode;
242 		static Timer tPublicServers;
243 
244 		QMenu *qmPopup, *qmFilters;
245 		QActionGroup *qagFilters;
246 		QPushButton *qpbEdit;
247 
248 		bool bPublicInit;
249 		bool bAutoConnect;
250 
251 		Timer tPing;
252 		Timer tCurrent, tHover, tRestart;
253 		QUdpSocket *qusSocket4;
254 		QUdpSocket *qusSocket6;
255 		QTimer *qtPingTick;
256 		QList<ServerItem *> qlItems;
257 
258 		ServerItem *siAutoConnect;
259 
260 		QList<UnresolvedServerAddress> qlDNSLookup;
261 		QSet<UnresolvedServerAddress> qsDNSActive;
262 		QHash<UnresolvedServerAddress, QSet<ServerItem *> > qhDNSWait;
263 		QHash<UnresolvedServerAddress, QList<ServerAddress> > qhDNSCache;
264 
265 		QHash<ServerAddress, quint64> qhPingRand;
266 		QHash<ServerAddress, QSet<ServerItem *> > qhPings;
267 
268 		QMap<UnresolvedServerAddress, unsigned int> qmPingCache;
269 
270 		bool bIPv4;
271 		bool bIPv6;
272 		int iPingIndex;
273 
274 		bool bLastFound;
275 
276 		/// bAllowPing determines whether ConnectDialog can use
277 		/// UDP packets to ping remote hosts to be able to show a
278 		/// ping latency and user count.
279 		bool bAllowPing;
280 		/// bAllowHostLookup determines whether ConnectDialog can
281 		/// resolve hosts via DNS, Bonjour, and so on.
282 		bool bAllowHostLookup;
283 		/// bAllowBonjour determines whether ConfigDialog can use
284 		/// Bonjour to find nearby servers on the local network.
285 		bool bAllowBonjour;
286 		/// bAllowFilters determines whether filters are available
287 		/// in the ConfigDialog. If this option is diabled, the
288 		/// 'Show All' filter is forced, and no other filter can
289 		/// be chosen.
290 		bool bAllowFilters;
291 
292 		QMap<QString, QIcon> qmIcons;
293 
294 		void sendPing(const QHostAddress &, unsigned short port);
295 
296 		void initList();
297 		void fillList();
298 
299 		void startDns(ServerItem *);
300 		void stopDns(ServerItem *);
301 	public slots:
302 		void accept();
303 		void fetched(QByteArray xmlData, QUrl, QMap<QString, QString>);
304 
305 		void udpReply();
306 		void lookedUp();
307 		void timeTick();
308 
309 		void on_qaFavoriteAdd_triggered();
310 		void on_qaFavoriteAddNew_triggered();
311 		void on_qaFavoriteEdit_triggered();
312 		void on_qaFavoriteRemove_triggered();
313 		void on_qaFavoriteCopy_triggered();
314 		void on_qaFavoritePaste_triggered();
315 		void on_qaUrl_triggered();
316 		void onFiltersTriggered(QAction *);
317 		void on_qtwServers_currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *);
318 		void on_qtwServers_itemDoubleClicked(QTreeWidgetItem *, int);
319 		void on_qtwServers_customContextMenuRequested(const QPoint &);
320 		void on_qtwServers_itemExpanded(QTreeWidgetItem *);
321 		void OnSortChanged(int, Qt::SortOrder);
322 	public:
323 		QString qsServer, qsUsername, qsPassword;
324 		unsigned short usPort;
325 		ConnectDialog(QWidget *parent, bool autoconnect);
326 		~ConnectDialog();
327 
328 #ifdef USE_BONJOUR
329 	protected:
330 		QList<BonjourRecord> qlBonjourActive;
331 	public slots:
332 		void onUpdateLanList(const QList<BonjourRecord> &);
333 		void onLanBrowseError(DNSServiceErrorType);
334 
335 		void onResolved(BonjourRecord, QString, int);
336 		void onLanResolveError(BonjourRecord, DNSServiceErrorType);
337 #endif
338 };
339 
340 #endif
341