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