static int update_link(const char *curdir, const char *linkname, const char *linkvalue, const char *shareddir, const char *msgfilename, size_t msgfilenamelen) { char *p=malloc(strlen(shareddir)+sizeof("/cur/")+msgfilenamelen); char *q; int fd; struct maildir_tmpcreate_info createInfo; if (!p) { perror("malloc"); return (-1); } strcat(strcpy(p, shareddir), "/cur/"); q=p+strlen(p); memcpy(q, msgfilename, msgfilenamelen); q[msgfilenamelen]=0; if (linkvalue && strcmp(p, linkvalue) == 0) { /* the link is good */ free(p); return (0); } /* Ok, we want this to be an atomic operation. */ maildir_tmpcreate_init(&createInfo); createInfo.maildir=curdir; createInfo.uniq="relink"; createInfo.doordie=1; if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0) return -1; close(fd); unlink(createInfo.tmpname); if (symlink(p, createInfo.tmpname) < 0 || rename(createInfo.tmpname, linkname) < 0) { perror(createInfo.tmpname); maildir_tmpcreate_free(&createInfo); return (-1); } maildir_tmpcreate_free(&createInfo); return (0); }
static int savepop3dlist(struct msglist **a, size_t cnt, unsigned long uid) { FILE *fp; size_t i; struct maildir_tmpcreate_info createInfo; maildir_tmpcreate_init(&createInfo); createInfo.uniq="pop3"; createInfo.doordie=1; if ((fp=maildir_tmpcreate_fp(&createInfo)) == NULL) { maildir_tmpcreate_free(&createInfo); return -1; } fprintf(fp, "/2 %lu %lu\n", uid, uidv); for (i=0; i<cnt; i++) { char *p=a[i]->filename; char *q; if ((q=strrchr(p, '/')) != NULL) p=q+1; fprintf(fp, "%s %lu %lu:%lu\n", p, (unsigned long)a[i]->size, a[i]->uid.n, a[i]->uid.uidv); } if (fflush(fp) || ferror(fp)) { fclose(fp); unlink(createInfo.tmpname); maildir_tmpcreate_free(&createInfo); return -1; } if (fclose(fp) || rename(createInfo.tmpname, POP3DLIST) < 0) { unlink(createInfo.tmpname); maildir_tmpcreate_free(&createInfo); return -1; } maildir_tmpcreate_free(&createInfo); return 0; }
int maildir_filter_savemaildirfilter(struct maildirfilter *mf, const char *maildir, const char *from) { // by lfan, to support .qmail-user forward file char *p, *p2, *user; char *maildirpath; //const char *maildirpath=maildir_filter_config(maildir, "MAILDIR"); struct maildir_tmpcreate_info createInfo; int fd, rc; p=login_returnaddr(); p2=strdup(p); user=strtok(p2, "@"); p = malloc(strlen(user) + 12); sprintf( p, "./%s/Maildir", user ); free(p2); maildirpath=p; if (!maildirpath || !*maildirpath) { errno=EINVAL; return (-1); } maildir_tmpcreate_init(&createInfo); createInfo.maildir=maildir; createInfo.uniq="maildirfilter-tmp"; createInfo.doordie=1; if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0) return -1; close(fd); unlink(createInfo.tmpname); strcat(strcpy(createInfo.newname, maildir), "/maildirfilter.tmp"); rc=maildir_filter_saverules(mf, createInfo.tmpname, maildir, maildirpath, from); if (rc == 0 && rename(createInfo.tmpname, createInfo.newname)) rc= -1; maildir_tmpcreate_free(&createInfo); free(p); return (rc); }
void write_sqconfig(const char *dir, const char *configfile, const char *val) { char *p=malloc(strlen(dir) + strlen(configfile) + 2); struct maildir_tmpcreate_info createInfo; FILE *fp; if (!p) enomem(); strcat(strcat(strcpy(p, dir), "/"), configfile); if (!val) { unlink(p); free(p); return; } maildir_tmpcreate_init(&createInfo); createInfo.maildir=dir; createInfo.uniq="config"; createInfo.doordie=1; fp=maildir_tmpcreate_fp(&createInfo); if (!fp) enomem(); free(createInfo.newname); createInfo.newname=p; fprintf(fp, "%s\n", val); fflush(fp); if (ferror(fp)) eio("Error after write:",p); fclose(fp); /* Note - umask should already turn off the 077 bits, but ** just in case someone screwed up previously, I'll fix it ** myself */ chmod(createInfo.tmpname, 0600); rename(createInfo.tmpname, createInfo.newname); maildir_tmpcreate_free(&createInfo); }
static int create_db(struct dbobj *obj, const char *dir, char **dbname) { struct maildir_tmpcreate_info createInfo; maildir_tmpcreate_init(&createInfo); createInfo.maildir=dir; createInfo.uniq="sync"; createInfo.doordie=1; { int fd; fd=maildir_tmpcreate_fd(&createInfo); if (fd < 0) { perror(dir); return -1; } close(fd); dbobj_init(obj); if (dbobj_open(obj, createInfo.tmpname, "N") < 0) { perror(createInfo.tmpname); unlink(createInfo.tmpname); maildir_tmpcreate_free(&createInfo); return (-1); } } *dbname=createInfo.tmpname; createInfo.tmpname=NULL; maildir_tmpcreate_free(&createInfo); return (0); }
static int savemessage(const char *extension, const char *sender, const char *receipient, FILE *f, const char *name, const char *ufromline, const char *dtline, const char *rpline, const char *quota) { FILE *delivf; char buf[BUFSIZ]; int c; static unsigned counter=0; struct stat stat_buf; struct maildirsize quotainfo; struct maildir_tmpcreate_info createInfo; umask(077); if ((delivf=fopen(name, "a")) != 0) { /* Ok, perhaps this is a mailbox */ struct ll_mail *ll=ll_mail_alloc(name); fclose(delivf); if (!ll) { delivery_error(name); /* I Give up */ } while ((mbox_fd=ll_mail_open(ll)) < 0) { switch (errno) { case EEXIST: case EAGAIN: sleep(5); continue; break; } delivery_error(name); } delivf=fdopen(mbox_fd, "w"); if (delivf == NULL || fseek(delivf, 0L, SEEK_END) < 0 || (mbox_size=ftell(delivf)) == (off_t)-1) { if (delivf) fclose(delivf); close(mbox_fd); ll_mail_free(ll); delivery_error(name); /* I Give up */ } signal(SIGHUP, truncmbox); signal(SIGINT, truncmbox); signal(SIGQUIT, truncmbox); signal(SIGTERM, truncmbox); fprintf(delivf, "%s\n%s\n%s\n", ufromline, dtline, rpline); while (fgets(buf, sizeof(buf), f) != 0) { char *q=buf; while (*q == '>') q++; if (strncmp(q, "From ", 5) == 0) putc('>', delivf); fprintf(delivf, "%s", buf); if (strchr(buf, '\n') == 0) { while ((c=getc(f)) >= 0) { putc(c, delivf); if (c == '\n') break; } } } if ( ferror(f) || fflush(delivf) || ferror(delivf) #if EXPLICITSYNC || fsync(fileno(delivf)) #endif || (signal(SIGHUP, SIG_DFL), signal(SIGINT, SIG_DFL), signal(SIGQUIT, SIG_DFL), signal(SIGTERM, SIG_DFL), fclose(delivf)) ) { #if HAVE_FTRUNCATE if (ftruncate(mbox_fd, mbox_size) < 0) ; /* ignore */ #endif close(mbox_fd); ll_mail_free(ll); delivery_error("mailbox.close"); } close(mbox_fd); ll_mail_free(ll); return (0); } if (fstat(fileno(f), &stat_buf)) { delivery_error("stat"); return (-1); } stat_buf.st_size += strlen(dtline) + strlen(rpline) + 2; if (maildir_quota_add_start(name, "ainfo, stat_buf.st_size, 1, quota && *quota != 0 ? quota:NULL)) { errno=ENOSPC; delivery_error("out of memory."); } maildir_closequotafile("ainfo); /* For now. */ sprintf(buf, "%u", ++counter); maildir_tmpcreate_init(&createInfo); createInfo.maildir=name; createInfo.uniq=buf; createInfo.msgsize=stat_buf.st_size; createInfo.doordie=1; if ((delivf=maildir_tmpcreate_fp(&createInfo)) == NULL) { snprintf(buf, BUFSIZ-1, "maildir.open: %s: %s", name, strerror(errno)); buf[BUFSIZ-1] = 0; delivery_error(buf); return (-1); } fprintf(delivf, "%s\n%s\n", dtline, rpline); { char buffer[BUFSIZ]; int n; while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) if (fwrite(buffer, 1, n, delivf) != n) break; } if ( ferror(f) || fflush(delivf) || ferror(delivf) #if EXPLICITSYNC || fsync(fileno(delivf)) #endif || fclose(delivf) || (delivf=0, maildir_movetmpnew(createInfo.tmpname, createInfo.newname))) { snprintf(buf, BUFSIZ-1, "maildir.close: %s: %s", name, strerror(errno)); buf[BUFSIZ-1] = 0; if (delivf) fclose(delivf); unlink(createInfo.newname); delivery_error(buf); return (-1); } #if EXPLICITDIRSYNC { int fd; strcpy(strrchr(createInfo.newname, '/')+1, "."); fd=open(createInfo.newname, O_RDONLY); if (fd >= 0) { fsync(fd); close(fd); } } #endif maildir_tmpcreate_free(&createInfo); maildir_quota_deleted(name, stat_buf.st_size, 1); return (0); }
int maildir_filter_importmaildirfilter(const char *maildir) { const char *p=maildir_filter_config(maildir, "MAILDIRFILTER"); char *maildirfilter; FILE *i, *o; struct maildir_tmpcreate_info createInfo; if (!p) return (-1); if (!*p) { errno=ENOENT; return (-1); } maildirfilter=maildir_filter_config_maildirfilter(maildir); if (!maildirfilter) return (-1); maildir_tmpcreate_init(&createInfo); createInfo.maildir=maildir; createInfo.uniq="maildirfilter-tmp"; createInfo.doordie=1; if ((o=maildir_tmpcreate_fp(&createInfo)) == NULL) { free(maildirfilter); return (-1); } strcat(strcpy(createInfo.newname, maildir), "/maildirfilter.tmp"); /* We enough we have enough mem: .uniq */ if ((i=fopen(maildirfilter, "r")) == 0) { struct maildirfilter mf; if (errno != ENOENT) { fclose(o); unlink(createInfo.tmpname); maildir_tmpcreate_free(&createInfo); free(maildirfilter); return (-1); } memset(&mf, 0, sizeof(mf)); fclose(o); unlink(createInfo.tmpname); unlink(createInfo.newname); maildir_filter_savemaildirfilter(&mf, maildir, ""); /* write out a blank one */ } else { char buf[BUFSIZ]; int n; while ((n=fread(buf, 1, sizeof(buf), i)) > 0) if (fwrite(buf, 1, n, o) != n) { fclose(o); fclose(i); unlink(createInfo.tmpname); maildir_tmpcreate_free(&createInfo); free(maildirfilter); return (-1); } if (fflush(o)) { fclose(o); fclose(i); unlink(createInfo.tmpname); maildir_tmpcreate_free(&createInfo); free(maildirfilter); return (-1); } fclose(o); fclose(i); if (chmod(createInfo.tmpname, 0600) || rename(createInfo.tmpname, createInfo.newname)) { unlink(createInfo.tmpname); maildir_tmpcreate_free(&createInfo); free(maildirfilter); return (-1); } } maildir_tmpcreate_free(&createInfo); free(maildirfilter); return (0); }
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 int newmsgs(const char *cur, const char *shared, struct dbobj *obj) { char *key, *val; size_t keylen, vallen; int fd; struct maildir_tmpcreate_info createInfo; maildir_tmpcreate_init(&createInfo); createInfo.maildir=cur; createInfo.uniq="newlink"; createInfo.doordie=1; if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0) return -1; close(fd); unlink(createInfo.tmpname); for (key=dbobj_firstkey(obj, &keylen, &val, &vallen); key; key=dbobj_nextkey(obj, &keylen, &val, &vallen)) { char *slink=malloc(strlen(shared)+sizeof("/cur/")+vallen); char *q; if (!slink) { free(val); maildir_tmpcreate_free(&createInfo); return (-1); } strcat(strcpy(slink, shared), "/cur/"); q=slink+strlen(slink); memcpy(q, val, vallen); q[vallen]=0; free(val); if (symlink(slink, createInfo.tmpname)) { perror(createInfo.tmpname); free(slink); maildir_tmpcreate_free(&createInfo); return (-1); } free(slink); slink=malloc(strlen(cur)+sizeof("/new/" MDIRSEP "2,")+keylen); if (!slink) { perror("malloc"); maildir_tmpcreate_free(&createInfo); return (-1); } strcat(strcpy(slink, cur), "/new/"); q=slink+strlen(slink); memcpy(q, key, keylen); strcpy(q+keylen, MDIRSEP "2,"); if (rename(createInfo.tmpname, slink)) { free(slink); maildir_tmpcreate_free(&createInfo); return (-1); } free(slink); } maildir_tmpcreate_free(&createInfo); return (0); }
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); }