ERIC@UOFT02.BITNET (07/07/88)
/***********************************************************************/ /* This program will log any messages sent to you while you are out, */ /* and then send a reply message to the user. The reply can be passed */ /* to the program, or a default reply can be used. See REPLY.DOC for */ /* more information on how to use or install this program. */ /* */ /* Program by Eric Rostetter, University of Toledo, Toledo, Ohio 43606 */ /* */ /* This program will correctly handle the following types of messages: */ /* */ /* SEND messages from the current node (log and reply) */ /* SEND messages from another node (log and reply) */ /* MAIL messages (log, no reply) */ /* BATCH messages (log, no reply) */ /* ^T messages (log, no reply) */ /* */ /***********************************************************************/ /***********************************************************************/ /* Modification History: */ /* 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 infinate 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... */ /***********************************************************************/ /***********************************************************************/ /* Before we start anything, lets have a word from our sponsors... */ /***********************************************************************/ #include <stdio> #include <descrip> #include <ctype> #include <iodef> #include <ttdef> #include <tt2def> #include <ssdef> #define then #define false 0 #define true 1 #define esc 27 #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 count1,count2,count0; /* 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 term_type; /* terminal type,hardcopy/scope */ char send_msg[128]; /* the message we send to them! */ char name[16]; /* name of the sender, if any. */ char cmd[2]; /* command typed in at terminal */ char *node,*rscs; /* local and network node names */ char *tranlog( char *s, int flag); /* tranlate logicals subroutine */ char reply_string[] = "Out of office - message logged; Will reply ASAP. "; char file_string[] = "send foobart::foobarer \"Received file xxxxxxxx.xxxxxxxx - Thank you!"; 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 { /* hold info about last message */ char name[16]; /* holds the last name and node */ int count; /* number of message sent to it */ } last; /* this will stop infinate loop */ 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() { get_time(); /* gets a time and date */ mbx.message[mbx.length] = 0; /* null terminates msgs */ if (mbx.length != 0) then { /* only continue if msg */ fprintf(fp,"%s\n", header.weekday); /* print time log notes */ fprintf(fp,"%s\n", mbx.message); /* puts message to file */ get_name(); /* gets a name and node */ if ((!strncmp(name,"Job ",4)) || /* if its batch message */ (!strncmp(name,"New ",4)) || /* or a mail message... */ (!strncmp(name,"CSNEWS",6)) || /* ignores csnews@maine */ (!strncmp(name," ",6)) || /* network msg, no name */ (!strcmp(name,rscs)) || /* or a transfer msg... */ (!strncmp(name,node,strlen(node)))) /* or ^T messages... */ then { ++count2; /* say we got a sys msg */ reply_to_file(); /* do received messages */ } else { ++count1; /* must be user message */ reply_to_msg(); /* send a reply message */ } } 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; { /* First, get the reply message to send and set up the command line... */ if (argc > 2) then { printf("FORMAT: REPLY\n or REPLY \"REPLY STRING\"\n" ); exit(); } if (argc == 2) then strcpy(reply_string, *++argv); strcpy(send_msg, "send foobart@foobarer \""); strcpy(send_msg+24, reply_string); /* the messages to send */ initialize(); /* open file, do screen */ while (status==true) { /* 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' */ case 'E': call_editor();/* calls editors on 'E' */ } /* otherwise ignores it */ } lib$signal(status); /* report the error msg */ } /***********************************************************************/ /* Close files, clear screen, tie up loose ends, then exit this mess! */ /***********************************************************************/ leave_reply() { uninitialize(); /* kill everything here */ exit(); /* bye and good ridence */ } /***********************************************************************/ /* Close up our log file and exit all the screen manager 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_terminal(); /* resets user terminal */ sys$dassgn(tt_chan); /* deassign the channel */ } /***********************************************************************/ /* 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); /* closes the log files */ if (term_type) then /* if we're using a CRT */ printf("%c[2J%c[H",esc,esc); /* then clear screen... */ sys$setast(0); /* disable the ast call */ } /***********************************************************************/ /* Sets up the display, open log file, sets up the mailbox stuff, etc. */ /***********************************************************************/ initialize() { int len; printf("Vax Automatic Message Reply Facility started - Please wait.\n"); open_file(); /* open the file again */ /* Find out our local and rscs node names from translating logicals now */ node = tranlog(local_node,0); /* translate a logical */ len = strlen(node)-2; /* skip the '::' of it */ if (len <= 0) then { /* make sure it exists */ printf("?Logical name SYS$NODE must be defined to use REPLY"); exit(); /* if not then exit... */ } *(node+len) = 0; /* skip over '::' in it */ rscs = tranlog(rscs_node,0); /* try translating this */ if (*rscs == 0) then /* if none then try new */ rscs = tranlog(jan_node,0); /* jnet version logical */ if (*rscs == 0) then strcpy(rscs,node); /* none? uses other one */ /* 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 != true) then lib$signal(status); status = lib$spawn(0,&mbx_name,0,&1,0,&pid); if (status != true) then lib$signal(status); status = lib$asn_wth_mbx(&term,&0,&0,&tt_chan,&msg_chan); if (status != true) then lib$signal(status); /* 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]; count0 = 0; count1 = 0; count2 = 0; /* assumes no messages */ fp=fopen("sys$login:messages.log","r"); /* try opening my file */ if (fp != NULL) then { /* if it exists, then */ count0--; /* (otherwise one off) */ do { fgets(junk,128,fp); /* gets line from file */ count0++; /* increments counters */ } /* repeat loop til eof */ while (feof(fp) != 1); /* count0 := msg's * 2 */ count0 = count0 / 2; /* gets the real count */ fclose(fp); /* close file up again */ } fp=fopen("sys$login:messages.log","a+");/* open the file again */ if (fp == NULL) then { /* check for errors... */ printf("?Error opening file SYS$LOGIN:MESSAGES.LOG"); exit(); /* exit if an error... */ } } /***********************************************************************/ /* Set up the terminal display, and save/set terminal characteristics */ /***********************************************************************/ setup_term() { int mask[1]; term_type = (!strncmp(getenv("TERM"),"vt1",3) || !strncmp(getenv("TERM"),"vt2",3)); status = sys$qiow(0,tt_chan,IO$_SENSEMODE,0,0,0,&charbuf,12,0,0,0,0); if (status != true) then 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 != true) then 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,leave_reply,mask,0,0,0,0);/* so as to exit nicely */ if (status != true) lib$signal(status); /* an error setting it? */ /* Fix a gap in the time/date/day header so that we have a neat display */ strcpy(header.filler," "); /* make display neat... */ /* Set up screen display -- works on hardcopy or on ANSI CRT terminals */ if (term_type) then printf("%c[2J%c[H",esc,esc); printf(" Vax Automatic Message Reply Facility\n\n"); printf(" E to EDIT message file Q to QUIT this program"); printf("\n"); printf(" Enter Selection: "); printf("\n"); printf(" --------------------------------------------------------------"); printf("\n"); reset_input(); /* Queue an ast routine to read from the terminal's message mailbox... */ sys$setast(1); /* enable ast delivery */ status=sys$qio(3,msg_chan,IO$_READVBLK,0,get_msg,0,&mbx,120,0,0,0,0); /* This loads status, which is tested in the WHILE statement of main() */ } /***********************************************************************/ /* 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() { if (term_type) then { printf("%c[7;7H%d User messages received",esc,count1); printf("\t\t %d System messages received",count2); printf("%c[8;26H%d Old messages in file",esc,count0); 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[10;23H%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 */ } /***********************************************************************/ /* Send the reply message to the subprocess to send it to the senders. */ /***********************************************************************/ reply_to_msg() { int i; if (!strcmp(name,last.name)) then { strcpy(name, last.name); last.count = 0; } last.count++; if (last.count < 5) then { for (i=0;i<16;i++) send_msg[i+5] = name[i]; status=sys$qiow(0,mbx_chan,IO$_WRITEVBLK,0,0,0, &send_msg,strlen(send_msg),0,0,0,0); if (status != true) then lib$signal(status); } else fprintf(fp,"?No reply sent...\n"); reset_input(); } /***********************************************************************/ /* Send file received message to subprocess to send it back to sender. */ /***********************************************************************/ reply_to_file() { int i; for (i=0;mbx.message[i] != '-'; i++); status = sscanf(&mbx.message[i], "- Received network file %s from %s", file_string+38, file_string+5 ); for (i= 5+strlen(file_string+5); i<22; i++) file_string[i] = ' '; for (i=38+strlen(file_string+38); i<55; i++) file_string[i] = ' '; if (status == 2) then { status=sys$qiow(0,mbx_chan,IO$_WRITEVBLK,0,0,0, &file_string,strlen(file_string),0,0,0,0); if (status != true) then lib$signal(status); } reset_input(); } /***********************************************************************/ /* Call a callable editor to edit the message file --- uses EDIT$INIT */ /***********************************************************************/ call_editor() { char *junk; char *editor = "REPLY$EDIT"; $DESCRIPTOR(tpu_dsc,"TPU SYS$LOGIN:MESSAGES.LOG"); $DESCRIPTOR(edt_dsc,"SYS$LOGIN:MESSAGES.LOG"); reset_terminal(); /* reset terminal now */ junk = tranlog(editor,1); /* try translating it */ if (!strcmp(junk,"TPU")) then /* if it equals "tpu" */ status = tpu$tpu(&tpu_dsc); /* then call "tpu" */ else /* otherwise, we just */ status = edt$edit(&edt_dsc); /* call this "edt" */ if (status != true) lib$signal(status); /* exit if any errors */ open_file(); /* open the file again */ setup_term(); /* sets terminal again */ } /***********************************************************************/ /* get the users name and node if needed for the reply message to him. */ /***********************************************************************/ get_name() { int i,j; char node[16]; for (i=0;i<16;i++) { /* before we start, we */ node[i]=32; /* move spaces to node */ name[i]=32; /* move spaces to name */ } i=0;j=0; /* init our pointers... */ if (mbx.message[i]==7) then i=1; /* skip bell if present */ if (mbx.message[i]==40) then { /* if a node name, then */ node[j++] = 64; /* -- put in at sign... */ for (i++;mbx.message[i]!=41;i++) /* -- get the node name */ node[j++] = mbx.message[i]; node[j++]=32; i++; /* -- and add the space */ } j=0; for (;isvalid(mbx.message[i]);i++) name[j++] = mbx.message[i]; /* copy the name please */ if (j != 0) then /* iff a name was found */ for (i=0;j<16;i++) name[j++]=node[i]; /* - copy the node name */ } /***********************************************************************/ /* Sees if a character is valid for use in a user name or a node name. */ /***********************************************************************/ isvalid(ch) char ch; { return( isalnum(ch) || ch == '$' || ch == '_' ); } /***********************************************************************/ /* 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) then 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) then loglen = 0; *(cp + (loglen&255)) = 0; /* null terminate result */ return(cp); /* and return the result */ }