5733d3fa088592ab0b28d9c9110be44e1985521e
[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
31 void
32 context_read(void)
33 {
34         char buf[BUFSIZ];            /* path name buffer                 */
35         char *cp;                    /* miscellaneous pointer            */
36         char *nd;                    /* nmh directory pointer            */
37         struct stat st;              /* stat() results                   */
38         register struct passwd *pw;  /* getpwuid() results               */
39         register FILE *ib;           /* profile and context file pointer */
40
41         /*
42         ** If this routine _is_ called again (despite the wanings in the
43         ** comments above), return immediately.
44         */
45         if (m_defs) {
46                 return;
47         }
48
49         /*
50         ** Find user's home directory. Try the HOME environment variable first,
51         ** the home directory field in the password file if that's not found.
52         */
53         if (!(mypath = getenv("HOME"))) {
54                 if (!(pw = getpwuid(getuid())) || !*pw->pw_dir) {
55                         adios(NULL, "cannot determine your home directory");
56                 }
57                 mypath = pw->pw_dir;
58         }
59
60         /*
61         ** set mmhpath
62         */
63         if ((cp = getenv("MMH")) && *cp) {
64                 mmhpath = getcpy(expanddir(cp));  /* rel to cwd */
65                 if (stat(mmhpath, &st) != -1 && (st.st_mode & S_IFDIR) == 0) {
66                         adios(NULL, "`%s' specified by your MMH environment variable is not a directory", cp);
67                 }
68         } else {
69                 mmhpath = concat(mypath, "/", mmhdir, NULL);
70                 if (stat(mmhpath, &st) == -1 || (st.st_mode & S_IFDIR) == 0) {
71                         adios(NULL, "Doesn't look like mmh is set up for your account.  Run `install-mh' to do so.");
72                 }
73         }
74
75         /*
76         ** Find and read user's profile.  Check for the existence of
77         ** a non-empty MMHP environment variable first.  Look for the
78         ** profile in the mmh directory otherwise.
79         */
80         if ((cp = getenv("MMHP")) && *cp) {
81                 if (*cp == '/') {
82                         defpath = getcpy(cp);
83                 } else {
84                         defpath = concat(mmhpath, "/", cp, NULL);
85                 }
86                 if (stat(defpath, &st) != -1 && (st.st_mode & S_IFREG) == 0) {
87                         adios(NULL, "Your profile `%s', specified by the MMHP environment variable, is not a normal file", cp);
88                 }
89                 if ((ib = fopen(defpath, "r")) == (FILE *)0) {
90                         adios(NULL, "Unable to read your profile `%s', specified by the MMHP environment variable", defpath);
91                 }
92         } else {
93                 defpath = concat(mmhpath, "/", profile, NULL);
94                 if ((ib = fopen(defpath, "r")) == (FILE *)0) {
95                         adios(NULL, "No profile found. Please create `%s' first.", defpath);
96                 }
97                 cp = profile;
98         }
99         readconfig(&m_defs, ib, cp, 0);
100         fclose(ib);
101
102         /*
103         ** Find the user's mail storage directory, which is specified by
104         ** the `Path' profile component.  Convert a relative path name
105         ** to an absolute one rooted in the home directory.
106         */
107         if ((cp = context_find("path")) == NULL) {
108                 adios(NULL, "Your profile `%s' does not contain the required path entry.", defpath);
109         }
110         if (!*cp) {
111                 adios(NULL, "The Path entry of your profile `%s' must be non-empty.", defpath);
112         }
113         if (*cp == '/') {
114                 nd = cp;
115         } else {
116                 snprintf(nd = buf, sizeof buf, "%s/%s", mypath, cp);
117         }
118         if (stat(nd, &st) == -1) {
119                 if (errno != ENOENT) {
120                         adios(nd, "error opening");
121                 }
122                 cp = concat("Your mail storage directory `", nd, "' doesn't exist; Create it? ", NULL);
123                 if (!getanswer(cp)) {
124                         adios(NULL, "Unable to access the mail storage directory `%s'", nd);
125                 }
126                 free(cp);
127                 if (!makedir(nd)) {
128                         adios(nd, "unable to create");
129                 }
130         } else if ((st.st_mode & S_IFDIR) == 0) {
131                 adios(NULL, "Your mail storage `%s' is not a directory", nd);
132         }
133         /*
134         ** Create the default folder (inbox)
135         */
136         cp = toabsdir(defaultfolder);
137         if (stat(cp, &st) == -1) {
138                 if (!makedir(cp)) {
139                         adios(cp, "Unable to create the default folder");
140                 }
141         } else if ((st.st_mode & S_IFDIR) == 0) {
142                 adios(NULL, "The default folder `%s' is not a directory", cp);
143         }
144
145         /*
146         ** Open and read user's context file.  The name of the context
147         ** file comes from the profile unless overridden by the MMHC
148         ** environment variable.
149         */
150         if (!(cp = getenv("MMHC")) || !*cp) {
151                 if (!(cp = context_find("context")) || !*cp) {
152                         cp = context;
153                 }
154         }
155
156         /*
157         ** context is NULL if context_foil() was called to disable use
158         ** of context. We also support users setting explicitly setting
159         ** MMHC to /dev/null.  (If this wasn't special-cased then the
160         ** locking would be liable to fail.)
161         */
162         if (!context || (strcmp(cp, "/dev/null") == 0)) {
163                 ctxpath = NULL;
164                 return;
165         }
166
167         if (*cp == '/') {
168                 ctxpath = getcpy(cp);
169         } else {
170                 ctxpath = concat(mmhpath, "/", cp, NULL);
171         }
172         if ((ib = lkfopen(ctxpath, "r"))) {
173                 readconfig((struct node **) 0, ib, cp, 1);
174                 lkfclose(ib, ctxpath);
175         }
176
177         /* Set editor */
178         if (!(cp = getenv("MMHEDITOR")) || !*cp) {
179                 if (!(cp = context_find("editor")) || !*cp) {
180                         if (!(cp = getenv("VISUAL")) || !*cp) {
181                                 if (!(cp = getenv("EDITOR")) || !*cp) {
182                                         cp = defaulteditor;
183                                 }
184                         }
185                 }
186         }
187         defaulteditor = cp;
188
189         /* Set pager */
190         if (!(cp = getenv("MMHPAGER")) || !*cp) {
191                 if (!(cp = context_find("pager")) || !*cp) {
192                         if (!(cp = getenv("PAGER")) || !*cp) {
193                                 cp = defaultpager;
194                         }
195                 }
196         }
197         defaultpager = cp;
198 }