summaryrefslogtreecommitdiffstats
path: root/imap/storeinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'imap/storeinfo.c')
-rw-r--r--imap/storeinfo.c495
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, &current_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(&current_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(&current_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, &current_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, &current_maildir_info, n);
+ if (fd < 0) return (0);
+ filename=current_maildir_info.msgs[n].filename;
+
+ get_message_flags(&current_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);
+}