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