~ubuntu-branches/ubuntu/wily/psi/wily-proposed

« back to all changes in this revision

Viewing changes to third-party/qca/qca/src/support/console.cpp

  • Committer: Package Import Robot
  • Author(s): Jan Niehusmann
  • Date: 2014-07-01 21:49:34 UTC
  • mfrom: (6.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20140701214934-gt4dkgm94byi4vnn
Tags: 0.15-1
* New upstream version
* set debhelper compat level to 9
* set Standards-Version to 3.9.5 (no further changes)
* add lintian override regarding license-problem-non-free-RFC
* use qconf to regenerate configure script
* implement hardening using buildflags instead of hardening-wrapper

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2006,2007  Justin Karneges <justin@affinix.com>
3
 
 *
4
 
 * This library is free software; you can redistribute it and/or
5
 
 * modify it under the terms of the GNU Lesser General Public
6
 
 * License as published by the Free Software Foundation; either
7
 
 * version 2.1 of the License, or (at your option) any later version.
8
 
 *
9
 
 * This library is distributed in the hope that it will be useful,
10
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 
 * Lesser General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU Lesser General Public
15
 
 * License along with this library; if not, write to the Free Software
16
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
 
 * 02110-1301  USA
18
 
 *
19
 
 */
20
 
 
21
 
#include "qca_support.h"
22
 
 
23
 
#include "qpipe.h"
24
 
#include "qca_safeobj.h"
25
 
 
26
 
#include <QPointer>
27
 
#include <QTextCodec>
28
 
#include <QMutex>
29
 
 
30
 
#ifdef Q_OS_WIN
31
 
# include <windows.h>
32
 
#else
33
 
# include <sys/termios.h>
34
 
# include <unistd.h>
35
 
# include <fcntl.h>
36
 
# include <stdlib.h>
37
 
#endif
38
 
 
39
 
#include <stdio.h>
40
 
 
41
 
#define CONSOLEPROMPT_INPUT_MAX 56
42
 
 
43
 
Q_DECLARE_METATYPE(QCA::SecureArray)
44
 
 
45
 
namespace QCA {
46
 
 
47
 
//----------------------------------------------------------------------------
48
 
// ConsoleWorker
49
 
//----------------------------------------------------------------------------
50
 
class ConsoleWorker : public QObject
51
 
{
52
 
        Q_OBJECT
53
 
private:
54
 
        QPipeEnd in, out;
55
 
        bool started;
56
 
        QByteArray in_left, out_left;
57
 
 
58
 
public:
59
 
        ConsoleWorker(QObject *parent = 0) : QObject(parent), in(this), out(this)
60
 
        {
61
 
                started = false;
62
 
        }
63
 
 
64
 
        ~ConsoleWorker()
65
 
        {
66
 
                stop();
67
 
        }
68
 
 
69
 
        void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id)
70
 
        {
71
 
                Q_ASSERT(!started);
72
 
 
73
 
                if(in_id != INVALID_Q_PIPE_ID)
74
 
                {
75
 
                        in.take(in_id, QPipeDevice::Read);
76
 
                        connect(&in, SIGNAL(readyRead()), SLOT(in_readyRead()));
77
 
                        connect(&in, SIGNAL(closed()), SLOT(in_closed()));
78
 
                        connect(&in, SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(in_error(QCA::QPipeEnd::Error)));
79
 
                        in.enable();
80
 
                }
81
 
 
82
 
                if(out_id != INVALID_Q_PIPE_ID)
83
 
                {
84
 
                        out.take(out_id, QPipeDevice::Write);
85
 
                        connect(&out, SIGNAL(bytesWritten(int)), SLOT(out_bytesWritten(int)));
86
 
                        connect(&out, SIGNAL(closed()), SLOT(out_closed()));
87
 
                        out.enable();
88
 
                }
89
 
 
90
 
                started = true;
91
 
        }
92
 
 
93
 
        void stop()
94
 
        {
95
 
                if(!started)
96
 
                        return;
97
 
 
98
 
                if(in.isValid())
99
 
                        in.finalizeAndRelease();
100
 
                if(out.isValid())
101
 
                        out.release();
102
 
 
103
 
                in_left = in.read();
104
 
                out_left = out.takeBytesToWrite();
105
 
 
106
 
                started = false;
107
 
        }
108
 
 
109
 
public slots:
110
 
        bool isValid() const
111
 
        {
112
 
                return in.isValid();
113
 
        }
114
 
 
115
 
        void setSecurityEnabled(bool enabled)
116
 
        {
117
 
                if(in.isValid())
118
 
                        in.setSecurityEnabled(enabled);
119
 
                if(out.isValid())
120
 
                        out.setSecurityEnabled(enabled);
121
 
        }
122
 
 
123
 
        QByteArray read(int bytes = -1)
124
 
        {
125
 
                return in.read(bytes);
126
 
        }
127
 
 
128
 
        void write(const QByteArray &a)
129
 
        {
130
 
                out.write(a);
131
 
        }
132
 
 
133
 
        QCA::SecureArray readSecure(int bytes = -1)
134
 
        {
135
 
                return in.readSecure(bytes);
136
 
        }
137
 
 
138
 
        void writeSecure(const QCA::SecureArray &a)
139
 
        {
140
 
                out.writeSecure(a);
141
 
        }
142
 
 
143
 
        void closeOutput()
144
 
        {
145
 
                out.close();
146
 
        }
147
 
 
148
 
        int bytesAvailable() const
149
 
        {
150
 
                return in.bytesAvailable();
151
 
        }
152
 
 
153
 
        int bytesToWrite() const
154
 
        {
155
 
                return in.bytesToWrite();
156
 
        }
157
 
 
158
 
public:
159
 
        QByteArray takeBytesToRead()
160
 
        {
161
 
                QByteArray a = in_left;
162
 
                in_left.clear();
163
 
                return a;
164
 
        }
165
 
 
166
 
        QByteArray takeBytesToWrite()
167
 
        {
168
 
                QByteArray a = out_left;
169
 
                out_left.clear();
170
 
                return a;
171
 
        }
172
 
 
173
 
signals:
174
 
        void readyRead();
175
 
        void bytesWritten(int bytes);
176
 
        void inputClosed();
177
 
        void outputClosed();
178
 
 
179
 
private slots:
180
 
        void in_readyRead()
181
 
        {
182
 
                emit readyRead();
183
 
        }
184
 
 
185
 
        void out_bytesWritten(int bytes)
186
 
        {
187
 
                emit bytesWritten(bytes);
188
 
        }
189
 
 
190
 
        void in_closed()
191
 
        {
192
 
                emit inputClosed();
193
 
        }
194
 
 
195
 
        void in_error(QCA::QPipeEnd::Error)
196
 
        {
197
 
                emit inputClosed();
198
 
        }
199
 
 
200
 
        void out_closed()
201
 
        {
202
 
                emit outputClosed();
203
 
        }
204
 
};
205
 
 
206
 
//----------------------------------------------------------------------------
207
 
// ConsoleThread
208
 
//----------------------------------------------------------------------------
209
 
class ConsoleThread : public SyncThread
210
 
{
211
 
        Q_OBJECT
212
 
public:
213
 
        ConsoleWorker *worker;
214
 
        Q_PIPE_ID _in_id, _out_id;
215
 
        QByteArray in_left, out_left;
216
 
        QMutex call_mutex;
217
 
 
218
 
        ConsoleThread(QObject *parent = 0) : SyncThread(parent)
219
 
        {
220
 
                qRegisterMetaType<SecureArray>("QCA::SecureArray");
221
 
        }
222
 
 
223
 
        ~ConsoleThread()
224
 
        {
225
 
                stop();
226
 
        }
227
 
 
228
 
        void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id)
229
 
        {
230
 
                _in_id = in_id;
231
 
                _out_id = out_id;
232
 
                SyncThread::start();
233
 
        }
234
 
 
235
 
        void stop()
236
 
        {
237
 
                SyncThread::stop();
238
 
        }
239
 
 
240
 
        QVariant mycall(QObject *obj, const char *method, const QVariantList &args = QVariantList())
241
 
        {
242
 
                QVariant ret;
243
 
                bool ok;
244
 
 
245
 
                call_mutex.lock();
246
 
                ret = call(obj, method, args, &ok);
247
 
                call_mutex.unlock();
248
 
 
249
 
                Q_ASSERT(ok);
250
 
                if(!ok)
251
 
                {
252
 
                        fprintf(stderr, "QCA: ConsoleWorker call [%s] failed.\n", method);
253
 
                        abort();
254
 
                        return QVariant();
255
 
                }
256
 
                return ret;
257
 
        }
258
 
 
259
 
        bool isValid()
260
 
        {
261
 
                return mycall(worker, "isValid").toBool();
262
 
        }
263
 
 
264
 
        void setSecurityEnabled(bool enabled)
265
 
        {
266
 
                mycall(worker, "setSecurityEnabled", QVariantList() << enabled);
267
 
        }
268
 
 
269
 
        QByteArray read(int bytes = -1)
270
 
        {
271
 
                return mycall(worker, "read", QVariantList() << bytes).toByteArray();
272
 
        }
273
 
 
274
 
        void write(const QByteArray &a)
275
 
        {
276
 
                mycall(worker, "write", QVariantList() << a);
277
 
        }
278
 
 
279
 
        SecureArray readSecure(int bytes = -1)
280
 
        {
281
 
                return qVariantValue<SecureArray>(mycall(worker, "readSecure", QVariantList() << bytes));
282
 
        }
283
 
 
284
 
        void writeSecure(const SecureArray &a)
285
 
        {
286
 
                mycall(worker, "writeSecure", QVariantList() << qVariantFromValue<SecureArray>(a));
287
 
        }
288
 
 
289
 
        void closeOutput()
290
 
        {
291
 
                mycall(worker, "closeOutput");
292
 
        }
293
 
 
294
 
        int bytesAvailable()
295
 
        {
296
 
                return mycall(worker, "bytesAvailable").toInt();
297
 
        }
298
 
 
299
 
        int bytesToWrite()
300
 
        {
301
 
                return mycall(worker, "bytesToWrite").toInt();
302
 
        }
303
 
 
304
 
        QByteArray takeBytesToRead()
305
 
        {
306
 
                QByteArray a = in_left;
307
 
                in_left.clear();
308
 
                return a;
309
 
        }
310
 
 
311
 
        QByteArray takeBytesToWrite()
312
 
        {
313
 
                QByteArray a = out_left;
314
 
                out_left.clear();
315
 
                return a;
316
 
        }
317
 
 
318
 
signals:
319
 
        void readyRead();
320
 
        void bytesWritten(int);
321
 
        void inputClosed();
322
 
        void outputClosed();
323
 
 
324
 
protected:
325
 
        virtual void atStart()
326
 
        {
327
 
                worker = new ConsoleWorker;
328
 
 
329
 
                // use direct connections here, so that the emits come from
330
 
                //   the other thread.  we can also connect to our own
331
 
                //   signals to avoid having to make slots just to emit.
332
 
                connect(worker, SIGNAL(readyRead()), SIGNAL(readyRead()), Qt::DirectConnection);
333
 
                connect(worker, SIGNAL(bytesWritten(int)), SIGNAL(bytesWritten(int)), Qt::DirectConnection);
334
 
                connect(worker, SIGNAL(inputClosed()), SIGNAL(inputClosed()), Qt::DirectConnection);
335
 
                connect(worker, SIGNAL(outputClosed()), SIGNAL(outputClosed()), Qt::DirectConnection);
336
 
 
337
 
                worker->start(_in_id, _out_id);
338
 
        }
339
 
 
340
 
        virtual void atEnd()
341
 
        {
342
 
                in_left = worker->takeBytesToRead();
343
 
                out_left = worker->takeBytesToWrite();
344
 
                delete worker;
345
 
        }
346
 
};
347
 
 
348
 
