NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
lib.h File Reference

Maildir local mailbox type. More...

#include <stdbool.h>
#include <stdio.h>
#include "core/lib.h"
+ Include dependency graph for lib.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int maildir_check_empty (struct Buffer *path)
 Is the mailbox empty.
 
struct Emailmaildir_email_new (void)
 Create a Maildir Email.
 
void maildir_gen_flags (char *dest, size_t destlen, struct Email *e)
 Generate the Maildir flags for an email.
 
bool maildir_msg_open_new (struct Mailbox *m, struct Message *msg, const struct Email *e)
 Open a new message in a Mailbox - Implements MxOps::msg_open_new() -.
 
FILE * maildir_open_find_message (const char *folder, const char *msg, char **newname)
 Find a message by name.
 
void maildir_parse_flags (struct Email *e, const char *path)
 Parse Maildir file flags.
 
bool maildir_parse_message (enum MailboxType type, const char *fname, bool is_old, struct Email *e)
 Actually parse a maildir message.
 
bool maildir_parse_stream (enum MailboxType type, FILE *fp, const char *fname, bool is_old, struct Email *e)
 Parse a Maildir message.
 
bool maildir_sync_mailbox_message (struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
 Save changes to the mailbox.
 
bool maildir_update_flags (struct Mailbox *m, struct Email *e_old, struct Email *e_new)
 Update the mailbox flags.
 
int mh_check_empty (struct Buffer *path)
 Is mailbox empty.
 
int mh_sync_mailbox_message (struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
 Save changes to the mailbox.
 

Variables

const struct MxOps MxMaildirOps
 Maildir Mailbox - Implements MxOps -.
 
const struct MxOps MxMhOps
 MH Mailbox - Implements MxOps -.
 

Detailed Description

Maildir local mailbox type.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file lib.h.

Function Documentation

◆ maildir_check_empty()

int maildir_check_empty ( struct Buffer path)

Is the mailbox empty.

Parameters
pathMailbox to check
Return values
1Mailbox is empty
0Mailbox contains mail
-1Error

Definition at line 1070 of file maildir.c.

1071{
1072 DIR *dir = NULL;
1073 struct dirent *de = NULL;
1074 int rc = 1; /* assume empty until we find a message */
1075 char realpath[PATH_MAX] = { 0 };
1076 int iter = 0;
1077
1078 /* Strategy here is to look for any file not beginning with a period */
1079
1080 do
1081 {
1082 /* we do "cur" on the first iteration since it's more likely that we'll
1083 * find old messages without having to scan both subdirs */
1084 snprintf(realpath, sizeof(realpath), "%s/%s", buf_string(path),
1085 (iter == 0) ? "cur" : "new");
1086 dir = mutt_file_opendir(realpath, MUTT_OPENDIR_CREATE);
1087 if (!dir)
1088 return -1;
1089 while ((de = readdir(dir)))
1090 {
1091 if (*de->d_name != '.')
1092 {
1093 rc = 0;
1094 break;
1095 }
1096 }
1097 closedir(dir);
1098 iter++;
1099 } while (rc && iter < 2);
1100
1101 return rc;
1102}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:616
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:74
#define PATH_MAX
Definition: mutt.h:41
+ Here is the call graph for this function:

◆ maildir_email_new()

struct Email * maildir_email_new ( void  )

Create a Maildir Email.

Return values
ptrNewly created Email

Create a new Email and attach MaildirEmailData.

Note
This should be freed using email_free()

Definition at line 85 of file maildir.c.

86{
87 struct Email *e = email_new();
90
91 return e;
92}
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
struct MaildirEmailData * maildir_edata_new(void)
Create a new MaildirEmailData object.
Definition: edata.c:53
The envelope/body of an email.
Definition: email.h:37
void * edata
Driver-specific data.
Definition: email.h:72
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_gen_flags()

void maildir_gen_flags ( char *  dest,
size_t  destlen,
struct Email e 
)

Generate the Maildir flags for an email.

Parameters
destBuffer for the result
destlenLength of buffer
eEmail

Definition at line 206 of file maildir.c.

207{
208 *dest = '\0';
209
210 const char *flags = NULL;
211
213 if (edata)
214 flags = edata->maildir_flags;
215
216 /* The maildir specification requires that all files in the cur
217 * subdirectory have the :unique string appended, regardless of whether
218 * or not there are any flags. If .old is set, we know that this message
219 * will end up in the cur directory, so we include it in the following
220 * test even though there is no associated flag. */
221
222 if (e->flagged || e->replied || e->read || e->deleted || e->old || flags)
223 {
224 char tmp[1024] = { 0 };
225 snprintf(tmp, sizeof(tmp), "%s%s%s%s%s", e->flagged ? "F" : "", e->replied ? "R" : "",
226 e->read ? "S" : "", e->deleted ? "T" : "", NONULL(flags));
227 if (flags)
228 mutt_qsort_r(tmp, strlen(tmp), 1, maildir_sort_flags, NULL);
229
230 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
231 snprintf(dest, destlen, "%c2,%s", c_maildir_field_delimiter, tmp);
232 }
233}
const char * cc_maildir_field_delimiter(void)
Get the cached value of $maildir_field_delimiter.
Definition: config_cache.c:130
static int maildir_sort_flags(const void *a, const void *b, void *sdata)
Compare two flag characters - Implements sort_t -.
Definition: maildir.c:195
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:64
void mutt_qsort_r(void *base, size_t nmemb, size_t size, sort_t compar, void *sdata)
Sort an array, where the comparator has access to opaque data rather than requiring global variables.
Definition: qsort_r.c:66
#define NONULL(x)
Definition: string2.h:37
bool read
Email is read.
Definition: email.h:48
bool old
Email is seen, but unread.
Definition: email.h:47
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
bool deleted
Email is deleted.
Definition: email.h:76
Maildir-specific Email data -.
Definition: edata.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_open_find_message()

FILE * maildir_open_find_message ( const char *  folder,
const char *  msg,
char **  newname 
)

Find a message by name.

Parameters
[in]folderMaildir path
[in]msgEmail path
[out]newnameNew name, if it has moved
Return values
ptrFile handle

Definition at line 1023 of file maildir.c.

1024{
1025 static unsigned int new_hits = 0, cur_hits = 0; /* simple dynamic optimization */
1026
1027 struct Buffer *unique = buf_pool_get();
1028 maildir_canon_filename(unique, msg);
1029
1030 FILE *fp = maildir_open_find_message_dir(folder, buf_string(unique),
1031 (new_hits > cur_hits) ? "new" : "cur", newname);
1032 if (fp || (errno != ENOENT))
1033 {
1034 if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
1035 {
1036 new_hits += ((new_hits > cur_hits) ? 1 : 0);
1037 cur_hits += ((new_hits > cur_hits) ? 0 : 1);
1038 }
1039
1040 goto cleanup;
1041 }
1042 fp = maildir_open_find_message_dir(folder, buf_string(unique),
1043 (new_hits > cur_hits) ? "cur" : "new", newname);
1044 if (fp || (errno != ENOENT))
1045 {
1046 if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
1047 {
1048 new_hits += ((new_hits > cur_hits) ? 0 : 1);
1049 cur_hits += ((new_hits > cur_hits) ? 1 : 0);
1050 }
1051
1052 goto cleanup;
1053 }
1054
1055 fp = NULL;
1056
1057cleanup:
1058 buf_pool_release(&unique);
1059
1060 return fp;
1061}
static void maildir_canon_filename(struct Buffer *dest, const char *src)
Generate the canonical filename for a Maildir folder.
Definition: maildir.c:750
static FILE * maildir_open_find_message_dir(const char *folder, const char *unique, const char *subfolder, char **newname)
Find a message in a maildir folder.
Definition: maildir.c:786
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
String manipulation buffer.
Definition: buffer.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_parse_flags()

void maildir_parse_flags ( struct Email e,
const char *  path 
)

Parse Maildir file flags.

Parameters
eEmail
pathPath to email file

Definition at line 840 of file maildir.c.

841{
842 char *q = NULL;
843
844 e->flagged = false;
845 e->read = false;
846 e->replied = false;
847
849
850 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
851 char *p = strrchr(path, c_maildir_field_delimiter);
852 if (p && mutt_str_startswith(p + 1, "2,"))
853 {
854 p += 3;
855
856 mutt_str_replace(&edata->maildir_flags, p);
857 q = edata->maildir_flags;
858
859 while (*p)
860 {
861 switch (*p)
862 {
863 case 'F': // Flagged
864 e->flagged = true;
865 break;
866
867 case 'R': // Replied
868 e->replied = true;
869 break;
870
871 case 'S': // Seen
872 e->read = true;
873 break;
874
875 case 'T': // Trashed
876 {
877 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
878 if (!e->flagged || !c_flag_safe)
879 {
880 e->trash = true;
881 e->deleted = true;
882 }
883 break;
884 }
885
886 default:
887 *q++ = *p;
888 break;
889 }
890 p++;
891 }
892 }
893
894 if (q == edata->maildir_flags)
895 FREE(&edata->maildir_flags);
896 else if (q)
897 *q = '\0';
898}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
#define FREE(x)
Definition: memory.h:45
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:228
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:51
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_parse_message()

bool maildir_parse_message ( enum MailboxType  type,
const char *  fname,
bool  is_old,
struct Email e 
)

Actually parse a maildir message.

Parameters
typeMailbox type, e.g. MUTT_MAILDIR
fnameMessage filename
is_oldtrue, if the email is old (read)
eEmail to populate
Return values
trueSuccess

This may also be used to fill out a fake header structure generated by lazy maildir parsing.

Definition at line 954 of file maildir.c.

956{
957 if (!fname || !e)
958 return false;
959
960 FILE *fp = fopen(fname, "r");
961 if (!fp)
962 return false;
963
964 bool rc = maildir_parse_stream(type, fp, fname, is_old, e);
965 mutt_file_fclose(&fp);
966 return rc;
967}
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
bool maildir_parse_stream(enum MailboxType type, FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition: maildir.c:912
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_parse_stream()

bool maildir_parse_stream ( enum MailboxType  type,
FILE *  fp,
const char *  fname,
bool  is_old,
struct Email e 
)

Parse a Maildir message.

Parameters
typeMailbox type, e.g. MUTT_MAILDIR
fpMessage file handle
fnameMessage filename
is_oldtrue, if the email is old (read)
eEmail
Return values
trueSuccess

Actually parse a maildir message. This may also be used to fill out a fake header structure generated by lazy maildir parsing.

Definition at line 912 of file maildir.c.

914{
915 if (!fp || !fname || !e)
916 return false;
917
918 const long size = mutt_file_get_size_fp(fp);
919 if (size == 0)
920 return false;
921
922 e->env = mutt_rfc822_read_header(fp, e, false, false);
923
924 if (e->received == 0)
925 e->received = e->date_sent;
926
927 /* always update the length since we have fresh information available. */
928 e->body->length = size - e->body->offset;
929
930 e->index = -1;
931
932 if (type == MUTT_MAILDIR)
933 {
934 /* maildir stores its flags in the filename, so ignore the
935 * flags in the header of the message */
936
937 e->old = is_old;
938 maildir_parse_flags(e, fname);
939 }
940 return e;
941}
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1170
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1578
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition: maildir.c:840
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct Envelope * env
Envelope information.
Definition: email.h:66
struct Body * body
List of MIME parts.
Definition: email.h:67
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:58
int index
The absolute (unsorted) message number.
Definition: email.h:109
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_sync_mailbox_message()

bool maildir_sync_mailbox_message ( struct Mailbox m,
struct Email e,
struct HeaderCache hc 
)

Save changes to the mailbox.

Parameters
mMailbox
eEmail
hcHeader cache handle
Return values
trueSuccess
falseError

Definition at line 977 of file maildir.c.

978{
979 if (!e)
980 return false;
981
982 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
983 if (e->deleted && !c_maildir_trash)
984 {
985 char path[PATH_MAX] = { 0 };
986 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
987#ifdef USE_HCACHE
988 if (hc)
989 {
990 const char *key = e->path + 3;
991 size_t keylen = maildir_hcache_keylen(key);
992 hcache_delete_record(hc, key, keylen);
993 }
994#endif
995 unlink(path);
996 }
997 else if (e->changed || e->attach_del ||
998 ((c_maildir_trash || e->trash) && (e->deleted != e->trash)))
999 {
1000 if (maildir_sync_message(m, e) == -1)
1001 return false;
1002 }
1003
1004#ifdef USE_HCACHE
1005 if (hc && e->changed)
1006 {
1007 const char *key = e->path + 3;
1008 size_t keylen = maildir_hcache_keylen(key);
1009 hcache_store(hc, key, keylen, e, 0);
1010 }
1011#endif
1012
1013 return true;
1014}
int hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:686
int hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:759
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
static int maildir_sync_message(struct Mailbox *m, struct Email *e)
Sync an email to a Maildir folder.
Definition: maildir.c:405
static size_t maildir_hcache_keylen(const char *fn)
Calculate the length of the Maildir path.
Definition: maildir.c:599
bool changed
Email has been edited.
Definition: email.h:75
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:98
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_update_flags()

bool maildir_update_flags ( struct Mailbox m,
struct Email e_old,
struct Email e_new 
)

Update the mailbox flags.

Parameters
mMailbox
e_oldOld Email
e_newNew Email
Return values
trueThe flags changed
falseOtherwise

Definition at line 120 of file shared.c.

121{
122 if (!m)
123 return false;
124
125 /* save the global state here so we can reset it at the
126 * end of list block if required. */
127 bool context_changed = m->changed;
128
129 /* user didn't modify this message. alter the flags to match the
130 * current state on disk. This may not actually do
131 * anything. mutt_set_flag() will just ignore the call if the status
132 * bits are already properly set, but it is still faster not to pass
133 * through it */
134 if (e_old->flagged != e_new->flagged)
135 mutt_set_flag(m, e_old, MUTT_FLAG, e_new->flagged, true);
136 if (e_old->replied != e_new->replied)
137 mutt_set_flag(m, e_old, MUTT_REPLIED, e_new->replied, true);
138 if (e_old->read != e_new->read)
139 mutt_set_flag(m, e_old, MUTT_READ, e_new->read, true);
140 if (e_old->old != e_new->old)
141 mutt_set_flag(m, e_old, MUTT_OLD, e_new->old, true);
142
143 /* mutt_set_flag() will set this, but we don't need to
144 * sync the changes we made because we just updated the
145 * context to match the current on-disk state of the
146 * message. */
147 bool header_changed = e_old->changed;
148 e_old->changed = false;
149
150 /* if the mailbox was not modified before we made these
151 * changes, unset the changed flag since nothing needs to
152 * be synchronized. */
153 if (!context_changed)
154 m->changed = false;
155
156 return header_changed;
157}
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition: flags.c:53
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:72
@ MUTT_OLD
Old messages.
Definition: mutt.h:70
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:78
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:71
bool changed
Mailbox has been modified.
Definition: mailbox.h:109
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_check_empty()

int mh_check_empty ( struct Buffer path)

Is mailbox empty.

Parameters
pathMailbox to check
Return values
1Mailbox is empty
0Mailbox contains mail
-1Error

Definition at line 166 of file mh.c.

167{
168 struct dirent *de = NULL;
169 int rc = 1; /* assume empty until we find a message */
170
172 if (!dir)
173 return -1;
174 while ((de = readdir(dir)))
175 {
176 if (mh_valid_message(de->d_name))
177 {
178 rc = 0;
179 break;
180 }
181 }
182 closedir(dir);
183
184 return rc;
185}
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:73
static bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition: mh.c:149
+ Here is the call graph for this function:

◆ mh_sync_mailbox_message()

int mh_sync_mailbox_message ( struct Mailbox m,
struct Email e,
struct HeaderCache hc 
)

Save changes to the mailbox.

Parameters
mMailbox
eEmail
hcHeader cache handle
Return values
0Success
-1Error

Definition at line 746 of file mh.c.

747{
748 if (!m || !e)
749 return -1;
750
751 if (e->deleted)
752 {
753 char path[PATH_MAX] = { 0 };
754 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
755 const bool c_mh_purge = cs_subset_bool(NeoMutt->sub, "mh_purge");
756 if (c_mh_purge)
757 {
758#ifdef USE_HCACHE
759 if (hc)
760 {
761 const char *key = e->path;
762 size_t keylen = strlen(key);
763 hcache_delete_record(hc, key, keylen);
764 }
765#endif
766 unlink(path);
767 }
768 else
769 {
770 /* MH just moves files out of the way when you delete them */
771 if (*e->path != ',')
772 {
773 char tmp[PATH_MAX] = { 0 };
774 snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
775 unlink(tmp);
776 if (rename(path, tmp) != 0)
777 {
778 return -1;
779 }
780 }
781 }
782 }
783 else if (e->changed || e->attach_del)
784 {
785 if (mh_sync_message(m, e) == -1)
786 return -1;
787 }
788
789#ifdef USE_HCACHE
790 if (hc && e->changed)
791 {
792 const char *key = e->path;
793 size_t keylen = strlen(key);
794 hcache_store(hc, key, keylen, e, 0);
795 }
796#endif
797
798 return 0;
799}
static int mh_sync_message(struct Mailbox *m, struct Email *e)
Sync an email to an MH folder.
Definition: mh.c:447
+ Here is the call graph for this function:
+ Here is the caller graph for this function: