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

watcher_base.cc

#include <assert.h>

#include <algorithm>
#include <set>
#include <map>

#include "lib/util.h"
#include "watch_maildirs.h"
#include "watcher_maildir.h"
#include "watcher_partial.h"
#include "watcher_base.h"

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

watcher_base::watcher_base(struct dnotify_state* state)
      : state(state)
{
      // watch for maildir creates, deletes, and renames
      // NOTE: This will not detect a maildir move (or a parent move) or delete.
      //       Detecting this would take some good work, eg directory symlinks.
      fd = start_watch(state->base_path.c_str());

      set<string> partial_maildirs;

      add_maildirs(state->base_path.c_str(),
                   inserter(maildirs), inserter(partial_maildirs));

      for (set<string>::iterator it = maildirs.begin();
           it != maildirs.end();
           ++it)
            new watcher_maildir(state, *it);

      for (set<string>::iterator it = partial_maildirs.begin();
           it != partial_maildirs.end();
           ++it)
            new watcher_partial(state, *it);

      maildirs.insert(partial_maildirs.begin(), partial_maildirs.end());
}

watcher_base::~watcher_base()
{
      if (fd >= 0)
            stop_watch(fd);
}


void watcher_base::process_event(int fd)
{
      assert(fd == this->fd);
      refresh_maildirs();
}


void watcher_base::refresh_maildirs()
{
      // XXX: Even when 'maildirs' and 'now_maildirs' are equal,
      // a maildir could have been removed and another with the same name
      // created. This function will miss such cases!
      // However, we take this "risky" approach instead of always exiting
      // because MUAs/MTAs may create/delete files for their own
      // tracking. For example, courier's 'courierimapuiddb',
      // which is recreated for each newly delivered message sync.

      set<string> now_maildirs, now_partial_maildirs;
      set<string> del_maildirs;
      set<string> new_maildirs;

      add_maildirs(state->base_path.c_str(),
                   inserter(now_maildirs), inserter(now_partial_maildirs));

      set_difference(maildirs.begin(), maildirs.end(),
                     now_maildirs.begin(), now_maildirs.end(),
                     inserter(del_maildirs));
      set_difference(now_maildirs.begin(), now_maildirs.end(),
                     maildirs.begin(), maildirs.end(),
                     inserter(new_maildirs));

      for (set<string>::iterator it = del_maildirs.begin();
           it != del_maildirs.end();
           ++it)
      {
            string imap_name(maildir_to_imap(*it));
            watcher* w = state->get_imap_watcher(imap_name);
            assert(w);
            delete w;
            maildirs.erase(*it);
            send_maildir_modified(imap_name.c_str());
      }

      for (set<string>::iterator it = now_partial_maildirs.begin();
           it != now_partial_maildirs.end();
           ++it)
      {
            if (maildirs.find(*it) == maildirs.end())
            {
                  new watcher_partial(state, *it);
                  maildirs.insert(*it);
            }
      }

      for (set<string>::iterator it = new_maildirs.begin();
           it != new_maildirs.end();
           ++it)
      {
            new watcher_maildir(state, *it);
            send_maildir_modified(maildir_to_imap(*it).c_str());
      }
      maildirs.insert(new_maildirs.begin(), new_maildirs.end());
}

int watcher_base::start_watch(const char* dir)
{
      int fd = open(dir, O_RDONLY);
      die_if(fd < 0, "open(\"%s\")", dir);
      set_fd_watch(fd, notify, dir);
      state->add_base_watcher(fd, this);
      return fd;
}

void watcher_base::stop_watch(int fd)
{
      state->remove_base_watcher(fd);
      int r = close(fd);
      die_if(r < 0, "close");
}

Generated by  Doxygen 1.6.0   Back to index