//----------------------------------------------------------------------------
349
 
// Console
350
 
//----------------------------------------------------------------------------
351
 
class ConsolePrivate : public QObject
352
 
{
353
 
        Q_OBJECT
354
 
public:
355
 
        Console *q;
356
 
 
357
 
        bool started;
358
 
        Console::Type type;
359
 
        Console::ChannelMode cmode;
360
 
        Console::TerminalMode mode;
361
 
        ConsoleThread *thread;
362
 
        ConsoleReference *ref;
363
 
        Q_PIPE_ID in_id;
364
 
 
365
 
#ifdef Q_OS_WIN
366
 
        DWORD old_mode;
367
 
#else
368
 
        struct termios old_term_attr;
369
 
#endif
370
 
 
371
 
        ConsolePrivate(Console *_q) : QObject(_q), q(_q)
372
 
        {
373
 
                started = false;
374
 
                mode = Console::Default;
375
 
                thread = new ConsoleThread(this);
376
 
                ref = 0;
377
 
        }
378
 
 
379
 
        ~ConsolePrivate()
380
 
        {
381
 
                delete thread;
382
 
                setInteractive(Console::Default);
383
 
        }
384
 
 
385
 
        void setInteractive(Console::TerminalMode m)
386
 
        {
387
 
                // no change
388
 
                if(m == mode)
389
 
                        return;
390
 
 
391
 
                if(m == Console::Interactive)
392
 
                {
393
 
#ifdef Q_OS_WIN
394
 
                        GetConsoleMode(in_id, &old_mode);
395
 
                        SetConsoleMode(in_id, old_mode & (~ENABLE_LINE_INPUT & ~ENABLE_ECHO_INPUT));
396
 
#else
397
 
                        int fd = in_id;
398
 
                        struct termios attr;
399
 
                        tcgetattr(fd, &attr);
400
 
                        old_term_attr = attr;
401
 
 
402
 
                        attr.c_lflag &= ~(ECHO);    // turn off the echo flag
403
 
                        attr.c_lflag &= ~(ICANON);  // no wait for a newline
404
 
                        attr.c_cc[VMIN] = 1;        // read at least 1 char
405
 
                        attr.c_cc[VTIME] = 0;       // set wait time to zero
406
 
 
407
 
                        // set the new attributes
408
 
                        tcsetattr(fd, TCSAFLUSH, &attr);
409
 
#endif
410
 
                }
411
 
                else
412
 
                {
413
 
#ifdef Q_OS_WIN
414
 
                        SetConsoleMode(in_id, old_mode);
415
 
#else
416
 
                        int fd = in_id;
417
 
                        tcsetattr(fd, TCSANOW, &old_term_attr);
418
 
#endif
419
 
                }
420
 
 
421
 
                mode = m;
422
 
        }
423
 
};
424
 
 
425
 
