Logo Search packages:      
Sourcecode: mailody version File versions  Download package

imaplib.cpp

/* This file is part of the KDE project
   Copyright (C) 2006-2007 KovoKs <info@kovoks.nl>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include <qstringlist.h>
#include <qsocket.h>
#include <qregexp.h>
#include <qtimer.h>

#include <kdebug.h>
#include <klocale.h>

#include "socketsafe.h"
#include "imaplib.h"

namespace Mailody {

static inline bool endSimpleCommand(const QString& text)
{
    return text.find(
            QRegExp("(?:^|\n|\r)a02 (?:OK|NO|BAD)[^\n]+(?:\n)\r?$")) > -1;
}

00038 Imaplib::Imaplib( QWidget* parent,  const char* name)
    : QWidget( parent, name ), m_currentState( NotConnected ), m_socket( 0 )
{
    // kdDebug() << k_funcinfo << endl;

    // This will process the queue with requests that should go to
    // the server
    startTimer(20);

    // This will prevent the autologout after 30 minutes, after each
    // read it will start the timer to send a noop after 25 minutes.
    m_preventLogOutTimer = new QTimer( this );
    connect( m_preventLogOutTimer, SIGNAL(timeout()), SLOT(slotSendNoop()) );

    // When a mailbox is selected, we want to sent a NOOP every minute
    // for that mailbox. That will get us an update of the mailbox.
    m_checkMailTimer = new QTimer( this );
    connect( m_checkMailTimer, SIGNAL(timeout()), SLOT(slotSendNoop()) );
    /*
        // testcases for the regex.

    kdDebug() << "These should be true:" << endl;
    kdDebug() << endSimpleCommand("bla\na02 OK bla\n\r") << endl;   // true
    kdDebug() << endSimpleCommand("a02 OK bla\n")<< endl;          // true
    kdDebug() << endSimpleCommand("bla\na02 OK bla\n\r")<< endl;   // true
    kdDebug() << endSimpleCommand("bla\n\ra02 OK bla\n")<< endl;   // true

    kdDebug() << "These should be false:" << endl;
    kdDebug() << endSimpleCommand("bla a02 OK bla")<< endl;        // false
    kdDebug() << endSimpleCommand("a02 OK bla")<< endl;            // false
    kdDebug() << endSimpleCommand("\n\ra02 OK bla")<< endl;        // false
    kdDebug() << endSimpleCommand("\na02 OK bla")<< endl;          // false
    kdDebug() << endSimpleCommand("bla\na02 OK bla")<< endl;       // false
    kdDebug() << endSimpleCommand("bla\na02 OK bla\n\rbla\n\r")<< endl; // false
    kdDebug() << endSimpleCommand("a02 OK bla\n\rbla\n") << endl;   // false
    kdDebug() << endSimpleCommand("bla\na02 OK bla\r") << endl;   // false

    */
}

00078 Imaplib::~Imaplib()
{
    // kdDebug() << k_funcinfo << endl;
    // queued jobs can be removed...
    m_queue.clear();
    m_currentQueueItem=Queue();
}

