📄 popclient.cpp
字号:
/******************************************************************************** Copyright (C) 2000-2006 TROLLTECH ASA. All rights reserved.**** This file is part of the Phone Edition of the Qtopia Toolkit.**** Licensees holding a valid license agreement from Trolltech or any of its** authorized distributors may use this file in accordance with** the License Agreement provided with the Licensed Software.**** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for** information about Trolltech's Commercial License Agreements.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.********** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "popclient.h"#include "emailhandler.h"PopClient::PopClient(){#ifndef SMTPAUTH createSocket();#else secureSocket = 0; socket = 0;#endif receiving = false; headerLimit = 0; preview = false;}PopClient::~PopClient(){ delete socket; delete stream;}void PopClient::createSocket(){#ifdef SMTPAUTH if(account->mailEncryption() != MailAccount::Encrypt_NONE) { if(secureSocket) return; secureSocket = new QtSslSocket(QtSslSocket::Client,this); secureSocket->setObjectName("popClient-secure"); secureSocket->setPathToCACertDir(QtMail::sslCertsPath()); connect(secureSocket,SIGNAL(connectionVerificationDone(QtSslSocket::VerifyResult, bool,const QString&)),SLOT(certCheckDone(QtSslSocket::VerifyResult,bool,const QString&))); if(socket) { delete stream; socket->deleteLater(); } socket = secureSocket; } else { if(secureSocket) { secureSocket->deleteLater(); delete stream; secureSocket = 0; socket = 0; } if(socket) return; socket = new QTcpSocket(this); socket->setObjectName("popClient"); }#else socket = new QTcpSocket(this); socket->setObjectName("popClient"); #endif connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); connect(socket, SIGNAL(connected()), this, SLOT(connectionEstablished())); connect(socket, SIGNAL(readyRead()), this, SLOT(incomingData())); stream = new QTextStream(socket); stream->setCodec("UTF-8");}#ifdef SMTPAUTHvoid PopClient::certCheckDone(QtSslSocket::VerifyResult result, bool hostnameMatch, const QString& msg){ Q_UNUSED(hostnameMatch) if(result == QtSslSocket::VerifyOk) return; qWarning(("SSL cert check failed: " + msg).toLatin1()); errorHandling(ErrLoginFailed, "");}#endifvoid PopClient::newConnection(){ if (receiving) { qWarning("socket in use, connection refused"); return; } if ( account->mailServer().isEmpty() ) { status = Exit; emit mailTransferred(0); return; } #ifdef SMTPAUTH createSocket();#endif status = Init; uidlList.clear(); uniqueUidlList.clear(); unresolvedUidl.clear(); sizeList.clear(); receiving = true; selected = false; awaitingData = false; newMessages = 0; mailDropSize = 0; messageCount = 0; internalId = QUuid(); deleteList.clear(); emit updateStatus(tr("DNS lookup")); socket->connectToHost(account->mailServer(), account->mailPort() );}void PopClient::setAccount(MailAccount *_account){ account = _account; lastUidl = account->getUidlList();}void PopClient::headersOnly(bool headers, int limit){ preview = headers; headerLimit = limit;}void PopClient::setSelectedMails(MailList *list, bool connected){ selected = true; mailList = list; messageCount = 0; mailDropSize = 0; newMessages = 0; if (connected) { status = Retr; incomingData(); }}void PopClient::connectionEstablished(){#ifdef QTOPIA_PHONE emit updateStatus(tr("Connected"));#else emit updateStatus(tr("Connection established"));#endif #ifdef SMTPAUTH if(secureSocket) qDebug("Secure connection established");#endif}void PopClient::errorHandling(int status, QString msg){ if ( receiving ) { receiving = false; account->setUidlList(lastUidl); socket->close(); emit updateStatus(tr("Error occurred")); emit errorOccurred(status, msg); }}void PopClient::socketError(QAbstractSocket::SocketError status){ QString msg = tr("Error occurred"); socket->close(); receiving = false; emit updateStatus(tr("Error occurred")); emit errorOccurred(static_cast<int>(status), msg);}void PopClient::quit(){ if ( status == Exit ) { emit mailTransferred(0); } else { status = Quit; incomingData(); }}// new implementation, need to store uids etc..void PopClient::incomingData(){ QString response, temp; if ( (status != Dele) && (status != Quit) ) response = socket->readLine(); if (status == Init) { emit updateStatus(tr("Logging in")); *stream << "USER " << account->mailUserName() << "\r\n" << flush; status = Pass; } else if (status == Pass) { if (response[0] != '+') { errorHandling(ErrLoginFailed, ""); return; } *stream << "PASS " << account->mailPassword() << "\r\n" << flush; status = Uidl; } else if (status == Uidl) { if (response[0] != '+') { errorHandling(ErrLoginFailed, ""); return; } status = Guidl; awaitingData = false; *stream << "UIDL\r\n" << flush; return; } else if (status == Guidl) { //get list of uidls //means first time in, response should be "+Ok" if (! awaitingData) { if ( response[0] != '+' ) { errorHandling(ErrUnknownResponse, response); return; } awaitingData = true; if ( socket->canReadLine() ) { response = socket->readLine(); } else return; } uidlList.append( response.mid(0, response.length() - 2) ); while ( socket->canReadLine() ) { response = socket->readLine(); uidlList.append( response.mid(0, response.length() - 2) ); } if (response == ".\r\n") { uidlList.removeLast(); status = List; } else return; //more data incoming } if (status == List) { *stream << "LIST\r\n" << flush; awaitingData = false; status = Size; return; } if (status == Size) { //means first time in, response should be "+Ok" if (! awaitingData) { if ( response[0] != '+' ) { errorHandling(ErrUnknownResponse, response); return; } awaitingData = true; if ( socket->canReadLine() ) { response = socket->readLine(); } else return; } sizeList.append( response.mid(0, response.length() - 2) ); while ( socket->canReadLine() ) { response = socket->readLine(); sizeList.append( response.mid(0, response.length() - 2) ); } if (response == ".\r\n") { sizeList.removeLast(); status = Retr; uidlIntegrityCheck(); } else return; //more data incoming } if (status == Retr) { msgNum = nextMsgServerPos(); if (msgNum != -1) { temp.setNum(msgNum); if (!selected) emit updateStatus(tr("Retrieving %1").arg(temp)); else emit updateStatus(tr("Completing %1").arg(temp)); if (!preview || mailSize <= headerLimit) { *stream << "RETR " << msgNum << "\r\n" << flush; } else { //only header *stream << "TOP " << msgNum << " 0\r\n" << flush; } status = Ignore; return; } else { status = Acks; } } if (status == Ignore) { if (response[0] == '+') { message = ""; status = Read; if (!socket->canReadLine()) //sync. problems return; response = socket->readLine(); } else errorHandling(ErrUnknownResponse, response); } if (status == Read) { message += response; while ( socket->canReadLine()) { response = socket->readLine(); message += response; } emit downloadedSize(mailDropSize + message.length()); int x = message.indexOf("\r\n.\r\n",-5); if (x == -1) return; //complete mail downloaded if ( (!preview ) || ((preview) && (mailSize <= headerLimit)) ){ emit newMessage(message, msgUidl, internalId, mailSize, true); } else { //incomplete mail downloaded emit newMessage(message, msgUidl, internalId, mailSize, false); } // in case user jumps out, don't dowwload message on next entry if (preview) { lastUidl.append(msgUidl); account->setUidlList(lastUidl); mailDropSize += headerLimit; } else { mailDropSize += mailSize; } newMessages++; if(!preview || (preview && mailSize <= headerLimit) && account->deleteMail()) account->deleteMsg(msgUidl,0); status = Retr; incomingData(); //remember: recursive return; } if (status == Acks) { //ok, delete mail, await user input if ( account->deleteMail() ) { status = Dele; awaitingData = false; deleteList = account->msgToDelete(); if ( deleteList.isEmpty() ) status = Done; } else { status = Done; } } if (status == Dele) { if ( awaitingData ) { response = socket->readLine(); if ( response[0] != '+' ) { errorHandling(ErrUnknownResponse, response); return; } } else { qWarning( (QString::number( deleteList.count() ) + " messages in mailbox to be deleted").toAscii()); emit updateStatus(tr("Removing old messages")); } if ( deleteList.count() == 0 ) { status = Done; } else { QString str = deleteList.first(); QString strPos = msgPosFromUidl( str ); deleteList.removeAll( str ); account->msgDeleted( str, "" ); if ( !strPos.isEmpty() ) { awaitingData = true; qWarning(("deleting message at pos: " + strPos ).toAscii()); *stream << "DELE " << strPos << "\r\n" << flush; } else { qWarning(("delete failed on message: " + str ).toAscii()); incomingData(); return; } } } if (status == Done) { if ( preview ) { emit mailTransferred(newMessages); return; } status = Quit; } if (status == Quit) { qWarning("quit sent"); status = Exit; *stream << "QUIT\r\n" << flush; return; } if (status == Exit) { socket->close(); //close regardless receiving = false; emit updateStatus(tr("Communication finished")); if (unresolvedUidl.count() > 0 && !preview) { emit unresolvedUidlList(unresolvedUidl); } account->setUidlList(uidlList); emit mailTransferred(newMessages); }}QString PopClient::getUidl(QString uidl){ return uidl.mid( uidl.indexOf(" ") + 1, uidl.length() );}QString PopClient::msgPosFromUidl(QString uidl){ QStringList list = uidlList.filter(uidl); if ( list.count() != 1 ) //should be only 1 match return QString::null; QString str = list.join("").trimmed(); bool ok; uint x = str.mid(0, str.indexOf(" ") ).toUInt(&ok); if ( ok ) { return QString::number(x); //found current pos of msg } else { return QString::null; }}int PopClient::nextMsgServerPos(){ int thisMsg = -1; QString *mPtr; if (preview) { if ( messageCount < (int) uniqueUidlList.count() ) { const QString& it = uniqueUidlList.at(messageCount); messageCount++; thisMsg = ( it.left( it.indexOf(" ") ) ).toInt(); msgUidl = it; internalId = QUuid(); } } if (selected) { if (messageCount == 0) { messageCount = 1; mPtr = mailList->first(); } else { mPtr = mailList->next(); } QStringList ref; // if requested mail is not on server, try to get // a new mail from the list while ( (mPtr != NULL) && (ref.count() == 0) ) { ref = uidlList.filter(*mPtr); if (ref.count() != 1) { unresolvedUidl.append(*mPtr); mPtr = mailList->next(); } else { const QString& it = ref.first(); thisMsg = ( it.left( it.indexOf(" ") ) ).toInt(); msgUidl = it; } } if (ref.count() != 1) //temporary, what if two? should never happen return thisMsg; internalId = mailList->currentId(); } getSize(thisMsg); return thisMsg;}// get the reported server size from stored listint PopClient::getSize(int pos){ int sizeRef = 0; for ( QStringList::Iterator it = sizeList.begin(); it != sizeList.end(); ++it ) { sizeRef = ( (*it).left( (*it).indexOf(" ") ) ).toInt(); if (sizeRef == pos) { mailSize = ( (*it).mid( (*it).indexOf(" ") + 1, (*it).length() )).toInt(); return mailSize; } } return -1;}// checks the list of uidls retrieved from the server by// comparing them against the last known serverlist.// if everything is ok, then qtmail is a very happy programvoid PopClient::uidlIntegrityCheck(){ QString str; int pos = 1, size; QStringList::Iterator itSize = sizeList.begin(); for (QStringList::Iterator it = uidlList.begin(); it != uidlList.end(); ++it ) { size = getSize(pos); str.setNum(size); itSize++; pos++; } // create list of new entries that should be downloaded if (preview) { if ( !account->synchronize() ) { lastUidl.clear(); } QStringList previousList; QString thisUidl; for ( QStringList::Iterator it = uidlList.begin(); it != uidlList.end(); ++it ) { thisUidl = getUidl(*it); //strips pos if ( (lastUidl.filter(thisUidl)).count() == 0 ) { uniqueUidlList.append(*it); mailDropSize += headerLimit; } else { previousList.append(*it); } } lastUidl = previousList; emit mailboxSize(mailDropSize); messageCount = 0; mailDropSize = 0; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -