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
00374 if ( foundSlash ) {
00375 while ( result.contains( "\\\"" ) )
00376 result.replace( "\\\"", "\"" );
00377 while ( result.contains( "\\\\" ) )
00378 result.replace( "\\\\", "\\" );
00379 }
00380 m_position = end;
00381 return result;
00382 }
00383
00384 qint64 ImapStreamParser::readNumber( bool * ok )
00385 {
00386 qint64 result;
00387 if ( ok )
00388 *ok = false;
00389 if (! waitForMoreData( m_data.length() == 0 ) )
00390 throw ImapParserException("Unable to read more data");
00391 stripLeadingSpaces();
00392 if ( !waitForMoreData( m_position >= m_data.length() ) )
00393 throw ImapParserException("Unable to read more data");
00394 if ( m_position >= m_data.length() )
00395 throw ImapParserException("Unable to read more data");
00396 int i = m_position;
00397 Q_FOREVER {
00398 if ( !waitForMoreData( m_data.length() <= i ) )
00399 {
00400 m_position = i;
00401 throw ImapParserException("Unable to read more data");
00402 }
00403 if ( !isdigit( m_data.at( i ) ) )
00404 break;
00405 ++i;
00406 }
00407 const QByteArray tmp = m_data.mid( m_position, i - m_position );
00408 result = tmp.toLongLong( ok );
00409 m_position = i;
00410 return result;
00411 }
00412
00413 void ImapStreamParser::stripLeadingSpaces()
00414 {
00415 for ( int i = m_position; i < m_data.length(); ++i ) {
00416 if ( m_data[i] != ' ' )
00417 {
00418 m_position = i;
00419 return;
00420 }
00421 }
00422 m_position = m_data.length();
00423 }
00424
00425 bool ImapStreamParser::waitForMoreData( bool wait )
00426 {
00427 if ( wait ) {
00428 if ( m_socket->bytesAvailable() > 0 ||
00429 m_socket->waitForReadyRead(30000) ) {
00430 m_data.append( m_socket->readAll() );
00431 } else
00432 {
00433 return false;
00434 }
00435 }
00436 return true;
00437 }
00438
00439 void ImapStreamParser::setData( const QByteArray &data )
00440 {
00441 m_data = data;
00442 }
00443
00444 QByteArray ImapStreamParser::readRemainingData()
00445 {
00446 return m_data.mid(m_position);
00447 }
00448
00449 int ImapStreamParser::availableDataSize() const
00450 {
00451 return m_socket->bytesAvailable()+m_data.size()-m_position;
00452 }
00453
00454 bool ImapStreamParser::atCommandEnd()
00455 {
00456 if ( !waitForMoreData( m_position >= m_data.length() ) )
00457 throw ImapParserException("Unable to read more data");
00458 int savedPos = m_position;
00459 stripLeadingSpaces();
00460 if ( m_data[m_position] == '\n' || m_data[m_position] == '\r') {
00461 if ( m_position < m_data.length() && m_data[m_position] == '\r' )
00462 ++m_position;
00463 if ( m_position < m_data.length() && m_data[m_position] == '\n' )
00464 ++m_position;
00465
00466
00467 m_data = m_data.right(m_data.size()-m_position);
00468 m_position = 0;
00469
00470 return true;
00471 }
00472 m_position = savedPos;
00473 return false;
00474 }
00475
00476 QByteArray ImapStreamParser::readUntilCommandEnd()
00477 {
00478 QByteArray result;
00479 int i = m_position;
00480 int paranthesisBalance = 0;
00481 Q_FOREVER {
00482 if ( !waitForMoreData( m_data.length() <= i ) )
00483 {
00484 m_position = i;
00485 throw ImapParserException("Unable to read more data");
00486 }
00487 if ( m_data[i] == '{' )
00488 {
00489 m_position = i - 1;
00490 hasLiteral();
00491 result.append(m_data.mid(i-1, m_position - i +1));
00492 while (!atLiteralEnd())
00493 {
00494 result.append( readLiteralPart() );
00495 }
00496 i = m_position;
00497 }
00498 if ( m_data[i] == '(' )
00499 paranthesisBalance++;
00500 if ( m_data[i] == ')' )
00501 paranthesisBalance--;
00502 result.append( m_data[i]);
00503 if ( ( i == m_data.length() && paranthesisBalance == 0 ) || m_data[i] == '\n' || m_data[i] == '\r')
00504 break;
00505 ++i;
00506 }
00507 m_position = i + 1;
00508 return result;
00509 }
00510
00511 void ImapStreamParser::sendContinuationResponse()
00512 {
00513 QByteArray block = "+ Ready for literal data (expecting "
00514 + QByteArray::number( m_continuationSize ) + " bytes)\r\n";
00515 m_socket->write(block);
00516 m_socket->waitForBytesWritten(30000);
00517 }