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