2 Kopete Groupwise Protocol
3 responseprotocol.cpp - Protocol used for reading incoming GroupWise Responses
5 Copyright (c) 2004 SUSE Linux AG http://www.suse.com
7 Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
9 *************************************************************************
11 * This library is free software; you can redistribute it and/or *
12 * modify it under the terms of the GNU Lesser General Public *
13 * License as published by the Free Software Foundation; either *
14 * version 2 of the License, or (at your option) any later version. *
16 *************************************************************************
22 #include <QStringList>
26 #include "responseprotocol.h"
28 ResponseProtocol::ResponseProtocol(QObject
* parent
)
29 : InputProtocolBase(parent
)
34 ResponseProtocol::~ResponseProtocol()
38 Transfer
* ResponseProtocol::parse( QByteArray
& wire
, uint
& bytes
)
41 m_collatingFields
.clear();
42 //m_din = new QDataStream( wire, QIODevice::ReadOnly );
43 QBuffer
inBuf( &wire
);
44 inBuf
.open( QIODevice::ReadOnly
);
45 m_din
.setDevice( &inBuf
);
46 m_din
.setByteOrder( QDataStream::LittleEndian
);
48 // check that this begins with a HTTP (is a response)
51 m_bytes
+= sizeof( quint32
);
53 Q_ASSERT( qstrncmp( (const char *)&val
, "HTTP", strlen( "HTTP" ) ) == 0 );
55 // read rest of HTTP header and look for a 301 redirect.
56 QByteArray headerFirst
;
57 if ( !readGroupWiseLine( headerFirst
) )
59 // pull out the HTTP return code
60 int firstSpace
= headerFirst
.indexOf( ' ' );
61 QByteArray rtnField
= headerFirst
.mid( firstSpace
+ 1, 3 );
65 rtnCode
= rtnField
.toInt( &ok
);
66 debug( QString("CoreProtocol::readResponse() got HTTP return code '%1'").arg( rtnCode
) );
67 // read rest of header
68 QStringList headerRest
;
70 while ( line
!= "\r\n" )
72 if ( !readGroupWiseLine( line
) )
77 headerRest
.append( line
);
78 debug( QString( "- read header line - (%1) : %2" ).arg( line
.length() ).arg( line
.data() ) );
80 debug( "ResponseProtocol::readResponse() header finished" );
81 // if it's a redirect, set flag
82 if ( ok
&& rtnCode
== 301 )
84 debug( "- server redirect " );
85 packetState
= ServerRedirect
;
89 // other header processing ( 500! )
90 if ( ok
&& rtnCode
== 500 )
92 debug( QString( "- server error %1" ).arg( rtnCode
) );
93 packetState
= ServerError
;
97 if ( ok
&& rtnCode
== 404 )
99 debug( QString( "- server error %1" ).arg( rtnCode
) );
100 packetState
= ServerError
;
106 debug( "- no fields" );
107 packetState
= ProtocolError
;
113 if ( !readFields( -1 ) )
118 // find transaction id field and create Response object if nonzero
121 Field::FieldListIterator it
;
122 Field::FieldListIterator end
= m_collatingFields
.end();
123 it
= m_collatingFields
.find( Field::NM_A_SZ_TRANSACTION_ID
);
126 Field::SingleField
* sf
= dynamic_cast<Field::SingleField
*>( *it
);
129 tId
= sf
->value().toInt();
130 debug( QString( "ResponseProtocol::readResponse() - transaction ID is %1" ).arg( tId
) );
131 m_collatingFields
.erase( it
);
135 it
= m_collatingFields
.find( Field::NM_A_SZ_RESULT_CODE
);
138 Field::SingleField
* sf
= dynamic_cast<Field::SingleField
*>( *it
);
141 resultCode
= sf
->value().toInt();
142 debug( QString( "ResponseProtocol::readResponse() - result code is %1" ).arg( resultCode
) );
143 m_collatingFields
.erase( it
);
150 debug( QString( "ResponseProtocol::readResponse() - setting state Available, got %1 fields in base array" ).arg(m_collatingFields
.count() ) );
151 packetState
= Available
;
154 return new Response( tId
, resultCode
, m_collatingFields
);
158 debug( "- WARNING - NO TRANSACTION ID FOUND!" );
159 if ( resultCode
== -1 ) {
160 debug( "- WARNING - NO RESULT CODE FOUND!" );
162 m_state
= ProtocolError
;
164 m_collatingFields
.purge();
169 bool ResponseProtocol::readFields( int fieldCount
, Field::FieldList
* list
)
171 // build a list of fields.
172 // If there is already a list of fields stored in m_collatingFields,
173 // the list we're reading on this iteration must be a nested list
174 // so when we're done reading it, add it to the MultiList element
175 // that is the last element in the top list in m_collatingFields.
176 // if we find the beginning of a new nested list, push the current list onto m_collatingFields
178 if ( fieldCount
> 0 )
179 debug( QString( "reading %1 fields" ).arg( fieldCount
) );
180 Field::FieldList currentList
;
181 while ( fieldCount
!= 0 ) // prevents bad input data from ruining our day
183 // the field being read
189 if ( !okToProceed() )
195 m_bytes
+= sizeof( quint8
);
196 // if type is 0 SOMETHING_INVALID, we're at the end of the fields
197 if ( type
== 0 ) /*&& m_din->atEnd() )*/
199 debug( "- end of field list" );
200 m_packetState
= FieldsRead
;
201 // do something to indicate we're done
205 if ( !okToProceed() )
211 m_bytes
+= sizeof( quint8
);
212 // read tag and length
213 if ( !safeReadBytes( tag
, val
) )
219 debug( QString( "- type: %1, method: %2, tag: %3," ).arg( type
).arg( method
).arg( tag
.data() ) );
220 // if multivalue or array
221 if ( type
== NMFIELD_TYPE_MV
|| type
== NMFIELD_TYPE_ARRAY
)
223 // read length uint32
224 if ( !okToProceed() )
230 m_bytes
+= sizeof( quint32
);
233 debug( QString( " multi field containing: %1" ).arg( val
) );
234 Field::MultiField
* m
= new Field::MultiField( tag
.constData(), method
, 0, type
);
235 currentList
.append( m
);
236 if ( !readFields( val
, ¤tList
) )
245 if ( type
== NMFIELD_TYPE_UTF8
|| type
== NMFIELD_TYPE_DN
)
248 if( !safeReadBytes( rawData
, val
) )
253 if ( val
> NMFIELD_MAX_STR_LENGTH
)
255 m_packetState
= ProtocolError
;
258 // convert to unicode - ignore the terminating NUL, because Qt<3.3.2 doesn't sanity check val.
259 QString fieldValue
= QString::fromUtf8( rawData
.data(), val
- 1 );
260 debug( QString( "- utf/dn single field: %1" ).arg( fieldValue
) );
261 // create singlefield
262 Field::SingleField
* s
= new Field::SingleField( tag
.constData(), method
, 0, type
, fieldValue
);
263 currentList
.append( s
);
267 // otherwise ( numeric )
269 if ( !okToProceed() )
275 m_bytes
+= sizeof( quint32
);
276 debug( QString( "- numeric field: %1" ).arg( val
) );
277 Field::SingleField
* s
= new Field::SingleField( tag
.constData(), method
, 0, type
, val
);
278 currentList
.append( s
);
281 // decrease the fieldCount if we're using it
282 if ( fieldCount
> 0 )
286 // if fieldCount == 0, we've just read a whole nested list, so add this list to the last element in 'list'
287 if ( fieldCount
== 0 && list
)
289 debug( "- finished reading nested list" );
290 Field::MultiField
* m
= dynamic_cast<Field::MultiField
*>( list
->last() );
291 m
->setFields( currentList
);
294 // if fieldCount == -1; we're done reading the top level fieldlist, so store it.
295 if ( fieldCount
== -1 )
297 debug( "- finished reading ALL FIELDS!" );
298 m_collatingFields
= currentList
;
303 bool ResponseProtocol::readGroupWiseLine( QByteArray
& line
)
310 if (! okToProceed() )
321 #include "responseprotocol.moc"