diff options
Diffstat (limited to 'kopete/protocols/groupwise/libgroupwise/responseprotocol.cpp')
-rw-r--r-- | kopete/protocols/groupwise/libgroupwise/responseprotocol.cpp | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/kopete/protocols/groupwise/libgroupwise/responseprotocol.cpp b/kopete/protocols/groupwise/libgroupwise/responseprotocol.cpp new file mode 100644 index 00000000..6784fd15 --- /dev/null +++ b/kopete/protocols/groupwise/libgroupwise/responseprotocol.cpp @@ -0,0 +1,314 @@ +/* + Kopete Groupwise Protocol + responseprotocol.cpp - Protocol used for reading incoming GroupWise Responses + + Copyright (c) 2004 SUSE Linux AG http://www.suse.com + + Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#include <qbuffer.h> + +#include "response.h" + +#include "responseprotocol.h" + +ResponseProtocol::ResponseProtocol(QObject* parent, const char* name): InputProtocolBase(parent, name) +{ +} + + +ResponseProtocol::~ResponseProtocol() +{ +} + +Transfer * ResponseProtocol::parse( const QByteArray & wire, uint & bytes ) +{ + m_bytes = 0; + m_collatingFields.clear(); + //m_din = new QDataStream( wire, IO_ReadOnly ); + QBuffer inBuf( wire ); + inBuf.open( IO_ReadOnly); + m_din.setDevice( &inBuf ); + m_din.setByteOrder( QDataStream::LittleEndian ); + + // check that this begins with a HTTP (is a response) + Q_UINT32 val; + m_din >> val; + m_bytes += sizeof( Q_UINT32 ); + + Q_ASSERT( qstrncmp( (const char *)&val, "HTTP", strlen( "HTTP" ) ) == 0 ); + + // read rest of HTTP header and look for a 301 redirect. + QCString headerFirst; + if ( !readGroupWiseLine( headerFirst ) ) + return 0; + // pull out the HTTP return code + int firstSpace = headerFirst.find( ' ' ); + QString rtnField = headerFirst.mid( firstSpace, headerFirst.find( ' ', firstSpace + 1 ) ); + bool ok = true; + int rtnCode; + int packetState = -1; + rtnCode = rtnField.toInt( &ok ); + debug( "CoreProtocol::readResponse() got HTTP return code " ); + // read rest of header + QStringList headerRest; + QCString line; + while ( line != "\r\n" ) + { + if ( !readGroupWiseLine( line ) ) + { + m_din.unsetDevice(); + return 0; + } + headerRest.append( line ); + debug( QString( "- read header line - (%1) : %2" ).arg( line.length() ).arg( line.data() ) ); + } + debug( "ResponseProtocol::readResponse() header finished" ); + // if it's a redirect, set flag + if ( ok && rtnCode == 301 ) + { + debug( "- server redirect " ); + packetState = ServerRedirect; + m_din.unsetDevice(); + return 0; + } + // other header processing ( 500! ) + if ( ok && rtnCode == 500 ) + { + debug( QString( "- server error %1" ).arg( rtnCode ) ); + packetState = ServerError; + m_din.unsetDevice(); + return 0; + } + if ( ok && rtnCode == 404 ) + { + debug( QString( "- server error %1" ).arg( rtnCode ) ); + packetState = ServerError; + m_din.unsetDevice(); + return 0; + } + if ( m_din.atEnd() ) + { + debug( "- no fields" ); + packetState = ProtocolError; + m_din.unsetDevice(); + return 0; + } + + // read fields + if ( !readFields( -1 ) ) + { + m_din.unsetDevice(); + return 0; + } + // find transaction id field and create Response object if nonzero + int tId = 0; + int resultCode = 0; + Field::FieldListIterator it; + Field::FieldListIterator end = m_collatingFields.end(); + it = m_collatingFields.find( NM_A_SZ_TRANSACTION_ID ); + if ( it != end ) + { + Field::SingleField * sf = dynamic_cast<Field::SingleField*>( *it ); + if ( sf ) + { + tId = sf->value().toInt(); + debug( QString( "ResponseProtocol::readResponse() - transaction ID is %1" ).arg( tId ) ); + m_collatingFields.remove( it ); + delete sf; + } + } + it = m_collatingFields.find( NM_A_SZ_RESULT_CODE ); + if ( it != end ) + { + Field::SingleField * sf = dynamic_cast<Field::SingleField*>( *it ); + if ( sf ) + { + resultCode = sf->value().toInt(); + debug( QString( "ResponseProtocol::readResponse() - result code is %1" ).arg( resultCode ) ); + m_collatingFields.remove( it ); + delete sf; + } + } + // append to inQueue + if ( tId ) + { + debug( QString( "ResponseProtocol::readResponse() - setting state Available, got %1 fields in base array" ).arg(m_collatingFields.count() ) ); + packetState = Available; + bytes = m_bytes; + m_din.unsetDevice(); + return new Response( tId, resultCode, m_collatingFields ); + } + else + { + debug( "- WARNING - NO TRANSACTION ID FOUND!" ); + m_state = ProtocolError; + m_din.unsetDevice(); + m_collatingFields.purge(); + return 0; + } +} + +bool ResponseProtocol::readFields( int fieldCount, Field::FieldList * list ) +{ + // build a list of fields. + // If there is already a list of fields stored in m_collatingFields, + // the list we're reading on this iteration must be a nested list + // so when we're done reading it, add it to the MultiList element + // that is the last element in the top list in m_collatingFields. + // if we find the beginning of a new nested list, push the current list onto m_collatingFields + debug( "ResponseProtocol::readFields()" ); + if ( fieldCount > 0 ) + debug( QString( "reading %1 fields" ).arg( fieldCount ) ); + Field::FieldList currentList; + while ( fieldCount != 0 ) // prevents bad input data from ruining our day + { + // the field being read + // read field + Q_UINT8 type, method; + Q_UINT32 val; + QCString tag; + // read uint8 type + if ( !okToProceed() ) + { + currentList.purge(); + return false; + } + m_din >> type; + m_bytes += sizeof( Q_UINT8 ); + // if type is 0 SOMETHING_INVALID, we're at the end of the fields + if ( type == 0 ) /*&& m_din->atEnd() )*/ + { + debug( "- end of field list" ); + m_packetState = FieldsRead; + // do something to indicate we're done + break; + } + // read uint8 method + if ( !okToProceed() ) + { + currentList.purge(); + return false; + } + m_din >> method; + m_bytes += sizeof( Q_UINT8 ); + // read tag and length + if ( !safeReadBytes( tag, val ) ) + { + currentList.purge(); + return false; + } + + debug( QString( "- type: %1, method: %2, tag: %3," ).arg( type ).arg( method ).arg( tag.data() ) ); + // if multivalue or array + if ( type == NMFIELD_TYPE_MV || type == NMFIELD_TYPE_ARRAY ) + { + // read length uint32 + if ( !okToProceed() ) + { + currentList.purge(); + return false; + } + m_din >> val; + m_bytes += sizeof( Q_UINT32 ); + + // create multifield + debug( QString( " multi field containing: %1" ).arg( val ) ); + Field::MultiField* m = new Field::MultiField( tag, method, 0, type ); + currentList.append( m ); + if ( !readFields( val, ¤tList) ) + { + currentList.purge(); + return false; + } + } + else + { + + if ( type == NMFIELD_TYPE_UTF8 || type == NMFIELD_TYPE_DN ) + { + QCString rawData; + if( !safeReadBytes( rawData, val ) ) + { + currentList.purge(); + return false; + } + if ( val > NMFIELD_MAX_STR_LENGTH ) + { + m_packetState = ProtocolError; + break; + } + // convert to unicode - ignore the terminating NUL, because Qt<3.3.2 doesn't sanity check val. + QString fieldValue = QString::fromUtf8( rawData.data(), val - 1 ); + debug( QString( "- utf/dn single field: %1" ).arg( fieldValue ) ); + // create singlefield + Field::SingleField* s = new Field::SingleField( tag, method, 0, type, fieldValue ); + currentList.append( s ); + } + else + { + // otherwise ( numeric ) + // read value uint32 + if ( !okToProceed() ) + { + currentList.purge(); + return false; + } + m_din >> val; + m_bytes += sizeof( Q_UINT32 ); + debug( QString( "- numeric field: %1" ).arg( val ) ); + Field::SingleField* s = new Field::SingleField( tag, method, 0, type, val ); + currentList.append( s ); + } + } + // decrease the fieldCount if we're using it + if ( fieldCount > 0 ) + fieldCount--; + } + // got a whole list! + // if fieldCount == 0, we've just read a whole nested list, so add this list to the last element in 'list' + if ( fieldCount == 0 && list ) + { + debug( "- finished reading nested list" ); + Field::MultiField * m = dynamic_cast<Field::MultiField*>( list->last() ); + m->setFields( currentList ); + } + + // if fieldCount == -1; we're done reading the top level fieldlist, so store it. + if ( fieldCount == -1 ) + { + debug( "- finished reading ALL FIELDS!" ); + m_collatingFields = currentList; + } + return true; +} + +bool ResponseProtocol::readGroupWiseLine( QCString & line ) +{ + line = QCString(); + while ( true ) + { + Q_UINT8 c; + + if (! okToProceed() ) + return false; + m_din >> c; + m_bytes++; + line += QChar(c); + if ( c == '\n' ) + break; + } + return true; +} + +#include "responseprotocol.moc" |