static Console *g_tty_console = 0, *g_stdio_console = 0;
426
 
 
427
 
Console::Console(Type type, ChannelMode cmode, TerminalMode tmode, QObject *parent)
428
 
:QObject(parent)
429
 
{
430
 
        if(type == Tty)
431
 
        {
432
 
                Q_ASSERT(g_tty_console == 0);
433
 
                g_tty_console = this;
434
 
        }
435
 
        else
436
 
        {
437
 
                Q_ASSERT(g_stdio_console == 0);
438
 
                g_stdio_console = this;
439
 
        }
440
 
 
441
 
        d = new ConsolePrivate(this);
442
 
        d->type = type;
443
 
        d->cmode = cmode;
444
 
 
445
 
        Q_PIPE_ID in = INVALID_Q_PIPE_ID;
446
 
        Q_PIPE_ID out = INVALID_Q_PIPE_ID;
447
 
 
448
 
#ifdef Q_OS_WIN
449
 
        if(type == Tty)
450
 
        {
451
 
                in = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE,
452
 
                        FILE_SHARE_READ | FILE_SHARE_WRITE, false,
453
 
                        OPEN_EXISTING, 0, NULL);
454
 
        }
455
 
        else
456
 
        {
457
 
                in = GetStdHandle(STD_INPUT_HANDLE);
458
 
        }
