/* Copyright (C) 2001-2006 Ben Kibbey This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #endif #include "mail.h" #ifndef HAVE_ERR_H #include "../err.c" #endif #ifndef HAVE_STRSEP #include "../strsep.c" #endif void ui_module_init(int *chainable) { #ifdef DEBUG fprintf(stderr, "%s: ui_module_init()\n", __FILE__); #endif *chainable = 0; return; } void ui_module_exit() { #ifdef DEBUG fprintf(stderr, "%s: ui_module_exit()\n", __FILE__); #endif if (aliasbuf) munmap(aliasbuf, strlen(aliasbuf)); aliasbuf = NULL; return; } /* Remove characters (rm) from string (str). */ static char *stripstr(char *str, char *rm) { static char buf[LINE_MAX]; char *orm; int i = 0, c; if (rm == NULL || str == NULL) return str; while (*str) { orm = rm; while (*orm) { if (*str == *orm) { c = *str++; continue; } c = *orm++; } buf[i++] = *str++; } buf[i] = '\0'; return buf; } /* Return a string of mail aliases for the user. Looks in /etc/aliases (or * whatever was specified at compile-time). The file is read into a buffer * only once (mmap(2)). */ static char *mail_aliases(const char *user, const int multi) { char t[LINE_MAX]; static char aliases[LINE_MAX], *p; static int firstrun; int i, n; struct stat st; char m[2] = { multi, '\0' }; int fd; aliases[0] = '\0'; if ((!aliasbuf && firstrun) || aliasbuf == MAP_FAILED) return "!"; if (!aliasbuf) { firstrun = 1; if (stat(ALIAS_FILE, &st) == -1) return "!"; if ((fd = open(ALIAS_FILE, O_RDONLY)) == -1) return "!"; if ((aliasbuf = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) { warn("%s", "mmap()"); return "!"; } close(fd); } for (i = n = 0; aliasbuf[i]; i++) { char *last, *name, *tmp; while (aliasbuf[i] != '\n') t[n++] = aliasbuf[i++]; t[n] = 0; n = 0; if (t[0] == '#' || t[0] == '\0') continue; last = t; if ((name = strsep(&last, ":")) == NULL) continue; if (strcmp(user, name) == 0) { while ((tmp = strsep(&last, ",")) != NULL) { tmp = stripstr(tmp, " \n\t"); strncat(aliases, tmp, sizeof(aliases)); strncat(aliases, m, sizeof(aliases)); } continue; } while ((tmp = strsep(&last, ",")) != NULL) { tmp = stripstr(tmp, " \n\t"); if (strcmp(user, tmp) == 0) { strncat(aliases, name, sizeof(aliases)); strncat(aliases, m, sizeof(aliases)); } } } if (aliases[0] == '\0') return "-"; else aliases[strlen(aliases) - 1] = '\0'; p = aliases; return p; } /* Returns a string of forward aliases for the user. Reads ~/.forward if it * exists and is readable. */ static char *forwards(const char *dir, const int multi) { FILE *fp; char buf[LINE_MAX], *s; static char buf2[FILENAME_MAX]; int n = 0; char m[2] = { multi, '\0' }; buf[0] = buf2[0] = '\0'; snprintf(buf2, sizeof(buf2), "%s/.forward", dir); if ((fp = fopen(buf2, "r")) == NULL) { if (errno == ENOENT) return "-"; else return "!"; } buf2[0] = '\0'; while ((s = fgets(buf, sizeof(buf), fp)) != NULL) { if (buf[0] == '\n') continue; if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0'; if (n++) strncat(buf2, m, sizeof(buf2)); strncat(buf2, buf, sizeof(buf2)); } fclose(fp); if (!n) return "-"; s = buf2; return s; } /* /var/mail/username folder size in bytes. */ static char *foldersize(struct stat st) { static char str[33], *p; str[0] = '\0'; snprintf(str, sizeof(str), "%lu", (unsigned long) st.st_size); p = str; return p; } /* This is output if the -h command line option is passed to the main program. */ void ui_module_help() { #ifdef DEBUG fprintf(stderr, "%s: ui_module_help()\n", __FILE__); #endif printf(" Mail information [-M (-%s)]:\n", MAIL_OPTION_ORDER); printf("\t-f forwarding addresses\t"); printf("-a mail aliases\n"); printf("\t-r folder access (read) time\t"); printf("-m folder modification time\n"); printf("\t-s folder size\n\n"); return; } /* This is the equivalent to main() only without argc and argv available. */ int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char, const int verbose, char *tf) { char *p = options; int gotstat = 0; struct stat st; char folder[FILENAME_MAX]; strings = *s; folder[0] = '\0'; snprintf(folder, sizeof(folder), "%s/%s", _PATH_MAILDIR, pw->pw_name); if (stat(folder, &st) != -1) gotstat = 1; while (*p) { switch (*p) { case 's': add_string(&strings, (gotstat) ? foldersize(st) : "!"); break; case 'r': add_string(&strings, (gotstat) ? stamp(st.st_atime, tf) : "!"); break; case 'm': add_string(&strings, (gotstat) ? stamp(st.st_mtime, tf) : "!"); break; case 'f': add_string(&strings, forwards(pw->pw_dir, multi_char)); break; case 'a': add_string(&strings, mail_aliases(pw->pw_name, multi_char)); break; default: break; } p++; } *s = strings; return EXIT_SUCCESS; } char *ui_module_options_init(char **defaults) { *defaults = "M"; return MAIL_OPTION_STRING; } /* Check module option validity. */ int ui_module_options(int argc, char **argv) { int opt; char *p = options; #ifdef DEBUG fprintf(stderr, "%s: ui_module_options()\n", __FILE__); #endif while ((opt = getopt(argc, argv, MAIL_OPTION_STRING)) != -1) { switch (opt) { case 'f': case 's': case 'r': case 'm': case 'a': case 'M': break; case '?': warnx("mail: invalid option -- %c", optopt); default: return 1; } /* * This option '-M' sets all available options for this module. */ if (opt == 'M') { strncpy(options, MAIL_OPTION_ORDER, sizeof(options)); break; } *p++ = opt; *p = '\0'; } return 0; }