1 /* seq_save.c -- 1) synchronize sequences
2 * -- 2) save public sequences
3 *
4 * This code is Copyright (c) 2002, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <h/signals.h>
11 #include "lock_file.h"
12 #include "m_mktemp.h"
13
14
15 /*
16 * 1. If sequence is public and folder is readonly,
17 * then change it to be private
18 * 2a. If sequence is public, then add it to the sequences file
19 * in folder (name specified by mh-sequences profile entry).
20 * 2b. If sequence is private, then add it to the
21 * context file.
22 */
23
24 void
seq_save(struct msgs * mp)25 seq_save (struct msgs *mp)
26 {
27 size_t i;
28 char flags, *cp, attr[BUFSIZ], seqfile[PATH_MAX];
29 FILE *fp;
30 sigset_t set, oset;
31
32 /* check if sequence information has changed */
33 if (!(mp->msgflags & SEQMOD)) {
34 if (mp->seqhandle) {
35 lkfclosedata (mp->seqhandle, mp->seqname);
36 mp->seqhandle = NULL;
37 free(mp->seqname);
38 mp->seqname = NULL;
39 }
40 return;
41 }
42 mp->msgflags &= ~SEQMOD;
43
44 fp = NULL;
45 flags = mp->msgflags; /* record folder flags */
46
47 /*
48 * If no mh-sequences file is defined, or if a mh-sequences file
49 * is defined but empty (*mh_seq == '\0'), then pretend folder
50 * is readonly. This will force all sequences to be private.
51 */
52 if (mh_seq == NULL || *mh_seq == '\0')
53 set_readonly (mp);
54 else
55 snprintf (seqfile, sizeof(seqfile), "%s/%s", mp->foldpath, mh_seq);
56
57 for (i = 0; i < svector_size (mp->msgattrs); i++) {
58 snprintf (attr, sizeof(attr), "atr-%s-%s",
59 svector_at (mp->msgattrs, i), mp->foldpath);
60
61 /* get space separated list of sequence ranges */
62 if (!(cp = seq_list(mp, svector_at (mp->msgattrs, i)))) {
63 context_del (attr); /* delete sequence from context */
64 continue;
65 }
66
67 if (is_readonly(mp) || is_seq_private(mp, i)) {
68 priv:
69 /*
70 * sequence is private
71 */
72 context_replace (attr, cp); /* update sequence in context */
73 } else {
74 /*
75 * sequence is public
76 */
77 context_del (attr); /* delete sequence from context */
78
79 if (!fp) {
80 int failed_to_lock = 0;
81
82 /*
83 * Attempt to open file for public sequences.
84 * If that fails (probably because folder is
85 * readonly), then make sequence private.
86 */
87
88 if (mp->seqhandle) {
89 fp = mp->seqhandle;
90 mp->seqhandle = NULL;
91 free(mp->seqname);
92 mp->seqname = NULL;
93 rewind(fp);
94 if (ftruncate(fileno(fp), 0) < 0) {
95 advise ("sequence file", "ftruncate");
96 }
97 } else if ((fp = lkfopendata (seqfile, "w", &failed_to_lock))
98 == NULL
99 && (m_unlink (seqfile) == -1 ||
100 (fp = lkfopendata (seqfile, "w", &failed_to_lock))
101 == NULL)) {
102 if (failed_to_lock) {
103 admonish (attr, "unable to lock");
104 } else {
105 admonish (attr, "unable to write");
106 }
107 goto priv;
108 }
109
110 /* block a few signals */
111 sigemptyset (&set);
112 sigaddset(&set, SIGHUP);
113 sigaddset(&set, SIGINT);
114 sigaddset(&set, SIGQUIT);
115 sigaddset(&set, SIGTERM);
116 sigprocmask (SIG_BLOCK, &set, &oset);
117 }
118 fprintf (fp, "%s: %s\n", svector_at (mp->msgattrs, i), cp);
119 }
120 }
121
122 if (fp) {
123 lkfclosedata (fp, seqfile);
124 sigprocmask (SIG_SETMASK, &oset, &set); /* reset signal mask */
125 } else {
126 /*
127 * If folder is not readonly, and we didn't save any
128 * public sequences, then remove that file.
129 */
130 if (!is_readonly(mp))
131 (void) m_unlink (seqfile);
132 }
133
134 /*
135 * Reset folder flag, since we may be
136 * pretending that folder is readonly.
137 */
138 mp->msgflags = flags;
139 }
140