Fix toggling of info messages
[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
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         }
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 }