void Imaplib::slotRead(const QString& received)
{
    // kdDebug() << k_funcinfo << received <<
    //         " for " << m_currentQueueItem.state() << endl;

    // ignore empty, but not when we do tls, just after the handshake
    // it will return an empty string.
    if (received.isEmpty() && m_safe != SocketSafe::TLS)
        return;

    // get the untagged alert...
    if (received.find("* OK [ALERT]") > -1)
    {
        emit alert(this, received.mid(13));
        m_currentQueueItem=Queue();
        return;
    }

    if (m_currentQueueItem.state() == Queue::Logout &&
        received.find("* BYE") > -1)
    {
        m_currentState = LoggedOut;
        m_queue.clear();
        m_currentQueueItem=Queue();
        emit status(i18n("Offline"));
        return;
    }

    // Handle the response per connection state.
    if (m_currentState == Connected)
    {
        // The reply is a response to a connect. Lets see if the input
        // starts with * OK
        if (received.find("* OK") != -1)
        {
            // Lets see if the server return the capabilities directly, so
            // we dont have to poll for it.
            if (received.find("* OK [CAPABILITY") != -1)
            {
                m_capabilities =
                        QStringList::split(" ", received.mid(16).lower());
            }

            if (m_safe == SocketSafe::TLS)
            {
                m_capabilities = QString::null; // after tls, we refetch.
                m_socket->write("a02 starttls");
                return;
            }
        }

        // In this state, we can receive a response...
        if (received.find("* CAPABILITY") != -1)
            m_capabilities = QStringList::split(" ", received.lower());

        // Now, we should have the capabilities, carry on...
        if (m_capabilities.count() > 1)
        {
            m_currentState = NotAuthenticated;
            kdDebug() << "Log in, we can do: " << m_capabilities <<
                    m_capabilities.count() << endl;
            emit login(this);
            return;
        }
        else
        {
            m_queue.append( Queue(Queue::Capability, QString::null,
                            "CAPABILITY"));
            m_currentQueueItem = Queue();
            return;
        }
        return;
    }
    else if (m_currentState == NotAuthenticated)
    {
        // if we receive a response in this state, this will mean an
        // authentication attemped is made.
        if (m_currentQueueItem.state() == Queue::Auth)
        {
            if (received.find("a02 NO") != -1 ||
                received.find("a02 BAD") != -1)
            {
                emit loginFailed( this );
                m_currentQueueItem=Queue();
            }
            else
            {
                m_currentState = Authenticated;
                m_preventLogOutTimer->start( 25*60*1000, true );
                emit loginOk( this );
                m_currentQueueItem = Queue();
            }
        }
    }
    else if (m_currentState == Authenticated)
    {
        m_received = received;
        if (m_currentQueueItem.state() == Queue::GetMailBoxList)
            QTimer::singleShot(0, this,
                               SLOT(slotParseGetMailBoxList()));

        else if (m_currentQueueItem.state() == Queue::GetRecent)
            QTimer::singleShot(0, this,
                               SLOT(slotParseGetRecent()));

        else if (m_currentQueueItem.state() == Queue::Noop)
            QTimer::singleShot(0, this,
                               SLOT(slotParseNoop()));

        else if (m_currentQueueItem.state() == Queue::Copy)
            QTimer::singleShot(0, this,
                       SLOT(slotParseCopy()));

        else if (m_currentQueueItem.state() == Queue::CheckMail)
            QTimer::singleShot(0, this,
                       SLOT(slotParseCheckMail()));

        else if (m_currentQueueItem.state() == Queue::Expunge)
            QTimer::singleShot(0, this,
                       SLOT(slotParseExpunge()));

        else if (m_currentQueueItem.state() == Queue::SyncMailBox ||
                 m_currentQueueItem.state() == Queue::SelectMailBox ||
                 m_currentQueueItem.state() == Queue::SaveMessageData)
            QTimer::singleShot(0, this,
                       SLOT(slotParseExists()));

        else if (m_currentQueueItem.state() == Queue::SaveMessage)
            QTimer::singleShot(0,this,
                       SLOT(slotParseSaveMessage()));

        else if (m_currentQueueItem.state() == Queue::GetHeaderList)
            QTimer::singleShot(0, this,
                       SLOT(slotParseGetHeaderList()));

        else if (m_currentQueueItem.state() == Queue::GetHeaders ||
                 m_currentQueueItem.state() == Queue::GetMessage)
            QTimer::singleShot(0, this,
                       SLOT(slotParseGetMessage()));

        else if (m_currentQueueItem.state() == Queue::CreateMailBox)
            QTimer::singleShot(0, this,
                       SLOT(slotParseCreateMailBox()));

        else if (m_currentQueueItem.state() == Queue::DeleteMailBox)
            QTimer::singleShot(0, this,
                       SLOT(slotParseDeleteMailBox()));

        else if (m_currentQueueItem.state() == Queue::RenameMailBox)
            QTimer::singleShot(0, this,
                       SLOT(slotParseRenameMailBox()));

        else
        {
            m_currentQueueItem = Queue();
            QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
        }
    }
}

