int Maildir::MaildirOpen(const char *dir, Mio &file, off_t s) { Buffer buf; 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; 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()) { Buffer name_buf; name_buf="UMASK"; const char *um=GetVarStr(name_buf); unsigned 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) { Buffer b; b="FLAGS"; const char *flags=GetVarStr(b); tmpname=createInfo.tmpname; tmpname += '\0'; if (flags) { const char *p=flags; while (*p) { if (strchr("DRSF", *p) == NULL) { f=0; break; } ++p; } } if (flags && *flags) { newname=createInfo.curname; newname += ':'; newname += '2'; newname += ','; newname += flags; } else { newname=createInfo.newname; } newname += '\0'; maildir_tmpcreate_free(&createInfo); file.fd(f); is_open=1; maildirRoot=dir; maildirRoot += '\0'; 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, quota_warn_message); merr << "maildrop: maildir over quota.\n"; return (-1); } maildir_quota_add_end("ainfo, s, 1); 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); }
static long deliver(int fdin, const char *dir, long s, int auto_create, int quota_warn_percent, const char *pfix, const char *newquota) { struct maildir_tmpcreate_info createInfo; char buf[BUFSIZ]; int n; long ss=0; int fd; maildir_tmpcreate_init(&createInfo); createInfo.maildir=dir; createInfo.uniq=pfix; createInfo.msgsize=s; createInfo.doordie=1; while ((fd=maildir_tmpcreate_fd(&createInfo)) < 0) { if (errno == ENOENT && auto_create && maildir_mkdir(dir) == 0) { auto_create=0; continue; } perror(dir); exit(EX_TEMPFAIL); } while ((n=read(fdin, buf, sizeof(buf))) > 0) { char *p=buf; ss += n; while (n) { int l; if ((l=write(fd, p, n)) < 0) { close(fd); unlink(createInfo.tmpname); perror(createInfo.tmpname); exit(EX_IOERR); } p += l; n -= l; } } close(fd); if (n < 0) { unlink(createInfo.tmpname); perror(createInfo.tmpname); exit(EX_IOERR); } if (s != ss) { char *qq; struct maildirsize info; if (s) *strrchr(createInfo.newname, ',')=0; /* Zap incorrect size */ qq=malloc(strlen(createInfo.newname)+100); if (!qq) { unlink(createInfo.tmpname); perror(createInfo.tmpname); exit(EX_OSERR); } sprintf(qq, "%s,S=%ld", createInfo.newname, ss-s); free(createInfo.newname); createInfo.newname=qq; if (maildirquota_countfolder(dir)) { if (maildir_quota_add_start(dir, &info, ss-s, 1, newquota)) { unlink(createInfo.tmpname); printf("Mail quota exceeded.\n"); exit(EX_NOPERM); } maildir_quota_add_end(&info, ss-s, 1); } } if (maildir_movetmpnew(createInfo.tmpname, createInfo.newname)) { unlink(createInfo.tmpname); perror(createInfo.tmpname); exit(EX_IOERR); } maildir_tmpcreate_free(&createInfo); if (quota_warn_percent >= 0) maildir_deliver_quota_warning(dir, quota_warn_percent); return (ss); }
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, quota_warn_message); } } }
int main(int argc, char **argv) { const char *dir; struct stat stat_buf; int auto_create = 0; int quota_warn_percent = -1; int i; const char *quota=NULL; for (i=1; i<argc; i++) { if (strcmp(argv[i], "-c") == 0) { auto_create = 1; continue; } if (strcmp(argv[i], "-w") == 0 && argc - i > 1) { quota_warn_percent = atoi(argv[i+1]); ++i; continue; } break; } if (i >= argc || quota_warn_percent < -1 || quota_warn_percent > 100) { fprintf(stderr, "Usage: %s [-c] [-w percent] maildir\n", argv[0]); exit(73); } dir=argv[i]; ++i; if (i < argc) quota=argv[i]; if (fstat(0, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) && stat_buf.st_size > 0) { struct maildirsize info; int doquota=maildirquota_countfolder(dir); if (doquota && maildir_quota_add_start(dir, &info, stat_buf.st_size, 1, quota)) { if (quota_warn_percent >= 0) maildir_deliver_quota_warning(dir, quota_warn_percent); printf("Mail quota exceeded.\n"); exit(77); } deliver(0, dir, stat_buf.st_size, auto_create, quota_warn_percent, NULL, quota); if (doquota) maildir_quota_add_end(&info, stat_buf.st_size, 1); exit(0); } deliver(0, dir, 0, auto_create, quota_warn_percent, NULL, quota); exit(0); }