459
 
#else
460
 
        if(type == Tty)
461
 
        {
462
 
                in = open("/dev/tty", O_RDONLY);
463
 
        }
464
 
        else
465
 
        {
466
 
                in = 0; // stdin
467
 
        }
468
 
#endif
469
 
        if(cmode == ReadWrite)
470
 
        {
471
 
#ifdef Q_OS_WIN
472
 
                if(type == Tty)
473
 
                {
474
 
                        out = CreateFileA("CONOUT$",
475
 
                                GENERIC_READ | GENERIC_WRITE,
476
 
                                FILE_SHARE_READ | FILE_SHARE_WRITE, false,
477
 
                                OPEN_EXISTING, 0, NULL);
478
 
                }
479
 
                else
480
 
                {
481
 
                        out = GetStdHandle(STD_OUTPUT_HANDLE);
482
 
                }
483
 
#else
484
 
                if(type == Tty)
485
 
                {
486
 
                        out = open("/dev/tty", O_WRONLY);
487
 
                }
488
 
                else
489
 
                {
490
 
                        out = 1; // stdout
491
 
                }
492
 
#endif
493
 
        }
494
 
 
495
 
        d->in_id = in;
496
 
        d->setInteractive(tmode);
497
 
        d->thread->start(in, out);
498
 
}
499
 
 
500
 
