Update copyright year.
[userinfo.git] / src / modules / mail.c
blob8c8dc6cdd1a1dce2a7235a250a58b1b205169505
1 /*
2 Copyright (C) 2001-2013 Ben Kibbey <bjk@luxsci.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <errno.h>
28 #include <pwd.h>
30 #ifdef HAVE_FCNTL_H
31 #include <fcntl.h>
32 #endif
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #endif
38 #ifdef HAVE_LIMITS_H
39 #include <limits.h>
40 #ifndef LINE_MAX
41 #ifdef _POSIX2_LINE_MAX
42 #define LINE_MAX _POSIX2_LINE_MAX
43 #else
44 #define LINE_MAX 2048
45 #endif
46 #endif
47 #endif
49 #ifdef HAVE_SYS_MMAN_H
50 #include <sys/mman.h>
51 #endif
53 #ifdef HAVE_ERR_H
54 #include <err.h>
55 #endif
57 #ifdef HAVE_PATHS_H
58 #include <paths.h>
59 #endif
60 #ifndef _PATH_MAILDIR
61 #define _PATH_MAILDIR "/var/mail"
62 #endif
64 #ifndef HAVE_ERR_H
65 #include "../err.c"
66 #endif
68 #ifndef HAVE_STRSEP
69 #include "../strsep.c"
70 #endif
72 #ifdef WITH_DMALLOC
73 #include <dmalloc.h>
74 #endif
76 #define MAIL_OPTION_ORDER "smrfa"
77 #define MAIL_OPTION_STRING "Mfrsam"
79 static char options[6]; /* NULL terminated. */
80 static char *aliasbuf;
81 static char **strings;
83 void add_string(char ***, const char *);
84 char *stamp(time_t, const char *);
85 char *safe_strncat(char *, const char *, size_t);
87 void ui_module_init(int *chainable)
89 *chainable = 0;
92 void ui_module_exit()
94 if (aliasbuf)
95 munmap(aliasbuf, strlen(aliasbuf));
97 aliasbuf = NULL;
100 /* Remove characters (rm) from string (str). */
101 static char *stripstr(char *str, char *rm)
103 static char buf[LINE_MAX];
104 char *orm;
105 int i = 0;
107 if (rm == NULL || str == NULL)
108 return str;
110 while (*str) {
111 orm = rm;
113 while (*orm) {
114 if (*str == *orm) {
115 str++;
116 continue;
119 orm++;
122 buf[i++] = *str++;
125 buf[i] = '\0';
126 return buf;
129 /* Return a string of mail aliases for the user. Looks in /etc/aliases (or
130 * whatever was specified at compile-time). The file is read into a buffer
131 * only once (mmap(2)). */
132 static char *mail_aliases(const char *user, const int multi)
134 char t[LINE_MAX];
135 static char aliases[LINE_MAX], *p;
136 static int firstrun;
137 int i, n;
138 struct stat st;
139 char m[2] = { multi, '\0' };
140 int fd;
142 aliases[0] = '\0';
144 if ((!aliasbuf && firstrun) || aliasbuf == MAP_FAILED)
145 return "!";
147 if (!aliasbuf) {
148 firstrun = 1;
150 if (stat(ALIAS_FILE, &st) == -1)
151 return "!";
153 if ((fd = open(ALIAS_FILE, O_RDONLY)) == -1)
154 return "!";
156 if ((aliasbuf = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd,
157 0)) == MAP_FAILED) {
158 warn("%s", "mmap()");
159 return "!";
162 close(fd);
165 for (i = n = 0; aliasbuf[i]; i++) {
166 char *last, *name, *tmp;
168 while (aliasbuf[i] != '\n')
169 t[n++] = aliasbuf[i++];
171 t[n] = 0;
172 n = 0;
174 if (t[0] == '#' || t[0] == '\0')
175 continue;
177 last = t;
179 if ((name = strsep(&last, ":")) == NULL)
180 continue;
182 if (strcmp(user, name) == 0) {
183 while ((tmp = strsep(&last, ",")) != NULL) {
184 tmp = stripstr(tmp, " \n\t");
186 safe_strncat(aliases, tmp, sizeof(aliases));
187 safe_strncat(aliases, m, sizeof(aliases));
190 continue;
193 while ((tmp = strsep(&last, ",")) != NULL) {
194 tmp = stripstr(tmp, " \n\t");
196 if (strcmp(user, tmp) == 0) {
197 safe_strncat(aliases, name, sizeof(aliases));
198 safe_strncat(aliases, m, sizeof(aliases));
203 if (aliases[0] == '\0')
204 return "-";
205 else
206 aliases[strlen(aliases) - 1] = '\0';
208 p = aliases;
209 return p;
212 /* Returns a string of forward aliases for the user. Reads ~/.forward if it
213 * exists and is readable. */
214 static char *forwards(const char *dir, const int multi)
216 FILE *fp;
217 char buf[LINE_MAX], *s;
218 static char buf2[LINE_MAX];
219 int n = 0;
220 char m[2] = { multi, '\0' };
222 snprintf(buf2, sizeof(buf2), "%s/.forward", dir);
224 if ((fp = fopen(buf2, "r")) == NULL) {
225 if (errno == ENOENT)
226 return "-";
227 else
228 return "!";
231 buf2[0] = '\0';
233 while ((s = fgets(buf, sizeof(buf), fp)) != NULL) {
234 if (buf[0] == '\n')
235 continue;
237 if (buf[strlen(buf) - 1] == '\n')
238 buf[strlen(buf) - 1] = '\0';
240 if (n++)
241 safe_strncat(buf2, m, sizeof(buf2));
243 safe_strncat(buf2, buf, sizeof(buf2));
246 fclose(fp);
248 if (!n)
249 return "-";
251 s = buf2;
252 return s;
255 /* /var/mail/username folder size in bytes. */
256 static char *foldersize(struct stat st)
258 static char str[33], *p;
260 snprintf(str, sizeof(str), "%lu", (unsigned long) st.st_size);
261 p = str;
262 return p;
265 /* This is output if the -h command line option is passed to the main program.
267 void ui_module_help()
269 printf(" Mail information [-M (-%s)]:\n", MAIL_OPTION_ORDER);
270 printf("\t-f forwarding addresses\t");
271 printf("-a mail aliases\n");
272 printf("\t-r folder access (read) time\t");
273 printf("-m folder modification time\n");
274 printf("\t-s folder size\n\n");
277 /* This is the equivalent to main() only without argc and argv available. */
278 int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char,
279 const int verbose, char *tf)
281 char *p = options;
282 int gotstat = 0;
283 struct stat st;
284 char folder[PATH_MAX];
286 strings = *s;
287 folder[0] = '\0';
288 snprintf(folder, sizeof(folder), "%s/%s", _PATH_MAILDIR, pw->pw_name);
290 if (stat(folder, &st) != -1)
291 gotstat = 1;
293 for (; *p; p++) {
294 switch (*p) {
295 case 's':
296 add_string(&strings, (gotstat) ? foldersize(st) : "!");
297 break;
298 case 'r':
299 add_string(&strings, (gotstat) ? stamp(st.st_atime, tf) : "!");
300 break;
301 case 'm':
302 add_string(&strings, (gotstat) ? stamp(st.st_mtime, tf) : "!");
303 break;
304 case 'f':
305 add_string(&strings, forwards(pw->pw_dir, multi_char));
306 break;
307 case 'a':
308 add_string(&strings, mail_aliases(pw->pw_name, multi_char));
309 break;
310 default:
311 break;
315 *s = strings;
316 return EXIT_SUCCESS;
319 char *ui_module_options_init(char **defaults)
321 *defaults = "M";
322 return MAIL_OPTION_STRING;
325 /* Check module option validity. */
326 int ui_module_options(int argc, char **argv)
328 int opt;
329 char *p = options;
331 while ((opt = getopt(argc, argv, MAIL_OPTION_STRING)) != -1) {
332 switch (opt) {
333 case 'M':
334 strncpy(options, MAIL_OPTION_ORDER, sizeof(options));
335 return 0;
336 case 'f':
337 case 's':
338 case 'r':
339 case 'm':
340 case 'a':
341 break;
342 case '?':
343 warnx("mail: invalid option -- %c", optopt);
344 default:
345 return 1;
348 *p++ = opt;
349 *p = '\0';
352 return 0;