From:	CSBVAX::MRGATE!RELAY-INFO-VAX@CRVAX.SRI.COM@SMTP 17-AUG-1988 22:15
To:	ARISIA::EVERHART
Subj:	Announcing TERMLOCK.  Lock terminal plus REPLY for VMS.


Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Wed, 17 AUG 88 08:23:20 PDT
Received: from ucbvax.Berkeley.EDU by KL.SRI.COM with TCP; Wed, 17 Aug 88 07:58:08 PDT
Received: by ucbvax.Berkeley.EDU (5.59/1.30)
	id AA05298; Wed, 17 Aug 88 07:08:43 PDT
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 16 Aug 88 00:25:22 GMT
From: mcmi!hdr!unocss!dent@uunet.uu.net  (Dave Caplinger)
Organization: U. of Nebraska at Omaha
Subject: Announcing TERMLOCK.  Lock terminal plus REPLY for VMS.
Message-Id: <378@unocss.UUCP>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

Following is the source code for TERMLOCK.C, a program based on Eric
Rostetter's recently posted REPLY program.  Termlock functions similarly
to REPLY, but adds the ability to lock the terminal.

See the comments below for more specific details on the program, how to
compile it, etc.   (I appologize for posting straight source code, but I
don't have VMS_SHAR(E)....)

-/ Dave Caplinger /--------------+--------------------------------------------
 Microcomputer Specialist        | Internet: UNOCC07%ZEUS.DNET@FERGVAX.UNL.EDU
 Campus Computing                | UUCP:     uunet!unocss!dent
 University of Nebraska at Omaha | Bitnet:   UNOCC07@UNOMA1
 Omaha, NE 68182                 |   or      dc3a+@andrew.cmu.edu



(----------------- cut here ------------------------------------------------)

/***********************************************************************/
/*                                                                     */
/*   TERMLOCK							       */
/*								       */
/*	This program will automatically reply to user messages, phone  */
/*   requests, and network files with a different message depending on */
/*   the type of message received.  The standard user-message reply    */
/*   can be redefined by the user by 1) defining TERMLOCK as a foreign */
/*   command (i.e. $ termlock :== $the$disk:[the.path]the.file ), and  */
/*   2) adding an additional argument in quotes.  The TERMLOCK program */
/*   additionally provides the ability to lock the terminal with a     */
/*   user-defined password, so the user can run the program with a msg */
/*   like: TERMLOCK "I'm at lunch right now, be back at 12:45.", lock  */
/*   the terminal, and leave the office without having to worry about  */
/*   someone walking in, hitting 'Q', and damaging his or her account. */
/*	TERMLOCK logs all messages it receives in a file called        */
/*   TERMLOCK.LOG in the user's login directory (sys$login).  The file */
/*   can be deleted when the log is no longer wanted.		       */
/*								       */
/*   Many thanks to Eric Rostetter of the University of Toledo for the */
/*   original program "REPLY", which was the inspiriation for (and     */
/*   indeed the very basis of) this program.  Several of the routines  */
/*   included here are written by him.  (The majority of, as a matter  */
/*   of fact! :-)  Many thanks also to Tim Russell, CONSLT32@UNOMA1,   */
/*   for his invaluble help in programming and extensive testing.      */
/*
     Bug reports, comments, questions, etc to:

-/ Dave Caplinger /---------------+--------------------------------------------
  Microcomputer Specialist        | Internet: unocc07%zeus.dnet@crcvms.unl.edu
  Campus Computing                | uucp:     uunet!ugn!unocss!dent
  University of Nebraska at Omaha | Bitnet:   UNOCC07@UNOMA1
  Omaha, NE 68182                 | (Last Resort: dc3a+@andrew.cmu.edu)

*/
/***********************************************************************/
/*								       */
/* This program will correctly handle the following types of messages: */
/*                                                                     */
/*	Message Type			       Log    Reply  Display   */
/*                                                                     */
/*	SEND user "msg"				x	x	       */
/*	SEND user@node "msg"			x	x	       */
/*	SEND node::user "msg"			x	x	       */
/*	SEND/FILE file user			x	x	       */
/*	SEND/FILE file user@node		x	x	       */
/*	SEND/FILE file node::user		x	x	       */
/*	PHONE user				x	x	       */
/*	PHONE node::user			x	x	       */
/*	REPLY (from operator)			x		x      */
/*	REPLY/URGENT				x		x      */
/*	REPLY/SHUTDOWN				x		x      */
/*	(New Mail...)				x		       */
/*	(Job completed...)			x		       */
/*								       */
/*	NOTE: messages from the person running the program not logged  */
/*	  and not replied to (this would start an infinite loop).      */
/*	  Also, messages received that begin with * are ignored.       */
/*	  (This prevents replies to servers, other TERMLOCKs running   */
/*	  at the same time, etc.)  Lastly, messages received from      */
/*	  machines themselves (i.e. the response from something like   */
/*	  SEND @UNOMA1 FINGER UNOCC07) are ignored.                    */
/*                                                                     */
/***********************************************************************/
/*                                                                     */
/* Modification History: (For REPLY, written by Eric Rostetter)        */
/*                                                                     */
/*      21-JAN-1986     Finished initial coding of program version 1.0 */
/*      21-APR-1986     Update for the new version of JNET (user@node) */
/*      18-JUN-1986     Fix GET_NAME bug,  make it ignore csnews@maine */
/*      16-SEP-1986     Added code to save and restore terminal stuffs */
/*      19-SEP-1986     Added code to allow the user to supply message */
/*      23-SEP-1986     Added code to display time and date on  screen */
/*       9-OCT-1986     Removed SMG routines and added mailbox routine */
/*      14-OCT-1986     Cleaned up the screen I/O and what have you... */
/*      20-OCT-1986     Add code to stop the infinite loop problems... */
/*       2-DEC-1986     Fixed reply_to_msg so screen is always updated */
/*      17-DEC-1986     Fixed 'logout' bug caused by network/blank msg */
/*      11-FEB-1987     Kludged bug in UPDATE_TIME,  added ^C/^Y traps */
/*      31-MAR-1987     Added logical name translation,  fixed isvalid */
/*       9-APR-1987     Removed reference to LNMDEF.H for compatibilty */
/*      13-APR-1987     Added third counter, reset counters code, etc. */
/*      14-APR-1987     Cleaned up the code, made slight modifications */
/*      19-AUG-1987     Changed logicals for JNET version 3.2 supports */
/*      14-DEC-1987     Add startup message to let one know it's going */
/*       8-FEB-1988     Changed editor command to use callable editors */
/*       9-FEB-1988     Added '$' to list of good node/name characters */
/*      29-JUN-1988     Cleaned up code some, added reply for files... */
/*                                                                     */
/***********************************************************************/
/*                                                                     */
/* Modifications made for TERMLOCK.C by Dave Caplinger and Tim Russell */
/*                                                                     */
/*	18-JUL-1988	Changed reply message to indicate program      */
/*			Modified reply_to_file to only reply to        */
/*				users on the same node.                */
/*			Disabled ^Y and ^C completely - bell rings     */
/*			Removed editor support - added MORE-like view. */
/*			Added password support to lock terminal.       */
/*			Added log of # of failed unlock attempts       */
/*			Disabled control-t so people can't fill file   */
/*	20-JUL-1988	Cleaned up 'V' option to add percent and 'Q'.  */
/*			Added control-w to redraw screen (usefull for  */
/*				multi-session terminals).              */
/*	24-JUL-1988	Added special handling for (local) PHONE msgs. */
/*			Ignored messages from user running TERMLOCK.   */
/*	 7-AUG-1988	Finished version 1.0 of TERMLOCK.C, including  */
/*				automatic prepending reply message     */
/*				with "* " if not there (to follow the  */
/*				convention of messages beginning with  */
/*				"*" coming from programs, servers, and */
/*				the like.  Special handling of REPLY   */
/*				messages from an OPERATOR; REPLY msgs  */
/*				are now echoed to the screen as well   */
/*				in case of system down-time notices,   */
/*				etc.  (Still logged.)		       */
/*	11-AUG-1988	Fixed bug with user-defined reply message not  */
/*				being allowed to be > ~60 chars, fixed */
/*				idiotic bug of using '\013' for <CR>   */
/*				instead of '\0x0D' or whatever. :-)    */
/*	15-AUG-1988	Reincarnated the EDIT command, "back by        */
/*				popular demand".  Minor bug fixes.     */
/***********************************************************************/
/*								       */
/*  To compile:							       */
/*								       */
/*	$ cc termlock						       */
/*	$ link/notrace termlock,sys$input:/opt			       */
/*	sys$share:vaxcrtl/share					       */
/*	<CTRL-Z>						       */
/*								       */
/***********************************************************************/

#include <stdio>
#include <descrip>
#include <ctype>
#include <iodef>
#include <ttdef>
#include <tt2def>
#include <ssdef>

#define esc 27
#define odd( stat )	( (stat) & 1 )
 
#define LNM$_STRING 2
#define LNM$M_CASE_BLIND 33554432
 
/***********************************************************************/
/* First define all the needed global data structures for the programs */
/***********************************************************************/
 
FILE    *fp;                            /* output file id for messages. */
 
int     status;                         /* return status from functions */
int     user_cnt, sys_cnt, old_cnt;	/* number of messages that came */
int     tt_chan,mbx_chan,msg_chan,pid;  /* kb and mbx luns, process ids */
int     old_term_char,old_extended;     /* old terminal characteristics */
int	bad_tries = 0;			/* number of unsuccessfull 'U's */
int	ignore,send,file,phone,mail,job,local,reply; /* type flags for msgs. */

unsigned old_ctrl, no_ctrlt = 1048576;	/* control enable masks         */

char    password[11];			/* lock password                */
char	who[9],where[9],what[20];	/* who@where sent what.         */

char    *decnet_node,
	*bitnet_node;
char	myself[L_cuserid];		/* The user running this prgm   */

char    *tranlog( char *s, int flag);   /* tranlate logicals subroutine */

char	send_msg[110];
char    reply_string[110] =
	"* Away from terminal -- Message logged, Will reply ASAP.";
char	phone_string[110] =
	"* Away from terminal -- cannot answer phone.  Please send a message.";
 
struct  {                               /* the date and time of message */
        char    weekday[10];            /* --> the day of the week here */
        char    filler[1];              /* --> always contains a space! */
        char    date[12];               /* --> the date in ascii please */
        char    time[08];               /* --> the time in ascii please */
        } header;
 
struct {unsigned class          :8;     /* --> terminal class goes here */
        unsigned type           :8;     /* --> the terminal type please */
        unsigned page_width     :16;    /* --> terminal width goes here */
        unsigned term_char      :24;    /* --> terminal characteristics */
        unsigned page_length    :8;     /* --> page length goes in here */
        unsigned extended       :32;    /* --> extended characteristics */
        } charbuf;                      /* terminal characteristics buf */
 
struct  {
        char    buffer[20];             /* the mailbox message info blk */
        char    length;                 /* the current message's length */
        char    filler;                 /* for some reason this is null */
        char    message[100];           /* the messages sent to mailbox */
        } mbx;
 
struct dsc {    long int len;           /* descriptors needed sometimes */
                char     *addr;         /* using only a len and address */
           };                           /* instead of the whole descrip */
 
union  pointer  {                       /* defines pointer type used in */
                int  *intbuf;           /* in item lists of certain sys */
                char *charbuf;          /* routines and stuff like that */
                };
 
struct itmlst   {
                unsigned short int bufferlength;
                unsigned short int item_code;
                union pointer  addr;
                int  *retlength;
                };                      /* used in some system services */
struct itmlst trnlist[2];               /* Used in translating logicals */
 
$DESCRIPTOR(term, "SYS$OUTPUT");        /* device for in assign service */
$DESCRIPTOR(mbx_name, "REPLY_MBX");     /* mailbox to send messages out */
 
char    *local_node = "SYS$NODE";       /* local node name (for DECNET) */
char    *rscs_node  = "SYS$RSCS_NODE";  /* network node name (for JNET) */
char    *jan_node   = "JAN_LOCAL_NODE"; /* new network name (JNET V3.2) */
 
struct  dsc$descriptor_s header_dsc =
        { 20, DSC$K_DTYPE_T, DSC$K_CLASS_S, header.date };
 
/***********************************************************************/
/* Set up an AST handler for any trapped messages that come our way... */
/***********************************************************************/
 
get_msg()
{
int	start = 0;

        get_time();                             /* gets a time and date */
	while (mbx.message[start] == '\015') mbx.message[start++] = ' ';
	while (mbx.message[start] == '\007') mbx.message[start++] = ' ';
        mbx.message[mbx.length] = 0;            /* null terminates msgs */

        if (mbx.length != 0) {                  /* only continue if msg */
           get_name(start);                     /* gets a name and node */

	   if ((!ignore) && ((send) || (file) || (phone))) {
		user_cnt++;
		reset_input();
	   } else if ((!ignore) && ((mail) || (job) || (reply))) {
		sys_cnt++;
		reset_input();
	   }
        }
        status=sys$qio(3,msg_chan,IO$_READVBLK  /* - do read on mailbox */
                ,0,get_msg,0,&mbx,120,0,0,0,0); /* - with an AST finish */
}
 
/***********************************************************************/
/* The main control loop... Set up message, initialize stuff, and wait */
/***********************************************************************/
 
main(argc, argv)
int     argc;
char    **argv;
{
	char cmd[2];
 
	cuserid(myself);

	printf("TERMLOCK activated; Please wait.\n");

/* First, get the reply message to send and set up the command line... */
 
        if (argc > 2) 
        { printf("FORMAT: TERMLOCK\n    or  TERMLOCK \"REPLY STRING\"\n" ); exit(); }
 
        if ((argc == 2) && (strlen(argv[1]) < 101))
	    strcpy(reply_string, argv[1]);
	else if (argc == 2) {
	    strncpy(reply_string, argv[1], 100);
	    reply_string[strlen(reply_string)] = '\0';
	}

        initialize();                           /* open file, do screen */
        password[0] = 0;
        while (status) {                  /* while no errors here */
                status = sys$qiow(2,tt_chan,97,0,0,0,&cmd,1,0,0,0,0);
                switch (toupper(cmd[0])) {      /* input a character... */
                        case 'Q': leave_reply();/* quits if it is a 'Q' */
				  break;
			case 'E': call_editor();/* call editor on log   */
				  break;
                        case 'V': view_messages();/* view  messages-'V' */
				  break;
                        case 'L': lock_term();  /* lock the term on 'L' */
				  break;
                        case 'U': unlock_term();/* unlock term on a 'U' */
				  break;
			case 23 : draw_screen();/* redraw on control-w! */
                 }                              /* otherwise ignores it */
        }
        lib$signal(status);                     /* report the error msg */
}
 
/***********************************************************************/
/* Close files, clear screen, tie up loose ends,  then exit this mess! */
/***********************************************************************/
 
leave_reply()
{
        if (unlock_term() != 0) return;         /* no leaving if locked */
        uninitialize();                         /* kill everything here */
	reset_terminal();			/* reset and close file */
        sys$dassgn(tt_chan);                    /* deassign the channel */
	printf("%c[24;1H",esc);			/* put cursor at bottom */
        exit();
}
 
/***********************************************************************/
/* Close up our log file and remove all the mailbox stuff please.      */
/***********************************************************************/
 
uninitialize()
{
        sys$delprc(&pid,0);                     /* kills the subprocess */
        sys$delmbx(mbx_chan);                   /* kill its mailbox too */
        sys$delmbx(msg_chan);                   /* zap terminal mailbox */
        sys$cantim(0,3);                        /* cancels update timer */
}
 
/***********************************************************************/
/* Reset the terminal characteristics, kill ast traps, kill timer, etc */
/***********************************************************************/
 
reset_terminal()
{
        sys$cancel(tt_chan);                    /* cancels terminal I/O */
        charbuf.term_char = old_term_char;      /* restore the old term */
        charbuf.extended = old_extended;        /* characteristics back */
        sys$qiow(0,tt_chan,IO$_SETMODE,0,0,0,   /* so they can get msgs */
                 &charbuf,12,0,0,0,0);          /* again to their term! */
	fclose(fp);
	lib$enable_ctrl(&old_ctrl);		/* put back ctrl keys   */
        sys$setast(0);                          /* disable the ast call */
}
 
/***********************************************************************/
/* Sets up the display, open log file, sets up the mailbox stuff, etc. */
/***********************************************************************/
 
initialize()
{
int      len;
unsigned no_ctrlt; 

        open_file();                            /* open the file again */
 
/* Find out our local and rscs node names from translating logicals now */
 
        decnet_node = tranlog(local_node,0);    /* translate a logical */

        len  = strlen(decnet_node)-2;           /* skip the "::" of it */
        if (len <= 0) {                         /* make sure it exists */
                printf("?Logical name SYS$NODE must be defined to use REPLY");
                exit();                         /* if not then exit... */
        }
        bitnet_node = tranlog(rscs_node,0);     /* try translating this */
        if (*bitnet_node == 0)			/* if none then try new */
           bitnet_node = tranlog(jan_node,0);   /* jnet version logical */
        if (*bitnet_node == 0) 
	   strcpy(bitnet_node,decnet_node);     /* uses other if none.  */
 
/* Create mailbox thru which we send replys, create subprocess to do it */
 
        status = sys$crembx(0,&mbx_chan,0,0,240,0,&mbx_name);
        if (status != 1) lib$signal(status);
 
        status = lib$spawn(0,&mbx_name,0,&1,0,&pid);
        if (status != 1) lib$signal(status);
 
        status = lib$asn_wth_mbx(&term,&0,&0,&tt_chan,&msg_chan);
        if (status != 1) lib$signal(status);

/* Disable ^T,  save old mask so we can put it back.                    */

	lib$disable_ctrl(&no_ctrlt,&old_ctrl);

/* Set up the terminal so that everything works and draw a neat display */
 
        setup_term();
}
 
/***********************************************************************/
/* Open the message log file in append mode, if an error, then exit... */
/***********************************************************************/
 
open_file()
{
char    junk[128];
 
	user_cnt = sys_cnt = old_cnt = 0;	/* start with no msgs. */
        fp=fopen("sys$login:termlock.log","r"); /* try opening my file */
 
        if (fp != NULL) {                       /* if it exists,  then */
           old_cnt--;                           /* (otherwise one off) */
           do { fgets(junk,128,fp);             /* gets line from file */
                old_cnt++;                      /* increments counters */
                }                               /* repeat loop til eof */
           while (feof(fp) != 1);               /* count := msg's * 2  */
        old_cnt = old_cnt / 2;                  /* gets the real count */
        fclose(fp);                             /* close file up again */
        }
 
        fp=fopen("sys$login:termlock.log","a+");/* open the file again */

        if  (fp == NULL) {                      /* check for errors... */
                printf("?Error opening file SYS$LOGIN:TERMLOCK.LOG");
                exit();                         /* exit if an error... */
        }
}
 

/* Called on ^Y AST - ring the bell to make some noise. */
do_nothing()
{
	printf("\007");
	return;
}

/***********************************************************************/
/* Set up the terminal display,  and save/set terminal characteristics */
/***********************************************************************/
 
setup_term()
{
int     mask[1];
 
        status = sys$qiow(0,tt_chan,IO$_SENSEMODE,0,0,0,&charbuf,12,0,0,0,0);
        if (status != 1) lib$signal(status);
 
        old_term_char = charbuf.term_char;      /* saves chars for exit */
        old_extended = charbuf.extended;        /* saves extendeds too! */
 
        charbuf.term_char = charbuf.term_char   /* SET TERM/NOBROADCAST */
                |TT$M_MBXDSABL|TT$M_NOBRDCST;   /* (also sets MBXDSABL) */
        charbuf.extended = charbuf.extended     /* SET TERM/BRDCSTMBX   */
                |TT2$M_BRDCSTMBX;               /* so we receive in mbx */
 
        status = sys$qiow(0,tt_chan,IO$_SETMODE,0,0,0,&charbuf,12,0,0,0,0);
        if (status != 1) lib$signal(status);
 
/* Sets up an out of band ast trap for any control C or control Y chars */

        mask[0] = 0; mask[1] = 33554440;        /* mask for ^C/^Y chars */
        status = sys$qiow(4,tt_chan,            /* sets up the ast trap */
                IO$_SETMODE|IO$M_OUTBAND,       /* for ^C/^Y characters */
                0,0,0,do_nothing,mask,0,0,0,0); /* so no naughty exits! */
        if (status != 1) lib$signal(status);    /* an error setting it? */

/* Disable ^T so that malicious passersby can't fill our file.          */

	lib$disable_ctrl(&no_ctrlt);

/* Fix a gap in the time/date/day header so that we have a neat display */
 
        strcpy(header.filler," ");              /* make display neat... */
	draw_screen();

/* Queue an ast routine to read from the terminal's message mailbox... */
 
        sys$setast(1);                          /* enable ast delivery */

/* This loads status, which is tested in the WHILE statement of main() */

        status=sys$qio(3,msg_chan,IO$_READVBLK,0,get_msg,0,&mbx,120,0,0,0,0);
}
 

/***********************************************************************/
/*  Actually draw the screen display                                   */
/***********************************************************************/

draw_screen()
{
printf("%c[2J%c[H",esc,esc);
printf("                Vax Automatic Message Reply Facility  v1.02\n");
printf("      --------------------------------------------------------------");
printf("\n");
printf("       L to LOCK the terminal\n");
printf("       U to UNLOCK the terminal\n");
printf("       E to EDIT message file\n");
printf("       V to VIEW message file\n");
printf("       Q to QUIT this program\n\n\n");
printf("      --------------------------------------------------------------");
printf("\n");
reset_input();
}
 

/***********************************************************************/
/* get the time and date so we can log it to a file or screen display. */
/***********************************************************************/
 
get_time()
{
int      i;                                     /* counter variables... */
unsigned int j[4];                              /* holds internal times */
 
static     char day_list[] =
"Monday,   Tuesday,  Wednesday,Thursday, Friday,   Saturday, Sunday,   ";
 
        lib$date_time(&header_dsc);             /* get the current time */
 
        sys$gettim(&j[0]);                      /* and an internal time */
        lib$day_of_week(&j[0], &i);             /* gets day of the week */
        i = (i - 1) * 10;                       /* calculate offset now */
 
        strncpy(header.weekday,&day_list[i],10);/* put in output buffer */
}
 
/***********************************************************************/
/* reset the cursor to command line, used after message or bad command */
/***********************************************************************/
 
reset_input()
{
           printf("%c[3;42H%d User messages received",esc,user_cnt);
           printf("%c[4;42H%d System messages received",esc,sys_cnt);
           printf("%c[5;42H%d Old messages in file",esc,old_cnt);
           printf("%c[6;42H%d Failed unlocks",esc,bad_tries);
	   if (!password[0]) printf("%c[9;42HUNLOCKED!",esc);
	   else printf("%c[9;42HLOCKED!  ",esc);
           printf("%c[9;57HSelection:",esc);
           update_time();
}
 
/***********************************************************************/
/* Display the time and the date on screen every few seconds please... */
/***********************************************************************/
 
update_time()
{
int     time[4];
$DESCRIPTOR(delta, "0 ::30");
 
        get_time(); header.time[5] = 0;         /* get time, terminate */
        printf("%c[9;8H%s%c[4;46H", esc,header.weekday,esc);
 
        sys$cantim(0,3);                        /* kill time interupts */
        sys$bintim(&delta, &time);              /* gets new time delay */
        sys$setimr(0,&time,update_time,0);      /* sets interupt timer */
 
        printf("%c[9;67H",esc);
}
 
/***********************************************************************/
/* View the file, simulating type/page in the scroll region.           */
/***********************************************************************/
 
view_messages()
{
        char nothing[2], line[128], c[2];
	int i;
	double x;
        FILE *fd;
 
        if (unlock_term() != 0) return;

        reset_terminal();                       /* reset terminal now */

	printf("%c[21;1H%c[0J",esc,esc);    /* clear btm. */
        printf("%c[11;r%c[11;1H",esc,esc);  /* set scroll */
        fd = fopen("sys$login:termlock.log", "r");

	i = 0;
        while (fgets(line, 127, fd) != NULL) {
		if (++i % 12 == 0) {
			x = (i/((user_cnt+sys_cnt+old_cnt)*2.0))*100;
			printf(" (%d%%) <Press a key>", (int) (x + 0.5));
	                sys$qiow(2,tt_chan,97,0,0,0,&c,1,0,0,0,0);
			printf("\n");
			if (toupper(c[0]) == 'Q') { i = -1; break; }
		}
		if (strlen(line) > 80) i++;    /* count long lines twice */
		if (line[0]==7) line[0] = 32;
                printf("%s",line);
        }
 
        if (status != 1) lib$signal(status); /* exit if any errors */
        fclose(fd);

	switch (i) {
		case -1 : printf(" Aborted -");
			  break;
		case  0 : printf(" No messages received -");
			  break;
		default : printf(" End of messages -");
	}
        printf(" <Press a key>");
        sys$qiow(2,tt_chan,97,0,0,0,&c,1,0,0,0,0);
        printf("%c[;r",esc);
 
        open_file();                            /* open the file again */
        setup_term();                           /* sets terminal again */
}

/***********************************************************************/
/* Call editor (EDIT$INIT) on the message log, conditional on lock     */
/***********************************************************************/

call_editor()
{
char	*junk;
char	*editor = "TERMLOCK$EDIT";
$DESCRIPTOR(tpu_dsc,"TPU SYS$LOGIN:TERMLOCK.LOG");
$DESCRIPTOR(edt_dsc,"SYS$LOGIN:TERMLOCK.LOG");

        if (unlock_term() != 0) return;

	reset_terminal();

	junk = tranlog(editor,1);
	if (!strcmp(junk,"TPU")) status = tpu$tpu(&tpu_dsc);
	 else status = edt$edit(&edt_dsc);
	if (!odd(status)) lib$signal(status);

	open_file();
	setup_term();
}

 
/***********************************************************************/
/* get the users name and node if needed & send reply message to him.  */
/***********************************************************************/
 
get_name(start)
int start;
{
int	i, j = 0;

	ignore = send = file = phone = mail = job = local = reply = 0;
	for(i = 0; i < 9; i++) who[i] = where[i] = what[i] = ' ';
	for(i = 9; i <20; i++) what[i] = ' ';
	who[0] = where[0] = what[0] = '\0';

	if (mbx.message[i = start] == '(') {
		for(j = i; mbx.message[j] != ')'; j++);
		if (mbx.message[j] == ')') {
			strncpy(where,&mbx.message[i+1],j-i-1);
			where[j-i-1] = '\0';
			start += strlen(where) + 2;
			if (!strncmp(bitnet_node,where,strlen(where))) local=1;
		}
	} else local = 1;

	sscanf(&mbx.message[start], "%s - ", who);
	start += strlen(who) + 3;
	if (mbx.message[start] == '*') ignore = 1;
	if (!strncmp(who, myself, strlen(myself))) ignore = 1;
	if (!strcmp(who, "-")) ignore = 1;
	if (!strcmp(who, "New")) mail = 1;
	if (!strcmp(who, "Job")) job = 1;
	if (!strcmp(who, "Reply")) reply = 1;
	if (!strcmp(who, "*URGENT*")) { reply = 1; ignore = 0; }

/* note: our help reply/shutdown says "*SHUTDOWN* - etc", but actually
    doing it shows that it's just "SHUTDOWN - etc".  So I put in both. */

	if (!strcmp(who, "SHUTDOWN")) reply = 1;
	if (!strcmp(who, "*SHUTDOWN*")) reply = 1;
	if (strchr(who,':') != NULL) phone = 1;
	if (strchr(who,'(') != NULL) phone = 0;
	if (!strncmp(who, decnet_node, strlen(decnet_node))) local = 1;
	if (phone) got_phone_message();
	else if (reply) got_reply_message();
	     else if ((!mail) && (!job)) got_send_message();
}

got_send_message()
{
int	i = 0;
char	temp[20];

	while (mbx.message[i] != '-') i++;
	if ((i < strlen(mbx.message)) && (mbx.message[i] == '-') &&
	    (sscanf(mbx.message + i, "- Received network file %s from %s",
	    what,temp) == 2)) {
		if (!strncmp(temp,myself,strlen(myself))) ignore = 1;
		 else ignore = 0;
		sprintf(send_msg, "send %s \"* File %s received.",temp, what);
		reply_to_user();
		file = 1;
		return;
	}
	strcpy(send_msg, "send ");
	for (i = 0; who[i] != '('; i++);
	if ((i < strlen(who)) && (who[i] == '(')) who[i] = '\0';
	strcat(send_msg, who);
	if (local == 0) {
		strcat(send_msg, "@");
		strcat(send_msg, where);
	}
	strcat(send_msg, " \"");
	if (reply_string[0] != '*') strcat(send_msg, "* ");
	strcat(send_msg, reply_string);
	reply_to_user();
	send = 1;
}

got_phone_message()
{
int	i = 0;

	strcpy(send_msg,"send ");
	strcat(send_msg,who);
	strcat(send_msg," \"");
	strcat(send_msg, phone_string);
	reply_to_user();
}

got_reply_message()
{
	printf("%c[21;1H%c[0J%s",esc,esc,mbx.message);
}

reply_to_user()
{
    if (!ignore) {
        fprintf(fp,"%s\n", header.weekday);  /* print time log notes */
        fprintf(fp,"%s\n", mbx.message);     /* puts message to file */
	status = sys$qiow(0,mbx_chan,IO$_WRITEVBLK,0,0,0,
		&send_msg,strlen(send_msg),0,0,0,0);
	if (status != 1) lib$signal(status);
    }
}

/***********************************************************************/
/* Translate a logical name to the real physical name, if there is one */
/***********************************************************************/
 
char *tranlog(s,flag)
char *s;
int  flag;
{
$DESCRIPTOR(tab0desc,"LNM$SYSTEM_TABLE");
$DESCRIPTOR(tab1desc,"LNM$PROCESS_TABLE");
struct dsc name;
char *cp;
int loglen,status;
int attr_arg;
 
        cp = malloc( 256 );                     /* go get us some memory */
        name.addr = s;                          /* address for string... */
        name.len  = strlen(s);                  /* length of the strings */
        attr_arg = LNM$M_CASE_BLIND;            /* don't care about case */
        trnlist[0].bufferlength = 100;          /* set up an itemlist... */
        trnlist[0].item_code    = LNM$_STRING;  /* say it is a string... */
        trnlist[0].addr.charbuf = cp;           /* buffer for the result */
        trnlist[0].retlength    = &loglen;      /* the length for result */
        trnlist[1].bufferlength = 0;
        trnlist[1].item_code    = 0;
        if (flag) 
           status = sys$trnlnm(&attr_arg,&tab1desc,&name,0,&trnlist);
        else
           status = sys$trnlnm(&attr_arg,&tab0desc,&name,0,&trnlist);
        if ( status == SS$_NOLOGNAM || ( status & 1 ) == 0) loglen = 0;
        *(cp + (loglen&255)) = 0;               /* null terminate result */
        return(cp);                             /* and return the result */
}

lock_term()
{
        int status, i;
        char c[2], TEMP[10];

        if (password[0] != 0) return;
 
	for(i=0; i<11; TEMP[i] = password[i++] = 0);
 
        printf("%c[9;42H",esc);
	printf("Password? ");
        status = 1;
        i = 0;
        while ((status==1) && (i < 11) && (c[0] != 13)) {
                status = sys$qiow(2,tt_chan,97,0,0,0,&c,1,0,0,0,0);
                password[i++] = toupper(c[0]);
        }

	printf("%c[9;42H",esc);
	printf("Confirm?  ");
	status = 1;
	i = c[0] = 0;
	while ((status==1) && (i < 11) && (c[0] != 13)) {
                status = sys$qiow(2,tt_chan,97,0,0,0,&c,1,0,0,0,0);
                TEMP[i++] = toupper(c[0]);
	}

	if (strcmp(TEMP,password) != 0) {
		printf("%c[9;42H",esc);
		printf("Unlocked!\007");
		printf("%c[9;67H",esc);
		password[0] = 0;
		return;
	}

        printf("%c[9;42H",esc);
	printf("LOCKED!  ");
        printf("%c[9;67H",esc);
        return;
}
 
unlock_term()
{
        int status, i;
        char c[2], TEMP[10];
 
        for(i = 0; i < 11; TEMP[i++] = 0);
 
        if (password[0] == 0) return (0);
 
        printf("%c[9;42H",esc);
	printf("Unlock?  ");
        status = 1;
        i = 0;
        while ((status==1) && (i < 11) && (c[0] != 13)) {
                status = sys$qiow(2,tt_chan,97,0,0,0,&c,1,0,0,0,0);
                TEMP[i++] = (char) toupper(c[0]);
        }
 
        printf("%c[9;42H         ",esc);
 
        if (strcmp(TEMP,password) != 0) {
                printf("%c[9;42H",esc);
		printf("LOCKED!  \007");
                printf("%c[9;67H",esc);
		printf("%c[6;42H",esc);
		printf("%d Failed unlocks",++bad_tries);
	        printf("%c[9;67H",esc);
                return (-1);
        }
 
	printf("%c[6;42H%d Failed unlocks",esc, (bad_tries = 0));
	printf("%c[9;42H",esc);
	printf("UNLOCKED!  ");
        printf("%c[9;67H",esc);
        password[0] = 0;
        return (0);
}

