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