]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.bin/mail/edit.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.bin / mail / edit.c
1 /*
2  * Copyright (c) 1980, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #ifndef lint
31 #if 0
32 static char sccsid[] = "@(#)edit.c      8.1 (Berkeley) 6/6/93";
33 #endif
34 #endif /* not lint */
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include "rcv.h"
39 #include <fcntl.h>
40 #include "extern.h"
41
42 /*
43  * Mail -- a mail program
44  *
45  * Perform message editing functions.
46  */
47
48 /*
49  * Edit a message list.
50  */
51 int
52 editor(int *msgvec)
53 {
54
55         return (edit1(msgvec, 'e'));
56 }
57
58 /*
59  * Invoke the visual editor on a message list.
60  */
61 int
62 visual(int *msgvec)
63 {
64
65         return (edit1(msgvec, 'v'));
66 }
67
68 /*
69  * Edit a message by writing the message into a funnily-named file
70  * (which should not exist) and forking an editor on it.
71  * We get the editor from the stuff above.
72  */
73 int
74 edit1(int *msgvec, int type)
75 {
76         int c, i;
77         FILE *fp;
78         struct message *mp;
79         off_t size;
80
81         /*
82          * Deal with each message to be edited . . .
83          */
84         for (i = 0; msgvec[i] && i < msgCount; i++) {
85                 sig_t sigint;
86
87                 if (i > 0) {
88                         char buf[100];
89                         char *p;
90
91                         printf("Edit message %d [ynq]? ", msgvec[i]);
92                         if (fgets(buf, sizeof(buf), stdin) == 0)
93                                 break;
94                         for (p = buf; *p == ' ' || *p == '\t'; p++)
95                                 ;
96                         if (*p == 'q')
97                                 break;
98                         if (*p == 'n')
99                                 continue;
100                 }
101                 dot = mp = &message[msgvec[i] - 1];
102                 touch(mp);
103                 sigint = signal(SIGINT, SIG_IGN);
104                 fp = run_editor(setinput(mp), mp->m_size, type, readonly);
105                 if (fp != NULL) {
106                         (void)fseeko(otf, (off_t)0, SEEK_END);
107                         size = ftello(otf);
108                         mp->m_block = blockof(size);
109                         mp->m_offset = boffsetof(size);
110                         mp->m_size = (long)fsize(fp);
111                         mp->m_lines = 0;
112                         mp->m_flag |= MODIFY;
113                         rewind(fp);
114                         while ((c = getc(fp)) != EOF) {
115                                 if (c == '\n')
116                                         mp->m_lines++;
117                                 if (putc(c, otf) == EOF)
118                                         break;
119                         }
120                         if (ferror(otf))
121                                 warnx("/tmp");
122                         (void)Fclose(fp);
123                 }
124                 (void)signal(SIGINT, sigint);
125         }
126         return (0);
127 }
128
129 /*
130  * Run an editor on the file at "fpp" of "size" bytes,
131  * and return a new file pointer.
132  * Signals must be handled by the caller.
133  * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI.
134  */
135 FILE *
136 run_editor(FILE *fp, off_t size, int type, int readonly)
137 {
138         FILE *nf = NULL;
139         int t;
140         time_t modtime;
141         char *edit, tempname[PATHSIZE];
142         struct stat statb;
143
144         (void)snprintf(tempname, sizeof(tempname),
145             "%s/mail.ReXXXXXXXXXX", tmpdir);
146         if ((t = mkstemp(tempname)) == -1 ||
147             (nf = Fdopen(t, "w")) == NULL) {
148                 warn("%s", tempname);
149                 goto out;
150         }
151         if (readonly && fchmod(t, 0400) == -1) {
152                 warn("%s", tempname);
153                 (void)rm(tempname);
154                 goto out;
155         }
156         if (size >= 0)
157                 while (--size >= 0 && (t = getc(fp)) != EOF)
158                         (void)putc(t, nf);
159         else
160                 while ((t = getc(fp)) != EOF)
161                         (void)putc(t, nf);
162         (void)fflush(nf);
163         if (fstat(fileno(nf), &statb) < 0)
164                 modtime = 0;
165         else
166                 modtime = statb.st_mtime;
167         if (ferror(nf)) {
168                 (void)Fclose(nf);
169                 warnx("%s", tempname);
170                 (void)rm(tempname);
171                 nf = NULL;
172                 goto out;
173         }
174         if (Fclose(nf) < 0) {
175                 warn("%s", tempname);
176                 (void)rm(tempname);
177                 nf = NULL;
178                 goto out;
179         }
180         nf = NULL;
181         if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL)
182                 edit = type == 'e' ? _PATH_EX : _PATH_VI;
183         if (run_command(edit, 0, -1, -1, tempname, NULL, NULL) < 0) {
184                 (void)rm(tempname);
185                 goto out;
186         }
187         /*
188          * If in read only mode or file unchanged, just remove the editor
189          * temporary and return.
190          */
191         if (readonly) {
192                 (void)rm(tempname);
193                 goto out;
194         }
195         if (stat(tempname, &statb) < 0) {
196                 warn("%s", tempname);
197                 goto out;
198         }
199         if (modtime == statb.st_mtime) {
200                 (void)rm(tempname);
201                 goto out;
202         }
203         /*
204          * Now switch to new file.
205          */
206         if ((nf = Fopen(tempname, "a+")) == NULL) {
207                 warn("%s", tempname);
208                 (void)rm(tempname);
209                 goto out;
210         }
211         (void)rm(tempname);
212 out:
213         return (nf);
214 }