/* * asmail is the AfterStep mailbox monitor * Copyright (c) 2002-2007 Albert Dorofeev * For the updates see http://www.tigr.net/ * * This software is distributed under GPL. For details see LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #include #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 name of the configuration file to use\n"); printf("-geometry 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 ) { 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); }