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