Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!uwm.edu!gem.mps.ohio-state.edu!tut.cis.ohio-state.edu!bloom-beacon!eru!luth!sunic!mcsun!ukc!kl-cs!jonathan From: jonathan@cs.keele.ac.uk (Jonathan Knight) Newsgroups: alt.sources Subject: Cmail - check to see who's read their mail - UNIX Message-ID: <1121@kl-cs.UUCP> Date: 23 Oct 89 13:48:04 GMT Organization: University of Keele, England Lines: 536 Here's a neat little program which detects whether users on your local machine have ready their mail recently. It reports when they last checked it and also whether any new mail has arrived since. Very useful if your local machine uses userids which are based on department or type of user or year of graduation. You may copy this program as often as you like - just don't pretend you wrote it. You may rip off any useful bits of code you like - a "thankyou" would be nice. #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./Makefile` then echo "Writing ./Makefile" cat > ./Makefile << '\Rogue\Monster\' # Makefile for cmail - a mail checking program # # This is the CFLAGS I had to use under Dynix so that the normal # include files were found first, but regexp.h was found in the # att universe. # #CFLAGS = -O -I/usr/include -I/usr/att/usr/include # CFLAGS = -O LFLAGS = # Destination: # DEST - The destination for the cmail executeable # MDEST - The destination for the cmail.1 manual source DEST = /usr/local/bin MDEST = /usr/man/man1 # all: cmail cmail: cmail.c cmail.h cc $(CFLAGS) $(LFLAGS) -o cmail cmail.c install: cmail cmail.1 install -c -m 755 -s cmail $(DEST) install -c -m 644 cmail.1 $(MDEST) clean: rm -f cmail.o cmail core a.out \Rogue\Monster\ else echo "Will not over-write ./Makefile" fi if `test ! -s ./README` then echo "Writing ./README" cat > ./README << '\Rogue\Monster\' cmail - check when people have read their mail - Version 1.1 Cmail is useful if you want to check to see if a group of people have read their mail. It allows regular expressions as a list of usernames to check, so sites which have usernames derived from the department or project a user is involved in will benefit. Check the compile options in the Makefile and then take a look at cmail.h. Once these are correct run make. Cmail has been tested on the following systems: Ultrix 1.2A (BSD4.2) Dynix 3.0.15 (BSD4.2 ish) Microport 2.4 (SYSVR2) (R.I.P.) SunOS 3.5 (BSD4.2) (Yellow Pages) Bugs, etc can be sent to: ______ JANET :jonathan@uk.ac.keele.cs Jonathan Knight, / BITNET:jonathan%cs.kl.ac.uk@ukacrl Department of Computer Science / _ __ other :jonathan@cs.keele.ac.uk University of Keele, Keele, (_/ (_) / / UUCP :...!ukc!kl-cs!jonathan Staffordshire. ST5 5BG. U.K. \Rogue\Monster\ else echo "Will not over-write ./README" fi if `test ! -s ./cmail.1` then echo "Writing ./cmail.1" cat > ./cmail.1 << '\Rogue\Monster\' .TH CMAIL 1 "8 July 1989" "Local Commands" .SH NAME cmail \- check when users last checked their mail .SH SYNOPSIS cmail [-v] userlist... .SH DESCRIPTION .LP .I Cmail is a program for showing when users last checked their mail. It produces output given the user name, their full name (as given in the password file) and when they last checked their mail. If no system mailbox exists then no date is shown. .LP If mail has been added to the mailbox since it was last checked then .I cmail will print .B "New Mail" beside the date the user last read their mail. .LP The .I userlist is a list of restricted regular expressions. The regular expressions are compared to the usernames in the password file and any match is then used. The restriction on the regular expressions is that the comparison is only performed at the start of the user name (an implicit circumflex at the start of the regular expression). .LP Note that any command that scans the mailbox of a user will cause .I cmail to believe the user has checked their mailbox. So .IR from (1) and .IR mail (1) when run will cause cmail to believe all the mail has been checked. Programs like the auto-reply daemon of the elm mailing system will also make cmail believe the mail has been checked. .SH OPTIONS .IP "-v" Print the version and release date of cmail. .SH EXAMPLES .LP Check users who's usernames start with 'biy'. .IP cmail biy .LP Check users who's name has a 'd' as the third character. .IP cmail ..d .LP Check users who's username begins with csa or cca and check the username advisory. .IP cmail -v "c[sc]a" advisory$ .SH AUTHOR Jonathan@cs.keele.ac.uk \Rogue\Monster\ else echo "Will not over-write ./cmail.1" fi if `test ! -s ./cmail.c` then echo "Writing ./cmail.c" cat > ./cmail.c << '\Rogue\Monster\' /* Reports on who's got mail to read. Version 1.0 Initial release Version 1.1 Fixed manual page Usage: mailfor [-v] user1 user2 user3 .... Users can be given as regular expressions. */ /* Options you shouldn't change */ #define REGSIZE 100 #define UNAMESIZE 10 #define FNAMESIZE 25 #define PRINT1 "%-10.10s %-25.25s " #define VERSION "1.1" #define DATE "8 July 1989" #define YEAR "1989" /* Include files */ #include "cmail.h" #include #include #include #include #include #ifdef TIME #include #else #include #endif #ifdef STRING #include #else #include #endif #ifdef INDEX #define strchr(a, b) index(a, b) #define strrchr(a, b) rindex(a, b) #endif struct passwd *getpwent(); /* These are not declared for SYSVR2 */ void endpwent(); /* so we'll declare them here. */ /* Global data declarations */ char *myname; /* Now comes the initialisation of the regular expression package. We use this rather than the regexp(3) routines because then we can hold all the arguments in a compiled form and just do one pass of the password file. */ void regerr(err) int err; { fprintf(stderr, "%s: Regular expresion failure %d\n", myname, err); exit(255); } #define INIT register char *sp = instring; #define GETC() (*sp++) #define PEEKC() (*sp) #define UNGETC(c) (--sp) #define RETURN(c) return; #define ERROR(c) regerr(c) #include /* Structures to hold the list of users and their full names after a scan of the password file. */ typedef struct userlist { char username[UNAMESIZE]; /* Username */ char fullname[FNAMESIZE]; /* Full name */ struct userlist *next; /* Next user in list */ } USERLIST; typedef struct userroot { char reguser[REGSIZE]; /* User name in regexp format */ char *argument; /* Original argument */ USERLIST *last; /* Last username in list */ USERLIST *first; /* First username in list */ } USERROOT; /* Functions we may want to use later */ USERROOT *build(); USERROOT *buildarray(); void buildlist(); void addtolist(); char *getusername(); void printarray(); void printstat(); void fatal(); char *malloc(); char *calloc(); /* Now the program */ main(argc, argv) char *argv[]; int argc; { USERROOT *array; /* Find out who I am */ myname=strrchr(*argv, '/'); if (myname == NULL) myname=(*argv); else ++myname; ++argv; --argc; /* If they've asked for a version then now is a good time to print it out. */ if (strcmp(*argv, "-v") == 0) { printf("\n%s Version %s, %s\n(C) Copyright %s Jonathan Knight\n\n", myname, VERSION, DATE, YEAR); ++argv; --argc; } /* Check for the obvious */ if (argc == 0) exit(0); /* Go to the spool directory. */ if (chdir(MSPOOL)) fatal("Can't access mail spool directory", errno); /* Create an array of users which match the arguments */ array=build(argc, argv); /* Print out the result */ printarray(argc, array); exit(0); } /* Build a list of users and their full names */ USERROOT *build(argc, argv) int argc; char *argv[]; { USERROOT *array; array=buildarray(argc, argv); if (array != NULL) buildlist(argc, array); return(array); } /* This function builds an array of the arguments passed ready for a scan of the password file */ USERROOT *buildarray(argc, argv) int argc; char *argv[]; { USERROOT *array; int i; array=(USERROOT *)calloc(argc, sizeof(USERROOT)); if (array == NULL) return(NULL); /* Array already initialised to 0 by the calloc call */ for (i=0; ipw_name, array[i].reguser)) addtolist(&array[i], pwent); endpwent(); /* Report on any regexp's that didn't match anything */ for (i=0; ifirst == NULL) el->first = new; else el->last->next=new; el->last=new; new->next = NULL; strncpy(new->username, pwent->pw_name, UNAMESIZE); strncpy(new->fullname, getusername(pwent->pw_gecos), FNAMESIZE); } /* Now a function to print out all the users we have collected */ void printarray(argc, array) USERROOT array[]; { int i; USERLIST *p; if (array == NULL) return; for (i=0; inext) printstat(p); } /* Function to stat the mail file and print out some information. */ void printstat(p) USERLIST *p; { struct stat buf; printf(PRINT1, p->username, p->fullname); if (stat(p->username, &buf) == 0) { printf("%.19s", ctime(&buf.st_atime)); if ((buf.st_atime < buf.st_mtime) && (buf.st_size)) printf(" New Mail"); } putchar('\n'); fflush(stdout); } /* Function to perform a fatal error */ void fatal(mess, err) char *mess; int err; { fprintf(stderr, "%s: ", myname); perror(mess); exit(err); } \Rogue\Monster\ else echo "Will not over-write ./cmail.c" fi if `test ! -s ./cmail.h` then echo "Writing ./cmail.h" cat > ./cmail.h << '\Rogue\Monster\' /* Options: * *SYSVG - You have a SYSV gecos field in your passwd file "(000)-Name(0000)" * *FINGG - You have a BSD finger type GECOS field "name, office, ext, ..." * (If neither of the above is defined then the GECOS field is assumed * to only contain the user's name) * *STRING - If the file /usr/include/string.h exists. Otherwise * /usr/include/strings.h is used instead. * *TIME - time.h is in /usr/include and not /usr/include/sys * *INDEX - You have index and rindex rather that strchr and strrchr. * *MSPOOL - Where the system mailboxes are. */ #undef SYSVG #undef FINGG #undef STRING #undef TIME #define INDEX #define MSPOOL "/usr/spool/mail" \Rogue\Monster\ else echo "Will not over-write ./cmail.h" fi echo "Finished archive 1 of 1" exit -- ______ JANET :jonathan@uk.ac.keele.cs Jonathan Knight, / BITNET:jonathan%cs.kl.ac.uk@ukacrl Department of Computer Science / _ __ other :jonathan@cs.keele.ac.uk University of Keele, Keele, (_/ (_) / / UUCP :...!ukc!kl-cs!jonathan Staffordshire. ST5 5BG. U.K.