DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T s

⟦6bf2dfd78⟧ TextFile

    Length: 10629 (0x2985)
    Types: TextFile
    Names: »showmsg.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/elm/src/showmsg.c« 

TextFile

/** 			showmsg.c			**/

/** This file contains all the routines needed to display the specified
    message.

   These routines (C) Copyright 1986 Dave Taylor 

   Modified 6/86 to use pager variable!!!   Hurrah!!!!
   Modified 7/86 to have secure pipes.. *sigh*
**/

#include "headers.h"
#include <ctype.h>
#include <errno.h>
#include <signal.h>

#ifdef BSD
# include <sys/wait.h>
# undef tolower
#endif

extern int errno;

char *error_name(), *strcat(), *strcpy();
void   _exit();

int    memory_lock = FALSE;	/* is it available?? */
int    pipe_abort  = FALSE;	/* did we receive a SIGNAL(SIGPIPE)? */

int
show_msg(number)
int number;
{
	/*** display number'th message.  Get starting and ending lines
	     of message from headers data structure, then fly through
	     the file, displaying only those lines that are between the
	     two!
		Returns non-zero iff screen was changed
	***/

	dprint0(8, "show_msg called\n");

	if (number > message_count) {
	  error1("Only %d messages!", message_count);
	  return(0);
	}
	else if (number < 1) {
	  error("you can't read THAT message!");
	  return(0);
	}

	clearit(header_table[number-1].status, NEW);   /* it's been read now! */

	memory_lock = FALSE;

	/* some explaination for that last one - We COULD use memory locking
	   to speed up the paging, but the action of "ClearScreen" on a screen
	   with memory lock turned on seems to vary considerably (amazingly so)
	   so it's safer to only allow memory lock to be a viable bit of
	   trickery when dumping text to the screen in scroll mode.
	   Philosophical arguments should be forwarded to Bruce at the 
	   University of Walamazoo, Australia, via ACSNet  *wry chuckle* */

	return(show_message(header_table[number-1].lines, 
	       header_table[number-1].offset,number));
}

int
show_message(lines, file_loc, msgnumber)
int lines, msgnumber;
long file_loc;
{
	/*** Show the indicated range of lines from mailfile
	     for message 'msgnumber' by using 'display'
	     Returns non-zero iff screen was altered.
	***/

	dprint3(9,"show_message(%d,%ld,%d)\n", lines, file_loc, msgnumber);

	if (fseek(mailfile, file_loc, 0) != 0) {
	  dprint2(1,"Error: seek %d bytes into file, errno %s (show_message)\n",
		  file_loc, error_name(errno));
	  error2("ELM failed seeking %d bytes into file (%s)",
		  file_loc, error_name(errno));	
	  return(0);
	}

	if (feof(mailfile))
	  dprint0(1,"\n*** seek put us at END OF FILE!!! ***\n");

	/* next read will get 'this' line so must be at end of previous */

	Raw(OFF);
	if (strcmp(pager,"builtin") == 0 || strcmp(pager,"internal") == 0)
	  display(lines, msgnumber);
	else
	  secure_display(lines, msgnumber);
	Raw(ON);
	if (memory_lock) EndMemlock();	/* turn it off!! */

	return(1);	/* we did it boss! */
}
	

/** This next one is the 'pipe' file descriptor for writing to the 
    pager process... **/

FILE   *output_pipe, *popen();

