Use sysexits.h for better exit-codes
[mmh] / sbr / context_read.c
1 /*
2 ** context_read.c -- find and read profile and context files
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 **
8 ** This function must be called early on in any nmh utility, and
9 ** may only be called once.  It does the following:
10 **
11 **  o  Sets the global variables to absolute paths:
12 **     - "mypath": home directory (HOME)
13 **     - "mmhpath": mmh directory (MMH)
14 **     - "defpath": profile file (MMHP)
15 **     - "ctxpath": context file (MMHC)
16 **
17 **  o  Reads in the profile file.  Bails out if it can't.
18 **
19 **  o  Makes sure that the mail directory exists, prompting for
20 **     creation if it doesn't.
21 **
22 **  o  Reads the context file.
23 **
24 ** You might need to adjust uip/mmh.sh if you make changes here.
25 */
26
27 #include <h/mh.h>    /* mh internals */
28 #include <errno.h>   /* system call errors */
29 #include <pwd.h>     /* structure for getpwuid() results */
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <sysexits.h>
33
34 void
35 context_read(void)
36 {
37         char buf[BUFSIZ];            /* path name buffer                 */
38         char *cp;                    /* miscellaneous pointer            */
39         char *nd;                    /* nmh directory pointer            */
40         struct stat st;              /* stat() results                   */
41         register struct passwd *pw;  /* getpwuid() results               */
42         register FILE *ib;           /* profile and context file pointer */
43
44         /*
45         ** If this routine _is_ called again (despite the wanings in the
46         ** comments above), return immediately.
47         */
48         if (m_defs) {
49                 return;
50         }
51
52         /*
53         ** Find user's home directory. Try the HOME environment variable first,
54         ** the home directory field in the password file if that's not found.
55         */
56         if (!(mypath = getenv("HOME"))) {
57                 if (!(pw = getpwuid(getuid())) || !*pw->pw_dir) {
58                         adios(EX_OSERR, NULL, "cannot determine your home directory");
59                 }
60                 mypath = pw->pw_dir;
61         }
62
63         /*
64         ** set mmhpath
65         */
66         if ((cp = getenv("MMH")) && *cp) {
67                 mmhpath = getcpy(expanddir(cp));  /* rel to cwd */
68                 if (stat(mmhpath, &st) != -1 && (st.st_mode & S_IFDIR) == 0) {
69                         adios(EX_CONFIG, NULL, "`%s' specified by your MMH environment variable is not a directory", cp);
70                 }
71         } else {
72                 mmhpath = concat(mypath, "/", mmhdir, NULL);
73                 if (stat(mmhpath, &st) == -1 || (st.st_mode & S_IFDIR) == 0) {
74                         adios(EX_CONFIG, NULL, "Doesn't look like mmh is set up for your account.  Run `mmh' to do so.");
75                 }
76         }
77
78         /*
79         ** Find and read user's profile.  Check for the existence of
80         ** a non-empty MMHP environment variable first.  Look for the
81         ** profile in the mmh directory otherwise.
82         */
83         if ((cp = getenv("MMHP")) && *cp) {
84                 if (*cp == '/') {
85                         defpath = getcpy(cp);
86                 } else {
87                         defpath = concat(mmhpath, "/", cp, NULL);
88                 }
89                 if (stat(defpath, &st) != -1 && (st.st_mode & S_IFREG) == 0) {
90                         adios(EX_CONFIG, NULL, "Your profile `%s', specified by the MMHP environment variable, is not a normal file", cp);
91                 }
92                 if ((ib = fopen(defpath, "r")) == (FILE *)0) {
93                         adios(EX_IOERR, NULL, "Unable to read your profile `%s', specified by the MMHP environment variable", defpath);
94                 }
95         } else {
96                 defpath = concat(mmhpath, "/", profile, NULL);
97                 if ((ib = fopen(defpath, "r")) == (FILE *)0) {
98                         adios(EX_CONFIG, NULL, "No profile found. Please create `%s' first.", defpath);
99                 }
100                 cp = profile;
101         }
102         readconfig(&m_defs, ib, cp, 0);
103         fclose(ib);
104
105         /*
106         ** Find the user's mail storage directory, which is specified by
107         ** the `Path' profile component.  Convert a relative path name
108         ** to an absolute one rooted in the home directory.
109         */
110         if ((cp = context_find("path")) == NULL) {
111                 adios(EX_CONFIG, NULL, "Your profile `%s' does not contain the required path entry.", defpath);
112         }
113         if (!*cp) {
114                 adios(EX_CONFIG, NULL, "The Path entry of your profile `%s' must be non-empty.", defpath);
115         }
116         if (*cp == '/') {
117                 nd = cp;
118         } else {
119                 snprintf(nd = buf, sizeof buf, "%s/%s", mypath, cp);
120         }
121         if (stat(nd, &st) == -1) {
122                 if (errno != ENOENT) {
123                         adios(EX_IOERR, nd, "error opening");
124                 }
125                 cp = concat("Your mail storage directory `", nd, "' doesn't exist; Create it? ", NULL);
126                 if (!getanswer(cp)) {
127                         adios(EX_NOPERM, NULL, "Unable to access the mail storage directory `%s'", nd);
128                 }
129                 free(cp);
130                 if (!makedir(nd)) {
131                         adios(EX_CANTCREAT, nd, "unable to create");
132                 }
133         } else if ((st.st_mode & S_IFDIR) == 0) {
134                 adios(EX_DATAERR, NULL, "Your mail storage `%s' is not a directory", nd);
135         }
136         /*
137         ** Create the default folder (inbox)
138         */
139         cp = toabsdir(defaultfolder);
140         if (stat(cp, &st) == -1) {
141                 if (!makedir(cp)) {
142                         adios(EX_CANTCREAT, cp, "Unable to create the default folder");
143                 }
144         } else if ((st.st_mode & S_IFDIR) == 0) {
145                 adios(EX_DATAERR, NULL, "The default folder `%s' is not a directory", cp);
146         }
147
148         /*
149         ** Open and read user's context file.  The name of the context
150         ** file comes from the profile unless overridden by the MMHC
151         ** environment variable.
152         */
153         if (!(cp = getenv("MMHC")) || !*cp) {
154                 if (!(cp = context_find("context")) || !*cp) {
155                         cp = context;
156                 }
157         }
158
159         /*
160         ** context is NULL if the use of the context was diabled.
161         ** We also support users setting explicitly setting
162         ** MMHC to /dev/null.  (If this wasn't special-cased then the
163         ** locking would be liable to fail.)
164         */
165         if (!context || (strcmp(cp, "/dev/null") == 0)) {
166                 ctxpath = NULL;
167                 return;
168         }
169
170         if (*cp == '/') {
171                 ctxpath = getcpy(cp);
172         } else {
173                 ctxpath = concat(mmhpath, "/", cp, NULL);
174         }
175         if ((ib = lkfopen(ctxpath, "r"))) {
176                 readconfig((struct node **) 0, ib, cp, 1);
177                 lkfclose(ib, ctxpath);
178         }
179
180         /* Set editor */
181         if (!(cp = getenv("MMHEDITOR")) || !*cp) {
182                 if (!(cp = context_find("editor")) || !*cp) {
183                         if (!(cp = getenv("VISUAL")) || !*cp) {
184                                 if (!(cp = getenv("EDITOR")) || !*cp) {
185                                         cp = defaulteditor;
186                                 }
187                         }
188                 }
189         }
190         defaulteditor = cp;
191
192         /* Set pager */
193         if (!(cp = getenv("MMHPAGER")) || !*cp) {
194                 if (!(cp = context_find("pager")) || !*cp) {
195                         if (!(cp = getenv("PAGER")) || !*cp) {
196                                 cp = defaultpager;
197                         }
198                 }
199         }
200         defaultpager = cp;
201 }