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