Move layout code into separate ui file. Compile layout using uic
[vlp.git] / src / kernel / kernel.cpp
1 /**************************************************************
2
3   Copyright (C) 1997  Oskar Swida
4
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU General Public License
7  as published by the Free Software Foundation; either version 2
8  of the License, or (at your option) any later version.
9
10  This program 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 this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19
20
21
22  NOTE: This software is using the free software license of 
23        the QT library v.1.30 from Troll Tech AS.
24        See the file LICENSE.QT.
25
26  
27   To contact the author, write:
28      e-mail: swida@aragorn.pb.bialystok.pl
29
30 ************************************************************/
31
32
33 #include <QtGui/QApplication>
34 #include <QtGui/QMainWindow>
35 #include <QtGui/QTextEdit>
36 #include <QtGui/QMenuBar>
37 #include <QtGui/QMessageBox>
38 #include <QtGui/QFileDialog>
39 #include <QtGui/QDialog>
40 #include <QtCore/QString>
41 #include <QtGui/QLabel>
42 #include <QtGui/QLineEdit>
43 #include <QtGui/QPushButton>
44 #include <QtGui/QRadioButton>
45 #include <QtGui/QGroupBox>
46 #include <QtGui/QVBoxLayout>
47 #include <QtCore/QList>
48 #include <QtGui/QListWidget>
49 #include <qfile.h>
50 #include <qcursor.h>
51 #include <QtCore/QSocketNotifier>
52 #include <QtGui/QCloseEvent>
53 #include <qdir.h>
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <unistd.h>
58 #include <fcntl.h>
59
60 #include "genint1.h"
61 #include "socu.h"
62 #include <netinet/in.h>
63
64 #include <libconfig.h>
65
66 #include "kernel.h"
67 #include "kernelwindow.h"
68
69 /* File resides in top directory (where are Makefiles)*/
70 #include "../../config.h"
71
72
73 char CharLine[25] = "________________________";
74 char myargs[5][255];
75
76 //QApplication *app;
77
78 /**
79  * Event invoked on program close.
80  * Closes application. Displays additional window to confirm exit.
81  */
82 void QKernel::closeEvent(QCloseEvent * e)
83 {
84         e->ignore();
85
86         if (!LOCKED) {
87                 on_actionQuit_triggered();
88         }
89 }
90
91 void QKernel::setLocked(bool locked)
92 {
93         LOCKED = locked;
94
95         actionQuit->setDisabled(locked);
96
97         actionExecute->setDisabled(locked);
98         actionKill->setDisabled(locked);
99         actionMessage->setDisabled(locked);
100         actionConnect->setDisabled(locked);
101         actionDisconnect->setDisabled(locked);
102         actionInfo->setDisabled(locked);
103
104
105         /* Enable only menu entry for unlocking */
106         actionEditor->setDisabled(locked);
107         actionOptions->setDisabled(locked);
108         actionLock_console->setDisabled(locked);
109         actionUnlock_console->setDisabled(!locked);
110 }
111
112 /**
113  * Kernel program constructor.
114  * Prepares everything to work.
115  */
116 QKernel::QKernel()
117 {
118         setupUi(this);
119
120         QDir q(REMOTE_PATH);
121         char ss[255];
122
123         if (!q.exists()) {
124                 sprintf(ss, "mkdir %s", REMOTE_PATH);
125                 system(ss);
126         } 
127
128         info_messages = TRUE;
129         wait_for_info = FALSE;
130
131         setWindowTitle(PACKAGE_NAME);
132
133         LOCKED = FALSE;
134
135         desktop = new QTextEdit(this);
136         desktop->setReadOnly(TRUE);
137         QVBoxLayout * layout = new QVBoxLayout();
138         layout->setContentsMargins (3, 0, 3, 0);
139         layout->addWidget(desktop);
140         QWidget *window = new QWidget();
141         window->setLayout(layout);
142         setCentralWidget(window);
143
144         resize(400, 200);
145         Tasks = 0;
146         freeINTid = 1;
147         ActiveConnections = 0;
148         strcpy(LockPasswd, "");
149         LoadConfig("vlp.cfg");
150         RunNetModule();
151
152         Net_Notify = new QSocketNotifier(net_sock, QSocketNotifier::Read, this);
153         connect(Net_Notify, SIGNAL(activated(int)), this, SLOT(NetMessage()));
154 }
155
156 /**
157  * Event invoked on resizing kernel application window.
158  * @copydoc QWidget::resizeEvent(QResizeEvent*)
159  */
160 void QKernel::resizeEvent(QResizeEvent *ev)
161 {
162 //      QFrame::resizeEvent(ev);
163 //      if (desktop)
164 //              desktop->setGeometry(0, bar->height(), width(), 
165 //                                              height() - bar->height());
166 }
167
168 /**
169  * Displays window with information about not implemented functionality.
170  */
171 void QKernel::n_impl()
172 {
173         QMessageBox::information(this, "Function info", "This function is not "
174                                                 "implemented yet...", "Ok");
175 }
176
177 /**
178  * Loads configuration from the given file.
179  * @param fname Filename of the configuration file.
180  */
181 void QKernel::LoadConfig(char * fname)
182 {
183         config_t cfg;
184         config_setting_t *setting;
185         const char *str;
186
187         /* Hack for checking if file exists without using external libs.*/
188         FILE * file = fopen(fname, "rt");
189         if (!file) {
190                 fprintf(stderr, "Error: Cannot load configuration file %s!\n", 
191                                                                         fname);
192                 exit(3);
193         }
194         /* File exists, so file has been locked. Release it. */
195
196         config_init(&cfg);
197
198         /* Read the file. If there is an error, report it and exit. */
199         if (!config_read(&cfg, file)) {
200                 fprintf(stderr, "%s! In file %s, line %d\n", 
201                         config_error_text(&cfg), 
202                         config_error_file(&cfg), 
203                         config_error_line(&cfg));
204                 config_destroy(&cfg);
205                 fclose(file);
206                 exit(3);
207         }
208
209         setting = config_lookup(&cfg, "node_number");
210         if (setting) {
211                 NodeNumber = config_setting_get_int(setting);
212         } else {
213                 fprintf(stderr, "%s! In file %s, '%s' was not found.\n", 
214                                         "Warning", fname, "node_number");
215                 config_destroy(&cfg);
216                 fclose(file);
217                 exit(3);
218         }
219
220         setting = config_lookup(&cfg, "type");
221         if (setting) {
222                 /* same as strcmp(..) == 0 */
223                 if (!strcmp(config_setting_get_string(setting), "explicit")) {
224                         ConType = 1;
225                 } else {
226                         ConType = 2;
227                 }
228         } else {
229                 fprintf(stderr, "%s! In file %s, '%s' was not found.\n", 
230                                                 "Warning", fname, "type");
231         }
232
233         setting = config_lookup(&cfg, "host");
234         if (setting) {
235                 switch(config_setting_type(setting)) {
236                 /* TODO: Deprecated. Made for back compatibility. */
237                 case CONFIG_TYPE_STRING:
238                         ConnectList.append(new ConnectEntry((char*)
239                                         config_setting_get_string(setting)));
240                         break;
241                 case CONFIG_TYPE_ARRAY: {
242                         int size = config_setting_length(setting);
243                         for (int i = 0; i < size; i++) {
244                                 ConnectList.append(new ConnectEntry((char*)
245                                         config_setting_get_string_elem(setting,
246                                                                         i)));
247                         }
248                         break;
249                 }
250                 default:
251                         fprintf(stderr, "%s! In file %s, bad entry type for %s."
252                                                         " Will not be read.\n", 
253                                                         "Error", fname, "host");
254                 }
255         } else {
256                 fprintf(stderr, "%s! In file %s, '%s' was not found.\n", 
257                                                 "Warning", fname, "host");
258         }
259
260         setting = config_lookup(&cfg, "progdir");
261         if (setting){
262                 strncpy(progdir, config_setting_get_string(setting), 256);
263         } else {
264                 fprintf(stderr, "%s! In file %s, '%s' was not found.\n", 
265                                                 "Warning", fname, "progdir");
266         }
267
268         setting = config_lookup(&cfg, "homedir");
269         if (setting) {
270                 strncpy(HomeDir, config_setting_get_string(setting), 255);
271         } else {
272                 fprintf(stderr, "%s! In file %s, '%s' was not found.\n", 
273                                                 "Warning", fname, "homedir");
274         }
275
276         config_destroy(&cfg);
277         fclose(file);
278 }
279
280 /**
281  * Executes program.
282  * Additional window id displayed to set which code to execute.
283  */
284 void QKernel::on_actionExecute_triggered()
285 {
286         int i;
287         QString s = QFileDialog::getOpenFileName(this, "Execute", progdir, "*.log");
288
289         if (!s.isNull()) {
290                 i = s.indexOf(".log");
291
292                 if (i > 0)
293                         s.remove(i, 4);
294
295                 RunIntModule((char*)s.toAscii().data(), 0);
296         }
297 }
298
299 /**
300  * Invokes editor program
301  */
302 void QKernel::on_actionEditor_triggered()
303 {
304         char cmd[255];
305         sprintf(cmd, "%s/modules/logedit %s %s %s %s %s %s &", HomeDir, HomeDir, 
306                         myargs[0], myargs[1], myargs[2], myargs[3], myargs[4]);
307         system(cmd);
308 }
309
310 /**
311  * Invokes help program
312  */
313 void QKernel::on_actionHelp_triggered()
314 {
315         char cmd[255];
316         sprintf(cmd, "%s/modules/loghelp %s/doc %s %s %s %s %s &", HomeDir,
317                 HomeDir, myargs[0], myargs[1], myargs[2], myargs[3], myargs[4]);
318         system(cmd);
319 }
320
321 /**
322  * Invokes graphics module
323  */
324 void QKernel::RunGraphModule(char *sk)
325 {
326         char cmd[255];
327
328         sprintf(cmd, "%s/modules/loggraph %s %s %s %s %s %s &", HomeDir,
329                 sk, myargs[0], myargs[1], myargs[2], myargs[3], myargs[4]);
330
331         if (system(cmd) != 0)
332                 WriteMessage("Cannot connect GRAPH resources");
333 }
334
335 /**
336  * Invokes net module
337  */
338 void QKernel::RunNetModule()
339 {
340         struct sockaddr_un svr;
341         int len, on;
342         int sock;
343         char cmd[255];
344         sprintf(cmd, "%s/modules/lognet %s %s %s %s %s %s &", HomeDir,
345                 NPATH, myargs[0], myargs[1], myargs[2], myargs[3], myargs[4]);
346
347         /* -------- socket for NET module -------- */
348         unlink(NPATH);
349         sock = socket(AF_UNIX, SOCK_STREAM, 0);
350         bzero(&svr, sizeof(svr));
351         svr.sun_family = AF_UNIX;
352         strcpy(svr.sun_path, NPATH);
353         len = strlen(svr.sun_path) + sizeof(svr.sun_family);
354         bind(sock, (struct sockaddr*)&svr, len);      
355         listen(sock, 5);
356
357         if (system(cmd) == 0) {
358                 net_sock = accept(sock, (struct sockaddr*)0, (unsigned int*)0);
359                 // close(sock); 
360                 if (net_sock != 0) {
361                         WriteMessage("NETWORK successfully connected");
362                         fcntl(net_sock, F_SETFL, O_NONBLOCK|fcntl(net_sock,
363                                                                 F_GETFL, 0));
364                         on=1;
365                         setsockopt(net_sock, IPPROTO_TCP, TCP_NODELAY,
366                                                         (char*)&on, sizeof(on)); 
367                 } else {
368                         WriteMessage("Cannot connect NETWORK resources");
369                         WriteMessage("Exiting...");
370                         sleep(2);
371                         on_actionQuit_triggered();
372                 }
373         /* system OK */
374         } else {
375                 WriteMessage("Cannot connect NETWORK resources");
376                 WriteMessage("Exiting...");
377                 sleep(2);
378                 on_actionQuit_triggered();
379         }
380 }
381
382 /**
383  * Connects to the specified address
384  * Additional window is displayed to connect to the specified address
385  */
386 void QKernel::on_actionConnect_triggered()
387 {
388         QDialog d(this, Qt::Dialog);
389         QLabel lab("IP Address:", &d);
390         QLineEdit ed("", &d);
391         QPushButton ob("", &d);
392         QPushButton cb("", &d);
393         MESSAGE m;
394
395         ob.setGeometry(30, 60, 80, 30);
396         ob.setText("Ok");
397         ob.setDefault(TRUE);
398         lab.setGeometry(10, 10, 60, 30);
399         lab.setText("Address");
400         ed.setGeometry(70, 10, 140, 30);
401         cb.setGeometry(130, 60, 80, 30);
402         cb.setText("Cancel");
403         d.resize(240, 100);
404
405         connect(&ob, SIGNAL(clicked()), &d, SLOT(accept()));
406         connect(&cb, SIGNAL(clicked()), &d, SLOT(reject()));
407         if (d.exec()) {
408                 m.msg_type = MSG_NET;
409                 m.param.pword[0] = NET_CONNECT_TO;
410                 strcpy(m.param.pstr, ed.text().toAscii().data());
411                 write(net_sock, &m, sizeof(MESSAGE)); 
412         }
413 }
414
415 /**
416  * Disconnects from virtual machine
417  */
418 void QKernel::on_actionDisconnect_triggered()
419 {
420         MESSAGE msg;
421
422         if (info_messages)
423                 WriteMessage("Disconnecting from virtual machine");
424
425         msg.msg_type = MSG_NET;
426         msg.param.pword[0] = NET_DISCONNECT;
427         write(net_sock, &msg, sizeof(MESSAGE));
428 }
429
430 /**
431  * Quits process. Closes VLP. Shows additional window to confirm exit. 
432  */
433 void QKernel::on_actionQuit_triggered()
434 {
435         MESSAGE msg;
436
437         QMessageBox::StandardButton response;
438         response = QMessageBox::question(this, "Close VLP", "Terminate VLP ?",
439                 QMessageBox::Ok | QMessageBox::Cancel);
440
441
442         if (response == QMessageBox::Cancel) {
443                 return;
444         }
445         /*
446         msg.msg_type = MSG_NET;
447         msg.param.pword[0] = NET_DISCONNECT;
448         write(net_sock, &msg, sizeof(MESSAGE));*/
449         delete Net_Notify;
450
451         msg.msg_type = MSG_NET;
452         msg.param.pword[0] = NET_EXIT;
453         write(net_sock, &msg, sizeof(MESSAGE));
454         /*  ::close(net_sock);*/
455         QApplication::instance()->quit();
456 }
457
458 /**
459  * Adds IP address to the configuration.
460  * Additional window is displayed to add address to the list
461  */
462 void QKernel::AddAddress()
463 {
464         QDialog d(this, Qt::Dialog);
465         QLabel lab("IP Address:", &d);
466         QLineEdit ed("", &d);
467         QPushButton ob("", &d);
468         QPushButton cb("", &d);
469
470         if (connections) {
471                 ob.setGeometry(30, 60, 80, 30);
472                 ob.setText("Ok");
473                 ob.setDefault(TRUE);
474                 lab.setGeometry(10, 10, 60, 30);
475                 lab.setText("Address");
476                 ed.setGeometry(70, 10, 140, 30);
477                 cb.setGeometry(130, 60, 80, 30);
478                 cb.setText("Cancel");
479                 d.resize(240, 100);
480                 connect(&ob, SIGNAL(clicked()), &d, SLOT(accept()));
481                 connect(&cb, SIGNAL(clicked()), &d, SLOT(reject())); 
482                 if (d.exec())
483                         if (strcmp(ed.text().toAscii().data(), "") != 0) {
484                                 connections->addItem(ed.text());
485                         }
486         }
487 }
488
489 /**
490  * Deletes current address from available connections.
491  */
492 void QKernel::DelAddress()
493 {
494         if (connections) {
495                 if (connections->currentRow() != -1) {
496                         /* TODO: Checki if this work correctly after porting */
497                         connections->removeItemWidget(connections->currentItem());
498                 }
499         }
500 }
501
502 /**
503  * Sends message to node.
504  * Additional window is displayed to set Node Number of node where send message,
505  * and textfield to enter message.
506  */
507 void QKernel::on_actionMessage_triggered()
508 {
509         QDialog *dlg;
510         QLineEdit *nodenr;
511         MESSAGE m;
512
513         dlg = new QDialog(this, Qt::Dialog);
514         dlg->setWindowTitle("Send message to node");
515
516         nodenr = new QLineEdit("number", dlg);
517         nodenr->setGeometry(90, 10, 50, 30);
518         nodenr->setText("");
519
520         QLabel *tmpQLabel;
521         tmpQLabel = new QLabel("Node number:", dlg);
522         tmpQLabel->setGeometry(10, 10, 77, 30);
523
524         tmpQLabel = new QLabel("Message:", dlg);
525         tmpQLabel->setGeometry(10, 50, 70, 30);
526
527         QLineEdit *msg;
528         msg = new QLineEdit("", dlg);
529         msg->setGeometry(80, 60, 330, 30);
530
531         QPushButton *ob;
532         ob = new QPushButton("Send", dlg);
533         ob->setGeometry(230, 10, 80, 30);
534         ob->setDefault(TRUE);
535         
536         QPushButton *cb;
537         cb = new QPushButton("Cancel", dlg);
538         cb->setGeometry(330, 10, 80, 30);
539         dlg->resize(430, 110);
540         connect(ob, SIGNAL(clicked()), dlg, SLOT(accept()));
541         connect(cb, SIGNAL(clicked()), dlg, SLOT(reject()));
542
543         if (dlg->exec()) {
544                 m.msg_type = MSG_NET;
545                 m.param.pword[0] = NET_PROPAGATE;
546                 m.param.pword[1] = MSG_VLP;
547                 m.param.pword[2] = NodeNumber;
548                 m.param.pword[4] = atoi(nodenr->text().toAscii().data());
549                 m.param.pword[6] = VLP_WRITE;
550                 strcpy(m.param.pstr, msg->text().toAscii().data());
551                 write(net_sock, &m, sizeof(MESSAGE));
552         }
553 }
554
555 /**
556  * Kills interpreter.
557  * Additional window is displayed to get ID of interpreter which should be
558  * killed.
559  */
560 void QKernel::on_actionKill_triggered()
561 {
562         QDialog *dlg;
563         QLineEdit *nodenr;
564         MESSAGE m;
565         InterpEntry *pom;
566
567         dlg = new QDialog(this, Qt::Dialog);
568         dlg->setWindowTitle("Kill interpreter");
569
570         nodenr = new QLineEdit("", dlg); 
571         nodenr->setGeometry(90, 10, 50, 30);
572
573         QLabel * tmpQLabel = new QLabel("Interp. ID:", dlg);
574         tmpQLabel->setGeometry(10, 10, 77, 30);
575
576         QPushButton * ob = new QPushButton("Kill", dlg);
577         ob->setGeometry( 160, 10, 80, 30);
578         ob->setDefault(TRUE);
579
580         QPushButton * cb = new QPushButton("Cancel", dlg);
581         cb->setGeometry(260, 10, 80, 30);
582         dlg->resize(360, 50);
583
584         connect(ob, SIGNAL(clicked()), dlg, SLOT(accept()));
585         connect(cb, SIGNAL(clicked()), dlg, SLOT(reject())); 
586
587         if (dlg->exec()) {
588                 m.msg_type = MSG_INT;
589                 m.param.pword[0] = INT_KILL;
590                 pom = findINTbyID(atoi(nodenr->text().toAscii().data()));
591                 if (pom != NULL) {
592                         if (!(pom->remote))
593                                 write(pom->sock, &m, sizeof(MESSAGE));
594                         else
595                                 WriteMessage("This is a remote instance of "
596                                                                 "a program!");
597                 }
598                 else {
599                         WriteMessage("Interpreter not found");
600                 }
601         }
602 }
603
604 /**
605  * Sends message to the net module.
606  */
607 void QKernel::NetMessage()
608 {
609         
610         /* TODO: It has to be rewritten */
611         MESSAGE msg;
612         int cnt;
613         char ss[255];
614         InterpEntry *pom;
615
616         cnt = read(net_sock, &msg, sizeof(MESSAGE));
617         if ((cnt > 0) && (msg.msg_type == MSG_NET)) {
618                 switch(msg.param.pword[0]) {
619                 case NET_CSWRITELN:
620                         WriteMessage(msg.param.pstr);
621                         break;
622                 case NET_PROPAGATE: 
623                         switch(msg.param.pword[1]) {
624                         case MSG_INT:
625                                 /*  pom = find_link_by_ID(msg.param.pword[5]);
626                                 msg.msg_type = MSG_NET;
627                                 msg.param.pword[0] = NET_PROPAGATE;
628                                 send_int(pom, &msg);*/
629                                 break;
630                         case MSG_VLP:
631                                 switch(msg.param.pword[6]) {
632                                 case VLP_WRITE:
633                                         QApplication::beep();
634                                         WriteMessage(CharLine);
635                                         WriteMessage(
636                                                 "### Incoming Messsage ###");
637                                         sprintf(ss, "Mesg from Node %d: %s",
638                                                         msg.param.pword[2],
639                                                         msg.param.pstr);
640                                         WriteMessage(ss);
641                                         WriteMessage(CharLine);
642                                         break;
643                                 case VLP_REMOTE_INSTANCE:
644                                         sprintf(ss, "%s/%s", REMOTE_PATH,
645                                                                 msg.param.pstr);
646
647                                         if (info_messages) { 
648                                                 WriteMessage("Running program:");
649                                                 WriteMessage(ss);
650                                         }
651                                         pom = RunIntModule(ss, 1);
652                                         if (pom != NULL) {
653                                                 pom->p_ctx.node = msg.param.pword[2];
654                                                 pom->p_ctx.program_id = 
655                                                         msg.param.pword[7];
656                                                 pom->RInstances[msg.param.pword[2]] = msg.param.pword[7];
657                                         }
658                                         break;
659                                 case VLP_CLOSE_INSTANCE:
660                                         msg.msg_type = MSG_INT;
661                                         msg.param.pword[0] = INT_CLOSE_INSTANCE;
662                                         pom = findINTbyID(msg.param.pword[7]);
663                                         if (pom != NULL) {
664                                                 write(pom->sock, &msg,
665                                                         sizeof(MESSAGE));
666                                                 MESSAGE m1;
667                                                 m1.msg_type = MSG_VLP;
668                                                 m1.param.pword[0] = VLP_INTERPRETER_DOWN;
669                                                 m1.param.pword[1] = pom->ID;
670                                                 write(net_sock, &m1,
671                                                         sizeof(MESSAGE));
672                                         } else {
673                                                 WriteMessage("Instance not found"); 
674                                         }
675                                         break; 
676                                 } /* VLP switch */
677                         }/* switch */
678                         break;
679                 case NET_CONNECTIONS:
680                         ActiveConnections = msg.param.pword[1];
681                         WriteMessage(msg.param.pstr);
682                         if (!synchro) 
683                                 synchro = TRUE;
684                         break;
685                 case NET_INFO:
686                         /* TODO: It has to be rewritten */
687                         if (wait_for_info) {
688                                 QString poms, poms1, poms2;
689                                 poms.sprintf("%s", msg.param.pstr);
690                                 while (poms.length() > 0) {
691                                         cnt = poms.indexOf(';');
692                                         if (cnt!=-1) {
693                                                 poms1 = poms.left(cnt);
694                                                 poms = poms.right(poms.length() - cnt - 1);
695                                                 cnt = poms1.indexOf('=');
696                                                 if (cnt != -1) {
697                                                         poms2 = poms1.left(cnt);
698                                                         poms1 = poms1.right(
699                                                                 poms1.length() -
700                                                                 cnt - 1);
701                                                         sprintf(ss, "Node: %s Addr: %s", poms2.data(), poms1.data());
702                                                         WriteMessage(ss); 
703                                                 }
704                                         } 
705                                 }
706                         } 
707                         break;
708                 case NET_INFO_END:
709                         wait_for_info = FALSE;
710                         WriteMessage(CharLine);
711                         break;
712                 } /* switch */
713         }
714 }
715
716 /**
717  * Sends message to the interpreter program.
718  * @param sock Interpreter socket to whom the message will be send.
719  */
720 void QKernel::IntMessage(int sock)
721 {
722         MESSAGE msg;
723         int cnt;
724         InterpEntry *e;
725
726         cnt = read(sock, &msg, sizeof(MESSAGE));
727         e = findINTbySocket(sock);
728         if ((cnt > 0) && (e != NULL)) {
729                 switch (msg.msg_type) { 
730                 case MSG_GRAPH:
731                         if (msg.param.pword[0] == GRAPH_ALLOCATE) {
732                                 RunGraphModule(msg.param.pstr);
733                         }
734                         break;
735                 case MSG_NET:
736                         write(net_sock, &msg, sizeof(MESSAGE));
737                         break;
738                 case MSG_VLP:
739                         switch(msg.param.pword[0]) {
740                         case VLP_REMOTE_INSTANCE_PLEASE:
741                                 RemoteInstance(e, msg.param.pword[2]);
742                                 break;
743                         }/* switch */
744                         break;
745                 case MSG_INT:
746                         switch(msg.param.pword[0]) {
747                         case INT_EXITING:
748                                 char ss[255];
749
750                                 MESSAGE m;
751                                 m.msg_type = MSG_VLP;
752                                 m.param.pword[0] = VLP_INTERPRETER_DOWN;
753                                 m.param.pword[1] = e->ID;
754                                 write(net_sock, &m, sizeof(MESSAGE));
755                                 if (e->remote == 0)
756                                         CloseInstances(e);
757                                 delete e->notify;
758                                 ::close(e->sock);
759                                 /* TODO: Check this */
760                                 Interpreters.removeOne(e);
761                                 delete e;
762
763                                 if (info_messages) {
764                                         sprintf(ss, "%s : End of program "
765                                                 "execution", msg.param.pstr);
766                                         WriteMessage(ss);
767                                 }
768                                 break;
769                         case INT_CTX_REQ:
770                                 msg.msg_type = MSG_INT;
771                                 msg.param.pword[0] = INT_CTX;
772                                 msg.param.pword[1] = NodeNumber;
773                                 msg.param.pword[2] = e->ID;
774                                 if (e->remote) {
775                                         msg.param.pword[3] = e->p_ctx.node;
776                                         msg.param.pword[4] = 
777                                                         e->p_ctx.program_id;
778                                 }
779                                 write(sock, &msg, sizeof(MESSAGE)); 
780                                 break;
781                         };
782                         break;
783                 }
784         }
785 }
786
787 /**
788  * Writes message to kernel logger.
789  * @parame msg String with message to log
790  */
791 void QKernel::WriteMessage(char *msg)
792 {
793         int x;
794         int y;
795         x = desktop->textCursor().blockNumber();
796         y = desktop->textCursor().columnNumber();
797
798         if (x > 100) {
799                 desktop->clear();
800         }
801         
802         desktop->setReadOnly(FALSE);
803         desktop->append(msg);
804         desktop->setReadOnly(TRUE);
805
806         QTextCursor tmpCursor = desktop->textCursor();
807         tmpCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
808         desktop->setTextCursor(tmpCursor);
809
810         desktop->repaint();
811         
812         if (desktop->document()->blockCount() > 100) {
813                 desktop->clear();
814         }
815 }
816
817 /**
818  * Adds checkbox to menu item. If it is checked additional info messages are
819  * shown.
820  */
821 void QKernel::on_actionInfo_messages_triggered()
822 {
823         if (toolsMenu != NULL) {
824                 actionInfo_messages->setChecked(!actionInfo_messages->isChecked());
825 //              actionInfo_messages->toggle();
826                 info_messages = actionInfo_messages->isChecked();
827                 fprintf(stderr, "Info is checked? %s\n", actionInfo_messages->isChecked() ? "yes" : "no");
828         }
829 //      menuBar()->repaint();
830 }
831
832 /**
833  * Allows to set options in GUI window.
834  * Additional window is displayed to set kernel options which are saved in 
835  * vlp.cfg file in kernel executable directory.
836  */
837 void QKernel::on_actionOptions_triggered()
838 {
839         QDialog dlg(this, Qt::Dialog);
840         dlg.setWindowTitle("Options");
841         ConnectEntry *e;
842         unsigned int i;
843
844         QLineEdit* progs;
845         progs = new QLineEdit(progdir, &dlg);
846         progs->setGeometry(150, 20, 180, 30);
847
848         QLabel* tmpQLabel;
849         tmpQLabel = new QLabel("Programs directory", &dlg);
850         tmpQLabel->setGeometry(30, 20, 120, 30);
851
852         QFrame* tmpQFrame;
853         tmpQFrame = new QFrame(&dlg);
854         tmpQFrame->setGeometry(10, 60, 380, 30);
855         tmpQFrame->setFrameStyle(52);
856
857         tmpQLabel = new QLabel("Virtual Processor properties (activated after "
858                                                 "restarting VLP):", &dlg);
859         tmpQLabel->setGeometry(10, 80, 340, 30);
860
861         QLineEdit *nn;
862         char nns[256];
863         sprintf(nns, "%d", NodeNumber);
864         nn = new QLineEdit(nns, &dlg);
865         nn->setGeometry(110, 110, 40, 30);
866
867         tmpQLabel = new QLabel("Node number:", &dlg);
868         tmpQLabel->setGeometry(20, 110, 90, 30);
869
870         QRadioButton *exp, *reg;
871         exp = new QRadioButton("Explicit", &dlg);
872         exp->setGeometry(30, 170, 100, 30);
873         exp->setChecked(TRUE);
874
875         reg = new QRadioButton("Registration", &dlg);
876         reg->setGeometry(30, 200, 100, 30);
877         reg->setEnabled(FALSE);
878
879         connections = new QListWidget(&dlg);
880         connections->setGeometry(170, 140, 130, 100);
881
882         for (int i = 0; i < ConnectList.size(); i++) {
883                 e = ConnectList.at(i);
884                 connections->addItem(e->addr);
885         }
886
887         tmpQLabel = new QLabel("Connection list:", &dlg);
888         tmpQLabel->setGeometry(170, 110, 100, 30);
889
890         QPushButton *addbtn;
891         QPushButton *delbtn;
892         QPushButton *okbtn;
893         QPushButton *cancelbtn;
894         addbtn = new QPushButton("Add", &dlg);
895         addbtn->setGeometry(310, 150, 60, 30);
896         connect(addbtn, SIGNAL(clicked()), this, SLOT(AddAddress()));
897
898         delbtn = new QPushButton("Del", &dlg);
899         delbtn->setGeometry(310, 200, 60, 30);
900         connect(delbtn, SIGNAL(clicked()), this, SLOT(DelAddress()));
901
902         okbtn = new QPushButton("Ok", &dlg);
903         okbtn->setGeometry(80, 260, 100, 30);
904         okbtn->setDefault(TRUE);
905         connect(okbtn, SIGNAL(clicked()), &dlg, SLOT(accept()));
906
907         cancelbtn = new QPushButton("Cancel", &dlg);
908         cancelbtn->setGeometry(210, 260, 100, 30);
909         connect(cancelbtn, SIGNAL(clicked()), &dlg, SLOT(reject()));
910
911         QGroupBox* group;
912         group = new QGroupBox("Connection type", &dlg);
913         group->setGeometry(20, 150, 120, 90);
914         group->setAlignment(Qt::AlignLeft);
915         group->lower();
916
917         QVBoxLayout *vbox = new QVBoxLayout();
918         vbox->addWidget(exp);
919         vbox->addWidget(reg);
920         vbox->addStretch(1);
921         group->setLayout(vbox);
922
923         dlg.resize(400, 310);
924         if (dlg.exec()) {
925                 config_t cfg;
926                 config_setting_t *root;
927                 config_setting_t *setting;
928                 config_init(&cfg);
929
930                 root = config_root_setting(&cfg);
931
932                 setting = config_setting_add(root, "progdir",
933                                                         CONFIG_TYPE_STRING);
934                 config_setting_set_string(setting, progs->text().toAscii().data());
935                 strcpy(progdir, progs->text().toAscii().data());
936
937                 setting = config_setting_add(root, "node_number",
938                                                         CONFIG_TYPE_INT);
939                 config_setting_set_int(setting, atoi(nn->text().toAscii().data()));
940
941                 setting = config_setting_add(root, "homedir",
942                                                         CONFIG_TYPE_STRING);
943                 config_setting_set_string(setting, HomeDir);
944
945                 setting = config_setting_add(root, "type",
946                                                         CONFIG_TYPE_STRING);
947                 if (exp->isChecked()) {
948                         config_setting_set_string(setting, "explicit");
949
950                         config_setting_t *hosts = NULL;
951                         hosts = config_setting_add(root, "host",
952                                                         CONFIG_TYPE_ARRAY);
953                         for(i = 0; i < connections->count(); i++) {
954                                 setting = config_setting_add(hosts, NULL,
955                                                         CONFIG_TYPE_STRING);
956                                 config_setting_set_string(setting,
957                                                 connections->item(i)->text().toAscii().data());
958                         }
959                 } else {
960                         config_setting_set_string(setting, "register");
961                 }
962
963                 if (!config_write_file(&cfg, "vlp.cfg")) {
964                         fprintf(stderr, "Error while writing to file: %s.\n", 
965                                                                 "vlp.cfg");
966                 }
967                 config_destroy(&cfg);
968         }
969 }
970
971 /**
972  * Locks kernel program.
973  * Additional window is displayed to enter password and retype it. If both are
974  * same kernel window is locked.
975  */
976 void QKernel::on_actionLock_console_triggered()
977 {
978         QDialog d(this, Qt::Dialog);
979         d.setWindowTitle("Lock console");
980
981         QPushButton ob("Ok", &d);
982         ob.setGeometry(30, 60, 80, 30);
983         ob.setDefault(TRUE);
984         connect(&ob, SIGNAL(clicked()), &d, SLOT(accept()));
985
986         QLabel lab("Password:", &d);
987         lab.setGeometry(10, 10, 60, 30);
988
989         QLineEdit ed("", &d);
990         ed.setGeometry(70, 10, 140, 30);
991         ed.setEchoMode(QLineEdit::Password);
992
993         QPushButton cb("Cancel", &d);
994         cb.setGeometry(130, 60, 80, 30);
995         connect(&cb, SIGNAL(clicked()), &d, SLOT(reject())); 
996
997         d.resize(240, 100);
998
999         if (d.exec()) {
1000                 if (strcmp(ed.text().toAscii().data(), "") != 0) {
1001                         strcpy(LockPasswd, ed.text().toAscii().data());
1002                         lab.setText("Retype:");
1003                         ed.setText("");
1004                         /*
1005                          * Following exec(), could produce error:
1006                          * X Error: BadWindow (invalid Window parameter) 3
1007                          *   Major opcode: 3 (X_GetWindowAttributes)
1008                          *
1009                          * This is not error in our code. Basing on:
1010                          * https://bugreports.qt-project.org/browse/QTBUG-1782
1011                          * this happens only on Qt 4.3 - 4.4.
1012                          */
1013                         if (d.exec()) {
1014                                 if (strcmp(ed.text().toAscii().data(), LockPasswd) == 0) {
1015                                         setLocked(TRUE);
1016                                         WriteMessage("CONSOLE LOCKED");
1017                                 } else {
1018                                         QMessageBox msg(this);
1019                                         msg.setText("Not matching!");
1020                                         msg.setButtonText(0, "Close");
1021                                         msg.show();
1022                                 }
1023                         } else {
1024                                 strcpy(LockPasswd, "");
1025                         }
1026                 }
1027         }
1028 }
1029
1030 /**
1031  * Unlocks kernel program.
1032  * Additional window is displayed to enter password. If it is correct, kernel 
1033  * window is unlocked
1034  */
1035 void QKernel::on_actionUnlock_console_triggered()
1036 {
1037         QDialog d(this, Qt::Dialog);
1038         d.setWindowTitle("Enter password");
1039
1040         QLabel lab("Password:", &d);
1041         lab.setGeometry(10, 10, 60, 30);
1042
1043         QLineEdit ed("", &d);
1044         ed.setGeometry(70, 10, 140, 30);
1045         ed.setEchoMode(QLineEdit::Password);
1046
1047         QPushButton ob("Ok", &d);
1048         ob.setGeometry(30, 60, 80, 30);
1049         ob.setDefault(TRUE);
1050         connect(&ob, SIGNAL(clicked()), &d, SLOT(accept()));
1051
1052         QPushButton cb("Cancel", &d);
1053         cb.setGeometry(130, 60, 80, 30);
1054         connect(&cb, SIGNAL(clicked()), &d, SLOT(reject())); 
1055
1056         d.resize(240, 100);
1057
1058         if (d.exec()) {
1059                 if (strcmp(ed.text().toAscii().data(), LockPasswd) == 0) {
1060                         setLocked(FALSE);
1061                         WriteMessage("CONSOLE UNLOCKED");
1062                 } else {
1063                         QMessageBox msg(this);
1064                         msg.setText("Wrong password!");
1065                         msg.setButtonText(0, "Close");
1066                         msg.show();
1067                 }
1068         }
1069 }
1070
1071 /**
1072  * Writes init message in kernel
1073  */
1074 void QKernel::InitMessage()
1075 {
1076         WriteMessage("\n " PACKAGE_STRING ": READY \n");
1077 }
1078
1079 /**
1080  * Finds Interpreter by its socket
1081  * @param _id ID of the socket
1082  * @return returns pointer to the found interpreter slot. NULL otherwise
1083  */
1084 InterpEntry *QKernel::findINTbySocket(int _id)
1085 {
1086         InterpEntry *pom = NULL;
1087         
1088         for (int i = 0; i < Interpreters.size(); i++) {
1089                 if (Interpreters.at(i)->sock == _id) {
1090                         pom = Interpreters.at(i);
1091                         break;
1092                 }
1093         }
1094
1095         return pom;
1096 }
1097
1098 /**
1099  * Finds Interpreter by its ID.
1100  * @param _id ID of the interpreter
1101  * @return returns pointer to the found interpreter slot. NULL otherwise
1102  */
1103 InterpEntry *QKernel::findINTbyID(int _id)
1104 {
1105         InterpEntry *pom = NULL;
1106         
1107         for (int i = 0; i < Interpreters.size(); i++) {
1108                 if (Interpreters.at(i)->ID == _id) {
1109                         pom = Interpreters.at(i);
1110                         break;
1111                 }
1112         }
1113
1114         return pom;
1115 }
1116
1117
1118 /**
1119  * Connects interpreter
1120  * @param ss full filepath with filename but without extension of the loglan
1121  *           program to run.
1122  * @param r Interpreter execution mode. 0 if it will be local instance, 1 if
1123  *          remote
1124  * @return Returns pointer to newly created interpreter slot, or NULL on error.
1125  */
1126 InterpEntry *QKernel::RunIntModule(char *ss, int r)
1127 {
1128         char a[256], b[255];
1129         struct sockaddr_un svr;
1130         int len, sock, i, on;
1131         int newint=-1;
1132         char cmd[255];
1133         FILE *cf;
1134         MESSAGE msg;
1135         InterpEntry *newINT = NULL;
1136
1137         strcpy(a, ss);
1138         strcat(a, ".ccd");
1139         cf = fopen(a, "r");
1140         if (cf == NULL) {
1141                 WriteMessage("File not found: no .ccd file");
1142                 return NULL;
1143         }
1144         fclose(cf);
1145
1146         strcpy(a, ss);
1147         strcat(a, ".pcd");
1148         cf = fopen(a, "r");
1149         if (cf == NULL) {
1150                 WriteMessage("File not found: no .pcd file");
1151                 return NULL;
1152         }
1153         fclose(cf);
1154
1155         newINT = new InterpEntry;
1156         for(i = 0; i < MAXINSTANCES; i++) 
1157                 newINT->RInstances[i] =- 1;
1158
1159         strcpy(b, rindex(ss, '/'));
1160         for(i = 0; i < strlen(b); i++)
1161                 b[i] = b[i+1];
1162         if (info_messages) {
1163                 sprintf(a, "%s : Start execution", b);
1164                 WriteMessage(a); 
1165         }
1166
1167         newint = freeINTid;
1168         freeINTid++;
1169         newINT->ID = newint;
1170         strcpy(newINT->shortname, b);
1171         strcpy(newINT->fullname, ss);
1172
1173         sprintf(a, "%s%d", IPATH, newint);
1174         sprintf(cmd, "%s/modules/logint %s %s", HomeDir, a, ss);
1175         if (r) 
1176                 strcat(cmd, " r");
1177         sprintf(b, " %s %s %s %s %s", myargs[0], myargs[1], myargs[2],
1178                                                         myargs[3], myargs[4]);
1179         strcat(cmd, b);
1180         strcat(cmd, " &");
1181
1182         sock = socket(AF_UNIX, SOCK_STREAM, 0);
1183         unlink(a);
1184         bzero(&svr, sizeof(svr));
1185         svr.sun_family = AF_UNIX;
1186         strcpy(svr.sun_path, a);
1187         len = strlen(svr.sun_path)+sizeof(svr.sun_family);
1188         bind(sock, (struct sockaddr*)&svr, len);
1189         listen(sock, 5);
1190         system(cmd);
1191         newINT->sock = accept(sock, (struct sockaddr*)0, (unsigned int *)0);
1192         //::close(sock);
1193
1194         if (newINT->sock > 0) { 
1195                 fcntl(newINT->sock, F_SETFL, 
1196                                 O_NONBLOCK|fcntl(newINT->sock, F_GETFL, 0));
1197                 on=1; 
1198                 setsockopt(newINT->sock, IPPROTO_TCP, TCP_NODELAY, (char*)&on,
1199                                                                 sizeof(on));
1200                 if (r)
1201                         newINT->remote = 1;
1202                 else 
1203                         newINT->remote = 0;
1204
1205                 bzero(&msg, sizeof(MESSAGE));
1206                 msg.msg_type = MSG_VLP;
1207                 msg.param.pword[0] = VLP_REGINT;
1208                 msg.param.pword[1] = newINT->ID;
1209                 sprintf(msg.param.pstr, "logi%d.net", newint);
1210                 write(net_sock, &msg, sizeof(MESSAGE)); 
1211
1212                 Interpreters.append(newINT);
1213                 newINT->notify = new QSocketNotifier(newINT->sock,
1214                                                         QSocketNotifier::Read);
1215                 connect(newINT->notify, SIGNAL(activated(int)), this,
1216                                                         SLOT(IntMessage(int)));
1217                 if (info_messages)
1218                         WriteMessage("INTERPRETER successfully connected");
1219         } else {
1220                 WriteMessage("Cannot connect interpreter");
1221         }
1222
1223         return newINT;
1224 }
1225
1226 /**
1227  * Allocates remote instance of interpreter
1228  * @param interp Interpreter slot 
1229  * @param on Node Number
1230  */
1231 void QKernel::RemoteInstance(InterpEntry *interp, int on)
1232 {
1233         MESSAGE m;
1234         char s[255];
1235
1236         m.msg_type = MSG_NET;
1237         m.param.pword[0] = NET_NODE_EXIST;
1238         m.param.pword[1] = on;
1239         m.param.pword[2] = interp->ID;
1240         write(net_sock, &m, sizeof(MESSAGE));
1241         bzero(&m, sizeof(MESSAGE));
1242         while((m.msg_type!=MSG_NET) && (m.param.pword[0]!=NET_NODE_EXIST))
1243                 read(net_sock, &m, sizeof(MESSAGE));
1244
1245          /* means node exists */
1246         if (m.param.pword[1] == 1) {
1247                 m.msg_type = MSG_NET;
1248                 m.param.pword[0] = NET_TRANSMIT_CODE;
1249                 m.param.pword[1] = interp->ID;
1250                 m.param.pword[2] = on;
1251                 strcpy(m.param.pstr, interp->fullname);
1252                 write(net_sock, &m, sizeof(MESSAGE));
1253
1254                 Net_Notify->setEnabled(FALSE);
1255                 while ((m.msg_type != MSG_NET) ||
1256                         (m.param.pword[0] != NET_TRANSMITTED))
1257                         read(net_sock, &m, sizeof(MESSAGE));
1258
1259                 m.msg_type = MSG_NET;
1260                 m.param.pword[0] = NET_PROPAGATE;
1261                 m.param.pword[1] = MSG_VLP;
1262                 m.param.pword[2] = NodeNumber;
1263                 m.param.pword[3] = 0;
1264                 m.param.pword[4] = on;
1265                 m.param.pword[5] = 0;
1266                 m.param.pword[6] = VLP_REMOTE_INSTANCE;
1267                 m.param.pword[7] = interp->ID;
1268                 strcpy(m.param.pstr, interp->shortname);
1269                 write(net_sock, &m, sizeof(MESSAGE));
1270
1271                 read(net_sock, &m, sizeof(MESSAGE));
1272                 while (1) {
1273                         if ((m.param.pword[0] == NET_PROPAGATE) &&
1274                                 (m.param.pword[6] == VLP_REMOTE_INSTANCE_OK)) {
1275                                 interp->RInstances[on] = m.param.pword[7];
1276                                 break;
1277                         }
1278                         read(net_sock, &m, sizeof(MESSAGE));
1279                 }
1280
1281                 Net_Notify->setEnabled(TRUE);
1282
1283                 /*bzero(&m, sizeof(MESSAGE));*/
1284                 m.msg_type = MSG_VLP;
1285                 m.param.pword[0] = VLP_REMOTE_INSTANCE_HERE;
1286                 m.param.pword[1] = interp->RInstances[on];
1287                 write(interp->sock, &m, sizeof(MESSAGE));
1288         } else { /* There is no such a node! */
1289                 sprintf(s, "Warning: Node number %d not found!", on); 
1290                 WriteMessage(s);
1291                 WriteMessage("Allocating O-process on the local node");
1292                 bzero(&m, sizeof(MESSAGE));
1293                 m.msg_type = MSG_VLP;
1294                 m.param.pword[0] = VLP_REMOTE_INSTANCE_HERE;
1295                 m.param.pword[1] = interp->ID;
1296                 write(interp->sock, &m, sizeof(MESSAGE));
1297         }
1298 }
1299
1300 /**
1301  * Closes all remote instances
1302  */
1303 void QKernel::CloseInstances(InterpEntry *e)
1304 {
1305         MESSAGE msg;
1306         int i;
1307
1308         if (info_messages)
1309                 WriteMessage("Closing remote instances");
1310
1311         for(i=0; i < MAXINSTANCES; i++)
1312                 if (e->RInstances[i]>=0) {
1313                         msg.msg_type = MSG_NET;
1314                         msg.param.pword[0] = NET_PROPAGATE;
1315                         msg.param.pword[1] = MSG_VLP;
1316                         msg.param.pword[2] = NodeNumber;
1317                         msg.param.pword[4] = i;
1318                         msg.param.pword[6] = VLP_CLOSE_INSTANCE;
1319                         msg.param.pword[7] = e->RInstances[i];
1320                         write(net_sock, &msg, sizeof(MESSAGE));
1321                 }
1322 }
1323
1324 /**
1325  * Displays information about virtual machine
1326  */
1327 void QKernel::on_actionInfo_triggered()
1328 {
1329         MESSAGE m;
1330
1331         WriteMessage(CharLine);
1332         WriteMessage("### Virtual Machine Information ###");
1333         m.msg_type = MSG_NET;
1334         m.param.pword[0] = NET_GET_INFO;
1335         write(net_sock, &m, sizeof(MESSAGE));
1336         wait_for_info = TRUE;
1337 }
1338
1339 /**
1340  * Program main function
1341  * All program arguments but the first one (argv[0]: program name) are saved and
1342  * passed to all dependent programs on their invocation.
1343  * @param argc Number of program arguments
1344  * @param argv Program arguments
1345  */
1346 int main(int argc, char **argv)
1347 {
1348         int i;
1349         for(i = 0; i < 5; i++) {
1350                 strcpy(myargs[i], "");
1351         }
1352         for(i = 1; i < argc; i++) {
1353                 strcpy(myargs[i - 1], argv[i]);
1354         }
1355
1356         QApplication * app = new QApplication(argc, argv);
1357         QKernel kernel;
1358         kernel.show();
1359         kernel.InitMessage();
1360         
1361         return app->exec();
1362 }