aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/local/camel-maildir-summary.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/local/camel-maildir-summary.c')
-rw-r--r--camel/providers/local/camel-maildir-summary.c187
1 files changed, 175 insertions, 12 deletions
diff --git a/camel/providers/local/camel-maildir-summary.c b/camel/providers/local/camel-maildir-summary.c
index cbe5a56f00..92b2be23f8 100644
--- a/camel/providers/local/camel-maildir-summary.c
+++ b/camel/providers/local/camel-maildir-summary.c
@@ -133,6 +133,71 @@ CamelMaildirSummary *camel_maildir_summary_new (const char *filename, const char
return o;
}
+/* the 'standard' maildir flags. should be defined in sorted order. */
+static struct {
+ char flag;
+ guint32 flagbit;
+} flagbits[] = {
+ { 'F', CAMEL_MESSAGE_FLAGGED },
+ { 'R', CAMEL_MESSAGE_ANSWERED },
+ { 'S', CAMEL_MESSAGE_SEEN },
+ { 'T', CAMEL_MESSAGE_DELETED },
+};
+
+/* convert the uid + flags into a unique:info maildir format */
+char *camel_maildir_summary_info_to_name(const CamelMessageInfo *info)
+{
+ char *p, *buf;
+ int i;
+
+ buf = alloca(strlen(info->uid) + strlen(":2,") + (sizeof(flagbits)/sizeof(flagbits[0])) + 1);
+ p = buf + sprintf(buf, "%s:2,", info->uid);
+ for (i=0;i<sizeof(flagbits)/sizeof(flagbits[0]);i++) {
+ if (info->flags & flagbits[i].flagbit)
+ *p++ = flagbits[i].flag;
+ }
+ *p = 0;
+
+ return g_strdup(buf);
+}
+
+/* returns 0 if the info matches (or there was none), otherwise we changed it */
+int camel_maildir_summary_name_to_info(CamelMessageInfo *info, const char *name)
+{
+ char *p, c;
+ guint32 set = 0; /* what we set */
+ /*guint32 all = 0;*/ /* all flags */
+ int i;
+
+ p = strstr(name, ":2,");
+ if (p) {
+ p+=3;
+ while ((c = *p++)) {
+ /* we could assume that the flags are in order, but its just as easy not to require */
+ for (i=0;i<sizeof(flagbits)/sizeof(flagbits[0]);i++) {
+ if (flagbits[i].flag == c && (info->flags & flagbits[i].flagbit) == 0) {
+ set |= flagbits[i].flagbit;
+ }
+ /*all |= flagbits[i].flagbit;*/
+ }
+ }
+
+ /* changed? */
+ /*if ((info->flags & all) != set) {*/
+ if ((info->flags & set) != set) {
+ /* ok, they did change, only add the new flags ('merge flags'?) */
+ /*info->flags &= all; if we wanted to set only the new flags, which we probably dont */
+ info->flags |= set;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* FIXME: We need to also provide an encode/decode X-Evolution function, as the default
+ is no good for us, and can screw up the uid info */
+
static CamelMessageInfo *message_info_new(CamelFolderSummary * s, struct _header_raw *h)
{
CamelMessageInfo *mi;
@@ -144,13 +209,41 @@ static CamelMessageInfo *message_info_new(CamelFolderSummary * s, struct _header
if (mi) {
mdi = (CamelMaildirMessageInfo *)mi;
- mi->uid = camel_folder_summary_next_uid_string(s);
+ if (mi->uid == NULL) {
+ mi->uid = camel_folder_summary_next_uid_string(s);
+ }
+
+ /* with maildir we know the real received date, from the filename */
+ mi->date_received = strtoul(mi->uid, NULL, 10);
- /* should store some status info in the filename, but we wont (yet) (fixme) */
if (mds->priv->current_file) {
+#if 0
+ char *p1, *p2, *p3;
+ unsigned long uid;
+#endif
+ /* if setting from a file, grab the flags from it */
mdi->filename = g_strdup(mds->priv->current_file);
+ camel_maildir_summary_name_to_info(mi, mdi->filename);
+
+#if 0
+ /* Actually, I dont think all this effort is worth it at all ... */
+
+ /* also, see if we can extract the next-id from tne name, and safe-if-fy ourselves against collisions */
+ /* we check for something.something_number.something */
+ p1 = strchr(mdi->filename, '.');
+ if (p1) {
+ p2 = strchr(p1+1, '.');
+ p3 = strchr(p1+1, '_');
+ if (p2 && p3 && p3<p2) {
+ uid = strtoul(p3+1, &p1, 10);
+ if (p1 == p2 && uid>0)
+ camel_folder_summary_set_uid(s, uid);
+ }
+ }
+#endif
} else {
- mdi->filename = g_strdup_printf("%s:2,", mi->uid);
+ /* if creating a file, set its name from the flags we have */
+ mdi->filename = camel_maildir_summary_info_to_name(mi);
}
}
@@ -160,9 +253,10 @@ static CamelMessageInfo *message_info_new(CamelFolderSummary * s, struct _header
static char *maildir_summary_next_uid_string(CamelFolderSummary *s)
{
CamelMaildirSummary *mds = (CamelMaildirSummary *)s;
- /*CamelLocalSummary *cls = (CamelLocalSummary *)s;*/
- /* current_file is more a current_filename, so map the filename to a uid */
+ d(printf("next uid string called?\n"));
+
+ /* if we have a current file, then use that to get the uid */
if (mds->priv->current_file) {
char *cln;
@@ -172,8 +266,33 @@ static char *maildir_summary_next_uid_string(CamelFolderSummary *s)
else
return g_strdup(mds->priv->current_file);
} else {
- /* we use time.pid_count.hostname */
+ /* the first would probably work, but just to be safe, check for collisions */
+#if 0
return g_strdup_printf("%ld.%d_%u.%s", time(0), getpid(), camel_folder_summary_next_uid(s), mds->priv->hostname);
+#else
+ CamelLocalSummary *cls = (CamelLocalSummary *)s;
+ char *name = NULL, *uid = NULL;
+ struct stat st;
+ int retry = 0;
+ guint32 nextuid = camel_folder_summary_next_uid(s);
+
+ /* we use time.pid_count.hostname */
+ do {
+ if (retry > 0) {
+ g_free(name);
+ g_free(uid);
+ sleep(2);
+ }
+ uid = g_strdup_printf("%ld.%d_%u.%s", time(0), getpid(), nextuid, mds->priv->hostname);
+ name = g_strdup_printf("%s/tmp/%s", cls->folder_path, uid);
+ retry++;
+ } while (stat(name, &st) == 0 && retry<3);
+
+ /* I dont know what we're supposed to do if it fails to find a unique name?? */
+
+ g_free(name);
+ return uid;
+#endif
}
}
@@ -220,6 +339,21 @@ remove_summary(char *key, CamelMessageInfo *info, CamelLocalSummary *cls)
}
static int
+sort_receive_cmp(const void *ap, const void *bp)
+{
+ const CamelMessageInfo
+ *a = *((CamelMessageInfo **)ap),
+ *b = *((CamelMessageInfo **)bp);
+
+ if (a->date_received < b->date_received)
+ return -1;
+ else if (a->date_received > b->date_received)
+ return 1;
+
+ return 0;
+}
+
+static int
maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, CamelException *ex)
{
DIR *dir;
@@ -343,6 +477,9 @@ maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, Ca
g_free(new);
g_free(cur);
+ /* sort the summary based on receive time, since the directory order is not useful */
+ qsort(s->messages->pdata, s->messages->len, sizeof(CamelMessageInfo *), sort_receive_cmp);
+
/* FIXME: move this up a class? */
/* force a save of the index, just to make sure */
@@ -355,8 +492,7 @@ maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, Ca
return 0;
}
-/* sync the summary with the ondisk files.
- It doesnt store the state in the file, the summary only, == MUCH faster */
+/* sync the summary with the ondisk files. */
static int
maildir_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changes, CamelException *ex)
{
@@ -364,20 +500,19 @@ maildir_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChange
CamelMessageInfo *info;
CamelMaildirMessageInfo *mdi;
char *name;
+ struct stat st;
d(printf("summary_sync(expunge=%s)\n", expunge?"true":"false"));
if (cls->index) {
ibex_save(cls->index);
}
- if (!expunge)
- return 0;
count = camel_folder_summary_count((CamelFolderSummary *)cls);
for (i=count-1;i>=0;i--) {
info = camel_folder_summary_index((CamelFolderSummary *)cls, i);
- if (info && info->flags & CAMEL_MESSAGE_DELETED) {
- mdi = (CamelMaildirMessageInfo *)info;
+ mdi = (CamelMaildirMessageInfo *)info;
+ if (info && (info->flags & CAMEL_MESSAGE_DELETED) && expunge) {
name = g_strdup_printf("%s/cur/%s", cls->folder_path, mdi->filename);
d(printf("deleting %s\n", name));
if (unlink(name) == 0 || errno==ENOENT) {
@@ -389,6 +524,34 @@ maildir_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChange
camel_folder_change_info_remove_uid(changes, info->uid);
camel_folder_summary_remove((CamelFolderSummary *)cls, info);
}
+ g_free(name);
+ } else if (info && (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
+ char *newname = camel_maildir_summary_info_to_name(info);
+ char *dest;
+
+ /* do we care about additional metainfo stored inside the message? */
+ /* probably should all go in the filename? */
+
+ /* have our flags/ i.e. name changed? */
+ if (strcmp(newname, mdi->filename)) {
+ name = g_strdup_printf("%s/cur/%s", cls->folder_path, mdi->filename);
+ dest = g_strdup_printf("%s/cur/%s", cls->folder_path, newname);
+ rename(name, dest);
+ if (stat(dest, &st) == -1) {
+ /* we'll assume it didn't work, but dont change anything else */
+ g_free(newname);
+ } else {
+ g_free(mdi->filename);
+ mdi->filename = newname;
+ }
+ g_free(name);
+ g_free(dest);
+ } else {
+ g_free(newname);
+ }
+
+ /* strip FOLDER_MESSAGE_FLAGED, etc */
+ info->flags &= 0xffff;
}
}
return 0;