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