|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 10629 (0x2985)
Types: TextFile
Names: »showmsg.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/elm/src/showmsg.c«
/** 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
}