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