devine@asgb.UUCP (11/19/84)
Here is a little program that I have used for a while and thought other folks may want to use. The idea came from Brian Kernighan and Rob Pike's book "The Unix Programming Environment". They gave a little program that checked for a growing mailbox. The assumption is that a larger mailbox means that one (or more) message have been appended to it since the last time its size was checked. It was fine for the simple case. However, if you are reading mail when a new message comes in and you delete an existing message, there is no way to determine if a new message arrived by size checking alone. I've also added all sorts of bells and whistles to the original. In the latest incarnation of 'checkail' it will asynchronously tell you when mail has arrived, giving the sender's name and the 'Subject:' line, if any. BUT, if you don't like it breaking through when you are editing, you'll have to modify it to wait with a message (some suggestions are setting the eXecute bit for your TTY line or using a LCK.TERM file to mean "don't bother me with mail now!"). Environment stuff: I use it for System V.2 Unix, it MAY still work for BSD Unixes -- it has been modified greatly since it last ran on 4.1. There are #ifdef BSD sections included. Run 'checkmail' in the background. Use the command sh -c "checkmail &" if you don't like the process number to be displayed. For BSD, you will have to kill the process when you logout, so keep that PID or just make sure that it is the first job and kill it using %1. If you are worried about everyone running their own copy or checkmail and gobbling up needed process slots, change it to run like 'biff' to check everyone's mailbox who wants it done (exercise left to the reader...). One more thing, change the NOISE string to whatever you want to be bothered by. Postnews will probably chew up the current string "escape#>". Bob Devine Burroughs-ASG {sdcsvax || sdcrdcf}!bmcg!asgb!moloch!devine ---------------- cut ------ here ------------------------ /* checkmail : program to watch a user's mailbox */ /* Oct. 84 Bob Devine */ #include <stdio.h> #include <errno.h> #include <signal.h> #include <sys/types.h> #include <time.h> #ifdef BSD #include <sys/timeb.h> #endif #include <sys/stat.h> #define WHO_LENGTH 15 /* assume max user_name is 15 chars (safe)*/ #ifdef BSD #define POST_OFFICE "/usr/spool/mail" #else #define POST_OFFICE "/usr/mail" #endif /**** GLOBAL VARIABLES ****/ unsigned char line[512]; /* working space throughout program */ char *prog_name; /* what this program is called */ struct tm * prev_tm; FILE *outfile, *mailfp; char *NOISE = "#>"; /* vt100 style keyclick -- -- should use BEL from terminfo/cap */ main (argc, argv) char **argv; { struct stat mail_box; /* the user's mailbox */ struct tm temp_tm; /* used at program start up */ char *user_name; char *getlogin(); /* used for finding correct mailbox */ long last_time_checked; long time(); int last_size, snooze_amount; prog_name = argv[0]; if ((outfile = fopen("/dev/tty", "w")) == NULL) die("error opening /dev/tty for output", (char *) 0); if ((user_name = getlogin()) == NULL) /* find out who is running this */ die("can't get your login name", (char *) 0); if (chdir(POST_OFFICE) == -1) die("can't cd to %s", POST_OFFICE); prev_tm = &temp_tm; /* start with it zeroed out */ #ifdef BSD /* ignore the TOSTOP signal for running in background */ signal(SIGTTOU, SIG_IGN); #endif while (1) /* run until gets [kill, intr, hup, ETC] sig) */ { while (stat(user_name, &mail_box) == -1) /* no mailbox found */ if (errno == ENOENT) sleep(300); /* wait 5 min & try again */ else die("error with the mail file", (char *) 0); if ((mailfp = fopen(user_name, "r")) == NULL) die("error opening mail file for read\n", (char *) 0); /* Any new mail? */ if (mail_box.st_size != last_size) { /* examine EVERY message to see if it is new */ lseek(fileno(mailfp), 0L, 0); check_for_new_msgs(); } fclose(mailfp); last_size = mail_box.st_size; time(&last_time_checked); prev_tm = localtime(&last_time_checked); /* sleep until the 'top-of-the-minute' */ snooze_amount = 59 - prev_tm->tm_sec; if (snooze_amount < 20) /* for efficiency sake && */ snooze_amount += 60; /* avoiding sleeps of zero */ sleep(snooze_amount); } } /* has_a : tells if the 'string' has 'word' at beginning */ has_a(word, string) register char *word, *string; { while(*word) if (*word++ != *string++) return(0); return(1); } /* is_a_new_msg : check the From line for the date (kludge, kludge) */ is_a_new_msg(from_line) char *from_line; { register char *p; int day, hour, min; /* the date has format "Mon Oct 8 10:48 1984" */ for (p = from_line+12; *p!=':' && *p!='\0'; p++) ; if (! *p) return(0); /* if colon not found, assume old mesg */ p = p - 5; /* back into the DAY field */ day=0; if (*p >= '\060') /* ignore if blank */ day = ((int) *p - 060); p++; day = day * 10 + ((int) *p - 060); p = p + 2; hour = ((int) *p++ - 060) * 10 + ((int) *p - 060); p = p + 2; min = ((int) *p++ - 060) * 10 + ((int) *p - 060); /* check to see if this message is older than the last time checked */ /* NOTE: best resolution is 1 min */ if ((min >= prev_tm->tm_min) && (hour == prev_tm->tm_hour)) return(1); if ((hour > prev_tm->tm_hour) && (day == prev_tm->tm_mday)) return(1); if (day > prev_tm->tm_mday) /* if program is run after midnight */ return(1); /*-- or program has just started */ return(0); } check_for_new_msgs() { int i; /* loop variable */ char who_sent[WHO_LENGTH]; while (fgets(line, sizeof(line), mailfp) != NULL) if (has_a("From ", line)) if (is_a_new_msg(line)) { int count = 0; for (i=0; i < WHO_LENGTH; i++) if ((who_sent[i] = line[i+5]) == ' ') break; who_sent[i] = '\0'; fprintf(outfile, "\n New mail from %s - ", who_sent); fgets(line, sizeof(line), mailfp); /* eat 'To' line */ fgets(line, sizeof(line), mailfp); /* subject line? */ while ((count < 4) && (! has_a("Subject: ", line))) { fgets(line, sizeof(line), mailfp); count++; } if (has_a("Subject: ", line)) fprintf(outfile, "%s%s", line, NOISE); else fprintf(outfile, "(no subject)%s\n", NOISE); fflush(outfile); } } /* die : print error message and die */ die(s1, s2) char *s1, *s2; { extern int errno, sys_nerr; extern char *sys_errlist[], *prog_name; if (prog_name) fprintf(stderr, "%s: ", prog_name); (void)fprintf(stderr, s1, s2); if (errno > 0 && errno < sys_nerr) fprintf(stderr, " (%s)", sys_errlist[errno]); (void)fprintf(stderr, "\n"); exit(1); }