1 #include "server_config_dialog.h"
2 #include <QCoreApplication>
3 #include <QGridLayout>
4 #include <QNetworkInterface>
5 #include <QHostInfo>
6 #include <QHostAddress>
7 #include <QSettings>
8 #include <QPalette>
9 #include <QIntValidator>
10 #include <QFormLayout>
11 #include <QBitmap>
12 #include <QPainter>
13 
14 #include "startup.h"
15 #include "yacreader_global_gui.h"
16 
17 #include "qnaturalsorting.h"
18 
19 #include <algorithm>
20 
21 //192.168 (most comon local subnet for ips are always put first)
22 //IPs are sorted using natoral sorting
ipComparator(const QString & ip1,const QString & ip2)23 bool ipComparator(const QString &ip1, const QString &ip2)
24 {
25     if (ip1.startsWith("192.168") && ip2.startsWith("192.168"))
26         return naturalSortLessThanCI(ip1, ip2);
27 
28     if (ip1.startsWith("192.168"))
29         return true;
30 
31     if (ip2.startsWith("192.168"))
32         return false;
33 
34     return naturalSortLessThanCI(ip1, ip2);
35 }
36 
37 #ifndef Q_OS_WIN32
38 
39 #include <sys/types.h>
40 #include <ifaddrs.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <string.h>
44 #include <arpa/inet.h>
45 
addresses()46 QList<QString> addresses()
47 {
48     struct ifaddrs *ifAddrStruct = NULL;
49     struct ifaddrs *ifa = NULL;
50     void *tmpAddrPtr = NULL;
51 
52     QList<QString> localAddreses;
53 
54     getifaddrs(&ifAddrStruct);
55 
56     for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
57         if (ifa->ifa_addr) {
58             if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
59                 // is a valid IP4 Address
60                 tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
61                 char addressBuffer[INET_ADDRSTRLEN];
62                 inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
63                 localAddreses.push_back(QString(addressBuffer));
64                 //printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
65             } else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6
66                 // is a valid IP6 Address
67                 tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
68                 char addressBuffer[INET6_ADDRSTRLEN];
69                 inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
70                 //printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
71             }
72         }
73     }
74     if (ifAddrStruct != NULL)
75         freeifaddrs(ifAddrStruct);
76     return localAddreses;
77 }
78 
79 #endif
80 
81 extern Startup *s;
82 
ServerConfigDialog(QWidget * parent)83 ServerConfigDialog::ServerConfigDialog(QWidget *parent)
84     : QDialog(parent)
85 {
86     accept = new QPushButton(tr("set port"), this);
87     qrCode = new QLabel(this);
88     qrCode->move(64, 112);
89     qrCode->setFixedSize(200, 200);
90     qrCode->setScaledContents(true);
91 
92     QLabel *title1 = new QLabel(tr("Server connectivity information"), this);
93     title1->move(332, 61);
94     title1->setStyleSheet("QLabel {color:#474747; font-size:30px; font-family: Arial;}");
95 
96     QLabel *qrMessage = new QLabel(tr("Scan it!"), this);
97     qrMessage->move(135, 388); //373,627);
98     qrMessage->setStyleSheet("QLabel {color:#A3A3A3; font-size:18px; font-family: Arial;}");
99     qrMessage->setWordWrap(true);
100     qrMessage->setFixedWidth(200);
101 
102     QLabel *propaganda = new QLabel(tr("YACReader is available for iOS devices. <a href='http://ios.yacreader.com' style='color:rgb(193, 148, 65)'> Discover it! </a>"), this);
103     propaganda->move(332, 505);
104     propaganda->setStyleSheet("QLabel {color:#4D4D4D; font-size:13px; font-family: Arial; font-style: italic;}");
105     /*propaganda->setWordWrap(true);
106     propaganda->setFixedWidth(590);*/
107     propaganda->setOpenExternalLinks(true);
108 
109     //FORM---------------------------------------------------------------------
110 
111     QLabel *ipLabel = new QLabel(tr("Choose an IP address"), this);
112     ipLabel->move(332, 117);
113     ipLabel->setStyleSheet("QLabel {color:#575757; font-size:18px; font-family: Arial;}");
114 
115     QLabel *portLabel = new QLabel(tr("Port"), this);
116     portLabel->move(332, 211);
117     portLabel->setStyleSheet("QLabel {color:#575757; font-size:18px; font-family: Arial;}");
118 
119     ip = new QComboBox(this);
120     connect(ip, SIGNAL(activated(const QString &)), this, SLOT(regenerateQR(const QString &)));
121 
122     ip->setFixedWidth(200);
123     ip->move(332, 153);
124 
125     port = new QLineEdit("8080", this);
126     port->setReadOnly(false);
127     //port->setFixedWidth(100);
128     //port->move(332, 244);
129 
130     //port->move(520,110);
131     QValidator *validator = new QIntValidator(1024, 65535, this);
132     port->setValidator(validator);
133 
134     QWidget *portWidget = new QWidget(this);
135     auto portWidgetLayout = new QHBoxLayout(this);
136     portWidgetLayout->addWidget(port);
137     portWidgetLayout->addWidget(accept);
138     portWidgetLayout->setMargin(0);
139     portWidget->setLayout(portWidgetLayout);
140     portWidget->move(332, 244);
141     //accept->move(514,149);
142     connect(accept, SIGNAL(pressed()), this, SLOT(updatePort()));
143     //END FORM-----------------------------------------------------------------
144 
145     check = new QCheckBox(this);
146     check->move(332, 314);
147     check->setText(tr("enable the server"));
148     check->setStyleSheet("QCheckBox {color:#262626; font-size:13px; font-family: Arial;}");
149 
150     performanceWorkaroundCheck = new QCheckBox(this);
151     performanceWorkaroundCheck->move(332, 354);
152     performanceWorkaroundCheck->setText(tr("display less information about folders in the browser\nto improve the performance"));
153     performanceWorkaroundCheck->setStyleSheet("QCheckBox {color:#262626; font-size:13px; font-family: Arial;}");
154 
155     // set black background
156     QPalette palette;
157     QImage image(":/images/serverConfigBackground.png");
158     palette.setBrush(this->backgroundRole(), QBrush(image));
159 
160     setPalette(palette);
161 
162     this->setFixedSize(image.size());
163 
164     QSettings *settings = new QSettings(YACReader::getSettingsPath() + "/YACReaderLibrary.ini", QSettings::IniFormat); //TODO unificar la creación del fichero de config con el servidor
165     settings->beginGroup("libraryConfig");
166 
167     if (settings->value(SERVER_ON, true).toBool()) {
168         check->setChecked(true);
169         generateQR();
170     } else
171         check->setChecked(false);
172 
173     performanceWorkaroundCheck->setChecked(settings->value(REMOTE_BROWSE_PERFORMANCE_WORKAROUND, false).toBool());
174 
175     settings->endGroup();
176 
177     connect(check, SIGNAL(stateChanged(int)), this, SLOT(enableServer(int)));
178     connect(performanceWorkaroundCheck, SIGNAL(stateChanged(int)), this, SLOT(enableperformanceWorkaround(int)));
179 }
180 
enableServer(int status)181 void ServerConfigDialog::enableServer(int status)
182 {
183     QSettings *settings = new QSettings(YACReader::getSettingsPath() + "/YACReaderLibrary.ini", QSettings::IniFormat); //TODO unificar la creación del fichero de config con el servidor
184     settings->beginGroup("libraryConfig");
185 
186     if (status == Qt::Checked) {
187         s->start();
188         this->generateQR();
189         settings->setValue(SERVER_ON, true);
190     } else {
191         s->stop();
192         qrCode->setPixmap(QPixmap());
193         ip->clear();
194         port->setText("");
195         settings->setValue(SERVER_ON, false);
196     }
197     settings->endGroup();
198 }
199 
enableperformanceWorkaround(int status)200 void ServerConfigDialog::enableperformanceWorkaround(int status)
201 {
202     QSettings *settings = new QSettings(YACReader::getSettingsPath() + "/YACReaderLibrary.ini", QSettings::IniFormat); //TODO unificar la creación del fichero de config con el servidor
203     settings->beginGroup("libraryConfig");
204 
205     if (status == Qt::Checked) {
206         settings->setValue(REMOTE_BROWSE_PERFORMANCE_WORKAROUND, true);
207     } else {
208         settings->setValue(REMOTE_BROWSE_PERFORMANCE_WORKAROUND, false);
209     }
210     settings->endGroup();
211 }
212 
generateQR()213 void ServerConfigDialog::generateQR()
214 {
215     ip->clear();
216     QString dir;
217 
218 #ifdef Q_OS_WIN32
219     QList<QHostAddress> list = QHostInfo::fromName(QHostInfo::localHostName()).addresses();
220 
221     QList<QString> otherAddresses;
222     foreach (QHostAddress add, list) {
223         QString tmp = add.toString();
224         if (tmp.contains(".") && !tmp.startsWith("127")) {
225             otherAddresses.push_back(tmp);
226         }
227     }
228 
229 #else
230     QList<QString> list = addresses();
231 
232     QList<QString> otherAddresses;
233     foreach (QString add, list) {
234         QString tmp = add;
235         if (tmp.contains(".") && !tmp.startsWith("127")) {
236             otherAddresses.push_back(tmp);
237         }
238     }
239 #endif
240 
241     std::sort(otherAddresses.begin(), otherAddresses.end(), ipComparator);
242 
243     if (!otherAddresses.isEmpty()) {
244         dir = otherAddresses.first();
245         otherAddresses.pop_front();
246     }
247 
248     if (otherAddresses.length() > 0 || !dir.isEmpty()) {
249         if (!dir.isEmpty()) {
250             generateQR(dir + ":" + s->getPort());
251 
252             ip->addItem(dir);
253         } else {
254             generateQR(otherAddresses.first() + ":" + s->getPort());
255         }
256         ip->addItems(otherAddresses);
257         port->setText(s->getPort());
258     }
259 }
260 
generateQR(const QString & serverAddress)261 void ServerConfigDialog::generateQR(const QString &serverAddress)
262 {
263     qrCode->clear();
264 
265     QrEncoder encoder;
266     QBitmap image = encoder.encode(serverAddress);
267     if (image.isNull()) {
268         qrCode->setText(tr("Could not load libqrencode."));
269     } else {
270         image = image.scaled(qrCode->size() * devicePixelRatio());
271 
272         QPixmap pMask(image.size());
273         pMask.fill(QColor(66, 66, 66));
274         pMask.setMask(image.createMaskFromColor(Qt::white));
275         pMask.setDevicePixelRatio(devicePixelRatio());
276 
277         qrCode->setPixmap(pMask);
278     }
279 }
280 
regenerateQR(const QString & ip)281 void ServerConfigDialog::regenerateQR(const QString &ip)
282 {
283     generateQR(ip + ":" + s->getPort());
284 }
285 
updatePort()286 void ServerConfigDialog::updatePort()
287 {
288 
289     QSettings *settings = new QSettings(YACReader::getSettingsPath() + "/YACReaderLibrary.ini", QSettings::IniFormat); //TODO unificar la creación del fichero de config con el servidor
290     settings->beginGroup("listener");
291     settings->setValue("port", port->text().toInt());
292     settings->endGroup();
293 
294     s->stop();
295     s->start();
296 
297     generateQR(ip->currentText() + ":" + port->text());
298 }
299 
QrEncoder()300 QrEncoder::QrEncoder()
301 {
302 #ifdef Q_OS_MACOS
303     QLibrary encoder(QCoreApplication::applicationDirPath() + "/utils/libqrencode.dylib");
304 #else
305     QLibrary encoder("qrencode");
306 #endif
307     QRcode_encodeString8bit = (_QRcode_encodeString8bit)encoder.resolve("QRcode_encodeString8bit");
308     QRcode_free = (_QRcode_free)encoder.resolve("QRcode_free");
309 }
310 
encode(const QString & string)311 QBitmap QrEncoder::encode(const QString &string)
312 {
313     if (!QRcode_encodeString8bit) {
314         return QBitmap();
315     }
316     QRcode *code;
317     code = QRcode_encodeString8bit(string.toUtf8().data(), 0, 0);
318     QBitmap result(code->width, code->width);
319     result.fill();
320     /* convert to QBitmap */
321     QPainter painter;
322     painter.begin(&result);
323     unsigned char *pointer = code->data;
324     for (int x = 0; x < code->width; x++) {
325         for (int y = 0; y < code->width; y++) {
326             if ((*pointer++ & 0x1) == 1) {
327                 painter.drawPoint(x, y);
328             }
329         }
330     }
331     painter.end();
332     QRcode_free(code);
333     return result;
334 }
335