0
|
1 /* Copyright (C) 2002 Timo Sirainen */
|
|
2
|
|
3 #include "lib.h"
|
|
4 #include "maildir-index.h"
|
|
5 #include "mail-index-util.h"
|
|
6
|
|
7 #include <stdio.h>
|
|
8
|
|
9 static MailIndex maildir_index;
|
|
10
|
|
11 const char *maildir_filename_set_flags(const char *fname, MailFlags flags)
|
|
12 {
|
|
13 const char *info, *oldflags;
|
|
14 char *flags_buf, *p;
|
|
15 int i, nextflag;
|
|
16
|
|
17 /* remove the old :info from file name, and get the old flags */
|
|
18 info = strrchr(fname, ':');
|
|
19 if (info != NULL && strrchr(fname, '/') > info)
|
|
20 info = NULL;
|
|
21
|
|
22 oldflags = "";
|
|
23 if (info != NULL) {
|
|
24 fname = t_strndup(fname, (unsigned int) (info-fname));
|
|
25 if (info[1] == '2' && info[2] == ',')
|
|
26 oldflags = info+3;
|
|
27 }
|
|
28
|
|
29 /* insert the new flags between old flags. flags must be sorted by
|
|
30 their ASCII code. unknown flags are kept. */
|
|
31 flags_buf = t_malloc(MAIL_FLAGS_COUNT+strlen(oldflags)+1);
|
|
32 p = flags_buf;
|
|
33
|
|
34 for (;;) {
|
|
35 /* skip all known flags */
|
|
36 while (*oldflags == 'D' || *oldflags == 'F' ||
|
|
37 *oldflags == 'R' || *oldflags == 'S' ||
|
|
38 *oldflags == 'T' ||
|
|
39 (*oldflags >= 'a' && *oldflags <= 'z'))
|
|
40 oldflags++;
|
|
41
|
|
42 nextflag = *oldflags == '\0' ? 256 :
|
|
43 (unsigned char) *oldflags;
|
|
44
|
|
45 if ((flags & MAIL_DRAFT) && nextflag > 'D') {
|
|
46 *p++ = 'D';
|
|
47 flags &= ~MAIL_DRAFT;
|
|
48 }
|
|
49 if ((flags & MAIL_FLAGGED) && nextflag > 'F') {
|
|
50 *p++ = 'F';
|
|
51 flags &= ~MAIL_FLAGGED;
|
|
52 }
|
|
53 if ((flags & MAIL_ANSWERED) && nextflag > 'R') {
|
|
54 *p++ = 'R';
|
|
55 flags &= ~MAIL_ANSWERED;
|
|
56 }
|
|
57 if ((flags & MAIL_SEEN) && nextflag > 'S') {
|
|
58 *p++ = 'S';
|
|
59 flags &= ~MAIL_SEEN;
|
|
60 }
|
|
61 if ((flags & MAIL_DELETED) && nextflag > 'T') {
|
|
62 *p++ = 'T';
|
|
63 flags &= ~MAIL_DELETED;
|
|
64 }
|
|
65
|
|
66 if ((flags & MAIL_CUSTOM_FLAGS_MASK) && nextflag > 'a') {
|
|
67 for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
|
|
68 if (flags & (1 << (i + MAIL_CUSTOM_FLAG_1_BIT)))
|
|
69 *p++ = 'a' + i;
|
|
70 }
|
|
71 flags &= ~MAIL_CUSTOM_FLAGS_MASK;
|
|
72 }
|
|
73
|
|
74 if (*oldflags == '\0')
|
|
75 break;
|
|
76
|
|
77 *p++ = *oldflags++;
|
|
78 }
|
|
79
|
|
80 *p = '\0';
|
|
81
|
|
82 return t_strconcat(fname, ":2,", flags_buf, NULL);
|
|
83 }
|
|
84
|
|
85 MailIndex *maildir_index_alloc(const char *dir)
|
|
86 {
|
|
87 MailIndex *index;
|
|
88 int len;
|
|
89
|
|
90 i_assert(dir != NULL);
|
|
91
|
|
92 index = i_new(MailIndex, 1);
|
|
93 memcpy(index, &maildir_index, sizeof(MailIndex));
|
|
94
|
|
95 index->fd = -1;
|
|
96 index->dir = i_strdup(dir);
|
|
97
|
|
98 len = strlen(index->dir);
|
|
99 if (index->dir[len-1] == '/')
|
|
100 index->dir[len-1] = '\0';
|
|
101
|
|
102 return (MailIndex *) index;
|
|
103 }
|
|
104
|
|
105 static void maildir_index_free(MailIndex *index)
|
|
106 {
|
|
107 mail_index_close(index);
|
|
108 i_free(index->dir);
|
|
109 i_free(index);
|
|
110 }
|
|
111
|
|
112 static int maildir_index_update_flags(MailIndex *index, MailIndexRecord *rec,
|
|
113 unsigned int seq, MailFlags flags,
|
|
114 int external_change)
|
|
115 {
|
|
116 MailIndexUpdate *update;
|
|
117 const char *old_fname, *new_fname;
|
|
118 const char *old_path, *new_path;
|
|
119
|
|
120 if (!mail_index_update_flags(index, rec, seq, flags, external_change))
|
|
121 return FALSE;
|
|
122
|
|
123 /* we need to update the flags in the file name */
|
|
124 old_fname = index->lookup_field(index, rec, FIELD_TYPE_LOCATION);
|
|
125 if (old_fname == NULL) {
|
|
126 INDEX_MARK_CORRUPTED(index);
|
|
127 index_set_error(index, "Corrupted index file %s: "
|
|
128 "Missing location field for record %u",
|
|
129 index->filepath, rec->uid);
|
|
130 return FALSE;
|
|
131 }
|
|
132
|
|
133 new_fname = maildir_filename_set_flags(old_fname, flags);
|
|
134
|
|
135 if (strcmp(old_fname, new_fname) != 0) {
|
|
136 old_path = t_strconcat(index->dir, "/cur/", old_fname, NULL);
|
|
137 new_path = t_strconcat(index->dir, "/cur/", new_fname, NULL);
|
|
138
|
|
139 /* minor problem: new_path is overwritten if it exists.. */
|
|
140 if (rename(old_path, new_path) == -1) {
|
|
141 index_set_error(index, "maildir flags update: "
|
|
142 "rename(%s, %s) failed: %m",
|
|
143 old_path, new_path);
|
|
144 return FALSE;
|
|
145 }
|
|
146
|
|
147 /* update the filename in index */
|
|
148 update = index->update_begin(index, rec);
|
|
149 index->update_field(update, FIELD_TYPE_LOCATION, new_fname, 0);
|
|
150
|
|
151 if (!index->update_end(update))
|
|
152 return FALSE;
|
|
153 }
|
|
154
|
|
155 return TRUE;
|
|
156 }
|
|
157
|
|
158 static MailIndex maildir_index = {
|
|
159 mail_index_open,
|
|
160 mail_index_open_or_create,
|
|
161 maildir_index_free,
|
|
162 mail_index_set_lock,
|
|
163 mail_index_try_lock,
|
|
164 maildir_index_rebuild,
|
|
165 mail_index_fsck,
|
|
166 maildir_index_sync,
|
|
167 mail_index_get_header,
|
|
168 mail_index_lookup,
|
|
169 mail_index_next,
|
|
170 mail_index_lookup_uid_range,
|
|
171 mail_index_lookup_field,
|
|
172 mail_index_get_sequence,
|
|
173 maildir_open_mail,
|
|
174 mail_index_expunge,
|
|
175 maildir_index_update_flags,
|
|
176 mail_index_append,
|
|
177 mail_index_update_begin,
|
|
178 mail_index_update_end,
|
|
179 mail_index_update_field,
|
|
180 mail_index_get_last_error,
|
|
181 mail_index_is_inconsistency_error
|
|
182 };
|