4
0
mirror of https://github.com/QuasarApp/qca.git synced 2025-05-11 10:19:33 +00:00

new event system

svn path=/trunk/kdesupport/qca/; revision=527107
This commit is contained in:
Justin Karneges 2006-04-06 21:43:31 +00:00
parent a88fb079f8
commit 6a0884f267
2 changed files with 736 additions and 0 deletions
include/QtCrypto
src

@ -967,6 +967,134 @@ namespace QCA
*/
InitializationVector(const QByteArray &a);
};
class QCA_EXPORT Event
{
public:
enum Type
{
Password, ///< Asking for a password
Token ///< Asking for a token
};
enum Source
{
KeyStore, ///< KeyStore generated the event
Data ///< File/bytearray generated the event
};
enum PasswordStyle
{
StylePassword, ///< User should be prompted for a "Password"
StylePassphrase, ///< User should be prompted for a "Passphrase"
StylePIN ///< User should be prompted for a "PIN"
};
Event();
Event(const Event &from);
~Event();
Event & operator=(const Event &from);
bool isNull() const;
Type type() const;
Source source() const;
PasswordStyle passwordStyle() const;
QString keyStoreId() const;
QString keyStoreEntryId() const;
QString fileName() const;
void *ptr() const;
void setPasswordKeyStore(PasswordStyle pstyle, const QString &keyStoreId, const QString &keyStoreEntryId, void *ptr);
void setPasswordData(PasswordStyle pstyle, const QString &fileName, void *ptr);
void setToken(const QString &keyStoreEntryId, void *ptr);
private:
class Private;
QSharedDataPointer<Private> d;
};
class EventHandlerPrivate;
class PasswordAsker;
class PasswordAskerPrivate;
class TokenAsker;
class TokenAskerPrivate;
class AskerItem;
class QCA_EXPORT EventHandler : public QObject
{
Q_OBJECT
public:
EventHandler(QObject *parent = 0);
~EventHandler();
void start();
void submitPassword(int id, const QSecureArray &password);
void tokenOkay(int id);
void reject(int id);
signals:
void eventReady(int id, const QCA::Event &context);
private:
friend class EventHandlerPrivate;
EventHandlerPrivate *d;
friend class PasswordAsker;
friend class PasswordAskerPrivate;
friend class TokenAsker;
friend class AskerItem;
};
class QCA_EXPORT PasswordAsker : public QObject
{
Q_OBJECT
public:
PasswordAsker(QObject *parent = 0);
~PasswordAsker();
void ask(Event::PasswordStyle pstyle, const QString &keyStoreId, const QString &keyStoreEntryId, void *ptr);
void ask(Event::PasswordStyle pstyle, const QString &fileName, void *ptr);
void cancel();
void waitForResponse();
bool accepted() const;
QSecureArray password() const;
signals:
void responseReady();
private:
friend class PasswordAskerPrivate;
PasswordAskerPrivate *d;
friend class AskerItem;
};
class QCA_EXPORT TokenAsker : public QObject
{
Q_OBJECT
public:
TokenAsker(QObject *parent = 0);
~TokenAsker();
void ask(const QString &keyStoreEntryId, void *ptr);
void cancel();
void waitForResponse();
bool accepted() const;
signals:
void responseReady();
private:
friend class TokenAskerPrivate;
TokenAskerPrivate *d;
friend class AskerItem;
};
}
#endif

