initial web page
[woller] / woller.cpp
1 // Copyright 2010 Ilkka Tengvall
2 //
3 // This file is part of Woller.
4 //
5 // Woller is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Woller is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Woller.  If not, see <http://www.gnu.org/licenses/>.
17
18
19 #include "woller.h"
20
21
22 Woller::Woller(QWidget *parent)
23         : QWidget(parent)
24 {
25     QList<QString> targets;
26     status_orig = new QString(
27             tr("Choose the target or configure and fire it up!"));
28     status_timer = new QTimer(this);
29     hosts_list = new QList<host_s>;
30     settings = new QSettings("woller", "woller");
31     // build the main widget
32     this->setWindowIcon(QIcon::fromTheme("woller", QIcon(":/woller.png")));
33     status_lbl = new QLabel(*status_orig , this);
34     fire_btn = new QPushButton(tr("Wake UP"), this);
35     fire_btn->setToolTip(
36             tr("Press the button to wake up selected target (or config)"));
37     fire_btn->setIcon(QIcon::fromTheme("woller", QIcon(":/woller.png")));
38     targets_cb = new QComboBox(this);
39     targets_cb->setToolTip(
40             tr("Choose host to wake up, or configure hosts option"));
41
42     vlayout = new QVBoxLayout();
43     hlayout = new QHBoxLayout();
44     hlayout->addWidget(targets_cb);
45     hlayout->addWidget(fire_btn);
46     vlayout->addWidget(status_lbl);
47     vlayout->addLayout(hlayout);
48     this->setLayout(vlayout);
49     this->setWindowTitle(tr("Woller-program"));
50
51     //populate CB
52     load_config();
53
54     target = new wol_target;
55
56     connect(fire_btn, SIGNAL(clicked()), this, SLOT(send_pkt()));
57     connect(targets_cb, SIGNAL(activated(int)), this, SLOT(targets_act(int)));
58 }
59
60 Woller::~Woller()
61 {
62     int i = targets_cb->currentIndex();
63     qDebug() << "~Woller" << endl;
64     qDebug() << "~Woller last" << i << endl;
65     settings->setValue("last selected", i);
66     settings->setValue("position", pos());
67     delete settings;
68     delete hosts_list;
69     delete status_lbl;
70     delete fire_btn;
71     delete targets_cb;
72     //delete vlayout;
73     //delete hlayout;
74     delete target;
75     delete status_orig;
76     delete status_timer;
77 }
78
79 void Woller::send_pkt()
80 {
81     int t = targets_cb->currentIndex();
82
83     if (t == 0)
84     {
85         targets_act(0);
86     }
87     else
88     {
89         if (!hosts_list->isEmpty() && t-1 <= hosts_list->count())
90         {
91             QString status = "Sent wakeup packet to ";
92             status.append(hosts_list->at(t-1).hostname);
93             target->set_mac(hosts_list->at(t-1).mac);
94             target->set_ip(hosts_list->at(t-1).ip);
95             target->wake_me();
96             status_lbl->setText(status);
97             status_timer->singleShot(5000, this, SLOT(reset_status()));
98         }
99     }
100 }
101
102 void Woller::reset_status()
103 {
104     status_lbl->setText(*status_orig);
105 }
106
107 void Woller::targets_act(int i)
108 {
109     if (i == 0)
110     {
111         // build the config widget
112         qDebug() << "building the config" << endl;
113         config_win = new ConfigWidget(0, hosts_list);
114         config_win->setWindowModality(Qt::ApplicationModal);
115         connect(config_win, SIGNAL(hosts_changed()), this, SLOT(hosts_changed()));
116         config_win->show();
117     }
118     else
119     {
120         qDebug() << "targets: " << targets_cb->currentText() << endl;
121     }
122 }
123
124 void Woller::add_new(host_s *host)
125 {
126     qDebug() << "add_new:" << host->hostname << host->ip << host->mac << endl;
127 }
128
129 void Woller::do_list()
130 {
131     qDebug() << "do_list" << endl;
132     //populate CB
133     targets_cb->clear();
134     targets_cb->addItem(tr("Configure Targets"));
135     for (int i = 0; i < hosts_list->size(); ++i) {
136         targets_cb->addItem(hosts_list->at(i).hostname);
137      }
138 }
139
140 void Woller::hosts_changed()
141 {
142     qDebug() << "hosts_changed" << endl;
143     do_list();
144     save_config();
145 }
146
147 void Woller::save_config()
148 {
149     qDebug() << "save config" << endl;
150     settings->beginWriteArray("targets");
151     for (int i = 0; i < hosts_list->count(); ++i) {
152         settings->setArrayIndex(i);
153         settings->setValue("hostname", hosts_list->at(i).hostname);
154         settings->setValue("ip", hosts_list->at(i).ip.toString().toAscii());
155         settings->setValue("mac", hosts_list->at(i).mac.toAscii());
156      }
157     settings->endArray();
158 }
159
160 void Woller::load_config()
161 {
162     host_s host;
163     qDebug() << "loading config" << endl;
164     int size = settings->beginReadArray("targets");
165     for (int i = 0; i < size; ++i) {
166         settings->setArrayIndex(i);
167         host.hostname = settings->value("hostname").toString();
168         host.ip.setAddress(settings->value("ip").toString());
169         host.mac = settings->value("mac").toString();
170         hosts_list->append(host);
171     }
172     settings->endArray();
173
174     move(settings->value("position", QPoint(200, 200)).toPoint());
175
176     do_list();
177
178     targets_cb->setCurrentIndex(settings->value("last selected", 0).toInt());
179 }
180
181
182 ConfigWidget::ConfigWidget(QWidget *parent, QList<host_s> *hosts)
183         : QWidget(parent)
184 {
185     qDebug() << "ConfigWidget" << endl;
186     hosts_list = hosts;
187
188     //add buttons and the list
189     this->setWindowTitle(tr("Woller Config"));
190     add_host = new QPushButton(tr("&Add Host"), this);
191     edit_host = new QPushButton(tr("&Edit Host"), this);
192     del_host = new QPushButton(tr("&Delete Host"), this);
193     save_btn = new QPushButton(tr("&Save"), this);
194     close_btn = new QPushButton(tr("&Close"), this);
195     list = new QListWidget(this);
196     button_layout = new QVBoxLayout();
197     layout = new QHBoxLayout();
198     button_layout->addWidget(add_host);
199     button_layout->addWidget(edit_host);
200     button_layout->addWidget(del_host);
201     button_layout->addWidget(save_btn);
202     button_layout->addWidget(close_btn);
203     layout->addWidget(list);
204     layout->addLayout(button_layout);
205     this->setLayout(layout);
206     close_btn->setDefault(true);
207     edit_host->setDisabled(true);
208     del_host->setDisabled(true);
209     save_btn->setDisabled(true);
210
211     connect(add_host, SIGNAL(clicked()), this, SLOT(add_sig()));
212     connect(edit_host, SIGNAL(clicked()), this, SLOT(edit_sig()));
213     connect(del_host, SIGNAL(clicked()), this, SLOT(del_sig()));
214     connect(save_btn, SIGNAL(clicked()), this, SLOT(save_sig()));
215     connect(close_btn, SIGNAL(clicked()), this, SLOT(close_sig()));
216     connect(list, SIGNAL(itemClicked(QListWidgetItem *)), this,
217             SLOT(select_sig()));
218     connect(list, SIGNAL(itemActivated(QListWidgetItem *)), this,
219             SLOT(edit_sig()));
220
221     for (int i = 0; i < hosts_list->size(); ++i) {
222         list->addItem(hosts_list->at(i).hostname);
223      }
224 }
225
226 ConfigWidget::~ConfigWidget()
227 {
228     delete add_host;
229     delete edit_host;
230     delete del_host;
231     delete save_btn;
232     delete close_btn;
233     delete list;
234     delete button_layout;
235     delete layout;
236 }
237
238
239 void ConfigWidget::add_sig()
240 {
241     qDebug() << "conf add" << endl;
242     host_tmp.hostname.clear();
243     host_tmp.mac.clear();
244     host_tmp.ip.clear();
245     host_widget = new HostWidget(0, &host_tmp);
246
247     host_widget->setWindowModality(Qt::ApplicationModal);
248     connect(host_widget, SIGNAL(change_host()), this, SLOT(host_added()));
249     host_widget->show();
250     qDebug() << "conf add - exit" << endl;
251
252 }
253
254 void ConfigWidget::edit_sig()
255 {
256     qDebug() << "conf edit" << endl;
257     host_tmp.hostname = hosts_list->at(list->currentIndex().row()).hostname;
258     host_tmp.mac = hosts_list->at(list->currentIndex().row()).mac;
259     host_tmp.ip = hosts_list->at(list->currentIndex().row()).ip;
260     host_widget = new HostWidget(0, &host_tmp);
261     connect(host_widget, SIGNAL(change_host()), this, SLOT(host_edited()));
262
263     host_widget->setWindowModality(Qt::ApplicationModal);
264     //hostWidget->hostname->setPlaceholderText("my_host_name");
265     //hostWidget->hostname->setText("edit1");
266     //hostWidget->mac->setPlaceholderText("001133aabbcc");
267     //hostWidget->mac->setText("001133aabbcc");
268     //hostWidget->ip->setPlaceholderText("10.10.11.255");
269     host_widget->show();
270 }
271
272 void ConfigWidget::del_sig()
273 {
274     QMessageBox msg_box;
275     int ret, i = list->currentIndex().row();
276     qDebug() << "conf del: " << i << endl;
277
278     msg_box.setText("Host is to be deleted.");
279     msg_box.setInformativeText("Do you want to save your changes?");
280     msg_box.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
281     msg_box.setDefaultButton(QMessageBox::Save);
282     ret = msg_box.exec();
283
284     if ( ret ==  QMessageBox::Save ) {
285         hosts_list->removeAt(i);
286         list->takeItem(i);
287         emit hosts_changed();
288     }
289 }
290
291 void ConfigWidget::save_sig()
292 {
293     qDebug() << "conf save" << endl;
294     emit hosts_changed();
295     save_btn->setDisabled(true);
296 }
297
298 void ConfigWidget::close_sig()
299 {
300     qDebug() << "conf close" << endl;
301     this->close();
302 }
303
304 void ConfigWidget::select_sig()
305 {
306     qDebug() << "conf sel: " << endl;
307     edit_host->setDisabled(false);
308     del_host->setDisabled(false);
309 }
310
311 void ConfigWidget::host_added()
312 {
313     qDebug() << "host changed" << endl;
314     list->addItem(host_tmp.hostname);
315     qDebug() << "hostsList size:" << hosts_list->size()
316         << "count:" << hosts_list->size() << endl;
317     hosts_list->append(host_tmp);
318     qDebug() << "hostsList size:" << hosts_list->size()
319         << "count:" << hosts_list->size() << endl;
320     save_btn->setDisabled(false);
321     save_btn->setDefault(true);
322 }
323
324 void ConfigWidget::host_edited()
325 {
326     int i = list->currentIndex().row();
327     qDebug() << "host edited: " << i << endl;
328
329     hosts_list->replace(i, host_tmp);
330     list->takeItem(i);
331     list->insertItem(i, hosts_list->at(i).hostname);
332     save_btn->setDisabled(false);
333     save_btn->setDefault(true);
334 }
335
336 HostWidget::HostWidget(QWidget *parent, host_s *host)
337         : QWidget(parent)
338 {
339     //TODO: add setValidator and use QRegExpValidator
340
341     qDebug() << "host widget" << endl;
342     new_host = host;
343     this->setWindowTitle("Add new WOL target host");
344     vlayout = new QVBoxLayout(this);
345
346     host_row = new QHBoxLayout;
347     host_lbl = new QLabel(tr("Hostname:"), this);
348     hostname = new QLineEdit(host->hostname, this);
349     hostname->setToolTip(tr("Give target computer's hostname"));
350     host_row->addWidget(host_lbl);
351     host_row->addWidget(hostname);
352     vlayout->addLayout(host_row);
353
354     mac_row = new QHBoxLayout;
355     mac_lbl = new QLabel(tr("Mac:"), this);
356     mac = new QLineEdit(host->mac, this);
357     mac->setToolTip(
358             tr("HW address of target, e.g. 00:01:02:AA:BB:CC. "
359                "Hint, in Linux/Unix: \"ifconfig\","
360                "in Windows \"ipconfig /all\""));
361     mac->setInputMask("HH:HH:HH:HH:HH:HH;0");
362     mac_row->addWidget(mac_lbl);
363     mac_row->addWidget(mac);
364     vlayout->addLayout(mac_row);
365
366     ip_row = new QHBoxLayout;
367     ip_lbl = new QLabel(tr("Bcast ip:"), this);
368     ip = new QLineEdit(host->ip.toString(), this);
369     ip->setToolTip(
370             tr("Use ip broadcast address if you want to wake up target outside"
371                "of local network, or if you have several network interfaces."
372                "E.g. 192.168.1.255. You may leave this empty if unsure."));
373     ip->setMaxLength(MAX_IP_LEN);
374     ip_row->addWidget(ip_lbl);
375     ip_row->addWidget(ip);
376     vlayout->addLayout(ip_row);
377
378     button_row = new QHBoxLayout;
379     cancel = new QPushButton(tr("&Cancel"), this);
380     button_row->addWidget(cancel);
381     ok = new QPushButton(tr("&Ok"), this);
382     ok->setDefault(true);
383     button_row->addWidget(ok);
384     vlayout->addLayout(button_row);
385
386     this->setLayout(vlayout);
387
388     ok->setDefault(true);
389
390     connect(ok, SIGNAL(clicked()), this, SLOT(ok_sig()));
391     connect(cancel, SIGNAL(clicked()), this, SLOT(cancel_sig()));
392
393 }
394
395 void HostWidget::cancel_sig()
396 {
397     qDebug() << "host cancel" << endl;
398     this->close();
399 }
400
401 void HostWidget::ok_sig()
402 {
403     qDebug() << "host ok" << this->hostname->text() << this->mac->text()
404             << this->ip->text() << endl;
405
406     new_host->hostname = this->hostname->text();
407     if (new_host->hostname.isEmpty())
408     {
409         QMessageBox msgBox;
410         msgBox.setText("You must set hostname!");
411         msgBox.exec();
412         return;
413     }
414     new_host->mac= this->mac->text();
415     if (new_host->mac.isEmpty())
416     {
417         QMessageBox msgBox;
418         msgBox.setText("You must set mac!");
419         msgBox.exec();
420         return;
421     }
422     new_host->ip = this->ip->text();
423     emit change_host();
424
425     qDebug() << "host ok" << new_host->hostname << new_host->mac
426             << new_host->ip << endl;
427
428     this->close();
429 }
430
431 HostWidget::~HostWidget()
432 {
433     qDebug() << "host ~widget" << endl;
434     delete vlayout;
435     delete host_row;
436     delete host_lbl;
437     delete hostname;
438     delete mac_row;
439     delete mac_lbl;
440     delete mac;
441     delete ip_row;
442     delete ip_lbl;
443     delete ip;
444     delete button_row;
445     delete cancel;
446     delete ok;
447     //delete new_host;
448 }
449
450
451 int wol_target::get_mac( QString *gmac)
452 {
453     if (!gmac)
454         return -1;
455     *gmac = *mac;
456     return 0;
457 }
458
459 int wol_target::set_mac( const QString smac )
460 {
461     if (smac.size() != MAX_MAC_LEN) {
462         qDebug() << "set mac mac size:" << smac.size() << smac << endl;
463         //return -1;
464     }
465     *mac = smac;
466     qDebug() << "set mac mac:" << mac;
467     return 0;
468 }
469
470 int wol_target::get_ip( QHostAddress *gip)
471 {
472     if (!gip)
473         return -1;
474     *gip = *ip;
475     return 0;
476 }
477
478 int wol_target::set_ip( const QHostAddress sip )
479 {
480     if (sip.isNull())
481         return -1;
482     *ip = sip;
483     return 0;
484 }
485
486
487 wol_target::wol_target()
488 {
489     mac = new QString;
490     ip = new QHostAddress;
491     magic_pkt = new QByteArray;
492 }
493
494 wol_target::~wol_target()
495 {
496     delete mac;
497     delete ip;
498     delete magic_pkt;
499 }
500
501 int wol_target::create_magic_pkt(const QString *mac)
502 {
503     const char magic_header[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
504     qDebug() << "create magic pkt" << endl;
505     if (mac->size() != MAX_MAC_LEN)
506     {
507         qDebug() << "create magic pkt size:" << mac->size() << endl;
508         //return -1;
509     }
510     *magic_pkt = QByteArray::fromRawData(magic_header, sizeof(magic_header));
511     for (int i=0; i < WOL_MAGIC_MAC_CNT; i++)
512         magic_pkt->append(QByteArray::fromHex(mac->toAscii()));
513     return 0;
514 }
515
516 int wol_target::wake_me()
517 {
518     QUdpSocket udpSocket;
519
520     if (mac->isEmpty()) {
521         qDebug() << "wakeme: no mac set" << endl;
522         return -1;
523     }
524     create_magic_pkt(mac);
525     qDebug() << "magic:" << endl;
526     qDebug() << magic_pkt->toHex() << endl ;
527
528     if (ip->isNull()) {
529         qDebug() << "sending broadcast to mac" << *mac << endl;
530         udpSocket.writeDatagram(magic_pkt->data(), magic_pkt->size(),
531                                 QHostAddress::Broadcast,
532                                 WOL_MAGIC_UDP_PORT);
533     }
534     else {
535         qDebug() << "sending with ip" << *ip << endl;
536         udpSocket.writeDatagram(magic_pkt->data(), magic_pkt->size(),
537                                 *ip,
538                                 WOL_MAGIC_UDP_PORT);
539     }
540     return 0;
541 }
542