NeoMutt  2022-04-29-178-g3b62e6
Teaching an old dog new tricks
DOXYGEN
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 (const char *path)
 Is the mailbox empty. More...
 
void maildir_gen_flags (char *dest, size_t destlen, struct Email *e)
 Generate the Maildir flags for an email. More...
 
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() -. More...
 
FILE * maildir_open_find_message (const char *folder, const char *msg, char **newname)
 Find a new. More...
 
void maildir_parse_flags (struct Email *e, const char *path)
 Parse Maildir file flags. More...
 
struct Emailmaildir_parse_message (enum MailboxType type, const char *fname, bool is_old, struct Email *e)
 Actually parse a maildir message. More...
 
struct Emailmaildir_parse_stream (enum MailboxType type, FILE *fp, const char *fname, bool is_old, struct Email *e)
 Parse a Maildir message. More...
 
bool maildir_sync_mailbox_message (struct Mailbox *m, int msgno, struct HeaderCache *hc)
 Save changes to the mailbox. More...
 
bool maildir_update_flags (struct Mailbox *m, struct Email *e_old, struct Email *e_new)
 Update the mailbox flags. More...
 
int mh_check_empty (const char *path)
 Is mailbox empty. More...
 
int mh_sync_mailbox_message (struct Mailbox *m, int msgno, struct HeaderCache *hc)
 Save changes to the mailbox. More...
 

Variables

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

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 ( const char *  path)

Is the mailbox empty.

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

Definition at line 1042 of file maildir.c.

1043{
1044 DIR *dp = NULL;
1045 struct dirent *de = NULL;
1046 int rc = 1; /* assume empty until we find a message */
1047 char realpath[PATH_MAX] = { 0 };
1048 int iter = 0;
1049
1050 /* Strategy here is to look for any file not beginning with a period */
1051
1052 do
1053 {
1054 /* we do "cur" on the first iteration since it's more likely that we'll
1055 * find old messages without having to scan both subdirs */
1056 snprintf(realpath, sizeof(realpath), "%s/%s", path, (iter == 0) ? "cur" : "new");
1057 dp = opendir(realpath);
1058 if (!dp)
1059 return -1;
1060 while ((de = readdir(dp)))
1061 {
1062 if (*de->d_name != '.')
1063 {
1064 rc = 0;
1065 break;
1066 }
1067 }
1068 closedir(dp);
1069 iter++;
1070 } while (rc && iter < 2);
1071
1072 return rc;
1073}
#define PATH_MAX
Definition: mutt.h:40

◆ 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 186 of file maildir.c.

187{
188 *dest = '\0';
189
190 const char *flags = NULL;
191
193 if (edata)
194 flags = edata->maildir_flags;
195
196 /* The maildir specification requires that all files in the cur
197 * subdirectory have the :unique string appended, regardless of whether
198 * or not there are any flags. If .old is set, we know that this message
199 * will end up in the cur directory, so we include it in the following
200 * test even though there is no associated flag. */
201
202 if (e->flagged || e->replied || e->read || e->deleted || e->old || flags)
203 {
204 char tmp[1024] = { 0 };
205 snprintf(tmp, sizeof(tmp), "%s%s%s%s%s", e->flagged ? "F" : "", e->replied ? "R" : "",
206 e->read ? "S" : "", e->deleted ? "T" : "", NONULL(flags));
207 if (flags)
208 qsort(tmp, strlen(tmp), 1, ch_compare);
209 snprintf(dest, destlen, ":2,%s", tmp);
210 }
211}
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:64
static int ch_compare(const void *a, const void *b)
qsort() callback to sort characters
Definition: maildir.c:175
#define NONULL(x)
Definition: string2.h:37
bool read
Email is read.
Definition: email.h:48
void * edata
Driver-specific data.
Definition: email.h:72
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 new.

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

Definition at line 995 of file maildir.c.

