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