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