larry@geowhiz.UUCP (Larry McVoy) (07/31/86)
[munch] This is a hack that I wrote to replace biff(1) as available under the BSD systems. It runs one process per user instead of just a daemon. Instead of listening to a socket it looks at yor mail file every 30 seconds to see if it got bigger. If so it will print out the header lines from the last message in the file (bug: it won't catch multiple messages that come in at the same time, just the last one). The difference between biff and MAILCHECK is that biff is asynchronous -- it will interrupt whatever you are doing (not really, you can control it with mesg(1)) to tell you abot new mail. You have to get root to install it unless you can create a dir in /usr/spool. --- cut here --- # This is a shell archive. Remove anything before this line, then # unpack it by saving it in a file and typing "sh file". (Files # unpacked will be owned by you and have default permissions.) # # This archive contains: # biff.biff biff.c biff.l biff.readme echo x - biff.biff cat > "biff.biff" << '//E*O*F biff.biff//' ^[>]From ^Subject //E*O*F biff.biff// echo x - biff.c cat > "biff.c" << '//E*O*F biff.c//' /* biff.c 1.3 - main, shh, cleanup, syserr, isthere, ping */ /* * biff -- be informed about incoming mail * * usage biff [y] [n] * bugs: it uses a stupid alg to see if you have new mail: stat the file, * sleep TIMEOUT seconds, stat it again & if it got bigger then new mail. * This can occassionally miss new mail. * * You can have this code, hack it, claim it as your own, and you don't have * to keep any stupid little copyright notice at the top. Can you deal? */ # include <stdio.h> # include <varargs.h> # include <signal.h> # include <sys/types.h> # include <sys/stat.h> # define TIMEOUT 30 # define isthere(x) (access(x, 0) == 0) # define ping(id) kill(id, 0) # define shhh(x) (!(x.st_mode & 02) && !getenv("BIFF")) /* #define strrchr rindex /* for 4.x */ char* biff = "/usr/spool/biff/llllllllll0"; /* global for cleanup */ main(argc, argv) char** argv; { char* biffdir = "/usr/spool/biff"; char* mail = "/usr/mail/llllllllll0"; char* sysmatch = "/usr/skel/.biff"; char* match; char usrmatch[100], line[100]; int sh_id = getppid(); struct stat old, new; int cleanup(); FILE* popen(); FILE* info; sprintf(strrchr(biff, '/') + 1, "%.10s", getlogin()); sprintf(strrchr(mail, '/') + 1, "%.10s", getlogin()); sprintf(usrmatch, "%s/.biff", getenv("HOME")); if (!isthere(biffdir)) syserr("%s: can't access %s\n", argv[0], biffdir); if (argc == 1) { if (!isthere(biff) == 0) printf("is y\n"); else printf("is n\n"); exit(0); } else if (argc == 2 && *argv[1] == 'n') { unlink(biff); exit(0); } else if (*argv[1] != 'y') { fprintf(stderr, "usage: %s [y] [n]\n", argv[0]); exit(1); } signal(SIGINT, cleanup); signal(SIGQUIT, cleanup); signal(SIGHUP, cleanup); signal(SIGTERM, cleanup); close(creat(biff, 0644)); if (fork()) exit(0); if (stat(mail, &new)) { fprintf(stderr, "%s: can't stat %s\n", argv[0], mail); unlink(biff); exit(2); } while(1) { sleep(TIMEOUT); if (ping(sh_id)) { unlink(biff); exit(0); } if (!isthere(biff)) exit(0); stat(mail, &new); if (shhh(new)) continue; if (new.st_size > old.st_size) { if (isthere(usrmatch)) match = usrmatch; else if (isthere(sysmatch)) match = sysmatch; else match = "'^[>]*From'"; /* must be single quoted */ printf("\007\r\nNew mail has arrived...\r\n"); sprintf(line, "revgrep -t '^[>]*From' %s | egrep %s%s\n", mail, match[0] == 047 ? "" : "-f ", match); info = popen(line, "r"); while (fgets(line, sizeof(line), info)) { printf("%s\r", line); } pclose(info); } old = new; /* struct assign */ } } cleanup() { unlink(biff); exit(0); } /* from "Advanced Unix Programming" (p13), M. Rochkind (modified) */ syserr(va_alist) va_dcl { extern int errno, sys_nerr; extern char* sys_errlist[]; va_list ap; char* fmt; va_start(ap); fmt = va_arg(ap, char*); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\terrno: (%d", errno); if (errno > 0 && errno < sys_nerr) fprintf(stderr, "; %s)\n", sys_errlist[errno]); else fprintf(stderr, ")\n"); exit(errno ? errno : 1); } //E*O*F biff.c// echo x - biff.l cat > "biff.l" << '//E*O*F biff.l//' .TH BIFF 1 LOCAL .ad b .SH NAME biff \- be informed of new mail arrivals .SH SYNOPSIS \fBbiff\fR [\fBn\fR] [\fBy\fR] .SH DESCRIPTION .I Biff will asynchronously print out the header lines of your latest mail message soon after it arrives. Biff without arguments tells you if it is on or off. Biff is not completly asynchronous, it will run but be silent if messages are off (ie it's quiet when you're in vi). You may make biff fully asynchronous by creating an environment variable \fIBIFF\fR with an arbitrary value. .PP The header lines printed are matched based on a list of possibilities that the user can create and store in a file called \fI$HOME/.biff\fR. For example, to match the \fIFrom\fP, \fITO\fP and \fISubject\fP lines, the file contains .sp 1 ^[>]*From .br ^To .br ^Subject .br .sp 1 The carats (^) insure that only the header lines are matched. .PP If \fI$HOME/.biff\fR is not accessible then \fI/usr/skel/.biff\fR is used. The fields in that file are whatever the systems administrator choses (From & Subject should be there and those make a pretty good default). If neither \fI$HOME/.biff\fR nor \fI/usr/skel/.biff\fR is accessible then the first \fIFrom\fR line is printed. .PP Available options are: .TP .B y Turn on biff. .TP .B n Turn off biff. .SH BUGS .I Biff should really be a daemon but that only works if mail comes in over a socket. .PP It would be nice if you could be informed about mail coming into multiple mailboxes. .SH FILES .TP /usr/spool/biff directory for flag files. Must be writable by users. .TP /usr/spool/biff/$LOGFILE flag file .TP $HOME/.biff list of fields, one per line, to print. .TP /usr/skel/.biff default list of fields, one per line, to print. .SH "SEE ALSO" revgrep(1), egrep(1), mesg(1), setenv(1) .SH AUTHOR Larry McVoy (idea from 4.2 biff(1)) //E*O*F biff.l// echo x - biff.readme cat > "biff.readme" << '//E*O*F biff.readme//' OK, here's how you install it: cc -O biff.c -o biff chown bin biff; chgrp bin biff; mv biff /usr/local/bin mkdir /usr/spool/biff; chmod 777 /usr/spool/biff cp biff.biff /usr/skel/.biff cp biff.l /usr/man/manl (or whatever you man local dir is) Complain to larry@geowhiz.uucp or mcvoy@rsch.wisc.edu if it doesn't work. //E*O*F biff.readme// echo Possible errors detected by \'wc\' [hopefully none]: temp=/tmp/shar$$ trap "rm -f $temp; exit" 0 1 2 3 15 cat > $temp <<\!!! 2 2 18 biff.biff 132 434 3263 biff.c 65 302 1819 biff.l 9 47 320 biff.readme 208 785 5420 total !!! wc biff.biff biff.c biff.l biff.readme | sed 's=[^ ]*/==' | diff -b $temp - exit 0 -- Larry McVoy ----------- Arpa: mcvoy@rsch.wisc.edu Uucp: {seismo, topaz, harvard, ihnp4}!uwvax!geowhiz!larry "Just remember, wherever you go -- there you are." -Buckaroo Banzai