Common maildir part to separate modile.
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Thu, 1 Nov 2007 20:17:45 +0000 (20:17 +0000)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Thu, 1 Nov 2007 20:17:45 +0000 (20:17 +0000)
org.glite.lbjp-common.maildir/.cvsignore [new file with mode: 0644]
org.glite.lbjp-common.maildir/Makefile [new file with mode: 0644]
org.glite.lbjp-common.maildir/interface/maildir.h [new file with mode: 0644]
org.glite.lbjp-common.maildir/project/version.properties [new file with mode: 0644]
org.glite.lbjp-common.maildir/src/maildir.c [new file with mode: 0644]

diff --git a/org.glite.lbjp-common.maildir/.cvsignore b/org.glite.lbjp-common.maildir/.cvsignore
new file mode 100644 (file)
index 0000000..378eac2
--- /dev/null
@@ -0,0 +1 @@
+build
diff --git a/org.glite.lbjp-common.maildir/Makefile b/org.glite.lbjp-common.maildir/Makefile
new file mode 100644 (file)
index 0000000..68aa74c
--- /dev/null
@@ -0,0 +1,87 @@
+# defaults
+top_srcdir=.
+builddir=build
+stagedir=.
+distdir=.
+globalprefix=glite
+lbutilsprefix=lbu
+package=glite-lb-utils-maildir
+version=1.0.0
+PREFIX=/opt/glite
+flavour=gcc32thr
+
+glite_location=/opt/glite
+cppunit_prefix=/opt/cppunit
+thrflavour=gcc32pthr
+nothrflavour=gcc32
+
+-include Makefile.inc
+-include ../project/version.properties
+
+CC=gcc
+
+VPATH=${top_srcdir}/interface:${top_srcdir}/src:${top_srcdir}/examples
+
+DEBUG:=-g -O0 -W -Wall
+
+CFLAGS:= \
+       ${DEBUG} \
+       -DVERSION=\"${version}\" \
+       -I${stagedir}/include -I${top_srcdir}/src -I. \
+       -I${top_srcdir}/interface \
+       ${COVERAGE_FLAGS} \
+       -D_GNU_SOURCE
+
+LDFLAGS:=-L${stagedir}/lib ${COVERAGE_FLAGS}
+
+COMPILE:=libtool --mode=compile ${CC} ${CFLAGS}
+LINK:=libtool --mode=link ${CC} -rpath ${stagedir}/lib ${LDFLAGS} 
+INSTALL:=libtool --mode=install install
+
+EXT_LIBS:=
+OBJS:=maildir.o
+HDRS:=maildir.h
+LOBJS:=${OBJS:.o=.lo}
+
+default all: compile doc
+
+libglite_lbu_maildir.la: ${LOBJS}
+       ${LINK} -o $@ $< ${EXT_LIBS}
+
+compile: libglite_lbu_maildir.la
+
+check:
+       -echo No checks here yet.
+
+test_coverage:
+       -mkdir coverage
+       cd coverage && $(MAKE) -f ../Makefile top_srcdir=../../ COVERAGE_FLAGS="-fprofile-arcs -ftest-coverage" check
+       cd coverage && for i in `echo ${OBJS} | tr ' ' '\012' | sort -u`; do gcov $$i ; done
+
+examples:
+
+#doc:
+#      cp ${top_srcdir}/doc/*.dox .
+#      echo "PROJECT_NUMBER = ${version}" >> C.dox
+#      doxygen C.dox
+
+stage: compile
+       $(MAKE) install PREFIX=${stagedir} DOSTAGE=yes
+
+install: all
+       -mkdir -p ${PREFIX}/lib
+       -mkdir -p ${PREFIX}/share/doc/${package}-${version}
+       -mkdir -p ${PREFIX}/include/${globalprefix}/${lbutilsprefix}
+       ${INSTALL} -m 755 "libglite_lbu_maildir.la" "${PREFIX}/lib/libglite_lbu_maildir.la"; \
+       ${INSTALL} -m 644 ${top_srcdir}/interface/${HDRS} ${PREFIX}/include/${globalprefix}/${lbutilsprefix}
+
+clean:
+       rm -rvf *.o *.lo .libs lib* *.c *.h *.dox C/ CPP/
+       rm -rvf log.xml project/ rpmbuild/ RPMS/ tgz/
+
+%.o %.lo: %.c
+       ${COMPILE} -c $<
+
+maildir.lo: maildir.c maildir.h
+
+.PHONY: default all compile check examples doc stage dist distsrc distbin install clean test_coverage
diff --git a/org.glite.lbjp-common.maildir/interface/maildir.h b/org.glite.lbjp-common.maildir/interface/maildir.h
new file mode 100644 (file)
index 0000000..fbca506
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef GLITE_LBU_MAILDIR_H
+#define GLITE_LBU_MAILDIR_H
+
+/*
+ * Functions for reading and writing messages via
+ * maildir protocol.
+ * Used when registering job to the JP, i.e.
+ */
+
+enum {
+       LBMD_TRANS_OK,
+       LBMD_TRANS_FAILED,
+       LBMD_TRANS_FAILED_RETRY,
+};
+       
+extern char lbm_errdesc[];
+
+extern int glite_lbu_MaildirInit(const char *);
+extern int glite_lbu_MaildirStoreMsg(const char *, const char *, const char *);
+extern int glite_lbu_MaildirRetryTransStart(const char *, time_t, time_t, char **, char **);
+extern int glite_lbu_MaildirTransStart(const char *, char **, char **);
+extern int glite_lbu_MaildirTransEnd(const char *, char *, int);
+
+#endif /* GLITE_LBU_MAILDIR_H */
diff --git a/org.glite.lbjp-common.maildir/project/version.properties b/org.glite.lbjp-common.maildir/project/version.properties
new file mode 100644 (file)
index 0000000..608e174
--- /dev/null
@@ -0,0 +1,3 @@
+# $Header$
+module.version=1.0.0
+module.age=0
diff --git a/org.glite.lbjp-common.maildir/src/maildir.c b/org.glite.lbjp-common.maildir/src/maildir.c
new file mode 100644 (file)
index 0000000..13e694b
--- /dev/null
@@ -0,0 +1,399 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <string.h>
+
+#include "glite/lb/lb_maildir.h"
+
+#define DEFAULT_ROOT   "/tmp/lb_maildir"
+
+enum {
+       LBMD_DIR_TMP = 0,
+       LBMD_DIR_NEW,
+       LBMD_DIR_WORK,
+       LBMD_DIR_POST,
+       LBMD_DIR_UNDELIVERABLE
+};
+
+static const char *dirs[] = { "tmp", "new", "work", "post", "undeliverable" };
+
+
+#define MAX_ERR_LEN            1024
+char lbm_errdesc[MAX_ERR_LEN];
+
+
+static int check_mkdir(const char *dir)
+{
+       struct stat sbuf;
+
+       if ( stat(dir, &sbuf) ) {
+               if ( errno == ENOENT ) {
+                       if ( mkdir(dir, S_IRWXU) ) return 1;
+                       if ( stat(dir, &sbuf) )  return 1;
+               }
+               else return 1;
+       }
+
+       if (!S_ISDIR(sbuf.st_mode)) return 1;
+
+       if (access(dir, R_OK | W_OK)) return 1;
+
+       return 0;
+}
+
+
+int glite_lbu_MaildirInit(
+       const char                 *dir)
+{
+       const char *root = dir? : DEFAULT_ROOT;
+       char            dirname[PATH_MAX];
+       int                     i;
+
+       lbm_errdesc[0] = '\0';
+       if ( check_mkdir(root) ) {
+               snprintf(lbm_errdesc, MAX_ERR_LEN, "%s: %s\n", root, strerror(errno));
+               return 1;
+       }
+       
+       for ( i = 0; i < sizeof(dirs)/sizeof((dirs)[0]); i++ ) {
+               snprintf(dirname, PATH_MAX, "%s/%s", root, dirs[i]);
+               if ( check_mkdir(dirname) ) {
+                       snprintf(lbm_errdesc, MAX_ERR_LEN, "%s: %s\n", dirname, strerror(errno));
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+
+int glite_lbu_MaildirStoreMsg(
+       const char      *root,
+       const char      *srvname,
+       const char      *msg)
+{
+       char    fname[PATH_MAX],
+               newfname[PATH_MAX];
+       int     fhnd,
+               written,
+               msgsz,
+               ct, i;
+       struct  timeval  tv;
+
+
+       lbm_errdesc[0] = '\0';
+       if ( !root ) root = DEFAULT_ROOT;
+
+       errno = 0;
+       i = 0;
+       while ( 1 ) {
+               if ( ++i > 10 ) {
+                       errno = ECANCELED;
+                       snprintf(lbm_errdesc, MAX_ERR_LEN, "Maximum tries limit reached with unsuccessful file creation");
+                       return -1;
+               }
+               gettimeofday(&tv, NULL);
+               snprintf(fname, PATH_MAX, "%s/%s/%ld_%ld.%s", root, dirs[LBMD_DIR_TMP], tv.tv_sec, tv.tv_usec, srvname);
+               if ( (fhnd = open(fname, O_CREAT|O_EXCL|O_WRONLY, 00600)) < 0 ) {
+                       if ( errno == EEXIST ) { usleep(1000); continue; }
+                       snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't create file %s", fname);
+                       return -1;
+               }
+               break;
+       }
+
+       msgsz = strlen(msg);
+       written = 0;
+       while ( written < msgsz ) {
+               if ( (ct = write(fhnd, msg+written, msgsz-written)) < 0 ) {
+                       if ( errno == EINTR ) { errno = 0; continue; }
+                       snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't write into file %s", fname);
+                       return -1;
+               }
+               written += msgsz;
+       }
+       if ( fsync(fhnd) ) {
+               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't fsync file %s", fname);
+               return -1;
+       }
+       if ( close(fhnd) ) {
+               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't close file %s", fname);
+               return -1;
+       }
+       snprintf(newfname, PATH_MAX, "%s/%s/%s", root, dirs[LBMD_DIR_NEW], strrchr(fname, '/')+1);
+       if ( link(fname, newfname) ) {
+               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't link new file %s", newfname);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int glite_lbu_MaildirTransEnd(
+       const char                 *root,
+       char                       *fname,
+       int                                     tstate)
+{
+       char            workfname[PATH_MAX],
+                               newfname[PATH_MAX],
+                               origfname[PATH_MAX];
+       struct stat     st;
+
+
+       lbm_errdesc[0] = '\0';
+       if ( !root ) root = DEFAULT_ROOT;
+
+       snprintf(workfname, PATH_MAX, "%s/%s/%s", root, dirs[LBMD_DIR_WORK], fname);
+       unlink(workfname);
+
+       snprintf(origfname, PATH_MAX, "%s/%s/%s", root, dirs[LBMD_DIR_TMP], fname);
+       if ( tstate == LBMD_TRANS_OK ) {
+               unlink(origfname);
+               return 0;
+       }
+
+       if ( tstate == LBMD_TRANS_FAILED ) return 0;
+
+       if ( stat(origfname, &st) ) {
+               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't stat file '%s'", origfname);
+               return -1;
+       }
+
+       snprintf(newfname, PATH_MAX, "%s/%s/%s", root, dirs[LBMD_DIR_POST], fname);
+       if ( link(origfname, newfname) ) {
+               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't link new file %s", newfname);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int glite_lbu_MaildirRetryTransStart(
+       const char      *root,
+       time_t          retry,
+       time_t          remove,
+       char            **msg,
+       char            **fname)
+{
+       static DIR      *dir = NULL;
+       struct dirent   *ent;
+       time_t          tlimit_retry, tlimit_remove;
+       struct stat     st;
+       char            newfname[PATH_MAX],
+                       oldfname[PATH_MAX],
+                       *buf = NULL;
+       int             fhnd,
+                       toread, ct,
+                       bufsz, bufuse;
+
+
+       lbm_errdesc[0] = '\0';
+       if ( !root ) root = DEFAULT_ROOT;
+
+       if ( !dir ) {
+               char    dirname[PATH_MAX];
+               snprintf(dirname, PATH_MAX, "%s/%s", root, dirs[LBMD_DIR_POST]);
+               if ( !(dir = opendir(dirname)) ) {
+                       snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't open directory '%s'", root);
+                       goto err;
+               }
+       }
+
+       tlimit_retry = time(NULL) - retry;
+       tlimit_remove = time(NULL) - remove;
+       do {
+               errno = 0;
+               if ( !(ent = readdir(dir)) ) {
+                       if ( errno == EBADF ) {
+                               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't read directory '%s'", root);
+                               dir = NULL;
+                               goto err;
+                       } else {
+                               closedir(dir);
+                               dir = NULL;
+                               return 0;
+                       }
+               }
+               if ( ent->d_name[0] == '.' ) continue;
+
+               snprintf(oldfname, PATH_MAX, "%s/%s/%s", root, dirs[LBMD_DIR_POST], ent->d_name);
+               snprintf(newfname, PATH_MAX, "%s/%s/%s", root, dirs[LBMD_DIR_WORK], ent->d_name);
+
+               if ( stat(oldfname, &st) < 0 ) {
+                       snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't stat file '%s'", oldfname);
+                       goto err;
+               }
+
+               /* if we cannot deliver the file for 'remove' time limit, */
+               /* it is moved to undeliverable folder and forgotten      */
+               if ( st.st_mtime < tlimit_remove ) {
+                       snprintf(newfname, PATH_MAX, "%s/%s/%s",
+                                root, dirs[LBMD_DIR_UNDELIVERABLE], ent->d_name);
+               }
+               /* try to deliver file every 'retry' seconds */
+               else if ( st.st_ctime > tlimit_retry ) continue;
+
+
+               if ( rename(oldfname, newfname) ) {
+                       if ( errno == ENOENT ) {
+                               /* maybe some other instance moved this file away... */
+                               continue;
+                       } else {
+                               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't move file '%s'", oldfname);
+                               goto err;
+                       }
+               } else {
+                       if (st.st_mtime < tlimit_remove) {
+                               /* we have moved undeliverable file to undeliverable folder */
+                               /* no other action needed */
+                               snprintf(oldfname, PATH_MAX, "%s/%s/%s", root, dirs[LBMD_DIR_TMP], ent->d_name);
+                               unlink(oldfname);
+                               continue;
+                       } else {
+                               /* we have found and moved the file  to work folder */
+                               /* going to process it */
+                               break;
+                       }
+               }
+       } while ( 1 );
+
+       if ( (fhnd = open(newfname, O_RDONLY)) < 0 ) {
+               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't open file '%s'", newfname);
+               goto err;
+       }
+
+       bufuse = bufsz = toread = ct = 0;
+       do {
+               errno = 0;
+               if ( bufuse == bufsz ) {
+                       char *tmp = realloc(buf, bufsz+BUFSIZ);
+                       if ( !tmp ) goto err;
+                       buf = tmp;
+                       bufsz += BUFSIZ;
+               }
+               toread = bufsz - bufuse;
+               if ( (ct = read(fhnd, buf+bufuse, toread)) < 0 ) {
+                       if ( errno == EINTR ) continue;
+                       snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't read file '%s'", newfname);
+                       goto err;
+               }
+               if ( ct == 0 ) break;
+               bufuse += ct;
+       } while ( ct == toread );
+       close(fhnd);
+
+       if ( !(*fname = strdup(ent->d_name)) ) goto err;
+       buf[bufuse] = 0;
+       *msg = buf;
+       return 1;
+
+
+err:
+       if ( buf ) free(buf);
+
+       return -1;
+}
+
+
+int glite_lbu_MaildirTransStart(
+       const char                 *root,
+       char              **msg,
+       char                      **fname)
+{
+       static DIR         *dir = NULL;
+       struct dirent  *ent;
+       char                    newfname[PATH_MAX],
+                                       oldfname[PATH_MAX],
+                                  *buf = NULL;
+       int                             fhnd,
+                                       toread, ct,
+                                       bufsz, bufuse;
+
+
+       lbm_errdesc[0] = '\0';
+       if ( !root ) root = DEFAULT_ROOT;
+
+       if ( !dir ) {
+               char    dirname[PATH_MAX];
+               snprintf(dirname, PATH_MAX, "%s/%s", root, dirs[LBMD_DIR_NEW]);
+               if ( !(dir = opendir(dirname)) ) {
+                       snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't open directory '%s'", root);
+                       goto err;
+               }
+       }
+
+       do {
+               errno = 0;
+               if ( !(ent = readdir(dir)) ) {
+                       if ( errno == EBADF ) {
+                               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't read directory '%s'", root);
+                               dir = NULL;
+                               goto err;
+                       } else {
+                               closedir(dir);
+                               dir = NULL;
+                               return 0;
+                       }
+               }
+               if ( ent->d_name[0] == '.' ) continue;
+               snprintf(newfname, PATH_MAX, "%s/%s/%s", root, dirs[LBMD_DIR_WORK], ent->d_name);
+               snprintf(oldfname, PATH_MAX, "%s/%s/%s", root, dirs[LBMD_DIR_NEW], ent->d_name);
+               if ( rename(oldfname, newfname) ) {
+                       if ( errno == ENOENT ) {
+                               /* maybe some other instance moved this file away... */
+                               continue;
+                       } else {
+                               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't move file '%s'", oldfname);
+                               goto err;
+                       }
+               } else {
+                       /* we have found and moved the file with which we will work now */
+                       break;
+               }
+       } while ( 1 );
+
+       if ( (fhnd = open(newfname, O_RDONLY)) < 0 ) {
+               snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't open file '%s'", newfname);
+               goto err;
+       }
+
+       bufuse = bufsz = toread = ct = 0;
+       do {
+               errno = 0;
+               if ( bufuse == bufsz ) {
+                       char *tmp = realloc(buf, bufsz+BUFSIZ);
+                       if ( !tmp ) goto err;
+                       buf = tmp;
+                       bufsz += BUFSIZ;
+               }
+               toread = bufsz - bufuse;
+               if ( (ct = read(fhnd, buf+bufuse, toread)) < 0 ) {
+                       if ( errno == EINTR ) continue;
+                       snprintf(lbm_errdesc, MAX_ERR_LEN, "Can't read file '%s'", newfname);
+                       goto err;
+               }
+               if ( ct == 0 ) break;
+               bufuse += ct;
+       } while ( ct == toread );
+       close(fhnd);
+
+       if ( !(*fname = strdup(ent->d_name)) ) goto err;
+       buf[bufuse] = 0;
+       *msg = buf;
+       return 1;
+
+
+err:
+       if ( buf ) free(buf);
+
+       return -1;
+}