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