Console::~Console()
501
 
{
502
 
        release();
503
 
        Console::Type type = d->type;
504
 
        delete d;
505
 
        if(type == Tty)
506
 
                g_tty_console = 0;
507
 
        else
508
 
                g_stdio_console = 0;
509
 
}
510
 
 
511
 
Console::Type Console::type() const
512
 
{
513
 
        return d->type;
514
 
}
515
 
 
516
 
Console::ChannelMode Console::channelMode() const
517
 
{
518
 
        return d->cmode;
519
 
}
520
 
 
521
 
Console::TerminalMode Console::terminalMode() const
522
 
{
523
 
        return d->mode;
524
 
}
525
 
 
526
 
bool Console::isStdinRedirected()
527
 
{
528
 
#ifdef Q_OS_WIN
529
 
        HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
530
 
        DWORD mode;
531
 
        if(GetConsoleMode(h, &mode))
532
 
                return false;
533
 
        return true;
534
 
#else
535
 
        return (isatty(0) ? false : true); // 0 == stdin
536
 
#endif
537
 
}
538
 
 
539
 
bool Console::isStdoutRedirected()
540
 
{
541
 
#ifdef Q_OS_WIN
542
 
        HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
543
 
        DWORD mode;
544
 
        if(GetConsoleMode(h, &mode))
545
 
                return false;
546
 
        return true;
547
 
#else
548
 
        return (isatty(1) ? false : true); // 1 == stdout
549
 
#endif
550
 
}
551
 
 
552
 
Console *Console::ttyInstance()
553
 
{
554
 
        return g_tty_console;
555
 
}
556
 
 
557
 
Console *Console::stdioInstance()
558
 
{
559
 
        return g_stdio_console;
560
 
}
561
 
 
562
 
void Console::release()
563
 
{
564
 
        d->thread->stop();
565
 
}
566
 
 
567
 
QByteArray Console::bytesLeftToRead()
568
 
{
569
 
        return d->thread->takeBytesToRead();
570
 
}
571
 
 
572
 
QByteArray Console::bytesLeftToWrite()
573
 
{
574
 
        return d->thread->takeBytesToWrite();
575
 
}
576
 
 
577
 
//----------------------------------------------------------------------------
578
 
// ConsoleReference
579
 
//----------------------------------------------------------------------------
580
 
class ConsoleReferencePrivate : public QObject
581
 
{
582
 
        Q_OBJECT
583
 
public:
584
 
        ConsoleReference *q;
585
 
 
586
 
        Console *console;
587
 
        ConsoleThread *thread;
588
 
        ConsoleReference::SecurityMode smode;
589
 
        SafeTimer lateTrigger;
590
 
        bool late_read, late_close;
591
 
 
592
 
        ConsoleReferencePrivate(ConsoleReference *_q) : QObject(_q), q(_q), lateTrigger(this)
593
 
        {
594
 
                console = 0;
595
 
                thread = 0;
596
 
                connect(&lateTrigger, SIGNAL(timeout()), SLOT(doLate()));
597
 
                lateTrigger.setSingleShot(true);
598
 
        }
599
 
 
600
 
private slots:
601
 
        void doLate()
602
 
        {
603
 
                QPointer<QObject> self = this;
604
 
                if(late_read)
605
 
                        emit q->readyRead();
606
 
                if(!self)
607
 
                        return;
608
 
                if(late_close)
609
 
                        emit q->inputClosed();
610
 
        }
611
 
};
612
 
 
613
 
ConsoleReference::ConsoleReference(QObject *parent)
614
 
:QObject(parent)
615
 
{
616
 
        d = new ConsoleReferencePrivate(this);
617
 
}
618
 
 
619
 
ConsoleReference::~ConsoleReference()
620
 
{
621
 
        stop();
622
 
        delete d;
623
 
}
624
 
 
625
 
bool ConsoleReference::start(Console *console, SecurityMode mode)
626
 
