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