00246 void Imaplib::startConnection( const QString& server, int port,
                               SocketSafe::Secure safe)
{
    m_currentMailbox = QString::null;
    m_currentQueueItem = Queue();
    m_readyToSend = false;
    m_queue.clear();

    if (m_socket)
    {
        kdDebug() << "Delete connection" << endl;
        m_socket->aboutToClose();
        m_socket->deleteLater();
        m_socket = 0;
    }

    m_safe = safe;

    switch(safe)
    {
        case SocketSafe::NONE:
            if (port == 0)
                port = 143;
            m_socket  = new SocketSafe(this, "Imaplib", server, port,
                                       SocketSafe::NONE);
            break;
        case SocketSafe::SSL:
            if (port == 0)
                port = 993;
            m_socket  = new SocketSafe(this," Imaplib", server, port,
                                       SocketSafe::SSL);
            break;
        case SocketSafe::TLS:
            if (port == 0)
                port = 143;
            m_socket = new SocketSafe(this, "Imaplib", server, port,
                                      SocketSafe::TLS);
            break;
        case SocketSafe::CLEAR:
            break;
    }

    connect(m_socket, SIGNAL(data(const QString&)),
            SLOT(slotRead(const QString&)));
    connect(m_socket, SIGNAL(connected()),
            SLOT(slotConnected()));
    connect(m_socket, SIGNAL(error(const QString&)),
            SIGNAL(error(const QString&)));
    connect(m_socket, SIGNAL(disconnected()),
            SIGNAL(disconnected()));

    emit status(i18n("Connecting"));
    m_currentQueueItem= Queue(Queue::Connecting,"","");
    m_socket->reconnect();
}

00302 void Imaplib::login( const QString& username, const QString& password)
{
    // kdDebug() << k_funcinfo << endl;
    m_queue.prepend(Queue(Queue::Auth, "",
                    "login \"" + rfcDecoder::quoteIMAP(username)
                    + "\" \"" + rfcDecoder::quoteIMAP(password) + "\""));
    m_currentQueueItem = Queue();
}

00311 void Imaplib::logout()
{
    // kdDebug() << k_funcinfo << endl;
    m_socket->aboutToClose();
    m_queue.prepend(Queue(Queue::Logout, "", "logout"));
}

00318 void Imaplib::getMailBoxList()
{
    // kdDebug() << k_funcinfo << endl;
    m_queue.append(Queue(Queue::GetMailBoxList,"", "LIST \"\" \"*\"",
                        i18n("Retrieving mailbox list")));
}

00325 void Imaplib::getMailBox(const QString& box)
{
    // kdDebug() << k_funcinfo << box << endl;
    const QString box2 = rfcDecoder::toIMAP(box);
    m_queue.prepend(Queue(Queue::SyncMailBox, box, "SELECT \""+box2+"\""));
}

00332 void Imaplib::getHeaders(const QString& mb, const QStringList& uids)
{
    // kdDebug() << k_funcinfo << << uids << mb << endl;
    if (uids.count() == 0 || mb.isEmpty())
        return;

    // Join first, then split it in blocks of 250.
    QString complete = uids.join(",");

    int begin = 1;
    while (!complete.isEmpty())
    {
        QString part = complete.section(',',0,250);
        complete = complete.section(',',251);

        uint end = begin + 250;
        if (end > uids.count())
            end = uids.count();

        // Priority; above the checkmail calls in the queue.
        m_queue.prepend(Queue(Queue::GetHeaders, mb,
                   "UID FETCH " + part
           + " (RFC822.SIZE BODY.PEEK[HEADER.FIELDS (FROM TO CC SUBJECT "
                           "DATE IN-REPLY-TO MESSAGE-ID)])",
               i18n("Retrieving headers [%1-%2] for %3")
                       .arg(begin).arg(end).arg(mb)));

        begin += 250;
    }
}

00363 void Imaplib::getHeaderList(const QString& mb, int start, int end)
{
    // kdDebug() << k_funcinfo << start << "-" << end
    //        << "for" << mb << endl;
    if (! end>=1 || end < start || !start>=1)
        return;

    // Put this in queue with priority above the checkmail things...
    m_queue.prepend(Queue(Queue::GetHeaderList, mb,
                   "FETCH " + QString::number(start) + ':'
                           + QString::number(end) + " (UID FLAGS)",
                   i18n("Retrieving status list for %1").arg(mb)));
}

