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