• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • KDE Home
  • Contact Us
 

mailtransport

servertest.cpp
00001 /*
00002     Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
00003     Copyright (C) 2007 KovoKs <info@kovoks.nl>
00004     Copyright (c) 2008 Thomas McGuire <thomas.mcguire@gmx.net>
00005 
00006     This library is free software; you can redistribute it and/or modify it
00007     under the terms of the GNU Library General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or (at your
00009     option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful, but WITHOUT
00012     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00014     License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to the
00018     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00019     02110-1301, USA.
00020 */
00021 
00022 // Own
00023 #include "servertest.h"
00024 #include "socket.h"
00025 
00026 #include <mailtransport/transportbase.h>
00027 #include <mailtransport/mailtransport_defs.h>
00028 
00029 // Qt
00030 #include <QHostInfo>
00031 #include <QProgressBar>
00032 #include <QTimer>
00033 
00034 // KDE
00035 #include <KLocalizedString>
00036 #include <KDebug>
00037 
00038 using namespace MailTransport;
00039 
00040 namespace MailTransport
00041 {
00042 
00043 class ServerTestPrivate
00044 {
00045   public:
00046     ServerTestPrivate( ServerTest *test );
00047 
00048     ServerTest *const              q;
00049     QString                        server;
00050     QString                        fakeHostname;
00051     QString                        testProtocol;
00052 
00053     MailTransport::Socket         *normalSocket;
00054     MailTransport::Socket         *secureSocket;
00055 
00056     QSet< int >                    connectionResults;
00057     QHash< int, QList<int> >       authenticationResults;
00058     QSet< ServerTest::Capability > capabilityResults;
00059     QHash< int, uint >             customPorts;
00060     QTimer                        *normalSocketTimer;
00061     QTimer                        *secureSocketTimer;
00062     QTimer                        *progressTimer;
00063 
00064     QProgressBar                  *testProgress;
00065 
00066     bool                           secureSocketFinished;
00067     bool                           normalSocketFinished;
00068     bool                           tlsFinished;
00069     bool                           popSupportsTLS;
00070     int                            normalStage;
00071     int                            secureStage;
00072     int                            encryptionMode;
00073 
00074     bool                           normalPossible;
00075     bool                           securePossible;
00076 
00077     void finalResult();
00078     void handleSMTPIMAPResponse( int type, const QString &text );
00079     void sendInitialCapabilityQuery( MailTransport::Socket *socket );
00080     bool handlePopConversation( MailTransport::Socket *socket, int type, int stage,
00081                                 const QString &response, bool *shouldStartTLS );
00082     QList< int > parseAuthenticationList( const QStringList &authentications );
00083 
00084     // slots
00085     void slotNormalPossible();
00086     void slotNormalNotPossible();
00087     void slotSslPossible();
00088     void slotSslNotPossible();
00089     void slotTlsDone();
00090     void slotReadNormal( const QString &text );
00091     void slotReadSecure( const QString &text );
00092     void slotUpdateProgress();
00093 };
00094 
00095 }
00096 
00097 ServerTestPrivate::ServerTestPrivate( ServerTest *test )
00098   : q( test ), testProgress( 0 ), secureSocketFinished( false ),
00099     normalSocketFinished( false ), tlsFinished( false ),
00100     normalPossible( true ), securePossible( true )
00101 {
00102 }
00103 
00104 void ServerTestPrivate::finalResult()
00105 {
00106   if ( !secureSocketFinished || !normalSocketFinished || !tlsFinished ) {
00107     return;
00108   }
00109 
00110   kDebug() << "Modes:" << connectionResults;
00111   kDebug() << "Capabilities:" << capabilityResults;
00112   kDebug() << "Normal:" <<  q->normalProtocols();
00113   kDebug() << "SSL:" <<  q->secureProtocols();
00114   kDebug() << "TLS:" <<  q->tlsProtocols();
00115 
00116   if ( testProgress ) {
00117     testProgress->hide();
00118   }
00119   progressTimer->stop();
00120   secureSocketFinished =  false;
00121   normalSocketFinished =  false;
00122   tlsFinished = false ;
00123 
00124   emit q->finished( connectionResults.toList() );
00125 }
00126 
00127 QList< int > ServerTestPrivate::parseAuthenticationList( const QStringList &authentications )
00128 {
00129   QList< int > result;
00130   for ( QStringList::ConstIterator it = authentications.begin();
00131         it != authentications.end(); ++it )  {
00132     QString current = (*it).toUpper();
00133     if ( current == QLatin1String( "LOGIN" ) ) {
00134       result << Transport::EnumAuthenticationType::LOGIN;
00135     } else if ( current == QLatin1String( "PLAIN" ) ) {
00136       result << Transport::EnumAuthenticationType::PLAIN;
00137     } else if ( current == QLatin1String( "CRAM-MD5" ) ) {
00138       result << Transport::EnumAuthenticationType::CRAM_MD5;
00139     } else if ( current == QLatin1String( "DIGEST-MD5" ) ) {
00140       result << Transport::EnumAuthenticationType::DIGEST_MD5;
00141     } else if ( current == QLatin1String( "NTLM" ) ) {
00142       result << Transport::EnumAuthenticationType::NTLM;
00143     } else if ( current == QLatin1String( "GSSAPI" ) ) {
00144       result << Transport::EnumAuthenticationType::GSSAPI;
00145     } else if ( current == QLatin1String( "ANONYMOUS" ) ) {
00146       result << Transport::EnumAuthenticationType::ANONYMOUS;
00147     }
00148     // APOP is handled by handlePopConversation()
00149   }
00150   kDebug() << authentications << result;
00151 
00152   // LOGIN doesn't offer anything over PLAIN, requires more server
00153   // roundtrips and is not an official SASL mechanism, but a MS-ism,
00154   // so only enable it if PLAIN isn't available:
00155   if ( result.contains( Transport::EnumAuthenticationType::PLAIN ) ) {
00156     result.removeAll( Transport::EnumAuthenticationType::LOGIN );
00157   }
00158 
00159   return result;
00160 }
00161 
00162 void ServerTestPrivate::handleSMTPIMAPResponse( int type, const QString &text )
00163 {
00164   if ( !text.contains( QLatin1String( "AUTH" ), Qt::CaseInsensitive ) ) {
00165     kDebug() << "No authentication possible";
00166     return;
00167   }
00168 
00169   QStringList protocols;
00170   protocols << QLatin1String( "LOGIN" ) << QLatin1String( "PLAIN" )
00171             << QLatin1String( "CRAM-MD5" ) << QLatin1String( "DIGEST-MD5" )
00172             << QLatin1String( "NTLM" ) << QLatin1String( "GSSAPI" )
00173             << QLatin1String( "ANONYMOUS" );
00174 
00175   QStringList results;
00176   for ( int i = 0; i < protocols.count(); ++i ) {
00177     if ( text.contains( protocols.at( i ), Qt::CaseInsensitive ) ) {
00178       results.append( protocols.at( i ) );
00179     }
00180   }
00181 
00182   authenticationResults[type] = parseAuthenticationList( results );
00183 
00184   // if we couldn't parse any authentication modes, default to clear-text
00185   if ( authenticationResults[type].size() == 0 ) {
00186     authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
00187   }
00188 
00189   kDebug() << "For type" << type << ", we have:" << authenticationResults[type];
00190 }
00191 
00192 void ServerTestPrivate::slotNormalPossible()
00193 {
00194   normalSocketTimer->stop();
00195   connectionResults << Transport::EnumEncryption::None;
00196 }
00197 
00198 void ServerTestPrivate::sendInitialCapabilityQuery( MailTransport::Socket *socket )
00199 {
00200   if ( testProtocol == IMAP_PROTOCOL ) {
00201     socket->write( QLatin1String( "1 CAPABILITY" ) );
00202   }
00203 
00204   else if ( testProtocol == SMTP_PROTOCOL ) {
00205 
00206       // Detect the hostname which we send with the EHLO command.
00207       // If there is a fake one set, use that, otherwise use the
00208       // local host name (and make sure it contains a domain, so the
00209       // server thinks it is valid).
00210     QString hostname;
00211     if ( !fakeHostname.isNull() ) {
00212       hostname = fakeHostname;
00213     } else {
00214       hostname = QHostInfo::localHostName();
00215       if ( hostname.isEmpty() ) {
00216         hostname = QLatin1String( "localhost.invalid" );
00217       } else if ( !hostname.contains( QChar::fromAscii( '.' ) ) ) {
00218         hostname += QLatin1String( ".localnet" );
00219       }
00220     }
00221     kDebug() << "Hostname for EHLO is" << hostname;
00222 
00223     socket->write( QLatin1String( "EHLO " ) + hostname );
00224   }
00225 }
00226 
00227 void ServerTestPrivate::slotTlsDone()
00228 {
00229 
00230   // The server will not send a response after starting TLS. Therefore, we have to manually
00231   // call slotReadNormal(), because this is not triggered by a data received signal this time.
00232   slotReadNormal( QString() );
00233 }
00234 
00235 bool ServerTestPrivate::handlePopConversation( MailTransport::Socket *socket, int type, int stage,
00236                                                const QString &response, bool *shouldStartTLS )
00237 {
00238   Q_ASSERT( shouldStartTLS != 0 );
00239 
00240   // Initial Greeting
00241   if ( stage == 0 ) {
00242 
00243     //Regexp taken from POP3 ioslave
00244     QString responseWithoutCRLF = response;
00245     responseWithoutCRLF.chop( 2 );
00246     QRegExp re( QLatin1String( "<[A-Za-z0-9\\.\\-_]+@[A-Za-z0-9\\.\\-_]+>$" ),
00247                 Qt::CaseInsensitive );
00248     if ( responseWithoutCRLF.indexOf( re ) != -1 ) {
00249       authenticationResults[type] << Transport::EnumAuthenticationType::APOP;
00250     }
00251 
00252     //Each server is supposed to support clear text login
00253     authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR;
00254 
00255     // If we are in TLS stage, the server does not send the initial greeting.
00256     // Assume that the APOP availability is the same as with an unsecured connection.
00257     if ( type == Transport::EnumEncryption::TLS &&
00258          authenticationResults[Transport::EnumEncryption::None].
00259          contains( Transport::EnumAuthenticationType::APOP ) ) {
00260       authenticationResults[Transport::EnumEncryption::TLS]
00261         << Transport::EnumAuthenticationType::APOP;
00262     }
00263 
00264     socket->write( QLatin1String( "CAPA" ) );
00265     return true;
00266   }
00267 
00268   // CAPA result
00269   else if ( stage == 1 ) {
00270 //     Example:
00271 //     CAPA
00272 //     +OK
00273 //     TOP
00274 //     USER
00275 //     SASL LOGIN CRAM-MD5
00276 //     UIDL
00277 //     RESP-CODES
00278 //     .
00279     if ( response.contains( QLatin1String( "TOP" ) ) ) {
00280       capabilityResults += ServerTest::Top;
00281     }
00282     if ( response.contains( QLatin1String( "PIPELINING" ) ) ) {
00283       capabilityResults += ServerTest::Pipelining;
00284     }
00285     if ( response.contains( QLatin1String( "UIDL" ) ) ) {
00286       capabilityResults += ServerTest::UIDL;
00287     }
00288     if ( response.contains( QLatin1String( "STLS" ) ) ) {
00289       connectionResults << Transport::EnumEncryption::TLS;
00290       popSupportsTLS = true;
00291     }
00292     socket->write( QLatin1String( "AUTH" ) );
00293     return true;
00294   }
00295 
00296   // AUTH response
00297   else if ( stage == 2 ) {
00298 //     Example:
00299 //     C: AUTH
00300 //     S: +OK List of supported authentication methods follows
00301 //     S: LOGIN
00302 //     S: CRAM-MD5
00303 //     S:.
00304     QString formattedReply = response;
00305 
00306     // Get rid of trailling ".CRLF"
00307     formattedReply.chop( 3 );
00308 
00309     // Get rid of the first +OK line
00310     formattedReply = formattedReply.right( formattedReply.size() -
00311                                            formattedReply.indexOf( QLatin1Char( '\n' ) ) - 1 );
00312     formattedReply =
00313       formattedReply.replace( QLatin1Char( ' ' ), QLatin1Char( '-' ) ).
00314       replace( QLatin1String( "\r\n" ), QLatin1String( " " ) );
00315 
00316     authenticationResults[type] +=
00317       parseAuthenticationList( formattedReply.split( QLatin1Char( ' ' ) ) );
00318   }
00319 
00320   *shouldStartTLS = popSupportsTLS;
00321   return false;
00322 }
00323 
00324 // slotReadNormal() handles normal (no) encryption and TLS encryption.
00325 // At first, the communication is not encrypted, but if the server supports
00326 // the STARTTLS/STLS keyword, the same authentication query is done again
00327 // with TLS.
00328 void ServerTestPrivate::slotReadNormal( const QString &text )
00329 {
00330   Q_ASSERT( encryptionMode != Transport::EnumEncryption::SSL );
00331   static const int tlsHandshakeStage = 42;
00332 
00333   kDebug() << "Stage" << normalStage + 1 << ", Mode" << encryptionMode;
00334 
00335   // If we are in stage 42, we just do the handshake for TLS encryption and
00336   // then reset the stage to -1, so that all authentication modes and
00337   // capabilities are queried again for TLS encryption (some servers have
00338   // different authentication  methods in normal and in TLS mode).
00339   if ( normalStage == tlsHandshakeStage ) {
00340     Q_ASSERT( encryptionMode == Transport::EnumEncryption::TLS );
00341     normalStage = -1;
00342     normalSocket->startTLS();
00343     return;
00344   }
00345 
00346   bool shouldStartTLS = false;
00347   normalStage++;
00348 
00349   // Handle the whole POP converstation separatly, it is very different from
00350   // IMAP and SMTP
00351   if ( testProtocol == POP_PROTOCOL ) {
00352     if ( handlePopConversation( normalSocket, encryptionMode, normalStage, text,
00353                                 &shouldStartTLS ) ) {
00354       return;
00355     }
00356   } else {
00357     // Handle the SMTP/IMAP conversation here. We just send the EHLO command in
00358     // sendInitialCapabilityQuery.
00359     if ( normalStage == 0 ) {
00360       sendInitialCapabilityQuery( normalSocket );
00361       return;
00362     }
00363 
00364     if ( text.contains( QLatin1String( "STARTTLS" ), Qt::CaseInsensitive ) ) {
00365       connectionResults << Transport::EnumEncryption::TLS;
00366       shouldStartTLS = true;
00367     }
00368     handleSMTPIMAPResponse( encryptionMode, text );
00369   }
00370 
00371   // If we reach here, the normal authentication/capabilities query is completed.
00372   // Now do the same for TLS.
00373   normalSocketFinished = true;
00374 
00375   // If the server announced that STARTTLS/STLS is available, we'll add TLS to the
00376   // connection result, do the command and set the stage to 42 to start the handshake.
00377   if ( shouldStartTLS && encryptionMode == Transport::EnumEncryption::None ) {
00378     kDebug() << "Trying TLS...";
00379     connectionResults << Transport::EnumEncryption::TLS;
00380     if ( testProtocol == POP_PROTOCOL ) {
00381       normalSocket->write( QLatin1String( "STLS" ) );
00382     } else if ( testProtocol == IMAP_PROTOCOL ) {
00383       normalSocket->write( QLatin1String( "2 STARTTLS" ) );
00384     } else {
00385       normalSocket->write( QLatin1String( "STARTTLS" ) );
00386     }
00387     encryptionMode = Transport::EnumEncryption::TLS;
00388     normalStage = tlsHandshakeStage;
00389     return;
00390   }
00391 
00392   // If we reach here, either the TLS authentication/capabilities query is finished
00393   // or the server does not support the STARTTLS/STLS command.
00394   tlsFinished = true;
00395   finalResult();
00396 }
00397 
00398 void ServerTestPrivate::slotReadSecure( const QString &text )
00399 {
00400   secureStage++;
00401   if ( testProtocol == POP_PROTOCOL ) {
00402     bool dummy;
00403     if ( handlePopConversation( secureSocket, Transport::EnumEncryption::SSL,
00404                                 secureStage, text, &dummy ) ) {
00405       return;
00406     }
00407   } else {
00408     if ( secureStage == 0 ) {
00409       sendInitialCapabilityQuery( secureSocket );
00410       return;
00411     }
00412     handleSMTPIMAPResponse( Transport::EnumEncryption::SSL, text );
00413   }
00414   secureSocketFinished = true;
00415   finalResult();
00416 }
00417 
00418 void ServerTestPrivate::slotNormalNotPossible()
00419 {
00420   normalSocketTimer->stop();
00421   normalPossible = false;
00422   normalSocketFinished = true;
00423   tlsFinished = true;
00424   finalResult();
00425 }
00426 
00427 void ServerTestPrivate::slotSslPossible()
00428 {
00429   secureSocketTimer->stop();
00430   connectionResults << Transport::EnumEncryption::SSL;
00431 }
00432 
00433 void ServerTestPrivate::slotSslNotPossible()
00434 {
00435   secureSocketTimer->stop();
00436   securePossible = false;
00437   secureSocketFinished = true;
00438   finalResult();
00439 }
00440 
00441 void ServerTestPrivate::slotUpdateProgress()
00442 {
00443   if ( testProgress ) {
00444     testProgress->setValue( testProgress->value() + 1 );
00445   }
00446 }
00447 
00448 //---------------------- end private class -----------------------//
00449 
00450 ServerTest::ServerTest( QWidget *parent )
00451   : QWidget( parent ), d( new ServerTestPrivate( this ) )
00452 {
00453   d->normalSocketTimer = new QTimer( this );
00454   d->normalSocketTimer->setSingleShot( true );
00455   connect( d->normalSocketTimer, SIGNAL( timeout() ), SLOT( slotNormalNotPossible() ) );
00456 
00457   d->secureSocketTimer = new QTimer( this );
00458   d->secureSocketTimer->setSingleShot( true );
00459   connect( d->secureSocketTimer, SIGNAL( timeout() ), SLOT( slotSslNotPossible() ) );
00460 
00461   d->progressTimer = new QTimer( this );
00462   connect( d->progressTimer, SIGNAL( timeout() ), SLOT( slotUpdateProgress() ) );
00463 }
00464 
00465 ServerTest::~ServerTest()
00466 {
00467   delete d;
00468 }
00469 
00470 void ServerTest::start()
00471 {
00472   kDebug() << d;
00473 
00474   d->connectionResults.clear();
00475   d->authenticationResults.clear();
00476   d->capabilityResults.clear();
00477   d->popSupportsTLS = false;
00478   d->normalStage = -1;
00479   d->secureStage = -1;
00480   d->encryptionMode = Transport::EnumEncryption::None;
00481   d->normalPossible = true;
00482   d->securePossible = true;
00483 
00484   if ( d->testProgress ) {
00485     d->testProgress->setMaximum( 20 );
00486     d->testProgress->setValue( 0 );
00487     d->testProgress->setTextVisible( true );
00488     d->testProgress->show();
00489     d->progressTimer->start( 1000 );
00490   }
00491 
00492   d->normalSocket = new MailTransport::Socket( this );
00493   d->secureSocket = new MailTransport::Socket( this );
00494   d->normalSocket->setObjectName( QLatin1String( "normal" ) );
00495   d->normalSocket->setServer( d->server );
00496   d->normalSocket->setProtocol( d->testProtocol );
00497   if ( d->testProtocol == IMAP_PROTOCOL ) {
00498     d->normalSocket->setPort( IMAP_PORT );
00499     d->secureSocket->setPort( IMAPS_PORT );
00500   } else if ( d->testProtocol == SMTP_PROTOCOL ) {
00501     d->normalSocket->setPort( SMTP_PORT );
00502     d->secureSocket->setPort( SMTPS_PORT );
00503   } else if ( d->testProtocol == POP_PROTOCOL ) {
00504     d->normalSocket->setPort( POP_PORT );
00505     d->secureSocket->setPort( POPS_PORT );
00506   }
00507 
00508   if ( d->customPorts.contains( Transport::EnumEncryption::None ) ) {
00509     d->normalSocket->setPort( d->customPorts.value( Transport::EnumEncryption::None ) );
00510   }
00511   if ( d->customPorts.contains( Transport::EnumEncryption::SSL ) ) {
00512     d->secureSocket->setPort( d->customPorts.value( Transport::EnumEncryption::SSL ) );
00513   }
00514 
00515   connect( d->normalSocket, SIGNAL(connected()), SLOT(slotNormalPossible()) );
00516   connect( d->normalSocket, SIGNAL(failed()), SLOT(slotNormalNotPossible()) );
00517   connect( d->normalSocket, SIGNAL(data(const QString&)),
00518            SLOT(slotReadNormal(const QString&)) );
00519   connect( d->normalSocket, SIGNAL(tlsDone()), SLOT(slotTlsDone()));
00520   d->normalSocket->reconnect();
00521   d->normalSocketTimer->start( 10000 );
00522 
00523   d->secureSocket->setObjectName( QLatin1String( "secure" ) );
00524   d->secureSocket->setServer( d->server );
00525   d->secureSocket->setProtocol( d->testProtocol + QLatin1Char( 's' ) );
00526   d->secureSocket->setSecure( true );
00527   connect( d->secureSocket, SIGNAL(connected()), SLOT(slotSslPossible()) );
00528   connect( d->secureSocket, SIGNAL(failed()), SLOT(slotSslNotPossible()) );
00529   connect( d->secureSocket, SIGNAL(data(const QString&) ),
00530            SLOT(slotReadSecure(const QString&)) );
00531   d->secureSocket->reconnect();
00532   d->secureSocketTimer->start( 10000 );
00533 }
00534 
00535 void ServerTest::setFakeHostname( const QString &fakeHostname )
00536 {
00537   d->fakeHostname = fakeHostname;
00538 }
00539 
00540 QString ServerTest::fakeHostname()
00541 {
00542   return d->fakeHostname;
00543 }
00544 
00545 void ServerTest::setServer( const QString &server )
00546 {
00547   d->server = server;
00548 }
00549 
00550 void ServerTest::setPort( Transport::EnumEncryption::type encryptionMode, uint port )
00551 {
00552   Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
00553             encryptionMode == Transport::EnumEncryption::SSL );
00554   d->customPorts.insert( encryptionMode, port );
00555 }
00556 
00557 void ServerTest::setProgressBar( QProgressBar *pb )
00558 {
00559   d->testProgress = pb;
00560 }
00561 
00562 void ServerTest::setProtocol( const QString &protocol )
00563 {
00564   d->testProtocol = protocol;
00565 }
00566 
00567 QString ServerTest::protocol()
00568 {
00569   return d->testProtocol;
00570 }
00571 
00572 QString ServerTest::server()
00573 {
00574   return d->server;
00575 }
00576 
00577 int ServerTest::port( Transport::EnumEncryption::type encryptionMode )
00578 {
00579   Q_ASSERT( encryptionMode == Transport::EnumEncryption::None ||
00580             encryptionMode == Transport::EnumEncryption::SSL );
00581   if ( d->customPorts.contains( encryptionMode ) ) {
00582     return d->customPorts.value( static_cast<int>( encryptionMode ) );
00583   } else {
00584     return -1;
00585   }
00586 }
00587 
00588 QProgressBar *ServerTest::progressBar()
00589 {
00590   return d->testProgress;
00591 }
00592 
00593 QList< int > ServerTest::normalProtocols()
00594 {
00595   return d->authenticationResults[TransportBase::EnumEncryption::None];
00596 }
00597 
00598 bool ServerTest::isNormalPossible()
00599 {
00600   return d->normalPossible;
00601 }
00602 
00603 QList< int > ServerTest::tlsProtocols()
00604 {
00605   return d->authenticationResults[TransportBase::EnumEncryption::TLS];
00606 }
00607 
00608 QList< int > ServerTest::secureProtocols()
00609 {
00610   return d->authenticationResults[Transport::EnumEncryption::SSL];
00611 }
00612 
00613 bool ServerTest::isSecurePossible()
00614 {
00615   return d->securePossible;
00616 }
00617 
00618 QList< ServerTest::Capability > ServerTest::capabilities() const
00619 {
00620   return d->capabilityResults.toList();
00621 }
00622 
00623 #include "servertest.moc"

mailtransport

Skip menu "mailtransport"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal