• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDE Support
  • Sitemap
  • Contact Us
 

qca

console.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006,2007  Justin Karneges <justin@affinix.com>
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301  USA
00018  *
00019  */
00020 
00021 #include "qca_support.h"
00022 
00023 #include "qpipe.h"
00024 #include "qca_safeobj.h"
00025 
00026 #include <QPointer>
00027 #include <QTextCodec>
00028 #include <QMutex>
00029 
00030 #ifdef Q_OS_WIN
00031 # include <windows.h>
00032 #else
00033 # include <sys/termios.h>
00034 # include <unistd.h>
00035 # include <fcntl.h>
00036 # include <stdlib.h>
00037 #endif
00038 
00039 #include <stdio.h>
00040 
00041 #define CONSOLEPROMPT_INPUT_MAX 56
00042 
00043 Q_DECLARE_METATYPE(QCA::SecureArray)
00044 
00045 namespace QCA {
00046 
00047 //----------------------------------------------------------------------------
00048 // ConsoleWorker
00049 //----------------------------------------------------------------------------
00050 class ConsoleWorker : public QObject
00051 {
00052     Q_OBJECT
00053 private:
00054     QPipeEnd in, out;
00055     bool started;
00056     QByteArray in_left, out_left;
00057 
00058 public:
00059     ConsoleWorker(QObject *parent = 0) : QObject(parent), in(this), out(this)
00060     {
00061         started = false;
00062     }
00063 
00064     ~ConsoleWorker()
00065     {
00066         stop();
00067     }
00068 
00069     void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id)
00070     {
00071         Q_ASSERT(!started);
00072 
00073         if(in_id != INVALID_Q_PIPE_ID)
00074         {
00075             in.take(in_id, QPipeDevice::Read);
00076             connect(&in, SIGNAL(readyRead()), SLOT(in_readyRead()));
00077             connect(&in, SIGNAL(closed()), SLOT(in_closed()));
00078             connect(&in, SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(in_error(QCA::QPipeEnd::Error)));
00079             in.enable();
00080         }
00081 
00082         if(out_id != INVALID_Q_PIPE_ID)
00083         {
00084             out.take(out_id, QPipeDevice::Write);
00085             connect(&out, SIGNAL(bytesWritten(int)), SLOT(out_bytesWritten(int)));
00086             connect(&out, SIGNAL(closed()), SLOT(out_closed()));
00087             out.enable();
00088         }
00089 
00090         started = true;
00091     }
00092 
00093     void stop()
00094     {
00095         if(!started)
00096             return;
00097 
00098         if(in.isValid())
00099             in.finalizeAndRelease();
00100         if(out.isValid())
00101             out.release();
00102 
00103         in_left = in.read();
00104         out_left = out.takeBytesToWrite();
00105 
00106         started = false;
00107     }
00108 
00109 public slots:
00110     bool isValid() const
00111     {
00112         return in.isValid();
00113     }
00114 
00115     void setSecurityEnabled(bool enabled)
00116     {
00117         if(in.isValid())
00118             in.setSecurityEnabled(enabled);
00119         if(out.isValid())
00120             out.setSecurityEnabled(enabled);
00121     }
00122 
00123     QByteArray read(int bytes = -1)
00124     {
00125         return in.read(bytes);
00126     }
00127 
00128     void write(const QByteArray &a)
00129     {
00130         out.write(a);
00131     }
00132 
00133     QCA::SecureArray readSecure(int bytes = -1)
00134     {
00135         return in.readSecure(bytes);
00136     }
00137 
00138     void writeSecure(const QCA::SecureArray &a)
00139     {
00140         out.writeSecure(a);
00141     }
00142 
00143     void closeOutput()
00144     {
00145         out.close();
00146     }
00147 
00148     int bytesAvailable() const
00149     {
00150         return in.bytesAvailable();
00151     }
00152 
00153     int bytesToWrite() const
00154     {
00155         return in.bytesToWrite();
00156     }
00157 
00158 public:
00159     QByteArray takeBytesToRead()
00160     {
00161         QByteArray a = in_left;
00162         in_left.clear();
00163         return a;
00164     }
00165 
00166     QByteArray takeBytesToWrite()
00167     {
00168         QByteArray a = out_left;
00169         out_left.clear();
00170         return a;
00171     }
00172 
00173 signals:
00174     void readyRead();
00175     void bytesWritten(int bytes);
00176     void inputClosed();
00177     void outputClosed();
00178 
00179 private slots:
00180     void in_readyRead()
00181     {
00182         emit readyRead();
00183     }
00184 
00185     void out_bytesWritten(int bytes)
00186     {
00187         emit bytesWritten(bytes);
00188     }
00189 
00190     void in_closed()
00191     {
00192         emit inputClosed();
00193     }
00194 
00195     void in_error(QCA::QPipeEnd::Error)
00196     {
00197         emit inputClosed();
00198     }
00199 
00200     void out_closed()
00201     {
00202         emit outputClosed();
00203     }
00204 };
00205 
00206 //----------------------------------------------------------------------------
00207 // ConsoleThread
00208 //----------------------------------------------------------------------------
00209 class ConsoleThread : public SyncThread
00210 {
00211     Q_OBJECT
00212 public:
00213     ConsoleWorker *worker;
00214     Q_PIPE_ID _in_id, _out_id;
00215     QByteArray in_left, out_left;
00216     QMutex call_mutex;
00217 
00218     ConsoleThread(QObject *parent = 0) : SyncThread(parent)
00219     {
00220         qRegisterMetaType<SecureArray>("QCA::SecureArray");
00221     }
00222 
00223     ~ConsoleThread()
00224     {
00225         stop();
00226     }
00227 
00228     void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id)
00229     {
00230         _in_id = in_id;
00231         _out_id = out_id;
00232         SyncThread::start();
00233     }
00234 
00235     void stop()
00236     {
00237         SyncThread::stop();
00238     }
00239 
00240     QVariant mycall(QObject *obj, const char *method, const QVariantList &args = QVariantList())
00241     {
00242         QVariant ret;
00243         bool ok;
00244 
00245         call_mutex.lock();
00246         ret = call(obj, method, args, &ok);
00247         call_mutex.unlock();
00248 
00249         Q_ASSERT(ok);
00250         if(!ok)
00251         {
00252             fprintf(stderr, "QCA: ConsoleWorker call [%s] failed.\n", method);
00253             abort();
00254             return QVariant();
00255         }
00256         return ret;
00257     }
00258 
00259     bool isValid()
00260     {
00261         return mycall(worker, "isValid").toBool();
00262     }
00263 
00264     void setSecurityEnabled(bool enabled)
00265     {
00266         mycall(worker, "setSecurityEnabled", QVariantList() << enabled);
00267     }
00268 
00269     QByteArray read(int bytes = -1)
00270     {
00271         return mycall(worker, "read", QVariantList() << bytes).toByteArray();
00272     }
00273 
00274     void write(const QByteArray &a)
00275     {
00276         mycall(worker, "write", QVariantList() << a);
00277     }
00278 
00279     SecureArray readSecure(int bytes = -1)
00280     {
00281         return qVariantValue<SecureArray>(mycall(worker, "readSecure", QVariantList() << bytes));
00282     }
00283 
00284     void writeSecure(const SecureArray &a)
00285     {
00286         mycall(worker, "writeSecure", QVariantList() << qVariantFromValue<SecureArray>(a));
00287     }
00288 
00289     void closeOutput()
00290     {
00291         mycall(worker, "closeOutput");
00292     }
00293 
00294     int bytesAvailable()
00295     {
00296         return mycall(worker, "bytesAvailable").toInt();
00297     }
00298 
00299     int bytesToWrite()
00300     {
00301         return mycall(worker, "bytesToWrite").toInt();
00302     }
00303 
00304     QByteArray takeBytesToRead()
00305     {
00306         QByteArray a = in_left;
00307         in_left.clear();
00308         return a;
00309     }
00310 
00311     QByteArray takeBytesToWrite()
00312     {
00313         QByteArray a = out_left;
00314         out_left.clear();
00315         return a;
00316     }
00317 
00318 signals:
00319     void readyRead();
00320     void bytesWritten(int);
00321     void inputClosed();
00322     void outputClosed();
00323 
00324 protected:
00325     virtual void atStart()
00326     {
00327         worker = new ConsoleWorker;
00328 
00329         // use direct connections here, so that the emits come from
00330         //   the other thread.  we can also connect to our own
00331         //   signals to avoid having to make slots just to emit.
00332         connect(worker, SIGNAL(readyRead()), SIGNAL(readyRead()), Qt::DirectConnection);
00333         connect(worker, SIGNAL(bytesWritten(int)), SIGNAL(bytesWritten(int)), Qt::DirectConnection);
00334         connect(worker, SIGNAL(inputClosed()), SIGNAL(inputClosed()), Qt::DirectConnection);
00335         connect(worker, SIGNAL(outputClosed()), SIGNAL(outputClosed()), Qt::DirectConnection);
00336 
00337         worker->start(_in_id, _out_id);
00338     }
00339 
00340     virtual void atEnd()
00341     {
00342         in_left = worker->takeBytesToRead();
00343         out_left = worker->takeBytesToWrite();
00344         delete worker;
00345     }
00346 };
00347 
00348 //----------------------------------------------------------------------------
00349 // Console
00350 //----------------------------------------------------------------------------
00351 class ConsolePrivate : public QObject
00352 {
00353     Q_OBJECT
00354 public:
00355     Console *q;
00356 
00357     bool started;
00358     Console::Type type;
00359     Console::ChannelMode cmode;
00360     Console::TerminalMode mode;
00361     ConsoleThread *thread;
00362     ConsoleReference *ref;
00363     Q_PIPE_ID in_id;
00364 
00365 #ifdef Q_OS_WIN
00366     DWORD old_mode;
00367 #else
00368     struct termios old_term_attr;
00369 #endif
00370 
00371     ConsolePrivate(Console *_q) : QObject(_q), q(_q)
00372     {
00373         started = false;
00374         mode = Console::Default;
00375         thread = new ConsoleThread(this);
00376         ref = 0;
00377     }
00378 
00379     ~ConsolePrivate()
00380     {
00381         delete thread;
00382         setInteractive(Console::Default);
00383     }
00384 
00385     void setInteractive(Console::TerminalMode m)
00386     {
00387         // no change
00388         if(m == mode)
00389             return;
00390 
00391         if(m == Console::Interactive)
00392         {
00393 #ifdef Q_OS_WIN
00394             GetConsoleMode(in_id, &old_mode);
00395             SetConsoleMode(in_id, old_mode & (~ENABLE_LINE_INPUT & ~ENABLE_ECHO_INPUT));
00396 #else
00397             int fd = in_id;
00398             struct termios attr;
00399             tcgetattr(fd, &attr);
00400             old_term_attr = attr;
00401 
00402             attr.c_lflag &= ~(ECHO);    // turn off the echo flag
00403             attr.c_lflag &= ~(ICANON);  // no wait for a newline
00404             attr.c_cc[VMIN] = 1;        // read at least 1 char
00405             attr.c_cc[VTIME] = 0;       // set wait time to zero
00406 
00407             // set the new attributes
00408             tcsetattr(fd, TCSAFLUSH, &attr);
00409 #endif
00410         }
00411         else
00412         {
00413 #ifdef Q_OS_WIN
00414             SetConsoleMode(in_id, old_mode);
00415 #else
00416             int fd = in_id;
00417             tcsetattr(fd, TCSANOW, &old_term_attr);
00418 #endif
00419         }
00420 
00421         mode = m;
00422     }
00423 };
00424 
00425 static Console *g_tty_console = 0, *g_stdio_console = 0;
00426 
00427 Console::Console(Type type, ChannelMode cmode, TerminalMode tmode, QObject *parent)
00428 :QObject(parent)
00429 {
00430     if(type == Tty)
00431     {
00432         Q_ASSERT(g_tty_console == 0);
00433         g_tty_console = this;
00434     }
00435     else
00436     {
00437         Q_ASSERT(g_stdio_console == 0);
00438         g_stdio_console = this;
00439     }
00440 
00441     d = new ConsolePrivate(this);
00442     d->type = type;
00443     d->cmode = cmode;
00444 
00445     Q_PIPE_ID in = INVALID_Q_PIPE_ID;
00446     Q_PIPE_ID out = INVALID_Q_PIPE_ID;
00447 
00448 #ifdef Q_OS_WIN
00449     if(type == Tty)
00450     {
00451         in = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE,
00452             FILE_SHARE_READ | FILE_SHARE_WRITE, false,
00453             OPEN_EXISTING, 0, NULL);
00454     }
00455     else
00456     {
00457         in = GetStdHandle(STD_INPUT_HANDLE);
00458     }
00459 #else
00460     if(type == Tty)
00461     {
00462         in = open("/dev/tty", O_RDONLY);
00463     }
00464     else
00465     {
00466         in = 0; // stdin
00467     }
00468 #endif
00469     if(cmode == ReadWrite)
00470     {
00471 #ifdef Q_OS_WIN
00472         if(type == Tty)
00473         {
00474             out = CreateFileA("CONOUT$",
00475                 GENERIC_READ | GENERIC_WRITE,
00476                 FILE_SHARE_READ | FILE_SHARE_WRITE, false,
00477                 OPEN_EXISTING, 0, NULL);
00478         }
00479         else
00480         {
00481             out = GetStdHandle(STD_OUTPUT_HANDLE);
00482         }
00483 #else
00484         if(type == Tty)
00485         {
00486             out = open("/dev/tty", O_WRONLY);
00487         }
00488         else
00489         {
00490             out = 1; // stdout
00491         }
00492 #endif
00493     }
00494 
00495     d->in_id = in;
00496     d->setInteractive(tmode);
00497     d->thread->start(in, out);
00498 }
00499 
00500 Console::~Console()
00501 {
00502     release();
00503     Console::Type type = d->type;
00504     delete d;
00505     if(type == Tty)
00506         g_tty_console = 0;
00507     else
00508         g_stdio_console = 0;
00509 }
00510 
00511 Console::Type Console::type() const
00512 {
00513     return d->type;
00514 }
00515 
00516 Console::ChannelMode Console::channelMode() const
00517 {
00518     return d->cmode;
00519 }
00520 
00521 Console::TerminalMode Console::terminalMode() const
00522 {
00523     return d->mode;
00524 }
00525 
00526 bool Console::isStdinRedirected()
00527 {
00528 #ifdef Q_OS_WIN
00529     HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
00530     DWORD mode;
00531     if(GetConsoleMode(h, &mode))
00532         return false;
00533     return true;
00534 #else
00535     return (isatty(0) ? false : true); // 0 == stdin
00536 #endif
00537 }
00538 
00539 bool Console::isStdoutRedirected()
00540 {
00541 #ifdef Q_OS_WIN
00542     HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
00543     DWORD mode;
00544     if(GetConsoleMode(h, &mode))
00545         return false;
00546     return true;
00547 #else
00548     return (isatty(1) ? false : true); // 1 == stdout
00549 #endif
00550 }
00551 
00552 Console *Console::ttyInstance()
00553 {
00554     return g_tty_console;
00555 }
00556 
00557 Console *Console::stdioInstance()
00558 {
00559     return g_stdio_console;
00560 }
00561 
00562 void Console::release()
00563 {
00564     d->thread->stop();
00565 }
00566 
00567 QByteArray Console::bytesLeftToRead()
00568 {
00569     return d->thread->takeBytesToRead();
00570 }
00571 
00572 QByteArray Console::bytesLeftToWrite()
00573 {
00574     return d->thread->takeBytesToWrite();
00575 }
00576 
00577 //----------------------------------------------------------------------------
00578 // ConsoleReference
00579 //----------------------------------------------------------------------------
00580 class ConsoleReferencePrivate : public QObject
00581 {
00582     Q_OBJECT
00583 public:
00584     ConsoleReference *q;
00585 
00586     Console *console;
00587     ConsoleThread *thread;
00588     ConsoleReference::SecurityMode smode;
00589     SafeTimer lateTrigger;
00590     bool late_read, late_close;
00591 
00592     ConsoleReferencePrivate(ConsoleReference *_q) : QObject(_q), q(_q), lateTrigger(this)
00593     {
00594         console = 0;
00595         thread = 0;
00596         connect(&lateTrigger, SIGNAL(timeout()), SLOT(doLate()));
00597         lateTrigger.setSingleShot(true);
00598     }
00599 
00600 private slots:
00601     void doLate()
00602     {
00603         QPointer<QObject> self = this;
00604         if(late_read)
00605             emit q->readyRead();
00606         if(!self)
00607             return;
00608         if(late_close)
00609             emit q->inputClosed();
00610     }
00611 };
00612 
00613 ConsoleReference::ConsoleReference(QObject *parent)
00614 :QObject(parent)
00615 {
00616     d = new ConsoleReferencePrivate(this);
00617 }
00618 
00619 ConsoleReference::~ConsoleReference()
00620 {
00621     stop();
00622     delete d;
00623 }
00624 
00625 bool ConsoleReference::start(Console *console, SecurityMode mode)
00626 {
00627     // make sure this reference isn't using a console already
00628     Q_ASSERT(!d->console);
00629 
00630     // one console reference at a time
00631     Q_ASSERT(console->d->ref == 0);
00632 
00633     // let's take it
00634     d->console = console;
00635     d->thread = d->console->d->thread;
00636     d->console->d->ref = this;
00637 
00638     bool valid = d->thread->isValid();
00639     int avail = d->thread->bytesAvailable();
00640 
00641     // pipe already closed and no data?  consider this an error
00642     if(!valid && avail == 0)
00643     {
00644         d->console->d->ref = 0;
00645         d->thread = 0;
00646         d->console = 0;
00647         return false;
00648     }
00649 
00650     // enable security?  it will last for this active session only
00651     d->smode = mode;
00652     if(mode == SecurityEnabled)
00653         d->thread->setSecurityEnabled(true);
00654 
00655     connect(d->thread, SIGNAL(readyRead()), SIGNAL(readyRead()));
00656     connect(d->thread, SIGNAL(bytesWritten(int)), SIGNAL(bytesWritten(int)));
00657     connect(d->thread, SIGNAL(inputClosed()), SIGNAL(inputClosed()));
00658     connect(d->thread, SIGNAL(outputClosed()), SIGNAL(outputClosed()));
00659 
00660     d->late_read = false;
00661     d->late_close = false;
00662 
00663     if(avail > 0)
00664         d->late_read = true;
00665 
00666     if(!valid)
00667         d->late_close = true;
00668 
00669     if(d->late_read || d->late_close)
00670         d->lateTrigger.start();
00671 
00672     return true;
00673 }
00674 
00675 void ConsoleReference::stop()
00676 {
00677     if(!d->console)
00678         return;
00679 
00680     d->lateTrigger.stop();
00681 
00682     disconnect(d->thread, 0, this, 0);
00683 
00684     // automatically disable security when we go inactive
00685     d->thread->setSecurityEnabled(false);
00686 
00687     d->console->d->ref = 0;
00688     d->thread = 0;
00689     d->console = 0;
00690 }
00691 
00692 Console *ConsoleReference::console() const
00693 {
00694     return d->console;
00695 }
00696 
00697 ConsoleReference::SecurityMode ConsoleReference::securityMode() const
00698 {
00699     return d->smode;
00700 }
00701 
00702 QByteArray ConsoleReference::read(int bytes)
00703 {
00704     return d->thread->read(bytes);
00705 }
00706 
00707 void ConsoleReference::write(const QByteArray &a)
00708 {
00709     d->thread->write(a);
00710 }
00711 
00712 SecureArray ConsoleReference::readSecure(int bytes)
00713 {
00714     return d->thread->readSecure(bytes);
00715 }
00716 
00717 void ConsoleReference::writeSecure(const SecureArray &a)
00718 {
00719     d->thread->writeSecure(a);
00720 }
00721 
00722 void ConsoleReference::closeOutput()
00723 {
00724     d->thread->closeOutput();
00725 }
00726 
00727 int ConsoleReference::bytesAvailable() const
00728 {
00729     return d->thread->bytesAvailable();
00730 }
00731 
00732 int ConsoleReference::bytesToWrite() const
00733 {
00734     return d->thread->bytesToWrite();
00735 }
00736 
00737 //----------------------------------------------------------------------------
00738 // ConsolePrompt
00739 //----------------------------------------------------------------------------
00740 class ConsolePrompt::Private : public QObject
00741 {
00742     Q_OBJECT
00743 public:
00744     ConsolePrompt *q;
00745 
00746     Synchronizer sync;
00747     Console *con;
00748     bool own_con;
00749     ConsoleReference console;
00750     QString promptStr;
00751     SecureArray result;
00752     bool waiting;
00753     int at;
00754     bool done;
00755     bool charMode;
00756     QTextCodec *codec;
00757     QTextCodec::ConverterState *encstate, *decstate;
00758 
00759     Private(ConsolePrompt *_q) : QObject(_q), q(_q), sync(_q), console(this)
00760     {
00761         connect(&console, SIGNAL(readyRead()), SLOT(con_readyRead()));
00762         connect(&console, SIGNAL(inputClosed()), SLOT(con_inputClosed()));
00763 
00764         con = 0;
00765         own_con = false;
00766         waiting = false;
00767 
00768 #ifdef Q_OS_WIN
00769         codec = QTextCodec::codecForMib(106); // UTF-8
00770 #else
00771         codec = QTextCodec::codecForLocale();
00772 #endif
00773         encstate = 0;
00774         decstate = 0;
00775     }
00776 
00777     ~Private()
00778     {
00779         reset();
00780     }
00781 
00782     void reset()
00783     {
00784         delete encstate;
00785         encstate = 0;
00786         delete decstate;
00787         decstate = 0;
00788 
00789         console.stop();
00790         if(own_con)
00791         {
00792             delete con;
00793             con = 0;
00794             own_con = false;
00795         }
00796     }
00797 
00798     bool start(bool _charMode)
00799     {
00800         own_con = false;
00801         con = Console::ttyInstance();
00802         if(!con)
00803         {
00804             con = new Console(Console::Tty, Console::ReadWrite, Console::Interactive);
00805             own_con = true;
00806         }
00807 
00808         result.clear();
00809         at = 0;
00810         done = false;
00811         charMode = _charMode;
00812 
00813         encstate = new QTextCodec::ConverterState(QTextCodec::IgnoreHeader);
00814         decstate = new QTextCodec::ConverterState(QTextCodec::IgnoreHeader);
00815 
00816         if(!console.start(con, ConsoleReference::SecurityEnabled))
00817         {
00818             reset();
00819             fprintf(stderr, "Console input not available or closed\n");
00820             return false;
00821         }
00822 
00823         if(!charMode)
00824             writeString(promptStr + ": ");
00825 
00826         return true;
00827     }
00828 
00829     void writeString(const QString &str)
00830     {
00831         console.writeSecure(codec->fromUnicode(str.unicode(), str.length(), encstate));
00832     }
00833 
00834     // process each char.  internally store the result as utf16, which
00835     //   is easier to edit (e.g. backspace)
00836     bool processChar(QChar c)
00837     {
00838         if(charMode)
00839         {
00840             appendChar(c);
00841             done = true;
00842             return false;
00843         }
00844 
00845         if(c == '\r' || c == '\n')
00846         {
00847             writeString("\n");
00848             done = true;
00849             return false;
00850         }
00851 
00852         if(c == '\b' || c == 0x7f)
00853         {
00854             if(at > 0)
00855             {
00856                 --at;
00857                 writeString("\b \b");
00858                 result.resize(at * sizeof(ushort));
00859             }
00860             return true;
00861         }
00862         else if(c < 0x20)
00863             return true;
00864 
00865         if(at >= CONSOLEPROMPT_INPUT_MAX)
00866             return true;
00867 
00868         appendChar(c);
00869 
00870         writeString("*");
00871         return true;
00872     }
00873 
00874     void appendChar(QChar c)
00875     {
00876         if((at + 1) * (int)sizeof(ushort) > result.size())
00877             result.resize((at + 1) * sizeof(ushort));
00878         ushort *p = (ushort *)result.data();
00879         p[at++] = c.unicode();
00880     }
00881 
00882     void convertToUtf8()
00883     {
00884         // convert result from utf16 to utf8, securely
00885         QTextCodec *codec = QTextCodec::codecForMib(106);
00886         QTextCodec::ConverterState cstate(QTextCodec::IgnoreHeader);
00887         SecureArray out;
00888         ushort *ustr = (ushort *)result.data();
00889         int len = result.size() / sizeof(ushort);
00890         for(int n = 0; n < len; ++n)
00891         {
00892             QChar c(ustr[n]);
00893             out += codec->fromUnicode(&c, 1, &cstate);
00894         }
00895         result = out;
00896     }
00897 
00898 private slots:
00899     void con_readyRead()
00900     {
00901         while(console.bytesAvailable() > 0)
00902         {
00903             SecureArray buf = console.readSecure(1);
00904             if(buf.isEmpty())
00905                 break;
00906 
00907             // convert to unicode and process
00908             QString str = codec->toUnicode(buf.data(), 1, decstate);
00909             bool quit = false;
00910             for(int n = 0; n < str.length(); ++n)
00911             {
00912                 if(!processChar(str[n]))
00913                 {
00914                     quit = true;
00915                     break;
00916                 }
00917             }
00918             if(quit)
00919                 break;
00920         }
00921 
00922         if(done)
00923         {
00924             convertToUtf8();
00925 
00926             reset();
00927             if(waiting)
00928                 sync.conditionMet();
00929             else
00930                 emit q->finished();
00931         }
00932     }
00933 
00934     void con_inputClosed()
00935     {
00936         fprintf(stderr, "Console input closed\n");
00937         if(!done)
00938         {
00939             done = true;
00940             result.clear();
00941 
00942             reset();
00943             if(waiting)
00944                 sync.conditionMet();
00945             else
00946                 emit q->finished();
00947         }
00948     }
00949 };
00950 
00951 ConsolePrompt::ConsolePrompt(QObject *parent)
00952 :QObject(parent)
00953 {
00954     d = new Private(this);
00955 }
00956 
00957 ConsolePrompt::~ConsolePrompt()
00958 {
00959     delete d;
00960 }
00961 
00962 void ConsolePrompt::getHidden(const QString &promptStr)
00963 {
00964     d->reset();
00965 
00966     d->promptStr = promptStr;
00967     if(!d->start(false))
00968     {
00969         QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
00970         return;
00971     }
00972 }
00973 
00974 void ConsolePrompt::getChar()
00975 {
00976     d->reset();
00977 
00978     if(!d->start(true))
00979     {
00980         QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
00981         return;
00982     }
00983 }
00984 
00985 void ConsolePrompt::waitForFinished()
00986 {
00987     // reparent the Console under us (for Synchronizer)
00988     QObject *orig_parent = d->con->parent();
00989     d->con->setParent(this);
00990 
00991     // block while prompting
00992     d->waiting = true;
00993     d->sync.waitForCondition();
00994     d->waiting = false;
00995 
00996     // restore parent (if con still exists)
00997     if(d->con)
00998         d->con->setParent(orig_parent);
00999 }
01000 
01001 SecureArray ConsolePrompt::result() const
01002 {
01003     return d->result;
01004 }
01005 
01006 QChar ConsolePrompt::resultChar() const
01007 {
01008     QString str = QString::fromUtf8(d->result.toByteArray());
01009 
01010     // this will never happen if getChar completes
01011     if(str.isEmpty())
01012         return QChar();
01013 
01014     return str[0];
01015 }
01016 
01017 }
01018 
01019 #include "console.moc"

qca

Skip menu "qca"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE Support

Skip menu "KDE Support"
  • akonadi
  • Decibel
  • grantlee
  • kdewin
  • phonon
  •     Backend
  • polkit-qt
  • qca
  • qimageblitz
  • soprano
  • strigi
  •     searchclient
  •     streamanalyzer
  •     streams
Generated for KDE Support by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal