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