[comp.sources.misc] v06i098: display time in MSKermit 2.32 mode line

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (05/08/89)

Posting-number: Volume 6, Issue 98
Submitted-by: spolsky-joel@YALE.ARPA (Joel Spolsky)
Archive-name: clock.msk

Here's a short program I wrote. It's not of much use unless you have
MS-Kermit 2.32 or some other PC-based VT100 terminal emulator with a
writable mode line.

If you happen to be using IBM/PC Kermit in VT102 emulation mode to log
onto a Unix machine, you might find this little program fun. When you
run it on Unix, it displays a running time and date in the mode line
(line 25, otherwise useless). If you have mail it tries to figure out
who it's from and displays that on the modeline too. I find it to be
really neat. There's just one C program and a man page; you should
have no problem getting it to work on any generic Unix: I've tried it
with SunOS 4.0 and Ultrix on Suns, VAXen, and Decstations.

It might be possible to modify this to work with other terminals that
let you write in the mode line; if so please let me know.

+----------------+----------------------------------------------------------+
|  Joel Spolsky  | bitnet: spolsky@yalecs.bitnet     uucp: ...!yale!spolsky |
|                | internet: spolsky@cs.yale.edu     voicenet: 203-436-1483 |
+----------------+----------------------------------------------------------+
                                                      #include <disclaimer.h>