{
627
 
        // make sure this reference isn't using a console already
628
 
        Q_ASSERT(!d->console);
629
 
 
630
 
        // one console reference at a time
631
 
        Q_ASSERT(console->d->ref == 0);
632
 
 
633
 
        // let's take it
634
 
        d->console = console;
635
 
        d->thread = d->console->d->thread;
636
 
        d->console->d->ref = this;
637
 
 
638
 
        bool valid = d->thread->isValid();
639
 
        int avail = d->thread->bytesAvailable();
640
 
 
641
 
        // pipe already closed and no data?  consider this an error
642
 
        if(!valid && avail == 0)
643
 
        {
644
 
                d->console->d->ref = 0;
645
 
                d->thread = 0;
646
 
                d->console = 0;
647
 
                return false;
648
 
        }
649
 
 
650
 
        // enable security?  it will last for this active session only
651
 
        d->smode = mode;
652
 
        if(mode == SecurityEnabled)
653
 
                d->thread->setSecurityEnabled(true);
654
 
 
655
 
        connect(d->thread, SIGNAL(readyRead()), SIGNAL(readyRead()));
656
 
        connect(d->thread, SIGNAL(bytesWritten(int)), SIGNAL(bytesWritten(int)));
657
 
        connect(d->thread, SIGNAL(inputClosed()), SIGNAL(inputClosed()));
658
 
        connect(d->thread, SIGNAL(outputClosed()), SIGNAL(outputClosed()));
659
 
 
660
 
        d->late_read = false;
661
 
        d->late_close = false;
662
 
 
663
 
        if(avail > 0)
664
 
                d->late_read = true;
665
 
 
666
 
        if(!valid)
667
 
                d->late_close = true;
668
 
 
669
 
        if(d->late_read || d->late_close)
670
 
                d->lateTrigger.start();
671
 
 
672
 
        return true;
673
 
}
674
 
 
675
 
void ConsoleReference::stop()
676
 
{
677
 
        if(!d->console)
678
 
                return;
679
 
 
680
 
        d->lateTrigger.stop();
681
 
 
682
 
        disconnect(d->thread, 0, this, 0);
683
 
 
684
 
        // automatically disable security when we go inactive
685
 
        d->thread->setSecurityEnabled(false);
686
 
 
687
 
        d->console->d->ref = 0;
688
 
        d->thread = 0;
689
 
        d->console = 0;
690
 
}
691
 
 
692
 
Console *ConsoleReference::console() const
693
 
{
694
 
        return d->console;
695
 
}
696
 
 
697
 
ConsoleReference::SecurityMode ConsoleReference::securityMode() const
698
 
{
699
 
        return d->smode;
700
 
}
701
 
 
702
 
QByteArray ConsoleReference::read(int bytes)
703
 
{
704
 
        return d->thread->read(bytes);
705
 
}
706
 
 
707
 
void ConsoleReference::write(const QByteArray &a)
708
 
{
709
 
        d->thread->write(a);
710
 
}
711
 
 
712
 
SecureArray ConsoleReference::readSecure(int bytes)
713
 
{
714
 
        return d->thread->readSecure(bytes);
715
 
}
716
 
 
717
 
void ConsoleReference::writeSecure(const SecureArray &a)
718
 
{
719
 
        d->thread->writeSecure(a);
720
 
}
721
 
 
722
 
void ConsoleReference::closeOutput()
723
 
{
724
 
        d->thread->closeOutput();
725
 
}
726
 
 
727
 
int ConsoleReference::bytesAvailable() const
728
 
{
729
 
        return d->thread->bytesAvailable();
730
 
}
731
 
 
732
 
int ConsoleReference::bytesToWrite() const
733
 
{
734
 
        return d->thread->bytesToWrite();
735
 
}
736
 
 
737
 
//----------------------------------------------------------------------------
738
 
// ConsolePrompt
739
 
//----------------------------------------------------------------------------
740
 
class ConsolePrompt::Private : public QObject
741
 