@ -966,4 +966,612 @@ InitializationVector::InitializationVector(const QByteArray &a)
set(QSecureArray(a));
}
//----------------------------------------------------------------------------
// Event
//----------------------------------------------------------------------------
class Event::Private : public QSharedData
{
public:
Type type;
Source source;
PasswordStyle style;
QString ks, kse;
QString fname;
void *ptr;
};
Event::Event()
{
}
Event::Event(const Event &from)
:d(from.d)
{
}
Event::~Event()
{
}
Event & Event::operator=(const Event &from)
{
d = from.d;
return *this;
}
bool Event::isNull() const
{
return (d ? false : true);
}
Event::Type Event::type() const
{
return d->type;
}
Event::Source Event::source() const
{
return d->source;
}
Event::PasswordStyle Event::passwordStyle() const
{
return d->style;
}
QString Event::keyStoreId() const
{
return d->ks;
}
QString Event::keyStoreEntryId() const
{
return d->kse;
}
QString Event::fileName() const
{
return d->fname;
}
void *Event::ptr() const
{
return d->ptr;
}
void Event::setPasswordKeyStore(PasswordStyle pstyle, const QString &keyStoreId, const QString &keyStoreEntryId, void *ptr)
{
if(!d)
d = new Private;
d->type = Password;
d->source = KeyStore;
d->style = pstyle;
d->ks = keyStoreId;
d->kse = keyStoreEntryId;
d->fname = QString();
d->ptr = ptr;
}
void Event::setPasswordData(PasswordStyle pstyle, const QString &fileName, void *ptr)
{
if(!d)
d = new Private;
d->type = Password;
d->source = Data;
d->style = pstyle;
d->ks = QString();
d->kse = QString();
d->fname = fileName;
d->ptr = ptr;
}
void Event::setToken(const QString &keyStoreEntryId, void *ptr)
{
if(!d)
d = new Private;
d->type = Token;
d->source = KeyStore;
d->style = StylePassword;
d->ks = QString();
d->kse = keyStoreEntryId;
d->fname = QString();
d->ptr = ptr;
}
//----------------------------------------------------------------------------
// EventHandler
//----------------------------------------------------------------------------
class AskerItem : public QObject
{
Q_OBJECT
public:
enum Type { Password, Token };
Type type;
PasswordAsker *passwordAsker;
TokenAsker *tokenAsker;
bool accepted;
QSecureArray password;
int id;
bool waiting;
bool done;
QTimer readyTrigger;
QMutex m;
QWaitCondition w;
QThread *emitFrom;
QList<EventHandler*> handlers;
AskerItem(QObject *parent = 0);
~AskerItem();
void ask(const Event &e);
void handlerGone(EventHandler *h);
void unreg();
void waitForFinished();
void finish();
// handler calls this
void accept_password(const QSecureArray &_password);
void accept_token();
void reject();
private slots:
void ready_timeout();
};
Q_GLOBAL_STATIC(QMutex, g_event_mutex)
class EventGlobal;
static EventGlobal *g_event = 0;
class EventGlobal
{
public:
QList<EventHandler*> handlers;
int next_id;
EventGlobal()
{
next_id = 0;
}
static void ensureInit()
{
if(g_event)
return;
g_event = new EventGlobal;
}
static void tryCleanup()
{
if(!g_event)
return;
if(g_event->handlers.isEmpty() /*&& g_event->askers.isEmpty()*/)
{
delete g_event;
g_event = 0;
}
}
};
class EventHandlerPrivate
{
public:
bool started;
QHash<int,AskerItem*> askers;
QMutex m;
EventHandlerPrivate()
{
started = false;
}
};
EventHandler::EventHandler(QObject *parent)
:QObject(parent)
{
d = new EventHandlerPrivate;
}
EventHandler::~EventHandler()
{
//MX QMutexLocker locker(&d->m);
if(d->started)
{
for(int n = 0; n < d->askers.count(); ++n)
{
d->askers[n]->handlerGone(this);
}
/*if(d->askers.isEmpty())
{
// if this flag is set, then AskerItem::ask() will do
// the global cleanup instead of us.
//g_event->deleteLaterList += this;
}
else
{*/
QMutexLocker locker(g_event_mutex());
g_event->handlers.removeAll(this);
EventGlobal::tryCleanup();
//}
}
delete d;
}
void EventHandler::start()
{
QMutexLocker locker(g_event_mutex());
EventGlobal::ensureInit();
d->started = true;
g_event->handlers += this;
}
void EventHandler::submitPassword(int id, const QSecureArray &password)
{
//MX QMutexLocker locker(&d->m);
AskerItem *ai = d->askers.value(id);
if(!ai || ai->type != AskerItem::Password)
return;
ai->accept_password(password);
}
void EventHandler::tokenOkay(int id)
{
//MX QMutexLocker locker(&d->m);
AskerItem *ai = d->askers.value(id);
if(!ai || ai->type != AskerItem::Token)
return;
ai->accept_token();
}
void EventHandler::reject(int id)
{
//MX QMutexLocker locker(&d->m);
AskerItem *ai = d->askers.value(id);
if(!ai)
return;
ai->reject();
}
//----------------------------------------------------------------------------
// PasswordAsker
//----------------------------------------------------------------------------
class PasswordAskerPrivate
{
public:
AskerItem *ai;
PasswordAskerPrivate()
{
ai = 0;
}
~PasswordAskerPrivate()
{
delete ai;
}
};
PasswordAsker::PasswordAsker(QObject *parent)
:QObject(parent)
{
d = new PasswordAskerPrivate;
}
PasswordAsker::~PasswordAsker()
{
delete d;
}
void PasswordAsker::ask(Event::PasswordStyle pstyle, const QString &keyStoreId, const QString &keyStoreEntryId, void *ptr)
{
Event e;
e.setPasswordKeyStore(pstyle, keyStoreId, keyStoreEntryId, ptr);
delete d->ai;
d->ai = new AskerItem(this);
d->ai->type = AskerItem::Password;
d->ai->passwordAsker = this;
d->ai->ask(e);
}
void PasswordAsker::ask(Event::PasswordStyle pstyle, const QString &fileName, void *ptr)
{
Event e;
e.setPasswordData(pstyle, fileName, ptr);
delete d->ai;
d->ai = new AskerItem(this);
d->ai->type = AskerItem::Password;
d->ai->passwordAsker = this;
d->ai->ask(e);
}
void PasswordAsker::cancel()
{
delete d->ai;
d->ai = 0;
}
void PasswordAsker::waitForResponse()
{
d->ai->waitForFinished();
}
bool PasswordAsker::accepted() const
{
return d->ai->accepted;
}
QSecureArray PasswordAsker::password() const
{
return d->ai->password;
}
//----------------------------------------------------------------------------
// TokenAsker
//----------------------------------------------------------------------------
class TokenAskerPrivate
{
public:
AskerItem *ai;
TokenAskerPrivate()
{
ai = 0;
}
~TokenAskerPrivate()
{
delete ai;
}
};
TokenAsker::TokenAsker(QObject *parent)
:QObject(parent)
{
d = new TokenAskerPrivate;
}
TokenAsker::~TokenAsker()
{
delete d;
}
void TokenAsker::ask(const QString &keyStoreEntryId, void *ptr)
{
Event e;
e.setToken(keyStoreEntryId, ptr);
delete d->ai;
d->ai = new AskerItem(this);
d->ai->type = AskerItem::Token;
d->ai->tokenAsker = this;
d->ai->ask(e);
}
void TokenAsker::cancel()
{
delete d->ai;
d->ai = 0;
}
void TokenAsker::waitForResponse()
{
d->ai->waitForFinished();
}
bool TokenAsker::accepted() const
{
return d->ai->accepted;
}
//----------------------------------------------------------------------------
// AskerItem
//----------------------------------------------------------------------------
AskerItem::AskerItem(QObject *parent)
:QObject(parent), readyTrigger(this)
{
readyTrigger.setSingleShot(true);
connect(&readyTrigger, SIGNAL(timeout()), SLOT(ready_timeout()));
done = true;
emitFrom = 0;
}
AskerItem::~AskerItem()
{
if(!done)
unreg();
}
void AskerItem::ask(const Event &e)
{
accepted = false;
password = QSecureArray();
waiting = false;
done = false;
{
//MX QMutexLocker locker(g_event_mutex());
// no handlers? reject the request then
if(!g_event || g_event->handlers.isEmpty())
{
done = true;
readyTrigger.start();
return;
}
id = g_event->next_id++;
handlers = g_event->handlers;
//g_event->askers.insert(id, this);
}
/*{
QMutexLocker locker(g_event_mutex());
++g_event->emitrefs;
}*/
{
//MX QMutexLocker locker(&m);
for(int n = 0; n < handlers.count(); ++n)
{
//MX QMutexLocker locker(&handlers[n]->d->m);
handlers[n]->d->askers.insert(id, this);
}
emitFrom = QThread::currentThread();
for(int n = 0; n < handlers.count(); ++n)
{
EventHandler *h = handlers[n];
if(!h)
continue;
emit h->eventReady(id, e);
/*{
QMutexLocker locker(g_event->deleteLaterMutex);
if(g_event->deleteLaterList.contains(h))
{
g_event->deleteLaterList.removeAll(this);
g_event->handlers.removeAll(this);
--n; // adjust iterator
}
else
h->d->sync_emit = false;
}*/
if(done)
break;
}
emitFrom = 0;
}
/*{
QMutexLocker locker(g_event_mutex());
--g_event->emitrefs;
if(g_event->emitrefs == 0)
{*/
// clean up null handlers
for(int n = 0; n < handlers.count(); ++n)
{
if(handlers[n] == 0)
{
handlers.removeAt(n);
--n; // adjust position
}
}
/*}
}*/
if(done)
{
//MX QMutexLocker locker(&m);
unreg();
readyTrigger.start();
return;
}
}
void AskerItem::handlerGone(EventHandler *h)
{
if(QThread::currentThread() == emitFrom)
{
int n = handlers.indexOf(h);
if(n != -1)
handlers[n] = 0;
}
else
{
//MX QMutexLocker locker(&m);
handlers.removeAll(h);
}
}
void AskerItem::unreg()
{
//if(!done)
//{
//QMutexLocker locker(&m);
for(int n = 0; n < handlers.count(); ++n)
{
//MX QMutexLocker locker(&handlers[n]->d->m);
handlers[n]->d->askers.remove(id);
}
//}
}
void AskerItem::waitForFinished()
{
//MX QMutexLocker locker(&m);
if(done)
{
readyTrigger.stop();
return;
}
waiting = true;
w.wait(&m);
unreg();
}
void AskerItem::finish()
{
done = true;
if(waiting)
w.wakeOne();
else
{
if(type == Password)
emit passwordAsker->responseReady();
else // Token
emit tokenAsker->responseReady();
}
}
void AskerItem::accept_password(const QSecureArray &_password)
{
//MX QMutexLocker locker(&m);
accepted = true;
password = _password;
finish();
}
void AskerItem::accept_token()
{
//MX QMutexLocker locker(&m);
accepted = true;
finish();
}
void AskerItem::reject()
{
//MX QMutexLocker locker(&m);
finish();
}
void AskerItem::ready_timeout()
{
if(type == Password)
emit passwordAsker->responseReady();
else // Token
emit tokenAsker->responseReady();
}
}
#include "qca_core.moc"