]> diplodocus.org Git - nmh/blob - uip/rcvstore.c
3159d1d24eaeb8ad7e326cc434e304b6357fceb1
[nmh] / uip / rcvstore.c
1 /* rcvstore.c -- asynchronously add mail to a folder
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include "h/mh.h"
9 #include "sbr/folder_addmsg.h"
10 #include "sbr/context_save.h"
11 #include "sbr/context_find.h"
12 #include "sbr/ambigsw.h"
13 #include "sbr/path.h"
14 #include "sbr/print_version.h"
15 #include "sbr/print_help.h"
16 #include "sbr/seq_add.h"
17 #include "sbr/error.h"
18 #include <fcntl.h>
19 #include "h/signals.h"
20 #include "h/mts.h"
21 #include "h/done.h"
22 #include "h/utils.h"
23 #include "sbr/m_maildir.h"
24 #include "sbr/m_mktemp.h"
25 #include "sbr/makedir.h"
26
27 #define RCVSTORE_SWITCHES \
28 X("create", 0, CRETSW) \
29 X("nocreate", 0, NCRETSW) \
30 X("unseen", 0, UNSEENSW) \
31 X("nounseen", 0, NUNSEENSW) \
32 X("public", 0, PUBSW) \
33 X("nopublic", 0, NPUBSW) \
34 X("zero", 0, ZEROSW) \
35 X("nozero", 0, NZEROSW) \
36 X("sequence name", 0, SEQSW) \
37 X("version", 0, VERSIONSW) \
38 X("help", 0, HELPSW) \
39
40 #define X(sw, minchars, id) id,
41 DEFINE_SWITCH_ENUM(RCVSTORE);
42 #undef X
43
44 #define X(sw, minchars, id) { sw, minchars, id },
45 DEFINE_SWITCH_ARRAY(RCVSTORE, switches);
46 #undef X
47
48
49 /*
50 * name of temporary file to store incoming message
51 */
52 static char *tmpfilenam = NULL;
53
54 static void unlink_done(int) NORETURN;
55
56 int
57 main (int argc, char **argv)
58 {
59 int publicsw = -1;
60 bool zerosw = false;
61 bool create = true;
62 bool unseensw = true;
63 int fd, msgnum;
64 size_t seqp = 0;
65 char *cp, *maildir, *folder = NULL, buf[BUFSIZ];
66 char **argp, **arguments;
67 svector_t seqs = svector_create (0);
68 struct msgs *mp;
69 struct stat st;
70
71 if (nmh_init(argv[0], true, false)) { return 1; }
72
73 set_done(unlink_done);
74
75 mts_init ();
76 arguments = getarguments (invo_name, argc, argv, 1);
77 argp = arguments;
78
79 /* parse arguments */
80 while ((cp = *argp++)) {
81 if (*cp == '-') {
82 switch (smatch (++cp, switches)) {
83 case AMBIGSW:
84 ambigsw (cp, switches);
85 done (1);
86 case UNKWNSW:
87 die("-%s unknown", cp);
88
89 case HELPSW:
90 snprintf (buf, sizeof(buf), "%s [+folder] [switches]",
91 invo_name);
92 print_help (buf, switches, 1);
93 done (0);
94 case VERSIONSW:
95 print_version(invo_name);
96 done (0);
97
98 case SEQSW:
99 if (!(cp = *argp++) || *cp == '-')
100 die("missing argument name to %s", argp[-2]);
101
102 svector_push_back (seqs, cp);
103 seqp++;
104 continue;
105
106 case UNSEENSW:
107 unseensw = true;
108 continue;
109 case NUNSEENSW:
110 unseensw = false;
111 continue;
112
113 case PUBSW:
114 publicsw = 1;
115 continue;
116 case NPUBSW:
117 publicsw = 0;
118 continue;
119
120 case ZEROSW:
121 zerosw = true;
122 continue;
123 case NZEROSW:
124 zerosw = false;
125 continue;
126
127 case CRETSW:
128 create = true;
129 continue;
130 case NCRETSW:
131 create = false;
132 continue;
133 }
134 }
135 if (*cp == '+' || *cp == '@') {
136 if (folder)
137 die("only one folder at a time!");
138 folder = pluspath (cp);
139 } else {
140 die("usage: %s [+folder] [switches]", invo_name);
141 }
142 }
143
144 if (!context_find ("path"))
145 free (path ("./", TFOLDER));
146
147 /* if no folder is given, use default folder */
148 if (!folder)
149 folder = getfolder (0);
150 maildir = m_maildir (folder);
151
152 /* check if folder exists */
153 if (stat (maildir, &st) == NOTOK) {
154 if (errno != ENOENT)
155 adios (maildir, "error on folder");
156 if (!create)
157 die("folder %s doesn't exist", maildir);
158 if (!makedir (maildir))
159 die("unable to create folder %s", maildir);
160 }
161
162 if (chdir (maildir) == NOTOK)
163 adios (maildir, "unable to change directory to");
164
165 /* ignore a few signals */
166 SIGNAL (SIGHUP, SIG_IGN);
167 SIGNAL (SIGINT, SIG_IGN);
168 SIGNAL (SIGQUIT, SIG_IGN);
169 SIGNAL (SIGTERM, SIG_IGN);
170
171 /* create a temporary file */
172 tmpfilenam = m_mktemp (invo_name, &fd, NULL);
173 if (tmpfilenam == NULL) {
174 die("unable to create temporary file in %s", get_temp_dir());
175 }
176 chmod (tmpfilenam, m_gmprot());
177
178 /* copy the message from stdin into temp file */
179 cpydata (fileno (stdin), fd, "standard input", tmpfilenam);
180
181 if (fstat (fd, &st) == NOTOK) {
182 (void) m_unlink (tmpfilenam);
183 adios (tmpfilenam, "unable to fstat");
184 }
185 if (close (fd) == NOTOK)
186 adios (tmpfilenam, "error closing");
187
188 /* don't add file if it is empty */
189 if (st.st_size == 0) {
190 (void) m_unlink (tmpfilenam);
191 inform("empty file");
192 done (0);
193 }
194
195 /*
196 * read folder and create message structure
197 */
198 if (!(mp = folder_read (folder, 1)))
199 die("unable to read folder %s", folder);
200
201 /*
202 * Link message into folder, and possibly add
203 * to the Unseen-Sequence's.
204 */
205 if ((msgnum = folder_addmsg (&mp, tmpfilenam, 0, unseensw, 0, 0, NULL)) == -1)
206 done (1);
207
208 /*
209 * Add the message to any extra sequences
210 * that have been specified.
211 */
212 if (seqp) {
213 /* The only reason that seqp was checked to be non-zero is in
214 case a -nosequence switch is added. */
215 for (seqp = 0; seqp < svector_size (seqs); seqp++) {
216 if (!seq_addmsg (mp, svector_at (seqs, seqp), msgnum, publicsw,
217 zerosw))
218 done (1);
219 }
220 }
221
222 svector_free (seqs);
223 seq_setunseen (mp, 0); /* synchronize any Unseen-Sequence's */
224 seq_save (mp); /* synchronize and save message sequences */
225 folder_free (mp); /* free folder/message structure */
226
227 context_save (); /* save the global context file */
228 (void) m_unlink (tmpfilenam); /* remove temporary file */
229 tmpfilenam = NULL;
230
231 done (0);
232 return 1;
233 }
234
235 /*
236 * Clean up and exit
237 */
238 static void NORETURN
239 unlink_done(int status)
240 {
241 if (tmpfilenam && *tmpfilenam)
242 (void) m_unlink (tmpfilenam);
243 exit (status);
244 }