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

state.cc

#include <assert.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>

#include "lib/util.h"
#include "state.h"

using std::map;
using std::pair;
using std::set;
using std::string;

dnotify_state::dnotify_state(const char* base_path)
      : base_path(base_path), base_path_fd(-1), base_path_maildir_watch(false)
{
}

dnotify_state::~dnotify_state()
{
      for (map<int, watcher*>::iterator it = watchers.begin();
             it != watchers.end();
             ++it)
            delete it->second;
}


void dnotify_state::add_base_watcher(int fd, watcher* w)
{
      // safety checks
      assert(watchers.find(fd) == watchers.end());

      assert(base_path_file.get() == NULL);
      assert(base_path_fd == -1);
      assert(!base_path_maildir_watch);
      base_path_file.reset(new open_file(fd));
      base_path_fd = fd;

      pair<set<open_file>::iterator, bool> r = open_files.insert(open_file(fd));
      assert(r.second);

      // add
      watchers[fd] = w;
}

void dnotify_state::add_imap_watcher(int fd, const string& imap_name, watcher* w)
{
      // safety checks
      assert(watchers.find(fd) == watchers.end());
      assert(base_path_file.get() != NULL);
      assert(base_path_fd != -1);

      open_file fd_file(fd);
      pair<set<open_file>::iterator, bool> r = open_files.insert(fd_file);
      bool is_base_path = fd_file == *base_path_file;
      if ((!is_base_path && !r.second) || (is_base_path && base_path_maildir_watch))
      {
            fprintf(stderr, "Encountered the same inode multiple times, while starting to watch IMAP folder \"%s\". Either there are multiple paths to the inode (not supported) or the underlying filesystem is quickly changing (restart).\n", imap_name.c_str());
            exit(1);
      }
      if (is_base_path)
      {
            assert(!r.second);
            base_path_maildir_watch = true;
      }

      // add
      watchers[fd] = w;

      // allow multiple calls with the same 'imap_name' to allow multiple fds
      watcher* existing_imap = get_imap_watcher(imap_name);
      if (existing_imap)
            assert(existing_imap == w);
      else
            imap2watcher[imap_name] = w;
}


void dnotify_state::remove_watcher(int fd)
{
      set<open_file>::size_type ofn = open_files.erase(open_file(fd));
      assert(ofn == 1);
      map<int, watcher*>::size_type wn = watchers.erase(fd);
      assert(wn == 1);
}

void dnotify_state::remove_base_watcher(int fd)
{
      assert(base_path_fd != -1);
      assert(!base_path_maildir_watch);

      remove_watcher(fd);
      base_path_file.reset();
      base_path_fd = -1;
}

void dnotify_state::remove_imap_watcher(int fd, const string& imap_name)
{
      assert(base_path_file.get() != NULL);
      assert(base_path_fd != -1);
      bool is_base_path = open_file(fd) == *base_path_file;

      remove_watcher(fd);
      if (is_base_path)
      {
            assert(base_path_maildir_watch);
            base_path_maildir_watch = false;
      }

      // allow multiple calls with the same 'imap_name' to allow multiple fds
      map<string, watcher*>::iterator it = imap2watcher.find(imap_name);
      if (it != imap2watcher.end())
            (void) imap2watcher.erase(it);
}


watcher* dnotify_state::get_watcher_by_fd(int fd)
{
      map<int, watcher*>::iterator it = watchers.find(fd);
      if (it == watchers.end())
            return NULL;
      return it->second;
}

watcher* dnotify_state::get_imap_watcher(const string& imap_name)
{
      map<string, watcher*>::iterator it = imap2watcher.find(imap_name);
      if (it == imap2watcher.end())
            return NULL;
      return it->second;
}


void set_fd_watch(int fd, long notify_flags, const char* name)
{
      int r;
      r = fcntl(fd, F_SETSIG, SIGRTMIN);
      die_if(r < 0, "fcntl(F_SETSIG, \"%s\")", name);
      r = fcntl(fd, F_NOTIFY, notify_flags);
      die_if(r < 0, "fcntl(F_NOTIFY, \"%s\")", name);
}

Generated by  Doxygen 1.6.0   Back to index