NeoMutt  2021-10-29-43-g6b8931
Teaching an old dog new tricks
DOXYGEN
sequence.h File Reference

MH Mailbox Sequences. More...

#include <stdbool.h>
#include <stdint.h>
+ Include dependency graph for sequence.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  MhSequences
 Set of MH sequence numbers. More...
 

Macros

#define MH_SEQ_NO_FLAGS   0
 No flags are set. More...
 
#define MH_SEQ_UNSEEN   (1 << 0)
 Email hasn't been read. More...
 
#define MH_SEQ_REPLIED   (1 << 1)
 Email has been replied to. More...
 
#define MH_SEQ_FLAGGED   (1 << 2)
 Email is flagged. More...
 

Typedefs

typedef uint8_t MhSeqFlags
 Flags, e.g. MH_SEQ_UNSEEN. More...
 

Functions

int mh_seq_read (struct MhSequences *mhs, const char *path)
 Read a set of MH sequences. More...
 
void mh_seq_add_one (struct Mailbox *m, int n, bool unseen, bool flagged, bool replied)
 Update the flags for one sequence. More...
 
int mh_seq_changed (struct Mailbox *m)
 Has the mailbox changed. More...
 
void mh_seq_update (struct Mailbox *m)
 Update sequence numbers. More...
 
MhSeqFlags mh_seq_check (struct MhSequences *mhs, int i)
 Get the flags for a given sequence. More...
 
void mh_seq_free (struct MhSequences *mhs)
 Free some sequences. More...
 

Detailed Description

MH Mailbox Sequences.

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 sequence.h.

Macro Definition Documentation

◆ MH_SEQ_NO_FLAGS

#define MH_SEQ_NO_FLAGS   0

No flags are set.

Definition at line 32 of file sequence.h.

◆ MH_SEQ_UNSEEN

#define MH_SEQ_UNSEEN   (1 << 0)

Email hasn't been read.

Definition at line 33 of file sequence.h.

◆ MH_SEQ_REPLIED

#define MH_SEQ_REPLIED   (1 << 1)

Email has been replied to.

Definition at line 34 of file sequence.h.

◆ MH_SEQ_FLAGGED

#define MH_SEQ_FLAGGED   (1 << 2)

Email is flagged.

Definition at line 35 of file sequence.h.

Typedef Documentation

◆ MhSeqFlags

typedef uint8_t MhSeqFlags

Flags, e.g. MH_SEQ_UNSEEN.

Definition at line 31 of file sequence.h.

Function Documentation

◆ mh_seq_read()

int mh_seq_read ( struct MhSequences mhs,
const char *  path 
)

Read a set of MH sequences.

Parameters
mhsExisting sequences
pathFile to read from
Return values
0Success
-1Error

Definition at line 381 of file sequence.c.

