diff options
Diffstat (limited to 'imap/storeinfo.c')
| -rw-r--r-- | imap/storeinfo.c | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/imap/storeinfo.c b/imap/storeinfo.c new file mode 100644 index 0000000..de885e9 --- /dev/null +++ b/imap/storeinfo.c @@ -0,0 +1,495 @@ +/* +** Copyright 1998 - 2003 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <errno.h> +#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 "maildir/maildiraclt.h" +#include "outbox.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/stat.h> +#if HAVE_UTIME_H +#include <utime.h> +#endif +#if TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#endif +#endif + + +#if SMAP +extern int smapflag; +#endif + +extern char *get_reflagged_filename(const char *fn, struct imapflags *newfl); +extern int is_trash(const char *); +extern int get_flagname(const char *, struct imapflags *); +extern int get_flagsAndKeywords(struct imapflags *flags, + struct libmail_kwMessage **kwPtr); +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 int acl_flags_adjust(const char *access_rights, + struct imapflags *flags); + +extern struct imapscaninfo current_maildir_info; +extern char *current_mailbox; +extern char *current_mailbox_acl; +extern int fastkeywords(); + +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)); + + if ((si->keywords=libmail_kwmCreate()) == NULL) + write_error_exit(0); + + t=nexttoken_noparseliteral(); + if (t->tokentype == IT_LPAREN) + { + if (get_flagsAndKeywords(&si->flags, &si->keywords)) + { + libmail_kwmDestroy(si->keywords); + si->keywords=NULL; + return (-1); + } + nexttoken(); + } + else if (t->tokentype == IT_NIL) + nexttoken(); + else if (t->tokentype == IT_ATOM) + { + if (get_flagname(t->tokenbuf, &si->flags)) + libmail_kwmSetName(current_maildir_info + .keywordList, + si->keywords, + t->tokenbuf); + 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, old_flags; +int changedKeywords; +struct libmail_kwMessageEntry *kme; +int kwAllowed=1; + + --n; + fd=imapscan_openfile(current_mailbox, ¤t_maildir_info, n); + if (fd < 0) return (0); + + changedKeywords=0; + get_message_flags(current_maildir_info.msgs+n, 0, &new_flags); + + old_flags=new_flags; + + if (current_mailbox_acl) + { + if (strchr(current_mailbox_acl, ACL_WRITE[0]) == NULL) + kwAllowed=0; + } + + + 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; + + for (kme=si->keywords ? si->keywords->firstEntry:NULL; + kme; kme=kme->next) + { + int rc; + + if (!kwAllowed) + { + current_maildir_info.msgs[n].changedflags=1; + continue; + } + + imapscan_createKeyword(¤t_maildir_info, n); + + if ((rc=libmail_kwmSet(current_maildir_info.msgs[n] + .keywordMsg, + kme->libmail_keywordEntryPtr)) + < 0) + { + write_error_exit(0); + return 0; + } + + if (rc == 0) + { + if (fastkeywords()) + changedKeywords=1; + current_maildir_info.msgs[n].changedflags=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; + + if (current_maildir_info.msgs[n].keywordMsg && kwAllowed) + for (kme=si->keywords ? + si->keywords->firstEntry:NULL; + kme; kme=kme->next) + { + if (!kwAllowed) + { + current_maildir_info.msgs[n] + .changedflags=1; + continue; + } + + if (libmail_kwmClear(current_maildir_info.msgs[n] + .keywordMsg, + kme->libmail_keywordEntryPtr)==0) + { + if (fastkeywords()) + changedKeywords=1; + current_maildir_info.msgs[n] + .changedflags=1; + } + } + + if (current_maildir_info.msgs[n].keywordMsg && + !current_maildir_info.msgs[n].keywordMsg->firstEntry) + { + libmail_kwmDestroy(current_maildir_info.msgs[n] + .keywordMsg); + current_maildir_info.msgs[n].keywordMsg=NULL; + } + } + else + { + struct libmail_kwMessage *kw; + + new_flags=si->flags; + + kw=current_maildir_info.msgs[n].keywordMsg; + + if (kw && kw->firstEntry == NULL) + kw=NULL; + + if (si->keywords && si->keywords->firstEntry == NULL) + si->keywords=NULL; + + if ((si->keywords && !kw) || + (!si->keywords && kw) || + (si->keywords && kw && libmail_kwmCmp(si->keywords, kw))) + { + if (kwAllowed) + { + kw=current_maildir_info.msgs[n].keywordMsg; + + if (kw) + libmail_kwmDestroy(kw); + + current_maildir_info.msgs[n].keywordMsg=NULL; + + if (si->keywords && si->keywords->firstEntry) + { + struct libmail_kwMessageEntry *kme; + + kw=imapscan_createKeyword(¤t_maildir_info, + n); + + for (kme=si->keywords->lastEntry; kme; + kme=kme->prev) + if (libmail_kwmSet(kw, + kme->libmail_keywordEntryPtr) + < 0) + write_error_exit(0); + current_maildir_info.msgs[n].keywordMsg=kw; + } + } + + changedKeywords=1; + } + } + + if (current_mailbox_acl) + { + if (strchr(current_mailbox_acl, ACL_WRITE[0]) == NULL) + { + new_flags.drafts=old_flags.drafts; + new_flags.answered=old_flags.answered; + new_flags.flagged=old_flags.flagged; + } + + if (strchr(current_mailbox_acl, ACL_SEEN[0]) == NULL) + { + new_flags.seen=old_flags.seen; + } + + if (strchr(current_mailbox_acl, ACL_DELETEMSGS[0]) + == NULL) + { + new_flags.deleted=old_flags.deleted; + } + } + + if (changedKeywords) + { + current_maildir_info.msgs[n].changedflags=1; + if (imapscan_updateKeywords(current_maildir_info.msgs[n] + .filename, + current_maildir_info.msgs[n] + .keywordMsg)) + { + close(fd); + return -1; + } + } + + if (reflag_filename(current_maildir_info.msgs+n, &new_flags, fd)) + { + close(fd); + return (-1); + } + close(fd); + if (si->silent) + current_maildir_info.msgs[n].changedflags=0; + else + { +#if SMAP + /* SMAP flag notification is handled elsewhere */ + + if (!smapflag) +#endif + { + 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, + struct libmail_kwMessage *keywords, + unsigned long old_uid) +{ +char *tmpname; +char *newname; +FILE *fp; +struct stat stat_buf; +char buf[BUFSIZ]; +struct uidplus_info *new_uidplus_info; + + 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); + + new_uidplus_info->mtime = stat_buf.st_mtime; + + if (check_outbox(tmpname, cpy_info->mailbox)) + { + unlink(tmpname); + free(tmpname); + free(newname); + free(new_uidplus_info); + return (-1); + } + + if (keywords && keywords->firstEntry && + maildir_kwSave(cpy_info->mailbox, + strrchr(newname, '/')+1, + keywords, + &new_uidplus_info->tmpkeywords, + &new_uidplus_info->newkeywords, 0)) + { + unlink(tmpname); + free(tmpname); + free(newname); + free(new_uidplus_info); + perror("maildir_kwSave"); + 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; + return (0); +} + +int do_copy_message(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_maildir_info, n); + if (fd < 0) return (0); + get_message_flags(current_maildir_info.msgs+n, 0, &new_flags); + + if (copy_message(fd, cpy_info, &new_flags, + + acl_flags_adjust(cpy_info->acls, + &new_flags) ? NULL + : current_maildir_info.msgs[n].keywordMsg, + current_maildir_info.msgs[n].uid)) + { + close(fd); + return (-1); + } + close(fd); + current_maildir_info.msgs[n].copiedflag=1; + 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; +struct imapflags flags; +char *ff; + + --n; + + fd=imapscan_openfile(current_mailbox, ¤t_maildir_info, n); + if (fd < 0) return (0); + filename=current_maildir_info.msgs[n].filename; + + get_message_flags(¤t_maildir_info.msgs[n], NULL, &flags); + + (void)acl_flags_adjust(info->acls, &flags); + + ff=get_reflagged_filename(filename, &flags); + + if (maildirquota_countfile(ff)) + { + if (maildir_parsequota(ff, &nbytes)) + { + if (fstat(fd, &stat_buf) < 0) + { + close(fd); + free(ff); + return (0); + } + nbytes=stat_buf.st_size; + } + info->nbytes += nbytes; + info->nfiles += 1; + } + close(fd); + free(ff); + return (0); +} |
