/* ** Copyright 1998 - 2003 Double Precision, Inc. ** See COPYING for distribution information. */ /* ** Modified by Robin Whittle rw@firstpr.com.au ** 2008-04-29 based on mods on 2008-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 ** DELTAG variable is set to "1". ** ** See the other modified file: /maildrop/maildir.C ** for a full explanation. ** ** Mods are clearly commented and marked "RW". ** ** http://www.firstpr.com.au/web-mail/ */ /* RW * * A kludgey global variable to * communicate the results of the * test we do in maildir.C * to here. */ int deltagflag = 0; #include "maildircreate.h" #include "maildirmisc.h" #include #if HAVE_SYS_STAT_H #include #endif #if TIME_WITH_SYS_TIME #include #include #else #if HAVE_SYS_TIME_H #include #else #include #endif #endif #if HAVE_SYS_STAT_H #include #endif #if HAVE_UNISTD_H #include #endif #include #include #include #include #include #include "numlib/numlib.h" static const char rcsid[]="$Id: maildircreate.c,v 1.6 2003/01/26 04:07:03 mrsam Exp $"; FILE *maildir_tmpcreate_fp(struct maildir_tmpcreate_info *info) { int fd=maildir_tmpcreate_fd(info); FILE *fp; if (fd < 0) return NULL; fp=fdopen(fd, "w+"); if (fp == NULL) { close(fd); return NULL; } return fp; } static int maildir_tmpcreate_fd_do(struct maildir_tmpcreate_info *info); #define KEEPTRYING (60 * 60) #define SLEEPFOR 3 int maildir_tmpcreate_fd(struct maildir_tmpcreate_info *info) { int i; if (!info->doordie) return (maildir_tmpcreate_fd_do(info)); for (i=0; i= 0 || errno != EAGAIN) return fd; sleep(SLEEPFOR); } return -1; } static int maildir_tmpcreate_fd_do(struct maildir_tmpcreate_info *info) { const char *maildir=info->maildir; const char *uniq=info->uniq; const char *hostname=info->hostname; /* RW * * Make this 4 longer because * we may be making the file * name 4 chars longer. */ char hostname_buf[256 + 4]; /* char hostname_buf[256]; */ char time_buf[NUMBUFSIZE]; char usec_buf[NUMBUFSIZE]; char pid_buf[NUMBUFSIZE]; char len_buf[NUMBUFSIZE+3]; char dev_buf[NUMBUFSIZE]; char ino_buf[NUMBUFSIZE]; struct timeval tv; struct stat stat_buf; int fd; if (!maildir) maildir="."; if (!uniq) uniq=""; if (!hostname || !*hostname) { hostname_buf[sizeof(hostname_buf)-1]=0; if (gethostname(hostname_buf, sizeof(hostname_buf)-1) < 0) strcpy(hostname_buf, "localhost"); hostname=hostname_buf; } gettimeofday(&tv, NULL); libmail_str_time_t(tv.tv_sec, time_buf); libmail_str_time_t(tv.tv_usec, usec_buf); libmail_str_pid_t(getpid(), pid_buf); len_buf[0]=0; if (info->msgsize > 0) { strcpy(len_buf, ",S="); libmail_str_size_t(info->msgsize, len_buf+3); } if (info->tmpname) free(info->tmpname); info->tmpname=malloc(strlen(maildir)+strlen(uniq)+ strlen(hostname)+strlen(time_buf)+ strlen(usec_buf)+ strlen(pid_buf)+strlen(len_buf)+100); if (!info->tmpname) { maildir_tmpcreate_free(info); return -1; } strcpy(info->tmpname, maildir); strcat(info->tmpname, "/tmp/"); strcat(info->tmpname, time_buf); strcat(info->tmpname, ".M"); strcat(info->tmpname, usec_buf); strcat(info->tmpname, "P"); strcat(info->tmpname, pid_buf); if (*uniq) strcat(strcat(info->tmpname, "_"), uniq); strcat(info->tmpname, "."); strcat(info->tmpname, hostname); strcat(info->tmpname, len_buf); /* RW * * I am not sure what this tmpname * vs. newname stuff is, but we * do the same mods here and * below for newname. * * Check the value of deltagflag * and if it is 1 then append: * * :2,T * * to the file name. */ if (deltagflag == 1) { strcat(info->tmpname, ":2,T"); } if (stat( info->tmpname, &stat_buf) == 0) { maildir_tmpcreate_free(info); errno=EAGAIN; return -1; } if (errno != ENOENT) { maildir_tmpcreate_free(info); if (errno == EAGAIN) errno=EIO; return -1; } if ((fd=maildir_safeopen_stat(info->tmpname, O_CREAT|O_RDWR|O_TRUNC, info->openmode, &stat_buf)) < 0) { maildir_tmpcreate_free(info); return -1; } libmail_strh_dev_t(stat_buf.st_dev, dev_buf); libmail_strh_ino_t(stat_buf.st_ino, ino_buf); if (info->newname) free(info->newname); info->newname=malloc(strlen(info->tmpname)+strlen(ino_buf)+ strlen(dev_buf)+3); if (!info->newname) { maildir_tmpcreate_free(info); unlink(info->tmpname); close(fd); if (errno == EAGAIN) errno=EIO; return -1; } strcpy(info->newname, maildir); strcat(info->newname, "/new/"); strcat(info->newname, time_buf); strcat(info->newname, ".M"); strcat(info->newname, usec_buf); strcat(info->newname, "P"); strcat(info->newname, pid_buf); strcat(info->newname, "V"); strcat(info->newname, dev_buf); strcat(info->newname, "I"); strcat(info->newname, ino_buf); if (*uniq) strcat(strcat(info->newname, "_"), uniq); strcat(info->newname, "."); strcat(info->newname, hostname); strcat(info->newname, len_buf); /* RW * * I am not sure what this tmpname * vs. newname stuff is, but we * do the same mods here and * above for tmpname. * * Check the value of deltagflag * and if it is 1 then append: * * :2,T * * to the file name. * * The code above allocates space for * info->newname on the basis of the * length of info->tmpname, which * we already made potentially longer. */ if (deltagflag == 1) { strcat(info->newname, ":2,T"); } return fd; } void maildir_tmpcreate_free(struct maildir_tmpcreate_info *info) { if (info->tmpname) free(info->tmpname); info->tmpname=NULL; if (info->newname) free(info->newname); info->newname=NULL; } int maildir_movetmpnew(const char *tmpname, const char *newname) { if (link(tmpname, newname) == 0) { unlink(tmpname); return 0; } if (errno != EXDEV) return -1; /* AFS? */ return rename(tmpname, newname); }