Port things from MSN to WLM plugin:
[kdenetwork.git] / kopete / protocols / groupwise / libgroupwise / responseprotocol.cpp
blob41122ce62522eac78c4ffa8ff9cb0c51dd9f30f8
1 /*
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 *************************************************************************
10 * *
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. *
15 * *
16 *************************************************************************
19 #include <QBuffer>
20 #include <QByteArray>
21 #include <QDebug>
22 #include <QStringList>
24 #include "response.h"
26 #include "responseprotocol.h"
28 ResponseProtocol::ResponseProtocol(QObject* parent)
29 : InputProtocolBase(parent)
34 ResponseProtocol::~ResponseProtocol()
38 Transfer * ResponseProtocol::parse( QByteArray & wire, uint & bytes )
40 m_bytes = 0;
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)
49 quint32 val;
50 m_din >> val;
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 ) )
58 return 0;
59 // pull out the HTTP return code
60 int firstSpace = headerFirst.indexOf( ' ' );
61 QByteArray rtnField = headerFirst.mid( firstSpace + 1, 3 );
62 bool ok = true;
63 int rtnCode;
64 int packetState = -1;
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;
69 QByteArray line;
70 while ( line != "\r\n" )
72 if ( !readGroupWiseLine( line ) )
74 m_din.unsetDevice();
75 return 0;
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;
86 m_din.unsetDevice();
87 return 0;
89 // other header processing ( 500! )
90 if ( ok && rtnCode == 500 )
92 debug( QString( "- server error %1" ).arg( rtnCode ) );
93 packetState = ServerError;
94 m_din.unsetDevice();
95 return 0;
97 if ( ok && rtnCode == 404 )
99 debug( QString( "- server error %1" ).arg( rtnCode ) );
100 packetState = ServerError;
101 m_din.unsetDevice();
102 return 0;
104 if ( m_din.atEnd() )
106 debug( "- no fields" );
107 packetState = ProtocolError;
108 m_din.unsetDevice();
109 return 0;
112 // read fields
113 if ( !readFields( -1 ) )
115 m_din.unsetDevice();
116 return 0;
118 // find transaction id field and create Response object if nonzero
119 int tId = 0;
120 int resultCode = -1;
121 Field::FieldListIterator it;
122 Field::FieldListIterator end = m_collatingFields.end();
123 it = m_collatingFields.find( Field::NM_A_SZ_TRANSACTION_ID );
124 if ( it != end )
126 Field::SingleField * sf = dynamic_cast<Field::SingleField*>( *it );
127 if ( sf )
129 tId = sf->value().toInt();
130 debug( QString( "ResponseProtocol::readResponse() - transaction ID is %1" ).arg( tId ) );
131 m_collatingFields.erase( it );
132 delete sf;
135 it = m_collatingFields.find( Field::NM_A_SZ_RESULT_CODE );
136 if ( it != end )
138 Field::SingleField * sf = dynamic_cast<Field::SingleField*>( *it );
139 if ( sf )
141 resultCode = sf->value().toInt();
142 debug( QString( "ResponseProtocol::readResponse() - result code is %1" ).arg( resultCode ) );
143 m_collatingFields.erase( it );
144 delete sf;
147 // append to inQueue
148 if ( tId )
150 debug( QString( "ResponseProtocol::readResponse() - setting state Available, got %1 fields in base array" ).arg(m_collatingFields.count() ) );
151 packetState = Available;
152 bytes = m_bytes;
153 m_din.unsetDevice();
154 return new Response( tId, resultCode, m_collatingFields );
156 else
158 debug( "- WARNING - NO TRANSACTION ID FOUND!" );
159 if ( resultCode == -1 ) {
160 debug( "- WARNING - NO RESULT CODE FOUND!" );
162 m_state = ProtocolError;
163 m_din.unsetDevice();
164 m_collatingFields.purge();
165 return 0;
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
177 debug("");
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
184 // read field
185 quint8 type, method;
186 quint32 val;
187 QByteArray tag;
188 // read uint8 type
189 if ( !okToProceed() )
191 currentList.purge();
192 return false;
194 m_din >> type;
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
202 break;
204 // read uint8 method
205 if ( !okToProceed() )
207 currentList.purge();
208 return false;
210 m_din >> method;
211 m_bytes += sizeof( quint8 );
212 // read tag and length
213 if ( !safeReadBytes( tag, val ) )
215 currentList.purge();
216 return false;
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() )
226 currentList.purge();
227 return false;
229 m_din >> val;
230 m_bytes += sizeof( quint32 );
232 // create multifield
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, &currentList) )
238 currentList.purge();
239 return false;
242 else
245 if ( type == NMFIELD_TYPE_UTF8 || type == NMFIELD_TYPE_DN )
247 QByteArray rawData;
248 if( !safeReadBytes( rawData, val ) )
250 currentList.purge();
251 return false;
253 if ( val > NMFIELD_MAX_STR_LENGTH )
255 m_packetState = ProtocolError;
256 break;
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 );
265 else
267 // otherwise ( numeric )
268 // read value uint32
269 if ( !okToProceed() )
271 currentList.purge();
272 return false;
274 m_din >> val;
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 )
283 fieldCount--;
285 // got a whole list!
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;
300 return true;
303 bool ResponseProtocol::readGroupWiseLine( QByteArray & line )
305 line = QByteArray();
306 while ( true )
308 quint8 c = 0;
310 if (! okToProceed() )
311 return false;
312 m_din >> c;
313 m_bytes++;
314 line.append( c );
315 if ( c == '\n' )
316 break;
318 return true;
321 #include "responseprotocol.moc"