diff --git a/akonadi/imapparser.cpp b/akonadi/imapparser.cpp index b5546760d..14976231e 100644 --- a/akonadi/imapparser.cpp +++ b/akonadi/imapparser.cpp @@ -1,482 +1,482 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "imapparser.h" #include #include #include using namespace Akonadi; class ImapParser::Private { public: QByteArray tagBuffer; QByteArray dataBuffer; int parenthesesCount; int literalSize; bool continuation; // returns true if readBuffer contains a literal start and sets // parser state accordingly bool checkLiteralStart( const QByteArray &readBuffer, int pos = 0 ) { if ( readBuffer.trimmed().endsWith( '}' ) ) { const int begin = readBuffer.lastIndexOf( '{' ); const int end = readBuffer.lastIndexOf( '}' ); // new literal in previous literal data block if ( begin < pos ) return false; // TODO error handling literalSize = readBuffer.mid( begin + 1, end - begin - 1 ).toInt(); // empty literal if ( literalSize == 0 ) return false; continuation = true; return true; } return false; } }; int ImapParser::parseParenthesizedList( const QByteArray & data, QList &result, int start ) { result.clear(); if ( start >= data.length() ) return data.length(); int begin = data.indexOf( '(', start ); if ( begin < 0 ) return start; int count = 0; int sublistbegin = start; for ( int i = begin + 1; i < data.length(); ++i ) { if ( data[i] == '(' ) { ++count; if ( count == 1 ) sublistbegin = i; continue; } if ( data[i] == ')' ) { if ( count <= 0 ) return i + 1; if ( count == 1 ) result.append( data.mid( sublistbegin, i - sublistbegin + 1 ) ); --count; continue; } if ( data[i] == ' ' ) continue; if ( count == 0 ) { QByteArray ba; i = parseString( data, ba, i ) - 1; // compensate the increment result.append( ba ); } } return data.length(); } int ImapParser::parseString( const QByteArray & data, QByteArray & result, int start ) { int begin = stripLeadingSpaces( data, start ); result.clear(); if ( begin >= data.length() ) return data.length(); // literal string // TODO: error handling if ( data[begin] == '{' ) { int end = data.indexOf( '}', begin ); Q_ASSERT( end > begin ); int size = data.mid( begin + 1, end - begin - 1 ).toInt(); // strip CRLF begin = end + 1; if ( begin < data.length() && data[begin] == '\r' ) ++begin; if ( begin < data.length() && data[begin] == '\n' ) ++begin; end = begin + size; result = data.mid( begin, end - begin ); return end; } // quoted string return parseQuotedString( data, result, begin ); } int ImapParser::parseQuotedString( const QByteArray & data, QByteArray &result, int start ) { int begin = stripLeadingSpaces( data, start ); int end = begin; result.clear(); if ( begin >= data.length() ) return data.length(); // quoted string if ( data[begin] == '"' ) { ++begin; for ( int i = begin; i < data.length(); ++i ) { if ( data[i] == '\\' ) { ++i; continue; } if ( data[i] == '"' ) { result = data.mid( begin, i - begin ); end = i + 1; // skip the '"' break; } } } // unquoted string else { bool reachedInputEnd = true; for ( int i = begin; i < data.length(); ++i ) { if ( data[i] == ' ' || data[i] == '(' || data[i] == ')' || data[i] == '\n' || data[i] == '\r' ) { end = i; reachedInputEnd = false; break; } } if ( reachedInputEnd ) end = data.length(); result = data.mid( begin, end - begin ); // transform unquoted NIL if ( result == "NIL" ) result.clear(); } // strip quotes // FIXME: this can be done more efficiently while ( result.contains( "\\\"" ) ) result.replace( "\\\"", "\"" ); while ( result.contains( "\\\\" ) ) result.replace( "\\\\", "\\" ); return end; } int ImapParser::stripLeadingSpaces( const QByteArray & data, int start ) { for ( int i = start; i < data.length(); ++i ) { if ( data[i] != ' ' ) return i; } return data.length(); } int ImapParser::parenthesesBalance( const QByteArray & data, int start ) { int count = 0; bool insideQuote = false; for ( int i = start; i < data.length(); ++i ) { if ( data[i] == '"' ) { insideQuote = !insideQuote; continue; } if ( data[i] == '\\' && insideQuote ) { ++i; continue; } if ( data[i] == '(' && !insideQuote ) { ++count; continue; } if ( data[i] == ')' && !insideQuote ) { --count; continue; } } return count; } QByteArray ImapParser::join(const QList< QByteArray > & list, const QByteArray & separator) { if ( list.isEmpty() ) return QByteArray(); QByteArray result = list.first(); QList::ConstIterator it = list.constBegin(); ++it; for ( ; it != list.constEnd(); ++it ) result += separator + (*it); return result; } QByteArray ImapParser::join(const QSet< QByteArray > & set, const QByteArray & separator) { QList< QByteArray > list = QList< QByteArray >::fromSet( set ); return ImapParser::join( list, separator ); } int ImapParser::parseString(const QByteArray & data, QString & result, int start) { QByteArray tmp; int end = parseString( data, tmp, start ); result = QString::fromUtf8( tmp ); return end; } int ImapParser::parseNumber(const QByteArray & data, int & result, bool * ok, int start) { if ( ok ) *ok = false; int pos = stripLeadingSpaces( data, start ); if ( pos >= data.length() ) return data.length(); - QByteArray tmp; + int begin = pos; for (; pos < data.length(); ++pos ) { if ( !isdigit( data.at( pos ) ) ) break; - tmp += data.at( pos ); } + QByteArray tmp = data.mid( begin, pos - begin ); result = tmp.toInt( ok ); return pos; } QByteArray ImapParser::quote(const QByteArray & data) { QByteArray result( "\"" ); result.reserve( data.length() + 2 ); for ( int i = 0; i < data.length(); ++i ) { if ( data.at( i ) == '"' || data.at( i ) == '\\' ) result += '\\'; result += data.at( i ); } result += '"'; return result; } int ImapParser::parseSequenceSet(const QByteArray & data, ImapSet & result, int start) { int begin = stripLeadingSpaces( data, start ); int value = -1, lower = -1, upper = -1; for ( int i = begin; i < data.length(); ++i ) { if ( data[i] == '*' ) { value = 0; } else if ( data[i] == ':' ) { lower = value; } else if ( isdigit( data[i] ) ) { bool ok = false; i = parseNumber( data, value, &ok, i ); Q_ASSERT( ok ); // TODO handle error --i; } else { upper = value; if ( lower < 0 ) lower = value; result.add( ImapInterval( lower, upper ) ); lower = -1; upper = -1; value = -1; if ( data[i] != ',' ) return i; } } // take care of left-overs at input end upper = value; if ( lower < 0 ) lower = value; if ( lower >= 0 && upper >= 0 ) result.add( ImapInterval( lower, upper ) ); return data.length(); } int ImapParser::parseDateTime(const QByteArray & data, QDateTime & dateTime, int start) { // Syntax: // date-time = DQUOTE date-day-fixed "-" date-month "-" date-year // SP time SP zone DQUOTE // date-day-fixed = (SP DIGIT) / 2DIGIT // ; Fixed-format version of date-day // date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / // "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" // date-year = 4DIGIT // time = 2DIGIT ":" 2DIGIT ":" 2DIGIT // ; Hours minutes seconds // zone = ("+" / "-") 4DIGIT // ; Signed four-digit value of hhmm representing // ; hours and minutes east of Greenwich (that is, // ; the amount that the given time differs from // ; Universal Time). Subtracting the timezone // ; from the given time will give the UT form. // ; The Universal Time zone is "+0000". // Example : "28-May-2006 01:03:35 +0200" // Position: 0123456789012345678901234567 // 1 2 int pos = stripLeadingSpaces( data, start ); if ( data.length() <= pos ) return pos; bool quoted = false; if ( data[pos] == '"' ) { quoted = true; ++pos; } if ( data.length() <= pos + 26 ) return start; bool ok = true; const int day = ( data[pos] == ' ' ? data[pos + 1] - '0' // single digit day : data.mid( pos, 2 ).toInt( &ok ) ); if ( !ok ) return start; pos += 3; const QByteArray shortMonthNames( "janfebmaraprmayjunjulaugsepoctnovdec" ); int month = shortMonthNames.indexOf( data.mid( pos, 3 ).toLower() ); if ( month == -1 ) return start; month = month / 3 + 1; pos += 4; const int year = data.mid( pos, 4 ).toInt( &ok ); if ( !ok ) return start; pos += 5; const int hours = data.mid( pos, 2 ).toInt( &ok ); if ( !ok ) return start; pos += 3; const int minutes = data.mid( pos, 2 ).toInt( &ok ); if ( !ok ) return start; pos += 3; const int seconds = data.mid( pos, 2 ).toInt( &ok ); if ( !ok ) return start; pos += 4; const int tzhh = data.mid( pos, 2 ).toInt( &ok ); if ( !ok ) return start; pos += 2; const int tzmm = data.mid( pos, 2 ).toInt( &ok ); if ( !ok ) return start; int tzsecs = tzhh*60*60 + tzmm*60; if ( data[pos - 3] == '-' ) tzsecs = -tzsecs; const QDate date( year, month, day ); const QTime time( hours, minutes, seconds ); dateTime = QDateTime( date, time, Qt::UTC ); if ( !dateTime.isValid() ) return start; dateTime = dateTime.addSecs( -tzsecs ); pos += 2; if ( data.length() <= pos || !quoted ) return pos; if ( data[pos] == '"' ) ++pos; return pos; } ImapParser::ImapParser() : d ( new Private ) { reset(); } ImapParser::~ ImapParser() { delete d; } bool ImapParser::parseNextLine(const QByteArray &readBuffer) { d->continuation = false; // first line, get the tag if ( d->tagBuffer.isEmpty() ) { const int startOfData = ImapParser::parseString( readBuffer, d->tagBuffer ); if ( startOfData < readBuffer.length() && startOfData >= 0 ) d->dataBuffer = readBuffer.mid( startOfData + 1 ); } else { d->dataBuffer += readBuffer; } // literal read in progress if ( d->literalSize > 0 ) { d->literalSize -= readBuffer.size(); // still not everything read if ( d->literalSize > 0 ) return false; // check the remaining (non-literal) part for parentheses if ( d->literalSize < 0 ) { // the following looks strange but works since literalSize can be negative here d->parenthesesCount = ImapParser::parenthesesBalance( readBuffer, readBuffer.length() + d->literalSize ); // check if another literal read was started if ( d->checkLiteralStart( readBuffer, readBuffer.length() + d->literalSize ) ) return false; } // literal string finished but still open parentheses if ( d->parenthesesCount > 0 ) return false; } else { // open parentheses d->parenthesesCount += ImapParser::parenthesesBalance( readBuffer ); // start new literal read if ( d->checkLiteralStart( readBuffer ) ) return false; // still open parentheses if ( d->parenthesesCount > 0 ) return false; // just a normal response, fall through } return true; } QByteArray ImapParser::tag() const { return d->tagBuffer; } QByteArray ImapParser::data() const { return d->dataBuffer; } void ImapParser::reset() { d->dataBuffer.clear(); d->tagBuffer.clear(); d->parenthesesCount = 0; d->literalSize = 0; d->continuation = false; } bool ImapParser::continuationStarted() const { return d->continuation; } int ImapParser::continuationSize() const { return d->literalSize; -} \ No newline at end of file +} diff --git a/akonadi/itemappendjob.cpp b/akonadi/itemappendjob.cpp index eed5a093e..034ab33c4 100644 --- a/akonadi/itemappendjob.cpp +++ b/akonadi/itemappendjob.cpp @@ -1,122 +1,120 @@ /* Copyright (c) 2006 - 2007 Volker Krause Copyright (c) 2007 Robert Zwerus This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "itemappendjob.h" #include "imapparser.h" #include using namespace Akonadi; class Akonadi::ItemAppendJob::Private { public: Private( ItemAppendJob *parent ) : mParent( parent ) { } ItemAppendJob *mParent; Collection collection; Item item; QStringList parts; int uid; + QByteArray data; }; ItemAppendJob::ItemAppendJob( const Item &item, const Collection &collection, QObject * parent ) : Job( parent ), d( new Private( this ) ) { Q_ASSERT( !item.mimeType().isEmpty() ); d->item = item; d->parts = d->item.availableParts(); d->collection = collection; } ItemAppendJob::~ ItemAppendJob( ) { delete d; } void ItemAppendJob::doStart() { QByteArray remoteId; if ( !d->item.reference().remoteId().isEmpty() ) remoteId = " \\RemoteId[" + d->item.reference().remoteId().toUtf8() + ']'; // switch between a normal APPEND and a multipart X-AKAPPEND, based on the number of parts if ( d->parts.isEmpty() || (d->parts.size() == 1 && d->parts.first() == Item::PartBody) ) { - int dataSize = 0; if ( d->item.hasPayload() ) - dataSize = d->item.part( Item::PartBody ).size(); + d->data = d->item.part( Item::PartBody ); + int dataSize = d->data.size(); writeData( newTag() + " APPEND " + QByteArray::number( d->collection.id() ) + " (\\MimeType[" + d->item.mimeType().toLatin1() + ']' + remoteId + ") {" + QByteArray::number( dataSize ) + "}\n" ); } else { // do a multipart X-AKAPPEND QByteArray command = newTag() + " X-AKAPPEND " + QByteArray::number( d->collection.id() ) + " (\\MimeType[" + d->item.mimeType().toLatin1() + ']' + remoteId + ") "; - QString partName; QList partSpecs; int totalSize = 0; - foreach( partName, d->parts ) { - totalSize += d->item.part( partName ).size(); + foreach( const QString partName, d->parts ) { + QByteArray partData = d->item.part( partName ); + totalSize += partData.size(); partSpecs.append( ImapParser::quote( partName.toLatin1() ) + ":" + - QByteArray::number( d->item.part( partName ).size() )); + QByteArray::number( partData.size() ) ); + d->data += partData; } command += "(" + ImapParser::join( partSpecs, "," ) + ") " + "{" + QByteArray::number( totalSize ) + "}\n"; writeData( command ); } } void ItemAppendJob::doHandleResponse( const QByteArray & tag, const QByteArray & data ) { if ( tag == "+" ) { // ready for literal data - QString partName; - foreach( partName, d->parts ) { - writeData( d->item.part( partName ) ); - } - if ( !d->item.part( partName ).endsWith( '\n' ) ) + writeData( d->data ); + if ( !d->data.endsWith( '\n' ) ) writeData( "\n" ); - return; } if ( tag == this->tag() ) { if ( int pos = data.indexOf( "UIDNEXT" ) ) { bool ok = false; ImapParser::parseNumber( data, d->uid, &ok, pos + 7 ); if ( !ok ) qDebug() << "invalid UIDNEXT response to APPEND command: " << tag << data; } } } DataReference ItemAppendJob::reference() const { if ( d->uid == 0 ) return DataReference(); return DataReference( d->uid, d->item.reference().remoteId() ); } #include "itemappendjob.moc" diff --git a/akonadi/itemserializer.cpp b/akonadi/itemserializer.cpp index 7c966d90c..5cc4ed573 100644 --- a/akonadi/itemserializer.cpp +++ b/akonadi/itemserializer.cpp @@ -1,192 +1,193 @@ /* Copyright (c) 2007 Till Adam Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "itemserializer.h" #include "item.h" #include "itemserializerplugin.h" // Qt #include #include #include #include -#include +#include #include #include // libkdepim #include namespace Akonadi { class DefaultItemSerializerPlugin; static DefaultItemSerializerPlugin * s_p = 0; class DefaultItemSerializerPlugin : public ItemSerializerPlugin { private: DefaultItemSerializerPlugin() { } public: static DefaultItemSerializerPlugin * instance() { if ( !s_p ) { s_p = new DefaultItemSerializerPlugin; } return s_p; } bool deserialize( Item& item, const QString& label, QIODevice& data ) { if ( label != Item::PartBody ) return false; item.setPayload( data.readAll() ); return true; } void serialize( const Item& item, const QString& label, QIODevice& data ) { Q_ASSERT( label == Item::PartBody ); if ( item.hasPayload() ) data.write( item.payload() ); } }; namespace { KPIM_DEFINE_PLUGIN_LOADER( ItemSerializerPluginLoader, Akonadi::ItemSerializerPlugin, "create_item_serializer_plugin", "akonadi/plugins/serializer/*.desktop" ) } } using namespace Akonadi; -static QMap * all = 0; +static QHash * all = 0; static void loadPlugins() { const ItemSerializerPluginLoader* pl = ItemSerializerPluginLoader::instance(); if ( !pl ) { qWarning() << "ItemSerializerPluginLoader: cannot instantiate plugin loader!" << endl; return; } const QStringList types = pl->types(); qDebug() << "ItemSerializerPluginLoader: found" << types.size() << "plugins." << endl; for ( QStringList::const_iterator it = types.begin() ; it != types.end() ; ++it ) { ItemSerializerPlugin * plugin = pl->createForName( *it ); if ( !plugin ) { qWarning() << "ItemSerializerPlugin: plugin" << *it << "is not valid!" << endl; continue; } QStringList supportedTypes = (*it).split( QLatin1Char(',') ); foreach ( const QString t, supportedTypes ) { qDebug() << "ItemSerializerPluginLoader: inserting plugin for type:" << t; all->insert( t, plugin ); } } if ( !all->contains( QLatin1String("application/octet-stream") ) ) all->insert( QLatin1String("application/octet-stream"), DefaultItemSerializerPlugin::instance() ); } static void setup() { if (!all) { - all = new QMap(); + all = new QHash(); loadPlugins(); } } /*static*/ void ItemSerializer::deserialize( Item& item, const QString& label, const QByteArray& data ) { QBuffer buffer; buffer.setData( data ); buffer.open( QIODevice::ReadOnly ); buffer.seek( 0 ); deserialize( item, label, buffer ); buffer.close(); } /*static*/ void ItemSerializer::deserialize( Item& item, const QString& label, QIODevice& data ) { setup(); if ( !ItemSerializer::pluginForMimeType( item.mimeType() ).deserialize( item, label, data ) ) { data.seek( 0 ); item.addRawPart( label, data.readAll() ); } } /*static*/ void ItemSerializer::serialize( const Item& item, const QString& label, QByteArray& data ) { QBuffer buffer; buffer.setBuffer( &data ); buffer.open( QIODevice::WriteOnly ); buffer.seek( 0 ); serialize( item, label, buffer ); buffer.close(); } /*static*/ void ItemSerializer::serialize( const Item& item, const QString& label, QIODevice& data ) { setup(); - QStringList supportedParts = pluginForMimeType( item.mimeType() ).parts( item ); + ItemSerializerPlugin& plugin = pluginForMimeType( item.mimeType() ); + QStringList supportedParts = plugin.parts( item ); if ( !supportedParts.contains( label ) ) { data.write( item.rawPart( label ) ); return; } if ( !item.hasPayload() ) return; - ItemSerializer::pluginForMimeType( item.mimeType() ).serialize( item, label, data ); + plugin.serialize( item, label, data ); } QStringList ItemSerializer::parts(const Item & item) { if ( !item.hasPayload() ) return QStringList(); setup(); return pluginForMimeType( item.mimeType() ).parts( item ); } /*static*/ ItemSerializerPlugin& ItemSerializer::pluginForMimeType( const QString & mimetype ) { if ( all->contains( mimetype ) ) return *(all->value(mimetype)); qDebug() << "ItemSerializer: No plugin for mimetype " << mimetype << " found!"; qDebug() << "available plugins are: " << all->keys(); ItemSerializerPlugin *plugin = DefaultItemSerializerPlugin::instance(); Q_ASSERT(plugin); return *plugin; } diff --git a/akonadi/itemstorejob.cpp b/akonadi/itemstorejob.cpp index da8e07d1c..15490bfa6 100644 --- a/akonadi/itemstorejob.cpp +++ b/akonadi/itemstorejob.cpp @@ -1,223 +1,223 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "itemstorejob.h" #include "imapparser.h" #include using namespace Akonadi; class ItemStoreJob::Private { public: enum Operation { SetFlags, AddFlags, RemoveFlags, RemoveParts, Move, RemoteId, Dirty }; Private( ItemStoreJob *parent, Item & it ) : mParent( parent ), item( it ), itemRef( it ), revCheck( true ) { } Private( ItemStoreJob *parent, const Item &it ) : mParent( parent ), item( it ), itemRef( item ), revCheck( true ) { } ItemStoreJob *mParent; Item::Flags flags; Item::Flags addFlags; Item::Flags removeFlags; QList removeParts; QSet operations; QByteArray tag; Collection collection; Item item; Item & itemRef; // used for increasing revision number of given item bool revCheck; QStringList parts; QByteArray pendingData; void sendNextCommand(); }; void ItemStoreJob::Private::sendNextCommand() { // no further commands to send if ( operations.isEmpty() && parts.isEmpty() ) { mParent->emitResult(); return; } tag = mParent->newTag(); QByteArray command = tag; command += " UID STORE " + QByteArray::number( item.reference().id() ) + ' '; if ( !revCheck || addFlags.contains( "\\Deleted" ) ) { command += "NOREV "; } else { - command += "REV " + QByteArray::number( item.rev() ) + ' '; + command += "REV " + QByteArray::number( itemRef.rev() ) + ' '; } if ( !operations.isEmpty() ) { int op = *(operations.begin()); operations.remove( op ); switch ( op ) { case SetFlags: command += "FLAGS.SILENT (" + ImapParser::join( flags, " " ) + ')'; break; case AddFlags: command += "+FLAGS.SILENT (" + ImapParser::join( addFlags, " " ) + ')'; break; case RemoveFlags: command += "-FLAGS.SILENT (" + ImapParser::join( removeFlags, " " ) + ')'; break; case RemoveParts: command += "-PARTS.SILENT (" + ImapParser::join( removeParts, " " ) + ')'; break; case Move: command += "COLLECTION.SILENT " + QByteArray::number( collection.id() ); break; case RemoteId: if ( item.reference().remoteId().isNull() ) { sendNextCommand(); return; } command += "REMOTEID.SILENT \"" + item.reference().remoteId().toLatin1() + '\"'; break; case Dirty: command += "DIRTY.SILENT"; break; } } else { QString label = parts.takeFirst(); pendingData = item.part( label ); command += label.toUtf8(); command += ".SILENT {" + QByteArray::number( pendingData.size() ) + '}'; } command += '\n'; mParent->writeData( command ); mParent->newTag(); // hack to circumvent automatic response handling } ItemStoreJob::ItemStoreJob(Item & item, QObject * parent) : Job( parent ), d( new Private( this, item ) ) { d->operations.insert( Private::RemoteId ); } ItemStoreJob::ItemStoreJob(const Item &item, QObject * parent) : Job( parent ), d( new Private( this, item ) ) { d->operations.insert( Private::RemoteId ); } ItemStoreJob::~ ItemStoreJob() { delete d; } void ItemStoreJob::setFlags(const Item::Flags & flags) { d->flags = flags; d->operations.insert( Private::SetFlags ); } void ItemStoreJob::addFlag(const Item::Flag & flag) { d->addFlags.insert( flag ); d->operations.insert( Private::AddFlags ); } void ItemStoreJob::removeFlag(const Item::Flag & flag) { d->removeFlags.insert( flag ); d->operations.insert( Private::RemoveFlags ); } void ItemStoreJob::removePart(const QByteArray & part) { d->removeParts.append( part ); d->operations.insert( Private::RemoveParts ); } void ItemStoreJob::setCollection(const Collection &collection) { d->collection = collection; d->operations.insert( Private::Move ); } void ItemStoreJob::setClean() { d->operations.insert( Private::Dirty ); } void ItemStoreJob::doStart() { d->sendNextCommand(); } void ItemStoreJob::doHandleResponse(const QByteArray &_tag, const QByteArray & data) { if ( _tag == "+" ) { // ready for literal data writeData( d->pendingData ); // ### readLine() would deadlock in the server otherwise, should probably be fixed there if ( !d->pendingData.endsWith( '\n' ) ) writeData( "\n" ); return; } if ( _tag == d->tag ) { if ( data.startsWith( "OK" ) ) { // increase item revision of item, given by calling function if( d->revCheck ) d->itemRef.incRev(); else // increase item revision of own copy of item d->item.incRev(); d->sendNextCommand(); } else { setError( Unknown ); setErrorText( QString::fromUtf8( data ) ); emitResult(); } return; } qDebug() << "unhandled response in item store job: " << _tag << data; } void ItemStoreJob::storePayload() { Q_ASSERT( !d->item.mimeType().isEmpty() ); d->parts = d->item.availableParts(); } void ItemStoreJob::noRevCheck() { d->revCheck = false; } #include "itemstorejob.moc"