996{
997 static unsigned int new_hits = 0, cur_hits = 0; /* simple dynamic optimization */
998
999 struct Buffer *unique = mutt_buffer_pool_get();
1000 maildir_canon_filename(unique, msg);
1001
1002 FILE *fp = maildir_open_find_message_dir(folder, mutt_buffer_string(unique),
1003 (new_hits > cur_hits) ? "new" : "cur", newname);
1004 if (fp || (errno != ENOENT))
1005 {
1006 if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
1007 {
1008 new_hits += ((new_hits > cur_hits) ? 1 : 0);
1009 cur_hits += ((new_hits > cur_hits) ? 0 : 1);
1010 }
1011
1012 goto cleanup;
1013 }
1015 (new_hits > cur_hits) ? "cur" : "new", newname);
1016 if (fp || (errno != ENOENT))
1017 {
1018 if ((new_hits < UINT_MAX) && (cur_hits < UINT_MAX))
1019 {
1020 new_hits += ((new_hits > cur_hits) ? 0 : 1);
1021 cur_hits += ((new_hits > cur_hits) ? 1 : 0);
1022 }
1023
1024 goto cleanup;
1025 }
1026
1027 fp = NULL;
1028
1029cleanup:
1030 mutt_buffer_pool_release(&unique);
1031
1032 return fp;
1033}
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
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:755
void maildir_canon_filename(struct Buffer *dest, const char *src)
Generate the canonical filename for a Maildir folder.
Definition: maildir.c:725
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
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 809 of file maildir.c.

810{
811 char *q = NULL;
812
813 e->flagged = false;
814 e->read = false;
815 e->replied = false;
816
818
819 char *p = strrchr(path, ':');
820 if (p && mutt_str_startswith(p + 1, "2,"))
821 {
822 p += 3;
823
824 mutt_str_replace(&edata->maildir_flags, p);
825 q = edata->maildir_flags;
826
827 while (*p)
828 {
829 switch (*p)
830 {
831 case 'F':
832 e->flagged = true;
833 break;
834
835 case 'R': /* replied */
836 e->replied = true;
837 break;
838
839 case 'S': /* seen */
840 e->read = true;
841 break;
842
843 case 'T': /* trashed */
844 {
845 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
846 if (!e->flagged || !c_flag_safe)
847 {
848 e->trash = true;
849 e->deleted = true;
850 }
851 break;
852 }
853
854 default:
855 *q++ = *p;
856 break;
857 }
858 p++;
859 }
860 }
861
862 if (q == edata->maildir_flags)
863 FREE(&edata->maildir_flags);
864 else if (q)
865 *q = '\0';
866}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define FREE(x)
Definition: memory.h:43
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
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:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_parse_message()

struct Email * 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 (OPTIONAL)
Return values
ptrPopulated Email

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

Definition at line 928 of file maildir.c.

930{
931 FILE *fp = fopen(fname, "r");
932 if (!fp)
933 return NULL;
934
935 struct Email *e_res = maildir_parse_stream(type, fp, fname, is_old, e);
936 mutt_file_fclose(&fp);
937 return e_res;
938}
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
struct Email * maildir_parse_stream(enum MailboxType type, FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition: maildir.c:881
The envelope/body of an email.
Definition: email.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ maildir_parse_stream()

struct Email * 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
ptrPopulated Email
NULLon error

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 881 of file maildir.c.

883{
884 const long size = mutt_file_get_size_fp(fp);
885 if (size == 0)
886 {
887 return NULL;
888 }
889
890 if (!e)
891 {
892 e = email_new();
895 }
896 e->env = mutt_rfc822_read_header(fp, e, false, false);
897
898 if (e->received == 0)
899 e->received = e->date_sent;
900
901 /* always update the length since we have fresh information available. */
902 e->body->length = size - e->body->offset;
903
904 e->index = -1;
905
906 if (type == MUTT_MAILDIR)
907 {
908 /* maildir stores its flags in the filename, so ignore the
909 * flags in the header of the message */
910
911 e->old = is_old;
912 maildir_parse_flags(e, fname);
913 }
914 return e;
915}
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1569
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
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
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition: maildir.c:809
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1158
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
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:87
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:110
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,
int  msgno,
struct HeaderCache hc 
)

