NeoMutt  2021-02-05-666-ge300cd
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() -Open a new (temporary) message in a maildir folder. 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 1040 of file maildir.c.

1041 {
1042  DIR *dp = NULL;
1043  struct dirent *de = NULL;
1044  int rc = 1; /* assume empty until we find a message */
1045  char realpath[PATH_MAX];
1046  int iter = 0;
1047 
1048  /* Strategy here is to look for any file not beginning with a period */
1049 
1050  do
1051  {
1052  /* we do "cur" on the first iteration since it's more likely that we'll
1053  * find old messages without having to scan both subdirs */
1054  snprintf(realpath, sizeof(realpath), "%s/%s", path, (iter == 0) ? "cur" : "new");
1055  dp = opendir(realpath);
1056  if (!dp)
1057  return -1;
1058  while ((de = readdir(dp)))
1059  {
1060  if (*de->d_name != '.')
1061  {
1062  rc = 0;
1063  break;
1064  }
1065  }
1066  closedir(dp);
1067  iter++;
1068  } while (rc && iter < 2);
1069 
1070  return rc;
1071 }
#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];
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 }
#define NONULL(x)
Definition: string2.h:37
Maildir-specific Email data -.
Definition: edata.h:33
bool read
Email is read.
Definition: email.h:51
bool old
Email is seen, but unread.
Definition: email.h:50
static int ch_compare(const void *a, const void *b)
qsort callback to sort characters
Definition: maildir.c:175
bool flagged
Marked important?
Definition: email.h:43
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:111
bool replied
Email has been replied to.
Definition: email.h:54
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:64
char * maildir_flags
Unknown Maildir flags.
Definition: edata.h:35
+ 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 993 of file maildir.c.

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

