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