382 {
383  char *buf = NULL;
384  size_t sz = 0;
385 
386  MhSeqFlags flags;
387  int first, last, rc = 0;
388 
389  char pathname[PATH_MAX];
390  snprintf(pathname, sizeof(pathname), "%s/.mh_sequences", path);
391 
392  FILE *fp = fopen(pathname, "r");
393  if (!fp)
394  return 0; /* yes, ask callers to silently ignore the error */
395 
396  while ((buf = mutt_file_read_line(buf, &sz, fp, NULL, MUTT_RL_NO_FLAGS)))
397  {
398  char *t = strtok(buf, " \t:");
399  if (!t)
400  continue;
401 
402  const char *const c_mh_seq_unseen =
403  cs_subset_string(NeoMutt->sub, "mh_seq_unseen");
404  const char *const c_mh_seq_flagged =
405  cs_subset_string(NeoMutt->sub, "mh_seq_flagged");
406  const char *const c_mh_seq_replied =
407  cs_subset_string(NeoMutt->sub, "mh_seq_replied");
408  if (mutt_str_equal(t, c_mh_seq_unseen))
409  flags = MH_SEQ_UNSEEN;
410  else if (mutt_str_equal(t, c_mh_seq_flagged))
411  flags = MH_SEQ_FLAGGED;
412  else if (mutt_str_equal(t, c_mh_seq_replied))
413  flags = MH_SEQ_REPLIED;
414  else /* unknown sequence */
415  continue;
416 
417  while ((t = strtok(NULL, " \t:")))
418  {
419  if (mh_seq_read_token(t, &first, &last) < 0)
420  {
421  mh_seq_free(mhs);
422  rc = -1;
423  goto out;
424  }
425  for (; first <= last; first++)
426  mh_seq_set(mhs, first, flags);
427  }
428  }
429 
430  rc = 0;
431 
432 out:
433  FREE(&buf);
434  mutt_file_fclose(&fp);
435  return rc;
436 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:695
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define FREE(x)
Definition: memory.h:40
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:715
#define PATH_MAX
Definition: mutt.h:40
MhSeqFlags mh_seq_set(struct MhSequences *mhs, int i, MhSeqFlags f)
Set a flag for a given sequence.
Definition: sequence.c:92
void mh_seq_free(struct MhSequences *mhs)
Free some sequences.
Definition: sequence.c:67
static int mh_seq_read_token(char *t, int *first, int *last)
Parse a number, or number range.
Definition: sequence.c:356
#define MH_SEQ_UNSEEN
Email hasn't been read.
Definition: sequence.h:33
#define MH_SEQ_REPLIED
Email has been replied to.
Definition: sequence.h:34
uint8_t MhSeqFlags
Flags, e.g. MH_SEQ_UNSEEN.
Definition: sequence.h:29
#define MH_SEQ_FLAGGED
Email is flagged.
Definition: sequence.h:35
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:

◆ mh_seq_add_one()

void mh_seq_add_one ( struct Mailbox m,
int  n,
bool  unseen,
bool  flagged,
bool  replied 
)

Update the flags for one sequence.

Parameters
mMailbox
nSequence number to update
unseenUpdate the unseen sequence
flaggedUpdate the flagged sequence
repliedUpdate the replied sequence

Definition at line 107 of file sequence.c.

108 {
109  bool unseen_done = false;
110  bool flagged_done = false;
111  bool replied_done = false;
112 
113  char *tmpfname = NULL;
114  char sequences[PATH_MAX];
115 
116  char seq_unseen[256];
117  char seq_replied[256];
118  char seq_flagged[256];
119 
120  char *buf = NULL;
121  size_t sz;
122 
123  FILE *fp_new = NULL;
124  if (!mh_mkstemp(m, &fp_new, &tmpfname))
125  return;
126 
127  const char *const c_mh_seq_unseen =
128  cs_subset_string(NeoMutt->sub, "mh_seq_unseen");
129  const char *const c_mh_seq_replied =
130  cs_subset_string(NeoMutt->sub, "mh_seq_replied");
131  const char *const c_mh_seq_flagged =
132  cs_subset_string(NeoMutt->sub, "mh_seq_flagged");
133  snprintf(seq_unseen, sizeof(seq_unseen), "%s:", NONULL(c_mh_seq_unseen));
134  snprintf(seq_replied, sizeof(seq_replied), "%s:", NONULL(c_mh_seq_replied));
135  snprintf(seq_flagged, sizeof(seq_flagged), "%s:", NONULL(c_mh_seq_flagged));
136 
137  snprintf(sequences, sizeof(sequences), "%s/.mh_sequences", mailbox_path(m));
138  FILE *fp_old = fopen(sequences, "r");
139  if (fp_old)
140  {
141  while ((buf = mutt_file_read_line(buf, &sz, fp_old, NULL, MUTT_RL_NO_FLAGS)))
142  {
143  if (unseen && mutt_strn_equal(buf, seq_unseen, mutt_str_len(seq_unseen)))
144  {
145  fprintf(fp_new, "%s %d\n", buf, n);
146  unseen_done = true;
147  }
148  else if (flagged && mutt_strn_equal(buf, seq_flagged, mutt_str_len(seq_flagged)))
149  {
150  fprintf(fp_new, "%s %d\n", buf, n);
151  flagged_done = true;
152  }
153  else if (replied && mutt_strn_equal(buf, seq_replied, mutt_str_len(seq_replied)))
154  {
155  fprintf(fp_new, "%s %d\n", buf, n);
156  replied_done = true;
157  }
158  else
159  fprintf(fp_new, "%s\n", buf);
160  }
161  }
162  mutt_file_fclose(&fp_old);
163  FREE(&buf);
164 
165  if (!unseen_done && unseen)
166  fprintf(fp_new, "%s: %d\n", NONULL(c_mh_seq_unseen), n);
167  if (!flagged_done && flagged)
168  fprintf(fp_new, "%s: %d\n", NONULL(c_mh_seq_flagged), n);
169  if (!replied_done && replied)
170  fprintf(fp_new, "%s: %d\n", NONULL(c_mh_seq_replied), n);
171 
172  mutt_file_fclose(&fp_new);
173 
174  unlink(sequences);
175  if (mutt_file_safe_rename(tmpfname, sequences) != 0)
176  unlink(tmpfname);
177 
178  FREE(&tmpfname);
179 }
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:355
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:215
bool mh_mkstemp(struct Mailbox *m, FILE **fp, char **tgt)
Create a temporary file.
Definition: mh.c:77
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:404
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:475
#define NONULL(x)
Definition: string2.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_seq_changed()

int mh_seq_changed ( struct Mailbox m)

Has the mailbox changed.

Parameters
mMailbox
Return values
1mh_sequences last modification time is more recent than the last visit to this mailbox
0modification time is older
-1Error

Definition at line 445 of file sequence.c.

446 {
447  char path[PATH_MAX];
448  struct stat st = { 0 };
449 
450  if ((snprintf(path, sizeof(path), "%s/.mh_sequences", mailbox_path(m)) < sizeof(path)) &&
451  (stat(path, &st) == 0))
452  {
454  }
455  return -1;
456 }
int mutt_file_stat_timespec_compare(struct stat *st, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
Definition: file.c:1626
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:63
struct timespec last_visited
Time of last exit from this mailbox.
Definition: mailbox.h:108
+ Here is the call graph for this function:

◆ mh_seq_update()

void mh_seq_update ( struct Mailbox m)

Update sequence numbers.

Parameters
mMailbox

XXX we don't currently remove deleted messages from sequences we don't know. Should we?

Definition at line 234 of file sequence.c.

235 {
236  char sequences[PATH_MAX];
237  char *tmpfname = NULL;
238  char *buf = NULL;
239  char *p = NULL;
240  size_t s;
241  int seq_num = 0;
242 
243  int unseen = 0;
244  int flagged = 0;
245  int replied = 0;
246 
247  char seq_unseen[256];
248  char seq_replied[256];
249  char seq_flagged[256];
250 
251  struct MhSequences mhs = { 0 };
252 
253  const char *const c_mh_seq_unseen =
254  cs_subset_string(NeoMutt->sub, "mh_seq_unseen");
255  const char *const c_mh_seq_replied =
256  cs_subset_string(NeoMutt->sub, "mh_seq_replied");
257  const char *const c_mh_seq_flagged =
258  cs_subset_string(NeoMutt->sub, "mh_seq_flagged");
259  snprintf(seq_unseen, sizeof(seq_unseen), "%s:", NONULL(c_mh_seq_unseen));
260  snprintf(seq_replied, sizeof(seq_replied), "%s:", NONULL(c_mh_seq_replied));
261  snprintf(seq_flagged, sizeof(seq_flagged), "%s:", NONULL(c_mh_seq_flagged));
262 
263  FILE *fp_new = NULL;
264  if (!mh_mkstemp(m, &fp_new, &tmpfname))
265  {
266  /* error message? */
267  return;
268  }
269 
270  snprintf(sequences, sizeof(sequences), "%s/.mh_sequences", mailbox_path(m));
271 
272  /* first, copy unknown sequences */
273  FILE *fp_old = fopen(sequences, "r");
274  if (fp_old)
275  {
276  while ((buf = mutt_file_read_line(buf, &s, fp_old, NULL, MUTT_RL_NO_FLAGS)))
277  {
278  if (mutt_str_startswith(buf, seq_unseen) || mutt_str_startswith(buf, seq_flagged) ||
279  mutt_str_startswith(buf, seq_replied))
280  {
281  continue;
282  }
283 
284  fprintf(fp_new, "%s\n", buf);
285  }
286  }
287  mutt_file_fclose(&fp_old);
288 
289  /* now, update our unseen, flagged, and replied sequences */
290  for (int i = 0; i < m->msg_count; i++)
291  {
292  struct Email *e = m->emails[i];
293  if (!e)
294  break;
295 
296  if (e->deleted)
297  continue;
298 
299  p = strrchr(e->path, '/');
300  if (p)
301  p++;
302  else
303  p = e->path;
304 
305  if (!mutt_str_atoi_full(p, &seq_num))
306  continue;
307 
308  if (!e->read)
309  {
310  mh_seq_set(&mhs, seq_num, MH_SEQ_UNSEEN);
311  unseen++;
312  }
313  if (e->flagged)
314  {
315  mh_seq_set(&mhs, seq_num, MH_SEQ_FLAGGED);
316  flagged++;
317  }
318  if (e->replied)
319  {
320  mh_seq_set(&mhs, seq_num, MH_SEQ_REPLIED);
321  replied++;
322  }
323  }
324 
325  /* write out the new sequences */
326  if (unseen)
327  mh_seq_write_one(fp_new, &mhs, MH_SEQ_UNSEEN, NONULL(c_mh_seq_unseen));
328  if (flagged)
329  mh_seq_write_one(fp_new, &mhs, MH_SEQ_FLAGGED, NONULL(c_mh_seq_flagged));
330  if (replied)
331  mh_seq_write_one(fp_new, &mhs, MH_SEQ_REPLIED, NONULL(c_mh_seq_replied));
332 
333  mh_seq_free(&mhs);
334 
335  /* try to commit the changes - no guarantee here */
336  mutt_file_fclose(&fp_new);
337 
338  unlink(sequences);
339  if (mutt_file_safe_rename(tmpfname, sequences) != 0)
340  {
341  /* report an error? */
342  unlink(tmpfname);
343  }
344 
345  FREE(&tmpfname);
346 }
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:158
static void mh_seq_write_one(FILE *fp, struct MhSequences *mhs, MhSeqFlags f, const char *tag)
Write a flag sequence to a file.
Definition: sequence.c:188
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
bool deleted
Email is deleted.
Definition: email.h:76
int msg_count
Total number of messages.
Definition: mailbox.h:91
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Set of MH sequence numbers.
Definition: sequence.h:41
+ Here is the call graph for this function:

◆ mh_seq_check()

MhSeqFlags mh_seq_check ( struct MhSequences mhs,
int  i 
)

Get the flags for a given sequence.

Parameters
mhsSequences
iIndex number required
Return values
numFlags, see MhSeqFlags

Definition at line 78 of file sequence.c.

79 {
80  if (!mhs->flags || (i > mhs->max))
81  return 0;
82  return mhs->flags[i];
83 }
MhSeqFlags * flags
Flags for each email.
Definition: sequence.h:43
int max
Number of flags stored.
Definition: sequence.h:42
+ Here is the caller graph for this function:

◆ mh_seq_free()

void mh_seq_free ( struct MhSequences mhs)

Free some sequences.

Parameters
mhsSequences to free

Definition at line 67 of file sequence.c.

68 {
69  FREE(&mhs->flags);
70 }
+ Here is the caller graph for this function: