#include #include #include #include #include #include #include #include extern const char *__progname; #include "seq.h" #include "system.h" #include "folder.h" #include "profile.h" #include "message.h" static int nfolders; static FOLDER **folders; static unsigned int *flags; #define F_DISTINCT 0x00000001 #define F_CANTOPEN 0x00000002 #define F_CANTWRITE 0x00000004 #define F_LOCKED 0x00000008 #define F_ERROR (F_CANTOPEN|F_CANTWRITE) static MESSAGE **msgs; static int nfail; static char **seqs; static int nseqs; static int do_unseen = 1; static void add_seq(const char *s) { int i; for (i=0;i 1) && !strcmp(*av,"-s")) { add_seq(av[1]); ac --; av ++; continue; } break; } nfolders = 0; folders = 0; for (;ac;ac--,av++) { FOLDER *f; char *ep; if ((**av == '+') && folder_lookup(1+*av,&f,&ep) && !*ep) { nfolders ++; folders = realloc(folders,nfolders*sizeof(FOLDER *)); folders[nfolders-1] = f; } else { fprintf(stderr,"%s: `%s': not a folder\n",__progname,*av); errs ++; } } if (errs) exit(1); if (nfolders == 0) { const char *fname; FOLDER *f; char *ep; fname = profile_lookup(system_get_profile(),"inbox"); if (fname) { if (!folder_lookup(fname,&f,&ep) || *ep) { /* {inbox} is invalid - where to complain to? */ fprintf(stderr,"%s: warning: invalid {inbox}\n",__progname); fname = 0; } } if (! fname) { if (! folder_lookup("inbox",&f,0)) { fprintf(stderr,"%s: can't find a valid folder\n",__progname); exit(EX_CONFIG); } } nfolders = 1; folders = malloc(sizeof(FOLDER *)); *folders = f; } flags = malloc(nfolders*sizeof(*flags)); for (i=0;i time) tv.tv_sec --; tv.tv_usec = (time - tv.tv_sec) * 1000000; if (tv.tv_usec >= 1000000) { tv.tv_usec -= 1000000; tv.tv_sec ++; } select(0,0,0,0,&tv); } static double backoff_nap(int loops, unsigned int *vp) { int v; v = *vp; v = (v >> 1) ^ ((v & 1) ? 0xedb88320 : 0); *vp = v; return((.1*loops)+(1e-9*(int)(v&0x1fffffff))); } /* We have to be careful here to avoid danger of deadlock when two messages get delivered to the same folders in different orders. Essentially, the way we avoid deadlock is to never do a blocking folder_lock unless we're holding no other folder locks. We avoid livelock by varying the backoff nap time if we end up going around the loop too often. */ static void lock_all_folders(void) { int i; int lastfail; int loops; unsigned int backoff_val; backoff_val = getpid(); loops = 0; while (1) { lastfail = -1; for (i=0;i 30) { fprintf(stderr,"%s: apparent livelock locking folders\n",__progname); exit(EX_SOFTWARE); } if (loops > 3) nap(backoff_nap(loops,&backoff_val)); } } static void create_messages(void) { int i; int j; char buf[8192]; int nr; if (do_unseen) { const char *useq; useq = profile_lookup(system_get_profile(),"unseen-sequence"); if (useq) { int nus; const char **usv; ws_split(useq,&nus,&usv); for (i=0;i= i) { msgs[i] = folder_new_create(folders[i]); if (! msgs[i]) { fprintf(stderr,"%s: can't create message in +%s: %s\n",__progname,folder_name(folders[i]),strerror(errno)); flags[i] |= F_CANTOPEN; nfail ++; } else { flags[i] |= F_DISTINCT; } } if (msgs[i]) { SEQS *ss; int j; ss = seqs_open(folders[i]); if (ss) { SEQ *cs; SEQ *ns; for (j=0;j 0) { ns = seq_lookup(ss,"next"); if (seq_get(ns,0,0,0) < 1) { seq_add(ns,message_number(msgs[i])); } } seqs_close(ss); } else { fprintf(stderr,"%s: can't open sequence database in +%s: %s\n",__progname,folder_name(folders[i]),strerror(errno)); } } } while (1) { nr = read(0,&buf[0],sizeof(buf)); if (nr <= 0) { if (nr < 0) fprintf(stderr,"%s: input read error: %s\n",__progname,strerror(errno)); break; } for (i=0;i