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