00377 void Imaplib::getMessage(const QString& mb, int uid)
{
    // kdDebug() << k_funcinfo << endl;
    m_queue.prepend( Queue(Queue::GetMessage, mb,
                         "UID FETCH " + QString::number(uid)
                                 + ':' + QString::number(uid) + " BODY[]",
                          i18n("Retrieving message")));
}

00386 void Imaplib::checkMail(const QString& box)
{
    // kdDebug() << k_funcinfo << box << endl;
    const QString box2 = rfcDecoder::toIMAP(box);
    m_queue.append(Queue(Queue::CheckMail, box,
                   "STATUS \""+box2+"\" (MESSAGES UNSEEN UIDVALIDITY UIDNEXT)",
                    i18n("Checking mail for %1").arg(box)));
}

00395 void Imaplib::addFlag(const QString& box, int min, int max,
                      const QString& flag)
{
    // kdDebug() << k_funcinfo
    //        << box << " - " << min << " - " << max << " - " << flag << endl;
    m_queue.append(Queue(Queue::NoResponse, box,
                   "UID STORE "
                           + QString::number(min) + ":" + QString::number(max)
                           + " +FLAGS (" + flag + ')'));
}

00406 void Imaplib::removeFlag(const QString& box, int min, int max,
                         const QString& flag)
{
    // kdDebug() << k_funcinfo << box << " - " << uid << " - " << flag << endl;
    m_queue.append(Queue(Queue::NoResponse, box,
                   "UID STORE "
                           + QString::number(min) + ":" + QString::number(max)
                           + " -FLAGS (" + flag + ')'));
}

00416 void Imaplib::expungeMailBox(const QString& box)
{
    // kdDebug() << k_funcinfo << box << endl;
    const QString box2 = rfcDecoder::toIMAP(box);
    m_queue.append(Queue(Queue::Expunge, box, "EXPUNGE"));
}

00423 void Imaplib::createMailBox(const QString& box)
{
    // kdDebug() << k_funcinfo << box << endl;
    const QString box2 = rfcDecoder::toIMAP(box);
    m_queue.append(Queue(Queue::CreateMailBox, box, "CREATE \"" + box2 + "\""));
}

00430 void Imaplib::deleteMailBox(const QString& box)
{
    // kdDebug() << k_funcinfo << box << endl;
    const QString box2 = rfcDecoder::toIMAP(box);
    m_queue.append(Queue(Queue::DeleteMailBox, box, "DELETE \"" + box2 + "\""));
}

00437 void Imaplib::renameMailBox(const QString& oldbox, const QString& newbox)
{
    // kdDebug() << k_funcinfo << oldbox << "->" << newbox << endl;
    const QString oldbox2 = rfcDecoder::toIMAP(oldbox);
    const QString newbox2 = rfcDecoder::toIMAP(newbox);
    m_queue.append(Queue(Queue::RenameMailBox, oldbox + "~" + newbox,
                   "RENAME \"" + oldbox2 + "\" \"" + newbox2 + "\"",
                  i18n("Renaming mailbox from %1 to %2").arg(oldbox,newbox)));
}

00447 void Imaplib::copyMessage(const QString& origbox, int uid,
                       const QString& destbox)
{
    // kdDebug() << k_funcinfo << origbox
    //    << " - " << uid << " -> " << destbox << endl;
    const QString destbox2 = rfcDecoder::toIMAP(destbox);
    m_queue.append(Queue(Queue::Copy, origbox,
                  "UID COPY " + QString::number(uid) + " \"" + destbox2+ "\"",
                  i18n("Moving message to %1").arg(destbox)));
}

00458 void Imaplib::saveMessage(const QString& mb, const QString& message,
                          const QString& flags)
{
    // kdDebug() << k_funcinfo << message << endl;
    const QString mb2 = rfcDecoder::toIMAP(mb);
    QString flagsformatted = "\\seen";
    if (!flags.isEmpty())
         flagsformatted += " " + flags;
    m_queue.append( Queue(Queue::SaveMessage, mb,
                    "APPEND \"" + mb2 + "\" (" + flagsformatted + ") {"
                            + QString::number(message.length())
                            + "}"));
    m_queue.append( Queue(Queue::SaveMessageData, mb, message));
}

