Back to index

courier  0.68.2
Classes | Defines | Functions
maildirwatch.h File Reference
#include <time.h>
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  maildirwatch
struct  maildirwatch_contents

Defines

#define WATCHDOTLOCK   "tmp/courier.lock"
#define KEYWORDDIR   "courierimapkeywords"

Functions

struct maildirwatchmaildirwatch_alloc (const char *maildir)
void maildirwatch_free (struct maildirwatch *w)
void maildirwatch_cleanup ()
int maildirwatch_unlock (struct maildirwatch *w, int nseconds)
int maildirwatch_start (struct maildirwatch *p, struct maildirwatch_contents *w)
int maildirwatch_started (struct maildirwatch_contents *w, int *fdret)
int maildirwatch_check (struct maildirwatch_contents *w, int *changed, int *fdret, int *timeout)
void maildirwatch_end (struct maildirwatch_contents *w)
char * maildir_lock (const char *maildir, struct maildirwatch *w, int *tryAnyway)

Class Documentation

struct maildirwatch

Definition at line 48 of file maildirwatch.h.

Class Members
char * maildir
time_t now
time_t timeout
struct maildirwatch_contents

Definition at line 79 of file maildirwatch.h.

Collaboration diagram for maildirwatch_contents:
Class Members
struct maildirwatch * w

Define Documentation

#define KEYWORDDIR   "courierimapkeywords"

Definition at line 61 of file maildirwatch.h.

#define WATCHDOTLOCK   "tmp/courier.lock"

Definition at line 59 of file maildirwatch.h.


Function Documentation

char* maildir_lock ( const char *  maildir,
struct maildirwatch w,
int *  tryAnyway 
)

Definition at line 23 of file maildirlock.c.

