summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/groupwise/libgroupwise/responseprotocol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/groupwise/libgroupwise/responseprotocol.cpp')
-rw-r--r--kopete/protocols/groupwise/libgroupwise/responseprotocol.cpp314
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, &currentList) )
+ {
+ 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"