{
742
 
        Q_OBJECT
743
 
public:
744
 
        ConsolePrompt *q;
745
 
 
746
 
        Synchronizer sync;
747
 
        Console *con;
748
 
        bool own_con;
749
 
        ConsoleReference console;
750
 
        QString promptStr;
751
 
        SecureArray result;
752
 
        bool waiting;
753
 
        int at;
754
 
        bool done;
755
 
        bool charMode;
756
 
        QTextCodec *codec;
757
 
        QTextCodec::ConverterState *encstate, *decstate;
758
 
 
759
 
        Private(ConsolePrompt *_q) : QObject(_q), q(_q), sync(_q), console(this)
760
 
        {
761
 
                connect(&console, SIGNAL(readyRead()), SLOT(con_readyRead()));
762
 
                connect(&console, SIGNAL(inputClosed()), SLOT(con_inputClosed()));
763
 
 
764
 
                con = 0;
765
 
                own_con = false;
766
 
                waiting = false;
767
 
 
768
 
#ifdef Q_OS_WIN
769
 
                codec = QTextCodec::codecForMib(106); // UTF-8
770
 
#else
771
 
                codec = QTextCodec::codecForLocale();
772
 
#endif
773
 
                encstate = 0;
774
 
                decstate = 0;
775
 
        }
776
 
 
777
 
        ~Private()
778
 
        {
779
 
                reset();
780
 
        }
781
 
 
782
 
        void reset()
783
 
        {
784
 
                delete encstate;
785
 
                encstate = 0;
786
 
                delete decstate;
787
 
                decstate = 0;
788
 
 
789
 
                console.stop();
790
 
                if(own_con)
791
 
                {
792
 
                        delete con;
793
 
                        con = 0;
794
 
                        own_con = false;
795
 
                }
796
 
        }
797
 
 
798
 
        bool start(bool _charMode)
799
 
        {
800
 
                own_con = false;
801
 
                con = Console::ttyInstance();
802
 
                if(!con)
803
 
                {
804
 
                        con = new Console(Console::Tty, Console::ReadWrite, Console::Interactive);
805
 
                        own_con = true;
806
 
                }
807
 
 
808
 
                result.clear();
809
 
                at = 0;
810
 
                done = false;
811
 
                charMode = _charMode;
812
 
 
813
 
                encstate = new QTextCodec::ConverterState(QTextCodec::IgnoreHeader);
814
 
                decstate = new QTextCodec::ConverterState(QTextCodec::IgnoreHeader);
815
 
 
816
 
                if(!console.start(con, ConsoleReference::SecurityEnabled))
817
 
                {
818
 
                        reset();
819
 
                        fprintf(stderr, "Console input not available or closed\n");
820
 
                        return false;
821
 
                }
822
 
 
823
 
                if(!charMode)
824
 
                        writeString(promptStr + ": ");
825
 
 
826
 
                return true;
827
 
        }
828
 
 
829
 
        void writeString(const QString &str)
830
 
        {
831
 
                console.writeSecure(codec->fromUnicode(str.unicode(), str.length(), encstate));
832
 
        }
833
 
 
834
 
        // process each char.  internally store the result as utf16, which
835
 
        //   is easier to edit (e.g. backspace)
836
 
        bool processChar(QChar c)
837
 
        {
838
 
                if(charMode)
839
 
                {
840
 
                        appendChar(c);
841
 
                        done = true;
842
 
                        return false;
843
 
                }
844
 
 
845
 
                if(c == '\r' || c == '\n')
846
 
                {
847
 
                        writeString("\n");
848
 
                        done = true;
849
 
                        return false;
850
 
                }
851
 
 
852
 
                if(c == '\b' || c == 0x7f)
853
 
                {
854
 
                        if(at > 0)
855
 
                        {
856
 
                                --at;
857
 
                                writeString("\b \b");
858
 
                                result.resize(at * sizeof(ushort));
859
 
                        }
860
 
                        return true;
861
 
                }
862
 
                else if(c < 0x20)
863
 
                        return true;
864
 
 
865
 
                if(at >= CONSOLEPROMPT_INPUT_MAX)
866
 
                        return true;
867
 
 
868
 
                appendChar(c);
869
 
 
870
 
                writeString("*");
871
 
                return true;
872
 
        }
873
 
 
874
 
        void appendChar(QChar c)
875
 
        {
876
 
                if((at + 1) * (int)sizeof(ushort) > result.size())
877
 
                        result.resize((at + 1) * sizeof(ushort));
878
 
                ushort *p = (ushort *)result.data();
879
 
                p[at++] = c.unicode();
880
 
        }
881
 
 
882
 
        void convertToUtf8()
883
 
        {
884
 
                // convert result from utf16 to utf8, securely
885
 
                QTextCodec *codec = QTextCodec::codecForMib(106);
886
 
                QTextCodec::ConverterState cstate(QTextCodec::IgnoreHeader);
887
 
                SecureArray out;
888
 
                ushort *ustr = (ushort *)result.data();
889
 
                int len = result.size() / sizeof(ushort);
890
 
                for(int n = 0; n < len; ++n)
891
 
                {
892
 
                        QChar c(ustr[n]);
893
 
                        out += codec->fromUnicode(&c, 1, &cstate);
894
 
                }
895
 
                result = out;
896
 
        }
897
 
 
898
 
private slots:
899
 
        void con_readyRead()
900
 
        {
901
 
                while(console.bytesAvailable() > 0)
902
 
                {
903
 
                        SecureArray buf = console.readSecure(1);
904
 
                        if(buf.isEmpty())
905
 
                                break;
906
 
 
907
 
                        // convert to unicode and process
908
 
                        QString str = codec->toUnicode(buf.data(), 1, decstate);
909
 
                        bool quit = false;
910
 
                        for(int n = 0; n < str.length(); ++n)
911
 
                        {
912
 
                                if(!processChar(str[n]))
913
 
                                {
914
 
                                        quit = true;
915
 
                                        break;
916
 
                                }
917
 
                        }
918
 
                        if(quit)
919
 
                                break;
920
 
                }
921
 
 
922
 
                if(done)
923
 
                {
924
 
                        convertToUtf8();
925
 
 
926
 
                        reset();
927
 
                        if(waiting)
928
 
                                sync.conditionMet();
929
 
                        else
930
 
                                emit q->finished();
931
 
                }
932
 
        }
933
 
 
934
 
        void con_inputClosed()
935
 
        {
936
 
                fprintf(stderr, "Console input closed\n");
937
 
                if(!done)
938
 
                {
939
 
                        done = true;
940
 
                        result.clear();
941
 
 
942
 
                        reset();
943
 
                        if(waiting)
944
 
                                sync.conditionMet();
945
 
                        else
946
 
                                emit q->finished();
947
 
                }
948
 
        }
949
 
};
950
 
 
951
 
