NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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.
 
#define MH_SEQ_UNSEEN   (1 << 0)
 Email hasn't been read.
 
#define MH_SEQ_REPLIED   (1 << 1)
 Email has been replied to.
 
#define MH_SEQ_FLAGGED   (1 << 2)
 Email is flagged.
 

Typedefs

typedef uint8_t MhSeqFlags
 Flags, e.g. MH_SEQ_UNSEEN.
 

Functions

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

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_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 110 of file sequence.c.

111{
112 bool unseen_done = false;
113 bool flagged_done = false;
114 bool replied_done = false;
115
116 char *tmpfname = NULL;
117 char sequences[PATH_MAX] = { 0 };
118
119 char seq_unseen[256] = { 0 };
120 char seq_replied[256] = { 0 };
121 char seq_flagged[256] = { 0 };
122
123 char *buf = NULL;
124 size_t sz;
125
126 FILE *fp_new = NULL;
127 if (!mh_mkstemp(m, &fp_new, &tmpfname))
128 return;
129
130 const char *const c_mh_seq_unseen = cs_subset_string(NeoMutt->sub, "mh_seq_unseen");
131 const char *const c_mh_seq_replied = cs_subset_string(NeoMutt->sub, "mh_seq_replied");
132 const char *const c_mh_seq_flagged = 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 = mutt_file_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 {
160 fprintf(fp_new, "%s\n", buf);
161 }
162 }
163 }
164 mutt_file_fclose(&fp_old);
165 FREE(&buf);
166
167 if (!unseen_done && unseen)
168 fprintf(fp_new, "%s: %d\n", NONULL(c_mh_seq_unseen), n);
169 if (!flagged_done && flagged)
170 fprintf(fp_new, "%s: %d\n", NONULL(c_mh_seq_flagged), n);
171 if (!replied_done && replied)
172 fprintf(fp_new, "%s: %d\n", NONULL(c_mh_seq_replied), n);
173
174 mutt_file_fclose(&fp_new);
175
176 unlink(sequences);
177 if (mutt_file_safe_rename(tmpfname, sequences) != 0)
178 unlink(tmpfname);
179
180 FREE(&tmpfname);
181}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:213
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:678
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition file.c:310
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition file.h:40
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
bool mh_mkstemp(struct Mailbox *m, FILE **fp, char **tgt)
Create a temporary file.
Definition shared.c:73
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:429
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
#define PATH_MAX
Definition mutt.h:49
#define NONULL(x)
Definition string2.h:44
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ 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 441 of file sequence.c.

442{
443 char path[PATH_MAX] = { 0 };
444 struct stat st = { 0 };
445
446 if ((snprintf(path, sizeof(path), "%s/.mh_sequences", mailbox_path(m)) < sizeof(path)) &&
447 (stat(path, &st) == 0))
448 {
450 }
451 return -1;
452}
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:1514
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition file.h:54
struct timespec last_visited
Time of last exit from this mailbox.
Definition mailbox.h:103
+ Here is the call graph for this function:
+ Here is the caller 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 79 of file sequence.c.

80{
81 if ((i < 0) || !mhs->flags || (i > mhs->max))
82 return 0;
83 return mhs->flags[i];
84}
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 68 of file sequence.c.

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

◆ 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 380 of file sequence.c.

381{
382 char *buf = NULL;
383 size_t sz = 0;
384
385 MhSeqFlags flags;
386 int first, last, rc = 0;
387
388 char pathname[PATH_MAX] = { 0 };
389 snprintf(pathname, sizeof(pathname), "%s/.mh_sequences", path);
390
391 FILE *fp = mutt_file_fopen(pathname, "r");
392 if (!fp)
393 return 0; /* yes, ask callers to silently ignore the error */
394
395 const char *const c_mh_seq_unseen = cs_subset_string(NeoMutt->sub, "mh_seq_unseen");
396 const char *const c_mh_seq_flagged = cs_subset_string(NeoMutt->sub, "mh_seq_flagged");
397 const char *const c_mh_seq_replied = cs_subset_string(NeoMutt->sub, "mh_seq_replied");
398 while ((buf = mutt_file_read_line(buf, &sz, fp, NULL, MUTT_RL_NO_FLAGS)))
399 {
400 char *t = strtok(buf, " \t:");
401 if (!t)
402 continue;
403
404 if (mutt_str_equal(t, c_mh_seq_unseen))
405 flags = MH_SEQ_UNSEEN;
406 else if (mutt_str_equal(t, c_mh_seq_flagged))
407 flags = MH_SEQ_FLAGGED;
408 else if (mutt_str_equal(t, c_mh_seq_replied))
409 flags = MH_SEQ_REPLIED;
410 else /* unknown sequence */
411 continue;
412
413 while ((t = strtok(NULL, " \t:")))
414 {
415 if (mh_seq_read_token(t, &first, &last) < 0)
416 {
417 mh_seq_free(mhs);
418 rc = -1;
419 goto out;
420 }
421 for (; first <= last; first++)
422 mh_seq_set(mhs, first, flags);
423 }
424 }
425
426 rc = 0;
427
428out:
429 FREE(&buf);
430 mutt_file_fclose(&fp);
431 return rc;
432}
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
void mh_seq_free(struct MhSequences *mhs)
Free some sequences.
Definition sequence.c:68
static MhSeqFlags mh_seq_set(struct MhSequences *mhs, int i, MhSeqFlags f)
Set a flag for a given sequence.
Definition sequence.c:93
static int mh_seq_read_token(char *t, int *first, int *last)
Parse a number, or number range.
Definition sequence.c:355
#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:31
#define MH_SEQ_FLAGGED
Email is flagged.
Definition sequence.h:35
+ Here is the call graph for this function:
+ Here is the caller 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 236 of file sequence.c.

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