Save changes to the mailbox.

Parameters
mMailbox
msgnoIndex number
hcHeader cache handle
Return values
trueSuccess
falseError

Definition at line 948 of file maildir.c.

949{
950 struct Email *e = m->emails[msgno];
951 if (!e)
952 return false;
953
954 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
955 if (e->deleted && !c_maildir_trash)
956 {
957 char path[PATH_MAX] = { 0 };
958 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
959#ifdef USE_HCACHE
960 if (hc)
961 {
962 const char *key = e->path + 3;
963 size_t keylen = maildir_hcache_keylen(key);
964 mutt_hcache_delete_record(hc, key, keylen);
965 }
966#endif
967 unlink(path);
968 }
969 else if (e->changed || e->attach_del ||
970 ((c_maildir_trash || e->trash) && (e->deleted != e->trash)))
971 {
972 if (maildir_sync_message(m, msgno) == -1)
973 return false;
974 }
975
976#ifdef USE_HCACHE
977 if (hc && e->changed)
978 {
979 const char *key = e->path + 3;
980 size_t keylen = maildir_hcache_keylen(key);
981 mutt_hcache_store(hc, key, keylen, e, 0);
982 }
983#endif
984
985 return true;
986}
int mutt_hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:552
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:631
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:211
size_t maildir_hcache_keylen(const char *fn)
Calculate the length of the Maildir path.
Definition: maildir.c:585
int maildir_sync_message(struct Mailbox *m, int msgno)
Sync an email to a Maildir folder.
Definition: maildir.c:387
bool changed
Email has been edited.
Definition: email.h:75
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:99
int msgno
Number displayed to the user.
Definition: email.h:111
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
+ 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 122 of file shared.c.

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

◆ mh_check_empty()

int mh_check_empty ( const char *  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
171 DIR *dp = opendir(path);
172 if (!dp)
173 return -1;
174 while ((de = readdir(dp)))
175 {
176 if (mh_valid_message(de->d_name))
177 {
178 rc = 0;
179 break;
180 }
181 }
182 closedir(dp);
183
184 return rc;
185}
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,
int  msgno,
struct HeaderCache hc 
)

Save changes to the mailbox.

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

Definition at line 756 of file mh.c.

757{
758 if (!m || !m->emails || (msgno >= m->msg_count))
759 return -1;
760
761 struct Email *e = m->emails[msgno];
762 if (!e)
763 return -1;
764
765 if (e->deleted)
766 {
767 char path[PATH_MAX] = { 0 };
768 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
769 const bool c_mh_purge = cs_subset_bool(NeoMutt->sub, "mh_purge");
770 if (c_mh_purge)
771 {
772#ifdef USE_HCACHE
773 if (hc)
774 {
775 const char *key = e->path;
776 size_t keylen = strlen(key);
777 mutt_hcache_delete_record(hc, key, keylen);
778 }
779#endif
780 unlink(path);
781 }
782 else
783 {
784 /* MH just moves files out of the way when you delete them */
785 if (*e->path != ',')
786 {
787 char tmp[PATH_MAX] = { 0 };
788 snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
789 unlink(tmp);
790 if (rename(path, tmp) != 0)
791 {
792 return -1;
793 }
794 }
795 }
796 }
797 else if (e->changed || e->attach_del)
798 {
799 if (mh_sync_message(m, msgno) == -1)
800 return -1;
801 }
802
803#ifdef USE_HCACHE
804 if (hc && e->changed)
805 {
806 const char *key = e->path;
807 size_t keylen = strlen(key);
808 mutt_hcache_store(hc, key, keylen, e, 0);
809 }
810#endif
811
812 return 0;
813}
int mh_sync_message(struct Mailbox *m, int msgno)
Sync an email to an MH folder.
Definition: mh.c:451
int msg_count
Total number of messages.
Definition: mailbox.h:88
+ Here is the call graph for this function:
+ Here is the caller graph for this function: