00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "blobiohandler.h"
00025
00026 #include <QDBusArgument>
00027 #include <QBuffer>
00028 #include <QDataStream>
00029 #include <QDebug>
00030 #include <QDataStream>
00031
00032 #include "SignOn/signonplugincommon.h"
00033
00034 #define SIGNON_IPC_BUFFER_PAGE_SIZE 16384
00035
00036 using namespace SignOn;
00037
00038 BlobIOHandler::BlobIOHandler(QIODevice *readChannel,
00039 QIODevice *writeChannel,
00040 QObject *parent):
00041 QObject(parent),
00042 m_readChannel(readChannel),
00043 m_writeChannel(writeChannel),
00044 m_readNotifier(0),
00045 m_blobSize(-1),
00046 m_isReading(false)
00047 {
00048 }
00049
00050 void BlobIOHandler::setReadChannelSocketNotifier(QSocketNotifier *notifier)
00051 {
00052 if (notifier == 0)
00053 return;
00054
00055 m_readNotifier = notifier;
00056 }
00057
00058 bool BlobIOHandler::sendData(const QVariantMap &map)
00059 {
00060 if (m_writeChannel == 0) {
00061 TRACE() << "NULL write channel.";
00062 return false;
00063 }
00064
00065 QDataStream stream(m_writeChannel);
00066 QByteArray ba = variantMapToByteArray(map);
00067 stream << ba.size();
00068
00069 QVector<QByteArray> pages = pageByteArray(ba);
00070 for (int i = 0; i < pages.count(); ++i)
00071 stream << pages[i];
00072
00073 return true;
00074 }
00075
00076 void BlobIOHandler::setReadNotificationEnabled(bool enabled)
00077 {
00078 m_isReading = enabled;
00079 if (enabled) {
00080 if (m_readNotifier != 0) {
00081 connect(m_readNotifier, SIGNAL(activated(int)),
00082 this, SLOT(readBlob()));
00083 } else {
00084 connect(m_readChannel, SIGNAL(readyRead()),
00085 this, SLOT(readBlob()));
00086 }
00087 } else {
00088 if (m_readNotifier != 0) {
00089 disconnect(m_readNotifier, SIGNAL(activated(int)),
00090 this, SLOT(readBlob()));
00091 } else {
00092 disconnect(m_readChannel, SIGNAL(readyRead()),
00093 this, SLOT(readBlob()));
00094 }
00095 }
00096 }
00097
00098 void BlobIOHandler::receiveData(int expectedDataSize)
00099 {
00100 m_blobBuffer.clear();
00101 m_blobSize = expectedDataSize;
00102
00103
00104
00105 if (m_blobSize > SIGNON_IPC_BUFFER_PAGE_SIZE)
00106 setReadNotificationEnabled(true);
00107
00108 readBlob();
00109 }
00110
00111 void BlobIOHandler::readBlob()
00112 {
00113 QDataStream in(m_readChannel);
00114
00115 QByteArray fractionBa;
00116 in >> fractionBa;
00117 m_blobBuffer.append(fractionBa);
00118
00119
00120 if ((fractionBa.size() == 0) && (m_blobBuffer.size() < m_blobSize)) {
00121 setReadNotificationEnabled(false);
00122 emit error();
00123 return;
00124 }
00125
00126 if (m_blobBuffer.size() == m_blobSize) {
00127 QVariantMap sessionDataMap;
00128 sessionDataMap = byteArrayToVariantMap(m_blobBuffer);
00129
00130 if (m_blobSize > SIGNON_IPC_BUFFER_PAGE_SIZE)
00131 setReadNotificationEnabled(false);
00132
00133 emit dataReceived(sessionDataMap);
00134 }
00135 }
00136
00137 QVariantMap expandDBusArgumentValue(const QVariant &value, bool *success)
00138 {
00139
00140 QDBusArgument dbusValue = value.value<QDBusArgument>();
00141 QVariantMap converted;
00142 if (dbusValue.currentType() == QDBusArgument::MapType &&
00143
00144 dbusValue.currentSignature() == "a{sv}") {
00145 converted = qdbus_cast<QVariantMap>(dbusValue);
00146 } else {
00147 *success = false;
00148 return QVariantMap();
00149 }
00150
00151
00152
00153 QVariantMap returnValue;
00154 QVariantMap::const_iterator i;
00155 for (i = converted.constBegin(); i != converted.constEnd(); ++i) {
00156 if (qstrcmp(i.value().typeName(), "QDBusArgument") == 0) {
00157 QVariantMap convertedValue = expandDBusArgumentValue(i.value(), success);
00158 if (*success == false) {
00159
00160 return QVariantMap();
00161 }
00162 returnValue.insert(i.key(), convertedValue);
00163 } else {
00164 returnValue.insert(i.key(), i.value());
00165 }
00166 }
00167
00168 return returnValue;
00169 }
00170
00171 static QVariantMap filterOutComplexTypes(const QVariantMap &map)
00172 {
00173 QVariantMap filteredMap;
00174 QVariantMap::const_iterator i;
00175 for (i = map.constBegin(); i != map.constEnd(); i++) {
00176 if (qstrcmp(i.value().typeName(), "QDBusArgument") == 0) {
00177 bool success = true;
00178 QVariantMap convertedMap = expandDBusArgumentValue(i.value(), &success);
00179 if (success == false) {
00180
00181
00182
00183
00184
00185 BLAME() << "Found non-map QDBusArgument in data; skipping.";
00186 continue;
00187 }
00188 filteredMap.insert(i.key(), convertedMap);
00189 } else {
00190 filteredMap.insert(i.key(), i.value());
00191 }
00192 }
00193 return filteredMap;
00194 }
00195
00196 QByteArray BlobIOHandler::variantMapToByteArray(const QVariantMap &map)
00197 {
00198 QBuffer buffer;
00199 if (!buffer.open(QIODevice::WriteOnly))
00200 BLAME() << "Buffer opening failed.";
00201
00202 QDataStream stream(&buffer);
00203 stream << filterOutComplexTypes(map);
00204 buffer.close();
00205
00206 return buffer.data();
00207 }
00208
00209 QVariantMap BlobIOHandler::byteArrayToVariantMap(const QByteArray &array)
00210 {
00211 QByteArray nonConst = array;
00212 QBuffer buffer(&nonConst);
00213 if (!buffer.open(QIODevice::ReadOnly))
00214 BLAME() << "Buffer opening failed.";
00215
00216 buffer.reset();
00217 QDataStream stream(&buffer);
00218 QVariantMap map;
00219 stream >> map;
00220 buffer.close();
00221
00222 return map;
00223 }
00224
00225 QVector<QByteArray> BlobIOHandler::pageByteArray(const QByteArray &array)
00226 {
00227 QVector<QByteArray> dataPages;
00228 QByteArray ba = array;
00229 QBuffer pagingBuffer(&ba);
00230
00231 if (!pagingBuffer.open(QIODevice::ReadOnly))
00232 BLAME() << "Error while paging BLOB. Buffer opening failed.";
00233
00234 while (!pagingBuffer.atEnd()) {
00235 QByteArray page = pagingBuffer.read(SIGNON_IPC_BUFFER_PAGE_SIZE);
00236 dataPages.append(page);
00237 }
00238 pagingBuffer.close();
00239
00240 return dataPages;
00241 }