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