/*
* asmail is the AfterStep mailbox monitor
* Copyright (c) 2002-2007 Albert Dorofeev <albert@tigr.net>
* For the updates see http://www.tigr.net/
*
* This software is distributed under GPL. For details see LICENSE file.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h>
#include <errno.h>
#include "globals.h"
#include "mbox.h"
#include "maildir.h"
#include "mh.h"
#include "pop3.h"
#include "imap.h"
#include "gui.h"
#include "config.h"
int passwords_in_config = 0;
void version() {
printf("asmail : AfterStep e-mail monitor version %s\n", VERSION);
}
void usage() {
version();
printf("Usage : asmail [-options...]\n");
printf("\n");
printf("-V print version and exit\n");
printf("-h print this help screen and exit\n");
printf("-v verbose: print mailbox stats to STDOUT\n");
printf("-insecure allow config file to be readable by others\n");
printf("-f <filename> name of the configuration file to use\n");
printf("-geometry <xy> X geometry specification (position/size)\n");
printf("-nox don't use X11 interface (implies -v)\n");
printf("-noconfig don't read config file (run default settings)\n");
printf("-iconic start as an icon rather than a window\n");
printf("-withdrawn \"withdrawn\" mode for WindowMaker\n");
printf("\n");
printf("Use $DISPLAY environment variable to run asmail on a different display.\n");
printf("\n");
}
static void err_printf(char const *tmpl, ...) {
va_list val;
int errno_;
errno_ = errno;
va_start(val, tmpl);
vprintf(tmpl, val);
va_end(val);
errno = errno_;
}
/*
* Set up the defaults that cannot be determined at compile time.
*/
void defaults() {
strncpy(config_file_name, (char *) getenv("HOME"), MAX_INPUT_LENGTH);
strncat(config_file_name, "/", MAX_INPUT_LENGTH-strlen(config_file_name));
strncat(config_file_name, RCFILE, MAX_INPUT_LENGTH-strlen(config_file_name));
/*
* Just in case, prevent the strings from overrunning
*/
config_file_name[MAX_INPUT_LENGTH] = '\0';
x11_set.geometry[MAX_INPUT_LENGTH] = '\0';
x11_set.title[MAX_INPUT_LENGTH] = '\0';
x11_set.font[MAX_INPUT_LENGTH] = '\0';
x11_set.on_left[MAX_INPUT_LENGTH] = '\0';
x11_set.on_middle[MAX_INPUT_LENGTH] = '\0';
x11_set.on_right[MAX_INPUT_LENGTH] = '\0';
x11_set.on_new_mail[MAX_INPUT_LENGTH] = '\0';
x11_set.beep = 1;
x11_set.shape = 0;
x11_set.use_frame = 1;
x11_set.withdrawn = 0;
x11_set.iconic = 0;
strcpy(x11_set.geometry, "");
strcpy(x11_set.title, "asmail");
strcpy(x11_set.on_left, "");
strcpy(x11_set.on_middle, "");
strcpy(x11_set.on_right, "");
strcpy(x11_set.on_new_mail, "");
x11_set.each = 0;
x11_set.total = 1;
x11_set.status = 1;
x11_set.old = 1;
x11_set.new = 1;
x11_set.x = 0;
x11_set.y = 52;
strcpy(x11_set.delimiter, "/");
strcpy(x11_set.font, "-*-*-medium-r-normal--10-*-*-*-*-*-*-*");
strcpy(x11_set.color, "black");
x11_set.refresh = 10;
x11_set.nomail = NULL;
x11_set.oldmail = NULL;
x11_set.newmail = NULL;
x11_set.frame = NULL;
}
/*
* The function parses the command line switches and sets
* global variables accordingly.
* Returns 0 on success, -1 = error.
*/
int parse_cmd(int argc, char *argv[]) {
int i;
for (i=1; i<argc; i++) {
if ( ! strcmp(argv[i], "-geometry") ) {
if ( ++i >= argc ) {
usage();
return(-1);
}
strncpy(x11_set.geometry, argv[i], MAX_INPUT_LENGTH);
} else if ( ! strcmp(argv[i], "-title") ) {
if ( ++i >= argc ) {
usage();
return(-1);
}
strncpy(x11_set.title, argv[i], MAX_INPUT_LENGTH);
} else if ( ! strcmp(argv[i], "-f") ) {
if ( ++i >= argc ) {
usage();
return(-1);
}
strncpy(config_file_name, argv[i], MAX_INPUT_LENGTH);
flag_config_specified = 1;
} else if ( ! strcmp(argv[i], "-V") ) {
version();
return(-1);
} else if ( ! strcmp(argv[i], "-h") ) {
usage();
return(-1);
} else if ( ! strcmp(argv[i], "-v") ) {
flag_verbose = 1;
} else if ( ! strcmp(argv[i], "-nox") ) {
flag_verbose = 1;
flag_no_x = 1;
} else if ( ! strcmp(argv[i], "-noconfig") ) {
flag_no_config = 1;
} else if ( ! strcmp(argv[i], "-iconic") ) {
x11_set.iconic = 1;
} else if ( ! strcmp(argv[i], "-withdrawn") ) {
x11_set.withdrawn = 1;
} else if ( ! strcmp(argv[i], "-insecure") ) {
flag_allow_insecure = 1;
/*
* Unrecognised options
*/
} else if ( argv[i][0] == '-' ) {
printf("asmail: Unknown option: %s\n", argv[i]);
usage();
return(-1);
/*
* Old-style configuration file name
*/
} else {
strncpy(config_file_name, argv[i], MAX_INPUT_LENGTH);
flag_config_specified = 1;
}
}
return(0);
}
/*
* Remove the blanks at the beginning and the end of the line
*/
void shorten(char * line) {
int i = 0, j = 0;
if (line[strlen(line)-1] == '\n')
line[strlen(line)-1] = '\0';
while (isspace(line[i]) && line[i])
i++;
if (i == 0 || i == strlen(line))
return;
while (line[i])
line[j++] = line[i++];
line[j] = '\0';
i = strlen(line);
while (isspace(line[i]) && i > 0)
i--;
if (line[i] == '\n')
i--;
line[++i] = '\0';
}
/*
* Strips the outside quotes (' or ") from the given line.
* If there are no matching quotes - nothing is done.
*/
void strip_quotes(char * line) {
char tmp1[MAX_INPUT_LENGTH+1];
int len;
if ( strlen(line) < 2 )
return;
strcpy(tmp1, line);
shorten(tmp1);
if ( ( tmp1[0] != '\'' ) && ( tmp1[0] != '"' ) ) {
return;
}
/*
* Now the first character is either ' or ",
* find the terminating one.
*/
len = strlen(tmp1);
if ( tmp1[len-1] != tmp1[0] )
return;
tmp1[len-1] = '\0';
strcpy(line, &tmp1[1]);
}
/*
* Clean the config line, check and prepare for parsing
* Returns 0 if ok
* -1 if error
*/
int parse_cfg_check(char * line) {
if (line[strlen(line)-1] != '\n') {
/* The line does not end in EOL - too long */
printf("asmail: a line in configuration is too long, maximum length is %d.\n",
MAX_INPUT_LENGTH);
printf("asmail: Offending line (%d chars): %s\n",
(unsigned)strlen(line), line);
return(-1);
}
/* Leading and trailing space are removed */
shorten(line);
return(0);
}
/*
* Inside the X11 settings, parse the block with animation settings
* and picture file names.
*/
int parse_cfg_animate(FILE * f, int * line_counter, char * filename) {
char line[MAX_INPUT_LENGTH+1];
char key[MAX_INPUT_LENGTH+1];
struct pixfile * tmp_pixfile;
while ( fgets(line, MAX_INPUT_LENGTH, f) ) {
++(*line_counter);
if ( parse_cfg_check(line) ) {
return(-1);
}
/* Weed out comments and empty lines */
if ( (line[0] == '#') || (line[0] == '\0') ) {
continue;
}
/* Read the command */
sscanf( line, "%s", key );
if (!strcasecmp(key, "refresh")) {
sscanf(line, "%s %d", key, &x11_set.refresh);
} else if (!strcasecmp(key, "nomail")) {
if ( strlen(line) > (strlen(key) + 1) ) {
tmp_pixfile = (struct pixfile *)
malloc(sizeof(struct pixfile));
if ( ! tmp_pixfile ) {
err_printf("asmail: parse_cfg_animate: failed to allocate memory for the pixfile\n");
perror("asmail: parse_cfg_animate: ");
return(-1);
}
strcpy(tmp_pixfile->name, &line[strlen(key)+1]);
tmp_pixfile->next = x11_set.nomail;
x11_set.nomail = tmp_pixfile;
}
} else if (!strcasecmp(key, "old")) {
if ( strlen(line) > (strlen(key) + 1) ) {
tmp_pixfile = (struct pixfile *)
malloc(sizeof(struct pixfile));
if ( ! tmp_pixfile ) {
err_printf("asmail: parse_cfg_animate: failed to allocate memory for the pixfile\n");
perror("asmail: parse_cfg_animate: ");
return(-1);
}
strcpy(tmp_pixfile->name, &line[strlen(key)+1]);
tmp_pixfile->next = x11_set.oldmail;
x11_set.oldmail = tmp_pixfile;
}
} else if (!strcasecmp(key, "new")) {
if ( strlen(line) > (strlen(key) + 1) ) {
tmp_pixfile = (struct pixfile *)
malloc(sizeof(struct pixfile));
if ( ! tmp_pixfile ) {
err_printf("asmail: parse_cfg_animate: failed to allocate memory for the pixfile\n");
perror("asmail: parse_cfg_animate: ");
return(-1);
}
strcpy(tmp_pixfile->name, &line[strlen(key)+1]);
tmp_pixfile->next = x11_set.newmail;
x11_set.newmail = tmp_pixfile;
}
} else if (!strcasecmp(key, "frame")) {
if ( strlen(line) > (strlen(key) + 1) ) {
if ( !strcasecmp(&line[strlen(key)+1], "none") ) {
x11_set.use_frame = 0;
} else {
tmp_pixfile = (struct pixfile *)
malloc(sizeof(struct pixfile));
if ( ! tmp_pixfile ) {
err_printf("asmail: parse_cfg_animate: failed to allocate memory for the pixfile\n");
perror("asmail: parse_cfg_animate: ");
return(-1);
}
strcpy(tmp_pixfile->name, &line[strlen(key)+1]);
tmp_pixfile->next = x11_set.frame;
x11_set.frame = tmp_pixfile;
x11_set.use_frame = 1;
}
}
} else if ( !strcmp(key, "}") ) {
/* config block terminator */
return(0);
} else {
printf("asmail: cannot understand config file %s\n",
filename);
printf("asmail: Offending line (%d): %s\n",
(*line_counter), line);
return(-1);
}
}
/*
* If we reach here, we did not find the terminating '}'
*/
printf("asmail: Did not find terminating '}' for animate configuration block.\n");
return(-1);
}
/*
* Inside the X11 settings, parse the block related to the
* display of message statistics.
*/
int parse_cfg_stat(FILE * f, int * line_counter, char * filename) {
char line[MAX_INPUT_LENGTH+1];
char key[MAX_INPUT_LENGTH+1];
char rest[MAX_INPUT_LENGTH+1];
while ( fgets(line, MAX_INPUT_LENGTH, f) ) {
++(*line_counter);
if ( parse_cfg_check(line) ) {
return(-1);
}
/* Weed out comments and empty lines */
if ( (line[0] == '#') || (line[0] == '\0') ) {
continue;
}
/* Read the command */
sscanf( line, "%s", key );
if (!strcasecmp(key, "total")) {
sscanf(line, "%s %s", key, rest);
x11_set.total = strcasecmp(rest, "yes") ? 0 : 1;
} else if (!strcasecmp(key, "each")) {
sscanf(line, "%s %s", key, rest);
x11_set.each = strcasecmp(rest, "yes") ? 0 : 1;
} else if (!strcasecmp(key, "status")) {
sscanf(line, "%s %s", key, rest);
x11_set.status = strcasecmp(rest, "yes") ? 0 : 1;
} else if (!strcasecmp(key, "old")) {
sscanf(line, "%s %s", key, rest);
x11_set.old = strcasecmp(rest, "yes") ? 0 : 1;
} else if (!strcasecmp(key, "new")) {
sscanf(line, "%s %s", key, rest);
x11_set.new = strcasecmp(rest, "yes") ? 0 : 1;
} else if (!strcasecmp(key, "x")) {
sscanf(line, "%s %d", key, &x11_set.x);
} else if (!strcasecmp(key, "y")) {
sscanf(line, "%s %d", key, &x11_set.y);
} else if (!strcasecmp(key, "delimiter")) {
if ( strlen(line) > (strlen(key) + 1) ) {
strcpy(x11_set.delimiter, &line[strlen(key)+1]);
strip_quotes(x11_set.delimiter);
}
} else if (!strcasecmp(key, "font")) {
sscanf(line, "%s %s", key, x11_set.font);
} else if (!strcasecmp(key, "color")) {
if ( strlen(line) > (strlen(key) + 1) ) {
strcpy(x11_set.color, &line[strlen(key)+1]);
strip_quotes(x11_set.color);
}
} else if ( !strcmp(key, "}") ) {
/* config block terminator */
return(0);
} else {
printf("asmail: cannot understand config file %s\n",
filename);
printf("asmail: Offending line (%d): %s\n",
(*line_counter), line);
return(-1);
}
}
/*
* If we reach here, we did not find the terminating '}'
*/
printf("asmail: Did not find terminating '}' for stat configuration block.\n");
return(-1);
}
/*
* Parse the X11 settings (were global definitions)
*/
int parse_cfg_x11(FILE * f, int * line_counter, char * filename) {
char line[MAX_INPUT_LENGTH+1];
char key[MAX_INPUT_LENGTH+1];
char rest[MAX_INPUT_LENGTH+1];
while ( fgets(line, MAX_INPUT_LENGTH, f) ) {
++(*line_counter);
if ( parse_cfg_check(line) ) {
return(-1);
}
/* Weed out comments and empty lines */
if ( (line[0] == '#') || (line[0] == '\0') ) {
continue;
}
/* Read the command */
sscanf( line, "%s", key );
if (!strcasecmp(key, "beep")) {
sscanf(line, "%s %s", key, rest);
x11_set.beep = strcasecmp(rest, "yes") ? 0 : 1;
} else if (!strcasecmp(key, "shape")) {
sscanf(line, "%s %s", key, rest);
x11_set.shape = strcasecmp(rest, "yes") ? 0 : 1;
} else if (!strcasecmp(key, "on_mouse_left")) {
if ( strlen(line) > (strlen(key) + 1) ) {
strcpy(x11_set.on_left, &line[strlen(key)+1]);
}
} else if (!strcasecmp(key, "on_mouse_middle")) {
if ( strlen(line) > (strlen(key) + 1) ) {
strcpy(x11_set.on_middle, &line[strlen(key)+1]);
}
} else if (!strcasecmp(key, "on_mouse_right")) {
if ( strlen(line) > (strlen(key) + 1) ) {
strcpy(x11_set.on_right, &line[strlen(key)+1]);
}
} else if (!strcasecmp(key, "on_new_mail")) {
if ( strlen(line) > (strlen(key) + 1) ) {
strcpy(x11_set.on_new_mail, &line[strlen(key)+1]);
}
} else if (!strcasecmp(key, "font")) {
if ( strlen(line) > (strlen(key) + 1) ) {
strcpy(x11_set.font, &line[strlen(key)+1]);
}
} else if (!strcasecmp(key, "stat")) {
sscanf( line, "%s %s", key, rest);
if ( !strcmp(rest, "{") ) {
if ( parse_cfg_stat(f, line_counter, filename) ) {
return(-1);
}
}
} else if (!strcasecmp(key, "animate")) {
sscanf( line, "%s %s", key, rest);
if ( !strcmp(rest, "{") ) {
if ( parse_cfg_animate(f, line_counter,
filename) ) {
return(-1);
}
}
} else if ( !strcmp(key, "}") ) {
/* config block terminator */
return(0);
} else {
printf("asmail: cannot understand config file %s\n",
filename);
printf("asmail: Offending line (%d): %s\n",
(*line_counter), line);
return(-1);
}
}
/*
* If we reach here, we did not find the terminating '}'
*/
printf("asmail: Did not find terminating '}' for X11 configuration block.\n");
return(-1);
}
/*
* Initialize the new mailbox record and return it
*/
int init_mbox( struct mbox_struct ** mb ) {
struct mbox_struct * new_mbox;
new_mbox = (struct mbox_struct *) malloc(sizeof(struct mbox_struct));
if ( ! new_mbox ) {
printf("asmail: failed to allocate memory for the mailbox control structure.\n");
return(-1);
}
if ( pthread_mutex_init(&new_mbox->mutex, NULL) ) {
printf("asmail: parse_cfg_mbox: failed to initialize mutex.\n");
return(-1);
}
new_mbox->type = 0;
strcpy(new_mbox->file, "");
strcpy(new_mbox->server, "");
strcpy(new_mbox->user, "");
strcpy(new_mbox->pass, "");
strcpy(new_mbox->mbox, "");
new_mbox->auth = AUTH_PLAIN | AUTH_MD5;
new_mbox->port = 0;
new_mbox->timeout = 60; /* Default timeout for IP connections, sec */
new_mbox->update = 10;
new_mbox->flags = FLAG_DEFAULT;
new_mbox->status = STAT_IDLE;
new_mbox->mail = MAIL_NONE;
new_mbox->ctotal = 0;
new_mbox->cnew = 0;
#ifdef HAVE_OPENSSL_SSL_H
strcpy(new_mbox->trustedCaDir, "");
#endif
new_mbox->next = NULL;
*mb = new_mbox;
return(0);
}
/*
* Parse the configuration block related to a mailbox
*/
int parse_cfg_mbox(FILE * f, int * line_counter, char * filename) {
char line[MAX_INPUT_LENGTH+1];
char key[MAX_INPUT_LENGTH+1];
char rest[MAX_INPUT_LENGTH+1];
struct mbox_struct * new_mbox;
char * str_ptr;
if ( init_mbox(&new_mbox) ) {
return(-1);
}
while ( fgets(line, MAX_INPUT_LENGTH, f) ) {
++(*line_counter);
if ( parse_cfg_check(line) ) {
return(-1);
}
/* Weed out comments and empty lines */
if ( (line[0] == '#') || (line[0] == '\0') ) {
continue;
}
/* Read the command */
sscanf( line, "%s", key );
if (!strcasecmp(key, "type")) {
sscanf(line, "%s %s", key, rest);
if ( !strcasecmp(rest, "mbox") ) {
new_mbox->type = MBOX_FILE;
} else if ( !strcasecmp(rest, "maildir") ) {
new_mbox->type = MBOX_DIR;
} else if ( !strcasecmp(rest, "mh") ) {
new_mbox->type = MBOX_MH;
} else if ( !strcasecmp(rest, "pop3") ) {
new_mbox->type = MBOX_POP3;
} else if ( !strcasecmp(rest, "imap") ) {
new_mbox->type = MBOX_IMAP;
} else {
printf("asmail: don't know how to handle mailbox type '%s'\n",
rest);
printf("asmail: Offending line (%d): %s\n",
(*line_counter), line);
}
} else if (!strcasecmp(key, "update")) {
sscanf(line, "%s %d", key, &new_mbox->update);
} else if (!strcasecmp(key, "file")) {
sscanf(line, "%s %s", key, new_mbox->file);
} else if (!strcasecmp(key, "server")) {
sscanf(line, "%s %s", key, new_mbox->server);
} else if (!strcasecmp(key, "user")) {
sscanf(line, "%s %s", key, new_mbox->user);
} else if (!strcasecmp(key, "password")) {
sscanf(line, "%s %s", key, new_mbox->pass);
passwords_in_config = 1;
} else if (!strcasecmp(key, "auth")) {
/* Watch the magic: empty list (just the keyword
* without parameters) resets the settings to
* none */
new_mbox->auth = AUTH_NONE;
if ( strlen(line) > (strlen(key) + 1) ) {
new_mbox->auth = 0;
strcpy(rest, &line[strlen(key)+1]);
str_ptr = strtok(rest, " \t\n");
while ( str_ptr ) {
sscanf(str_ptr, "%s", key);
if ( !strcasecmp(key, "plain")) {
new_mbox->auth |= AUTH_PLAIN;
} else if (!strcasecmp(key, "md5")) {
new_mbox->auth |= AUTH_MD5;
} else {
printf("asmail: cannot understand authorisation scheme '%s'\n", key);
printf("asmail: Offending configuration line (%d): %s\n", (*line_counter), line);
return(-1);
}
str_ptr = strtok(NULL, " \t\n");
}
}
} else if (!strcasecmp(key, "port")) {
sscanf(line, "%s %d", key, &new_mbox->port);
} else if (!strcasecmp(key, "timeout")) {
sscanf(line, "%s %d", key, &new_mbox->timeout);
} else if (!strcasecmp(key, "mailbox")) {
sscanf(line, "%s %s", key, new_mbox->mbox);
} else if (!strcasecmp(key, "unread-is-new")) {
sscanf(line, "%s %s", key, rest);
if ( ! strcasecmp(rest, "yes") ) {
new_mbox->flags |= FLAG_UNREAD_AS_NEW;
} else {
new_mbox->flags &= ~FLAG_UNREAD_AS_NEW;
}
} else if (!strcasecmp(key, "use-mh-sequences")) {
sscanf(line, "%s %s", key, rest);
if ( ! strcasecmp(rest, "yes") ) {
new_mbox->flags |= FLAG_USE_MH_SEQ;
} else {
new_mbox->flags &= ~FLAG_USE_MH_SEQ;
}
} else if (!strcasecmp(key, "persistent")) {
sscanf(line, "%s %s", key, rest);
if ( ! strcasecmp(rest, "yes") ) {
new_mbox->flags |= FLAG_PERSISTENT_CONN;
} else {
new_mbox->flags &= ~FLAG_PERSISTENT_CONN;
}
} else if (!strcasecmp(key, "ssl")) {
#ifdef HAVE_OPENSSL_SSL_H
sscanf(line, "%s %s", key, rest);
if ( ! strcasecmp(rest, "yes") ) {
new_mbox->flags |= FLAG_SSL;
} else {
new_mbox->flags &= ~FLAG_SSL;
}
#else
printf("asmail: ssl support is not available, ignoring ssl statement\n");
#endif
} else if (!strcasecmp(key, "trustedCaDir")) {
#ifdef HAVE_OPENSSL_SSL_H
sscanf(line, "%s %s", key, new_mbox->trustedCaDir);
#else
printf("asmail: ssl support is not available, ignoring trustedCaDir statement\n");
#endif
} else if ( !strcmp(key, "}") ) {
if ((new_mbox->flags & FLAG_SSL) && (new_mbox->type != MBOX_IMAP))
printf("asmail: ssl is only supported with imap mailboxes, ignoring ssl statement\n");
/* config block terminator */
new_mbox->next = mbox;
mbox = new_mbox;
return(0);
} else {
printf("asmail: cannot understand config file %s\n",
filename);
printf("asmail: Offending line (%d): %s\n",
(*line_counter), line);
return(-1);
}
}
/*
* If we reach here, we did not find the terminating '}'
*/
printf("asmail: Did not find terminating '}' for mailbox configuration block.\n");
return(-1);
}
/*
* Parse the specified config file. Return 0 on success, -1 = error.
*/
int parse_cfg(char * filename) {
FILE * f;
struct stat f_stat;
int line_counter = 0;
char line[MAX_INPUT_LENGTH+1];
char key[MAX_INPUT_LENGTH+1];
char rest[MAX_INPUT_LENGTH+1];
if ( stat(filename, &f_stat) ) {
err_printf("asmail: Cannot stat the config file (%s).\n", filename);
/* if the file does not exist, we still can run with
* the default settings using $MAIL unless a config
* file was given on command line. */
if ( ! flag_config_specified )
if ( ENOENT == errno )
return(-2);
perror("asmail: parse_cfg");
return(-1);
}
if ( ( f = fopen(filename, "r") ) == NULL ) {
err_printf("asmail: Cannot open the config file (%s).\n", filename);
perror("asmail: parse_cfg");
return(-1);
}
while ( fgets(line, MAX_INPUT_LENGTH, f) ) {
++line_counter;
if ( parse_cfg_check(line) ) {
return(-1);
}
/* Weed out comments and empty lines */
if ( (line[0] == '#') || (line[0] == '\0') ) {
continue;
}
/* Read the command */
sscanf( line, "%s", key );
if (!strcasecmp(key, "x11")) {
sscanf( line, "%s %s", key, rest);
if ( !strcmp(rest, "{") ) {
if ( parse_cfg_x11(f, &line_counter, filename) ) {
return(-1);
}
}
} else if (!strcasecmp(key, "mailbox")) {
sscanf( line, "%s %s", key, rest);
if ( !strcmp(rest, "{") ) {
if ( parse_cfg_mbox(f, &line_counter, filename) ) {
return(-1);
}
}
} else {
printf("asmail: cannot understand config file %s\n",
filename);
printf("asmail: Offending line (%d): %s\n",
line_counter, line);
return(-1);
}
}
if ( fclose(f) ) {
err_printf("asmail: Cannot close the config file (%s).\n", filename);
perror("asmail: parse_cfg");
return(-1);
}
if ( ( ((f_stat.st_mode & S_IRWXG) != 0) ||
((f_stat.st_mode & S_IRWXO) != 0) ) &&
passwords_in_config ) {
if ( flag_allow_insecure ) {
printf("asmail: configuration file mode is insecure but '-insecure' was given.\n");
} else {
printf("asmail: The configuration file has permissions for group and/or others set.\n");
printf("asmail: Configuration file : '%s'.\n", filename);
printf("asmail: Make sure the permissions are set to 0600 before proceeding.\n");
return(-1);
}
}
return 0;
}
void mbox_thread( void * ptr ) {
struct mbox_struct * mb;
mb = (struct mbox_struct *) ptr;
if ( mb->type == MBOX_FILE ) {
mbox_handle( mb );
} else if ( mb->type == MBOX_DIR ) {
maildir_handle( mb );
} else if ( mb->type == MBOX_MH ) {
mh_handle( mb );
} else if ( mb->type == MBOX_POP3 ) {
pop3_handle( mb );
} else if ( mb->type == MBOX_IMAP ) {
imap_handle( mb );
} else {
printf("Don't know how to handle the mailbox of format '%d'\n",
mb->type);
mb->status = STAT_FAIL;
signal_update();
}
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
struct mbox_struct * tmp_mbox;
char * tmp_ptr;
x11_set.argc = argc;
x11_set.argv = argv;
if ( pthread_mutex_init(&update_lock, NULL) ) {
printf("asmail: main: failed to initialize update mutex.\n");
exit(-1);
}
if ( pthread_cond_init(&update_cv, NULL) ) {
printf("asmail: main: failed to initialize update condition variable.\n");
exit(-1);
}
if ( pthread_mutex_init(&md5_lock, NULL) ) {
printf("asmail: main: failed to initialize MD5 mutex.\n");
exit(-1);
}
if ( pthread_mutex_init(&check_lock, NULL) ) {
printf("asmail: main: failed to initialize check mutex.\n");
exit(-1);
}
if ( pthread_cond_init(&check_cv, NULL) ) {
printf("asmail: main: failed to initialize check condition variable.\n");
exit(-1);
}
defaults();
if ( parse_cmd(argc, argv) )
exit(-1);
if ( ! flag_no_config ) {
if ( parse_cfg(config_file_name) == -1 )
exit(-1);
}
if ( ! mbox ) {
/* no mailbox definitions, try to recover */
tmp_ptr = getenv("MAIL");
if ( tmp_ptr ) {
printf("asmail: no mailbox defnitions, using $MAIL (%s)\n", tmp_ptr);
if ( init_mbox(&tmp_mbox) ) {
return(-1);
}
strncpy(tmp_mbox->file, tmp_ptr, MAX_INPUT_LENGTH);
tmp_mbox->type = MBOX_FILE;
tmp_mbox->next = mbox;
mbox = tmp_mbox;
}
}
if ( ! mbox ) {
printf("asmail: no mailboxes to check, cowardly quitting.\n");
return(-1);
}
tmp_mbox = mbox;
while (tmp_mbox) {
pthread_create( &tmp_mbox->thread, pthread_attr_default,
(void*)&mbox_thread, (void*) tmp_mbox);
pthread_detach( tmp_mbox->thread );
tmp_mbox = tmp_mbox->next;
}
if ( ! flag_no_x ) {
pthread_create( &x11_set.thread, pthread_attr_default,
(void*)&startx, (void*) &x11_set);
pthread_detach( x11_set.thread );
}
while (1) {
pthread_mutex_lock(&update_lock);
while( update_count <= 0 ) {
pthread_cond_wait(&update_cv, &update_lock);
}
if ( flag_verbose )
printf("%d > ", update_count);
--update_count;
pthread_mutex_unlock(&update_lock);
tmp_mbox = mbox;
while ( tmp_mbox ) {
if ( flag_verbose ) {
printf("[%d] ", (unsigned)tmp_mbox->thread);
if ( tmp_mbox->status & STAT_RUN )
printf("R");
else
printf(" ");
if ( tmp_mbox->status & STAT_FAIL )
printf("F");
else
printf(" ");
if ( tmp_mbox->status & STAT_CONN )
printf("C");
else
printf(" ");
if ( tmp_mbox->status & STAT_LOGIN )
printf("L");
else
printf(" ");
if ( tmp_mbox->status & STAT_TIMEOUT )
printf("T");
else
printf(" ");
printf(" ");
switch (tmp_mbox->mail) {
case MAIL_NONE : printf(" ");
break;
case MAIL_OLD : printf("O");
break;
case MAIL_NEW : printf("N");
}
printf(" %d/%d ", tmp_mbox->cnew, tmp_mbox->ctotal);
}
tmp_mbox = tmp_mbox->next;
}
if ( flag_verbose )
printf("\n");
}
exit(0);
}
syntax highlighted by Code2HTML, v. 0.9.1