/* ** Copyright 1998 - 2003 Double Precision, Inc. ** See COPYING for distribution information. */ #if HAVE_CONFIG_H #include "config.h" #endif #if HAVE_UNISTD_H #include #endif #include #include "imaptoken.h" #include "imapscanclient.h" #include "imapwrite.h" #include "storeinfo.h" #include "maildir/maildirquota.h" #include "maildir/maildirmisc.h" #include "maildir/maildircreate.h" #include "outbox.h" #include #include #include #include #include #include #if HAVE_UTIME_H #include #endif #if TIME_WITH_SYS_TIME #include #include #else #if HAVE_SYS_TIME_H #include #else #include #endif #endif static const char rcsid[]="$Id: storeinfo.c,v 1.15 2003/02/28 13:37:27 mrsam Exp $"; extern int is_trash(const char *); extern int get_flagname(const char *, struct imapflags *); extern int get_flags(struct imapflags *); extern void get_message_flags( struct imapscanmessageinfo *, char *, struct imapflags *); extern int reflag_filename(struct imapscanmessageinfo *, struct imapflags *, int); extern void fetchflags(unsigned long); extern void fetchflags_byuid(unsigned long); extern FILE *maildir_mkfilename(const char *, struct imapflags *, unsigned long, char **, char **); extern struct imapscaninfo current_mailbox_info; extern char *current_mailbox; int storeinfo_init(struct storeinfo *si) { struct imaptoken *t=currenttoken(); const char *p; if (t->tokentype != IT_ATOM) return (-1); si->plusminus=0; si->silent=0; p=t->tokenbuf; if (*p == '+' || *p == '-') si->plusminus= *p++; if (strncmp(p, "FLAGS", 5)) return (-1); p += 5; if (*p) { if (strcmp(p, ".SILENT")) return (-1); si->silent=1; } memset(&si->flags, 0, sizeof(si->flags)); t=nexttoken(); if (t->tokentype == IT_LPAREN) { if (get_flags(&si->flags)) return (-1); nexttoken(); } else if (t->tokentype == IT_NIL) nexttoken(); else if (t->tokentype == IT_ATOM) { get_flagname(t->tokenbuf, &si->flags); nexttoken(); } return (0); } int do_store(unsigned long n, int byuid, void *voidptr) { struct storeinfo *si=(struct storeinfo *)voidptr; int fd; struct imapflags new_flags; --n; fd=imapscan_openfile(current_mailbox, ¤t_mailbox_info, n); if (fd < 0) return (0); get_message_flags(current_mailbox_info.msgs+n, 0, &new_flags); if (si->plusminus == '+') { if (si->flags.drafts) new_flags.drafts=1; if (si->flags.seen) new_flags.seen=1; if (si->flags.answered) new_flags.answered=1; if (si->flags.deleted) new_flags.deleted=1; if (si->flags.flagged) new_flags.flagged=1; } else if (si->plusminus == '-') { if (si->flags.drafts) new_flags.drafts=0; if (si->flags.seen) new_flags.seen=0; if (si->flags.answered) new_flags.answered=0; if (si->flags.deleted) new_flags.deleted=0; if (si->flags.flagged) new_flags.flagged=0; } else new_flags=si->flags; if (reflag_filename(current_mailbox_info.msgs+n, &new_flags, fd)) { close(fd); return (-1); } close(fd); if (si->silent) current_mailbox_info.msgs[n].changedflags=0; else if (byuid) fetchflags_byuid(n); else fetchflags(n); return (0); } static int copy_message(int fd, struct do_copy_info *cpy_info, struct imapflags *flags, unsigned long old_uid) { char *tmpname; char *newname; FILE *fp; struct stat stat_buf; char buf[BUFSIZ]; struct uidplus_info *new_uidplus_info; //DAVE: just a few variable declarations char *extprogram; char *envvar; char *syscall; char *mailboxclean; int ret; int idx; //EVAD if (fstat(fd, &stat_buf) < 0 || (new_uidplus_info=(struct uidplus_info *) malloc(sizeof(struct uidplus_info))) == NULL) { return (-1); } memset(new_uidplus_info, 0, sizeof(*new_uidplus_info)); fp=maildir_mkfilename(cpy_info->mailbox, flags, stat_buf.st_size, &tmpname, &newname); if (!fp) { free(new_uidplus_info); return (-1); } while (stat_buf.st_size) { int n=sizeof(buf); if (n > stat_buf.st_size) n=stat_buf.st_size; n=read(fd, buf, n); if (n <= 0 || fwrite(buf, 1, n, fp) != n) { fprintf(stderr, "ERR: error copying a message, user=%s, errno=%d\n", getenv("AUTHENTICATED"), errno); fclose(fp); unlink(tmpname); free(tmpname); free(newname); free(new_uidplus_info); return (-1); } stat_buf.st_size -= n; } if (fflush(fp) || ferror(fp)) { fclose(fp); free(tmpname); free(newname); free(new_uidplus_info); return (-1); } fclose(fp); #if HAVE_UTIME { struct utimbuf ub; ub.actime=ub.modtime=stat_buf.st_mtime; utime(tmpname, &ub); } #else #if HAVE_UTIMES { struct timeval tv; tv.tv_sec=stat_buf.st_mtime; tv.tv_usec=0; utimes(tmpname, &tv); } #endif #endif if (check_outbox(tmpname, cpy_info->mailbox)) { unlink(tmpname); free(tmpname); free(newname); free(new_uidplus_info); return (-1); } new_uidplus_info->tmpfilename=tmpname; new_uidplus_info->curfilename=newname; new_uidplus_info->next=NULL; new_uidplus_info->old_uid=old_uid; *cpy_info->uidplus_tail=new_uidplus_info; cpy_info->uidplus_tail=&new_uidplus_info->next; //DAVE: call an external program depending on the target mailbox envvar=(char *)malloc(1024); syscall=(char *)malloc(1024); mailboxclean=(char *)malloc(1024); // if length of the mailbox string is 1, it is "." == INBOX if( strlen(cpy_info->mailbox) == 1 ) { extprogram=getenv("ON_COPY_TO_INBOX"); strcpy(envvar, "ON_COPY_TO_INBOX"); } else { //we want to get the environment variable //matching the target mailbox. strcpy(envvar, "ON_COPY_TO_BOX_"); strncpy(mailboxclean, (char *)(cpy_info->mailbox+1), 1000); //we need to convert all special chars to underscores, //since an environment variable can only handle these for( idx = 0; (mailboxclean[idx] != 0) && (idx<1000); idx++ ) { if( ((mailboxclean[idx] < 'A') || (mailboxclean[idx] > 'Z')) && ((mailboxclean[idx] < 'a') || (mailboxclean[idx] > 'z')) ) { mailboxclean[idx] = '_'; } } //now get the env. var. strncat(envvar, mailboxclean, 1000); extprogram=getenv(envvar); } //if env. var. not specified, get the fallback var. if( extprogram == NULL ) { extprogram=getenv("ON_COPY_TO_NOT_LISTED"); strcpy(envvar, "ON_COPY_TO_NOT_LISTED"); } //run the program in the env. var., but replace the %s //with the filename first. if( (extprogram != NULL) && (strlen(extprogram) > 0) ) { snprintf(syscall, 1000, extprogram, tmpname); fprintf(stderr, "INFO: option: %s, calling %s\n", envvar, syscall); ret=system(syscall); //we want a syslog if there were errors. if( ret != 0 ) { fprintf(stderr, "INFO: calling %s returned error code %d\n", syscall, ret); } } free(syscall); free(mailboxclean); free(envvar); //EVAD return (0); } int do_copy(unsigned long n, int byuid, void *voidptr) { struct do_copy_info *cpy_info=(struct do_copy_info *)voidptr; int fd; struct imapflags new_flags; --n; fd=imapscan_openfile(current_mailbox, ¤t_mailbox_info, n); if (fd < 0) return (0); get_message_flags(current_mailbox_info.msgs+n, 0, &new_flags); if (copy_message(fd, cpy_info, &new_flags, current_mailbox_info.msgs[n].uid)) { close(fd); return (-1); } close(fd); return (0); } int do_copy_quota_calc(unsigned long n, int byuid, void *voidptr) { struct copyquotainfo *info=(struct copyquotainfo *)voidptr; const char *filename; unsigned long nbytes; struct stat stat_buf; int fd; --n; fd=imapscan_openfile(current_mailbox, ¤t_mailbox_info, n); if (fd < 0) return (0); filename=current_mailbox_info.msgs[n].filename; if (maildirquota_countfile(filename)) { if (maildir_parsequota(filename, &nbytes)) { if (fstat(fd, &stat_buf) < 0) { close(fd); return (0); } nbytes=stat_buf.st_size; } info->nbytes += nbytes; info->nfiles += 1; } close(fd); return (0); }