#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#-----cut here-----cut here-----cut here-----cut here-----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	vt100clock.1
#	vt100clock.c
# This archive created: Sat May  6 02:06:35 1989
echo shar: extracting vt100clock.1 '(1279 characters)'
sed 's/^X//' << \SHAR_EOF > vt100clock.1
X.TH VT100CLOCK 1 "5 May 1989"
X.SH NAME
Xvt100clock \- display clock & mail info on mode line of VT100 emulator
X.SH SYNOPSIS
X.B vt100clock
X[
X.B seconds
X] 
X.SH DESCRIPTION
X.B vt100clock
Xis meant for users who are logging onto Unix systems with PC's running
Xthe kermit terminal emulator in VT102 emulation mode. It might work
Xwith other terminal emulators; I haven't tried it.
X.B vt100clock
Xdisplays the date and time in the lower right hand corner of the
Xscreen. This is updated every 30 seconds, unless you specify a
Xdifferent number of seconds on the command line. In addition, if the
Xuser has mail, it attempts to find the names of the senders and
Xdisplay them on the mode line as well.
X.B vt100clock
Xruns in the background automatically. It will automatically die when
Xyou log out (actually, when the shell from which you executed the
Xcommand dies). 
X.SH BUGS
XThe method used to figure out who mail is from is not perfect and
Xsometimes gets confused. Also, since vt100clock drops into the
Xbackground automatically it is hard to kill it; you have to find its
Xprocess id (ps aux | grep vt100clock) and kill that process. Usually
Xit is sufficient to have it automatically die on logout. I have never
Xseen this interfere with other screen-oriented programs although it
Xmight do so.
SHAR_EOF
if test 1279 -ne "`wc -c vt100clock.1`"
then
echo shar: error transmitting vt100clock.1 '(should have been 1279 characters)'
fi
echo shar: extracting vt100clock.c '(8858 characters)'
sed 's/^X//' << \SHAR_EOF > vt100clock.c
X/** vt100clock for Unix and Kermit - version 1.00
X ** 
X ** (C) 1989 Joel Spolsky. All Rights Reserved. Permission is
X ** granted for noncommercial use of this software. You may use,
X ** distribute, or modify this software as long as you don't make
X ** people pay you for it. I assume no responsibility if this
X ** program doesn't work!!!
X **
X ** This program requires that you be logged on using a vt100 terminal
X ** emulator with 25 lines, for example, Kermit 2.31 with the mode line
X ** turned off. It's pretty generic; I have tested it on a Sun 3
X ** under Sun-OS 4.0, a VAX running Ultrix, and a decstation 3100 also
X ** running Ultrix. Standard "cc" and GNU "gcc" compile it with no
X ** complaints on all the above systems.
X **
X ** It displays the time and date in the lower right hand corner.
X ** Also, if you have mail, it tells you and tries to figure out who the
X ** mail is from. The program runs quietly in the background
X ** (you don't have to put it in the background with & - it drops
X ** to the background automatically). It dies as soon as the shell that
X ** spawned it dies, i.e., when you log out.
X **
X ** It accepts one optional argument which is the number of seconds
X ** to sleep for between checks. This is currently 30 seconds by
X ** default if no argument is specified.
X **/
X
X/** 
X ** Here are some #defines you might need to play with:
X **/
X
X#define MAILFILE "/usr/spool/mail/%s"
X/* Where mail spool files are kept in your system. The %s will be replaced
X   with the user name. */
X
X#define SLEEPTIME 30
X/* by default, how many seconds to sleep for between checks */
X
X
X#define ESC 27
X#define clearmodeline() printf("%c7%c[25;1H%c[2K%c8", ESC, ESC, ESC, ESC)
X
X#include <signal.h>		/* to handle keyboard interrupts */
X#include <stdio.h>		
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <time.h>
X
Xint clean_and_exit();		/* clear mode line and exit */
X
Xmain(argc,argv)
X     int argc;
X     char **argv;
X{
X    char modeline[81];		/* whats on the modeline now */
X    char newmodeline[1024];	/* what we want to be there - big in case
X				   lots of mail. */
X    int firstchange, lastchange;/* changes in modeline */
X    struct tm *tm;		/* time structure */
X    long timeval;		/* time in seconds locally */
X    char *nowtext;		/* text of day, date, time */
X    struct stat st;		/* for checking size of mailbox */
X    char path[50];		/* path file name of mailbox */
X    char iline[80];		/* input line from mail file */
X    int old_size=0, new_size=0;	/* size of mailbox */
X    int shellid; /* pid of user's shell. program will die if user logs off */
X    FILE *mailfile;		/* mailbox */
X    int i;			/* loops */
X    int sleeptime=SLEEPTIME;	/* how long to sleep */
X
X
X    /* Trap signals to abort: first clean bottom line, then die. */
X    signal(SIGHUP,clean_and_exit);  /* handle hangup */
X    signal(SIGINT,clean_and_exit);  /* ctrl-C handler */
X    signal(SIGQUIT,clean_and_exit); /* ctrl-\ handler */
X    signal(SIGTERM,clean_and_exit); /* if process is killed */
X
X    if (argc == 2) sleeptime = atoi(argv[1]);
X
X    /* When the parent dies, this will die. Since vt100clock is
X       usually execl'ed from the users shell, this means that when
X       the user logs out, vt100clock will die immediately instead
X       of scribbling on the terminal of the next person that
X       happens to log on to the same tty. */
X
X    shellid = getppid();
X
X    /* drop into the background */
X    if (fork()) exit();
X
X    /* first thing - clear the mode line */
X    clearmodeline();
X    fflush(stdout);
X
X    /* for portability, I am not using memset. */
X    for (i=0; i<80; i++) 
X	newmodeline[i] = modeline[i] = ' ';
X    newmodeline[80] = modeline[80] = 0;
X
X    /* remember where mail is kept */
X    sprintf(path, MAILFILE, cuserid(NULL));
X
X    while(kill(shellid,0)==0) {       /* while still logged on */
X
X	/* check mail */
X	old_size = new_size;
X	if (!stat(sprintf(path, MAILFILE, cuserid(NULL)), &st))
X	    new_size = st.st_size;
X	else 
X	    new_size = 0;
X
X	/* if mailbox grew or shrank, analyze who mail is from... */
X	if (old_size != new_size) {
X	    newmodeline[0] = '\0';
X	    if (new_size > 0) {
X		strcat (newmodeline,"Mail from: ");
X		
X		/* open mail file to see who mail is from */
X		mailfile = fopen (path, "r");
X
X		/* read a line at a time... */
X		while (fgets (iline,79,mailfile) != NULL) {
X		    /* check if line begins From: **/
X		    if (strncmp(iline, "From:", 5) == 0) {
X			parse(iline); /* extract name */
X			strcat (newmodeline, iline);
X		    }
X		    if (strlen(newmodeline) > 63) {
X			newmodeline[60] =
X			    newmodeline[61] =
X				newmodeline[62] = '.';
X			newmodeline[63] = ' ';
X			newmodeline[64] = 0; /* max length we can display */
X		    }
X		}
X		fclose (mailfile);
X	    }
X	}
X	/* find time */
X	timeval = time(0);
X	tm=localtime(&timeval);
X	nowtext = asctime(tm);
X	nowtext[16]=0;		/* get rid of seconds and year */
X	/* put this time into newmodeline */
X	/* add at least 64 blanks to newmodeline */
X	for (i=0; i<4; i++)
X	    strcat(newmodeline,"                ");
X	/* chop it... */
X	newmodeline[64] = 0;
X	strcat(newmodeline, nowtext);
X
X        /* Instead of printing the whole newmodeline, just see
X	   where it differs from the old modeline
X	   and print that much. */
X	firstchange = 0; lastchange = 79;
X	/* assume we'll have to update whole modeline */
X
X	while (newmodeline[firstchange] == modeline[firstchange] &&
X	       firstchange <= 80)
X	    firstchange++;
X	if (firstchange!=81) /* changes */ {
X	    /* figure out last change */
X	    while (newmodeline[lastchange] == modeline[lastchange] &&
X		   lastchange >= firstchange)
X		lastchange--;
X	    /* print line from firstchange to lastchange. */
X	    /* sorry this printf is such a mess. */
X	    printf("%c7%c[25;%dH%.*s%c8",ESC,ESC,
X		   firstchange+1,
X		   lastchange-firstchange+1,
X		   newmodeline+firstchange,ESC);
X
X	    /* output must be flushed or else it will not necessarily be sent
X	       right away. */
X	    fflush(stdout);
X	}
X	strncpy(modeline,newmodeline,80);
X
X	sleep(sleeptime); /* redo this every sleeptime seconds... */
X    }
X    /* if we get this far, user logged off - take no more action. */
X}
X
Xclean_and_exit()
X{
X    clearmodeline();
X    fflush(stdout);
X    exit(-1);
X}
X
X/** parse: take a whole From: line and try to extract the person's name
X ** otherwise settle for email address.
X **
X ** Cases this understands:
X **
X ** From: Email@address.here               Use Email address (all we know)
X ** From: email@so.and.so (Joe User)       Extracts name from (parentheses)
X ** From: Joe User <Email@address.here>    Just take the name before <email>
X ** From: <email@address.here>             Take email address (all we know)
X **
X ** BUGS: From: lines that do not signify new messages will also be
X ** reported as senders (this can happen if a message is quoted)
X ** Officially we should be looking at "\nFrom " which really means
X ** "new message" but that does not usually have the sender's real name.
X ** There may be problems with some kinds of mailers that I don't
X ** know about. This algorithm seems to usually work for arpanet,
X ** uucp, and bitnet mail. 
X **/
X
Xparse (iline)
X     char *iline;
X{
X    int i,j,l;
X
X    /* Shift left to get rid of From: keyword and blanks */
X    j=5;
X    while (iline[j]==' ') j++;
X    for (i=0; iline[j]; i++, j++)
X	iline[i] = iline[j];
X    iline[i]=0;
X
X    l=strlen(iline);
X    
X    /* scan for parentheses */
X    for (i=0; i<l; i++) {
X	if (iline[i] == '(') {
X	    for (j=0, i++; iline[i] != ')'; j++, i++)
X		iline[j] = iline[i];
X	    iline[j] = 0;
X	}
X	/* if there is an email address <in angle brackets>
X	   AND there is something between the From: and the brackets,
X	   keep only that something. */
X        if ((iline[i] == '<') && (i>7)) {
X	    iline[i] = 0;
X	}
X    }
X
X/* scan and replace newlines with 0s */
X    for (i=0; i<l; i++)
X	if (iline[i] == '\n') {
X	    iline[i] = 0;
X	    break;
X	}
X    strcat(iline," "); /* add a space, always. */
X    return;
X}
X	    
X
X/** A few words about this program:
X ** It works by instructing the terminal to remember the cursor position,
X ** then it jumps down to the 25th line and updates what needs to be
X ** updated, then it instructs the terminal to restore the remembered
X ** cursor position.
X **
X ** The byte stream this sends to the terminal is kept short, in hopes
X ** that it will be sent atomically. I have observed no problems with
X ** any programs, including emacs and other curses programs.
X ** It is conceivable that some software (perhaps software that relies
X ** upon the ability to save and restore cursor positions) will not
X ** work correctly while vt100clock is running.
X **
X ** For more info, later versions, etc, please contact the author:
X **
X **                             Joel Spolsky
X **                             spolsky@yalecs.bitnet
X **                             spolsky@cs.yale.edu
X **                             ...!yale!spolsky
X **/
X
X
X
X
X
SHAR_EOF
if test 8858 -ne "`wc -c vt100clock.c`"
then
echo shar: error transmitting vt100clock.c '(should have been 8858 characters)'
fi
#	End of shell archive
exit 0