/* ** Copyright 1998 - 2003 Double Precision, Inc. ** See COPYING for distribution information. */ /* ** Modified by Robin Whittle rw@firstpr.com.au ** 2008-04-29 based on similar mods in 2003-05-29 ** to create the new file name with ** ":2,T" on the ** end to indicate that it is tagged for deletion at ** the next IMAP expunge operation - but only if the ** actions of .mailfilter, according to the nature ** of the message, have set the DELTAG variable to "1" ** ** The purpose of this is to allow the filter file ** to set this variable for SPAM, or for a message ** which has been copied to a mailing list mailbox ** and which we want to see it in the Inbox, but ** which we want tagged for deletion. This way ** we can see all activity on various mailing lists ** without having to look in their mailboxes, ** and can easily delete them all from our Inbox ** when we don't want to see them any more. ** ** This replicates the "Move to folder" function ** of Netscape's mail filtering system. ** ** ** Here, we test the DELTAG variable and set a ** global variable deltagflag accordingly. ** Then the standard code calls maildir_tmpcreate_fd() ** in /maildir/maildircreate.c . (Watch out for two ** functions of similar name, one ending in 'b' and ** the other in 'd'.) ** ** We test DELTAG here because code in this ** directory can use the varlist.c/h while I can't ** easily see a way of doing it in code in /maildir/ . ** ** It is in /maildir/maildircreate.c. that the ** additional ":2,T" characters may be added. ** ** We communicate whether DELTAG == 1 with a ** global variable kludgey global variable: ** "deltagflag". This is declared in ** /maildir/maildircreateh.c, as an int and ** initialised to 0. ** ** Only one area is changed, as marked "RW". */ extern int deltagflag; #include "config.h" #include "maildir.h" #include "mio.h" #include "alarmtimer.h" #include "alarmsleep.h" #include "config.h" #include "xconfig.h" #include "funcs.h" #include "varlist.h" #if HAVE_SYS_STAT_H #include #endif #include #include #include "mytime.h" #if HAVE_UNISTD_H #include #endif #include "../maildir/maildirquota.h" #include "../maildir/maildircreate.h" #include "../maildir/maildirmisc.h" #include "../maildir/maildirkeywords.h" static const char rcsid[]="$Id: maildir.C,v 1.19 2004/01/15 03:12:13 mrsam Exp $"; #include "../maildir/maildirquota.h" extern int quota_warn_percent; Maildir::Maildir() : is_open(0) , is_afs(0) { } Maildir::~Maildir() { MaildirAbort(); } //////////////////////////////////////////////////////////////////////////// // // Attempt to detect if this is a Maildir directory. // //////////////////////////////////////////////////////////////////////////// int Maildir::IsMaildir(const char *name) { Buffer dirname; Buffer subdirname; struct stat stat_buf; int c; if (!name || !*name) return (0); // Nope, not a Maildir dirname=name; c=dirname.pop(); if (c != SLASH_CHAR) dirname.push(c); // Strip trailing / subdirname=dirname; subdirname += "/tmp"; subdirname += '\0'; if ( stat( (const char *)subdirname, &stat_buf ) || ! S_ISDIR(stat_buf.st_mode) ) return (0); subdirname=dirname; subdirname += "/new"; subdirname += '\0'; if ( stat( (const char *)subdirname, &stat_buf ) || ! S_ISDIR(stat_buf.st_mode) ) return (0); subdirname=dirname; subdirname += "/cur"; subdirname += '\0'; if ( stat( (const char *)subdirname, &stat_buf ) || ! S_ISDIR(stat_buf.st_mode) ) return (0); return (1); // If it looks like a duck, walks like a duck... } int Maildir::MaildirOpen(const char *dir, Mio &file, off_t s) { Buffer buf; #if MAILDIRQUOTA struct maildirsize quotainfo; const char *quotap; Buffer quotabuf; quotabuf="MAILDIRQUOTA"; /* Reuse a convenient buffer */ quotabuf= *GetVar(quotabuf); quotabuf += '\0'; quotap=quotabuf; if (!*quotap) quotap=NULL; #endif MaildirAbort(); AlarmTimer abort_timer; static long counter=0; buf.set(counter++); buf += '\0'; struct maildir_tmpcreate_info createInfo; maildir_tmpcreate_init(&createInfo); createInfo.maildir=dir; createInfo.uniq=(const char *)buf; createInfo.msgsize=s; createInfo.openmode=0666; abort_timer.Set( 24 * 60 * 60 ); while (!abort_timer.Expired()) { /* RW * Set deltagflag according to * the state of variable DELTAG. */ Buffer dtstring; dtstring = "DELTAG"; deltagflag = 0; if (strcmp (GetVarStr(dtstring), "1") == 0 ) { deltagflag = 1; } Buffer name_buf; name_buf="UMASK"; const char *um=GetVarStr(name_buf); int umask_val=077; sscanf(um, "%o", &umask_val); umask_val=umask(umask_val); int f=maildir_tmpcreate_fd(&createInfo); umask(umask_val); if (f >= 0) { tmpname=createInfo.tmpname; newname=createInfo.newname; tmpname += '\0'; newname += '\0'; maildir_tmpcreate_free(&createInfo); file.fd(f); is_open=1; maildirRoot=dir; maildirRoot += '\0'; #if MAILDIRQUOTA if (maildir_quota_add_start(dir, "ainfo, s, 1, quotap)) { file.fd(-1); unlink( (const char *)tmpname ); is_open=0; maildir_deliver_quota_warning(dir, quota_warn_percent); merr << "maildrop: maildir over quota.\n"; return (-1); } maildir_quota_add_end("ainfo, s, 1); #endif return (0); } if (errno != EAGAIN) { merr << "maildrop: " << dir << ": " << strerror(errno) << "\n"; return -1; } AlarmSleep try_again(2); } merr << "maildrop: time out on maildir directory.\n"; return (-1); } void Maildir::MaildirSave() { if (is_open) { Buffer keywords; keywords="KEYWORDS"; keywords=*GetVar(keywords); keywords += '\0'; const char *keywords_s=keywords; while (*keywords_s && *keywords_s == ',') ++keywords_s; if (*keywords_s) { struct libmail_kwHashtable kwh; struct libmail_kwMessage *kwm; libmail_kwhInit(&kwh); if ((kwm=libmail_kwmCreate()) == NULL) throw strerror(errno); while (*keywords_s) { const char *p=keywords_s; while (*keywords_s && *keywords_s != ',') ++keywords_s; char *n=new char [keywords_s - p + 1]; if (!n) { libmail_kwmDestroy(kwm); throw strerror(errno); } memcpy(n, p, keywords_s - p); n[keywords_s - p]=0; while (*keywords_s && *keywords_s == ',') ++keywords_s; if (libmail_kwmSetName(&kwh, kwm, n) < 0) { delete n; libmail_kwmDestroy(kwm); throw strerror(errno); } delete n; } char *tmpkname, *newkname; if (maildir_kwSave( (const char *)maildirRoot, strrchr(newname, '/')+1, kwm, &tmpkname, &newkname, 0) < 0) { libmail_kwmDestroy(kwm); throw "maildir_kwSave() failed."; } libmail_kwmDestroy(kwm); if (rename(tmpkname, newkname) < 0) { /* Maybe the keyword directory needs creating */ struct stat stat_buf; if (stat(maildirRoot, &stat_buf) < 0) { free(tmpkname); free(newkname); throw strerror(errno); } char *keywordDir=strrchr(newkname, '/'); *keywordDir=0; mkdir(newkname, 0700); chmod(newkname, stat_buf.st_mode & 0777); *keywordDir='/'; if (rename(tmpkname, newkname) < 0) { free(tmpkname); free(newkname); throw strerror(errno); } } free(tmpkname); free(newkname); } Buffer dir; if (link( (const char *)tmpname, (const char *)newname) < 0) { if (errno == EXDEV){ if(rename((const char *)tmpname, (const char *)newname) < 0) throw "rename() failed."; is_afs = 1; } else { throw "link() failed."; } } dir=newname; const char *p=dir; const char *q=strrchr(p, '/'); if (q) { dir.Length(q-p); dir.push((char)0); #if EXPLICITDIRSYNC int syncfd=open(dir, O_RDONLY); if (syncfd >= 0) { fsync(syncfd); close(syncfd); } #endif dir.Length(q-p); dir += "/../"; dir.push((char)0); maildir_deliver_quota_warning(dir, quota_warn_percent); } } } void Maildir::MaildirAbort() { if (is_open && !is_afs) unlink( (const char *)tmpname ); }