NeoMutt  2022-04-29-247-gc6aae8
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 1041 of file maildir.c.

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

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

809{
810 char *q = NULL;
811
812 e->flagged = false;
813 e->read = false;
814 e->replied = false;
815
817
818 char *p = strrchr(path, ':');
819 if (p && mutt_str_startswith(p + 1, "2,"))
820 {
821 p += 3;
822
823 mutt_str_replace(&edata->maildir_flags, p);
824 q = edata->maildir_flags;
825
826 while (*p)
827 {
828 switch (*p)
829 {
830 case 'F':
831 e->flagged = true;
832 break;
833
834 case 'R': /* replied */
835 e->replied = true;
836 break;
837
838 case 'S': /* seen */
839 e->read = true;
840 break;
841
842 case 'T': /* trashed */
843 {
844 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
845 if (!e->flagged || !c_flag_safe)
846 {
847 e->trash = true;
848 e->deleted = true;
849 }
850 break;
851 }
852
853 default:
854 *q++ = *p;
855 break;
856 }
857 p++;
858 }
859 }
860
861 if (q == edata->maildir_flags)
862 FREE(&edata->maildir_flags);
863 else if (q)
864 *q = '\0';
865}
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 927 of file maildir.c.

929{
930 FILE *fp = fopen(fname, "r");
931 if (!fp)
932 return NULL;
933
934 struct Email *e_res = maildir_parse_stream(type, fp, fname, is_old, e);
935 mutt_file_fclose(&fp);
936 return e_res;
937}
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:880
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 880 of file maildir.c.

882{
883 const long size = mutt_file_get_size_fp(fp);
884 if (size == 0)
885 {
886 return NULL;
887 }
888
889 if (!e)
890 {
891 e = email_new();
894 }
895 e->env = mutt_rfc822_read_header(fp, e, false, false);
896
897 if (e->received == 0)
898 e->received = e->date_sent;
899
900 /* always update the length since we have fresh information available. */
901 e->body->length = size - e->body->offset;
902
903 e->index = -1;
904
905 if (type == MUTT_MAILDIR)
906 {
907 /* maildir stores its flags in the filename, so ignore the
908 * flags in the header of the message */
909
910 e->old = is_old;
911 maildir_parse_flags(e, fname);
912 }
913 return e;
914}
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:808
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1157
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 947 of file maildir.c.

948{
949 struct Email *e = m->emails[msgno];
950 if (!e)
951 return false;
952
953 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
954 if (e->deleted && !c_maildir_trash)
955 {
956 char path[PATH_MAX] = { 0 };
957 snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
958#ifdef USE_HCACHE
959 if (hc)
960 {
961 const char *key = e->path + 3;
962 size_t keylen = maildir_hcache_keylen(key);
963 mutt_hcache_delete_record(hc, key, keylen);
964 }
965#endif
966 unlink(path);
967 }
968 else if (e->changed || e->attach_del ||
969 ((c_maildir_trash || e->trash) && (e->deleted != e->trash)))
970 {
971 if (maildir_sync_message(m, msgno) == -1)
972 return false;
973 }
974
975#ifdef USE_HCACHE
976 if (hc && e->changed)
977 {
978 const char *key = e->path + 3;
979 size_t keylen = maildir_hcache_keylen(key);
980 mutt_hcache_store(hc, key, keylen, e, 0);
981 }
982#endif
983
984 return true;
985}
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:210
size_t maildir_hcache_keylen(const char *fn)
Calculate the length of the Maildir path.
Definition: maildir.c:584
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:63
bool changed
Mailbox has been modified.
Definition: mailbox.h:110
+ 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: