KIMAP Library
imapstreamparser.cpp
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, bool serverModeEnabled )
00032 {
00033 m_socket = socket;
00034 m_isServerModeEnabled = serverModeEnabled;
00035 m_position = 0;
00036 m_literalSize = 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.at(pos) == '{' )
00083 return true;
00084 if (m_data.at(pos) == '"' )
00085 return true;
00086 if ( m_data.at(pos) != ' ' &&
00087 m_data.at(pos) != '(' &&
00088 m_data.at(pos) != ')' &&
00089 m_data.at(pos) != '[' &&
00090 m_data.at(pos) != ']' &&
00091 m_data.at(pos) != '\n' &&
00092 m_data.at(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.at(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.at(m_position) == '\r' )
00118 ++m_position;
00119 if ( m_position < m_data.length() && m_data.at(m_position) == '\n' )
00120 ++m_position;
00121
00122
00123 if (m_isServerModeEnabled && m_literalSize > 0)
00124 sendContinuationResponse( m_literalSize );
00125 return true;
00126 } else
00127 {
00128 m_position = savedPos;
00129 return false;
00130 }
00131 }
00132
00133 bool ImapStreamParser::atLiteralEnd() const
00134 {
00135 return (m_literalSize == 0);
00136 }
00137
00138 QByteArray ImapStreamParser::readLiteralPart()
00139 {
00140 static qint64 maxLiteralPartSize = 4096;
00141 int size = qMin(maxLiteralPartSize, m_literalSize);
00142
00143 if ( !waitForMoreData( m_data.length() < m_position + size ) )
00144 throw ImapParserException("Unable to read more data");
00145
00146 if ( m_data.length() < m_position + size ) {
00147
00148 size = m_data.length() - m_position;
00149 }
00150
00151 QByteArray result = m_data.mid(m_position, size);
00152 m_position += size;
00153 m_literalSize -= size;
00154 Q_ASSERT(m_literalSize >= 0);
00155 trimBuffer();
00156
00157 return result;
00158 }
00159
00160 bool ImapStreamParser::hasList()
00161 {
00162 if ( !waitForMoreData( m_position >= m_data.length() ) )
00163 throw ImapParserException("Unable to read more data");
00164 int savedPos = m_position;
00165 stripLeadingSpaces();
00166 int pos = m_position;
00167 m_position = savedPos;
00168 if ( m_data.at(pos) == '(' )
00169 {
00170 return true;
00171 }
00172
00173 return false;
00174 }
00175
00176 bool ImapStreamParser::atListEnd()
00177 {
00178 if ( !waitForMoreData( m_position >= m_data.length() ) )
00179 throw ImapParserException("Unable to read more data");
00180 int savedPos = m_position;
00181 stripLeadingSpaces();
00182 int pos = m_position;
00183 m_position = savedPos;
00184 if ( m_data.at(pos) == ')' )
00185 {
00186 m_position = pos + 1;
00187 return true;
00188 }
00189
00190 return false;
00191 }
00192
00193 QList<QByteArray> ImapStreamParser::readParenthesizedList()
00194 {
00195 QList<QByteArray> result;
00196 if (! waitForMoreData( m_data.length() <= m_position ) )
00197 throw ImapParserException("Unable to read more data");
00198
00199 stripLeadingSpaces();
00200 if ( m_data.at(m_position) != '(' )
00201 return result;
00202
00203 bool concatToLast = false;
00204 int count = 0;
00205 int sublistbegin = m_position;
00206 int i = m_position + 1;
00207 Q_FOREVER {
00208 if ( !waitForMoreData( m_data.length() <= i ) )
00209 {
00210 m_position = i;
00211 throw ImapParserException("Unable to read more data");
00212 }
00213 if ( m_data.at(i) == '(' ) {
00214 ++count;
00215 if ( count == 1 )
00216 sublistbegin = i;
00217 ++i;
00218 continue;
00219 }
00220 if ( m_data.at(i) == ')' ) {
00221 if ( count <= 0 ) {
00222 m_position = i + 1;
00223 return result;
00224 }
00225 if ( count == 1 )
00226 result.append( m_data.mid( sublistbegin, i - sublistbegin + 1 ) );
00227 --count;
00228 ++i;
00229 continue;
00230 }
00231 if ( m_data.at(i) == ' ' ) {
00232 ++i;
00233 continue;
00234 }
00235 if ( m_data.at(i) == '"' ) {
00236 if ( count > 0 ) {
00237 m_position = i;
00238 parseQuotedString();
00239 i = m_position;
00240 continue;
00241 }
00242 }
00243 if ( m_data.at(i) == '[' ) {
00244 concatToLast = true;
00245 result.last()+='[';
00246 ++i;
00247 continue;
00248 }
00249 if ( m_data.at(i) == ']' ) {
00250 concatToLast = false;
00251 result.last()+=']';
00252 ++i;
00253 continue;
00254 }
00255 if ( count == 0 ) {
00256 m_position = i;
00257 QByteArray ba;
00258 if (hasLiteral()) {
00259 while (!atLiteralEnd()) {
00260 ba+=readLiteralPart();
00261 }
00262 } else {
00263 ba = readString();
00264 }
00265
00266
00267
00268 while ( ( m_position < m_data.size() ) && ( m_data.at(m_position) == '\r' || m_data.at(m_position) == '\n' ) ) {
00269 m_position++;
00270 }
00271
00272 i = m_position - 1;
00273 if (concatToLast) {
00274 result.last()+=ba;
00275 } else {
00276 result.append( ba );
00277 }
00278 }
00279 ++i;
00280 }
00281
00282 throw ImapParserException( "Something went very very wrong!" );
00283 }
00284
00285 bool ImapStreamParser::hasResponseCode()
00286 {
00287 if ( !waitForMoreData( m_position >= m_data.length() ) )
00288 throw ImapParserException("Unable to read more data");
00289 int savedPos = m_position;
00290 stripLeadingSpaces();
00291 int pos = m_position;
00292 m_position = savedPos;
00293 if ( m_data.at(pos) == '[' )
00294 {
00295 m_position = pos + 1;
00296 return true;
00297 }
00298
00299 return false;
00300 }
00301
00302 bool ImapStreamParser::atResponseCodeEnd()
00303 {
00304 if ( !waitForMoreData( m_position >= m_data.length() ) )
00305 throw ImapParserException("Unable to read more data");
00306 int savedPos = m_position;
00307 stripLeadingSpaces();
00308 int pos = m_position;
00309 m_position = savedPos;
00310 if ( m_data.at(pos) == ']' )
00311 {
00312 m_position = pos + 1;
00313 return true;
00314 }
00315
00316 return false;
00317 }
00318
00319 QByteArray ImapStreamParser::parseQuotedString()
00320 {
00321 QByteArray result;
00322 if (! waitForMoreData( m_data.length() == 0 ) )
00323 throw ImapParserException("Unable to read more data");
00324 stripLeadingSpaces();
00325 int end = m_position;
00326 result.clear();
00327 if ( !waitForMoreData( m_position >= m_data.length() ) )
00328 throw ImapParserException("Unable to read more data");
00329 if ( !waitForMoreData( m_position >= m_data.length() ) )
00330 throw ImapParserException("Unable to read more data");
00331
00332 bool foundSlash = false;
00333
00334 if ( m_data.at(m_position) == '"' ) {
00335 ++m_position;
00336 int i = m_position;
00337 Q_FOREVER {
00338 if ( !waitForMoreData( m_data.length() <= i ) )
00339 {
00340 m_position = i;
00341 throw ImapParserException("Unable to read more data");
00342 }
00343 if ( m_data.at(i) == '\\' ) {
00344 i += 2;
00345 foundSlash = true;
00346 continue;
00347 }
00348 if ( m_data.at(i) == '"' ) {
00349 result = m_data.mid( m_position, i - m_position );
00350 end = i + 1;
00351 break;
00352 }
00353 ++i;
00354 }
00355 }
00356
00357
00358 else {
00359 bool reachedInputEnd = true;
00360 int i = m_position;
00361 Q_FOREVER {
00362 if ( !waitForMoreData( m_data.length() <= i ) )
00363 {
00364 m_position = i;
00365 throw ImapParserException("Unable to read more data");
00366 }
00367 if ( m_data.at(i) == ' ' || m_data.at(i) == '(' || m_data.at(i) == ')' || m_data.at(i) == '[' || m_data.at(i) == ']' || m_data.at(i) == '\n' || m_data.at(i) == '\r' || m_data.at(i) == '"') {
00368 end = i;
00369 reachedInputEnd = false;
00370 break;
00371 }
00372 if (m_data.at(i) == '\\')
00373 foundSlash = true;
00374 i++;
00375 }
00376 if ( reachedInputEnd )
00377 end = m_data.length();
00378
00379 result = m_data.mid( m_position, end - m_position );
00380 }
00381
00382
00383 if ( foundSlash ) {
00384 while ( result.contains( "\\\"" ) )
00385 result.replace( "\\\"", "\"" );
00386 while ( result.contains( "\\\\" ) )
00387 result.replace( "\\\\", "\\" );
00388 }
00389 m_position = end;
00390 return result;
00391 }
00392
00393 qint64 ImapStreamParser::readNumber( bool * ok )
00394 {
00395 qint64 result;
00396 if ( ok )
00397 *ok = false;
00398 if (! waitForMoreData( m_data.length() == 0 ) )
00399 throw ImapParserException("Unable to read more data");
00400 stripLeadingSpaces();
00401 if ( !waitForMoreData( m_position >= m_data.length() ) )
00402 throw ImapParserException("Unable to read more data");
00403 if ( m_position >= m_data.length() )
00404 throw ImapParserException("Unable to read more data");
00405 int i = m_position;
00406 Q_FOREVER {
00407 if ( !waitForMoreData( m_data.length() <= i ) )
00408 {
00409 m_position = i;
00410 throw ImapParserException("Unable to read more data");
00411 }
00412 if ( !isdigit( m_data.at( i ) ) )
00413 break;
00414 ++i;
00415 }
00416 const QByteArray tmp = m_data.mid( m_position, i - m_position );
00417 result = tmp.toLongLong( ok );
00418 m_position = i;
00419 return result;
00420 }
00421
00422 void ImapStreamParser::stripLeadingSpaces()
00423 {
00424 for ( int i = m_position; i < m_data.length(); ++i ) {
00425 if ( m_data.at(i) != ' ' )
00426 {
00427 m_position = i;
00428 return;
00429 }
00430 }
00431 m_position = m_data.length();
00432 }
00433
00434 bool ImapStreamParser::waitForMoreData( bool wait )
00435 {
00436 if ( wait ) {
00437 if ( m_socket->bytesAvailable() > 0 ||
00438 m_socket->waitForReadyRead(30000) ) {
00439 m_data.append( m_socket->readAll() );
00440 } else
00441 {
00442 return false;
00443 }
00444 }
00445 return true;
00446 }
00447
00448 void ImapStreamParser::setData( const QByteArray &data )
00449 {
00450 m_data = data;
00451 }
00452
00453 QByteArray ImapStreamParser::readRemainingData()
00454 {
00455 return m_data.mid(m_position);
00456 }
00457
00458 int ImapStreamParser::availableDataSize() const
00459 {
00460 return m_socket->bytesAvailable()+m_data.size()-m_position;
00461 }
00462
00463 bool ImapStreamParser::atCommandEnd()
00464 {
00465 int savedPos = m_position;
00466 do {
00467 if ( !waitForMoreData( m_position >= m_data.length() ) )
00468 throw ImapParserException("Unable to read more data");
00469 stripLeadingSpaces();
00470 } while ( m_position >= m_data.size() );
00471
00472 if ( m_data.at(m_position) == '\n' || m_data.at(m_position) == '\r') {
00473 if ( m_data.at(m_position) == '\r' )
00474 ++m_position;
00475 if ( m_position < m_data.length() && m_data.at(m_position) == '\n' )
00476 ++m_position;
00477
00478
00479 trimBuffer();
00480
00481 return true;
00482 }
00483 m_position = savedPos;
00484 return false;
00485 }
00486
00487 QByteArray ImapStreamParser::readUntilCommandEnd()
00488 {
00489 QByteArray result;
00490 int i = m_position;
00491 int paranthesisBalance = 0;
00492 Q_FOREVER {
00493 if ( !waitForMoreData( m_data.length() <= i ) )
00494 {
00495 m_position = i;
00496 throw ImapParserException("Unable to read more data");
00497 }
00498 if ( m_data.at(i) == '{' )
00499 {
00500 m_position = i - 1;
00501 hasLiteral();
00502 result.append(m_data.mid(i-1, m_position - i +1));
00503 while (!atLiteralEnd())
00504 {
00505 result.append( readLiteralPart() );
00506 }
00507 i = m_position;
00508 }
00509 if ( m_data.at(i) == '(' )
00510 paranthesisBalance++;
00511 if ( m_data.at(i) == ')' )
00512 paranthesisBalance--;
00513 if ( ( i == m_data.length() && paranthesisBalance == 0 ) || m_data.at(i) == '\n' || m_data.at(i) == '\r')
00514 break;
00515 result.append( m_data.at(i) );
00516 ++i;
00517 }
00518 m_position = i;
00519 atCommandEnd();
00520 return result;
00521 }
00522
00523 void ImapStreamParser::sendContinuationResponse( qint64 size )
00524 {
00525 QByteArray block = "+ Ready for literal data (expecting "
00526 + QByteArray::number( size ) + " bytes)\r\n";
00527 m_socket->write(block);
00528 m_socket->waitForBytesWritten(30000);
00529 }
00530
00531 void ImapStreamParser::trimBuffer()
00532 {
00533 if ( m_position < 4096 )
00534 return;
00535 m_data = m_data.right(m_data.size()-m_position);
00536 m_position = 0;
00537 }