00473 void Imaplib::idleStart(const QString& mb)
{
    kdDebug() << k_funcinfo << endl;
    m_queue.append( Queue(Queue::IdleStart, mb, "IDLE"));
}

00479 void Imaplib::idleStop()
{
    kdDebug() << k_funcinfo << endl;
    m_queue.prepend( Queue(Queue::IdleStop, QString::null, "DONE"));
}

00485 bool Imaplib::capable(const QString& something)
{
    kdDebug() << k_funcinfo << something << endl;
    return m_capabilities.findIndex( something ) > -1;
}



// ------------------- Private functions -----------------------//


void Imaplib::write(const QString& text)
{
    // kdDebug() << k_funcinfo << text << endl;
    if (m_socket)
        m_socket->write("a02 "+text);
}

void Imaplib::selectMailBox(const QString& box)
{
    // kdDebug() << k_funcinfo << box << endl;
    const QString box2 = rfcDecoder::toIMAP(box);
    m_queue.prepend(Queue(Queue::SelectMailBox, box, "SELECT \""+box2+"\""));
}

// ------------------- Private slots --------------------------//


void Imaplib::slotConnected()
{
    // connection estabilished.
    m_currentState = Connected;
}

void Imaplib::slotSendNoop()
{
//    kdDebug() << k_funcinfo << endl;
    m_queue.append(Queue(Queue::Noop, "","NOOP"));
}

// -------------------- Parsers -------------------------------------//

