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 {
00047 }
00048
00049 void BlobIOHandler::setReadChannelSocketNotifier(QSocketNotifier *notifier)
00050 {
00051 if (notifier == 0)
00052 return;
00053
00054 m_readNotifier = notifier;
00055 }
00056
00057 bool BlobIOHandler::sendData(const QVariantMap &map)
00058 {
00059 if (m_writeChannel == 0) {
00060 TRACE() << "NULL write channel.";
00061 return false;
00062 }
00063
00064 QDataStream stream(m_writeChannel);
00065 QByteArray ba = variantMapToByteArray(map);
00066 stream << ba.size();
00067
00068 QVector<QByteArray> pages = pageByteArray(ba);
00069 for (int i = 0; i < pages.count(); ++i)
00070 stream << pages[i];
00071
00072 return true;
00073 }
00074
00075 void BlobIOHandler::setReadNotificationEnabled(bool enabled)
00076 {
00077 if (enabled) {
00078 if (m_readNotifier != 0) {
00079 m_readNotifier->setEnabled(true);
00080 connect(m_readNotifier, SIGNAL(activated(int)),
00081 this, SLOT(readBlob()));
00082 } else {
00083 connect(m_readChannel, SIGNAL(readyRead()),
00084 this, SLOT(readBlob()));
00085 }
00086 } else {
00087 if (m_readNotifier != 0) {
00088 disconnect(m_readNotifier, SIGNAL(activated(int)),
00089 this, SLOT(readBlob()));
00090 m_readNotifier->setEnabled(false);
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 }