/*
Copyright (C) 2001-2006 Ben Kibbey <bjk@luxsci.net>
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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1