{
       struct maildir_tmpcreate_info createInfo;
       char *tmpname;
       char *newname;
       int rc;

       *tryAnyway=0;

       maildir_tmpcreate_init(&createInfo);

       createInfo.maildir=dir;
       createInfo.uniq="courierlock";
       createInfo.hostname=getenv("HOSTNAME");
       createInfo.doordie=1;

       if ((rc=maildir_tmpcreate_fd(&createInfo)) < 0)
              return NULL;
       close(rc);

       tmpname=createInfo.tmpname;
       newname=createInfo.newname;

       createInfo.tmpname=NULL;
       createInfo.newname=NULL;
       maildir_tmpcreate_free(&createInfo);

       /* HACK: newname now contains: ".../new/filename" */

       strcpy(strrchr(newname, '/')-3, WATCHDOTLOCK);

       while (ll_dotlock(newname, tmpname, 120) < 0)
       {
              if (errno == EEXIST)
              {
                     if (w == NULL || maildirwatch_unlock(w, 120) < 0)
                            sleep(1);
                     continue;
              }

              if (errno == EAGAIN)
              {
                     unlink(newname);
                     sleep(5);
                     continue;
              }

              free(newname);
              newname=NULL;
              *tryAnyway=1;
              break;
       }

       free(tmpname);

       return newname;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct maildirwatch* maildirwatch_alloc ( const char *  maildir) [read]

Definition at line 25 of file maildirwatch.c.

{
       char wd[PATH_MAX];
       struct maildirwatch *w;

       if (maildir == 0 || *maildir == 0)
              maildir=".";

       if (getcwd(wd, sizeof(wd)-1) == NULL)
              return NULL;

       if (*maildir == '/')
              wd[0]=0;
       else
              strcat(wd, "/");

       if ((w=malloc(sizeof(struct maildirwatch))) == NULL)
              return NULL;

       if ((w->maildir=malloc(strlen(wd)+strlen(maildir)+1)) == NULL)
       {
              free(w);
              return NULL;
       }

       strcat(strcpy(w->maildir, wd), maildir);

#if HAVE_FAM
       if (!maildirwatch_currentfam)
       {
              if ((maildirwatch_currentfam
                   =malloc(sizeof(*maildirwatch_currentfam))) != NULL)
              {
                     maildirwatch_currentfam->broken=0;
                     maildirwatch_currentfam->refcnt=0;

                     alarm(15);
                     if (FAMOpen(&maildirwatch_currentfam->fc) < 0)
                     {
                            errno=EIO;
                            free(maildirwatch_currentfam);
                            maildirwatch_currentfam=NULL;
                     }
                     alarm(0);
              }
       }

       if (!maildirwatch_currentfam)
       {
              free(w->maildir);
              free(w);
              w=NULL;
       }
       else
       {
              w->fam=maildirwatch_currentfam;
              ++w->fam->refcnt;
       }
#endif
       return w;
}

Here is the caller graph for this function:

int maildirwatch_check ( struct maildirwatch_contents w,
int *  changed,
int *  fdret,
int *  timeout 
)

Definition at line 489 of file maildirwatch.c.

{
       struct maildirwatch *w=mc->w;
       time_t curTime;

       *changed=0;
       *fdret=-1;

       curTime=time(NULL);

       if (curTime < w->now)
              w->timeout=curTime; /* System clock changed */
       w->now=curTime;

#if HAVE_FAM

       if (!w->fam->broken)
       {
              *fdret=FAMCONNECTION_GETFD(&w->fam->fc);

              while (FAMPending(&w->fam->fc))
              {
                     FAMEvent fe;

                     errno=EIO;

                     if (FAMNextEvent(&w->fam->fc, &fe) != 1)
                     {
                            fprintf(stderr, "ERR:FAMNextEvent: %s\n",
                                   strerror(errno));
                            maildirwatch_fambroken(w);
                            return (-1);
                     }

                     switch (fe.code) {
                     case FAMDeleted:
                     case FAMCreated:
                     case FAMMoved:
                            if (!mc->cancelled)
                            {
                                   mc->cancelled=1;
                                   CANCEL(mc);
                            }
                            break;
                     case FAMAcknowledge:
                            ++mc->ack_received;
                     default:
                            break;
                     }
              }

              *changed=mc->ack_received >= DIRCNT;
              *timeout=60 * 60;
              return 0;
       }
#endif
       *timeout=60;

       if ( (*changed= w->now >= w->timeout) != 0)
              w->timeout = w->now + 60;
       return 0;
}

Here is the caller graph for this function:

Definition at line 115 of file maildirwatch.c.

{
#if HAVE_FAM

       if (maildirwatch_currentfam && maildirwatch_currentfam->refcnt == 0)
       {
              FAMClose(&maildirwatch_currentfam->fc);
              free(maildirwatch_currentfam);
              maildirwatch_currentfam=NULL;
       }
#endif
}

Here is the caller graph for this function:

Definition at line 555 of file maildirwatch.c.

{
#if HAVE_FAM
       struct maildirwatch *w=mc->w;

       if (!w->fam->broken)
       {
              if (!mc->cancelled)
              {
                     mc->cancelled=1;

#define return(x)
                     CANCEL(mc);
#undef return
              }
       }

       while (!w->fam->broken && mc->ack_received < DIRCNT)
       {
              FAMEvent fe;

              time(&w->now);
              w->timeout=w->now + 15;

              errno=EIO;

              if (waitEvent(w) != 1)
              {
                     fprintf(stderr, "ERR:FAMPending: timeout\n");
                     maildirwatch_fambroken(w);
                     break;
              }

              errno=EIO;

              if (FAMNextEvent(&w->fam->fc, &fe) != 1)
              {
                     fprintf(stderr, "ERR:FAMNextEvent: %s\n",
                            strerror(errno));
                     maildirwatch_fambroken(w);
                     break;
              }

              if (fe.code == FAMAcknowledge)
                     ++mc->ack_received;
       }
#endif
}

Here is the caller graph for this function:

void maildirwatch_free ( struct maildirwatch w)

Definition at line 87 of file maildirwatch.c.

{
#if HAVE_FAM
       if (--w->fam->refcnt == 0)
       {
              w->fam->broken=1;
              if (maildirwatch_currentfam &&
                  maildirwatch_currentfam->broken)
              {
                     /*
                     ** Last reference to the current FAM connection,
                     ** keep it active.
                     */

                     w->fam->broken=0;
              }
              else /* Some other connection, with no more refs */
              {
                     FAMClose(&w->fam->fc);
                     free(w->fam);
              }
       }
#endif

       free(w->maildir);
       free(w);
}

Here is the caller graph for this function:

int maildirwatch_start ( struct maildirwatch p,
struct maildirwatch_contents w 
)

Definition at line 308 of file maildirwatch.c.

{
       mc->w=w;

       time(&w->now);
       w->timeout = w->now + 60;

#if HAVE_FAM

       maildirwatch_famunbreak(w);

       if (w->fam->broken)
       {
              errno=EIO;
              return (1);
       }

       {
              char *s=malloc(strlen(w->maildir)
                            +sizeof("/" KEYWORDDIR));

              if (!s)
                     return (-1);

              strcat(strcpy(s, w->maildir), "/new");

              mc->endexists_received=0;
              mc->ack_received=0;
              mc->cancelled=0;

              errno=EIO;

              if (FAMMonitorDirectory(&w->fam->fc, s, &mc->new_req, NULL) < 0)
              {
                     fprintf(stderr, "ERR:"
                            "FAMMonitorDirectory(%s) failed: %s\n",
                            s, strerror(errno));
                     free(s);
                     errno=EIO;
                     return (-1);
              }

              strcat(strcpy(s, w->maildir), "/cur");
              errno=EIO;

              if (FAMMonitorDirectory(&w->fam->fc, s, &mc->cur_req, NULL) < 0)
              {
                     fprintf(stderr, "ERR:"
                            "FAMMonitorDirectory(%s) failed: %s\n",
                            s, strerror(errno));

                     errno=EIO;

                     if (FAMCancelMonitor(&mc->w->fam->fc, &mc->new_req) < 0)
                     {
                            free(s);
                            maildirwatch_fambroken(w);
                            fprintf(stderr, "ERR:FAMCancelMonitor: %s\n",
                                   strerror(errno));
                            errno=EIO;
                            return (-1);
                     }
                     mc->cancelled=1;
                     mc->ack_received=2;
              }

              strcat(strcpy(s, w->maildir), "/" KEYWORDDIR);
              errno=EIO;

              if (FAMMonitorDirectory(&w->fam->fc, s,
                                   &mc->courierimapkeywords_req, NULL)<0)
              {
                     fprintf(stderr, "ERR:"
                            "FAMMonitorDirectory(%s) failed: %s\n",
                            s, strerror(errno));

                     errno=EIO;

                     if (FAMCancelMonitor(&mc->w->fam->fc, &mc->new_req)<0)
                     {
                            free(s);
                            maildirwatch_fambroken(w);
                            fprintf(stderr, "ERR:FAMCancelMonitor: %s\n",
                                   strerror(errno));
                            errno=EIO;
                            return (-1);
                     }

                     errno=EIO;

                     if (FAMCancelMonitor(&mc->w->fam->fc, &mc->cur_req)<0)
                     {
                            free(s);
                            maildirwatch_fambroken(w);
                            fprintf(stderr, "ERR:FAMCancelMonitor: %s\n",
                                   strerror(errno));
                            errno=EIO;
                            return (-1);
                     }

                     mc->cancelled=1;
                     mc->ack_received=1;
              }

              free(s);
       }
       return 0;
#else
       return 1;
#endif
}

Here is the caller graph for this function:

int maildirwatch_started ( struct maildirwatch_contents w,
int *  fdret 
)

Definition at line 436 of file maildirwatch.c.

{
#if HAVE_FAM
       struct maildirwatch *w=mc->w;

       if (w->fam->broken)
              return (1);

       *fdret=FAMCONNECTION_GETFD(&w->fam->fc);

       while (FAMPending(&w->fam->fc))
       {
              FAMEvent fe;

              errno=EIO;

              if (FAMNextEvent(&w->fam->fc, &fe) != 1)
              {
                     fprintf(stderr, "ERR:FAMNextEvent: %s\n",
                            strerror(errno));
                     maildirwatch_fambroken(w);
                     return (-1);
              }

              switch (fe.code) {
              case FAMDeleted:
                     if (!mc->cancelled)
                     {
                            mc->cancelled=1;
                            CANCEL(mc);
                     }
                     break;
              case FAMAcknowledge:
                     if (++mc->ack_received >= DIRCNT)
                            return -1;
                     break;
              case FAMEndExist:
                     ++mc->endexists_received;
                     break;
              default:
                     break;
              }
       }

       return (mc->endexists_received >= DIRCNT && mc->ack_received == 0);
#else
       *fdret= -1;

       return 1;
#endif
}

Here is the caller graph for this function:

int maildirwatch_unlock ( struct maildirwatch w,
int  nseconds 
)

Definition at line 206 of file maildirwatch.c.

{
#if HAVE_FAM
       FAMRequest fr;
       FAMEvent fe;
       int cancelled=0;
       char *p;

       if (w->fam->broken)
       {
              errno=EIO;
              return -1;
       }

       p=malloc(strlen(w->maildir)+ sizeof("/" WATCHDOTLOCK));

       if (!p)
              return -1;

       strcat(strcpy(p, w->maildir), "/" WATCHDOTLOCK);

       errno=EIO;
       if (FAMMonitorFile(&w->fam->fc, p, &fr, NULL) < 0)
       {
              free(p);
              fprintf(stderr, "ERR:FAMMonitorFile: %s\n",
                     strerror(errno));
              return -1;
       }
       free(p);

       if (nseconds < 0)
              nseconds=0;

       time(&w->now);

       w->timeout=w->now + nseconds;

       for (;;)
       {
              if (waitEvent(w) != 1)
              {
                     errno=EIO;

                     if (!cancelled && FAMCancelMonitor(&w->fam->fc, &fr) == 0)
                     {
                            w->timeout=w->now+15;
                            cancelled=1;
                            continue;
                     }

                     if (!cancelled)
                            fprintf(stderr, "ERR:FAMCancelMonitor: %s\n",
                                   strerror(errno));

                     maildirwatch_fambroken(w);
                     break;
              }

              errno=EIO;

              if (FAMNextEvent(&w->fam->fc, &fe) != 1)
              {
                     fprintf(stderr, "ERR:FAMNextEvent: %s\n",
                            strerror(errno));
                     maildirwatch_fambroken(w);
                     break;
              }

              if (fe.fr.reqnum != fr.reqnum)
                     continue;

              if (fe.code == FAMDeleted && !cancelled)
              {
                     errno=EIO;
                     if (FAMCancelMonitor(&w->fam->fc, &fr) == 0)
                     {
                            w->timeout=w->now+15;
                            cancelled=1;
                            continue;
                     }
                     fprintf(stderr, "ERR:FAMCancelMonitor: %s\n",
                            strerror(errno));
                     maildirwatch_fambroken(w);
                     break;
              }

              if (fe.code == FAMAcknowledge)
                     break;
       }

       if (w->fam->broken)
              return -1;

       return 0;
#else
       return -1;
#endif
}

Here is the caller graph for this function: