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