23 #include "servertest.h"
26 #include <mailtransport/transportbase.h>
31 #include <QProgressBar>
35 #include <KLocalizedString>
38 using namespace MailTransport;
40 namespace MailTransport {
42 class ServerTestPrivate
55 QSet< int > connectionResults;
56 QHash< int, QList<int> > authenticationResults;
57 QSet< ServerTest::Capability > capabilityResults;
58 QHash< int, uint > customPorts;
59 QTimer *normalSocketTimer;
60 QTimer *secureSocketTimer;
61 QTimer *progressTimer;
63 QProgressBar *testProgress;
65 bool secureSocketFinished;
66 bool normalSocketFinished;
77 void handleSMTPIMAPResponse(
int type,
const QString &text );
80 const QString &response,
bool *shouldStartTLS );
81 QList< int > parseAuthenticationList(
const QStringList &authentications );
84 void slotNormalPossible();
85 void slotNormalNotPossible();
86 void slotSslPossible();
87 void slotSslNotPossible();
89 void slotReadNormal(
const QString &text );
90 void slotReadSecure(
const QString &text );
91 void slotUpdateProgress();
96 ServerTestPrivate::ServerTestPrivate(
ServerTest *test )
97 : q( test ), testProgress( 0 ), secureSocketFinished( false ),
98 normalSocketFinished( false ), tlsFinished( false ),
99 normalPossible( true ), securePossible( true )
103 void ServerTestPrivate::finalResult()
105 if ( !secureSocketFinished || !normalSocketFinished || !tlsFinished ) {
109 kDebug() <<
"Modes:" << connectionResults;
110 kDebug() <<
"Capabilities:" << capabilityResults;
111 kDebug() <<
"Normal:" << q->normalProtocols();
112 kDebug() <<
"SSL:" << q->secureProtocols();
113 kDebug() <<
"TLS:" << q->tlsProtocols();
115 if ( testProgress ) {
116 testProgress->hide();
118 progressTimer->stop();
119 secureSocketFinished =
false;
120 normalSocketFinished =
false;
121 tlsFinished = false ;
123 emit q->finished( connectionResults.toList() );
126 QList< int > ServerTestPrivate::parseAuthenticationList(
const QStringList &authentications )
129 for ( QStringList::ConstIterator it = authentications.begin();
130 it != authentications.end(); ++it ) {
131 QString current = ( *it ).toUpper();
132 if ( current == QLatin1String(
"LOGIN" ) ) {
133 result << Transport::EnumAuthenticationType::LOGIN;
134 }
else if ( current == QLatin1String(
"PLAIN" ) ) {
135 result << Transport::EnumAuthenticationType::PLAIN;
136 }
else if ( current == QLatin1String(
"CRAM-MD5" ) ) {
137 result << Transport::EnumAuthenticationType::CRAM_MD5;
138 }
else if ( current == QLatin1String(
"DIGEST-MD5" ) ) {
139 result << Transport::EnumAuthenticationType::DIGEST_MD5;
140 }
else if ( current == QLatin1String(
"NTLM" ) ) {
141 result << Transport::EnumAuthenticationType::NTLM;
142 }
else if ( current == QLatin1String(
"GSSAPI" ) ) {
143 result << Transport::EnumAuthenticationType::GSSAPI;
144 }
else if ( current == QLatin1String(
"ANONYMOUS" ) ) {
145 result << Transport::EnumAuthenticationType::ANONYMOUS;
149 kDebug() << authentications << result;
154 if ( result.contains( Transport::EnumAuthenticationType::PLAIN ) ) {
155 result.removeAll( Transport::EnumAuthenticationType::LOGIN );
161 void ServerTestPrivate::handleSMTPIMAPResponse(
int type,
const QString &text )
163 if ( !text.contains( QLatin1String(
"AUTH" ), Qt::CaseInsensitive ) ) {
164 kDebug() <<
"No authentication possible";
168 QStringList protocols;
169 protocols << QLatin1String(
"LOGIN" ) << QLatin1String(
"PLAIN" )
170 << QLatin1String(
"CRAM-MD5" ) << QLatin1String(
"DIGEST-MD5" )
171 << QLatin1String(
"NTLM" ) << QLatin1String(
"GSSAPI" )
172 << QLatin1String(
"ANONYMOUS" );
175 for (
int i = 0; i < protocols.count(); ++i ) {
176 if ( text.contains( protocols.at( i ), Qt::CaseInsensitive ) ) {
177 results.append( protocols.at( i ) );
181 authenticationResults[type] = parseAuthenticationList( results );
184 if ( authenticationResults[type].size() == 0 ) {
185 authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
188 kDebug() <<
"For type" << type <<
", we have:" << authenticationResults[type];
191 void ServerTestPrivate::slotNormalPossible()
193 normalSocketTimer->stop();
194 connectionResults << Transport::EnumEncryption::None;
199 if ( testProtocol == IMAP_PROTOCOL ) {
200 socket->
write( QLatin1String(
"1 CAPABILITY" ) );
202 }
else if ( testProtocol == SMTP_PROTOCOL ) {
209 if ( !fakeHostname.isNull() ) {
210 hostname = fakeHostname;
212 hostname = QHostInfo::localHostName();
213 if ( hostname.isEmpty() ) {
214 hostname = QLatin1String(
"localhost.invalid" );
215 }
else if ( !hostname.contains( QChar::fromLatin1(
'.' ) ) ) {
216 hostname += QLatin1String(
".localnet" );
219 kDebug() <<
"Hostname for EHLO is" << hostname;
221 socket->
write( QLatin1String(
"EHLO " ) + hostname );
225 void ServerTestPrivate::slotTlsDone()
230 slotReadNormal( QString() );
234 const QString &response,
bool *shouldStartTLS )
236 Q_ASSERT( shouldStartTLS != 0 );
242 QString responseWithoutCRLF = response;
243 responseWithoutCRLF.chop( 2 );
244 QRegExp re( QLatin1String(
"<[A-Za-z0-9\\.\\-_]+@[A-Za-z0-9\\.\\-_]+>$" ),
245 Qt::CaseInsensitive );
246 if ( responseWithoutCRLF.indexOf( re ) != -1 ) {
247 authenticationResults[type] << Transport::EnumAuthenticationType::APOP;
251 authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
255 if ( type == Transport::EnumEncryption::TLS &&
256 authenticationResults[Transport::EnumEncryption::None].
257 contains( Transport::EnumAuthenticationType::APOP ) ) {
258 authenticationResults[Transport::EnumEncryption::TLS]
259 << Transport::EnumAuthenticationType::APOP;
262 socket->
write( QLatin1String(
"CAPA" ) );
267 else if ( stage == 1 ) {
277 if ( response.contains( QLatin1String(
"TOP" ) ) ) {
280 if ( response.contains( QLatin1String(
"PIPELINING" ) ) ) {
283 if ( response.contains( QLatin1String(
"UIDL" ) ) ) {
286 if ( response.contains( QLatin1String(
"STLS" ) ) ) {
287 connectionResults << Transport::EnumEncryption::TLS;
288 popSupportsTLS =
true;
290 socket->
write( QLatin1String(
"AUTH" ) );
295 else if ( stage == 2 ) {
302 QString formattedReply = response;
305 formattedReply.chop( 3 );
308 formattedReply = formattedReply.right( formattedReply.size() -
309 formattedReply.indexOf( QLatin1Char(
'\n' ) ) - 1 );
311 formattedReply.replace( QLatin1Char(
' ' ), QLatin1Char(
'-' ) ).
312 replace( QLatin1String(
"\r\n" ), QLatin1String(
" " ) );
314 authenticationResults[type] +=
315 parseAuthenticationList( formattedReply.split( QLatin1Char(
' ' ) ) );
318 *shouldStartTLS = popSupportsTLS;
326 void ServerTestPrivate::slotReadNormal(
const QString &text )
328 Q_ASSERT( encryptionMode != Transport::EnumEncryption::SSL );
329 static const int tlsHandshakeStage = 42;
331 kDebug() <<
"Stage" << normalStage + 1 <<
", Mode" << encryptionMode;
337 if ( normalStage == tlsHandshakeStage ) {
338 Q_ASSERT( encryptionMode == Transport::EnumEncryption::TLS );
340 normalSocket->startTLS();
344 bool shouldStartTLS =
false;
349 if ( testProtocol == POP_PROTOCOL ) {
350 if ( handlePopConversation( normalSocket, encryptionMode, normalStage, text,
351 &shouldStartTLS ) ) {
357 if ( normalStage == 0 ) {
358 sendInitialCapabilityQuery( normalSocket );
362 if ( text.contains( QLatin1String(
"STARTTLS" ), Qt::CaseInsensitive ) ) {
363 connectionResults << Transport::EnumEncryption::TLS;
364 shouldStartTLS =
true;
366 handleSMTPIMAPResponse( encryptionMode, text );
371 normalSocketFinished =
true;
375 if ( shouldStartTLS && encryptionMode == Transport::EnumEncryption::None ) {
376 kDebug() <<
"Trying TLS...";
377 connectionResults << Transport::EnumEncryption::TLS;
378 if ( testProtocol == POP_PROTOCOL ) {
379 normalSocket->write( QLatin1String(
"STLS" ) );
380 }
else if ( testProtocol == IMAP_PROTOCOL ) {
381 normalSocket->write( QLatin1String(
"2 STARTTLS" ) );
383 normalSocket->write( QLatin1String(
"STARTTLS" ) );
385 encryptionMode = Transport::EnumEncryption::TLS;
386 normalStage = tlsHandshakeStage;
396 void ServerTestPrivate::slotReadSecure(
const QString &text )
399 if ( testProtocol == POP_PROTOCOL ) {
401 if ( handlePopConversation( secureSocket, Transport::EnumEncryption::SSL,
402 secureStage, text, &dummy ) ) {
406 if ( secureStage == 0 ) {
407 sendInitialCapabilityQuery( secureSocket );
410 handleSMTPIMAPResponse( Transport::EnumEncryption::SSL, text );
412 secureSocketFinished =
true;
416 void ServerTestPrivate::slotNormalNotPossible()
418 normalSocketTimer->stop();
419 normalPossible =
false;
420 normalSocketFinished =
true;
425 void ServerTestPrivate::slotSslPossible()
427 secureSocketTimer->stop();
428 connectionResults << Transport::EnumEncryption::SSL;
431 void ServerTestPrivate::slotSslNotPossible()
433 secureSocketTimer->stop();
434 securePossible =
false;
435 secureSocketFinished =
true;
439 void ServerTestPrivate::slotUpdateProgress()
441 if ( testProgress ) {
442 testProgress->setValue( testProgress->value() + 1 );
449 : QWidget( parent ), d( new ServerTestPrivate( this ) )
451 d->normalSocketTimer =
new QTimer(
this );
452 d->normalSocketTimer->setSingleShot(
true );
453 connect( d->normalSocketTimer, SIGNAL(timeout()), SLOT(slotNormalNotPossible()) );
455 d->secureSocketTimer =
new QTimer(
this );
456 d->secureSocketTimer->setSingleShot(
true );
457 connect( d->secureSocketTimer, SIGNAL(timeout()), SLOT(slotSslNotPossible()) );
459 d->progressTimer =
new QTimer(
this );
460 connect( d->progressTimer, SIGNAL(timeout()), SLOT(slotUpdateProgress()) );
472 d->connectionResults.clear();
473 d->authenticationResults.clear();
474 d->capabilityResults.clear();
475 d->popSupportsTLS =
false;
478 d->encryptionMode = Transport::EnumEncryption::None;
479 d->normalPossible =
true;
480 d->securePossible =
true;
482 if ( d->testProgress ) {
483 d->testProgress->setMaximum( 20 );
484 d->testProgress->setValue( 0 );
485 d->testProgress->setTextVisible(
true );
486 d->testProgress->show();
487 d->progressTimer->start( 1000 );
492 d->normalSocket->setObjectName( QLatin1String(
"normal" ) );
493 d->normalSocket->setServer( d->server );
494 d->normalSocket->setProtocol( d->testProtocol );
495 if ( d->testProtocol == IMAP_PROTOCOL ) {
496 d->normalSocket->setPort( IMAP_PORT );
497 d->secureSocket->setPort( IMAPS_PORT );
498 }
else if ( d->testProtocol == SMTP_PROTOCOL ) {
499 d->normalSocket->setPort( SMTP_PORT );
500 d->secureSocket->setPort( SMTPS_PORT );
501 }
else if ( d->testProtocol == POP_PROTOCOL ) {
502 d->normalSocket->setPort( POP_PORT );
503 d->secureSocket->setPort( POPS_PORT );
506 if ( d->customPorts.contains( Transport::EnumEncryption::None ) ) {
507 d->normalSocket->setPort( d->customPorts.value( Transport::EnumEncryption::None ) );
509 if ( d->customPorts.contains( Transport::EnumEncryption::SSL ) ) {
510 d->secureSocket->setPort( d->customPorts.value( Transport::EnumEncryption::SSL ) );
513 connect( d->normalSocket, SIGNAL(connected()), SLOT(slotNormalPossible()) );
514 connect( d->normalSocket, SIGNAL(failed()), SLOT(slotNormalNotPossible()) );
515 connect( d->normalSocket, SIGNAL(data(QString)),
516 SLOT(slotReadNormal(QString)) );
517 connect( d->normalSocket, SIGNAL(tlsDone()), SLOT(slotTlsDone()));
518 d->normalSocket->reconnect();
519 d->normalSocketTimer->start( 10000 );
521 d->secureSocket->setObjectName( QLatin1String(
"secure" ) );
522 d->secureSocket->setServer( d->server );
523 d->secureSocket->setProtocol( d->testProtocol + QLatin1Char(
's' ) );
524 d->secureSocket->setSecure(
true );
525 connect( d->secureSocket, SIGNAL(connected()), SLOT(slotSslPossible()) );
526 connect( d->secureSocket, SIGNAL(failed()), SLOT(slotSslNotPossible()) );
527 connect( d->secureSocket, SIGNAL(data(QString)),
528 SLOT(slotReadSecure(QString)) );
529 d->secureSocket->reconnect();
530 d->secureSocketTimer->start( 10000 );
540 return d->fakeHostname;
550 Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
551 encryptionMode == Transport::EnumEncryption::SSL );
552 d->customPorts.insert( encryptionMode, port );
557 d->testProgress = pb;
567 return d->testProtocol;
577 Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
578 encryptionMode == Transport::EnumEncryption::SSL );
579 if ( d->customPorts.contains( encryptionMode ) ) {
580 return d->customPorts.value( static_cast<int>( encryptionMode ) );
588 return d->testProgress;
593 return d->authenticationResults[TransportBase::EnumEncryption::None];
598 return d->normalPossible;
603 return d->authenticationResults[TransportBase::EnumEncryption::TLS];
608 return d->authenticationResults[Transport::EnumEncryption::SSL];
613 return d->securePossible;
618 return d->capabilityResults.toList();
621 #include "moc_servertest.cpp"