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

imapmanager.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 <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kpassdlg.h>
#include <kwallet.h>
using KWallet::Wallet;

#include "db.h"
#include "global.h"
#include "imaplib.h"
#include "socketsafe.h" // enum
#include "imapmanager.h"

namespace Mailody {

ImapManager* ImapManager::m_instance = 0;

00038 ImapManager::ImapManager( QWidget* parent,  const char* name)
    : QWidget( parent, name )
{
    m_instance = this;
    m_db = DB::dbinstance();
}

00045 ImapManager::~ImapManager()
{
}

00049 ImapManager* ImapManager::instance()
{
    return m_instance;
}

00054 void ImapManager::startConnection()
{
    kapp->config()->setGroup("General");
    const QString imapServer = kapp->config()->readEntry("imapServer");
    int safe = kapp->config()->readNumEntry("safeImap",2);

    QString server = imapServer.section(":",0,0);
    int port = imapServer.section(":",1,1).toInt();

    m_imap = new Imaplib(this,"serverconnection");

    if ((safe == 1 || safe == 2) && !Global::cryptoConnectionSupported())
    {
        kdDebug() << "Crypto not supported!" << endl;
        slotError(i18n("You requested TLS/SSL, but your "
                       "system does not seem to be setup for that."));
        return;
    }

    m_imap->startConnection(server, port, (SocketSafe::Secure)safe);
    connect(m_imap,
            SIGNAL(login( Imaplib* )),
            SLOT( slotLogin( Imaplib* ) ));
    connect(m_imap,
            SIGNAL(loginOk( Imaplib* )),
            SIGNAL( loginOk() ));
    connect(m_imap,
            SIGNAL(status( const QString& )),
            SIGNAL(status( const QString& )));
    connect(m_imap,
            SIGNAL(statusReady()),
            SIGNAL(statusReady()));
    connect(m_imap,
            SIGNAL(statusError( const QString& )),
            SIGNAL(statusError( const QString& )));
    connect(m_imap,
            SIGNAL(saveDone()),
            SIGNAL(saveDone()));
    connect(m_imap,
            SIGNAL(error(const QString&)),
            SLOT(slotError(const QString&)));
    connect(m_imap,
            SIGNAL(disconnected()),
            SLOT(slotDisconnected()));
    connect(m_imap,
            SIGNAL(loginFailed( Imaplib* )),
            SLOT( slotLoginFailed( Imaplib* ) ));
    connect(m_imap,
            SIGNAL(alert( Imaplib*, const QString& )),
            SLOT( slotAlert( Imaplib*, const QString& ) ));
    connect(m_imap,
            SIGNAL(mailBoxList(const QStringList&)),
            SLOT( slotGetMailBoxList(const QStringList& ) ));
    connect(m_imap,
            SIGNAL(mailBox( Imaplib*, const QString&, const QStringList& )),
            SLOT( slotGetMailBox( Imaplib*, const QString&, const QStringList& ) ));
    connect(m_imap,
            SIGNAL(message( Imaplib*, const QString&, int, const QString& )),
            SLOT( slotGetMessage( Imaplib*, const QString&, int, const QString& ) ));
    connect(m_imap,
            SIGNAL(messageCount(Imaplib*, const QString&, int)),
            SLOT(slotMessagesInMailbox(Imaplib*, const QString&, int) ));
    connect(m_imap,
            SIGNAL(unseenCount(Imaplib*, const QString&, int)),
            SLOT(slotUnseenMessagesInMailbox(Imaplib*, const QString& , int ) ));
    connect(m_imap,
            SIGNAL(mailBoxAdded(const QString&)),
            SLOT(slotMailBoxAdded(const QString&)));
    connect(m_imap,
            SIGNAL(mailBoxDeleted(const QString&)),
            SLOT(slotMailBoxRemoved(const QString&)));
    connect(m_imap,
            SIGNAL(mailBoxRenamed(const QString&, const QString&)),
            SLOT(slotMailBoxRenamed(const QString&, const QString&)));
    connect(m_imap,
            SIGNAL(expungeCompleted(Imaplib*, const QString&)),
            SLOT(slotMailBoxExpunged(Imaplib*, const QString&)));
    connect(m_imap,
            SIGNAL(itemsInMailBox(Imaplib*,const QString&,const QStringList&)),
            SLOT(slotMailBoxItems(Imaplib*,const QString&,const QStringList&)));
    connect(m_imap,
            SIGNAL(integrity(const QString&, int, const QString&,
                   const QString&)),
            SLOT(slotIntegrity(const QString&, int, const QString&,
                 const QString&)));
}

void ImapManager::slotLogin( Imaplib* connection)
{
    // kdDebug() << k_funcinfo << endl;
    emit status(i18n("Connected"));

    kapp->config()->setGroup("General");
    QString login = kapp->config()->readEntry("userName");
    QString pass;

    Wallet* wallet = Wallet::openWallet(Wallet::NetworkWallet(), this->winId());
    if (wallet && wallet->isOpen() && wallet->hasFolder("mailody"))
    {
        wallet->setFolder( "mailody" );
        wallet->readPassword("account1", pass);
    }
    delete wallet;

    if (pass.isEmpty())
    {
        manualAuth( connection, login);
    }
    else
    {
        connection->login(login, pass);
    }
}

void ImapManager::manualAuth(Imaplib* connection, const QString& username)
{
    // kdDebug() << k_funcinfo << endl;

    QCString password;
    int result = KPasswordDialog::getPassword(password,
                i18n("Could not find a valid password, please enter it here"));
    if (!password)
    {
        connection->logout();
        return;
    }
    else
    {
        if (result == KPasswordDialog::Accepted)
            connection->login(username, QString(password));
    }
    password.fill(0); // safe enough?
}

void ImapManager::slotLoginFailed(Imaplib* connection)
{
    // the credentials where not ok....
    int i = KMessageBox::questionYesNoCancel(this,
                i18n("The server refused the supplied username and password, "
                     "do you want to go to the settings, re-enter it for one "
                     "time or do nothing?"),
                i18n("Could not log in"),
                i18n("Settings"), i18n("Single Input"));
    if (i == KMessageBox::Yes)
    {
        emit showSettings();
    }
    else if (i == KMessageBox::No)
    {
        kapp->config()->setGroup("General");
        QString username = kapp->config()->readEntry("userName");
        manualAuth(connection, username);
    }
    else
    {
        connection->logout();
        emit statusError("Not connected");
    }
}

void ImapManager::slotAlert(Imaplib*, const QString& message)
{
    KMessageBox::information(this, i18n("Server reported: %1").arg(message));
}

00219 void ImapManager::getMailBoxList(bool sync)
{
    if (sync)
        m_imap->getMailBoxList();
    else
    {
        QStringList list = m_db->getMailBoxList();
        if (list.count() == 0)
            m_imap->getMailBoxList();
        else
            emit mailBoxList(list);
    }
}

void ImapManager::slotGetMailBoxList(const QStringList& origlist)
{
    // kdDebug() << k_funcinfo << origlist << endl;

    // we received the mailboxlist from the server. Store it in the database,
    // and emit it.

    m_db->beginTransaction();

    QStringList newList = origlist;

    // Get existing mailboxes.
    QStringList list = m_db->getMailBoxList();
    QStringList::ConstIterator it = list.begin();
    while (it != list.end())
    {
        QString oldItem = (*it);
        ++it;

        // check if it exists in the new list.
        if (newList.findIndex(oldItem) > -1)
        {
            kdDebug() << "Already in list, no need to delete: " << oldItem << endl;
            newList.remove(oldItem);     // prevent later addition
        }
        else
        {
            // so its not in the new list, we need to remove it now...
            kdDebug() << "Removing: " << oldItem  << endl;
            emit mailBoxDeleted(oldItem);
            m_db->deleteMessagesAndMailBoxes(oldItem);
        }

        ++it;   // skip count;
    }

    // For the newList add them if still true.
    it = newList.begin();
    while (it != newList.end())
    {
        kdDebug() << "ADDING: " << (*it) << endl;
        m_db->insertMailBox(*it);
        emit mailBoxAdded(*it);
        ++it;
    }

    m_db->commitTransaction();
}


00283 void ImapManager::getMailBox(const QString& box, bool sync)
{
    // kdDebug() << k_funcinfo << box << sync << endl;
    if (sync)
    {
        m_db->deleteMessages( box );
        emit messageCount( box, 0);
        emit unseenCount( box, 0);
        emit allUidsKnown( box ); // clear the view
        m_imap->getMailBox( box );
    }
    else
    {
        QStringList values;
        m_db->getCurrentMessages( box, values);
        // kdDebug() << "box has " << (values.count()/4)
        //        << " messages in cache " << values <<  endl;
        if (values.count() == 0)
            m_imap->getMailBox( box );
        else
        {
            emit mailBox( box, values );

            //when using the cache, update the status list.
            // updateStatus(box);
        }
    }
}

void ImapManager::slotGetMailBox(Imaplib*, const QString& box,
                                 const QStringList& list)
{
    // handling of the getMailBox call to imaplib

    QStringList results;

    m_db->beginTransaction();
    QStringList::ConstIterator it = list.begin();
    while (it != list.end())
    {
        const QString uid = (*it);
        ++it;

        const QString mbox = (*it);
        ++it;

        const QString headers = (*it);
        ++it;

        m_db->storeHeaders(uid.toInt(), mbox, headers);

        const QString flags = m_db->getFlags(uid.toInt(), mbox);
        results << uid << mbox << headers << flags;
    }
    m_db->commitTransaction();

    emit mailBoxAddition(box, results);
}

00342 QString ImapManager::getHeader( const QString& mb, int uid)
{
    return m_db->getHeader(uid, mb);
}

00347 void ImapManager::getMessage(const QString& mb, int uid)
{
    if (m_db->hasBody(uid, mb))
    {
        //kdDebug() << "MESSAGE from cache" << endl;
        emit message(mb, uid, m_db->getBody(uid, mb));
    }
    else
        m_imap->getMessage(mb, uid);
}

void ImapManager::slotGetMessage(Imaplib*, const QString& mb, int uid,
                                 const QString& body)
{
    // kdDebug() << "MESSAGE from Imap server" << body << endl;
    m_db->storeBody(uid, mb, body);
    emit message(mb, uid, body);
}

00366 void ImapManager::checkMail(const QString& mb)
{
    m_imap->checkMail( mb );
}

00371 void ImapManager::updateStatus(const QString& mb)
{
    m_imap->getHeaderList( mb, 1, m_db->getTotalMessagesMailbox(mb));
}

void ImapManager::slotMessagesInMailbox(Imaplib*, const QString& mb,
                                         int amount)
{
    m_db->setTotalMessagesMailbox(mb, amount);
    emit messageCount(mb, amount);
}

void ImapManager::slotUnseenMessagesInMailbox(Imaplib*, const QString& mb,
                                               int amount)
{
    emit unseenCount(mb, amount);
}

00389 bool ImapManager::hasFlag(const QString& box, int uid, const QString& flag)
{
    return m_db->hasFlag(uid, box, flag);
}

00394 void ImapManager::addFlag(const QString& box, int uid, const QString& flag)
{
    m_db->addFlag(uid, box, flag);
    m_imap->addFlag(box, uid, uid, flag);

    if (flag == "\\Seen")
        emit unseenCount(box, m_db->getTotalMessagesMailbox( box ) -
                m_db->getTotalSeenMessagesMessages( box ));
}

00404 void ImapManager::addFlag(const QString& box, const QString& flag)
{
    int min = 0, max = 0;
    m_db->getMinMax(box,min,max);
    m_db->addFlag(box, flag);
    m_imap->addFlag(box, min, max, flag);
}

00412 void ImapManager::removeFlag(const QString& box, int uid, const QString& flag)
{
    m_db->removeFlag(uid, box, flag);
    m_imap->addFlag(box, uid, uid, flag);
}

00418 void ImapManager::expungeMailBox(const QString& box)
{
    m_imap->expungeMailBox(box);
}

void ImapManager::slotMailBoxExpunged(Imaplib*, const QString& box)
{
    m_db->expunge( box );
    emit allUidsKnown( box );
}

00429 void ImapManager::createMailBox(const QString& box)
{
    m_imap->createMailBox(box);
}

void ImapManager::slotMailBoxAdded(const QString& box)
{
    m_db->insertMailBox(box);
    emit mailBoxAdded(box);
}

00440 void ImapManager::deleteMailBox(const QString& box)
{
    m_imap->deleteMailBox(box);
}

void ImapManager::slotMailBoxRemoved(const QString& box)
{
    m_db->deleteMessagesAndMailBoxes(box);
    emit mailBoxDeleted(box);
}

00451 void ImapManager::renameMailBox(const QString& oldbox, const QString& newbox)
{
    m_imap->renameMailBox(oldbox, newbox);
}

void ImapManager::slotMailBoxRenamed(const QString& oldbox,
                                    const QString& newbox)
{
    m_db->renameMailBox(oldbox, newbox);
    emit mailBoxDeleted(oldbox);
    emit mailBoxAdded(newbox);
}

00464 void ImapManager::moveMessage(const QString& oldbox, int uid,
                     const QString& newbox)
{
    m_imap->copyMessage(oldbox, uid, newbox);
    addFlag(oldbox, uid, "\\Deleted");
    m_db->setTotalMessagesMailbox( newbox,
                                   m_db->getTotalMessagesMailbox(newbox)+1);
}

00473 void ImapManager::copyMessage(const QString& oldbox, int uid,
                     const QString& newbox)
{
    m_imap->copyMessage(oldbox, uid, newbox);
}

00479 void ImapManager::saveMessage(const QString& mb, const QString& message,
                              const QString& flags)
{
    m_imap->saveMessage(mb, message, flags);
}

00485 void ImapManager::idleStart(const QString& mb)
{
    m_imap->idleStart(mb);
}

00490 void ImapManager::idleStop()
{
    m_imap->idleStop();
}

void ImapManager::slotMailBoxItems(Imaplib*, const QString& mb,
                                   const QStringList& values)
{
    // kdDebug() << k_funcinfo  << mb << values.count() << endl;

    QStringList fetchlist;

    // Get all uids, so we dont have to query
    QStringList all;
    m_db->getCurrentMessageIDs(mb, all);

    m_db->beginTransaction();
    QStringList::ConstIterator it = values.begin();
    while (it != values.end())
    {
        const QString uid = (*it);
        ++it;

        const QString flags = (*it);
        ++it;

        if (all.findIndex(uid) == -1)
            fetchlist.append(uid);

        m_db->setFlags(uid.toInt(), mb, flags);
    }
    m_db->commitTransaction();

    m_imap->getHeaders(mb, fetchlist);
}

void ImapManager::slotIntegrity(const QString& mb, int totalShouldBe,
                     const QString& uidvalidity, const QString& uidnext)
{

    // uidvalidity can change between sessions, we dont want to refetch
    // folders in that case. Keep track of what is processed and what not.
    static QStringList processed;
    bool firsttime = false;
    if (processed.findIndex(mb) == -1)
    {
        firsttime = true;
        processed.append(mb);
    }

    // Get the current uid next value and store it
    QString keyword = "uidvalidity|" + mb + "|||";
    const QString currentuidvalidity = m_db->getSetting(keyword);
    if (currentuidvalidity.isEmpty() || currentuidvalidity != uidvalidity)
        m_db->setSetting(keyword, uidvalidity);

    // Get the current uid next value and store it
    keyword = "uidnext|" + mb + "|||";
    const QString currentuidnext = m_db->getSetting(keyword);
    if (currentuidnext.isEmpty() || currentuidnext != uidnext )
        m_db->setSetting(keyword, uidnext);

    // First check the uidvalidity, if this has changed, it means the folder
    // has been deleted and recreated. So we wipe out the messages and
    // retrieve all.
    if (currentuidvalidity != uidvalidity && !firsttime
        && !currentuidvalidity.isEmpty() && !uidvalidity.isEmpty())
    {
        kdDebug() << "UIDVALIDITY check failed (" << currentuidvalidity << "|"
                << uidvalidity <<") refetching "<< mb << endl;

        m_db->deleteMessages(mb);
        // clear the view!
        emit allUidsKnown( mb );

        m_imap->getHeaderList(mb, 1, totalShouldBe);
        return;
    }

    // kdDebug() << k_funcinfo << endl;
    int mailsReal = m_db->getTotalMessagesMessages(mb);

    kdDebug() << "integrity: " << mb << " should be: "
        << totalShouldBe << " current: " << mailsReal << endl;

    if (totalShouldBe > mailsReal)
    {
        // The amount on the server is bigger than that we have in the cache
        // that probably means that there is new mail. Fetch missing.
        kdDebug() << "Fetch missing: " << totalShouldBe
                << " BUt: " << mailsReal << endl;
        m_imap->getHeaderList(mb, mailsReal+1, totalShouldBe);
    }
    else if (totalShouldBe != mailsReal)
    {
        // The amount on the server does not match the amount in the cache.
        // that means we need reget the catch completely.
        kdDebug() << "O OH: " << totalShouldBe << " BUt: " << mailsReal << endl;
        m_db->deleteMessages(mb);
        emit allUidsKnown( mb );// clear the view!
        m_imap->getHeaderList(mb, 1, totalShouldBe);
    }
    else if (totalShouldBe == mailsReal && currentuidnext != uidnext
             && !currentuidnext.isEmpty() && !uidnext.isEmpty() && !firsttime)
    {
        //buggy
        return;

        // amount is right but uidnext is different.... something happened
        // behind our back...
        m_db->deleteMessages(mb);
        emit allUidsKnown( mb );        // clear the view!
        m_imap->getHeaderList(mb, 1, totalShouldBe);
        kdDebug() << "UIDNEXT check failed, refetching mailbox" << endl;
    }
}

void ImapManager::slotError(const QString& msg)
{
    // kdDebug() << k_funcinfo << msg << endl;
    m_imap->logout();
    emit status(i18n("Offline"));

    KMessageBox::information(this, msg);
}

void ImapManager::slotDisconnected()
{
    // kdDebug() << k_funcinfo << endl;

    emit status(i18n("Offline"));

    int i = KMessageBox::questionYesNo(0,
                            i18n("Connection has been closed, reconnect?"));
    if (i == KMessageBox::Yes)
        startConnection();
}

};

#include "imapmanager.moc"

Generated by  Doxygen 1.6.0   Back to index