1 /* ***********************************************************
  2    *                                                         *
  3    * Copyright, (C) Honeywell Bull Inc., 1988                *
  4    *                                                         *
  5    * Copyright, (C) Honeywell Information Systems Inc., 1987 *
  6    *                                                         *
  7    *********************************************************** */
  8 
  9 
 10 /* HISTORY COMMENTS:
 11   1) change(87-03-08,Wallman), approve(87-03-08,MCR7586),
 12      audit(87-07-16,Flegel), install(87-08-07,MR12.1-1072):
 13      First release.
 14   2) change(88-02-24,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
 15      install(88-10-12,MR12.2-1160):
 16      Removed debugging code and unused variables, formatting.
 17   3) change(88-04-11,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
 18      install(88-10-12,MR12.2-1160):
 19      Added calls to handled BREAK key; mapped DEL key to ASCII DEL,
 20      mapped ^@ (or ^2) to ASCII NUL.
 21   4) change(88-04-26,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
 22      install(88-10-12,MR12.2-1160):
 23      Created routine check_wst_status() to update the status when
 24      WSTERM changes its mode (glass tty, sync or async).
 25   5) change(88-04-27,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
 26      install(88-10-12,MR12.2-1160):
 27      Added calls to scroll_1_to_24() to prevent the status line from
 28      being overwritten when using FANSI-CONSOLE.
 29   6) change(88-05-12,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
 30      install(88-10-12,MR12.2-1160):
 31      Added command line handling for /B option.
 32   7) change(88-05-31,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
 33      install(88-10-12,MR12.2-1160):
 34      Added command line handling for /A, /P; support for file and
 35      printer auditing.
 36   8) change(88-07-20,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
 37      install(88-10-12,MR12.2-1160):
 38      Default after atm changed edit mode.
 39   9) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
 40      install(88-10-12,MR12.2-1160):
 41      Documentation additions only. Added header comments to all routines.
 42  10) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
 43      install(88-10-12,MR12.2-1160):
 44      Fix references to include files; "wstdefs.h" was split into
 45      "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
 46      various constants defined to descriptive names.
 47  11) change(88-08-30,Lee), approve(88-09-12,MCR7986), audit(88-09-19,Flegel),
 48      install(88-10-12,MR12.2-1160):
 49      Removed non-edit async mode and references to non-edit async mode
 50      line editing routines.
 51  12) change(89-02-22,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
 52      install(89-04-24,MR12.3-1033):
 53      Separated input and output parameters to int86() to avoid confusion
 54      when parameters are used; enabled kb.echo flag when mowse is not active
 55      and in edit-mode.
 56                                                    END HISTORY COMMENTS */
 57 
 58 /* WSTERM -- WorkStation TERminal Manager for Multics MOWSE */
 59 
 60 
 61 #include  <stdio.h>
 62 #include  <dos.h>
 63 #include  <ws.h>
 64 #include  <ws_error.h>
 65 #include  <wsmincap.h>
 66 #include  <cat.h>
 67 #include  "wstdefs.h"
 68 #include  "wstglob.h"
 69 
 70 /****************************************************************************/
 71 
 72 /* Program entrypoint */
 73 
 74 /*^L
 75 **********************************************************************
 76 
 77   Routine:            MAIN
 78 
 79   Function:
 80       This is the command module for WSTERM. It analyzes command line
 81   arguments, setting appropriate flags and initializes the execution
 82   environment. It then enters a listener loops that continually
 83   checks and handles foreground messages, background messages, and
 84   keyboard input. It stays in the listener loop until the user enters
 85   a local escape sequence that signals that the program should
 86   terminate. While inside the listener loop, various modes and
 87   facilities may be called.
 88 
 89   Parameters:
 90      (input)          argc - indicates the number of command line
 91                           arguments; standard argc argument passed to
 92                           main()
 93      (input)          argv - pointer to the character pointer array
 94                           containing the actual command line
 95                           arguments; standard argv argument passed to
 96                           main()
 97 
 98   Returns:            NONE
 99 
100 **********************************************************************/
101 
102 main (argc,argv)
103 int argc;
104 char *argv[];
105 {
106     /* handle command line arguments */
107     if (parse_args(argc,argv) < 0)
108         exit(0);
109 
110     /* if /B option specified to send break to host */
111     if (break_sends_to_host)
112         set_break();   /* set up our ^BREAK handler */
113     else
114         enable_ctl_c_check();   /* turn ^C/BREAK checking ON */
115 
116     /* initialize screen structures for screen swapping */
117     wst_init_modes();
118 
119     init_kb_screen(SCREEN_LINES,SCREEN_COLS);
120     init_line(&edlin);
121 
122     /* initialize wsterm structures and variables */
123     if (wstinit () < 0) {
124         /* MOWSE not invoked error, clean up and exit */
125 
126         /* restore scrolling region to full screen */
127         reset_scroll();
128 
129         if (break_sends_to_host)
130             reset_break();   /* restore original ^BREAK handler */
131         else
132             restore_ctl_c_check();  /* restore original ^C/BREAK checking */
133         exit(0);
134     }
135 
136 
137     /* initialize wsterm's line mode flag to update on next check */
138     wst_status = WST_UNKNOWN_MODE;
139 
140     /* Listener loop -- control stays in this loop until the user
141        enters ALT-Q to quit the invocation. */
142 
143     while (local_action != QUIT) {
144 
145         /* check WSTERM's status and update status line if necessary */
146         check_wst_status();
147 
148         local_action = NUL;     /* Erase possible leftovers */
149 
150         /* If there is no pending foreground message, see if
151            one is waiting in MOWSE */
152 
153         if (fg_msg_len == 0) {
154             fg_msg_len = gettdata (&tdata_arg);
155 
156             /* If MOWSE doesnt have a message either, check MOWSE's status */
157             if (fg_msg_len == 0)
158                 check_MOWSE_status ();
159         }
160 
161         /* Is there a foreground message? */
162         if (fg_msg_len > 0) {
163 
164             /* If FB_BREAK has been sent and this is the return FG_BREAK */
165             if (break_sent && tdata_arg.minor_capability == FG_BREAK) {
166 
167                 break_sent = OFF;
168                 fg_msg_len = 0;     /* Discard the FG_BREAK message */
169 
170                 if (read_active) {     /* Terminate any active read */
171                     term_read = ON;
172                     send_msg (nul_str, 0);
173                 }
174             }
175             else if (~sync)      /* An async message */
176                 async_msg (~FORCE);
177             else
178                 sync_msg ();    /* A sync message */
179         }
180 
181         /* If mowse is active ... */
182         if (mowse_active) {
183 
184             /* Is there a background message that hasn't been
185                shown in line 25? */
186 
187             if (tdata_arg.background_pending_flag && ~bk_msg_showing)
188                 show_bkmsg ();
189 
190             /* If we're in sync mode with characters in the
191                keyboard buffer and there is an active read command,
192                check for echo delay timer runout */
193 
194             if (sync && read_active) {
195                 if (kb.cndx > 0 && check_echo_delay ()) {
196                     if ((kb.echo && kb.cndx > kb.endx) ||
197                         ~kb.echo)
198                         extract_msg (~NO_BLOCK,
199                              TRO, ~kb.echo, ~HIDE);
200                 }
201             }
202         }
203 
204         /* Anything from the keyboard? */
205 
206         if (!wst_edit_mode || sync) {
207             if (read_keyboard (~BLOCK))
208                 process_kbrd_char (~HIDE);
209         }
210         else
211             process_edit_line(&edlin);
212     }               /* End of listener loop */
213 
214     /* Bid adieu to MOWSE and return to DOS */
215 
216     destinst (&wst_mcb);
217 
218     /* restore scrolling region to full screen */
219     reset_scroll();
220 
221     /* move cursor to bottom of screen and display a new line */
222     /* so that the DOS prompt will appear at the bottom of the screen */
223     leave_screen();
224 
225     set_printer_timeout(wst_prt_timeout);
226 
227     /* if /B specified to send break to host */
228     if (break_sends_to_host)
229         reset_break();   /* restore original ^BREAK handler */
230 
231     else
232         restore_ctl_c_check();  /* restore original ^C/BREAK checking */
233 
234     if (wst_f_audit)
235         end_file_audit();
236 
237     if (wst_p_audit)
238         end_printer_audit();
239 
240     exit ();
241 
242 }               /* End of main */
243 
244 
245 /**** LOCAL FUNCTIONS *********************************************************/
246 
247 
248 /*^L
249 **********************************************************************
250 
251   Routine:            CHECK_ECHO_DELAY
252 
253   Function:
254       This function checks for echo delay timer runout. The echo
255   delay timer (currently set at 1 second) controls the echoing of
256   typeahead so that the user doesn't get too far ahead of the screen
257   display.
258 
259   Parameters:         NONE
260 
261   Returns:            ON if timer runout occurred
262                       OFF is no timer runout occurred
263 
264 **********************************************************************/
265 
266 check_echo_delay ()
267 {
268     int newtime;        /* Current clock */
269     union regs_struct regs, outregs;
270 
271     /* Record current DOS system time in 'newtime' */
272 
273     regs.hreg.ah = SYSTEM_TIME;
274     intdos (&regs, &outregs);
275     newtime = regs.hreg.dh & LO_BYTE_MASK; /* Use only seconds value */
276 
277     if (oldtime == -1)      /* Also set oldtime for first call */
278         oldtime = newtime;
279     if (newtime < oldtime)      /* Adjust for clock rollover */
280         oldtime -= 60;
281 
282     /* Check for timer runout */
283 
284     if (newtime - oldtime >= echo_delay) {
285 
286         oldtime = newtime;      /* Timer runout - record newtime */
287         return (ON);            /* Return true */
288     }
289 
290     else
291         return (OFF);       /* No timer runout - return false */
292 }               /* End of check_echo_delay */
293 
294 
295 
296 /*^L
297 **********************************************************************
298 
299   Routine:            CHECK_MOWSE_STATUS
300 
301   Function:
302       This routine checks MOWSE's status flag with WSTERM's static
303   switch to determine if there has been a change in MOWSE's status
304   (either attached or detached). If MOWSE's status has changed to
305   attached, a WSTERM capability is created; if MOWSE's status has
306   changed to detached, the WSTERM capability is destroyed; otherwise
307   there is no change in status and nothing happens.
308 
309   Parameters:         NONE
310 
311   Returns:            NONE
312 
313 **********************************************************************/
314 
315 check_MOWSE_status ()
316 {
317 
318     /* If WSTERM's static switch says MOWSE is active but Multics MOWSE is
319    detached, free WSTERM's MCB and set various static switches */
320 
321     if (mowse_active && tdata_arg.minor_capability == DETACHED) {
322 
323         destinst(&wst_mcb);
324 
325         mowse_active = OFF;
326 
327         /* in glass tty mode, use edit mode only if the default */
328         /* for glass tty mode is edit mode */
329         wst_edit_mode = glass_edit_mode;
330 
331         /* RL: phx21233 - always echo in edit mode when MOWSE is not */
332         /* attached since no mowse_io_ to control printer on/off */
333         if (wst_edit_mode)
334             kb.echo = ON;
335 
336         /* RL: phx21233 - OFF in non-edit mode to prevent double echoing */
337         else
338             kb.echo = OFF;
339 
340         /* Send any typeahead */
341 
342         if (kb.cndx > 0) {
343 
344             puttdata (FG_TERMINAL_DATA, kb.klin, strlen (kb.klin));
345 
346             kb.cndx = 0;            /* Wipe keyboard buffer */
347             kb.endx = 0;
348             kb.klin [0] = NUL;
349 
350             ds.ccol = 0;            /* Wipe keyboard display */
351             ds.lct = 0;
352             ds.lndx = 0;
353             ds.dlin [0] = NUL;
354             ds.pstrl = 0;
355             ds.pstr [0] = NUL;
356             screen.EOP_ct = 0;
357             ds.splct [0] = NUL;
358         }
359     }
360 
361     /* If WSTERM's static switch says MOWSE is not active but
362        Multics MOWSE is attached, tell MOWSE to put WSTERM into
363        the CAT and set static switches */
364 
365     else if (~mowse_active && tdata_arg.minor_capability == ATTACHED) {
366 
367         cretinst ("WSTERM",   /* capability name */
368             NULL,             /* NULL entry function */
369             0,                /* zero inbuff length */
370             0,                /* zero outbuff length */
371             NULL,             /* NULL data ptr */
372             &wst_mcb);        /* MCB ptr */
373 
374         mowse_active = ON;
375         kb.echo = ON;
376 
377         /* mowse now active, determine mode for editing; */
378         /* use edit mode only if default for async is edit mode */
379         wst_edit_mode = TRUE;
380         crecho = OFF;
381         lfecho = OFF;
382 
383     }
384 }               /* End of check_MOWSE_status */
385 
386 
387 
388 /*^L
389 **********************************************************************
390 
391   Routine:            CHECK_WST_STATUS
392 
393   Function:
394       This routine checks WSTERM's MOWSE status flag against the
395   global flag 'wst_status' (which indicates the status that is
396   displayed on the status line). If a change is detected, the
397   wst_status flag is updated and the new status is displayed in the
398   status line.
399 
400   Parameters:         NONE
401 
402   Returns:            NONE
403 
404 **********************************************************************/
405 
406 check_wst_status()
407 {
408     int status;
409 
410     status = WST_UNKNOWN_MODE;
411 
412     /* determine the current mode */
413     if (~mowse_active) status = WST_GLASS_TTY_MODE;
414     else if (sync) status = WST_SYNC_MODE;
415     else status = WST_ASYNC_MODE;
416 
417     /* if status is the same since last checked, do nothing */
418     if (wst_status == status) return;
419 
420     /* update the status flag for the next check */
421     wst_status = status;
422 
423     /* update the new status on the status line */
424     update_status();
425 }
426 
427 
428 
429 /*^L
430 **********************************************************************
431 
432   Routine:            PARSE_ARGS
433 
434   Function:
435       This routine parses WSTERM's command line arguments, setting
436   appropriate flags and variables if the command line arguments are
437   recognized. Default values are assigned to flags and variables not
438   affected by the command line arguments. The following table
439   indicates the flag/variables affected by their corresponding
440   control argument specifier:
441 
442   global flag         default value   control argument   new value
443   -----------         -------------   ----------------   ---------
444   break_sent_to_host  OFF             /B                 ON
445   audit_file_name     "wsterm.log"    /A                 <user file name>
446   wst_printer_card    0               /P                 0-2
447 
448   Parameters:
449      (input)          argc - the argc value passed to main()
450      (input)          argv - the argv value passed to main
451 
452   Returns:            -1 if a parsing error occurred
453                       0 if no error occurred
454 
455   Note 1 - If a parsing error is encountered, an error message is
456       displayed by this module.
457 **********************************************************************/
458 
459 parse_args(argc,argv)
460 int argc;
461 char *argv[];
462 {
463     int i;
464     char tmp[133]; /* trash variable for trapping invalid input */
465 
466     /* initialize with default values */
467     break_sends_to_host = OFF;
468     audit_file_name = DEFAULT_AUDIT_FILE;
469     wst_printer_card = DEFAULT_PRINTER_CARD;
470 
471     /* loop through each argument from left to right on command line */
472     for (i = 1; i < argc; i++) {
473 
474         /* check for /B */
475         if (!strcmp(argv[i],"/B") || !strcmp(argv[i],"/b"))
476             break_sends_to_host = ON;
477 
478         /* check for /A */
479         else if (!strcmp(argv[i],"/A") || !strcmp(argv[i],"/a")) {
480 
481             i++;
482             if (argc <= i || argv[i][0] == '/') {
483                 printf("Missing audit file name specifier for /A argument\n");
484                 return(-1);
485             }
486             audit_file_name = argv[i];
487 
488         }
489 
490         /* check for /P */
491         else if (!strcmp(argv[i],"/P") || !strcmp(argv[i],"/p")) {
492 
493             i++;
494             if (argc <= i || argv[i][0] == '/') {
495                 printf("Missing printer card number (0-2) for /P argument\n");
496                 return(-1);
497             }
498             if (sscanf(argv[i],"%d%s",&wst_printer_card,tmp) != 1 ||
499                 wst_printer_card < MIN_PRINTER_CARD_VAL ||
500                 wst_printer_card > MAX_PRINTER_CARD_VAL) {
501                 printf("Invalid printer card value; must be 0, 1 or 2.\n");
502                 wst_printer_card = DEFAULT_PRINTER_CARD;
503                 return(-1);
504             }
505         }
506 
507         /* not a recognized command line argument */
508         else {
509             printf("Invalid WSTERM argument: %s\n", argv[i]);
510             return(-1);
511         }
512     }
513     return(0);
514 }
515 
516 
517 
518 /*^L
519 **********************************************************************
520 
521   Routine:            LEAVE_SCREEN
522 
523   Function:
524       This routine is called before exiting WSTERM to leave most of
525   WSTERM's screen on the display upon exiting. This is done by
526   scrolling the screen up one line and positioning the cursor at the
527   bottom left hand corner of the screen.
528 
529   Parameters:         NONE
530 
531   Returns:            NONE
532 
533 **********************************************************************/
534 
535 leave_screen()
536 {
537     union REGS reg, outreg;
538 
539     /* scroll screen up a line */
540     reg.h.ah = VIDEO_SCROLL_UP_FUNC;
541     reg.h.al = DEFAULT_LINES_TO_SCROLL;
542     reg.h.ch = CURSOR_HOME_ROW;
543     reg.h.cl = CURSOR_HOME_COL;
544     reg.h.dh = SCREEN_LINES;
545     reg.h.dl = SCREEN_COLS-1;
546     reg.h.bh = wst_fg_screen.attr;
547     int86(BIOS_VIDEO,&reg,&outreg);
548 
549     /* move cursor to bottom line of screen, column 0 */
550     cursor_move(SCREEN_LINES,0);
551 }
552 
553 
554 /* End of WSTERM */