ConsolePrompt::ConsolePrompt(QObject *parent)
952
 
:QObject(parent)
953
 
{
954
 
        d = new Private(this);
955
 
}
956
 
 
957
 
ConsolePrompt::~ConsolePrompt()
958
 
{
959
 
        delete d;
960
 
}
961
 
 
962
 
void ConsolePrompt::getHidden(const QString &promptStr)
963
 
{
964
 
        d->reset();
965
 
 
966
 
        d->promptStr = promptStr;
967
 
        if(!d->start(false))
968
 
        {
969
 
                QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
970
 
                return;
971
 
        }
972
 
}
973
 
 
974
 
void ConsolePrompt::getChar()
975
 
{
976
 
        d->reset();
977
 
 
978
 
        if(!d->start(true))
979
 
        {
980
 
                QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
981
 
                return;
982
 
        }
983
 
}
984
 
 
985
 
void ConsolePrompt::waitForFinished()
986
 
{
987
 
        // reparent the Console under us (for Synchronizer)
988
 
        QObject *orig_parent = d->con->parent();
989
 
        d->con->setParent(this);
990
 
 
991
 
        // block while prompting
992
 
        d->waiting = true;
993
 
        d->sync.waitForCondition();
994
 
        d->waiting = false;
995
 
 
996
 
        // restore parent (if con still exists)
997
 
        if(d->con)
998
 
                d->con->setParent(orig_parent);
999
 
}
1000
 
 
1001
 
SecureArray ConsolePrompt::result() const
1002
 
{
1003
 
        return d->result;
1004
 
}
1005
 
 
1006
 
QChar ConsolePrompt::resultChar() const
1007
 
{
1008
 
        QString str = QString::fromUtf8(d->result.toByteArray());
1009
 
 
1010
 
        // this will never happen if getChar completes
1011
 
        if(str.isEmpty())
1012
 
                return QChar();
1013
 
 
1014
 
        return str[0];
1015
 
}
1016
 
 
1017
 
}
1018
 
 
1019
 
#include "console.moc"