int
display(lines, msgnum)
int lines, msgnum;
{
	/** Display specified number of lines from file mailfile.
	    Note: This routine MUST be placed at the first line 
	    of the input file! 
	    Returns the same as the routine above (namely zero or one)
	**/

	char from_buffer[LONG_STRING], buffer[VERY_LONG_STRING], *full_month();

	int lines_displayed = 0;	
	int crypted = 0, gotten_key = 0;	/* encryption */
	int weed_header, weeding_out = 0;	/* weeding    */ 
	int mail_sent,				/* misc use   */
	    form_letter = FALSE,		/* Form ltr?  */
	    form_letter_section = 0,		/* section    */
	    builtin = FALSE;			/* our pager? */

	dprint3(4,"displaying %d lines from message %d using %s\n", 
		lines, msgnum, pager);

	ClearScreen();

	if (cursor_control) transmit_functions(OFF);

	pipe_abort = FALSE;

	builtin = (strcmp(pager, "builtin") == 0 || 
		   strcmp(pager,"internal") == 0);

	if (form_letter = (header_table[msgnum-1].status&FORM_LETTER)) {
	  if (filter)
	    form_letter_section = 1;	/* initialize to section 1 */
	}

	if (builtin) 
	  start_builtin(lines);
	else {
	  if ((output_pipe = popen(pager,"w")) == NULL) {
	    error2("Can't create pipe to %s [%s]", pager, 
		    error_name(errno));
	    dprint2(1,"\n*** Can't create pipe to %s - error %s ***\n\n",
	   	    pager, error_name(errno));
	    return(0);
	  }
	  dprint1(4,"Opened a write-only pipe to routine %s \n", pager);
	}

	if (title_messages) {

	  mail_sent = (strncmp(header_table[msgnum-1].from, "To:", 3) == 0);

	  tail_of(header_table[msgnum-1].from, from_buffer, FALSE);

	  sprintf(buffer, "\r%s #%d %s %s%s\t %s %s %s, %d at %s%s\n\r",
		   form_letter? "Form": "Message",
		    msgnum, mail_sent? "to" : "from", from_buffer,
		   (strlen(from_buffer) > 24? "\n\r": 
		     (strlen(from_buffer) > 16 ? "" : "\t")),
		   "Mailed",
     		   full_month(header_table[msgnum-1].month), 
		   header_table[msgnum-1].day, 
	           atoi(header_table[msgnum-1].year) + 1900,
	           header_table[msgnum-1].time,
		   filter? "": "\n\r\n\r");

	  if (builtin)
	    display_line(buffer);
	  else
	    fprintf(output_pipe, "%s", buffer);

	  if (! mail_sent && matches_weedlist("To:") && filter &&
	      strcmp(header_table[current-1].to,username) != 0 &&
	      strlen(header_table[current-1].to) > 0) {
	    sprintf(buffer, "\n\r(message addressed to %s)\n\r", 
		    header_table[current-1].to);
	    if (builtin)
	      display_line(buffer);
	    else
	      fprintf(output_pipe, "%s", buffer);
	  }
	
	  /** The test above is: if we didn't originally send the mail
	      (e.g. we're not reading "mail.sent") AND the user is currently
	      weeding out the "To:" line (otherwise they'll get it twice!)
	      AND the user is actually weeding out headers AND the message 
	      wasn't addressed to the user AND the 'to' address is non-zero 
	      (consider what happens when the message doesn't HAVE a "To:" 
	      line...the value is NULL but it doesn't match the username 
	      either.  We don't want to display something ugly like 
	      "(message addressed to )" which will just clutter up the 
	      display!).

	      And you thought programming was EASY!!!!
	  **/
	}

	weed_header = filter;	/* allow us to change it after header */

	while (lines > 0 && pipe_abort == FALSE) {

	    if (fgets(buffer, VERY_LONG_STRING, mailfile) == NULL) {
	      if (lines_displayed == 0) {

		/* AUGH!  Why do we get this occasionally???  */

	        dprint0(1,
	   	  "\n\n** Out of Sync!!  EOF with nothing read (display) **\n");
		dprint0(1,"** closing and reopening mailfile... **\n\n");

	        if (!builtin) pclose(output_pipe);	/* close pipe NOW! */

		if (mailfile != NULL)
		  fclose(mailfile);		/* huh? */

		if ((mailfile = fopen(infile, "r")) == NULL) {
		  error("Sync error: can't re-open mailbox!!");
		  show_mailfile_stats();
		  emergency_exit();
	        }
	        return(show_message(lines, 
			            header_table[msgnum-1].offset,
				    msgnum));
	      }
	      if (!builtin) 
	        pclose(output_pipe);
	      if (lines == 0 && pipe_abort == FALSE) {	/* displayed it all */
		if (!builtin)
	          PutLine0(LINES,0,"\rPress <return> to return to Elm: ");
	        else
		  printf("\n\r\n\rPress <return> to return to Elm: ");
		fflush(stdout);
	        Raw(ON);
	        (void) ReadCh();
	        Raw(OFF);
	      }
	      return(TRUE);
	    }

	    if (strlen(buffer) > 0) 
              no_ret(buffer);

	    if (strlen(buffer) == 0) {
	      weed_header = 0;		/* past header! */
	      weeding_out = 0;
	    }

	    lines--;
	    lines_displayed++;

	    if (form_letter && weed_header)
		/* skip it.  NEVER display random headers in forms! */;
	    else if (weed_header && matches_weedlist(buffer)) 
	      weeding_out = 1;	 /* aha!  We don't want to see this! */
	    else if (buffer[0] == '[') {
	      if (strcmp(buffer, START_ENCODE)==0)
	        crypted++;
	      else if (strcmp(buffer, END_ENCODE)==0)
	        crypted--;
	      else if (crypted) {
                encode(buffer);
	        show_line(buffer, builtin);
	      }
	      else
	        show_line(buffer, builtin);
	    } 
	    else if (crypted) {
	      if (! gotten_key++) getkey(OFF);
	      encode(buffer);
	      show_line(buffer, builtin); 
	    }
	    else if (weeding_out) {
	      weeding_out = (whitespace(buffer[0]));	/* 'n' line weed */
	      if (! weeding_out) 	/* just turned on! */
	        show_line(buffer, builtin);
	    } 
	    else if (form_letter && first_word(buffer,"***") && filter) {
	      strcpy(buffer,
"\n------------------------------------------------------------------------------\n");
	      show_line(buffer, builtin);	/* hide '***' */
	      form_letter_section++;
	    }
	    else if (form_letter_section == 1 || form_letter_section == 3)
	      /** skip this stuff - we can't deal with it... **/;
	    else
	      show_line(buffer, builtin);
	}

        if (cursor_control) transmit_functions(ON);

	if (! builtin) pclose(output_pipe);

	if (lines == 0 && pipe_abort == FALSE) {  	/* displayed it all! */
	  if (! builtin)
	    PutLine0(LINES,0,"\rPress <return> to return to Elm: ");
	  else
	    printf("\n\r\n\rPress <return> to return to Elm: ");
	  fflush(stdout);
	  Raw(ON);
	  (void) ReadCh();
	  Raw(OFF);
	}
	return(TRUE);
}

