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 concatToLast = true;
00237 result.last()+='[';
00238 ++i;
00239 continue;
00240 }
00241 if ( m_data.at(i) == ']' ) {
00242 concatToLast = false;
00243 result.last()+=']';
00244 ++i;
00245 continue;
00246 }
00247 if ( count == 0 ) {
00248 m_position = i;
00249 QByteArray ba;
00250 if (hasLiteral()) {
00251 while (!atLiteralEnd()) {
00252 ba+=readLiteralPart();
00253 }
00254 } else {
00255 ba = readString();
00256 }
00257
00258
00259
00260 while ( ( m_position < m_data.size() ) && ( m_data.at(m_position) == '\r' || m_data.at(m_position) == '\n' ) ) {
00261 m_position++;
00262 }
00263
00264 i = m_position - 1;
00265 if (concatToLast) {
00266 result.last()+=ba;
00267 } else {
00268 result.append( ba );
00269 }
00270 }
00271 ++i;
00272 }
00273
00274 throw ImapParserException( "Something went very very wrong!" );
00275 }
00276
00277 bool ImapStreamParser::hasResponseCode()
00278 {
00279 if ( !waitForMoreData( m_position >= m_data.length() ) )
00280 throw ImapParserException("Unable to read more data");
00281 int savedPos = m_position;
00282 stripLeadingSpaces();
00283 int pos = m_position;
00284 m_position = savedPos;
00285 if ( m_data.at(pos) == '[' )
00286 {
00287 m_position = pos + 1;
00288 return true;
00289 }
00290
00291 return false;
00292 }
00293
00294 bool ImapStreamParser::atResponseCodeEnd()
00295 {
00296 if ( !waitForMoreData( m_position >= m_data.length() ) )
00297 throw ImapParserException("Unable to read more data");
00298 int savedPos = m_position;
00299 stripLeadingSpaces();
00300 int pos = m_position;
00301 m_position = savedPos;
00302 if ( m_data.at(pos) == ']' )
00303 {
00304 m_position = pos + 1;
00305 return true;
00306 }
00307
00308 return false;
00309 }
00310
00311 QByteArray ImapStreamParser::parseQuotedString()
00312 {
00313 QByteArray result;
00314 if (! waitForMoreData( m_data.length() == 0 ) )
00315 throw ImapParserException("Unable to read more data");
00316 stripLeadingSpaces();
00317 int end = m_position;
00318 result.clear();
00319 if ( !waitForMoreData( m_position >= m_data.length() ) )
00320 throw ImapParserException("Unable to read more data");
00321 if ( !waitForMoreData( m_position >= m_data.length() ) )
00322 throw ImapParserException("Unable to read more data");
00323
00324 bool foundSlash = false;
00325
00326 if ( m_data.at(m_position) == '"' ) {
00327 ++m_position;
00328 int i = m_position;
00329 Q_FOREVER {
00330 if ( !waitForMoreData( m_data.length() <= i ) )
00331 {
00332 m_position = i;
00333 throw ImapParserException("Unable to read more data");
00334 }
00335 if ( m_data.at(i) == '\\' ) {
00336 i += 2;
00337 foundSlash = true;
00338 continue;
00339 }
00340 if ( m_data.at(i) == '"' ) {
00341 result = m_data.mid( m_position, i - m_position );
00342 end = i + 1;
00343 break;
00344 }
00345 ++i;
00346 }
00347 }
00348
00349
00350 else {
00351 bool reachedInputEnd = true;
00352 int i = m_position;
00353 Q_FOREVER {
00354 if ( !waitForMoreData( m_data.length() <= i ) )
00355 {
00356 m_position = i;
00357 throw ImapParserException("Unable to read more data");
00358 }
00359 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) == '"') {
00360 end = i;
00361 reachedInputEnd = false;
00362 break;
00363 }
00364 if (m_data.at(i) == '\\')
00365 foundSlash = true;
00366 i++;
00367 }
00368 if ( reachedInputEnd )
00369 end = m_data.length();
00370
00371 result = m_data.mid( m_position, end - m_position );
00372 }
00373
00374
00375 if ( foundSlash ) {
00376 while ( result.contains( "\\\"" ) )
00377 result.replace( "\\\"", "\"" );
00378 while ( result.contains( "\\\\" ) )
00379 result.replace( "\\\\", "\\" );
00380 }
00381 m_position = end;
00382 return result;
00383 }
00384
00385 qint64 ImapStreamParser::readNumber( bool * ok )
00386 {
00387 qint64 result;
00388 if ( ok )
00389 *ok = false;
00390 if (! waitForMoreData( m_data.length() == 0 ) )
00391 throw ImapParserException("Unable to read more data");
00392 stripLeadingSpaces();
00393 if ( !waitForMoreData( m_position >= m_data.length() ) )
00394 throw ImapParserException("Unable to read more data");
00395 if ( m_position >= m_data.length() )
00396 throw ImapParserException("Unable to read more data");
00397 int i = m_position;
00398 Q_FOREVER {
00399 if ( !waitForMoreData( m_data.length() <= i ) )
00400 {
00401 m_position = i;
00402 throw ImapParserException("Unable to read more data");
00403 }
00404 if ( !isdigit( m_data.at( i ) ) )
00405 break;
00406 ++i;
00407 }
00408 const QByteArray tmp = m_data.mid( m_position, i - m_position );
00409 result = tmp.toLongLong( ok );
00410 m_position = i;
00411 return result;
00412 }
00413
00414 void ImapStreamParser::stripLeadingSpaces()
00415 {
00416 for ( int i = m_position; i < m_data.length(); ++i ) {
00417 if ( m_data.at(i) != ' ' )
00418 {
00419 m_position = i;
00420 return;
00421 }
00422 }
00423 m_position = m_data.length();
00424 }
00425
00426 bool ImapStreamParser::waitForMoreData( bool wait )
00427 {
00428 if ( wait ) {
00429 if ( m_socket->bytesAvailable() > 0 ||
00430 m_socket->waitForReadyRead(30000) ) {
00431 m_data.append( m_socket->readAll() );
00432 } else
00433 {
00434 return false;
00435 }
00436 }
00437 return true;
00438 }
00439
00440 void ImapStreamParser::setData( const QByteArray &data )
00441 {
00442 m_data = data;
00443 }
00444
00445 QByteArray ImapStreamParser::readRemainingData()
00446 {
00447 return m_data.mid(m_position);
00448 }
00449
00450 int ImapStreamParser::availableDataSize() const
00451 {
00452 return m_socket->bytesAvailable()+m_data.size()-m_position;
00453 }
00454
00455 bool ImapStreamParser::atCommandEnd()
00456 {
00457 int savedPos = m_position;
00458 do {
00459 if ( !waitForMoreData( m_position >= m_data.length() ) )
00460 throw ImapParserException("Unable to read more data");
00461 stripLeadingSpaces();
00462 } while ( m_position >= m_data.size() );
00463
00464 if ( m_data.at(m_position) == '\n' || m_data.at(m_position) == '\r') {
00465 if ( m_data.at(m_position) == '\r' )
00466 ++m_position;
00467 if ( m_position < m_data.length() && m_data.at(m_position) == '\n' )
00468 ++m_position;
00469
00470
00471 trimBuffer();
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.at(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.at(i) == '(' )
00502 paranthesisBalance++;
00503 if ( m_data.at(i) == ')' )
00504 paranthesisBalance--;
00505 if ( ( i == m_data.length() && paranthesisBalance == 0 ) || m_data.at(i) == '\n' || m_data.at(i) == '\r')
00506 break;
00507 result.append( m_data.at(i) );
00508 ++i;
00509 }
00510 m_position = i;
00511 atCommandEnd();
00512 return result;
00513 }
00514
00515 void ImapStreamParser::sendContinuationResponse( qint64 size )
00516 {
00517 QByteArray block = "+ Ready for literal data (expecting "
00518 + QByteArray::number( size ) + " bytes)\r\n";
00519 m_socket->write(block);
00520 m_socket->waitForBytesWritten(30000);
00521 }
00522
00523 void ImapStreamParser::trimBuffer()
00524 {
00525 if ( m_position < 4096 )
00526 return;
00527 m_data = m_data.right(m_data.size()-m_position);
00528 m_position = 0;
00529 }