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