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