summaryrefslogtreecommitdiffstats
path: root/libmail/mboxlock.C
diff options
context:
space:
mode:
Diffstat (limited to 'libmail/mboxlock.C')
-rw-r--r--libmail/mboxlock.C174
1 files changed, 174 insertions, 0 deletions
diff --git a/libmail/mboxlock.C b/libmail/mboxlock.C
new file mode 100644
index 0000000..46687a1
--- /dev/null
+++ b/libmail/mboxlock.C
@@ -0,0 +1,174 @@
+/*
+** Copyright 2002, Double Precision Inc.
+**
+** See COPYING for distribution information.
+*/
+#include "libmail_config.h"
+#include "mboxlock.H"
+#include "mboxopen.H"
+#include "file.H"
+#include <cstring>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+using namespace std;
+
+//
+// Stub callback used for the OpenTask that updates the internal folder
+// index. When OpenTask completes this object goes back on the queue.
+//
+
+
+mail::mbox::LockTask::reopenCallback::reopenCallback(mail::mbox::LockTask *t)
+ : task(t)
+{
+}
+
+mail::mbox::LockTask::reopenCallback::~reopenCallback()
+{
+}
+
+void mail::mbox::LockTask::reopenCallback::success(string msg)
+{
+ try {
+ task->mboxAccount.installTask(task);
+ } catch (...) {
+ delete task;
+ LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
+ }
+}
+
+void mail::mbox::LockTask::reopenCallback::fail(string msg)
+{
+ task->fail(msg);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+mail::mbox::LockTask::LockTask(mail::mbox &mboxAccount,
+ mail::callback &callbackArg, string filenameArg)
+ : TimedTask(mboxAccount, callbackArg), reopen(this),
+ filename(filenameArg)
+{
+}
+
+mail::mbox::LockTask::~LockTask()
+{
+}
+
+bool mail::mbox::LockTask::doit()
+{
+ for (;;)
+ {
+ string pathStr=filename;
+ bool ro=false;
+
+ if (pathStr.size() == 0)
+ {
+ pathStr=mboxAccount.currentFolder;
+ ro=mboxAccount.currentFolderReadOnly;
+ }
+
+ if (pathStr.size() == 0)
+ {
+ callback.success("Folder locked");
+ done();
+ return true;
+ }
+
+ struct stat stat_buf;
+
+ if (pathStr == "INBOX")
+ pathStr=mboxAccount.inboxMailboxPath;
+
+ if (mboxAccount.multiLockLock &&
+ mboxAccount.multiLockFilename == pathStr)
+ {
+ return locked( *mboxAccount.multiLockLock, pathStr);
+ }
+
+ mail::mbox::lock mailbox_lock( pathStr );
+
+ if (!mailbox_lock(ro))
+ {
+ // TODO: fail if EEXIST
+
+ if (errno != EAGAIN && errno != EEXIST)
+ {
+ fail(pathStr + ": " + strerror(errno));
+ return true;
+ }
+ return false;
+ }
+
+ if (filename.size() > 0)
+ // Locked another folder, no need
+ // to check.
+ {
+ try {
+ return locked(mailbox_lock, pathStr);
+ } catch (...) {
+ fail("Exception caught while accessing folder.");
+ }
+ return true;
+ }
+
+ if (fstat(mailbox_lock.getfd(), &stat_buf) < 0)
+ {
+ fail(pathStr + ": " + strerror(errno));
+ return true;
+ }
+
+ if (stat_buf.st_size != mboxAccount.folderSavedSize ||
+ stat_buf.st_mtime != mboxAccount.folderSavedTimestamp)
+ break;
+
+ try {
+ return locked(mailbox_lock, pathStr);
+ } catch (...) {
+ fail("Exception caught while accessing folder.");
+ }
+ return true;
+ }
+
+ // Uh-oh, something happened to the folder.
+
+ OpenTask *t=new OpenTask(mboxAccount, mboxAccount.currentFolder, reopen, NULL);
+
+ if (!t)
+ {
+ fail(mboxAccount.currentFolder + ": " + strerror(errno));
+ return true;
+ }
+
+ try {
+ mboxAccount.tasks.pop();
+ } catch (...) {
+ delete t;
+ LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
+ }
+
+ try {
+ mboxAccount.installTask(t);
+ } catch (...) {
+ fail("Exception caught while accessing folder.");
+ }
+
+ return true;
+}
+
+bool mail::mbox::LockTask::locked(mail::mbox::lock &mlock, string path)
+{
+ mail::file mboxFp(mlock.getfd(),
+ mlock.readOnly() ? "r":"r+");
+
+ if (!mboxFp)
+ {
+ fail(strerror(errno));
+ return true;
+ }
+
+ return (locked(mboxFp));
+}