]> diplodocus.org Git - nmh/blob - uip/install-mh.c
lock_file.c: close(2) file descriptor on failure, avoiding leak.
[nmh] / uip / install-mh.c
1 /* install-mh.c -- initialize the nmh environment of a new user
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> /* mh internals */
9 #include <h/utils.h>
10 #include "sbr/m_maildir.h"
11 #include "sbr/makedir.h"
12 #include <pwd.h> /* structure for getpwuid() results */
13 #include "sbr/read_line.h"
14
15 #define INSTALLMH_SWITCHES \
16 X("auto", 0, AUTOSW) \
17 X("version", 0, VERSIONSW) \
18 X("help", 0, HELPSW) \
19 X("check", 1, CHECKSW) \
20
21 #define X(sw, minchars, id) id,
22 DEFINE_SWITCH_ENUM(INSTALLMH);
23 #undef X
24
25 #define X(sw, minchars, id) { sw, minchars, id },
26 DEFINE_SWITCH_ARRAY(INSTALLMH, switches);
27 #undef X
28
29
30 int
31 main (int argc, char **argv)
32 {
33 int autof = 0;
34 char *cp, buf[BUFSIZ];
35 const char *pathname;
36 char *dp, **arguments, **argp;
37 struct node *np;
38 struct passwd *pw;
39 struct stat st;
40 FILE *in, *out;
41 int check;
42
43 if (nmh_init(argv[0], 0 /* use context_foil() */ )) { return 1; }
44
45 arguments = getarguments (invo_name, argc, argv, 0);
46 argp = arguments;
47
48 check = 0;
49
50 while ((dp = *argp++)) {
51 if (*dp == '-') {
52 switch (smatch (++dp, switches)) {
53 case AMBIGSW:
54 ambigsw (dp, switches);
55 done (1);
56 case UNKWNSW:
57 adios (NULL, "-%s unknown\n", dp);
58
59 case HELPSW:
60 snprintf (buf, sizeof(buf), "%s [switches]", invo_name);
61 print_help (buf, switches, 0);
62 done (0);
63 case VERSIONSW:
64 print_version(invo_name);
65 done (0);
66
67 case AUTOSW:
68 autof++;
69 continue;
70
71 case CHECKSW:
72 check = 1;
73 continue;
74 }
75 } else {
76 adios (NULL, "%s is invalid argument", dp);
77 }
78 }
79
80 /*
81 * Find user's home directory. Try the HOME environment variable first,
82 * the home directory field in the password file if that's not found.
83 */
84
85 if ((mypath = getenv("HOME")) == NULL) {
86 if ((pw = getpwuid(getuid())) == NULL || *pw->pw_dir == '\0')
87 adios(NULL, "cannot determine your home directory");
88 mypath = pw->pw_dir;
89 }
90
91 /*
92 * Find the user's profile. Check for the existence of an MH environment
93 * variable first with non-empty contents. Convert any relative path name
94 * found there to an absolute one. Look for the profile in the user's home
95 * directory if the MH environment variable isn't set.
96 */
97
98 if ((cp = getenv("MH")) && *cp != '\0')
99 defpath = path(cp, TFILE);
100 else
101 defpath = concat(mypath, "/", mh_profile, NULL);
102
103 /*
104 * Check for the existence of the profile file. It's an error if it exists and
105 * this isn't an installation check. An installation check fails if it does not
106 * exist, succeeds if it does.
107 */
108
109 if (stat (defpath, &st) != NOTOK) {
110 if (check)
111 done(0);
112 if (autof)
113 adios (NULL, "invocation error");
114 adios (NULL, "You already have an nmh profile, use an editor to modify it");
115 }
116 if (check)
117 done(1);
118
119 if (!autof && read_switch ("Do you want help? ", anoyes)) {
120 (void)printf(
121 "\n"
122 "Prior to using nmh, it is necessary to have a file in your login\n"
123 "directory (%s) named %s which contains information\n"
124 "to direct certain nmh operations. The only item which is required\n"
125 "is the path to use for all nmh folder operations. The suggested nmh\n"
126 "path for you is %s/Mail...\n"
127 "\n", mypath, mh_profile, mypath);
128 }
129
130 cp = concat (mypath, "/", "Mail", NULL);
131 if (stat (cp, &st) != NOTOK) {
132 if (!S_ISDIR(st.st_mode))
133 goto query;
134 cp = concat ("You already have the standard nmh directory \"",
135 cp, "\".\nDo you want to use it for nmh? ", NULL);
136 if (!read_switch (cp, anoyes))
137 goto query;
138 pathname = "Mail";
139 } else {
140 if (autof)
141 puts("I'm going to create the standard nmh path for you.");
142 else
143 cp = concat ("Do you want the standard nmh path \"",
144 mypath, "/", "Mail\"? ", NULL);
145 if (autof || read_switch (cp, anoyes))
146 pathname = "Mail";
147 else {
148 query:
149 if (read_switch ("Do you want a path below your login directory? ",
150 anoyes)) {
151 printf ("What is the path? %s/", mypath);
152 pathname = read_line ();
153 if (pathname == NULL) done (1);
154 } else {
155 printf ("What is the whole path? /");
156 pathname = read_line ();
157 if (pathname == NULL) done (1);
158 pathname = concat ("/", pathname, NULL);
159 }
160 }
161 }
162
163 if (chdir (mypath) < 0) {
164 advise (mypath, "chdir");
165 }
166 if (chdir (pathname) == NOTOK) {
167 cp = concat ("\"", pathname, "\" doesn't exist; Create it? ", NULL);
168 if (autof || read_switch (cp, anoyes))
169 if (makedir (pathname) == 0)
170 adios (NULL, "unable to create %s", pathname);
171 } else {
172 puts("[Using existing directory]");
173 }
174
175 /*
176 * Add some initial elements to the profile/context list
177 */
178 NEW(np);
179 m_defs = np;
180 np->n_name = mh_xstrdup("Path");
181 np->n_field = mh_xstrdup(pathname);
182 np->n_context = 0;
183 np->n_next = NULL;
184
185 /*
186 * If there is a default profile file in the
187 * nmh `etc' directory, then read it also.
188 */
189 if ((in = fopen (mh_defaults, "r"))) {
190 readconfig (&np->n_next, in, mh_defaults, 0);
191 fclose (in);
192 }
193
194 ctxpath = getcpy (m_maildir (context = "context"));
195
196 /* Initialize current folder to default */
197 context_replace (pfolder, defaultfolder);
198 context_save ();
199
200 /*
201 * Now write out the initial .mh_profile
202 */
203 if ((out = fopen (defpath, "w")) == NULL)
204 adios (defpath, "unable to write");
205 /*
206 * The main purpose of this first line is to fool file(1).
207 * Without it, if the first line of the profile is Path:,
208 * file 5.19 reports its type as message/news. With it,
209 * it reports the type as text/plain.
210 */
211 fprintf (out, "MH-Profile-Version: 1.0\n");
212 for (np = m_defs; np; np = np->n_next) {
213 if (!np->n_context)
214 fprintf (out, "%s: %s\n", np->n_name, np->n_field);
215 }
216 fclose (out);
217
218 puts ("\nPlease see the nmh(7) man page for an introduction to nmh.\n");
219 print_intro (stdout, false);
220
221 /* Initialize the saved nmh version. The Path profile entry was added
222 above, that's all this needs. */
223 (void) nmh_version_changed (0);
224
225 done (0);
226 return 1;
227 }