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