show_line(buffer, builtin)
char *buffer;
int  builtin;
{
	/** Hands the given line to the output pipe.  'builtin' is true if
	    we're using the builtin pager.  **/ 
	
	if (builtin) {
	  strcat(buffer, "\n\r");
	  pipe_abort = display_line(buffer);
	}
	else {
	  errno = 0;
	  fprintf(output_pipe, "%s\n", buffer);
	
	  if (errno != 0)
	    dprint1(1,"\terror %s hit!\n", error_name(errno));
	}
}

int
secure_display(lines, msgnumber)
int lines, msgnumber;
{
	/** This is the cheap way to implement secure pipes - spawn a
	    child process running under the old userid, then open the
	    pager and feed the message to it.  When the subprocess ends
	    (the routine returns) simply return.  Simple and effective.
	    (too bad it's this much of a hassle to implement secure
	    pipes, though - I can imagine it being a constant problem!)
	**/

	int pid, w;
#ifdef BSD
	union wait status;
#else
	int status;
#endif
	register int (*istat)(), (*qstat)();
	
#ifdef NO_VM		/* machine without virtual memory! */
	if ((pid = fork()) == 0) {
#else
	if ((pid = vfork()) == 0) {
#endif

	  setgid(groupid);	/* and group id		    */
	  setuid(userid);	/* back to the normal user! */

	  _exit(display(lines, msgnumber));
	}

	istat = signal(SIGINT, SIG_IGN);
	qstat = signal(SIGQUIT, SIG_IGN);

	while ((w = wait(&status)) != pid && w != -1)
		;

	signal(SIGINT, istat);
	signal(SIGQUIT, qstat);

#ifdef BSD
	return(status.w_retcode);
#else
	return(status);
#endif
}