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