NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
sequence.c File Reference

MH Mailbox Sequences. More...

#include "config.h"
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "sequence.h"
+ Include dependency graph for sequence.c:

Go to the source code of this file.

Functions

static void mh_seq_alloc (struct MhSequences *mhs, int i)
 Allocate more memory for sequences.
 
void mh_seq_free (struct MhSequences *mhs)
 Free some sequences.
 
MhSeqFlags mh_seq_check (struct MhSequences *mhs, int i)
 Get the flags for a given sequence.
 
static MhSeqFlags mh_seq_set (struct MhSequences *mhs, int i, MhSeqFlags f)
 Set a flag for a given sequence.
 
void mh_seq_add_one (struct Mailbox *m, int n, bool unseen, bool flagged, bool replied)
 Update the flags for one sequence.
 
static void mh_seq_write_one (FILE *fp, struct MhSequences *mhs, MhSeqFlags f, const char *tag)
 Write a flag sequence to a file.
 
void mh_seq_update (struct Mailbox *m)
 Update sequence numbers.
 
static int mh_seq_read_token (char *t, int *first, int *last)
 Parse a number, or number range.
 
int mh_seq_read (struct MhSequences *mhs, const char *path)
 Read a set of MH sequences.
 
int mh_seq_changed (struct Mailbox *m)
 Has the mailbox changed.
 

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.c.

Function Documentation

◆ mh_seq_alloc()

static void mh_seq_alloc ( struct MhSequences mhs,
int  i 
)
static

Allocate more memory for sequences.

Parameters
mhsExisting sequences
iNumber required
Note
Memory is allocated in blocks of 128.

Definition at line 49 of file sequence.c.

50{
51 if ((i <= mhs->max) && mhs->flags)
52 return;
53
54 const int newmax = i + 128;
55 int j = mhs->flags ? mhs->max + 1 : 0;
56 mutt_mem_realloc(&mhs->flags, sizeof(mhs->flags[0]) * (newmax + 1));
57 while (j <= newmax)
58 mhs->flags[j++] = 0;
59
60 mhs->max = newmax;
61}
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
MhSeqFlags * flags
Flags for each email.
Definition: sequence.h:43
int max
Number of flags stored.
Definition: sequence.h:42
+ Here is the call graph for this function:
+ 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}
#define FREE(x)
Definition: memory.h:45
+ 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 78 of file sequence.c.

79{
80 if (!mhs->flags || (i > mhs->max))
81 return 0;
82 return mhs->flags[i];
83}
+ Here is the caller graph for this function:

◆ mh_seq_set()

static MhSeqFlags mh_seq_set ( struct MhSequences mhs,
int  i,
MhSeqFlags  f 
)
static

Set a flag for a given sequence.

Parameters
mhsSequences
iIndex number
fFlags, see MhSeqFlags
Return values
numResulting flags, see MhSeqFlags

Definition at line 92 of file sequence.c.

93{
94 mh_seq_alloc(mhs, i);
95 mhs->flags[i] |= f;
96 return mhs->flags[i];
97}
static void mh_seq_alloc(struct MhSequences *mhs, int i)
Allocate more memory for sequences.
Definition: sequence.c:49
+ 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] = { 0 };
115
116 char seq_unseen[256] = { 0 };
117 char seq_replied[256] = { 0 };
118 char seq_flagged[256] = { 0 };
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 = cs_subset_string(NeoMutt->sub, "mh_seq_unseen");
128 const char *const c_mh_seq_replied = cs_subset_string(NeoMutt->sub, "mh_seq_replied");
129 const char *const c_mh_seq_flagged = cs_subset_string(NeoMutt->sub, "mh_seq_flagged");
130 snprintf(seq_unseen, sizeof(seq_unseen), "%s:", NONULL(c_mh_seq_unseen));
131 snprintf(seq_replied, sizeof(seq_replied), "%s:", NONULL(c_mh_seq_replied));
132 snprintf(seq_flagged, sizeof(seq_flagged), "%s:", NONULL(c_mh_seq_flagged));
133
134 snprintf(sequences, sizeof(sequences), "%s/.mh_sequences", mailbox_path(m));
135 FILE *fp_old = fopen(sequences, "r");
136 if (fp_old)
137 {
138 while ((buf = mutt_file_read_line(buf, &sz, fp_old, NULL, MUTT_RL_NO_FLAGS)))
139 {
140 if (unseen && mutt_strn_equal(buf, seq_unseen, mutt_str_len(seq_unseen)))
141 {
142 fprintf(fp_new, "%s %d\n", buf, n);
143 unseen_done = true;
144 }
145 else if (flagged && mutt_strn_equal(buf, seq_flagged, mutt_str_len(seq_flagged)))
146 {
147 fprintf(fp_new, "%s %d\n", buf, n);
148 flagged_done = true;
149 }
150 else if (replied && mutt_strn_equal(buf, seq_replied, mutt_str_len(seq_replied)))
151 {
152 fprintf(fp_new, "%s %d\n", buf, n);
153 replied_done = true;
154 }
155 else
156 {
157 fprintf(fp_new, "%s\n", buf);
158 }
159 }
160 }
161 mutt_file_fclose(&fp_old);
162 FREE(&buf);
163
164 if (!unseen_done && unseen)
165 fprintf(fp_new, "%s: %d\n", NONULL(c_mh_seq_unseen), n);
166 if (!flagged_done && flagged)
167 fprintf(fp_new, "%s: %d\n", NONULL(c_mh_seq_flagged), n);
168 if (!replied_done && replied)
169 fprintf(fp_new, "%s: %d\n", NONULL(c_mh_seq_replied), n);
170
171 mutt_file_fclose(&fp_new);
172
173 unlink(sequences);
174 if (mutt_file_safe_rename(tmpfname, sequences) != 0)
175 unlink(tmpfname);
176
177 FREE(&tmpfname);
178}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
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:763
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:346
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:39
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
bool mh_mkstemp(struct Mailbox *m, FILE **fp, char **tgt)
Create a temporary file.
Definition: mh.c:78
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:497
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
#define PATH_MAX
Definition: mutt.h:41
#define NONULL(x)
Definition: string2.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mh_seq_write_one()

