Freeciv21
Develop your civilization from humble roots to a global empire
page_network.cpp
Go to the documentation of this file.
1 /*
2  .--~~,__ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 :-....,-------`~~'._.' contributors. This file is part of Freeciv21.
4  `-,,, ,_ ;'~U' Freeciv21 is free software: you can redistribute it
5  _,-' ,'`-__; '--. and/or modify it under the terms of the GNU
6  (_/'~~ ''''(; General Public License as published by the
7  Free Software Foundation, either version 3 of
8  the License, or (at your option) any later version. You should have
9  received a copy of the GNU General Public License along with Freeciv21.
10  If not, see https://www.gnu.org/licenses/.
11  */
12 #include "page_network.h"
13 
14 #include <QTimer>
15 
16 // utility
17 #include "fcintl.h"
18 // client
19 #include "chatline.h"
20 #include "chatline_common.h"
21 #include "client_main.h"
22 #include "clinet.h"
23 #include "dialogs.h"
24 #include "fc_client.h"
25 
27 static struct server_scan *meta_scan, *lan_scan;
28 
30  : QWidget(parent), meta_scan_timer(nullptr), lan_scan_timer(nullptr)
31 {
32  king = gui;
33  ui.setupUi(this);
34 
35  QHeaderView *header;
36 
37  ui.connect_password_edit->setEchoMode(QLineEdit::Password);
38  ui.connect_confirm_password_edit->setEchoMode(QLineEdit::Password);
39  ui.connect_password_edit->setDisabled(true);
40  ui.connect_confirm_password_edit->setDisabled(true);
41 
42  QStringList servers_list;
43  servers_list << _("Server Name") << _("Port") << _("Version")
44  << _("Status") << Q_("?count:Players") << _("Comment");
45  QStringList server_info;
46  server_info << _("Name") << _("Type") << _("Host") << _("Nation");
47  // TODO put it to designer
48  ui.lan_widget->setRowCount(0);
49  ui.lan_widget->setColumnCount(servers_list.count());
50  ui.lan_widget->verticalHeader()->setVisible(false);
51  ui.lan_widget->setAutoScroll(false);
52  ui.wan_widget->setRowCount(0);
53  ui.wan_widget->setColumnCount(servers_list.count());
54  ui.wan_widget->verticalHeader()->setVisible(false);
55  ui.wan_widget->setAutoScroll(false);
56  ui.info_widget->setRowCount(0);
57  ui.info_widget->setColumnCount(server_info.count());
58  ui.info_widget->verticalHeader()->setVisible(false);
59  ui.lan_widget->setHorizontalHeaderLabels(servers_list);
60  ui.lan_widget->setProperty("showGrid", "false");
61  ui.lan_widget->setProperty("selectionBehavior", "SelectRows");
62  ui.lan_widget->setEditTriggers(QAbstractItemView::NoEditTriggers);
63  ui.lan_widget->setSelectionMode(QAbstractItemView::SingleSelection);
64  ui.wan_widget->setHorizontalHeaderLabels(servers_list);
65  ui.wan_widget->setProperty("showGrid", "false");
66  ui.wan_widget->setProperty("selectionBehavior", "SelectRows");
67  ui.wan_widget->setEditTriggers(QAbstractItemView::NoEditTriggers);
68  ui.wan_widget->setSelectionMode(QAbstractItemView::SingleSelection);
69 
70  connect(ui.wan_widget->selectionModel(),
71  &QItemSelectionModel::selectionChanged, this,
73 
74  connect(ui.lan_widget->selectionModel(),
75  &QItemSelectionModel::selectionChanged, this,
77  connect(ui.wan_widget, &QTableWidget::itemDoubleClicked, this,
79  connect(ui.lan_widget, &QTableWidget::itemDoubleClicked, this,
81 
82  ui.info_widget->setHorizontalHeaderLabels(server_info);
83  ui.info_widget->setProperty("selectionBehavior", "SelectRows");
84  ui.info_widget->setEditTriggers(QAbstractItemView::NoEditTriggers);
85  ui.info_widget->setSelectionMode(QAbstractItemView::SingleSelection);
86  ui.info_widget->setProperty("showGrid", "false");
87  ui.info_widget->setAlternatingRowColors(true);
88 
89  header = ui.lan_widget->horizontalHeader();
90  header->setSectionResizeMode(0, QHeaderView::Stretch);
91  header->setStretchLastSection(true);
92  header = ui.wan_widget->horizontalHeader();
93  header->setSectionResizeMode(0, QHeaderView::Stretch);
94  header->setStretchLastSection(true);
95  header = ui.info_widget->horizontalHeader();
96  header->setSectionResizeMode(0, QHeaderView::Stretch);
97  header->setStretchLastSection(true);
98 
99  ui.lhost->setText(_("Connect"));
100  ui.lport->setText(_("Port"));
101  ui.lname->setText(_("Username"));
102  ui.lpass->setText(_("Password"));
103  ui.lconfpass->setText(_("Confirm Password"));
104 
105  ui.refresh_button->setText(_("Refresh"));
106  ui.cancel_button->setText(_("Cancel"));
107  ui.connect_button->setText(_("Connect"));
108  QObject::connect(ui.refresh_button, &QAbstractButton::clicked, this,
110  QObject::connect(ui.cancel_button, &QPushButton::clicked,
111  [gui]() { gui->switch_page(PAGE_MAIN); });
112  connect(ui.connect_button, &QAbstractButton::clicked, this,
114  connect(ui.connect_login_edit, &QLineEdit::returnPressed, this,
116  connect(ui.connect_password_edit, &QLineEdit::returnPressed, this,
118  connect(ui.connect_confirm_password_edit, &QLineEdit::returnPressed, this,
120 
121  ui.lan_label->setText(_("Internet servers:"));
122  ui.wan_label->setText(_("Local servers:"));
123 
124  ui.connect_host_edit->setText(client_url().host());
125  ui.connect_port_edit->setText(QString::number(client_url().port()));
126  ui.connect_login_edit->setText(client_url().userName());
127  ui.connect_password_edit->setDisabled(true);
128  ui.connect_confirm_password_edit->setDisabled(true);
129  setLayout(ui.gridLayout);
130 }
131 
132 page_network::~page_network() = default;
133 
138 {
139  switch (state) {
140  case LOGIN_TYPE:
141  king->set_status_bar(QLatin1String(""));
142  ui.connect_password_edit->setText(QLatin1String(""));
143  ui.connect_password_edit->setDisabled(true);
144  ui.connect_confirm_password_edit->setText(QLatin1String(""));
145  ui.connect_confirm_password_edit->setDisabled(true);
146  break;
147  case NEW_PASSWORD_TYPE:
148  ui.connect_password_edit->setText(QLatin1String(""));
149  ui.connect_confirm_password_edit->setText(QLatin1String(""));
150  ui.connect_password_edit->setDisabled(false);
151  ui.connect_confirm_password_edit->setDisabled(false);
152  ui.connect_password_edit->setFocus(Qt::OtherFocusReason);
153  break;
154  case ENTER_PASSWORD_TYPE:
155  ui.connect_password_edit->setText(QLatin1String(""));
156  ui.connect_confirm_password_edit->setText(QLatin1String(""));
157  ui.connect_password_edit->setDisabled(false);
158  ui.connect_confirm_password_edit->setDisabled(true);
159  ui.connect_password_edit->setFocus(Qt::OtherFocusReason);
160 
161  break;
162  case WAITING_TYPE:
163  king->set_status_bar(QLatin1String(""));
164  break;
165  }
166 
167  connection_status = state;
168 }
169 
174  const struct server_list *list)
175 {
176  QTableWidget *sel = nullptr;
177  QString host, portstr;
178  int port;
179  int row;
180  int old_row_count;
181 
182  switch (sstype) {
183  case SERVER_SCAN_LOCAL:
184  sel = ui.lan_widget;
185  break;
186  case SERVER_SCAN_GLOBAL:
187  sel = ui.wan_widget;
188  break;
189  default:
190  break;
191  }
192 
193  if (!sel) {
194  return;
195  }
196 
197  if (!list) {
198  return;
199  }
200 
201  host = ui.connect_host_edit->text();
202  portstr = ui.connect_port_edit->text();
203  port = portstr.toInt();
204  old_row_count = sel->rowCount();
205  sel->clearContents();
206  row = 0;
207  server_list_iterate(list, pserver)
208  {
209  char buf[20];
210  int tmp;
211  QString tstring;
212 
213  if (old_row_count <= row) {
214  sel->insertRow(row);
215  }
216 
217  if (pserver->humans >= 0) {
218  fc_snprintf(buf, sizeof(buf), "%d", pserver->humans);
219  } else {
220  qstrncpy(buf, _("Unknown"), sizeof(buf) - 1);
221  }
222 
223  tmp = pserver->port;
224  tstring = QString::number(tmp);
225 
226  for (int col = 0; col < 6; col++) {
227  QTableWidgetItem *item;
228 
229  item = new QTableWidgetItem();
230 
231  switch (col) {
232  case 0:
233  item->setText(pserver->host);
234  break;
235  case 1:
236  item->setText(tstring);
237  break;
238  case 2:
239  item->setText(pserver->version);
240  break;
241  case 3:
242  item->setText(_(pserver->state));
243  break;
244  case 4:
245  item->setText(buf);
246  break;
247  case 5:
248  item->setText(pserver->message);
249  break;
250  default:
251  break;
252  }
253  sel->setItem(row, col, item);
254  }
255 
256  if (host == pserver->host && port == pserver->port) {
257  sel->selectRow(row);
258  }
259 
260  row++;
261  }
263 
264  // Remove unneeded rows, if there are any
265  while (old_row_count - row > 0) {
266  sel->removeRow(old_row_count - 1);
267  old_row_count--;
268  }
269 }
270 
274 void server_scan_error(struct server_scan *scan, const char *message)
275 {
276  Q_UNUSED(scan)
278  qCritical("%s", message);
279  qobject_cast<page_network *>(king()->pages[PAGE_NETWORK])
280  ->destroy_server_scans();
281 }
282 
287 {
288 #ifndef __EMSCRIPTEN__
289  if (meta_scan) {
291  meta_scan = nullptr;
292  }
293 
294  if (meta_scan_timer != nullptr) {
295  meta_scan_timer->stop();
296  meta_scan_timer->disconnect();
297  delete meta_scan_timer;
298  meta_scan_timer = nullptr;
299  }
300 
301  if (lan_scan) {
303  lan_scan = nullptr;
304  }
305 
306  if (lan_scan_timer != nullptr) {
307  lan_scan_timer->stop();
308  lan_scan_timer->disconnect();
309  delete lan_scan_timer;
310  lan_scan_timer = nullptr;
311  }
312 #endif
313 }
314 
319 {
320 #ifndef __EMSCRIPTEN__
322 
323  lan_scan_timer = new QTimer(this);
325  if (lan_scan_timer) {
326  // The timer may have been destroyed if there was an error
327  connect(lan_scan_timer, &QTimer::timeout, this,
329  lan_scan_timer->start(500);
330  }
331 
332  meta_scan_timer = new QTimer(this);
334  if (meta_scan_timer) {
335  // The timer may have been destroyed if there was an error
336  connect(meta_scan_timer, &QTimer::timeout, this,
338  meta_scan_timer->start(800);
339  }
340 #endif
341 }
342 
347 {
348 #ifndef __EMSCRIPTEN__
349  struct server_scan *scan = scan_data;
350  enum server_scan_status stat;
351 
352  if (!scan) {
353  return false;
354  }
355 
356  stat = server_scan_poll(scan);
357 
358  if (stat >= SCAN_STATUS_PARTIAL) {
359  enum server_scan_type type;
360  struct server_list *srvrs;
361 
362  type = server_scan_get_type(scan);
363  srvrs = server_scan_get_list(scan);
364  update_server_list(type, srvrs);
365  }
366 
367  return !(stat == SCAN_STATUS_ERROR || stat == SCAN_STATUS_DONE);
368 #else
369  return true;
370 #endif
371 }
372 
377 {
378  if (lan_scan_timer == nullptr) {
379  return;
380  }
382 }
383 
388 {
389  if (meta_scan_timer == nullptr) {
390  return;
391  }
393 }
399  const char *message)
400 {
401  king->set_status_bar(QString::fromUtf8(message));
403 
404  switch (type) {
405  case AUTH_NEWUSER_FIRST:
406  case AUTH_NEWUSER_RETRY:
408  return;
409  case AUTH_LOGIN_FIRST:
410  /* if we magically have a password already present in 'password'
411  * then, use that and skip the password entry dialog */
412  if (!client_url().password().isEmpty()) {
413  struct packet_authentication_reply reply;
414 
415  sz_strlcpy(reply.password, qUtf8Printable(client_url().password()));
416  send_packet_authentication_reply(&client.conn, &reply);
417 
418  // Don't store the password
419  client_url().setPassword(QString());
420  return;
421  } else {
423  }
424 
425  return;
426  case AUTH_LOGIN_RETRY:
428  return;
429  }
430 
431  qCritical("Unsupported authentication type %d: %s.", type, message);
432 }
433 
440 {
441  char errbuf[512];
442  struct packet_authentication_reply reply;
443 
444  switch (connection_status) {
445  case LOGIN_TYPE:
446  client_url().setScheme(QStringLiteral("fc21"));
447  client_url().setUserName(ui.connect_login_edit->text());
448  client_url().setHost(ui.connect_host_edit->text());
449  client_url().setPort(ui.connect_port_edit->text().toInt());
450 
451  if (connect_to_server(client_url(), errbuf, sizeof(errbuf)) < 0) {
452  king->set_status_bar(QString::fromUtf8(errbuf));
454  }
455 
456  return;
457  case NEW_PASSWORD_TYPE:
458  client_url().setPassword(ui.connect_password_edit->text());
459  if (client_url().password()
460  == ui.connect_confirm_password_edit->text()) {
461  fc_strlcpy(reply.password, qUtf8Printable(client_url().password()),
463  send_packet_authentication_reply(&client.conn, &reply);
465  } else {
466  king->set_status_bar(_("Passwords don't match, enter password."));
468  }
469 
470  return;
471  case ENTER_PASSWORD_TYPE:
472  client_url().setPassword(ui.connect_password_edit->text());
473  fc_strlcpy(reply.password, qUtf8Printable(client_url().password()),
475  send_packet_authentication_reply(&client.conn, &reply);
477  return;
478  case WAITING_TYPE:
479  return;
480  }
481 
482  qCritical("Unsupported connection status: %d", connection_status);
483 }
484 
488 void page_network::slot_selection_changed(const QItemSelection &selected,
489  const QItemSelection &deselected)
490 {
491  Q_UNUSED(deselected)
492  QModelIndexList indexes = selected.indexes();
493  QStringList sl;
494  QModelIndex index;
495  QTableWidgetItem *item;
496  QItemSelectionModel *tw;
497 
498  const struct server *pserver = nullptr;
499  int k, col, n;
500  struct server_list *srvrs;
501 
502  if (indexes.isEmpty()) {
503  return;
504  }
505 
506  index = indexes.at(0);
507  ui.connect_host_edit->setText(index.data().toString());
508  index = indexes.at(1);
509  ui.connect_port_edit->setText(index.data().toString());
510 
511  tw = qobject_cast<QItemSelectionModel *>(sender());
512 
513  if (tw == ui.lan_widget->selectionModel()) {
514  ui.wan_widget->clearSelection();
515  } else {
516  ui.lan_widget->clearSelection();
517  }
518 
519 #ifndef __EMSCRIPTEN__
521  if (srvrs) {
522  pserver = server_list_get(srvrs, index.row());
523  }
524  if (!pserver || !pserver->players) {
525  return;
526  }
527  n = pserver->nplayers;
528  ui.info_widget->clearContents();
529  ui.info_widget->setRowCount(0);
530  for (k = 0; k < n; k++) {
531  ui.info_widget->insertRow(k);
532  for (col = 0; col < 4; col++) {
533  item = new QTableWidgetItem();
534  switch (col) {
535  case 0:
536  item->setText(pserver->players[k].name);
537  break;
538  case 1:
539  item->setText(pserver->players[k].type);
540  break;
541  case 2:
542  item->setText(pserver->players[k].host);
543  break;
544  case 3:
545  item->setText(pserver->players[k].nation);
546  break;
547  default:
548  break;
549  }
550  ui.info_widget->setItem(k, col, item);
551  }
552  }
553 #endif
554 }
void version_message(const QString &vertext)
Got version message from metaserver.
Definition: chatline.cpp:897
void output_window_append(const struct ft_color color, const char *featured_text)
Add a line of text to the output ("chatline") window, like puts() would do it in the console.
void set_status_bar(const QString &str, int timeout=20000)
Sets application status bar for given time in miliseconds.
Definition: fc_client.cpp:606
void update_network_lists()
Stop and restart the metaserver and lan server scans.
void update_server_list(enum server_scan_type sstype, const struct server_list *list)
Updates list of servers in network page in proper QTableViews.
void slot_meta_scan()
Executes metaserver scan network.
void slot_lan_scan()
Executes lan scan network.
void slot_connect()
If on the network page, switch page to the login page (with new server and port).
QTimer * lan_scan_timer
Definition: page_network.h:50
void handle_authentication_req(enum authentication_type type, const char *message)
Configure the dialog depending on what type of authentication request the server is making.
bool check_server_scan(server_scan *scan_data)
This function updates the list of servers every so often.
~page_network() override
QTimer * meta_scan_timer
Definition: page_network.h:49
void slot_selection_changed(const QItemSelection &, const QItemSelection &)
void destroy_server_scans()
Free the server scans.
void set_connection_state(enum connection_state state)
Update network page connection state.
page_network(QWidget *, fc_client *)
fc_client * king
Definition: page_network.h:48
Ui::FormPageNetwork ui
Definition: page_network.h:51
QUrl & client_url()
Returns the URL that this client connects to.
struct civclient client
int connect_to_server(const QUrl &url, char *errbuf, int errbufsize)
Connect to a freeciv21-server instance – or at least try to.
Definition: clinet.cpp:167
#define MAX_LEN_PASSWORD
Definition: connection.h:43
connection_state
Definition: fc_client.h:42
@ LOGIN_TYPE
Definition: fc_client.h:43
@ NEW_PASSWORD_TYPE
Definition: fc_client.h:44
@ WAITING_TYPE
Definition: fc_client.h:46
@ ENTER_PASSWORD_TYPE
Definition: fc_client.h:45
class fc_client * king()
Return fc_client instance.
Definition: gui_main.cpp:58
#define Q_(String)
Definition: fcintl.h:53
#define _(String)
Definition: fcintl.h:50
const struct ft_color ftc_client
static mpgui * gui
Definition: mpgui_qt.cpp:47
authentication_type
Definition: packets.h:67
@ AUTH_NEWUSER_RETRY
Definition: packets.h:71
@ AUTH_NEWUSER_FIRST
Definition: packets.h:69
@ AUTH_LOGIN_RETRY
Definition: packets.h:70
@ AUTH_LOGIN_FIRST
Definition: packets.h:68
static enum connection_state connection_status
static struct server_scan * meta_scan
void server_scan_error(struct server_scan *scan, const char *message)
Callback function for when there's an error in the server scan.
static struct server_scan * lan_scan
struct server_list * server_scan_get_list(struct server_scan *scan)
Returns the srv_list currently held by the scan (may be nullptr).
Definition: servers.cpp:594
struct server_scan * server_scan_begin(enum server_scan_type type, ServerScanErrorFunc error_func)
Creates a new server scan and returns it, or nullptr if impossible.
Definition: servers.cpp:518
void server_scan_finish(struct server_scan *scan)
Closes the socket listening on the scan, frees the list of servers, and frees the memory allocated fo...
Definition: servers.cpp:607
enum server_scan_type server_scan_get_type(const struct server_scan *scan)
A simple query function to determine the type of a server scan (previously allocated in server_scan_b...
Definition: servers.cpp:546
enum server_scan_status server_scan_poll(struct server_scan *scan)
A function to query servers of the server scan.
Definition: servers.cpp:569
#define server_list_iterate_end
Definition: servers.h:75
server_scan_status
Definition: servers.h:21
@ SCAN_STATUS_PARTIAL
Definition: servers.h:24
@ SCAN_STATUS_ERROR
Definition: servers.h:22
@ SCAN_STATUS_DONE
Definition: servers.h:25
#define server_list_iterate(serverlist, pserver)
Definition: servers.h:73
server_scan_type
Definition: servers.h:79
@ SERVER_SCAN_LOCAL
Definition: servers.h:80
@ SERVER_SCAN_GLOBAL
Definition: servers.h:81
struct connection conn
Definition: client_main.h:89
Definition: climisc.h:66
enum server_scan_type type
Definition: servers.cpp:45
Definition: servers.h:55
str_players * players
Definition: servers.h:64
int nplayers
Definition: servers.h:65
char * host
Definition: servers.h:52
char * name
Definition: servers.h:50
char * type
Definition: servers.h:51
char * nation
Definition: servers.h:53
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
size_t fc_strlcpy(char *dest, const char *src, size_t n)
fc_strlcpy() provides utf-8 version of (non-standard) function strlcpy() It is intended as more user-...
Definition: support.cpp:412
#define sz_strlcpy(dest, src)
Definition: support.h:140