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

watch.cc

#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/poll.h>

#include <set>
#include <string>

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

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

char notify_method[] = "inotify";

void watch(const char* maildir)
{
      struct inotify_state state(maildir);
      const int pfds_len = 2;
      struct pollfd pfds[pfds_len];

      pfds[0].fd = state.inotify_fd;
      pfds[0].events = POLLIN;

      // watch for maildir creates and renames and 'maildir' deletion
      // NOTE: This will not detect a maildir move (or a parent move).
      //       Detecting this would take some good work, eg directory symlinks.
      watcher_base wb(&state);
      pfds[1].fd = wb.inotify_fd;
      pfds[1].events = POLLIN;


      // watch for changes in maildirs
      {
            set<string> maildirs, 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);
      }

      send_watch_started();

      while (1)
      {
            state.reset_new_wds();
            int r = TEMP_FAILURE_RETRY(poll(pfds, pfds_len, -1));
            die_if(r < 0, "poll");

            for (int pfd = 0; pfd < pfds_len; pfd++)
            {
                  if (!pfds[pfd].revents)
                        continue;

                  char buf[100 * sizeof(struct inotify_event) + MAXNAMLEN];
                  int len = TEMP_FAILURE_RETRY(read(pfds[pfd].fd, buf, sizeof(buf)));
                  die_if(len < 0, "read");
            
                  struct inotify_event* event;
                  for (int i = 0; i < len; i += sizeof(*event) + event->len)
                  {
                        event = (struct inotify_event*) &buf[i];

                        if (event->mask & (IN_Q_OVERFLOW | IN_UNMOUNT))
                              // events were missed->sync lost (QO) / mail gone (umount)
                              exit(EXIT_RESTART); 

                        if (event->mask & IN_IGNORED)
                              continue;

                        if (pfd == 1)
                              wb.process_event(*event);
                        else
                        {
                              if (state.is_new_wd(event->wd))
                                    continue;

                              watcher* w = state.get_watcher_by_wd(event->wd);
                              if (w)
                                    w->process_event(*event);
                        }
                  }
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index