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