static void mh_seq_write_one ( FILE *  fp,
struct MhSequences mhs,
MhSeqFlags  f,
const char *  tag 
)
static

Write a flag sequence to a file.

Parameters
fpFile to write to
mhsSequence list
fFlag, see MhSeqFlags
tagstring tag, e.g. "unseen"

Definition at line 187 of file sequence.c.

188{
189 fprintf(fp, "%s:", tag);
190
191 int first = -1;
192 int last = -1;
193
194 for (int i = 0; i <= mhs->max; i++)
195 {
196 if ((mh_seq_check(mhs, i) & f))
197 {
198 if (first < 0)
199 first = i;
200 else
201 last = i;
202 }
203 else if (first >= 0)
204 {
205 if (last < 0)
206 fprintf(fp, " %d", first);
207 else
208 fprintf(fp, " %d-%d", first, last);
209
210 first = -1;
211 last = -1;
212 }
213 }
214
215 if (first >= 0)
216 {
217 if (last < 0)
218 fprintf(fp, " %d", first);
219 else
220 fprintf(fp, " %d-%d", first, last);
221 }
222
223 fputc('\n', fp);
224}
MhSeqFlags mh_seq_check(struct MhSequences *mhs, int i)
Get the flags for a given sequence.
Definition: sequence.c:78
+ 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 233 of file sequence.c.

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

◆ mh_seq_read_token()

static int mh_seq_read_token ( char *  t,
int *  first,
int *  last 
)
static

Parse a number, or number range.

Parameters
tString to parse
firstFirst number
lastLast number (if a range, first number if not)
Return values
0Success
-1Error

Definition at line 352 of file sequence.c.

353{
354 char *p = strchr(t, '-');
355 if (p)
356 {
357 *p++ = '\0';
358 if (!mutt_str_atoi_full(t, first) || !mutt_str_atoi_full(p, last))
359 return -1;
360 }
361 else
362 {
363 if (!mutt_str_atoi_full(t, first))
364 return -1;
365 *last = *first;
366 }
367 return 0;
368}
+ 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 377 of file sequence.c.

378{
379 char *buf = NULL;
380 size_t sz = 0;
381
382 MhSeqFlags flags;
383 int first, last, rc = 0;
384
385 char pathname[PATH_MAX] = { 0 };
386 snprintf(pathname, sizeof(pathname), "%s/.mh_sequences", path);
387
388 FILE *fp = fopen(pathname, "r");
389 if (!fp)
390 return 0; /* yes, ask callers to silently ignore the error */
391
392 const char *const c_mh_seq_unseen = cs_subset_string(NeoMutt->sub, "mh_seq_unseen");
393 const char *const c_mh_seq_flagged = cs_subset_string(NeoMutt->sub, "mh_seq_flagged");
394 const char *const c_mh_seq_replied = cs_subset_string(NeoMutt->sub, "mh_seq_replied");
395 while ((buf = mutt_file_read_line(buf, &sz, fp, NULL, MUTT_RL_NO_FLAGS)))
396 {
397 char *t = strtok(buf, " \t:");
398 if (!t)
399 continue;
400
401 if (mutt_str_equal(t, c_mh_seq_unseen))
402 flags = MH_SEQ_UNSEEN;
403 else if (mutt_str_equal(t, c_mh_seq_flagged))
404 flags = MH_SEQ_FLAGGED;
405 else if (mutt_str_equal(t, c_mh_seq_replied))
406 flags = MH_SEQ_REPLIED;
407 else /* unknown sequence */
408 continue;
409
410 while ((t = strtok(NULL, " \t:")))
411 {
412 if (mh_seq_read_token(t, &first, &last) < 0)
413 {
414 mh_seq_free(mhs);
415 rc = -1;
416 goto out;
417 }
418 for (; first <= last; first++)
419 mh_seq_set(mhs, first, flags);
420 }
421 }
422
423 rc = 0;
424
425out:
426 FREE(&buf);
427 mutt_file_fclose(&fp);
428 return rc;
429}
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
static int mh_seq_read_token(char *t, int *first, int *last)
Parse a number, or number range.
Definition: sequence.c:352
uint8_t MhSeqFlags
Flags, e.g. MH_SEQ_UNSEEN.
Definition: sequence.h:31
+ 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 438 of file sequence.c.

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