00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "imapstreamparser.h"
00025
00026 #include <ctype.h>
00027 #include <QIODevice>
00028
00029 using namespace KIMAP;
00030
00031 ImapStreamParser::ImapStreamParser( QIODevice *socket )
00032 {
00033 m_socket = socket;
00034 m_position = 0;
00035 m_literalSize = 0;
00036 m_continuationSize = 0;
00037 }
00038
00039 ImapStreamParser::~ImapStreamParser()
00040 {
00041 }
00042
00043 QString ImapStreamParser::readUtf8String()
00044 {
00045 QByteArray tmp;
00046 tmp = readString();
00047 QString result = QString::fromUtf8( tmp );
00048 return result;
00049 }
00050
00051
00052 QByteArray ImapStreamParser::readString()
00053 {
00054 QByteArray result;
00055 if ( !waitForMoreData( m_data.length() == 0 ) )
00056 throw ImapParserException("Unable to read more data");
00057 stripLeadingSpaces();
00058 if ( !waitForMoreData( m_position >= m_data.length() ) )
00059 throw ImapParserException("Unable to read more data");
00060
00061
00062
00063 if ( hasLiteral() ) {
00064 while (!atLiteralEnd()) {
00065 result += readLiteralPart();
00066 }
00067 return result;
00068 }
00069
00070
00071 return parseQuotedString();
00072 }
00073
00074 bool ImapStreamParser::hasString()
00075 {
00076 if ( !waitForMoreData( m_position >= m_data.length() ) )
00077 throw ImapParserException("Unable to read more data");
00078 int savedPos = m_position;
00079 stripLeadingSpaces();
00080 int pos = m_position;
00081 m_position = savedPos;
00082 if ( m_data[pos] == '{' )
00083 return true;
00084 if (m_data[pos] == '"' )
00085 return true;
00086 if ( m_data[pos] != ' ' &&
00087 m_data[pos] != '(' &&
00088 m_data[pos] != ')' &&
00089 m_data[pos] != '[' &&
00090 m_data[pos] != ']' &&
00091 m_data[pos] != '\n' &&
00092 m_data[pos] != '\r' )
00093 return true;
00094
00095 return false;
00096 }
00097
00098 bool ImapStreamParser::hasLiteral()
00099 {
00100 if ( !waitForMoreData( m_position >= m_data.length() ) )
00101 throw ImapParserException("Unable to read more data");
00102 int savedPos = m_position;
00103 stripLeadingSpaces();
00104 if ( m_data[m_position] == '{' )
00105 {
00106 int end = -1;
00107 do {
00108 end = m_data.indexOf( '}', m_position );
00109 if ( !waitForMoreData( end == -1 ) )
00110 throw ImapParserException("Unable to read more data");
00111 } while (end == -1);
00112 Q_ASSERT( end > m_position );
00113 m_literalSize = m_data.mid( m_position + 1, end - m_position - 1 ).toInt();
00114
00115 m_position = end + 1;
00116
00117 if ( m_position < m_data.length() && m_data[m_position] == '\r' )
00118 ++m_position;
00119 if ( m_position < m_data.length() && m_data[m_position] == '\n' )
00120 ++m_position;
00121
00122
00123
00124
00125
00126 return true;
00127 } else
00128 {
00129 m_position = savedPos;
00130 return false;
00131 }
00132 }
00133
00134 bool ImapStreamParser::atLiteralEnd() const
00135 {
00136 return (m_literalSize == 0);
00137 }
00138
00139 QByteArray ImapStreamParser::readLiteralPart()
00140 {
00141 static qint64 maxLiteralPartSize = 4096;
00142 int size = qMin(maxLiteralPartSize, m_literalSize);
00143
00144 if ( !waitForMoreData( m_data.length() < m_position + size ) )
00145 throw ImapParserException("Unable to read more data");
00146
00147 if ( m_data.length() < m_position + size ) {
00148
00149 size = m_data.length() - m_position;
00150 }
00151
00152 QByteArray result = m_data.mid(m_position, size);
00153 m_position += size;
00154 m_literalSize -= size;
00155 Q_ASSERT(m_literalSize >= 0);
00156 m_data = m_data.right( m_data.size() - m_position );
00157 m_position = 0;
00158
00159 return result;
00160 }
00161
00162 bool ImapStreamParser::hasList()
00163 {
00164 if ( !waitForMoreData( m_position >= m_data.length() ) )
00165 throw ImapParserException("Unable to read more data");
00166 int savedPos = m_position;
00167 stripLeadingSpaces();
00168 int pos = m_position;
00169 m_position = savedPos;
00170 if ( m_data[pos] == '(' )
00171 {
00172 return true;
00173 }
00174
00175 return false;
00176 }
00177
00178 bool ImapStreamParser::atListEnd()
00179 {
00180 if ( !waitForMoreData( m_position >= m_data.length() ) )
00181 throw ImapParserException("Unable to read more data");
00182 int savedPos = m_position;
00183 stripLeadingSpaces();
00184 int pos = m_position;
00185 m_position = savedPos;
00186 if ( m_data[pos] == ')' )
00187 {
00188 m_position = pos + 1;
00189 return true;
00190 }
00191
00192 return false;
00193 }
00194
00195 QList<QByteArray> ImapStreamParser::readParenthesizedList()
00196 {
00197 QList<QByteArray> result;
00198 if (! waitForMoreData( m_data.length() <= m_position ) )
00199 throw ImapParserException("Unable to read more data");
00200
00201 stripLeadingSpaces();
00202 if ( m_data[m_position] != '(' )
00203 return result;
00204
00205 bool concatToLast = false;
00206 int count = 0;
00207 int sublistbegin = m_position;
00208 int i = m_position + 1;
00209 Q_FOREVER {
00210 if ( !waitForMoreData( m_data.length() <= i ) )
00211 {
00212 m_position = i;
00213 throw ImapParserException("Unable to read more data");
00214 }
00215 if ( m_data[i] == '(' ) {
00216 ++count;
00217 if ( count == 1 )
00218 sublistbegin = i;
00219 ++i;
00220 continue;
00221 }
00222 if ( m_data[i] == ')' ) {
00223 if ( count <= 0 ) {
00224 m_position = i + 1;
00225 return result;
00226 }
00227 if ( count == 1 )
00228 result.append( m_data.mid( sublistbegin, i - sublistbegin + 1 ) );
00229 --count;
00230 ++i;
00231 continue;
00232 }
00233 if ( m_data[i] == ' ' ) {
00234 ++i;
00235 continue;
00236 }
00237 if ( m_data[i] == '[' ) {
00238 concatToLast = true;
00239 result.last()+='[';
00240 ++i;
00241 continue;
00242 }
00243 if ( m_data[i] == ']' ) {
00244 concatToLast = false;
00245 result.last()+=']';
00246 ++i;
00247 continue;
00248 }
00249 if ( count == 0 ) {
00250 m_position = i;
00251 QByteArray ba;
00252 if (hasLiteral()) {
00253 while (!atLiteralEnd()) {
00254 ba+=readLiteralPart();
00255 }
00256 } else {
00257 ba = readString();
00258 }
00259
00260
00261
00262 while ( ( m_position < m_data.size() ) && ( m_data[m_position]=='\r' || m_data[m_position]=='\n' ) ) {
00263 m_position++;
00264 }
00265
00266 i = m_position - 1;
00267 if (concatToLast) {
00268 result.last()+=ba;
00269 } else {
00270 result.append( ba );
00271 }
00272 }
00273 ++i;
00274 }
00275
00276 throw ImapParserException( "Something went very very wrong!" );
00277 }
00278
00279 bool ImapStreamParser::hasResponseCode()
00280 {
00281 if ( !waitForMoreData( m_position >= m_data.length() ) )
00282 throw ImapParserException("Unable to read more data");
00283 int savedPos = m_position;
00284 stripLeadingSpaces();
00285 int pos = m_position;
00286 m_position = savedPos;
00287 if ( m_data[pos] == '[' )
00288 {
00289 m_position = pos + 1;
00290 return true;
00291 }
00292
00293 return false;
00294 }
00295
00296 bool ImapStreamParser::atResponseCodeEnd()
00297 {
00298 if ( !waitForMoreData( m_position >= m_data.length() ) )
00299 throw ImapParserException("Unable to read more data");
00300 int savedPos = m_position;
00301 stripLeadingSpaces();
00302 int pos = m_position;
00303 m_position = savedPos;
00304 if ( m_data[pos] == ']' )
00305 {
00306 m_position = pos + 1;
00307 return true;
00308 }
00309
00310 return false;
00311 }
00312
00313 QByteArray ImapStreamParser::parseQuotedString()
00314 {
00315 QByteArray result;
00316 if (! waitForMoreData( m_data.length() == 0 ) )
00317 throw ImapParserException("Unable to read more data");
00318 stripLeadingSpaces();
00319 int end = m_position;
00320 result.clear();
00321 if ( !waitForMoreData( m_position >= m_data.length() ) )
00322 throw ImapParserException("Unable to read more data");
00323 if ( !waitForMoreData( m_position >= m_data.length() ) )
00324 throw ImapParserException("Unable to read more data");
00325
00326 bool foundSlash = false;
00327
00328 if ( m_data[m_position] == '"' ) {
00329 ++m_position;
00330 int i = m_position;
00331 Q_FOREVER {
00332 if ( !waitForMoreData( m_data.length() <= i ) )
00333 {
00334 m_position = i;
00335 throw ImapParserException("Unable to read more data");
00336 }
00337 if ( m_data[i] == '\\' ) {
00338 i += 2;
00339 foundSlash = true;
00340 continue;
00341 }
00342 if ( m_data[i] == '"' ) {
00343 result = m_data.mid( m_position, i - m_position );
00344 end = i + 1;
00345 break;
00346 }
00347 ++i;
00348 }
00349 }
00350
00351
00352 else {
00353 bool reachedInputEnd = true;
00354 int i = m_position;
00355 Q_FOREVER {
00356 if ( !waitForMoreData( m_data.length() <= i ) )
00357 {
00358 m_position = i;
00359 throw ImapParserException("Unable to read more data");
00360 }
00361 if ( m_data[i] == ' ' || m_data[i] == '(' || m_data[i] == ')' || m_data[i] == '[' || m_data[i] == ']' || m_data[i] == '\n' || m_data[i] == '\r' || m_data[i] == '"') {
00362 end = i;
00363 reachedInputEnd = false;
00364 break;
00365 }
00366 if (m_data[i] == '\\')
00367 foundSlash = true;
00368 i++;
00369 }
00370 if ( reachedInputEnd )
00371 end = m_data.length();
00372
00373 result = m_data.mid( m_position, end - m_position );
00374 }
00375
00376
00377 if ( foundSlash ) {
00378 while ( result.contains( "\\\"" ) )
00379 result.replace( "\\\"", "\"" );
00380 while ( result.contains( "\\\\" ) )
00381 result.replace( "\\\\", "\\" );
00382 }
00383 m_position = end;
00384 return result;
00385 }
00386
00387 qint64 ImapStreamParser::readNumber( bool * ok )
00388 {
00389 qint64 result;
00390 if ( ok )
00391 *ok = false;
00392 if (! waitForMoreData( m_data.length() == 0 ) )
00393 throw ImapParserException("Unable to read more data");
00394 stripLeadingSpaces();
00395 if ( !waitForMoreData( m_position >= m_data.length() ) )
00396 throw ImapParserException("Unable to read more data");
00397 if ( m_position >= m_data.length() )
00398 throw ImapParserException("Unable to read more data");
00399 int i = m_position;
00400 Q_FOREVER {
00401 if ( !waitForMoreData( m_data.length() <= i ) )
00402 {
00403 m_position = i;
00404 throw ImapParserException("Unable to read more data");
00405 }
00406 if ( !isdigit( m_data.at( i ) ) )
00407 break;
00408 ++i;
00409 }
00410 const QByteArray tmp = m_data.mid( m_position, i - m_position );
00411 result = tmp.toLongLong( ok );
00412 m_position = i;
00413 return result;
00414 }
00415
00416 void ImapStreamParser::stripLeadingSpaces()
00417 {
00418 for ( int i = m_position; i < m_data.length(); ++i ) {
00419 if ( m_data[i] != ' ' )
00420 {
00421 m_position = i;
00422 return;
00423 }
00424 }
00425 m_position = m_data.length();
00426 }
00427
00428 bool ImapStreamParser::waitForMoreData( bool wait )
00429 {
00430 if ( wait ) {
00431 if ( m_socket->bytesAvailable() > 0 ||
00432 m_socket->waitForReadyRead(30000) ) {
00433 m_data.append( m_socket->readAll() );
00434 } else
00435 {
00436 return false;
00437 }
00438 }
00439 return true;
00440 }
00441
00442 void ImapStreamParser::setData( const QByteArray &data )
00443 {
00444 m_data = data;
00445 }
00446
00447 QByteArray ImapStreamParser::readRemainingData()
00448 {
00449 return m_data.mid(m_position);
00450 }
00451
00452 int ImapStreamParser::availableDataSize() const
00453 {
00454 return m_socket->bytesAvailable()+m_data.size()-m_position;
00455 }
00456
00457 bool ImapStreamParser::atCommandEnd()
00458 {
00459 if ( !waitForMoreData( m_position >= m_data.length() ) )
00460 throw ImapParserException("Unable to read more data");
00461 int savedPos = m_position;
00462 stripLeadingSpaces();
00463 if ( m_data[m_position] == '\n' || m_data[m_position] == '\r') {
00464 if ( m_position < m_data.length() && m_data[m_position] == '\r' )
00465 ++m_position;
00466 if ( m_position < m_data.length() && m_data[m_position] == '\n' )
00467 ++m_position;
00468
00469
00470 m_data = m_data.right(m_data.size()-m_position);
00471 m_position = 0;
00472
00473 return true;
00474 }
00475 m_position = savedPos;
00476 return false;
00477 }
00478
00479 QByteArray ImapStreamParser::readUntilCommandEnd()
00480 {
00481 QByteArray result;
00482 int i = m_position;
00483 int paranthesisBalance = 0;
00484 Q_FOREVER {
00485 if ( !waitForMoreData( m_data.length() <= i ) )
00486 {
00487 m_position = i;
00488 throw ImapParserException("Unable to read more data");
00489 }
00490 if ( m_data[i] == '{' )
00491 {
00492 m_position = i - 1;
00493 hasLiteral();
00494 result.append(m_data.mid(i-1, m_position - i +1));
00495 while (!atLiteralEnd())
00496 {
00497 result.append( readLiteralPart() );
00498 }
00499 i = m_position;
00500 }
00501 if ( m_data[i] == '(' )
00502 paranthesisBalance++;
00503 if ( m_data[i] == ')' )
00504 paranthesisBalance--;
00505 if ( ( i == m_data.length() && paranthesisBalance == 0 ) || m_data[i] == '\n' || m_data[i] == '\r')
00506 break;
00507 result.append( m_data[i]);
00508 ++i;
00509 }
00510 m_position = i;
00511 atCommandEnd();
00512 return result;
00513 }
00514
00515 void ImapStreamParser::sendContinuationResponse()
00516 {
00517 QByteArray block = "+ Ready for literal data (expecting "
00518 + QByteArray::number( m_continuationSize ) + " bytes)\r\n";
00519 m_socket->write(block);
00520 m_socket->waitForBytesWritten(30000);
00521 }