void Imaplib::slotParseGetMailBoxList()
{
    // kdDebug() << k_funcinfo << endl;

    static QString all_data;
    all_data.append(m_received);

    if ( !endSimpleCommand(all_data) )
        return;

    QStringList result;

    // Microsoft Server returns quotes sometimes:
    // * LIST (\Marked \HasNoChildren) "/" bbullshit
    // * LIST (\Marked \HasNoChildren) "/" "Trash/Deleted Items"

    QRegExp rx1("LIST \\(.*\\) \".\" (.*)\n");
    rx1.setMinimal(true);

    QMap<QString, bool> newList;
    int start = 0;
    while (start != -1)
    {
        start = rx1.search(all_data, start);

        if (start == -1)
            break;

        QString y = rx1.cap(1).stripWhiteSpace();

        // Remove them if they are there.... Think MS.
        if (y.startsWith("\"") && y.endsWith("\""))
            y=y.mid(1, y.length()-2);

        result.append(rfcDecoder::fromIMAP(y));

        ++start;
    }

    all_data = QString::null;
    emit mailBoxList( result );
    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseGetRecent()
{
    // kdDebug() << k_funcinfo << endl;

    QRegExp rx("SEARCH (.*)a02");
    if (rx.search(m_received.stripWhiteSpace()) != -1)
    {
        QString r = rx.cap(1).stripWhiteSpace();
        QStringList t =
            QStringList::split(" ",r);

        emit unseenCount(this, m_currentQueueItem.mailbox(), t.count());

        QStringList results;
        QStringList::iterator it = t.begin();
        while(it != t.end())
        {
            results.append(*it);
            results.append(QString::null); // no flag, that means unseen...
            ++it;
        }

        emit itemsInMailBox(this, m_currentQueueItem.mailbox(), results);
    }
    else
        emit unseenCount(this, m_currentQueueItem.mailbox(), 0);

    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseCopy()
{
    // kdDebug() << k_funcinfo << endl;

    QRegExp rx("a02 OK");
    if (rx.search(m_received.stripWhiteSpace()) == -1)
    {
        kdDebug() << "Store failed, removing the delete command" << endl;
        // TODO: emit something for the move people...
        // m_queue.pop_front();
    }
    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseNoop()
{
    // Make sure we have all data....
    static QString all_data;
    all_data.append(m_received);

    if ( !endSimpleCommand(all_data) )
        return;

    // process things....
    // kdDebug() << "NOOP: " << all_data << "ENDNOOP" << endl;

    // we will receive something like, we need to fetch it again, because we
    // need the uid ;-(
    //* 8 FETCH (FLAGS (\Recent \Seen $Label2))
    QRegExp rx("\\* (\\d+) FETCH \\(");
    int start = 0;
    while (start != -1)
    {
        start = rx.search(m_received.stripWhiteSpace(), start);

        if (start == -1)
            break;

        int i = rx.cap(1).toInt();
        getHeaderList(m_currentMailbox, i, i);
        kdDebug() << "Flag changed, regetting it." << endl;

        ++start;
    }

    // done!
    all_data = QString::null;
    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseCheckMail()
{
    // kdDebug() << k_funcinfo << endl;

    // kdDebug() << "checkmailresult: " << m_currentQueueItem.mailbox()
    //        << " : " << m_received << endl;
    QRegExp rx1("STATUS (.+) \\(");
    rx1.setMinimal(true);

    QString mb, uidvalidity, uidnext;
    int totalShouldBe=0;

    if (rx1.search(m_received.stripWhiteSpace()) != -1)
    {
        mb = rx1.cap(1);

        //regex in qt is weird...
        if (mb.startsWith("\"") && mb.endsWith("\""))
            mb = mb.mid(1,mb.length()-2);

        rx1.setPattern("[ (]MESSAGES (\\d+)[ )]");
        if (rx1.search(m_received.stripWhiteSpace()) != -1)
        {
            totalShouldBe = rx1.cap(1).toInt();
            emit messageCount(this, mb, totalShouldBe);
        }

        rx1.setPattern("[ (]UNSEEN (\\d+)[ )]");
        if (rx1.search(m_received.stripWhiteSpace()) != -1)
            emit unseenCount(this, mb, rx1.cap(1).toInt());

        rx1.setPattern("[ (]UIDVALIDITY (\\d+)[ )]");
        if (rx1.search(m_received.stripWhiteSpace()) != -1)
            uidvalidity = rx1.cap(1);

        rx1.setPattern("[ (]UIDNEXT (\\d+)[ )]");
        if (rx1.search(m_received.stripWhiteSpace()) != -1)
            uidnext = rx1.cap(1);
    }
    else
    {
        // we appereantly m_received garbage, should not happen, but
        // there are more things in life, requeue and get on with it.
        // possible loop of course...
        // kdDebug() << "unexpected response received" << m_received << endl;
        m_queue.append(m_currentQueueItem);
        m_currentQueueItem = Queue();
        QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
        emit statusError(i18n("Something is wrong..."));
        return;
    }

    emit integrity(mb, totalShouldBe, uidvalidity, uidnext);
    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseExpunge()
{
    emit expungeCompleted(this, m_currentQueueItem.mailbox());
    QTimer::singleShot(0, this, SLOT(slotParseExists()));
}

void Imaplib::slotParseSaveMessage()
{
    // kdDebug() << k_funcinfo << " : " << m_received << endl;
    m_currentQueueItem = m_queue.first();
    if (m_socket)
            m_socket->write( m_currentQueueItem.command() );
    m_queue.pop_front();
}

void Imaplib::slotParseCreateMailBox()
{
    // kdDebug() << k_funcinfo << " : " << m_received << endl;

    if (m_received.find("a02 OK") == -1)
        kdDebug() << "Failed to create folder" << endl;
    else
        emit mailBoxAdded( m_currentQueueItem.mailbox() );

    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseDeleteMailBox()
{
    // kdDebug() << k_funcinfo << " : " << m_received << endl;

    if (m_received.find("a02 OK") == -1)
        kdDebug() << "Failed to delete folder" << endl;
    else
        emit mailBoxDeleted(m_currentQueueItem.mailbox());

    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseRenameMailBox()
{
    // kdDebug() << k_funcinfo << " : " << m_received << endl;

    if (m_received.find("a02 OK") == -1)
        kdDebug() << "Failed to rename folder" << endl;
    else
    {
        QString boxes = m_currentQueueItem.mailbox();
        QStringList i = QStringList::split("~",boxes);
        emit mailBoxRenamed(i[0],i[1]);
    }

    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseExists()
{
    // kdDebug() << k_funcinfo << " for " << m_received << endl;

    m_currentMailbox=m_currentQueueItem.mailbox();

    // Error handling
    if (m_received.find("a02 NO") != -1)
    {
        // if we get here because the queue was delayed, then we
        // need to remove it from the queue to prevent a loop.
        Queue nextQueueItem = m_queue.first();
        if (m_currentQueueItem.mailbox() == nextQueueItem.mailbox())
        {
            kdDebug() << "Removing this and next command" << endl;
            m_queue.pop_front();
        }

        m_checkMailTimer->stop();

        emit statusError(i18n("Failed to select the mailbox"));
        m_currentQueueItem = Queue();
        QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
        return;
    }

    m_checkMailTimer->start( 20*1000 );

    QString uidvalidity, uidnext;
    QRegExp rx1(" OK \\[UIDVALIDITY (\\d+)\\]");
    if (rx1.search(m_received.stripWhiteSpace()) != -1)
        uidvalidity = rx1.cap(1);

    rx1.setPattern(" OK \\[UIDNEXT (\\d+)\\]");
    if (rx1.search(m_received.stripWhiteSpace()) != -1)
        uidnext = rx1.cap(1);

    rx1.setPattern(" (\\d+) EXISTS");
    if (rx1.search(m_received.stripWhiteSpace()) != -1)
    {

        int amount = rx1.cap(1).toInt();
        emit messageCount(this, m_currentQueueItem.mailbox(), amount);

        if (m_currentQueueItem.state() == Queue::SyncMailBox)
            getHeaderList(m_currentMailbox, 1, amount);
        else
            emit integrity(m_currentMailbox, amount, uidvalidity, uidnext);
    }

    // Sync will not emit the unseen count, so do a checkmail after that.
    if (m_currentQueueItem.state() == Queue::SyncMailBox)
        checkMail(m_currentMailbox);

    if (m_currentQueueItem.state() == Queue::SaveMessageData)
        emit saveDone();

    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseGetHeaderList()
{
    // kdDebug() << k_funcinfo << endl;

    static QString all_data;
    all_data.append(m_received);

    if ( !endSimpleCommand(all_data) )
        return;

    QStringList results;

    // * 1 FETCH (UID 1 FLAGS (\Seen))                  // CYRUS
    // * 3 FETCH (FLAGS (\Deleted \Seen) UID 26135)     // Courier
    QRegExp rx1("UID [\\(]?(\\d*)[\\)]?");
    QRegExp rx2("FLAGS \\((.*)\\)");
    rx2.setMinimal(true);

    QStringList fetchlist, allList, updateList;

    all_data = all_data.stripWhiteSpace();

    int start = 0, start2 = 0;
    while (start != -1)
    {
        start = rx1.search(all_data, start);
        if (start == -1)
            break;

        results.append(rx1.cap(1));

        start2 = rx2.search(all_data, start2);
        if (start2 != -1)
            results.append(rx2.cap(1));

        ++start2;
        ++start;
    }
    emit itemsInMailBox(this, m_currentQueueItem.mailbox(), results);

    all_data = QString::null;
    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}

void Imaplib::slotParseGetMessage()
{
    // kdDebug() << k_funcinfo << endl;

    // Courier:
    //|* 1 FETCH (UID 1 RFC822.SIZE 8609 BODY[HEADER.FIELDS ("FROM" "SUBJECT" "DATE")] {148}|
    // Cyrus:
    //|* 1 FETCH (UID 26133 RFC822.SIZE 8609 BODY[HEADER.FIELDS (FROM SUBJECT DATE)] {139}|
    // Dovecot:
    //|* 1 FETCH (RFC822.SIZE 8609 UID 2 BODY[HEADER.FIELDS (FROM TO CC SUBJECT DATE IN-REPLY-TO MESSAGE-ID)] {337}

    static QString all_data;
    all_data.append(m_received);

    if ( !endSimpleCommand(all_data) )
        return;

    QRegExp rx0;
    QRegExp rx1;
    QRegExp rx2;
    if (m_currentQueueItem.state() == Queue::GetHeaders)
    {
        rx0.setPattern("UID (\\d*)");
        rx1.setPattern("RFC822.SIZE (\\d*)");
        rx2.setPattern( QRegExp::escape(" BODY[HEADER.FIELDS ")
                + "\\(\"?FROM\"? \"?TO\"? \"?CC\"? "
                + "\"?SUBJECT\"? \"?DATE\"? \"?IN-REPLY-TO\"? "
                + "\"?MESSAGE-ID\"?\\)\\] "
                + QRegExp::escape("{") + "(\\d*)" + QRegExp::escape("}"));
    }
    else
    {
        rx0.setPattern("UID (\\d*)");
        rx2.setPattern(QRegExp::escape("BODY[] ")
                + QRegExp::escape("{") + "(\\d*)" + QRegExp::escape("}"));
    }

    QStringList headersToSend;
    while (rx2.search(all_data.stripWhiteSpace()) != -1)
    {
        // First capture the body part:
        QString size = rx2.cap(1);
        int startBody = rx2.pos(1)+size.length()+2;
        QString text = all_data.mid(startBody, size.toInt());

        // Second, remove the complete regex part from the string.
        all_data = all_data.left(rx2.pos(0))+all_data.mid(startBody+size.toInt());

        // Now figure out the uid.
        int uid=0;
        if (rx0.search(all_data.stripWhiteSpace()) != -1)
            uid = rx0.cap(1).toInt();

        if (m_currentQueueItem.state() == Queue::GetHeaders)
        {
            QString size;
            if (m_currentQueueItem.state() == Queue::GetHeaders &&
                rx1.search(all_data.stripWhiteSpace()) != -1)
                size = "Size: " + rx1.cap(1);

            text.append("\r\n");
            text.append(size);

            headersToSend.append(rx0.cap(1));
            headersToSend.append(m_currentQueueItem.mailbox());
            headersToSend.append(text);
        }
        else
            emit message(this, m_currentQueueItem.mailbox(), uid, text);

        // Find the next occorunce of FETCH and strip untill there.
        all_data = all_data.mid(all_data.find("FETCH", rx0.pos(1),false));
    }

    if (m_currentQueueItem.state() == Queue::GetHeaders)
        emit mailBox(this, m_currentQueueItem.mailbox(), headersToSend );

    // kdDebug() << "done" << endl;
    all_data = QString::null;
    emit statusReady();
    m_currentQueueItem = Queue();
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}


// ---------------------------- Management -----------------------//


void Imaplib::slotProcessQueue()
{
    /*
        kdDebug() << m_queue.count() << " - " << m_readyToSend
             << " - " << m_socket->available()
             << " - " << m_currentQueueItem.state()  << endl;
    */

    if (!m_socket || !m_queue.count() ||
        m_currentQueueItem.state() != Queue::None ||
        !m_socket->available() )
        return;

    m_currentQueueItem = m_queue.first();

    if (m_currentMailbox == m_currentQueueItem.mailbox() ||
        m_currentQueueItem.mailbox().isEmpty() ||
        m_currentQueueItem.state() == Queue::SyncMailBox ||
        m_currentQueueItem.state() == Queue::SelectMailBox ||
        m_currentQueueItem.state() == Queue::CreateMailBox ||
        m_currentQueueItem.state() == Queue::DeleteMailBox ||
        m_currentQueueItem.state() == Queue::RenameMailBox ||
        m_currentQueueItem.state() == Queue::Noop ||
        m_currentQueueItem.state() == Queue::Capability ||
        m_currentQueueItem.state() == Queue::CheckMail)
    {
        if (m_currentQueueItem.state() == Queue::CheckMail &&
            m_currentQueueItem.mailbox() == m_currentMailbox)
                m_currentQueueItem = Queue(Queue::GetRecent, m_currentMailbox,
                              "UID SEARCH UNSEEN");

        if (!m_currentQueueItem.comment().isEmpty())
            emit status(m_currentQueueItem.comment());

        write( m_currentQueueItem.command() );
        m_queue.pop_front();
    }
    else
    {
        // We need to switch to that mb first
        /*kdDebug() << "Delayed, first selecting "<< m_currentQueueItem.mailbox()
                << " instead of " << m_currentMailbox << " -> for: "
        << m_currentQueueItem.state() << endl; */
        selectMailBox(m_currentQueueItem.mailbox());
        m_currentQueueItem=Queue();
    }
}

void Imaplib::timerEvent( QTimerEvent * )
{
    QTimer::singleShot(0, this, SLOT(slotProcessQueue()));
}


void Imaplib::slotTLS()
{
    kdDebug() << k_funcinfo << endl;
    m_socket->write("a02 starttls");
}

};

#include "imaplib.moc"

Generated by  Doxygen 1.6.0   Back to index