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