812 {
813  char *q = NULL;
814 
815  e->flagged = false;
816  e->read = false;
817  e->replied = false;
818 
820 
821  char *p = strrchr(path, ':');
822  if (p && mutt_str_startswith(p + 1, "2,"))
823  {
824  p += 3;
825 
826  mutt_str_replace(&edata->maildir_flags, p);
827  q = edata->maildir_flags;
828 
829  while (*p)
830  {
831  switch (*p)
832  {
833  case 'F':
834  e->flagged = true;
835  break;
836 
837  case 'R': /* replied */
838  e->replied = true;
839  break;
840 
841  case 'S': /* seen */
842  e->read = true;
843  break;
844 
845  case 'T': /* trashed */
846  {
847  const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
848  if (!e->flagged || !c_flag_safe)
849  {
850  e->trash = true;
851  e->deleted = true;
852  }
853  break;
854  }
855 
856  default:
857  *q++ = *p;
858  break;
859  }
860  p++;
861  }
862  }
863 
864  if (q == edata->maildir_flags)
865  FREE(&edata->maildir_flags);
866  else if (q)
867  *q = '\0';
868 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Container for Accounts, Notifications.
Definition: neomutt.h:36
Maildir-specific Email data -.
Definition: edata.h:33
bool read
Email is read.
Definition: email.h:51
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:60
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
bool flagged
Marked important?
Definition: email.h:43
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:111
bool replied
Email has been replied to.
Definition: email.h:54
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
#define FREE(x)
Definition: memory.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct MaildirEmailData * maildir_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:64
char * maildir_flags
Unknown Maildir flags.
Definition: edata.h:35
+ 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 926 of file maildir.c.

928 {
929  FILE *fp = fopen(fname, "r");
930  if (!fp)
931  return NULL;
932 
933  e = maildir_parse_stream(type, fp, fname, is_old, e);
934  mutt_file_fclose(&fp);
935  return e;
936 }
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:882
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
+ 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

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

884 {
885  if (!e)
886  {
887  e = email_new();
888  e->edata = maildir_edata_new();
890  }
891  e->env = mutt_rfc822_read_header(fp, e, false, false);
892 
893  struct stat st;
894  fstat(fileno(fp), &st);
895 
896  if (!e->received)
897  e->received = e->date_sent;
898 
899  /* always update the length since we have fresh information available. */
900  e->body->length = st.st_size - e->body->offset;
901 
902  e->index = -1;
903 
904  if (type == MUTT_MAILDIR)
905  {
906  /* maildir stores its flags in the filename, so ignore the
907  * flags in the header of the message */
908 
909  e->old = is_old;
910  maildir_parse_flags(e, fname);
911  }
912  return e;
913 }
struct Body * body
List of MIME parts.
Definition: email.h:91
void maildir_parse_flags(struct Email *e, const char *path)
Parse Maildir file flags.
Definition: maildir.c:811
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
bool old
Email is seen, but unread.
Definition: email.h:50
struct Envelope * env
Envelope information.
Definition: email.h:90
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
struct MaildirEmailData * maildir_edata_new(void)
Create a new MaildirEmailData object.
Definition: edata.c:53
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:121
void * edata
Driver-specific data.
Definition: email.h:111
int index
The absolute (unsorted) message number.
Definition: email.h:86
void maildir_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1124
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
+ 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 946 of file maildir.c.

947 {
948  struct Email *e = m->emails[msgno];
949  if (!e)
950  return false;
951 
952  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
953  if (e->deleted && !c_maildir_trash)
954  {
955  char path[PATH_MAX];
956  snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
957 #ifdef USE_HCACHE
958  if (hc)
959  {
960  const char *key = e->path + 3;
961  size_t keylen = maildir_hcache_keylen(key);
962  mutt_hcache_delete_record(hc, key, keylen);
963  }
964 #endif
965  unlink(path);
966  }
967  else if (e->changed || e->attach_del ||
968  ((c_maildir_trash || e->trash) && (e->deleted != e->trash)))
969  {
970  if (maildir_sync_message(m, msgno) == -1)
971  return false;
972  }
973 
974 #ifdef USE_HCACHE
975  if (hc && e->changed)
976  {
977  const char *key = e->path + 3;
978  size_t keylen = maildir_hcache_keylen(key);
979  mutt_hcache_store(hc, key, keylen, e, 0);
980  }
981 #endif
982 
983  return true;
984 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
The envelope/body of an email.
Definition: email.h:37
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
bool changed
Email has been edited.
Definition: email.h:48
Container for Accounts, Notifications.
Definition: neomutt.h:36
size_t maildir_hcache_keylen(const char *fn)
Calculate the length of the Maildir path.
Definition: maildir.c:585
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:60
int maildir_sync_message(struct Mailbox *m, int msgno)
Sync an email to a Maildir folder.
Definition: maildir.c:387
#define PATH_MAX
Definition: mutt.h:40
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:637
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:556
bool deleted
Email is deleted.
Definition: email.h:45
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
int msgno
Number displayed to the user.
Definition: email.h:87
+ 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 }
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:66
Flagged messages.
Definition: mutt.h:98
bool changed
Email has been edited.
Definition: email.h:48
Messages that have been replied to.
Definition: mutt.h:91
bool read
Email is read.
Definition: email.h:51
bool old
Email is seen, but unread.
Definition: email.h:50
Old messages.
Definition: mutt.h:90
Messages that have been read.
Definition: mutt.h:92
bool flagged
Marked important?
Definition: email.h:43
bool replied
Email has been replied to.
Definition: email.h:54
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
+ 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 165 of file mh.c.

166 {
167  struct dirent *de = NULL;
168  int rc = 1; /* assume empty until we find a message */
169 
170  DIR *dp = opendir(path);
171  if (!dp)
172  return -1;
173  while ((de = readdir(dp)))
174  {
175  if (mh_valid_message(de->d_name))
176  {
177  rc = 0;
178  break;
179  }
180  }
181  closedir(dp);
182 
183  return rc;
184 }
bool mh_valid_message(const char *s)
Is this a valid MH message filename.
Definition: mh.c:148
+ 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 751 of file mh.c.

752 {
753  if (!m || !m->emails || (msgno >= m->msg_count))
754  return -1;
755 
756  struct Email *e = m->emails[msgno];
757  if (!e)
758  return -1;
759 
760  if (e->deleted)
761  {
762  char path[PATH_MAX];
763  snprintf(path, sizeof(path), "%s/%s", mailbox_path(m), e->path);
764  const bool c_mh_purge = cs_subset_bool(NeoMutt->sub, "mh_purge");
765  if (c_mh_purge)
766  {
767 #ifdef USE_HCACHE
768  if (hc)
769  {
770  const char *key = e->path;
771  size_t keylen = strlen(key);
772  mutt_hcache_delete_record(hc, key, keylen);
773  }
774 #endif
775  unlink(path);
776  }
777  else
778  {
779  /* MH just moves files out of the way when you delete them */
780  if (*e->path != ',')
781  {
782  char tmp[PATH_MAX];
783  snprintf(tmp, sizeof(tmp), "%s/,%s", mailbox_path(m), e->path);
784  unlink(tmp);
785  rename(path, tmp);
786  }
787  }
788  }
789  else if (e->changed || e->attach_del)
790  {
791  if (mh_sync_message(m, msgno) == -1)
792  return -1;
793  }
794 
795 #ifdef USE_HCACHE
796  if (hc && e->changed)
797  {
798  const char *key = e->path;
799  size_t keylen = strlen(key);
800  mutt_hcache_store(hc, key, keylen, e, 0);
801  }
802 #endif
803 
804  return 0;
805 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
int msg_count
Total number of messages.
Definition: mailbox.h:91
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
The envelope/body of an email.
Definition: email.h:37
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
bool changed
Email has been edited.
Definition: email.h:48
Container for Accounts, Notifications.
Definition: neomutt.h:36
int mh_sync_message(struct Mailbox *m, int msgno)
Sync an email to an MH folder.
Definition: mh.c:450
#define PATH_MAX
Definition: mutt.h:40
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:637
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:556
bool deleted
Email is deleted.
Definition: email.h:45
char * path
Path of Email (for local Mailboxes)
Definition: email.h:92
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
int msgno
Number displayed to the user.
Definition: email.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function: