From 5ec5bc2080bbc41e025fb98e6571a2c281b775cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sl=C3=A1vek=20Banko?= Date: Tue, 2 Jul 2013 18:32:11 +0200 Subject: Initial import --- kbiff/kbiff.cpp | 995 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 995 insertions(+) create mode 100644 kbiff/kbiff.cpp (limited to 'kbiff/kbiff.cpp') diff --git a/kbiff/kbiff.cpp b/kbiff/kbiff.cpp new file mode 100644 index 0000000..95abaab --- /dev/null +++ b/kbiff/kbiff.cpp @@ -0,0 +1,995 @@ +/* + * kbiff.cpp + * Copyright (C) 1999-2008 Kurt Granroth + * + * This file contains the implementation of the main KBiff + * widget + */ +#include "kbiff.h" +#include "kbiff.moc" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "setupdlg.h" +#include "notify.h" +#include "status.h" +#include "led.h" + +#include + +#include + +KBiff::KBiff(DCOPClient *client_, QWidget *parent_) + : DCOPObjectProxy(client_), + QLabel(parent_), + statusTimer(0), + status(0), + statusChanged(true), + mled( new Led("mled") ) +{ + setBackgroundMode(X11ParentRelative); + + setAutoResize(true); + setMargin(0); + setAlignment(AlignLeft | AlignTop); + + // enable the session management stuff + connect(kapp, SIGNAL(saveYourself()), this, SLOT(saveYourself())); + + // nuke the list stuff when removed + monitorList.setAutoDelete(true); + notifyList.setAutoDelete(true); + statusList.setAutoDelete(true); + + // register with DCOP + registerMe(client_); + + reset(); +} + +KBiff::~KBiff() +{ + monitorList.clear(); + notifyList.clear(); + statusList.clear(); + delete mled; + + // we no longer want to be registered + DCOPClient *client = kapp->dcopClient(); + QCString proxy = QCString("kbiff-") + QCString().setNum(getpid()); + if (client->isApplicationRegistered(proxy) == true) + { + QByteArray params; + QDataStream ds(params, IO_WriteOnly); + ds << proxy; + client->send("kbiff", "kbiff", "proxyDeregister(QString)", params); + } + client->detach(); +} + +void KBiff::processSetup(const KBiffSetup* setup_, bool run_) +{ + // General settings + isSecure = setup_->getSecure(); + profile = setup_->getProfile(); + mailClient = setup_->getMailClient(); + sessions = setup_->getSessionManagement(); + skipcheck = setup_->getCheckStartup(); + noMailIcon = setup_->getNoMailIcon(); + newMailIcon = setup_->getNewMailIcon(); + oldMailIcon = setup_->getOldMailIcon(); + noConnIcon = setup_->getNoConnIcon(); + stoppedIcon = setup_->getStoppedIcon(); + + // New mail + systemBeep = setup_->getSystemBeep(); + runCommand = setup_->getRunCommand(); + runCommandPath = setup_->getRunCommandPath(); + runResetCommand = setup_->getRunResetCommand(); + runResetCommandPath = setup_->getRunResetCommandPath(); + playSound = setup_->getPlaySound(); + playSoundPath = setup_->getPlaySoundPath(); + notify = setup_->getNotify(); + dostatus = setup_->getStatus(); + + // if we aren't going the status route, we should at least + // provide a tooltip! + if (dostatus == false) + QToolTip::add(this, profile); + else + QToolTip::remove(this); + + // set all the new mailboxes + setMailboxList(setup_->getMailboxList(), setup_->getPoll()); + + // change the dock state if necessary + if (docked != setup_->getDock()) + dock(); + + if (run_ && !skipcheck) + start(); + skipcheck = false; + + // handle session management disabling + if (sessions == false) + { + disconnect(this, SLOT(saveYourself())); + kapp->disableSessionManagement(); + } + + // if we are going to be doing status, we might as well create + // one now + if ( dostatus ) + { + statusList.clear(); + KBiffMonitor *monitor; + for (monitor = monitorList.first(); monitor; monitor = monitorList.next()) + { + statusList.append(new KBiffStatusItem(monitor->getMailboxKey(), + monitor->newMessages(), + monitor->curMessages())); + } + if (status) + { + status->hide(); + delete status; + status = 0; + } + status = new KBiffStatus(this, profile, statusList); + } + + delete setup_; +} + +void KBiff::setMailboxList(const QList& mailbox_list, unsigned int poll) +{ + QList tmp_list = mailbox_list; + + myMUTEX = true; + if (isRunning()) + stop(); + monitorList.clear(); + + KBiffMailbox *mbox; + for (mbox = tmp_list.first(); mbox != 0; mbox = tmp_list.next()) + { + KBiffURL *url = &(mbox->url); + KBiffMonitor *monitor = new KBiffMonitor(); + monitor->setMailbox(*url); + monitor->setPollInterval(poll); + monitor->setMailboxKey(mbox->key); + connect(monitor, SIGNAL(signal_newMail(const int, const QString&)), + this, SLOT(haveNewMail(const int, const QString&))); + connect(monitor, SIGNAL(signal_currentStatus(const int, const QString&, const KBiffMailState)), + this, SLOT(currentStatus(const int, const QString&, const KBiffMailState))); + connect(monitor, SIGNAL(signal_noMail()), this, SLOT(displayPixmap())); + connect(monitor, SIGNAL(signal_noMail()), + this, SLOT(haveNoNewMail())); + connect(monitor, SIGNAL(signal_oldMail()), this, SLOT(displayPixmap())); + connect(monitor, SIGNAL(signal_oldMail()), + this, SLOT(haveNoNewMail())); + connect(monitor, SIGNAL(signal_noConn()), this, SLOT(displayPixmap())); + connect(monitor, SIGNAL(signal_noConn()), + this, SLOT(haveNoNewMail())); + connect(monitor, SIGNAL(signal_invalidLogin(const QString&)), + this, SLOT(invalidLogin(const QString&))); + connect(monitor, SIGNAL(signal_fetchMail(const QString&)), + this, SLOT(slotLaunchFetchClient(const QString&))); + monitorList.append(monitor); + } + myMUTEX = false; +} + +bool KBiff::isDocked() const +{ + return docked; +} + +void KBiff::readSessionConfig() +{ + KConfig *config = kapp->sessionConfig(); + + config->setGroup("KBiff"); + + profile = config->readEntry("Profile", "Inbox"); + docked = config->readBoolEntry("IsDocked", false); + bool run = config->readBoolEntry("IsRunning", true); + + KBiffSetup *setup_dlg = new KBiffSetup(profile); + processSetup(setup_dlg, run); +} + +/////////////////////////////////////////////////////////////////////////// +// Protected Virtuals +/////////////////////////////////////////////////////////////////////////// +void KBiff::mousePressEvent(QMouseEvent *e) +{ + // regardless of which button, get rid of the status box + if (status) + status->hide(); + + // also, ditch the timer + if (statusTimer) + { + statusTimer->stop(); + delete statusTimer; + statusTimer = 0; + } + + // check if this is a right click + if(e->button() == RightButton) + { + // popup the context menu + popupMenu(); + } + else + { + // execute the command + slotLaunchMailClient(); + + readPop3MailNow(); + } +} + +void KBiff::enterEvent(QEvent *e) +{ + QLabel::enterEvent(e); + + // return now if the user doesn't want this feature. + // *sniff*.. the ingrate.. I worked so hard on this, too... *sob* + if (dostatus == false) + return; + + // don't do anything if we already have a timer + if (statusTimer) + return; + + // popup the status in one second + statusTimer = new QTimer(this); + connect(statusTimer, SIGNAL(timeout()), this, SLOT(popupStatus())); + + statusTimer->start(1000, true); +} + +void KBiff::leaveEvent(QEvent *e) +{ + QLabel::leaveEvent(e); + + // stop the timer if it is going + if (statusTimer) + { + statusTimer->stop(); + delete statusTimer; + statusTimer = 0; + } + + // get rid of the status box if it is activated + if (status) + status->hide(); +} + +void KBiff::popupStatus() +{ + // if we don't get rid of the timer, then the very next + // time we float over the icon, the status box will + // *not* be activated! + if (statusTimer) + { + statusTimer->stop(); + delete statusTimer; + statusTimer = 0; + } + + if (statusChanged) + { + statusList.clear(); + KBiffMonitor *monitor; + for(monitor = monitorList.first(); monitor; monitor = monitorList.next()) + { + statusList.append(new KBiffStatusItem(monitor->getMailboxKey(), monitor->newMessages(), monitor->curMessages())); + } + statusChanged = false; + } + + status->updateListView(statusList); + status->popup(QCursor::pos()); +} + +bool KBiff::isGIF8x(const QString& file_name) +{ + + /* The first test checks if we can open the file */ + QFile gif8x(file_name); + if (gif8x.open(IO_ReadOnly) == false) + return false; + + /** + * The GIF89 format specifies that the first five bytes of + * the file shall have the characters 'G' 'I' 'F' '8' '9'. + * The GIF87a format specifies that the first six bytes + * shall read 'G' 'I' 'F' '8' '7' 'a'. Knowing that, we + * shall read in the first six bytes and test away. + */ + char header[6]; + int bytes_read = gif8x.readBlock(header, 6); + + /* Close the file just to be nice */ + gif8x.close(); + + /* If we read less than 6 bytes, then its definitely not GIF8x */ + if (bytes_read < 6) + return false; + + /* Now test for the magical GIF8(9|7a) */ + if (header[0] == 'G' && + header[1] == 'I' && + header[2] == 'F' && + header[3] == '8' && + (header[4] == '9' || (header[4] == '7' && + header[5] == 'a'))) + { + /* Success! */ + return true; + } + + /* Apparently not GIF8(9|7a) */ + return false; +} + +/////////////////////////////////////////////////////////////////////////// +// Protected Slots +/////////////////////////////////////////////////////////////////////////// +void KBiff::saveYourself() +{ + if (sessions) + { + KConfig *config = kapp->sessionConfig(); + config->setGroup("KBiff"); + + config->writeEntry("Profile", profile); + config->writeEntry("IsDocked", docked); + config->writeEntry("IsRunning", isRunning()); + + config->sync(); + + } +} + +void KBiff::invokeHelp() +{ + kapp->invokeHelp(); +} + +void KBiff::displayPixmap() +{ + if (myMUTEX) + return; + + // we will try to deduce the pixmap (or gif) name now. it will + // vary depending on the dock and mail state + QString pixmap_name; + bool has_new = false, has_old = false, has_no = true, has_noconn = false; + KBiffMonitor *monitor; + for (monitor = monitorList.first(); + monitor != 0 && has_new == false; + monitor = monitorList.next()) + { + switch (monitor->getMailState()) + { + case NoMail: + has_no = true; + break; + case NewMail: + has_new = true; + break; + case OldMail: + has_old = true; + break; + case NoConn: + has_noconn = true; + break; + default: + has_no = true; + break; + } + } + + if ( !isRunning() ) + { + pixmap_name = stoppedIcon; + mled->Off(); + } + else if (has_new) + { + pixmap_name = newMailIcon; + // turn on led for new mail, otherwise turn off + mled->On(); + } + else if (has_old) + { + pixmap_name = oldMailIcon; + mled->Off(); + } + else if (has_noconn) + { + pixmap_name = noConnIcon; + mled->Off(); + } + else + { + pixmap_name = noMailIcon; + mled->Off(); + } + + if (docked) + { + // we need to check if this has path info encoded into it + QFileInfo info(pixmap_name); + + // if info.fileName() returns pixmap_name, then we no there + // isn't any paths attached and we can just prepend our 'mini' + if (info.fileName() == pixmap_name) + pixmap_name.prepend("mini-"); + else + { + // so we have some path junk on it. we get the filename + // by itself, prepend our 'mini' and tack it onto the end + // of the original dirpath. simple + QString filename(info.fileName()); + filename.prepend("mini-"); + + // we aren't guaranteed that the dirpath will end in a / + // so we add one (an extra one won't hurt, in any case + pixmap_name = info.dirPath() + "/" + filename; + } + } + QString filename = KGlobal::iconLoader()->iconPath( pixmap_name, KIcon::User ); + QFileInfo file(filename); + + // at this point, we have the file to display. so display it + if (isGIF8x(file.absFilePath())) + setMovie(QMovie(file.absFilePath())); + else + setPixmap(QPixmap(file.absFilePath())); + adjustSize(); +} + +void KBiff::currentStatus(const int num, const QString& the_mailbox, const KBiffMailState the_state) +{ + statusChanged = true; + // iterate through all saved notify dialogs to see if "our" one is + // currently being displayed + KBiffNotify *notifyptr; + for (notifyptr = notifyList.first(); + notifyptr != 0; + notifyptr = notifyList.next()) + { + // if this one is not visible, delete it from the list. the only + // way it will again become visible is if the haveNewMail slot + // gets triggered + if (notifyptr->isVisible() == false) + { + notifyList.remove(); + } + else + { + // if this box is visible (active), we see if it is the one + // we are looking for + if (notifyptr->getMailbox() == the_mailbox) + { + // yep. now, if there is new mail, we set the new number in + // the dialog. if it is any other state, we remove this + // dialog from the list + switch (the_state) + { + case NewMail: + notifyptr->setNew(num); + break; + case OldMail: + case NoMail: + case NoConn: + default: + notifyList.remove(); + break; + } + } + } + } +} + +void KBiff::haveNewMail(const int num, const QString& the_mailbox) +{ + displayPixmap(); + + // beep if we are allowed to + if (systemBeep) + { + kapp->beep(); + } + + // run a command if we have to + if (runCommand) + { + // make sure the command exists + if (!runCommandPath.isEmpty()) + { + executeCommand(replaceCommandArgs(runCommandPath)); + } + } + + // play a sound if we have to + if (playSound) + slotPlaySound(playSoundPath); + + // notify if we must + if (notify) + { + KBiffNotify *notify_dlg = new KBiffNotify(this, num, the_mailbox); + connect(notify_dlg, SIGNAL(signalLaunchMailClient()), + this, SLOT(slotLaunchMailClient())); + notifyList.append(notify_dlg); + notify_dlg->show(); + + // half-hearted attempt to center this + int x_pos = (KApplication::desktop()->width() - notify_dlg->width()) / 2; + int y_pos = (KApplication::desktop()->height() - notify_dlg->height()) / 2; + notify_dlg->move(x_pos, y_pos); + } +} + +void KBiff::haveNoNewMail() +{ + displayPixmap(); + + // run a command if we have to + if (runResetCommand) + { + // make sure the command exists + if (!runResetCommandPath.isEmpty()) + { + executeCommand(runResetCommandPath); + } + } +} + +QString KBiff::getURLWithNewMail() +{ + KBiffMonitor *monitor; + for (monitor = monitorList.first(); + monitor != 0; + monitor = monitorList.next()) + { + if(monitor->getMailState() == NewMail) + return monitor->getMailbox(); + } + + return monitorList.first()->getMailbox(); +} + +QString KBiff::getMailBoxWithNewMail() +{ + QString url(getURLWithNewMail()); + + int slashPos = url.find('/'); + if(slashPos == -1) + return url.mid(slashPos + 1); + else + return url.mid(url.find(':') + 1); +} + +QString KBiff::replaceCommandArgs(QString cmdStr) +{ + bool expand = false; + for(unsigned int i = 0; i < cmdStr.length(); i++) + { + if(expand) + { + expand = false; + if(cmdStr[i] == 'm') + cmdStr.replace(i - 1, 2, getMailBoxWithNewMail()); + else if(cmdStr[i] == 'u') + cmdStr.replace(i - 1, 2, getURLWithNewMail()); + else if(cmdStr[i] == '%') + cmdStr.replace(i - 1, 2, "%"); + + continue; + } + + if(cmdStr[i] == '%') + expand = true; + } + + return cmdStr; +} + +void KBiff::dock() +{ + // destroy the old window + if (this->isVisible()) + { + this->hide(); + this->destroy(true, true); + this->create(0, true, false); + kapp->setMainWidget(this); + + // we don't want a "real" top widget if we are _going_ to + // be docked. + if (docked) + kapp->setTopWidget(this); + else + kapp->setTopWidget(new QWidget); + } + + if (docked == false) + { + docked = true; + + // enable docking + KWin::setSystemTrayWindowFor(this->winId(), 0); + } + else + docked = false; + + // (un)dock it! + this->show(); + QTimer::singleShot(1000, this, SLOT(displayPixmap())); +} + +void KBiff::setup() +{ + KBiffSetup* setup_dlg = new KBiffSetup(profile); + + if (setup_dlg->exec()) + processSetup(setup_dlg, true); + else + delete setup_dlg; +} + +void KBiff::checkMailNow() +{ + KBiffMonitor *monitor; + for (monitor = monitorList.first(); + monitor != 0; + monitor = monitorList.next()) + { + monitor->checkMailNow(); + } +} + +void KBiff::readMailNow() +{ + KBiffMonitor *monitor; + for (monitor = monitorList.first(); + monitor != 0; + monitor = monitorList.next()) + { + monitor->setMailboxIsRead(); + } +} + +void KBiff::readPop3MailNow() +{ + KBiffMonitor *monitor; + for (monitor = monitorList.first(); + monitor != 0; + monitor = monitorList.next()) + { + if (monitor->getProtocol() == "pop3") + monitor->setMailboxIsRead(); + } +} + +void KBiff::stop() +{ + KBiffMonitor *monitor; + for (monitor = monitorList.first(); + monitor != 0; + monitor = monitorList.next()) + { + monitor->stop(); + } + displayPixmap(); +} + +void KBiff::start() +{ + myMUTEX = true; + KBiffMonitor *monitor; + for (unsigned int i = 0; i < monitorList.count(); i++) + { + monitor = monitorList.at(i); + monitor->start(); + } + myMUTEX = false; + displayPixmap(); +} + +/////////////////////////////////////////////////////////////////////////// +// Protected Functions +/////////////////////////////////////////////////////////////////////////// +void KBiff::popupMenu() +{ + KPopupMenu *popup = new KPopupMenu(0, "popup"); + popup->insertTitle(kapp->miniIcon(), profile); + + // if secure, disable everything but exit + if (isSecure == false) + { + if (docked) + popup->insertItem(i18n("&UnDock"), this, SLOT(dock())); + else + popup->insertItem(i18n("&Dock"), this, SLOT(dock())); + popup->insertItem(i18n("&Setup..."), this, SLOT(setup())); + popup->insertSeparator(); + popup->insertItem(i18n("&Help..."), this, SLOT(invokeHelp())); + popup->insertSeparator(); + + int check_id; + check_id = popup->insertItem(i18n("&Check Mail Now"), this, SLOT(checkMailNow())); + int read_id; + read_id = popup->insertItem(i18n("&Read Mail Now"), this, SLOT(readMailNow())); + + if (isRunning()) + { + popup->setItemEnabled(check_id, true); + popup->setItemEnabled(read_id, true); + popup->insertItem(i18n("&Stop"), this, SLOT(stop())); + } + else + { + popup->setItemEnabled(check_id, false); + popup->setItemEnabled(read_id, false); + popup->insertItem(i18n("&Start"), this, SLOT(start())); + } + popup->insertSeparator(); + } + + popup->insertItem(i18n("E&xit"), kapp, SLOT(quit())); + + popup->popup(QCursor::pos()); +} + +void KBiff::reset() +{ + // reset all the member variables + systemBeep = true; + runCommand = false; + runCommandPath = ""; + playSound = false; + playSoundPath = ""; + notify = true; + dostatus = true; + + noMailIcon = "nomail"; + newMailIcon = "newmail"; + oldMailIcon = "oldmail"; + noConnIcon = "noconn"; + stoppedIcon = "stopped"; + + docked = false; + isSecure = false; + + mailClient = "xmutt -f +%m"; + + myMUTEX = false; +} + +bool KBiff::isRunning() +{ + bool is_running = false; + KBiffMonitor *monitor; + for (monitor = monitorList.first(); + monitor != 0; + monitor = monitorList.next()) + { + if (monitor->isRunning()) + { + is_running = true; + break; + } + } + return is_running; +} + +void KBiff::executeCommand(const QString& command) +{ + KRun::runCommand(command); +} + +void KBiff::slotLaunchFetchClient(const QString& fetchClient) +{ + if (!fetchClient.isEmpty()) + executeCommand(fetchClient); +} + +void KBiff::slotLaunchMailClient() +{ + if (!mailClient.isEmpty()) + executeCommand(replaceCommandArgs(mailClient)); +} + +void KBiff::slotPlaySound(const QString& play_sound) +{ + // make sure something is specified + if (!play_sound.isNull()) + KAudioPlayer::play(play_sound); +} + +bool KBiff::process(const QCString&, const QCString& function, + const QByteArray& data, QCString& replyType, + QByteArray &replyData) +{ + QDataStream args(data, IO_ReadOnly); + QDataStream reply(replyData, IO_WriteOnly); + QString proxy; + if (function == "proxyRegister(QString)") + { + args >> proxy; + proxyList.append(proxy); + replyType = "void"; + return true; + } + + else if (function == "proxyDeregister(QString)") + { + args >> proxy; + proxyList.remove(proxy); + replyType = "void"; + return true; + } + + else if (function == "hasMailbox(QString)") + { + QString mailbox; + args >> mailbox; + + reply << (bool) findMailbox(mailbox, proxy); + replyType = "bool"; + return true; + } + + else if (function == "mailCount(QString)") + { + reply << -1; + replyType = "int"; + return true; + } + + else if (function == "newMailCount(QString)") + { + QString mailbox; + args >> mailbox; + + reply << newMailCount(mailbox); + replyType = "int"; + return true; + } + + + return false; +} + +int KBiff::newMailCount(const QString& url) +{ + int newmail = -1; + + QString proxy; + if (findMailbox(url, proxy) == true) + { + if (proxy != QString::null) + { + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + ds << url; + + QByteArray reply_data; + QCString reply_type; + QDataStream reply(reply_data, IO_ReadOnly); + + DCOPClient *dcc = kapp->dcopClient(); + if (dcc->call(proxy.ascii(), "kbiff", + "newMailCount(QString)", data, reply_type, + reply_data) == true) + { + reply >> newmail; + } + } + else + { + KBiffMonitor *monitor; + for(monitor = monitorList.first(); monitor; + monitor = monitorList.next()) + { + if (monitor->getMailbox() == url) + { + newmail = monitor->newMessages(); + break; + } + } + } + } + + return newmail; +} + +bool KBiff::findMailbox(const QString& url, QString& proxy) +{ + bool has_mailbox = false; + KBiffMonitor *monitor; + for(monitor = monitorList.first(); monitor; monitor = monitorList.next()) + { + if (monitor->getMailbox() == url) + { + has_mailbox = true; + break; + } + } + if (has_mailbox == false) + { + QByteArray data, replyData; + QCString replyType; + QDataStream ds(data, IO_WriteOnly); + ds << url; + // okay, now try to iterate through our proxies + QStringList::Iterator it = proxyList.begin(); + for ( ; it != proxyList.end(); it++) + { + DCOPClient *dcc = kapp->dcopClient(); + if (dcc->call(QCString((*it).ascii()), "kbiff", + "hasMailbox(QString)", data, replyType, + replyData) == true) + { + has_mailbox = true; + proxy = *it; + break; + } + } + } + + return has_mailbox; +} + +void KBiff::registerMe(DCOPClient *client) +{ + // we need to attach our client before doing anything + client->attach(); + + // if we aren't registered yet, then we will do so.. and be + // responsible for all *other* kbiff requests, too! + if (client->isApplicationRegistered("kbiff") == false) + client->registerAs("kbiff"); + else + { + // okay, there is a running kbiff already. we will let it + // know that we are active and let it feed us requests + QCString proxy = QCString("kbiff-") + QCString().setNum(getpid()); + QByteArray params, reply; + QCString reply_type; + QDataStream ds(params, IO_WriteOnly); + ds << proxy; + client->send("kbiff", "kbiff", "proxyRegister(QString)", params); + client->registerAs(QCString(proxy)); + } +} + +void KBiff::invalidLogin(const QString& mailbox) +{ + QString title(i18n("Invalid Login to %1").arg(mailbox)); + KMessageBox::sorry(0, + i18n("I was not able to login to the remote server.\n" + "This means that either the server is down or you have " + "entered an incorrect username or password.\n" + "Please make sure that you have entered the correct settings."), + title); +} -- cgit v1.2.3