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