summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAchim Gottinger <achim@gentoo.org>2001-04-30 11:40:12 +0000
committerAchim Gottinger <achim@gentoo.org>2001-04-30 11:40:12 +0000
commit1e4b581725e1a7a7c13b336f3a400ccddd16f81d (patch)
treefd15ffd5b93cf4325374f478fab91303c35bf2e4 /net-mail/pine/files
parentCleanup (diff)
downloadgentoo-2-1e4b581725e1a7a7c13b336f3a400ccddd16f81d.tar.gz
gentoo-2-1e4b581725e1a7a7c13b336f3a400ccddd16f81d.tar.bz2
gentoo-2-1e4b581725e1a7a7c13b336f3a400ccddd16f81d.zip
Cleanup
Diffstat (limited to 'net-mail/pine/files')
-rw-r--r--net-mail/pine/files/digest-pine-4.21-r21
-rw-r--r--net-mail/pine/files/filter.c6902
-rw-r--r--net-mail/pine/files/os.c5673
3 files changed, 0 insertions, 12576 deletions
diff --git a/net-mail/pine/files/digest-pine-4.21-r2 b/net-mail/pine/files/digest-pine-4.21-r2
deleted file mode 100644
index cdba66b6aa7f..000000000000
--- a/net-mail/pine/files/digest-pine-4.21-r2
+++ /dev/null
@@ -1 +0,0 @@
-MD5 9252a061387de806f8aa1ced885d41f6 pine4.21.tar.gz
diff --git a/net-mail/pine/files/filter.c b/net-mail/pine/files/filter.c
deleted file mode 100644
index ed1c2d6aedda..000000000000
--- a/net-mail/pine/files/filter.c
+++ /dev/null
@@ -1,6902 +0,0 @@
-#if !defined(lint) && !defined(DOS)
-static char rcsid[] = "$Id: filter.c,v 1.1 2000/11/15 16:46:05 achim Exp $";
-#endif
-/*----------------------------------------------------------------------
-
- T H E P I N E M A I L S Y S T E M
-
- Laurence Lundblade and Mike Seibel
- Networks and Distributed Computing
- Computing and Communications
- University of Washington
- Administration Builiding, AG-44
- Seattle, Washington, 98195, USA
- Internet: lgl@CAC.Washington.EDU
- mikes@CAC.Washington.EDU
-
- Please address all bugs and comments to "pine-bugs@cac.washington.edu"
-
-
- Pine and Pico are registered trademarks of the University of Washington.
- No commercial use of these trademarks may be made without prior written
- permission of the University of Washington.
-
- Pine, Pico, and Pilot software and its included text are Copyright
- 1989-1999 by the University of Washington.
-
- The full text of our legal notices is contained in the file called
- CPYRIGHT, included with this distribution.
-
-
- Pine is in part based on The Elm Mail System:
- ***********************************************************************
- * The Elm Mail System - Revision: 2.13 *
- * *
- * Copyright (c) 1986, 1987 Dave Taylor *
- * Copyright (c) 1988, 1989 USENET Community Trust *
- ***********************************************************************
-
-
- ----------------------------------------------------------------------*/
-
-/*======================================================================
- filter.c
-
- This code provides a generalized, flexible way to allow
- piping of data thru filters. Each filter is passed a structure
- that it will use to hold its static data while it operates on
- the stream of characters that are passed to it. After processing
- it will either return or call the next filter in
- the pipe with any character (or characters) it has ready to go. This
- means some terminal type of filter has to be the last in the
- chain (i.e., one that writes the passed char someplace, but doesn't
- call another filter).
-
- See below for more details.
-
- The motivation is to handle MIME decoding, richtext conversion,
- iso_code stripping and anything else that may come down the
- pike (e.g., PEM) in an elegant fashion. mikes (920811)
-
- TODO:
- reasonable error handling
-
- ====*/
-
-
-#include "headers.h"
-
-
-/*
- * Internal prototypes
- */
-int gf_so_readc PROTO((unsigned char *));
-int gf_so_writec PROTO((int));
-int gf_sreadc PROTO((unsigned char *));
-int gf_swritec PROTO((int));
-int gf_freadc PROTO((unsigned char *));
-int gf_fwritec PROTO((int));
-void gf_terminal PROTO((FILTER_S *, int));
-char *gf_filter_puts PROTO((char *));
-void gf_filter_eod PROTO((void));
-void gf_error PROTO((char *));
-void gf_8bit_put PROTO((FILTER_S *, int));
-int so_reaquire PROTO((STORE_S *));
-void *so_file_open PROTO((STORE_S *));
-int so_cs_writec PROTO((int, STORE_S *));
-int so_pico_writec PROTO((int, STORE_S *));
-int so_file_writec PROTO((int, STORE_S *));
-int so_cs_readc PROTO((unsigned char *, STORE_S *));
-int so_pico_readc PROTO((unsigned char *, STORE_S *));
-int so_file_readc PROTO((unsigned char *, STORE_S *));
-int so_cs_puts PROTO((STORE_S *, char *));
-int so_pico_puts PROTO((STORE_S *, char *));
-int so_file_puts PROTO((STORE_S *, char *));
-
-
-/*
- * GENERALIZED STORAGE FUNCTIONS. Idea is to allow creation of
- * storage objects that can be written into and read from without
- * the caller knowing if the storage is core or in a file
- * or whatever.
- */
-#define MSIZE_INIT 8192
-#define MSIZE_INC 4096
-
-
-/*
- * System specific options
- */
-#ifdef DOS
-#define NO_PIPE
-#endif
-#if defined(DOS) || defined(OS2)
-#define CRLF_NEWLINES
-#endif
-
-/*
- * Various parms for opening and creating files directly and via stdio.
- * NOTE: If "binary" mode file exists, use it.
- */
-#ifdef O_BINARY
-#define STDIO_READ "rb"
-#define STDIO_APPEND "a+b"
-#else
-#define O_BINARY 0
-#define STDIO_READ "r"
-#define STDIO_APPEND "a+"
-#endif
-
-#define OP_FL_RDWR (O_RDWR | O_CREAT | O_APPEND | O_BINARY)
-#define OP_FL_RDONLY (O_RDONLY | O_BINARY)
-
-#ifdef S_IREAD
-#define OP_MD_USER (S_IREAD | S_IWRITE)
-#else
-#define OP_MD_USER 0600
-#endif
-
-#ifdef S_IRUSR
-#define OP_MD_ALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | \
- S_IROTH | S_IWOTH)
-#else
-#define OP_MD_ALL 0666
-#endif
-
-
-/*
- * allocate resources associated with the specified type of
- * storage. If requesting a named file object, open it for
- * appending, else just open a temp file.
- *
- * return the filled in storage object
- */
-STORE_S *
-so_get(source, name, rtype)
- SourceType source; /* requested storage type */
- char *name; /* file name */
- int rtype; /* file access type */
-{
- STORE_S *so = (STORE_S *)fs_get(sizeof(STORE_S));
-
- memset(so, 0, sizeof(STORE_S));
- so->flags |= rtype;
-
- if(name) /* stash the name */
- so->name = cpystr(name);
-#ifdef DOS
- else if(source == TmpFileStar || source == FileStar){
- /*
- * Coerce to TmpFileStar. The MSC library's "tmpfile()"
- * doesn't observe the "TMP" or "TEMP" environment vars and
- * always wants to write "\". This is problematic in shared,
- * networked environments.
- */
- source = TmpFileStar;
- so->name = temp_nam(NULL, "pi");
- }
-#else
- else if(source == TmpFileStar) /* make one up! */
- so->name = temp_nam(NULL, "pine-tmp");
-#endif
-
- so->src = source;
- if(so->src == FileStar || so->src == TmpFileStar){
- so->writec = so_file_writec;
- so->readc = so_file_readc;
- so->puts = so_file_puts;
-
- /*
- * The reason for both FileStar and TmpFileStar types is
- * that, named or unnamed, TmpFileStar's are unlinked
- * when the object is given back to the system. This is
- * useful for keeping us from running out of file pointers as
- * the pointer associated with the object can be temporarily
- * returned to the system without destroying the object.
- *
- * The programmer is warned to be careful not to assign the
- * TmpFileStar type to any files that are expected to remain
- * after the dust has settled!
- */
- if(so->name){
- if(!(so->txt = so_file_open(so))){
- dprint(1, (debugfile, "so_get error: %s : %s", so->name,
- error_description(errno)));
- fs_give((void **)&so->name);
- fs_give((void **)&so); /* so freed & set to NULL */
- }
- }
- else{
- if(!(so->txt = (void *) create_tmpfile())){
- dprint(1, (debugfile, "so_get error: tmpfile : %s",
- error_description(errno)));
- fs_give((void **)&so); /* so freed & set to NULL */
- }
- }
- }
- else if(so->src == PicoText){
- so->writec = so_pico_writec;
- so->readc = so_pico_readc;
- so->puts = so_pico_puts;
- if(!(so->txt = pico_get())){
- dprint(1, (debugfile, "so_get error: alloc of pico text space"));
- if(so->name)
- fs_give((void **)&so->name);
- fs_give((void **)&so); /* so freed & set to NULL */
- }
- }
- else{
- so->writec = so_cs_writec;
- so->readc = so_cs_readc;
- so->puts = so_cs_puts;
- so->txt = (void *)fs_get((size_t) MSIZE_INIT * sizeof(char));
- so->dp = so->eod = (unsigned char *) so->txt;
- so->eot = so->dp + MSIZE_INIT;
- memset(so->eod, 0, so->eot - so->eod);
- }
-
- return(so);
-}
-
-
-/*
- * so_give - free resources associated with a storage object and then
- * the object itself.
- */
-void
-so_give(so)
-STORE_S **so;
-{
- if(!so)
- return;
-
- if((*so)->src == FileStar || (*so)->src == TmpFileStar){
- if((*so)->txt)
- fclose((FILE *)(*so)->txt); /* disassociate from storage */
-
- if((*so)->name && (*so)->src == TmpFileStar)
- unlink((*so)->name); /* really disassociate! */
- }
- else if((*so)->txt && (*so)->src == PicoText)
- pico_give((*so)->txt);
- else if((*so)->txt)
- fs_give((void **)&((*so)->txt));
-
- if((*so)->name)
- fs_give((void **)&((*so)->name)); /* blast the name */
-
- fs_give((void **)so); /* release the object */
-}
-
-
-/*
- * so_file_open
- */
-void *
-so_file_open(so)
- STORE_S *so;
-{
- char *type = ((so->flags) & WRITE_ACCESS) ? STDIO_APPEND : STDIO_READ;
- int flags = ((so->flags) & WRITE_ACCESS) ? OP_FL_RDWR : OP_FL_RDONLY,
- mode = (((so->flags) & OWNER_ONLY) || so->src == TmpFileStar)
- ? OP_MD_USER : OP_MD_ALL,
- fd;
-
- /*
- * Use open instead of fopen so we can make temp files private.
- */
- return(((fd = open(so->name, flags, mode)) >= 0)
- ? (so->txt = (void *) fdopen(fd, type)) : NULL);
-}
-
-
-/*
- * put a character into the specified storage object,
- * expanding if neccessary
- *
- * return 1 on success and 0 on failure
- */
-int
-so_cs_writec(c, so)
- int c;
- STORE_S *so;
-{
- if(so->dp >= so->eot){
- size_t cur_o = so->dp - (unsigned char *) so->txt;
- size_t data_o = so->eod - (unsigned char *) so->txt;
- size_t size = (so->eot - (unsigned char *) so->txt) + MSIZE_INC;
-
- fs_resize(&so->txt, size * sizeof(char));
- so->dp = (unsigned char *) so->txt + cur_o;
- so->eod = (unsigned char *) so->txt + data_o;
- so->eot = (unsigned char *) so->txt + size;
- memset(so->eod, 0, so->eot - so->eod);
- }
-
- *so->dp++ = (unsigned char) c;
- if(so->dp > so->eod)
- so->eod = so->dp;
-
- return(1);
-}
-
-int
-so_pico_writec(c, so)
- int c;
- STORE_S *so;
-{
- unsigned char ch = (unsigned char) c;
-
- return(pico_writec(so->txt, ch));
-}
-
-int
-so_file_writec(c, so)
- int c;
- STORE_S *so;
-{
- unsigned char ch = (unsigned char) c;
- int rv = 0;
-
- if(so->txt || so_reaquire(so))
- do
- rv = fwrite(&ch,sizeof(unsigned char),(size_t)1,(FILE *)so->txt);
- while(!rv && ferror((FILE *)so->txt) && errno == EINTR);
-
- return(rv);
-}
-
-
-/*
- * get a character from the specified storage object.
- *
- * return 1 on success and 0 on failure
- */
-int
-so_cs_readc(c, so)
- unsigned char *c;
- STORE_S *so;
-{
- return((so->dp < so->eod) ? *c = *(so->dp)++, 1 : 0);
-}
-
-int
-so_pico_readc(c, so)
- unsigned char *c;
- STORE_S *so;
-{
- return(pico_readc(so->txt, c));
-}
-
-int
-so_file_readc(c, so)
- unsigned char *c;
- STORE_S *so;
-{
- int rv = 0;
-
- if(so->txt || so_reaquire(so))
- do
- rv = fread(c, sizeof(char), (size_t)1, (FILE *)so->txt);
- while(!rv && ferror((FILE *)so->txt) && errno == EINTR);
-
- return(rv);
-}
-
-
-/*
- * write a string into the specified storage object,
- * expanding if necessary (and cheating if the object
- * happens to be a file!)
- *
- * return 1 on success and 0 on failure
- */
-int
-so_cs_puts(so, s)
- STORE_S *so;
- char *s;
-{
- int slen = strlen(s);
-
- if(so->dp + slen >= so->eot){
- register size_t cur_o = so->dp - (unsigned char *) so->txt;
- register size_t data_o = so->eod - (unsigned char *) so->txt;
- register size_t len = so->eot - (unsigned char *) so->txt;
- while(len <= cur_o + slen + 1)
- len += MSIZE_INC; /* need to resize! */
-
- fs_resize(&so->txt, len * sizeof(char));
- so->dp = (unsigned char *)so->txt + cur_o;
- so->eod = (unsigned char *)so->txt + data_o;
- so->eot = (unsigned char *)so->txt + len;
- memset(so->eod, 0, so->eot - so->eod);
- }
-
- memcpy(so->dp, s, slen);
- so->dp += slen;
- if(so->dp > so->eod)
- so->eod = so->dp;
-
- return(1);
-}
-
-int
-so_pico_puts(so, s)
- STORE_S *so;
- char *s;
-{
- return(pico_puts(so->txt, s));
-}
-
-int
-so_file_puts(so, s)
- STORE_S *so;
- char *s;
-{
- int rv = *s ? 0 : 1;
-
- if(!rv && (so->txt || so_reaquire(so)))
- do
- rv = fwrite(s, strlen(s)*sizeof(char), (size_t)1, (FILE *)so->txt);
- while(!rv && ferror((FILE *)so->txt) && errno == EINTR);
-
- return(rv);
-}
-
-
-/*
- *
- */
-int
-so_nputs(so, s, n)
- STORE_S *so;
- char *s;
- long n;
-{
- while(n--)
- if(!so_writec((unsigned char) *s++, so))
- return(0); /* ERROR putting char ! */
-
- return(1);
-}
-
-
-
-/*
- * Position the storage object's pointer to the given offset
- * from the start of the object's data.
- */
-int
-so_seek(so, pos, orig)
- STORE_S *so;
- long pos;
- int orig;
-{
- if(so->src == CharStar){
- switch(orig){
- case 0 : /* SEEK_SET */
- return((pos < so->eod - (unsigned char *) so->txt)
- ? so->dp = (unsigned char *)so->txt + pos, 0 : -1);
- case 1 : /* SEEK_CUR */
- return((pos > 0)
- ? ((pos < so->eod - so->dp) ? so->dp += pos, 0: -1)
- : ((pos < 0)
- ? ((-pos < so->dp - (unsigned char *)so->txt)
- ? so->dp += pos, 0 : -1)
- : 0));
- case 2 : /* SEEK_END */
- return((pos < so->eod - (unsigned char *) so->txt)
- ? so->dp = so->eod - pos, 0 : -1);
- default :
- return(-1);
- }
- }
- else if(so->src == PicoText)
- return(pico_seek(so->txt, pos, orig));
- else /* FileStar or TmpFileStar */
- return((so->txt || so_reaquire(so))
- ? fseek((FILE *)so->txt,pos,orig)
- : -1);
-}
-
-
-/*
- * Change the given storage object's size to that specified. If size
- * is less than the current size, the internal pointer is adjusted and
- * all previous data beyond the given size is lost.
- *
- * Returns 0 on failure.
- */
-int
-so_truncate(so, size)
- STORE_S *so;
- long size;
-{
- if(so->src == CharStar){
- if(so->eod < (unsigned char *) so->txt + size){ /* alloc! */
- unsigned char *newtxt = (unsigned char *) so->txt;
- register size_t len = so->eot - (unsigned char *) so->txt;
-
- while(len <= size)
- len += MSIZE_INC; /* need to resize! */
-
- if(len > so->eot - (unsigned char *) newtxt){
- fs_resize((void **) &newtxt, len * sizeof(char));
- so->eot = newtxt + len;
- so->eod = newtxt + (so->eod - (unsigned char *) so->txt);
- memset(so->eod, 0, so->eot - so->eod);
- }
-
- so->eod = newtxt + size;
- so->dp = newtxt + (so->dp - (unsigned char *) so->txt);
- so->txt = newtxt;
- }
- else if(so->eod > (unsigned char *) so->txt + size){
- if(so->dp > (so->eod = (unsigned char *)so->txt + size))
- so->dp = so->eod;
-
- memset(so->eod, 0, so->eot - so->eod);
- }
-
- return(1);
- }
- else if(so->src == PicoText){
- fatal("programmer botch: unsupported so_truncate call");
- /*NOTREACHED*/
- }
- else /* FileStar or TmpFileStar */
- return(fflush((FILE *) so->txt) != EOF
- && fseek((FILE *) so->txt, size, 0) == 0
- && ftruncate(fileno((FILE *)so->txt), size) == 0);
-}
-
-
-/*
- * so_release - a rather misnamed function. the idea is to release
- * what system resources we can (e.g., open files).
- * while maintaining a reference to it.
- * it's up to the functions that deal with this object
- * next to re-aquire those resources.
- */
-int
-so_release(so)
-STORE_S *so;
-{
- if(so->txt && so->name && (so->src == FileStar || so->src == TmpFileStar)){
- if(fgetpos((FILE *)so->txt, (fpos_t *)&(so->used)) == 0){
- fclose((FILE *)so->txt); /* free the handle! */
- so->txt = NULL;
- }
- }
-
- return(1);
-}
-
-
-/*
- * so_reaquire - get any previously released system resources we
- * may need for the given storage object.
- * NOTE: at the moment, only FILE * types of objects are
- * effected, so it only needs to be called before
- * references to them.
- *
- */
-so_reaquire(so)
-STORE_S *so;
-{
- int rv = 1;
-
- if(!so->txt && (so->src == FileStar || so->src == TmpFileStar)){
- if(!(so->txt = so_file_open(so))){
- q_status_message2(SM_ORDER,3,5, "ERROR reopening %s : %s", so->name,
- error_description(errno));
- rv = 0;
- }
- else if(fsetpos((FILE *)so->txt, (fpos_t *)&(so->used))){
- q_status_message2(SM_ORDER, 3, 5, "ERROR positioning in %s : %s",
- so->name, error_description(errno));
- rv = 0;
- }
- }
-
- return(rv);
-}
-
-
-/*
- * so_text - return a pointer to the text the store object passed
- */
-void *
-so_text(so)
-STORE_S *so;
-{
- return((so) ? so->txt : NULL);
-}
-
-
-/*
- * END OF GENERALIZE STORAGE FUNCTIONS
- */
-
-
-/*
- * Start of filters, pipes and various support functions
- */
-
-/*
- * pointer to first function in a pipe, and pointer to last filter
- */
-FILTER_S *gf_master = NULL;
-static gf_io_t last_filter;
-static char *gf_error_string;
-static long gf_byte_count;
-static jmp_buf gf_error_state;
-
-
-/*
- * A list of states used by the various filters. Reused in many filters.
- */
-#define DFL 0
-#define EQUAL 1
-#define HEX 2
-#define WSPACE 3
-#define CCR 4
-#define CLF 5
-#define TOKEN 6
-#define TAG 7
-#define HANDLE 8
-#define HDATA 9
-
-
-
-/*
- * Macros to reduce function call overhead associated with calling
- * each filter for each byte filtered, and to minimize filter structure
- * dereferences. NOTE: "queuein" has to do with putting chars into the
- * filter structs data queue. So, writing at the queuein offset is
- * what a filter does to pass processed data out of itself. Ditto for
- * queueout. This explains the FI --> queueout init stuff below.
- */
-#define GF_QUE_START(F) (&(F)->queue[0])
-#define GF_QUE_END(F) (&(F)->queue[GF_MAXBUF - 1])
-
-#define GF_IP_INIT(F) ip = (F) ? &(F)->queue[(F)->queuein] : NULL
-#define GF_EIB_INIT(F) eib = (F) ? GF_QUE_END(F) : NULL
-#define GF_OP_INIT(F) op = (F) ? &(F)->queue[(F)->queueout] : NULL
-#define GF_EOB_INIT(F) eob = (F) ? &(F)->queue[(F)->queuein] : NULL
-
-#define GF_IP_END(F) (F)->queuein = ip - GF_QUE_START(F)
-#define GF_OP_END(F) (F)->queueout = op - GF_QUE_START(F)
-
-#define GF_INIT(FI, FO) register unsigned char *GF_OP_INIT(FI); \
- register unsigned char *GF_EOB_INIT(FI); \
- register unsigned char *GF_IP_INIT(FO); \
- register unsigned char *GF_EIB_INIT(FO);
-
-#define GF_CH_RESET(F) (op = eob = GF_QUE_START(F), \
- (F)->queueout = (F)->queuein = 0)
-
-#define GF_END(FI, FO) (GF_OP_END(FI), GF_IP_END(FO))
-
-#define GF_FLUSH(F) ((int)(GF_IP_END(F), (*(F)->f)((F), GF_DATA), \
- GF_IP_INIT(F), GF_EIB_INIT(F)))
-
-#define GF_PUTC(F, C) ((int)(*ip++ = (C), (ip >= eib) ? GF_FLUSH(F) : 1))
-
-#define GF_GETC(F, C) ((op < eob) ? (((C) = *op++), 1) : GF_CH_RESET(F))
-
-
-/*
- * Generalized getc and putc routines. provided here so they don't
- * need to be re-done elsewhere to
- */
-
-/*
- * pointers to objects to be used by the generic getc and putc
- * functions
- */
-static struct gf_io_struct {
- FILE *file;
- char *txtp;
- unsigned long n;
-} gf_in, gf_out;
-
-
-#define GF_SO_STACK struct gf_so_stack
-static GF_SO_STACK {
- STORE_S *so;
- GF_SO_STACK *next;
-} *gf_so_in, *gf_so_out;
-
-
-/*
- * setup to use and return a pointer to the generic
- * getc function
- */
-void
-gf_set_readc(gc, txt, len, src)
- gf_io_t *gc;
- void *txt;
- unsigned long len;
- SourceType src;
-{
- gf_in.n = len;
- if(src == FileStar){
- gf_in.file = (FILE *)txt;
- fseek(gf_in.file, 0L, 0);
- *gc = gf_freadc;
- }
- else{
- gf_in.txtp = (char *)txt;
- *gc = gf_sreadc;
- }
-}
-
-
-/*
- * setup to use and return a pointer to the generic
- * putc function
- */
-void
-gf_set_writec(pc, txt, len, src)
- gf_io_t *pc;
- void *txt;
- unsigned long len;
- SourceType src;
-{
- gf_out.n = len;
- if(src == FileStar){
- gf_out.file = (FILE *)txt;
- *pc = gf_fwritec;
- }
- else{
- gf_out.txtp = (char *)txt;
- *pc = gf_swritec;
- }
-}
-
-
-/*
- * setup to use and return a pointer to the generic
- * getc function
- */
-void
-gf_set_so_readc(gc, so)
- gf_io_t *gc;
- STORE_S *so;
-{
- GF_SO_STACK *sp = (GF_SO_STACK *) fs_get(sizeof(GF_SO_STACK));
-
- sp->so = so;
- sp->next = gf_so_in;
- gf_so_in = sp;
- *gc = gf_so_readc;
-}
-
-
-void
-gf_clear_so_readc(so)
- STORE_S *so;
-{
- GF_SO_STACK *sp;
-
- if(sp = gf_so_in){
- if(so == sp->so){
- gf_so_in = gf_so_in->next;
- fs_give((void **) &sp);
- }
- else
- panic("Programmer botch: Can't unstack store readc");
- }
- else
- panic("Programmer botch: NULL store clearing store readc");
-}
-
-
-/*
- * setup to use and return a pointer to the generic
- * putc function
- */
-void
-gf_set_so_writec(pc, so)
- gf_io_t *pc;
- STORE_S *so;
-{
- GF_SO_STACK *sp = (GF_SO_STACK *) fs_get(sizeof(GF_SO_STACK));
-
- sp->so = so;
- sp->next = gf_so_out;
- gf_so_out = sp;
- *pc = gf_so_writec;
-}
-
-
-void
-gf_clear_so_writec(so)
- STORE_S *so;
-{
- GF_SO_STACK *sp;
-
- if(sp = gf_so_out){
- if(so == sp->so){
- gf_so_out = gf_so_out->next;
- fs_give((void **) &sp);
- }
- else
- panic("Programmer botch: Can't unstack store writec");
- }
- else
- panic("Programmer botch: NULL store clearing store writec");
-}
-
-
-/*
- * put the character to the object previously defined
- */
-int
-gf_so_writec(c)
-int c;
-{
- return(so_writec(c, gf_so_out->so));
-}
-
-
-/*
- * get a character from an object previously defined
- */
-int
-gf_so_readc(c)
-unsigned char *c;
-{
- return(so_readc(c, gf_so_in->so));
-}
-
-
-/* get a character from a file */
-/* assumes gf_out struct is filled in */
-int
-gf_freadc(c)
-unsigned char *c;
-{
- int rv = 0;
-
- do {
- errno = 0;
- clearerr(gf_in.file);
- rv = fread(c, sizeof(unsigned char), (size_t)1, gf_in.file);
- } while(!rv && ferror(gf_in.file) && errno == EINTR);
-
- return(rv);
-}
-
-
-/* put a character to a file */
-/* assumes gf_out struct is filled in */
-int
-gf_fwritec(c)
- int c;
-{
- unsigned char ch = (unsigned char)c;
- int rv = 0;
-
- do
- rv = fwrite(&ch, sizeof(unsigned char), (size_t)1, gf_out.file);
- while(!rv && ferror(gf_out.file) && errno == EINTR);
-
- return(rv);
-}
-
-
-/* get a character from a string, return nonzero if things OK */
-/* assumes gf_out struct is filled in */
-int
-gf_sreadc(c)
-unsigned char *c;
-{
- return((gf_in.n) ? *c = *(gf_in.txtp)++, gf_in.n-- : 0);
-}
-
-
-/* put a character into a string, return nonzero if things OK */
-/* assumes gf_out struct is filled in */
-int
-gf_swritec(c)
- int c;
-{
- return((gf_out.n) ? *(gf_out.txtp)++ = c, gf_out.n-- : 0);
-}
-
-
-/*
- * output the given string with the given function
- */
-int
-gf_puts(s, pc)
- register char *s;
- gf_io_t pc;
-{
- while(*s != '\0')
- if(!(*pc)((unsigned char)*s++))
- return(0); /* ERROR putting char ! */
-
- return(1);
-}
-
-
-/*
- * output the given string with the given function
- */
-int
-gf_nputs(s, n, pc)
- register char *s;
- long n;
- gf_io_t pc;
-{
- while(n--)
- if(!(*pc)((unsigned char)*s++))
- return(0); /* ERROR putting char ! */
-
- return(1);
-}
-
-
-/*
- * Start of generalized filter routines
- */
-
-/*
- * initializing function to make sure list of filters is empty.
- */
-void
-gf_filter_init()
-{
- FILTER_S *flt, *fltn = gf_master;
-
- while((flt = fltn) != NULL){ /* free list of old filters */
- fltn = flt->next;
- fs_give((void **)&flt);
- }
-
- gf_master = NULL;
- gf_error_string = NULL; /* clear previous errors */
- gf_byte_count = 0L; /* reset counter */
-}
-
-
-
-/*
- * link the given filter into the filter chain
- */
-void
-gf_link_filter(f, data)
- filter_t f;
- void *data;
-{
- FILTER_S *new, *tail;
-
-#ifdef CRLF_NEWLINES
- /*
- * If the system's native EOL convention is CRLF, then there's no
- * point in passing data thru a filter that's not doing anything
- */
- if(f == gf_nvtnl_local || f == gf_local_nvtnl)
- return;
-#endif
-
- new = (FILTER_S *)fs_get(sizeof(FILTER_S));
- memset(new, 0, sizeof(FILTER_S));
-
- new->f = f; /* set the function pointer */
- new->opt = data; /* set any optional parameter data */
- (*f)(new, GF_RESET); /* have it setup initial state */
-
- if(tail = gf_master){ /* or add it to end of existing */
- while(tail->next) /* list */
- tail = tail->next;
-
- tail->next = new;
- }
- else /* attach new struct to list */
- gf_master = new; /* start a new list */
-}
-
-
-/*
- * terminal filter, doesn't call any other filters, typically just does
- * something with the output
- */
-void
-gf_terminal(f, flg)
- FILTER_S *f;
- int flg;
-{
- if(flg == GF_DATA){
- GF_INIT(f, f);
-
- while(op < eob)
- if((*last_filter)(*op++) <= 0) /* generic terminal filter */
- gf_error(errno ? error_description(errno) : "Error writing pipe");
-
- GF_CH_RESET(f);
- }
- else if(flg == GF_RESET)
- errno = 0; /* prepare for problems */
-}
-
-
-/*
- * set some outside gf_io_t function to the terminal function
- * for example: a function to write a char to a file or into a buffer
- */
-void
-gf_set_terminal(f) /* function to set generic filter */
- gf_io_t f;
-{
- last_filter = f;
-}
-
-
-/*
- * common function for filter's to make it known that an error
- * has occurred. Jumps back to gf_pipe with error message.
- */
-void
-gf_error(s)
- char *s;
-{
- /* let the user know the error passed in s */
- gf_error_string = s;
- longjmp(gf_error_state, 1);
-}
-
-
-/*
- * The routine that shoves each byte through the chain of
- * filters. It sets up error handling, and the terminal function.
- * Then loops getting bytes with the given function, and passing
- * it on to the first filter in the chain.
- */
-char *
-gf_pipe(gc, pc)
- gf_io_t gc, pc; /* how to get a character */
-{
- unsigned char c;
-
-#if defined(DOS) && !defined(_WINDOWS)
- MoveCursor(0, 1);
- StartInverse();
-#endif
-
- dprint(4, (debugfile, "-- gf_pipe: "));
-
- /*
- * set up for any errors a filter may encounter
- */
- if(setjmp(gf_error_state)){
-#if defined(DOS) && !defined(_WINDOWS)
- ibmputc(' ');
- EndInverse();
-#endif
- dprint(4, (debugfile, "ERROR: %s\n",
- gf_error_string ? gf_error_string : "NULL"));
- return(gf_error_string); /* */
- }
-
- /*
- * set and link in the terminal filter
- */
- gf_set_terminal(pc);
- gf_link_filter(gf_terminal, NULL);
-
- /*
- * while there are chars to process, send them thru the pipe.
- * NOTE: it's necessary to enclose the loop below in a block
- * as the GF_INIT macro calls some automatic var's into
- * existence. It can't be placed at the start of gf_pipe
- * because its useful for us to be called without filters loaded
- * when we're just being used to copy bytes between storage
- * objects.
- */
- {
- GF_INIT(gf_master, gf_master);
-
- while((*gc)(&c)){
- gf_byte_count++;
-#ifdef DOS
- if(!(gf_byte_count & 0x3ff))
-#ifdef _WINDOWS
- /* Under windows we yeild to allow event processing.
- * Progress display is handled throught the alarm()
- * mechinism.
- */
- mswin_yeild ();
-#else
- /* Poor PC still needs spinning bar */
- ibmputc("/-\\|"[((int) gf_byte_count >> 10) % 4]);
- MoveCursor(0, 1);
-#endif
-#endif
-
- GF_PUTC(gf_master, c & 0xff);
- }
-
- /*
- * toss an end-of-data marker down the pipe to give filters
- * that have any buffered data the opportunity to dump it
- */
- GF_FLUSH(gf_master);
- (*gf_master->f)(gf_master, GF_EOD);
- }
-
-#if defined(DOS) && !defined(_WINDOWS)
- ibmputc(' ');
- EndInverse();
-#endif
-
- dprint(1, (debugfile, "done.\n"));
- return(NULL); /* everything went OK */
-}
-
-
-/*
- * return the number of bytes piped so far
- */
-long
-gf_bytes_piped()
-{
- return(gf_byte_count);
-}
-
-
-/*
- * filter the given input with the given command
- *
- * Args: cmd -- command string to execute
- * prepend -- string to prepend to filtered input
- * source_so -- storage object containing data to be filtered
- * pc -- function to write filtered output with
- * aux_filters -- additional filters to pass data thru after "cmd"
- *
- * Returns: NULL on sucess, reason for failure (not alloc'd!) on error
- */
-char *
-gf_filter(cmd, prepend, source_so, pc, aux_filters)
- char *cmd, *prepend;
- STORE_S *source_so;
- gf_io_t pc;
- FILTLIST_S *aux_filters;
-{
- unsigned char c;
- int flags;
- char *errstr = NULL, buf[MAILTMPLEN], *rfile = NULL;
- PIPE_S *fpipe;
-
- dprint(4, (debugfile, "so_filter: \"%s\"\n", cmd));
-
- gf_filter_init();
- for( ; aux_filters && aux_filters->filter; aux_filters++)
- gf_link_filter(aux_filters->filter, aux_filters->data);
-
- gf_set_terminal(pc);
- gf_link_filter(gf_terminal, NULL);
-
- /*
- * Spawn filter feeding it data, and reading what it writes.
- */
- so_seek(source_so, 0L, 0);
-#ifdef NO_PIPE
- /*
- * When there're no pipes for IPC, use an output file to collect
- * the result...
- */
- flags = PIPE_WRITE | PIPE_NOSHELL | PIPE_RESET;
- rfile = temp_nam(NULL, "pf");
-#else
- flags = PIPE_WRITE | PIPE_READ | PIPE_NOSHELL | PIPE_RESET;
-#endif
-
- if(fpipe = open_system_pipe(cmd, rfile ? &rfile : NULL, NULL, flags, 0)){
-#ifdef NO_PIPE
- if(prepend && (fputs(prepend, fpipe->out.f) == EOF
- || fputc('\n', fpipe->out.f) == EOF))
- errstr = error_description(errno);
-
- /*
- * Write the output, and deal with the result later...
- */
- while(!errstr && so_readc(&c, source_so))
- if(fputc(c, fpipe->out.f) == EOF)
- errstr = error_description(errno);
-#else
-#ifdef NON_BLOCKING_IO
- int n;
-
- if(fcntl(fileno(fpipe->in.f), F_SETFL, NON_BLOCKING_IO) == -1)
- errstr = "Can't set up non-blocking IO";
-
- if(prepend && (fputs(prepend, fpipe->out.f) == EOF
- || fputc('\n', fpipe->out.f) == EOF))
- errstr = error_description(errno);
-
- while(!errstr){
- /* if the pipe can't hold a K we're sunk (too bad PIPE_MAX
- * isn't ubiquitous ;).
- */
- for(n = 0; !errstr && fpipe->out.f && n < 1024; n++)
- if(!so_readc(&c, source_so)){
- fclose(fpipe->out.f);
- fpipe->out.f = NULL;
- }
- else if(fputc(c, fpipe->out.f) == EOF)
- errstr = error_description(errno);
-
- /*
- * Note: We clear errno here and test below, before ferror,
- * because *some* stdio implementations consider
- * EAGAIN and EWOULDBLOCK equivalent to EOF...
- */
- errno = 0;
- clearerr(fpipe->in.f); /* fix from <cananian@cananian.mit.edu> */
-
- while(!errstr && fgets(buf, MAILTMPLEN, fpipe->in.f))
- errstr = gf_filter_puts(buf);
-
- /* then fgets failed! */
- if(!errstr && !(errno == EAGAIN || errno == EWOULDBLOCK)){
- if(feof(fpipe->in.f)) /* nothing else interesting! */
- break;
- else if(ferror(fpipe->in.f)) /* bummer. */
- errstr = error_description(errno);
- }
- else if(errno == EAGAIN || errno == EWOULDBLOCK)
- clearerr(fpipe->in.f);
- }
-#else
- if(prepend && (fputs(prepend, fpipe->out.f) == EOF
- || fputc('\n', fpipe->out.f) == EOF))
- errstr = error_description(errno);
-
- /*
- * Well, do the best we can, and hope the pipe we're writing
- * doesn't fill up before we start reading...
- */
- while(!errstr && so_readc(&c, source_so))
- if(fputc(c, fpipe->out.f) == EOF)
- errstr = error_description(errno);
-
- fclose(fpipe->out.f);
- fpipe->out.f = NULL;
- while(!errstr && fgets(buf, MAILTMPLEN, fpipe->in.f))
- errstr = gf_filter_puts(buf);
-#endif /* NON_BLOCKING */
-#endif /* NO_PIPE */
-
- gf_filter_eod();
-
- if(close_system_pipe(&fpipe) && !errstr)
- errstr = "Pipe command returned error.";
-
-#ifdef NO_PIPE
- /*
- * retrieve filters result...
- */
- {
- FILE *fp;
-
- if(fp = fopen(rfile, STDIO_READ)){
- while(!errstr && fgets(buf, MAILTMPLEN, fp))
- errstr = gf_filter_puts(buf);
-
- fclose(fp);
- }
-
- fs_give((void **)&rfile);
- }
-#endif
- }
-
- return(errstr);
-}
-
-
-/*
- * gf_filter_puts - write the given string down the filter's pipe
- */
-char *
-gf_filter_puts(s)
- register char *s;
-{
- GF_INIT(gf_master, gf_master);
-
- /*
- * set up for any errors a filter may encounter
- */
- if(setjmp(gf_error_state)){
- dprint(4, (debugfile, "ERROR: gf_filter_puts: %s\n",
- gf_error_string ? gf_error_string : "NULL"));
- return(gf_error_string);
- }
-
- while(*s)
- GF_PUTC(gf_master, (*s++) & 0xff);
-
- GF_END(gf_master, gf_master);
- return(NULL);
-}
-
-
-/*
- * gf_filter_eod - flush pending data filter's input queue and deliver
- * the GF_EOD marker.
- */
-void
-gf_filter_eod()
-{
- GF_INIT(gf_master, gf_master);
- GF_FLUSH(gf_master);
- (*gf_master->f)(gf_master, GF_EOD);
-}
-
-
-
-
-/*
- * END OF PIPE SUPPORT ROUTINES, BEGINNING OF FILTERS
- *
- * Filters MUST use the specified interface (pointer to filter
- * structure, the unsigned character buffer in that struct, and a
- * cmd flag), and pass each resulting octet to the next filter in the
- * chain. Only the terminal filter need not call another filter.
- * As a result, filters share a pretty general structure.
- * Typically three main conditionals separate initialization from
- * data from end-of-data command processing.
- *
- * Lastly, being character-at-a-time, they're a little more complex
- * to write than filters operating on buffers because some state
- * must typically be kept between characters. However, for a
- * little bit of complexity here, much convenience is gained later
- * as they can be arbitrarily chained together at run time and
- * consume few resources (especially memory or disk) as they work.
- * (NOTE 951005: even less cpu now that data between filters is passed
- * via a vector.)
- *
- * A few notes about implementing filters:
- *
- * - A generic filter template looks like:
- *
- * void
- * gf_xxx_filter(f, flg)
- * FILTER_S *f;
- * int flg;
- * {
- * GF_INIT(f, f->next); // def's var's to speed queue drain
- *
- * if(flg == GF_DATA){
- * register unsigned char c;
- *
- * while(GF_GETC(f, c)){ // macro taking data off input queue
- * // operate on c and pass it on here
- * GF_PUTC(f->next, c); // macro writing output queue
- * }
- *
- * GF_END(f, f->next); // macro to sync pointers/offsets
- * //WARNING: DO NOT RETURN BEFORE ALL INCOMING DATA'S PROCESSED
- * }
- * else if(flg == GF_EOD){
- * // process any buffered data here and pass it on
- * GF_FLUSH(f->next); // flush pending data to next filter
- * (*f->next->f)(f->next, GF_EOD);
- * }
- * else if(flg == GF_RESET){
- * // initialize any data in the struct here
- * }
- * }
- *
- * - Any free storage allocated during initialization (typically tied
- * to the "line" pointer in FILTER_S) is the filter's responsibility
- * to clean up when the GF_EOD command comes through.
- *
- * - Filter's must pass GF_EOD they receive on to the next
- * filter in the chain so it has the opportunity to flush
- * any buffered data.
- *
- * - All filters expect NVT end-of-lines. The idea is to prepend
- * or append either the gf_local_nvtnl or gf_nvtnl_local
- * os-dependant filters to the data on the appropriate end of the
- * pipe for the task at hand.
- *
- * - NOTE: As of 951004, filters no longer take their input as a single
- * char argument, but rather get data to operate on via a vector
- * representing the input queue in the FILTER_S structure.
- *
- */
-
-
-
-/*
- * BASE64 TO BINARY encoding and decoding routines below
- */
-
-
-/*
- * BINARY to BASE64 filter (encoding described in rfc1341)
- */
-void
-gf_binary_b64(f, flg)
- FILTER_S *f;
- int flg;
-{
- static char *v =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register unsigned char t = f->t;
- register long n = f->n;
-
- while(GF_GETC(f, c)){
-
- switch(n++){
- case 0 : case 3 : case 6 : case 9 : case 12: case 15: case 18:
- case 21: case 24: case 27: case 30: case 33: case 36: case 39:
- case 42: case 45:
- GF_PUTC(f->next, v[c >> 2]);
- /* byte 1: high 6 bits (1) */
- t = c << 4; /* remember high 2 bits for next */
- break;
-
- case 1 : case 4 : case 7 : case 10: case 13: case 16: case 19:
- case 22: case 25: case 28: case 31: case 34: case 37: case 40:
- case 43:
- GF_PUTC(f->next, v[(t|(c>>4)) & 0x3f]);
- t = c << 2;
- break;
-
- case 2 : case 5 : case 8 : case 11: case 14: case 17: case 20:
- case 23: case 26: case 29: case 32: case 35: case 38: case 41:
- case 44:
- GF_PUTC(f->next, v[(t|(c >> 6)) & 0x3f]);
- GF_PUTC(f->next, v[c & 0x3f]);
- break;
- }
-
- if(n == 45){ /* start a new line? */
- GF_PUTC(f->next, '\015');
- GF_PUTC(f->next, '\012');
- n = 0L;
- }
- }
-
- f->n = n;
- f->t = t;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){ /* no more data */
- switch (f->n % 3) { /* handle trailing bytes */
- case 0: /* no trailing bytes */
- break;
-
- case 1:
- GF_PUTC(f->next, v[(f->t) & 0x3f]);
- GF_PUTC(f->next, '='); /* byte 3 */
- GF_PUTC(f->next, '='); /* byte 4 */
- break;
-
- case 2:
- GF_PUTC(f->next, v[(f->t) & 0x3f]);
- GF_PUTC(f->next, '='); /* byte 4 */
- break;
- }
-
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset binary_b64\n"));
- f->n = 0L;
- }
-}
-
-
-
-/*
- * BASE64 to BINARY filter (encoding described in rfc1341)
- */
-void
-gf_b64_binary(f, flg)
- FILTER_S *f;
- int flg;
-{
- static char v[] = {65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
- 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
- 65,65,65,65,65,65,65,65,65,65,65,62,65,65,65,63,
- 52,53,54,55,56,57,58,59,60,61,62,65,65,64,65,65,
- 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
- 15,16,17,18,19,20,21,22,23,24,25,65,65,65,65,65,
- 65,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
- 41,42,43,44,45,46,47,48,49,50,51,65,65,65,65,65};
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register unsigned char t = f->t;
- register int n = (int) f->n;
- register int state = f->f1;
-
- while(GF_GETC(f, c)){
-
- if(state){
- state = 0;
- if (c != '=') {
- gf_error("Illegal '=' in base64 text");
- /* NO RETURN */
- }
- }
-
- /* in range, and a valid value? */
- if((c & ~0x7f) || (c = v[c]) > 63){
- if(c == 64){
- switch (n++) { /* check quantum position */
- case 2:
- state++; /* expect an equal as next char */
- break;
-
- case 3:
- n = 0L; /* restart quantum */
- break;
-
- default: /* impossible quantum position */
- gf_error("Internal base64 decoder error");
- /* NO RETURN */
- }
- }
- }
- else{
- switch (n++) { /* install based on quantum position */
- case 0: /* byte 1: high 6 bits */
- t = c << 2;
- break;
-
- case 1: /* byte 1: low 2 bits */
- GF_PUTC(f->next, (t|(c >> 4)));
- t = c << 4; /* byte 2: high 4 bits */
- break;
-
- case 2: /* byte 2: low 4 bits */
- GF_PUTC(f->next, (t|(c >> 2)));
- t = c << 6; /* byte 3: high 2 bits */
- break;
-
- case 3:
- GF_PUTC(f->next, t | c);
- n = 0L; /* reinitialize mechanism */
- break;
- }
- }
- }
-
- f->f1 = state;
- f->t = t;
- f->n = n;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset b64_binary\n"));
- f->n = 0L; /* quantum position */
- f->f1 = 0; /* state holder: equal seen? */
- }
-}
-
-
-
-
-/*
- * QUOTED-PRINTABLE ENCODING AND DECODING filters below.
- * encoding described in rfc1341
- */
-
-#define GF_MAXLINE 80 /* good buffer size */
-
-/*
- * default action for QUOTED-PRINTABLE to 8BIT decoder
- */
-#define GF_QP_DEFAULT(f, c) { \
- if((c) == ' '){ \
- state = WSPACE; \
- /* reset white space! */ \
- (f)->linep = (f)->line; \
- *((f)->linep)++ = ' '; \
- } \
- else if((c) == '='){ \
- state = EQUAL; \
- } \
- else \
- GF_PUTC((f)->next, (c)); \
- }
-
-
-/*
- * QUOTED-PRINTABLE to 8BIT filter
- */
-void
-gf_qp_8bit(f, flg)
- FILTER_S *f;
- int flg;
-{
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register int state = f->f1;
-
- while(GF_GETC(f, c)){
-
- switch(state){
- case DFL : /* default case */
- default:
- GF_QP_DEFAULT(f, c);
- break;
-
- case CCR : /* non-significant space */
- state = DFL;
- if(c == '\012')
- continue; /* go on to next char */
-
- GF_QP_DEFAULT(f, c);
- break;
-
- case EQUAL :
- if(c == '\015'){ /* "=\015" is a soft EOL */
- state = CCR;
- break;
- }
-
- if(c == '='){ /* compatibility clause for old guys */
- GF_PUTC(f->next, '=');
- state = DFL;
- break;
- }
-
- if(!isxdigit((unsigned char)c)){ /* must be hex! */
- fs_give((void **)&(f->line));
- gf_error("Non-hexadecimal character in QP encoding");
- /* NO RETURN */
- }
-
- if (isdigit ((unsigned char)c))
- f->t = c - '0';
- else
- f->t = c - (isupper((unsigned char)c) ? 'A' - 10 : 'a' - 10);
-
- state = HEX;
- break;
-
- case HEX :
- state = DFL;
- if(!isxdigit((unsigned char)c)){ /* must be hex! */
- fs_give((void **)&(f->line));
- gf_error("Non-hexadecimal character in QP encoding");
- /* NO RETURN */
- }
-
- if (isdigit((unsigned char)c))
- c -= '0';
- else
- c -= (isupper((unsigned char)c) ? 'A' - 10 : 'a' - 10);
-
- GF_PUTC(f->next, c + (f->t << 4));
- break;
-
- case WSPACE :
- if(c == ' '){ /* toss it in with other spaces */
- if(f->linep - f->line < GF_MAXLINE)
- *(f->linep)++ = ' ';
- break;
- }
-
- state = DFL;
- if(c == '\015'){ /* not our white space! */
- f->linep = f->line; /* reset buffer */
- GF_PUTC(f->next, '\015');
- break;
- }
-
- /* the spaces are ours, write 'em */
- f->n = f->linep - f->line;
- while((f->n)--)
- GF_PUTC(f->next, ' ');
-
- GF_QP_DEFAULT(f, c); /* take care of 'c' in default way */
- break;
- }
- }
-
- f->f1 = state;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- fs_give((void **)&(f->line));
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset qp_8bit\n"));
- f->f1 = DFL;
- f->linep = f->line = (char *)fs_get(GF_MAXLINE * sizeof(char));
- }
-}
-
-
-
-/*
- * USEFUL MACROS TO HELP WITH QP ENCODING
- */
-
-#define QP_MAXL 75 /* 76th place only for continuation */
-
-/*
- * Macro to test and wrap long quoted printable lines
- */
-#define GF_8BIT_WRAP(f) { \
- GF_PUTC((f)->next, '='); \
- GF_PUTC((f)->next, '\015'); \
- GF_PUTC((f)->next, '\012'); \
- }
-
-/*
- * write a quoted octet in QUOTED-PRINTABLE encoding, adding soft
- * line break if needed.
- */
-#define GF_8BIT_PUT_QUOTE(f, c) { \
- if(((f)->n += 3) > QP_MAXL){ \
- GF_8BIT_WRAP(f); \
- (f)->n = 3; /* set line count */ \
- } \
- GF_PUTC((f)->next, '='); \
- GF_PUTC((f)->next, HEX_CHAR1(c)); \
- GF_PUTC((f)->next, HEX_CHAR2(c)); \
- }
-
-/*
- * just write an ordinary octet in QUOTED-PRINTABLE, wrapping line
- * if needed.
- */
-#define GF_8BIT_PUT(f, c) { \
- if((++(f->n)) > QP_MAXL){ \
- GF_8BIT_WRAP(f); \
- f->n = 1L; \
- } \
- if(f->n == 1L && c == '.'){ \
- GF_8BIT_PUT_QUOTE(f, c); \
- f->n = 3; \
- } \
- else \
- GF_PUTC(f->next, c); \
- }
-
-
-/*
- * default action for 8bit to quoted printable encoder
- */
-#define GF_8BIT_DEFAULT(f, c) if((c) == ' '){ \
- state = WSPACE; \
- } \
- else if(c == '\015'){ \
- state = CCR; \
- } \
- else if(iscntrl(c & 0x7f) || (c == 0x7f) \
- || (c & 0x80) || (c == '=')){ \
- GF_8BIT_PUT_QUOTE(f, c); \
- } \
- else{ \
- GF_8BIT_PUT(f, c); \
- }
-
-
-/*
- * 8BIT to QUOTED-PRINTABLE filter
- */
-void
-gf_8bit_qp(f, flg)
- FILTER_S *f;
- int flg;
-{
- short dummy_dots = 0, dummy_dmap = 1;
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register int state = f->f1;
-
- while(GF_GETC(f, c)){
-
- /* keep track of "^JFrom " */
- Find_Froms(f->t, dummy_dots, f->f2, dummy_dmap, c);
-
- switch(state){
- case DFL : /* handle ordinary case */
- GF_8BIT_DEFAULT(f, c);
- break;
-
- case CCR : /* true line break? */
- state = DFL;
- if(c == '\012'){
- GF_PUTC(f->next, '\015');
- GF_PUTC(f->next, '\012');
- f->n = 0L;
- }
- else{ /* nope, quote the CR */
- GF_8BIT_PUT_QUOTE(f, '\015');
- GF_8BIT_DEFAULT(f, c); /* and don't forget about c! */
- }
- break;
-
- case WSPACE:
- state = DFL;
- if(c == '\015' || f->t){ /* handle the space */
- GF_8BIT_PUT_QUOTE(f, ' ');
- f->t = 0; /* reset From flag */
- }
- else
- GF_8BIT_PUT(f, ' ');
-
- GF_8BIT_DEFAULT(f, c); /* handle 'c' in the default way */
- break;
- }
- }
-
- f->f1 = state;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- switch(f->f1){
- case CCR :
- GF_8BIT_PUT_QUOTE(f, '\015'); /* write the last cr */
- break;
-
- case WSPACE :
- GF_8BIT_PUT_QUOTE(f, ' '); /* write the last space */
- break;
- }
-
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset 8bit_qp\n"));
- f->f1 = DFL; /* state from last character */
- f->f2 = 1; /* state of "^NFrom " bitmap */
- f->t = 0;
- f->n = 0L; /* number of chars in current line */
- }
-}
-
-
-
-/*
- * RICHTEXT-TO-PLAINTEXT filter
- */
-
-/*
- * option to be used by rich2plain (NOTE: if this filter is ever
- * used more than once in a pipe, all instances will have the same
- * option value)
- */
-
-
-/*----------------------------------------------------------------------
- richtext to plaintext filter
-
- Args: f --
- flg --
-
- This basically removes all richtext formatting. A cute hack is used
- to get bold and underlining to work.
- Further work could be done to handle things like centering and right
- and left flush, but then it could no longer be done in place. This
- operates on text *with* CRLF's.
-
- WARNING: does not wrap lines!
- ----*/
-void
-gf_rich2plain(f, flg)
- FILTER_S *f;
- int flg;
-{
-/* BUG: qoute incoming \255 values */
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register int state = f->f1;
-
- while(GF_GETC(f, c)){
-
- switch(state){
- case TOKEN : /* collect a richtext token */
- if(c == '>'){ /* what should we do with it? */
- state = DFL; /* return to default next time */
- *(f->linep) = '\0'; /* cap off token */
- if(f->line[0] == 'l' && f->line[1] == 't'){
- GF_PUTC(f->next, '<'); /* literal '<' */
- }
- else if(f->line[0] == 'n' && f->line[1] == 'l'){
- GF_PUTC(f->next, '\015');/* newline! */
- GF_PUTC(f->next, '\012');
- }
- else if(!strcmp("comment", f->line)){
- (f->f2)++;
- }
- else if(!strcmp("/comment", f->line)){
- f->f2 = 0;
- }
- else if(!strcmp("/paragraph", f->line)) {
- GF_PUTC(f->next, '\r');
- GF_PUTC(f->next, '\n');
- GF_PUTC(f->next, '\r');
- GF_PUTC(f->next, '\n');
- }
- else if(!f->opt /* gf_rich_plain */){
- if(!strcmp(f->line, "bold")) {
- GF_PUTC(f->next, TAG_EMBED);
- GF_PUTC(f->next, TAG_BOLDON);
- } else if(!strcmp(f->line, "/bold")) {
- GF_PUTC(f->next, TAG_EMBED);
- GF_PUTC(f->next, TAG_BOLDOFF);
- } else if(!strcmp(f->line, "italic")) {
- GF_PUTC(f->next, TAG_EMBED);
- GF_PUTC(f->next, TAG_ULINEON);
- } else if(!strcmp(f->line, "/italic")) {
- GF_PUTC(f->next, TAG_EMBED);
- GF_PUTC(f->next, TAG_ULINEOFF);
- } else if(!strcmp(f->line, "underline")) {
- GF_PUTC(f->next, TAG_EMBED);
- GF_PUTC(f->next, TAG_ULINEON);
- } else if(!strcmp(f->line, "/underline")) {
- GF_PUTC(f->next, TAG_EMBED);
- GF_PUTC(f->next, TAG_ULINEOFF);
- }
- }
- /* else we just ignore the token! */
-
- f->linep = f->line; /* reset token buffer */
- }
- else{ /* add char to token */
- if(f->linep - f->line > 40){
- /* What? rfc1341 says 40 char tokens MAX! */
- fs_give((void **)&(f->line));
- gf_error("Richtext token over 40 characters");
- /* NO RETURN */
- }
-
- *(f->linep)++ = isupper((unsigned char)c) ? c-'A'+'a' : c;
- }
- break;
-
- case CCR :
- state = DFL; /* back to default next time */
- if(c == '\012'){ /* treat as single space? */
- GF_PUTC(f->next, ' ');
- break;
- }
- /* fall thru to process c */
-
- case DFL :
- default:
- if(c == '<')
- state = TOKEN;
- else if(c == '\015')
- state = CCR;
- else if(!f->f2) /* not in comment! */
- GF_PUTC(f->next, c);
-
- break;
- }
- }
-
- f->f1 = state;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- if(f->f1 = (f->linep != f->line)){
- /* incomplete token!! */
- gf_error("Incomplete token in richtext");
- /* NO RETURN */
- }
-
- fs_give((void **)&(f->line));
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset rich2plain\n"));
- f->f1 = DFL; /* state */
- f->f2 = 0; /* set means we're in a comment */
- f->linep = f->line = (char *)fs_get(45 * sizeof(char));
- }
-}
-
-
-/*
- * function called from the outside to set
- * richtext filter's options
- */
-void *
-gf_rich2plain_opt(plain)
- int plain;
-{
- return((void *) plain);
-}
-
-
-
-/*
- * ENRICHED-TO-PLAIN text filter
- */
-
-#define TEF_QUELL 0x01
-#define TEF_NOFILL 0x02
-
-
-
-/*----------------------------------------------------------------------
- enriched text to plain text filter (ala rfc1523)
-
- Args: f -- state and input data
- flg --
-
- This basically removes all enriched formatting. A cute hack is used
- to get bold and underlining to work.
-
- Further work could be done to handle things like centering and right
- and left flush, but then it could no longer be done in place. This
- operates on text *with* CRLF's.
-
- WARNING: does not wrap lines!
- ----*/
-void
-gf_enriched2plain(f, flg)
- FILTER_S *f;
- int flg;
-{
-/* BUG: qoute incoming \255 values */
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register int state = f->f1;
-
- while(GF_GETC(f, c)){
-
- switch(state){
- case TOKEN : /* collect a richtext token */
- if(c == '>'){ /* what should we do with it? */
- int off = *f->line == '/';
- char *token = f->line + (off ? 1 : 0);
- state = DFL;
- *f->linep = '\0';
- if(!strcmp("param", token)){
- if(off)
- f->f2 &= ~TEF_QUELL;
- else
- f->f2 |= TEF_QUELL;
- }
- else if(!strcmp("nofill", token)){
- if(off)
- f->f2 &= ~TEF_NOFILL;
- else
- f->f2 |= TEF_NOFILL;
- }
- else if(!f->opt /* gf_enriched_plain */){
- /* Following is a cute hack or two to get
- bold and underline on the screen.
- See Putline0n() where these codes are
- interpreted */
- if(!strcmp("bold", token)) {
- GF_PUTC(f->next, TAG_EMBED);
- GF_PUTC(f->next, off ? TAG_BOLDOFF : TAG_BOLDON);
- } else if(!strcmp("italic", token)) {
- GF_PUTC(f->next, TAG_EMBED);
- GF_PUTC(f->next, off ? TAG_ULINEOFF : TAG_ULINEON);
- } else if(!strcmp("underline", token)) {
- GF_PUTC(f->next, TAG_EMBED);
- GF_PUTC(f->next, off ? TAG_ULINEOFF : TAG_ULINEON);
- }
- }
- /* else we just ignore the token! */
-
- f->linep = f->line; /* reset token buffer */
- }
- else if(c == '<'){ /* literal '<'? */
- if(f->linep == f->line){
- GF_PUTC(f->next, '<');
- state = DFL;
- }
- else{
- fs_give((void **)&(f->line));
- gf_error("Malformed Enriched text: unexpected '<'");
- /* NO RETURN */
- }
- }
- else{ /* add char to token */
- if(f->linep - f->line > 60){ /* rfc1523 says 60 MAX! */
- fs_give((void **)&(f->line));
- gf_error("Malformed Enriched text: token too long");
- /* NO RETURN */
- }
-
- *(f->linep)++ = isupper((unsigned char)c) ? c-'A'+'a' : c;
- }
- break;
-
- case CCR :
- if(c != '\012'){ /* treat as single space? */
- state = DFL; /* lone cr? */
- f->f2 &= ~TEF_QUELL;
- GF_PUTC(f->next, '\015');
- goto df;
- }
-
- state = CLF;
- break;
-
- case CLF :
- if(c == '\015'){ /* treat as single space? */
- state = CCR; /* repeat crlf's mean real newlines */
- f->f2 |= TEF_QUELL;
- GF_PUTC(f->next, '\r');
- GF_PUTC(f->next, '\n');
- break;
- }
- else{
- state = DFL;
- if(!((f->f2) & TEF_QUELL))
- GF_PUTC(f->next, ' ');
-
- f->f2 &= ~TEF_QUELL;
- }
-
- /* fall thru to take care of 'c' */
-
- case DFL :
- default :
- df :
- if(c == '<')
- state = TOKEN;
- else if(c == '\015' && (!((f->f2) & TEF_NOFILL)))
- state = CCR;
- else if(!((f->f2) & TEF_QUELL))
- GF_PUTC(f->next, c);
-
- break;
- }
- }
-
- f->f1 = state;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- if(f->f1 = (f->linep != f->line)){
- /* incomplete token!! */
- gf_error("Incomplete token in richtext");
- /* NO RETURN */
- }
-
- /* Make sure we end with a newline so everything gets flushed */
- GF_PUTC(f->next, '\015');
- GF_PUTC(f->next, '\012');
-
- fs_give((void **)&(f->line));
-
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset enriched2plain\n"));
- f->f1 = DFL; /* state */
- f->f2 = 0; /* set means we're in a comment */
- f->linep = f->line = (char *)fs_get(65 * sizeof(char));
- }
-}
-
-
-/*
- * function called from the outside to set
- * richtext filter's options
- */
-void *
-gf_enriched2plain_opt(plain)
- int plain;
-{
- return((void *) plain);
-}
-
-
-
-/*
- * HTML-TO-PLAIN text filter
- */
-
-
-/* OK, here's the plan:
-
- * a universal output function handles writing chars and worries
- * about wrapping.
-
- * a unversal element collector reads chars and collects params
- * and dispatches the appropriate element handler.
-
- * element handlers are stacked. The most recently dispatched gets
- * first crack at the incoming character stream. It passes bytes it's
- * done with or not interested in to the next
-
- * installs that handler as the current one collecting data...
-
- * stacked handlers take their params from the element collector and
- * accept chars or do whatever they need to do. Sort of a vertical
- * piping? recursion-like? hmmm.
-
- * at least I think this is how it'll work. tres simple, non?
-
- */
-
-
-/*
- * Some important constants
- */
-#define HTML_BUF_LEN 1024 /* max scratch buffer length */
-#define MAX_ENTITY 20 /* maximum length of an entity */
-#define MAX_ELEMENT 72 /* maximum length of an element */
-#define HTML_BADVALUE 0x0100 /* good data, but bad entity value */
-#define HTML_BADDATA 0x0200 /* bad data found looking for entity */
-#define HTML_LITERAL 0x0400 /* Literal character value */
-#define HTML_NEWLINE 0x010A /* hard newline */
-#define HTML_DOBOLD 0x0400 /* Start Bold display */
-#define HTML_ID_GET 0 /* indent func: return current val */
-#define HTML_ID_SET 1 /* indent func: set to absolute val */
-#define HTML_ID_INC 2 /* indent func: increment by val */
-#define HTML_HX_CENTER 0x0001
-#define HTML_HX_ULINE 0x0002
-
-
-/*
- * Types used to manage HTML parsing
- */
-typedef int (*html_f) PROTO(());
-
-/*
- * Handler data, state information including function that uses it
- */
-typedef struct handler_s {
- FILTER_S *html_data;
- struct handler_s *below;
- html_f f;
- long x, y, z;
- unsigned char *s;
-} HANDLER_S;
-
-
-/*
- * to help manage line wrapping.
- */
-typedef struct _wrap_line {
- char *buf; /* buf to collect wrapped text */
- int used, /* number of chars in buf */
- width, /* text's width as displayed */
- len; /* length of allocated buf */
-} WRAPLINE_S;
-
-
-/*
- * to help manage centered text
- */
-typedef struct _center_s {
- WRAPLINE_S line; /* buf to assembled centered text */
- WRAPLINE_S word; /* word being to append to Line */
- int anchor;
- short embedded;
- short space;
-} CENTER_S;
-
-
-/*
- * Collector data and state information
- */
-typedef struct collector_s {
- char buf[HTML_BUF_LEN]; /* buffer to collect data */
- int len; /* length of that buffer */
- unsigned end_tag:1; /* collecting a closing tag */
- unsigned hit_equal:1; /* collecting right half of attrib */
- unsigned mkup_decl:1; /* markup declaration */
- unsigned start_comment:1; /* markup declaration comment */
- unsigned end_comment:1; /* legit comment format */
- unsigned hyphen:1; /* markup hyphen read */
- unsigned badform:1; /* malformed markup element */
- unsigned overrun:1; /* Overran buf above */
- char quoted; /* quoted element param value */
- char *element; /* element's collected name */
- PARAMETER *attribs; /* element's collected attributes */
- PARAMETER *cur_attrib; /* attribute now being collected */
-} CLCTR_S;
-
-
-/*
- * State information for all element handlers
- */
-typedef struct html_data {
- HANDLER_S *h_stack; /* handler list */
- CLCTR_S *el_data; /* element collector data */
- CENTER_S *centered; /* struct to manage centered text */
- int (*token) PROTO((FILTER_S *, int));
- char quoted; /* quoted, by either ' or ", text */
- short indent_level; /* levels of indention */
- int in_anchor; /* text now being written to anchor */
- int blanks; /* Consecutive blank line count */
- int wrapcol; /* column to wrap lines on */
- int *prefix; /* buffer containing Anchor prefix */
- int prefix_used;
- COLOR_PAIR *color;
- unsigned wrapstate:1; /* whether or not to wrap output */
- unsigned li_pending:1; /* <LI> next token expected */
- unsigned de_pending:1; /* <DT> or <DD> next token expected */
- unsigned bold_on:1; /* currently bolding text */
- unsigned uline_on:1; /* currently underlining text */
- unsigned center:1; /* center output text */
- unsigned bitbucket:1; /* Ignore input */
- unsigned head:1; /* In doc's HEAD */
- unsigned alt_entity:1; /* use alternative entity values */
-} HTML_DATA_S;
-
-
-/*
- * HTML filter options
- */
-typedef struct _html_opts {
- char *base; /* Base URL for this html file */
- int columns; /* Display columns */
- unsigned strip:1; /* Hilite TAGs allowed */
- unsigned handles:1; /* Anchors as handles requested? */
- unsigned handles_loc:1; /* Local handles requested? */
-} HTML_OPT_S;
-
-
-/*
- * Some macros to make life a little easier
- */
-#define WRAP_COLS(X) ((X)->opt ? ((HTML_OPT_S *)(X)->opt)->columns : 80)
-#define HTML_BASE(X) ((X)->opt ? ((HTML_OPT_S *)(X)->opt)->base : NULL)
-#define STRIP(X) ((X)->opt && ((HTML_OPT_S *)(X)->opt)->strip)
-#define HANDLES(X) ((X)->opt && ((HTML_OPT_S *)(X)->opt)->handles)
-#define HANDLES_LOC(X) ((X)->opt && ((HTML_OPT_S *)(X)->opt)->handles_loc)
-#define MAKE_LITERAL(C) (HTML_LITERAL | ((C) & 0xff))
-#define IS_LITERAL(C) (HTML_LITERAL & (C))
-#define HD(X) ((HTML_DATA_S *)(X)->data)
-#define ED(X) (HD(X)->el_data)
-#define HTML_ISSPACE(C) (IS_LITERAL(C) == 0 && isspace((unsigned char) (C)))
-#define NEW_CLCTR(X) { \
- ED(X) = (CLCTR_S *)fs_get(sizeof(CLCTR_S)); \
- memset(ED(X), 0, sizeof(CLCTR_S)); \
- HD(X)->token = html_element_collector; \
- }
-
-#define FREE_CLCTR(X) { \
- if(ED(X)->attribs){ \
- PARAMETER *p; \
- while(p = ED(X)->attribs){ \
- ED(X)->attribs = ED(X)->attribs->next; \
- if(p->attribute) \
- fs_give((void **)&p->attribute); \
- if(p->value) \
- fs_give((void **)&p->value); \
- fs_give((void **)&p); \
- } \
- } \
- if(ED(X)->element) \
- fs_give((void **) &ED(X)->element); \
- fs_give((void **) &ED(X)); \
- HD(X)->token = NULL; \
- }
-#define HANDLERS(X) (HD(X)->h_stack)
-#define BOLD_BIT(X) (HD(X)->bold_on)
-#define ULINE_BIT(X) (HD(X)->uline_on)
-#define CENTER_BIT(X) (HD(X)->center)
-#define HTML_FLUSH(X) { \
- html_write(X, (X)->line, (X)->linep - (X)->line); \
- (X)->linep = (X)->line; \
- (X)->f2 = 0L; \
- }
-#define HTML_BOLD(X, S) if(! STRIP(X)){ \
- if(S){ \
- html_output((X), TAG_EMBED); \
- html_output((X), TAG_BOLDON); \
- } \
- else if(!(S)){ \
- html_output((X), TAG_EMBED); \
- html_output((X), TAG_BOLDOFF); \
- } \
- }
-#define HTML_ULINE(X, S) \
- if(! STRIP(X)){ \
- if(S){ \
- html_output((X), TAG_EMBED); \
- html_output((X), TAG_ULINEON); \
- } \
- else if(!(S)){ \
- html_output((X), TAG_EMBED); \
- html_output((X), TAG_ULINEOFF); \
- } \
- }
-#define WRAPPED_LEN(X) ((HD(f)->centered) \
- ? (HD(f)->centered->line.width \
- + HD(f)->centered->word.width \
- + ((HD(f)->centered->line.width \
- && HD(f)->centered->word.width) \
- ? 1 : 0)) \
- : 0)
-#define HTML_DUMP_LIT(F, S, L) { \
- int i, c; \
- for(i = 0; i < (L); i++){ \
- c = isspace((S)[i]) \
- ? (S)[i] \
- : MAKE_LITERAL((S)[i]); \
- HTML_TEXT(F, c); \
- } \
- }
-#define HTML_PROC(F, C) { \
- if(HD(F)->token){ \
- int i; \
- if(i = (*(HD(F)->token))(F, C)){ \
- if(i < 0){ \
- HTML_DUMP_LIT(F, "<", 1); \
- if(HD(F)->el_data->element){ \
- HTML_DUMP_LIT(F, \
- HD(F)->el_data->element, \
- strlen(HD(F)->el_data->element));\
- } \
- if(HD(F)->el_data->len){ \
- HTML_DUMP_LIT(F, \
- HD(F)->el_data->buf, \
- HD(F)->el_data->len); \
- } \
- HTML_TEXT(F, C); \
- } \
- FREE_CLCTR(F); \
- } \
- } \
- else if((C) == '<'){ \
- NEW_CLCTR(F); \
- } \
- else \
- HTML_TEXT(F, C); \
- }
-#define HTML_TEXT(F, C) switch((F)->f1){ \
- case WSPACE : \
- if(HTML_ISSPACE(C)) /* ignore repeated WS */ \
- break; \
- HTML_TEXT_OUT(F, ' '); \
- (F)->f1 = DFL;/* stop sending chars here */ \
- /* fall thru to process 'c' */ \
- case DFL: \
- if(HD(F)->bitbucket) \
- (F)->f1 = DFL; /* no op */ \
- else if(HTML_ISSPACE(C) && HD(F)->wrapstate) \
- (F)->f1 = WSPACE;/* coalesce white space */ \
- else HTML_TEXT_OUT(F, C); \
- break; \
- }
-#define HTML_TEXT_OUT(F, C) if(HANDLERS(F)) /* let handlers see C */ \
- (*HANDLERS(F)->f)(HANDLERS(F),(C),GF_DATA); \
- else \
- html_output(F, C);
-#ifdef DEBUG
-#define HTML_DEBUG_EL(S, D) { \
- dprint(2, (debugfile, "-- html %s: %s\n", \
- S, (D)->element \
- ? (D)->element : "NULL")); \
- if(debug > 5){ \
- PARAMETER *p; \
- for(p = (D)->attribs; \
- p && p->attribute; \
- p = p->next) \
- dprint(6, (debugfile, \
- " PARM: %s%s%s\n", \
- p->attribute \
- ? p->attribute : "NULL",\
- p->value ? "=" : "", \
- p->value ? p->value : ""));\
- } \
- }
-#else
-#define HTML_DEBUG_EL(S, D)
-#endif
-
-
-/*
- * Protos for Tag handlers
- */
-int html_head PROTO((HANDLER_S *, int, int));
-int html_base PROTO((HANDLER_S *, int, int));
-int html_title PROTO((HANDLER_S *, int, int));
-int html_a PROTO((HANDLER_S *, int, int));
-int html_br PROTO((HANDLER_S *, int, int));
-int html_hr PROTO((HANDLER_S *, int, int));
-int html_p PROTO((HANDLER_S *, int, int));
-int html_tr PROTO((HANDLER_S *, int, int));
-int html_td PROTO((HANDLER_S *, int, int));
-int html_b PROTO((HANDLER_S *, int, int));
-int html_i PROTO((HANDLER_S *, int, int));
-int html_img PROTO((HANDLER_S *, int, int));
-int html_form PROTO((HANDLER_S *, int, int));
-int html_ul PROTO((HANDLER_S *, int, int));
-int html_ol PROTO((HANDLER_S *, int, int));
-int html_menu PROTO((HANDLER_S *, int, int));
-int html_dir PROTO((HANDLER_S *, int, int));
-int html_li PROTO((HANDLER_S *, int, int));
-int html_h1 PROTO((HANDLER_S *, int, int));
-int html_h2 PROTO((HANDLER_S *, int, int));
-int html_h3 PROTO((HANDLER_S *, int, int));
-int html_h4 PROTO((HANDLER_S *, int, int));
-int html_h5 PROTO((HANDLER_S *, int, int));
-int html_h6 PROTO((HANDLER_S *, int, int));
-int html_blockquote PROTO((HANDLER_S *, int, int));
-int html_address PROTO((HANDLER_S *, int, int));
-int html_pre PROTO((HANDLER_S *, int, int));
-int html_center PROTO((HANDLER_S *, int, int));
-int html_div PROTO((HANDLER_S *, int, int));
-int html_dl PROTO((HANDLER_S *, int, int));
-int html_dt PROTO((HANDLER_S *, int, int));
-int html_dd PROTO((HANDLER_S *, int, int));
-
-/*
- * Proto's for support routines
- */
-void html_pop PROTO((FILTER_S *, html_f));
-void html_push PROTO((FILTER_S *, html_f));
-int html_element_collector PROTO((FILTER_S *, int));
-int html_element_flush PROTO((CLCTR_S *));
-void html_element_comment PROTO((FILTER_S *, char *));
-void html_element_output PROTO((FILTER_S *, int));
-int html_entity_collector PROTO((FILTER_S *, int, char **));
-void html_a_prefix PROTO((FILTER_S *));
-void html_a_finish PROTO((HANDLER_S *));
-void html_a_output_prefix PROTO((FILTER_S *, int));
-void html_a_relative PROTO((char *, char *, HANDLE_S *));
-int html_indent PROTO((FILTER_S *, int, int));
-void html_blank PROTO((FILTER_S *, int));
-void html_newline PROTO((FILTER_S *));
-void html_output PROTO((FILTER_S *, int));
-void html_output_flush PROTO((FILTER_S *));
-void html_output_centered PROTO((FILTER_S *, int));
-void html_centered_handle PROTO((int *, char *, int));
-void html_centered_putc PROTO((WRAPLINE_S *, int));
-void html_centered_flush PROTO((FILTER_S *));
-void html_centered_flush_line PROTO((FILTER_S *));
-void html_write_anchor PROTO((FILTER_S *, int));
-void html_write_newline PROTO((FILTER_S *));
-void html_write_indent PROTO((FILTER_S *, int));
-void html_write PROTO((FILTER_S *, char *, int));
-void html_putc PROTO((FILTER_S *, int));
-
-
-/*
- * Named entity table -- most from HTML 2.0 (rfc1866) plus some from
- * W3C doc "Additional named entities for HTML"
- */
-static struct html_entities {
- char *name; /* entity name */
- unsigned char value; /* entity value */
- char *plain; /* plain text representation */
-} entity_tab[] = {
- {"quot", 042}, /* Double quote sign */
- {"amp", 046}, /* Ampersand */
- {"bull", 052}, /* Bullet */
- {"ndash", 055}, /* Dash */
- {"mdash", 055}, /* Dash */
- {"lt", 074}, /* Less than sign */
- {"gt", 076}, /* Greater than sign */
- {"nbsp", 0240, " "}, /* no-break space */
- {"iexcl", 0241}, /* inverted exclamation mark */
- {"cent", 0242}, /* cent sign */
- {"pound", 0243}, /* pound sterling sign */
- {"curren", 0244, "CUR"}, /* general currency sign */
- {"yen", 0245}, /* yen sign */
- {"brvbar", 0246, "|"}, /* broken (vertical) bar */
- {"sect", 0247}, /* section sign */
- {"uml", 0250, "\""}, /* umlaut (dieresis) */
- {"copy", 0251, "(C)"}, /* copyright sign */
- {"ordf", 0252, "a"}, /* ordinal indicator, feminine */
- {"laquo", 0253, "<<"}, /* angle quotation mark, left */
- {"not", 0254, "NOT"}, /* not sign */
- {"shy", 0255, "-"}, /* soft hyphen */
- {"reg", 0256, "(R)"}, /* registered sign */
- {"macr", 0257}, /* macron */
- {"deg", 0260, "DEG"}, /* degree sign */
- {"plusmn", 0261, "+/-"}, /* plus-or-minus sign */
- {"sup2", 0262}, /* superscript two */
- {"sup3", 0263}, /* superscript three */
- {"acute", 0264, "'"}, /* acute accent */
- {"micro", 0265}, /* micro sign */
- {"para", 0266}, /* pilcrow (paragraph sign) */
- {"middot", 0267}, /* middle dot */
- {"cedil", 0270}, /* cedilla */
- {"sup1", 0271}, /* superscript one */
- {"ordm", 0272, "o"}, /* ordinal indicator, masculine */
- {"raquo", 0273, ">>"}, /* angle quotation mark, right */
- {"frac14", 0274, " 1/4"}, /* fraction one-quarter */
- {"frac12", 0275, " 1/2"}, /* fraction one-half */
- {"frac34", 0276, " 3/4"}, /* fraction three-quarters */
- {"iquest", 0277}, /* inverted question mark */
- {"Agrave", 0300, "A"}, /* capital A, grave accent */
- {"Aacute", 0301, "A"}, /* capital A, acute accent */
- {"Acirc", 0302, "A"}, /* capital A, circumflex accent */
- {"Atilde", 0303, "A"}, /* capital A, tilde */
- {"Auml", 0304, "AE"}, /* capital A, dieresis or umlaut mark */
- {"Aring", 0305, "A"}, /* capital A, ring */
- {"AElig", 0306, "AE"}, /* capital AE diphthong (ligature) */
- {"Ccedil", 0307, "C"}, /* capital C, cedilla */
- {"Egrave", 0310, "E"}, /* capital E, grave accent */
- {"Eacute", 0311, "E"}, /* capital E, acute accent */
- {"Ecirc", 0312, "E"}, /* capital E, circumflex accent */
- {"Euml", 0313, "E"}, /* capital E, dieresis or umlaut mark */
- {"Igrave", 0314, "I"}, /* capital I, grave accent */
- {"Iacute", 0315, "I"}, /* capital I, acute accent */
- {"Icirc", 0316, "I"}, /* capital I, circumflex accent */
- {"Iuml", 0317, "I"}, /* capital I, dieresis or umlaut mark */
- {"ETH", 0320, "DH"}, /* capital Eth, Icelandic */
- {"Ntilde", 0321, "N"}, /* capital N, tilde */
- {"Ograve", 0322, "O"}, /* capital O, grave accent */
- {"Oacute", 0323, "O"}, /* capital O, acute accent */
- {"Ocirc", 0324, "O"}, /* capital O, circumflex accent */
- {"Otilde", 0325, "O"}, /* capital O, tilde */
- {"Ouml", 0326, "OE"}, /* capital O, dieresis or umlaut mark */
- {"times", 0327, "x"}, /* multiply sign */
- {"Oslash", 0330, "O"}, /* capital O, slash */
- {"Ugrave", 0331, "U"}, /* capital U, grave accent */
- {"Uacute", 0332, "U"}, /* capital U, acute accent */
- {"Ucirc", 0333, "U"}, /* capital U, circumflex accent */
- {"Uuml", 0334, "UE"}, /* capital U, dieresis or umlaut mark */
- {"Yacute", 0335, "Y"}, /* capital Y, acute accent */
- {"THORN", 0336, "P"}, /* capital THORN, Icelandic */
- {"szlig", 0337, "ss"}, /* small sharp s, German (sz ligature) */
- {"agrave", 0340, "a"}, /* small a, grave accent */
- {"aacute", 0341, "a"}, /* small a, acute accent */
- {"acirc", 0342, "a"}, /* small a, circumflex accent */
- {"atilde", 0343, "a"}, /* small a, tilde */
- {"auml", 0344, "ae"}, /* small a, dieresis or umlaut mark */
- {"aring", 0345, "a"}, /* small a, ring */
- {"aelig", 0346, "ae"}, /* small ae diphthong (ligature) */
- {"ccedil", 0347, "c"}, /* small c, cedilla */
- {"egrave", 0350, "e"}, /* small e, grave accent */
- {"eacute", 0351, "e"}, /* small e, acute accent */
- {"ecirc", 0352, "e"}, /* small e, circumflex accent */
- {"euml", 0353, "e"}, /* small e, dieresis or umlaut mark */
- {"igrave", 0354, "i"}, /* small i, grave accent */
- {"iacute", 0355, "i"}, /* small i, acute accent */
- {"icirc", 0356, "i"}, /* small i, circumflex accent */
- {"iuml", 0357, "i"}, /* small i, dieresis or umlaut mark */
- {"eth", 0360, "dh"}, /* small eth, Icelandic */
- {"ntilde", 0361, "n"}, /* small n, tilde */
- {"ograve", 0362, "o"}, /* small o, grave accent */
- {"oacute", 0363, "o"}, /* small o, acute accent */
- {"ocirc", 0364, "o"}, /* small o, circumflex accent */
- {"otilde", 0365, "o"}, /* small o, tilde */
- {"ouml", 0366, "oe"}, /* small o, dieresis or umlaut mark */
- {"divide", 0367, "/"}, /* divide sign */
- {"oslash", 0370, "o"}, /* small o, slash */
- {"ugrave", 0371, "u"}, /* small u, grave accent */
- {"uacute", 0372, "u"}, /* small u, acute accent */
- {"ucirc", 0373, "u"}, /* small u, circumflex accent */
- {"uuml", 0374, "ue"}, /* small u, dieresis or umlaut mark */
- {"yacute", 0375, "y"}, /* small y, acute accent */
- {"thorn", 0376, "p"}, /* small thorn, Icelandic */
- {"yuml", 0377, "y"}, /* small y, dieresis or umlaut mark */
- {NULL, 0}
-};
-
-
-/*
- * Table of supported elements and corresponding handlers
- */
-static struct element_table {
- char *element;
- int (*handler) PROTO(());
-} element_table[] = {
- {"HTML", NULL}, /* HTML ignore if seen? */
- {"HEAD", html_head}, /* slurp until <BODY> ? */
- {"TITLE", html_title}, /* Document Title */
- {"BASE", html_base}, /* HREF base */
- {"BODY", NULL}, /* (NO OP) */
- {"A", html_a}, /* Anchor */
- {"IMG", html_img}, /* Image */
- {"HR", html_hr}, /* Horizontal Rule */
- {"BR", html_br}, /* Line Break */
- {"P", html_p}, /* Paragraph */
- {"OL", html_ol}, /* Ordered List */
- {"UL", html_ul}, /* Unordered List */
- {"MENU", html_menu}, /* Menu List */
- {"DIR", html_dir}, /* Directory List */
- {"LI", html_li}, /* ... List Item */
- {"DL", html_dl}, /* Definition List */
- {"DT", html_dt}, /* ... Def. Term */
- {"DD", html_dd}, /* ... Def. Definition */
- {"I", html_i}, /* Italic Text */
- {"EM", html_i}, /* Typographic Emphasis */
- {"STRONG", html_i}, /* STRONG Typo Emphasis */
- {"VAR", html_i}, /* Variable Name */
- {"B", html_b}, /* Bold Text */
- {"BLOCKQUOTE", html_blockquote}, /* Blockquote */
- {"ADDRESS", html_address}, /* Address */
- {"CENTER", html_center}, /* Centered Text v3.2 */
- {"DIV", html_div}, /* Document Division 3.2 */
- {"H1", html_h1}, /* Headings... */
- {"H2", html_h2},
- {"H3", html_h3},
- {"H4", html_h4},
- {"H5", html_h5},
- {"H6", html_h6},
- {"PRE", html_pre}, /* Preformatted Text */
- {"KBD", NULL}, /* Keyboard Input (NO OP) */
- {"TT", NULL}, /* Typetype (NO OP) */
- {"SAMP", NULL}, /* Sample Text (NO OP) */
-
-/*----- Handlers below are NOT DONE OR CHECKED OUT YET -----*/
-
- {"CITE", NULL}, /* Citation */
- {"CODE", NULL}, /* Code Text */
-
-/*----- Handlers below UNIMPLEMENTED (and won't until later) -----*/
-
- {"FORM", html_form}, /* form within a document */
- {"INPUT", NULL}, /* One input field, options */
- {"OPTION", NULL}, /* One option within Select */
- {"SELECT", NULL}, /* Selection from a set */
- {"TEXTAREA", NULL}, /* A multi-line input field */
-
-/*----- Handlers below provide limited support for RFC 1942 Tables -----*/
-
- {"CAPTION", html_center}, /* Table Caption */
- {"TR", html_tr}, /* Table Table Row */
- {"TD", html_td}, /* Table Table Data */
-
- {NULL, NULL}
-};
-
-
-
-/*
- * Initialize the given handler, and add it to the stack if it
- * requests it.
- */
-void
-html_push(fd, hf)
- FILTER_S *fd;
- html_f hf;
-{
- HANDLER_S *new;
-
- new = (HANDLER_S *)fs_get(sizeof(HANDLER_S));
- memset(new, 0, sizeof(HANDLER_S));
- new->html_data = fd;
- new->f = hf;
- if((*hf)(new, 0, GF_RESET)){ /* stack the handler? */
- new->below = HANDLERS(fd);
- HANDLERS(fd) = new; /* push */
- }
- else
- fs_give((void **) &new);
-}
-
-
-/*
- * Remove the most recently installed the given handler
- * after letting it accept its demise.
- */
-void
-html_pop(fd, hf)
- FILTER_S *fd;
- html_f hf;
-{
- HANDLER_S *tp;
-
- for(tp = HANDLERS(fd); tp && hf != tp->f; tp = tp->below)
- ;
-
- if(tp){
- (*tp->f)(tp, 0, GF_EOD); /* may adjust handler list */
- if(tp != HANDLERS(fd)){
- HANDLER_S *p;
-
- for(p = HANDLERS(fd); p->below != tp; p = p->below)
- ;
-
- if(p)
- p->below = tp->below; /* remove from middle of stack */
- /* BUG: else programming botch and we should die */
- }
- else
- HANDLERS(fd) = tp->below; /* pop */
-
- fs_give((void **)&tp);
- }
- else if(hf == html_p || hf == html_li || hf == html_dt || hf == html_dd){
- /*
- * Possible "special case" tag handling here.
- * It's for such tags as Paragraph (`</P>'), List Item
- * (`</LI>'), Definition Term (`</DT>'), and Definition Description
- * (`</DD>') elements, which may be omitted...
- */
- HANDLER_S hd;
-
- memset(&hd, 0, sizeof(HANDLER_S));
- hd.html_data = fd;
- hd.f = hf;
-
- (*hf)(&hd, 0, GF_EOD);
- }
- /* BUG: else, we should bitch */
-}
-
-
-/*
- * Deal with data passed a hander in its GF_DATA state
- */
-html_handoff(hd, ch)
- HANDLER_S *hd;
- int ch;
-{
- if(hd->below)
- (*hd->below->f)(hd->below, ch, GF_DATA);
- else
- html_output(hd->html_data, ch);
-}
-
-
-/*
- * HTML <BR> element handler
- */
-int
-html_br(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET)
- html_output(hd->html_data, HTML_NEWLINE);
-
- return(0); /* don't get linked */
-}
-
-
-/*
- * HTML <HR> (Horizontal Rule) element handler
- */
-int
-html_hr(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET){
- int i, old_wrap, width, align;
- PARAMETER *p;
-
- width = WRAP_COLS(hd->html_data);
- align = 0;
- for(p = HD(hd->html_data)->el_data->attribs;
- p && p->attribute;
- p = p->next)
- if(p->value){
- if(!strucmp(p->attribute, "ALIGN")){
- if(!strucmp(p->value, "LEFT"))
- align = 1;
- else if(!strucmp(p->value, "RIGHT"))
- align = 2;
- }
- else if(!strucmp(p->attribute, "WIDTH")){
- char *cp;
-
- width = 0;
- for(cp = p->value; *cp; cp++)
- if(*cp == '%'){
- width = (WRAP_COLS(hd->html_data)*min(100,width))/100;
- break;
- }
- else if(isdigit((unsigned char) *cp))
- width = (width * 10) + (*cp - '0');
-
- width = min(width, WRAP_COLS(hd->html_data));
- }
- }
-
- html_blank(hd->html_data, 1); /* at least one blank line */
-
- old_wrap = HD(hd->html_data)->wrapstate;
- HD(hd->html_data)->wrapstate = 0;
- if((i = max(0, WRAP_COLS(hd->html_data) - width))
- && ((align == 0) ? i /= 2 : (align == 2)))
- for(; i > 0; i--)
- html_output(hd->html_data, ' ');
-
- for(i = 0; i < width; i++)
- html_output(hd->html_data, '_');
-
- html_blank(hd->html_data, 1);
- HD(hd->html_data)->wrapstate = old_wrap;
- }
-
- return(0); /* don't get linked */
-}
-
-
-/*
- * HTML <P> (paragraph) element handler
- */
-int
-html_p(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET){
- /* Make sure there's at least 1 blank line */
- html_blank(hd->html_data, 1);
-
- /* adjust indent level if needed */
- if(HD(hd->html_data)->li_pending){
- html_indent(hd->html_data, 4, HTML_ID_INC);
- HD(hd->html_data)->li_pending = 0;
- }
- }
- else if(cmd == GF_EOD)
- /* Make sure there's at least 1 blank line */
- html_blank(hd->html_data, 1);
-
- return(0); /* don't get linked */
-}
-
-
-/*
- * HTML Table <TR> (paragraph) table row
- */
-int
-html_tr(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET || cmd == GF_EOD)
- /* Make sure there's at least 1 blank line */
- html_blank(hd->html_data, 0);
-
- return(0); /* don't get linked */
-}
-
-
-/*
- * HTML Table <TD> (paragraph) table data
- */
-int
-html_td(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET){
- PARAMETER *p;
-
- for(p = HD(hd->html_data)->el_data->attribs;
- p && p->attribute;
- p = p->next)
- if(!strucmp(p->attribute, "nowrap")
- && (hd->html_data->f2 || hd->html_data->n)){
- HTML_DUMP_LIT(hd->html_data, " | ", 3);
- break;
- }
- }
-
- return(0); /* don't get linked */
-}
-
-
-/*
- * HTML <I> (italic text) element handler
- */
-int
-html_i(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- /* include LITERAL in spaceness test! */
- if(hd->x && !isspace((unsigned char) (ch & 0xff))){
- HTML_ULINE(hd->html_data, 1);
- hd->x = 0;
- }
-
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- hd->x = 1;
- }
- else if(cmd == GF_EOD){
- if(!hd->x)
- HTML_ULINE(hd->html_data, 0);
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <b> (Bold text) element handler
- */
-int
-html_b(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- /* include LITERAL in spaceness test! */
- if(hd->x && !isspace((unsigned char) (ch & 0xff))){
- HTML_ULINE(hd->html_data, 1);
- hd->x = 0;
- }
-
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- hd->x = 1;
- }
- else if(cmd == GF_EOD){
- if(!hd->x)
- HTML_ULINE(hd->html_data, 0);
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <IMG> element handler
- */
-int
-html_img(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET){
- PARAMETER *p;
- char *s = NULL;
-
- for(p = HD(hd->html_data)->el_data->attribs;
- p && p->attribute;
- p = p->next)
- if(!strucmp(p->attribute, "alt")){
- if(p->value && p->value[0]){
- HTML_DUMP_LIT(hd->html_data, p->value, strlen(p->value));
- HTML_TEXT(hd->html_data, ' ');
- }
-
- return(0);
- }
-
- for(p = HD(hd->html_data)->el_data->attribs;
- p && p->attribute;
- p = p->next)
- if(!strucmp(p->attribute, "src") && p->value)
- if((s = strrindex(p->value, '/')) && *++s != '\0'){
- HTML_TEXT(hd->html_data, '[');
- HTML_DUMP_LIT(hd->html_data, s, strlen(s));
- HTML_TEXT(hd->html_data, ']');
- HTML_TEXT(hd->html_data, ' ');
- return(0);
- }
-
- HTML_DUMP_LIT(hd->html_data, "[IMAGE] ", 7);
- }
-
- return(0); /* don't get linked */
-}
-
-
-/*
- * HTML <FORM> (Form) element handler
- */
-int
-html_form(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET){
- char *p;
-
- html_blank(hd->html_data, 0);
-
- HTML_DUMP_LIT(hd->html_data, "[FORM]", 6);
-
- html_blank(hd->html_data, 0);
- }
-
- return(0); /* don't get linked */
-}
-
-
-/*
- * HTML <HEAD> element handler
- */
-int
-html_head(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- HD(hd->html_data)->head = 1;
- }
- else if(cmd == GF_EOD){
- HD(hd->html_data)->head = 0;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <BASE> element handler
- */
-int
-html_base(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET){
- if(HD(hd->html_data)->head && !HTML_BASE(hd->html_data)){
- PARAMETER *p;
-
- for(p = HD(hd->html_data)->el_data->attribs;
- p && p->attribute && strucmp(p->attribute, "HREF");
- p = p->next)
- ;
-
- if(p && p->value && !((HTML_OPT_S *)(hd->html_data)->opt)->base)
- ((HTML_OPT_S *)(hd->html_data)->opt)->base = cpystr(p->value);
- }
- }
-
- return(0); /* DON'T get linked */
-}
-
-
-/*
- * HTML <TITLE> element handler
- */
-int
-html_title(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- if(hd->x + 1 >= hd->y){
- hd->y += 80;
- fs_resize((void **)&hd->s, (size_t)hd->y * sizeof(unsigned char));
- }
-
- hd->s[hd->x++] = (unsigned char) ch;
- }
- else if(cmd == GF_RESET){
- hd->x = 0L;
- hd->y = 80L;
- hd->s = (unsigned char *)fs_get((size_t)hd->y * sizeof(unsigned char));
- }
- else if(cmd == GF_EOD){
- /* Down the road we probably want to give these bytes to
- * someone...
- */
- hd->s[hd->x] = '\0';
- fs_give((void **)&hd->s);
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <A> (Anchor) element handler
- */
-int
-html_a(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- int i, n, x;
- char buf[256];
- HANDLE_S *h;
- PARAMETER *p, *href = NULL, *name = NULL;
-
- /*
- * Pending Anchor!?!?
- * space insertion/line breaking that's yet to get done...
- */
- if(HD(hd->html_data)->prefix){
- dprint(1, (debugfile, "-- html_a: NESTED/UNTERMINATED ANCHOR!\n"));
- html_a_finish(hd);
- }
-
- /*
- * Look for valid Anchor data vis the filter installer's parms
- * (e.g., Only allow references to our internal URLs if asked)
- */
- for(p = HD(hd->html_data)->el_data->attribs;
- p && p->attribute;
- p = p->next)
- if(!strucmp(p->attribute, "HREF")
- && p->value
- && (HANDLES_LOC(hd->html_data)
- || struncmp(p->value, "x-pine-", 7)))
- href = p;
- else if(!strucmp(p->attribute, "NAME"))
- name = p;
-
- if(HANDLES(hd->html_data) && (href || name)){
- h = new_handle();
-
- /*
- * Enhancement: we might want to get fancier and parse the
- * href a bit further such that we can launch images using
- * our image viewer, or browse local files or directories
- * with our internal tools. Of course, having the jump-off
- * point into text/html always be the defined "web-browser",
- * just might be the least confusing UI-wise...
- */
- h->type = URL;
-
- if(name && name->value)
- h->h.url.name = cpystr(name->value);
-
- /*
- * Prepare to build embedded prefix...
- */
- HD(hd->html_data)->prefix = (int *) fs_get(64 * sizeof(int));
- x = 0;
-
- /*
- * Is this something that looks like a URL? If not and
- * we were giving some "base" string, proceed ala RFC1808...
- */
- if(href){
- if(HTML_BASE(hd->html_data) && !rfc1738_scan(href->value, &n))
- html_a_relative(HTML_BASE(hd->html_data), href->value, h);
- else
- h->h.url.path = cpystr(href->value);
-
- if(pico_usingcolor()){
- char *fg = NULL, *bg = NULL, *q;
-
- if(ps_global->VAR_SLCTBL_FORE_COLOR
- && colorcmp(ps_global->VAR_SLCTBL_FORE_COLOR,
- ps_global->VAR_NORM_FORE_COLOR))
- fg = ps_global->VAR_SLCTBL_FORE_COLOR;
-
- if(ps_global->VAR_SLCTBL_BACK_COLOR
- && colorcmp(ps_global->VAR_SLCTBL_BACK_COLOR,
- ps_global->VAR_NORM_BACK_COLOR))
- bg = ps_global->VAR_SLCTBL_BACK_COLOR;
-
- if(fg || bg){
- COLOR_PAIR *tmp;
-
- /*
- * The blacks are just known good colors for testing
- * whether the other color is good.
- */
- tmp = new_color_pair(fg ? fg : colorx(COL_BLACK),
- bg ? bg : colorx(COL_BLACK));
- if(pico_is_good_colorpair(tmp)){
- q = color_embed(fg, bg);
-
- for(i = 0; q[i]; i++)
- HD(hd->html_data)->prefix[x++] = q[i];
- }
-
- if(tmp)
- free_color_pair(&tmp);
- }
-
- if(F_OFF(F_SLCTBL_ITEM_NOBOLD, ps_global))
- HD(hd->html_data)->prefix[x++] = HTML_DOBOLD;
- }
- else
- HD(hd->html_data)->prefix[x++] = HTML_DOBOLD;
- }
-
- HD(hd->html_data)->prefix[x++] = TAG_EMBED;
- HD(hd->html_data)->prefix[x++] = TAG_HANDLE;
-
- sprintf(buf, "%d", h->key);
- HD(hd->html_data)->prefix[x++] = n = strlen(buf);
- for(i = 0; i < n; i++)
- HD(hd->html_data)->prefix[x++] = buf[i];
-
- HD(hd->html_data)->prefix_used = x;
- }
- }
- else if(cmd == GF_EOD){
- html_a_finish(hd);
- }
-
- return(1); /* get linked */
-}
-
-
-void
-html_a_prefix(f)
- FILTER_S *f;
-{
- int *prefix, n;
-
- /* Do this so we don't visit from html_output... */
- prefix = HD(f)->prefix;
- HD(f)->prefix = NULL;
-
- for(n = 0; n < HD(f)->prefix_used; n++)
- html_a_output_prefix(f, prefix[n]);
-
- fs_give((void **) &prefix);
-}
-
-
-/*
- * html_a_finish - house keeping associated with end of link tag
- */
-void
-html_a_finish(hd)
- HANDLER_S *hd;
-{
- if(HANDLES(hd->html_data)){
- if(HD(hd->html_data)->prefix)
- html_a_prefix(hd->html_data);
-
- if(pico_usingcolor()){
- char *fg = NULL, *bg = NULL, *p;
- int i;
-
- if(ps_global->VAR_SLCTBL_FORE_COLOR
- && colorcmp(ps_global->VAR_SLCTBL_FORE_COLOR,
- ps_global->VAR_NORM_FORE_COLOR))
- fg = ps_global->VAR_NORM_FORE_COLOR;
-
- if(ps_global->VAR_SLCTBL_BACK_COLOR
- && colorcmp(ps_global->VAR_SLCTBL_BACK_COLOR,
- ps_global->VAR_NORM_BACK_COLOR))
- bg = ps_global->VAR_NORM_BACK_COLOR;
-
- if(F_OFF(F_SLCTBL_ITEM_NOBOLD, ps_global))
- HTML_BOLD(hd->html_data, 0); /* turn OFF bold */
-
- if(fg || bg){
- COLOR_PAIR *tmp;
-
- /*
- * The blacks are just known good colors for testing
- * whether the other color is good.
- */
- tmp = new_color_pair(fg ? fg : colorx(COL_BLACK),
- bg ? bg : colorx(COL_BLACK));
- if(pico_is_good_colorpair(tmp)){
- p = color_embed(fg, bg);
-
- for(i = 0; p[i]; i++)
- html_output(hd->html_data, p[i]);
- }
-
- if(tmp)
- free_color_pair(&tmp);
- }
- }
- else
- HTML_BOLD(hd->html_data, 0); /* turn OFF bold */
-
- html_output(hd->html_data, TAG_EMBED);
- html_output(hd->html_data, TAG_HANDLEOFF);
- }
-}
-
-
-/*
- * html_output_a_prefix - dump Anchor prefix data
- */
-void
-html_a_output_prefix(f, c)
- FILTER_S *f;
- int c;
-{
- switch(c){
- case HTML_DOBOLD :
- HTML_BOLD(f, 1);
- break;
-
- default :
- html_output(f, c);
- break;
- }
-}
-
-
-
-/*
- * relative_url - put full url path in h based on base and relative url
- */
-void
-html_a_relative(base_url, rel_url, h)
- char *base_url, *rel_url;
- HANDLE_S *h;
-{
- size_t len;
- char tmp[MAILTMPLEN], *p, *q;
- char *scheme = NULL, *net = NULL, *path = NULL,
- *parms = NULL, *query = NULL, *frag = NULL,
- *base_scheme = NULL, *base_net_loc = NULL,
- *base_path = NULL, *base_parms = NULL,
- *base_query = NULL, *base_frag = NULL,
- *rel_scheme = NULL, *rel_net_loc = NULL,
- *rel_path = NULL, *rel_parms = NULL,
- *rel_query = NULL, *rel_frag = NULL;
-
- /* Rough parse of base URL */
- rfc1808_tokens(base_url, &base_scheme, &base_net_loc, &base_path,
- &base_parms, &base_query, &base_frag);
-
- /* Rough parse of this URL */
- rfc1808_tokens(rel_url, &rel_scheme, &rel_net_loc, &rel_path,
- &rel_parms, &rel_query, &rel_frag);
-
- scheme = rel_scheme; /* defaults */
- net = rel_net_loc;
- path = rel_path;
- parms = rel_parms;
- query = rel_query;
- frag = rel_frag;
- if(!scheme && base_scheme){
- scheme = base_scheme;
- if(!net){
- net = base_net_loc;
- if(path){
- if(*path != '/'){
- if(base_path){
- for(p = q = base_path; /* Drop base path's tail */
- p = strchr(p, '/');
- q = ++p)
- ;
-
- len = q - base_path;
- }
- else
- len = 0;
-
- if(len + strlen(rel_path) < MAILTMPLEN - 1){
- if(len)
- sprintf(path = tmp, "%.*s", len, base_path);
-
- strcpy(tmp + len, rel_path);
-
- /* Follow RFC 1808 "Step 6" */
- for(p = tmp; p = strchr(p, '.'); )
- switch(*(p+1)){
- /*
- * a) All occurrences of "./", where "." is a
- * complete path segment, are removed.
- */
- case '/' :
- if(p > tmp)
- for(q = p; *q = *(q+2); q++)
- ;
- else
- p++;
-
- break;
-
- /*
- * b) If the path ends with "." as a
- * complete path segment, that "." is
- * removed.
- */
- case '\0' :
- if(p == tmp || *(p-1) == '/')
- *p = '\0';
- else
- p++;
-
- break;
-
- /*
- * c) All occurrences of "<segment>/../",
- * where <segment> is a complete path
- * segment not equal to "..", are removed.
- * Removal of these path segments is
- * performed iteratively, removing the
- * leftmost matching pattern on each
- * iteration, until no matching pattern
- * remains.
- *
- * d) If the path ends with "<segment>/..",
- * where <segment> is a complete path
- * segment not equal to "..", that
- * "<segment>/.." is removed.
- */
- case '.' :
- if(p > tmp + 1){
- for(q = p - 2; q > tmp && *q != '/'; q--)
- ;
-
- if(*q == '/')
- q++;
-
- if(q + 1 == p /* no "//.." */
- || (*q == '.' /* and "../.." */
- && *(q+1) == '.'
- && *(q+2) == '/')){
- p += 2;
- break;
- }
-
- switch(*(p+2)){
- case '/' :
- len = (p - q) + 3;
- p = q;
- for(; *q = *(q+len); q++)
- ;
-
- break;
-
- case '\0':
- *(p = q) = '\0';
- break;
-
- default:
- p += 2;
- break;
- }
- }
- else
- p += 2;
-
- break;
-
- default :
- p++;
- break;
- }
- }
- else
- path = ""; /* lame. */
- }
- }
- else{
- path = base_path;
- if(!parms){
- parms = base_parms;
- if(!query)
- query = base_query;
- }
- }
- }
- }
-
- len = (scheme ? strlen(scheme) : 0) + (net ? strlen(net) : 0)
- + (path ? strlen(path) : 0) + (parms ? strlen(parms) : 0)
- + (query ? strlen(query) : 0) + (frag ? strlen(frag ) : 0) + 8;
-
- h->h.url.path = (char *) fs_get(len * sizeof(char));
- sprintf(h->h.url.path, "%s%s%s%s%s%s%s%s%s%s%s%s",
- scheme ? scheme : "", scheme ? ":" : "",
- net ? "//" : "", net ? net : "",
- (path && *path == '/') ? "" : ((path && net) ? "/" : ""),
- path ? path : "",
- parms ? ";" : "", parms ? parms : "",
- query ? "?" : "", query ? query : "",
- frag ? "#" : "", frag ? frag : "");
-
- if(base_scheme)
- fs_give((void **) &base_scheme);
-
- if(base_net_loc)
- fs_give((void **) &base_net_loc);
-
- if(base_path)
- fs_give((void **) &base_path);
-
- if(base_parms)
- fs_give((void **) &base_parms);
-
- if(base_query)
- fs_give((void **) &base_query);
-
- if(base_frag)
- fs_give((void **) &base_frag);
-
- if(rel_scheme)
- fs_give((void **) &rel_scheme);
-
- if(rel_net_loc)
- fs_give((void **) &rel_net_loc);
-
- if(rel_parms)
- fs_give((void **) &rel_parms);
-
- if(rel_query)
- fs_give((void **) &rel_query);
-
- if(rel_frag)
- fs_give((void **) &rel_frag);
-
- if(rel_path)
- fs_give((void **) &rel_path);
-}
-
-
-/*
- * HTML <UL> (Unordered List) element handler
- */
-int
-html_ul(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- HD(hd->html_data)->li_pending = 1;
- html_blank(hd->html_data, 0);
- }
- else if(cmd == GF_EOD){
- html_blank(hd->html_data, 0);
-
- if(!HD(hd->html_data)->li_pending)
- html_indent(hd->html_data, -4, HTML_ID_INC);
- else
- HD(hd->html_data)->li_pending = 0;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <OL> (Ordered List) element handler
- */
-int
-html_ol(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /*
- * Signal that we're expecting to see <LI> as our next elemnt
- * and set the the initial ordered count.
- */
- HD(hd->html_data)->li_pending = 1;
- hd->x = 1L;
- html_blank(hd->html_data, 0);
- }
- else if(cmd == GF_EOD){
- html_blank(hd->html_data, 0);
-
- if(!HD(hd->html_data)->li_pending)
- html_indent(hd->html_data, -4, HTML_ID_INC);
- else
- HD(hd->html_data)->li_pending = 0;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <MENU> (Menu List) element handler
- */
-int
-html_menu(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- HD(hd->html_data)->li_pending = 1;
- }
- else if(cmd == GF_EOD){
- html_blank(hd->html_data, 0);
-
- if(!HD(hd->html_data)->li_pending)
- html_indent(hd->html_data, -4, HTML_ID_INC);
- else
- HD(hd->html_data)->li_pending = 0;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <DIR> (Directory List) element handler
- */
-int
-html_dir(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- HD(hd->html_data)->li_pending = 1;
- }
- else if(cmd == GF_EOD){
- html_blank(hd->html_data, 0);
-
- if(!HD(hd->html_data)->li_pending)
- html_indent(hd->html_data, -4, HTML_ID_INC);
- else
- HD(hd->html_data)->li_pending = 0;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <LI> (List Item) element handler
- */
-int
-html_li(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET){
- HANDLER_S *p, *found = NULL;
-
- /*
- * There better be a an unordered list, ordered list,
- * Menu or Directory handler installed
- * or else we crap out...
- */
- for(p = HANDLERS(hd->html_data); p; p = p->below)
- if(p->f == html_ul || p->f == html_ol
- || p->f == html_menu || p->f == html_dir){
- found = p;
- break;
- }
-
- if(found){
- char buf[8], *p;
- int wrapstate;
-
- /* Start a new line */
- html_blank(hd->html_data, 0);
-
- /* adjust indent level if needed */
- if(HD(hd->html_data)->li_pending){
- html_indent(hd->html_data, 4, HTML_ID_INC);
- HD(hd->html_data)->li_pending = 0;
- }
-
- if(found->f == html_ul){
- int l = html_indent(hd->html_data, 0, HTML_ID_GET);
-
- strcpy(buf, " ");
- buf[1] = (l < 5) ? '*' : (l < 9) ? '+' : (l < 17) ? 'o' : '#';
- }
- else if(found->f == html_ol)
- sprintf(buf, "%2ld.", found->x++);
- else if(found->f == html_menu)
- strcpy(buf, " ->");
-
- html_indent(hd->html_data, -4, HTML_ID_INC);
-
- /* So we don't munge whitespace */
- wrapstate = HD(hd->html_data)->wrapstate;
- HD(hd->html_data)->wrapstate = 0;
-
- html_write_indent(hd->html_data, HD(hd->html_data)->indent_level);
- for(p = buf; *p; p++)
- html_output(hd->html_data, (int) *p);
-
- HD(hd->html_data)->wrapstate = wrapstate;
- html_indent(hd->html_data, 4, HTML_ID_INC);
- }
- /* BUG: should really bitch about this */
- }
-
- return(0); /* DON'T get linked */
-}
-
-
-
-/*
- * HTML <DL> (Definition List) element handler
- */
-int
-html_dl(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /*
- * Set indention level for definition terms and definitions...
- */
- hd->x = html_indent(hd->html_data, 0, HTML_ID_GET);
- hd->y = hd->x + 2;
- hd->z = hd->y + 4;
- }
- else if(cmd == GF_EOD){
- html_indent(hd->html_data, (int) hd->x, HTML_ID_SET);
- html_blank(hd->html_data, 1);
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <DT> (Definition Term) element handler
- */
-int
-html_dt(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET){
- HANDLER_S *p;
-
- /*
- * There better be a Definition Handler installed
- * or else we crap out...
- */
- for(p = HANDLERS(hd->html_data); p && p->f != html_dl; p = p->below)
- ;
-
- if(p){ /* adjust indent level if needed */
- html_indent(hd->html_data, (int) p->y, HTML_ID_SET);
- html_blank(hd->html_data, 1);
- }
- /* BUG: else should really bitch about this */
- }
-
- return(0); /* DON'T get linked */
-}
-
-
-/*
- * HTML <DD> (Definition Definition) element handler
- */
-int
-html_dd(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_RESET){
- HANDLER_S *p;
-
- /*
- * There better be a Definition Handler installed
- * or else we crap out...
- */
- for(p = HANDLERS(hd->html_data); p && p->f != html_dl; p = p->below)
- ;
-
- if(p){ /* adjust indent level if needed */
- html_indent(hd->html_data, (int) p->z, HTML_ID_SET);
- html_blank(hd->html_data, 0);
- }
- /* BUG: should really bitch about this */
- }
-
- return(0); /* DON'T get linked */
-}
-
-
-/*
- * HTML <H1> (Headings 1) element handler.
- *
- * Bold, very-large font, CENTERED. One or two blank lines
- * above and below. For our silly character cell's that
- * means centered and ALL CAPS...
- */
-int
-html_h1(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /* turn ON the centered bit */
- CENTER_BIT(hd->html_data) = 1;
- }
- else if(cmd == GF_EOD){
- /* turn OFF the centered bit, add blank line */
- CENTER_BIT(hd->html_data) = 0;
- html_blank(hd->html_data, 1);
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <H2> (Headings 2) element handler
- */
-int
-html_h2(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- if((hd->x & HTML_HX_ULINE) && !isspace((unsigned char) (ch & 0xff))){
- HTML_ULINE(hd->html_data, 1);
- hd->x ^= HTML_HX_ULINE; /* only once! */
- }
-
- html_handoff(hd, (ch < 128 && islower((unsigned char) ch))
- ? toupper((unsigned char) ch) : ch);
- }
- else if(cmd == GF_RESET){
- /*
- * Bold, large font, flush-left. One or two blank lines
- * above and below.
- */
- if(CENTER_BIT(hd->html_data)) /* stop centering for now */
- hd->x = HTML_HX_CENTER;
- else
- hd->x = 0;
-
- hd->x |= HTML_HX_ULINE;
-
- CENTER_BIT(hd->html_data) = 0;
- hd->y = html_indent(hd->html_data, 0, HTML_ID_SET);
- hd->z = HD(hd->html_data)->wrapcol;
- HD(hd->html_data)->wrapcol = WRAP_COLS(hd->html_data) - 8;
- html_blank(hd->html_data, 1);
- }
- else if(cmd == GF_EOD){
- /*
- * restore previous centering, and indent level
- */
- if(!(hd->x & HTML_HX_ULINE))
- HTML_ULINE(hd->html_data, 0);
-
- html_indent(hd->html_data, hd->y, HTML_ID_SET);
- html_blank(hd->html_data, 1);
- CENTER_BIT(hd->html_data) = (hd->x & HTML_HX_CENTER) != 0;
- HD(hd->html_data)->wrapcol = hd->z;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <H3> (Headings 3) element handler
- */
-int
-html_h3(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- if((hd->x & HTML_HX_ULINE) && !isspace((unsigned char) (ch & 0xff))){
- HTML_ULINE(hd->html_data, 1);
- hd->x ^= HTML_HX_ULINE; /* only once! */
- }
-
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /*
- * Italic, large font, slightly indented from the left
- * margin. One or two blank lines above and below.
- */
- if(CENTER_BIT(hd->html_data)) /* stop centering for now */
- hd->x = HTML_HX_CENTER;
- else
- hd->x = 0;
-
- hd->x |= HTML_HX_ULINE;
- CENTER_BIT(hd->html_data) = 0;
- hd->y = html_indent(hd->html_data, 2, HTML_ID_SET);
- hd->z = HD(hd->html_data)->wrapcol;
- HD(hd->html_data)->wrapcol = WRAP_COLS(hd->html_data) - 8;
- html_blank(hd->html_data, 1);
- }
- else if(cmd == GF_EOD){
- /*
- * restore previous centering, and indent level
- */
- if(!(hd->x & HTML_HX_ULINE))
- HTML_ULINE(hd->html_data, 0);
-
- html_indent(hd->html_data, hd->y, HTML_ID_SET);
- html_blank(hd->html_data, 1);
- CENTER_BIT(hd->html_data) = (hd->x & HTML_HX_CENTER) != 0;
- HD(hd->html_data)->wrapcol = hd->z;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <H4> (Headings 4) element handler
- */
-int
-html_h4(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /*
- * Bold, normal font, indented more than H3. One blank line
- * above and below.
- */
- hd->x = CENTER_BIT(hd->html_data); /* stop centering for now */
- CENTER_BIT(hd->html_data) = 0;
- hd->y = html_indent(hd->html_data, 4, HTML_ID_SET);
- hd->z = HD(hd->html_data)->wrapcol;
- HD(hd->html_data)->wrapcol = WRAP_COLS(hd->html_data) - 8;
- html_blank(hd->html_data, 1);
- }
- else if(cmd == GF_EOD){
- /*
- * restore previous centering, and indent level
- */
- html_indent(hd->html_data, (int) hd->y, HTML_ID_SET);
- html_blank(hd->html_data, 1);
- CENTER_BIT(hd->html_data) = hd->x;
- HD(hd->html_data)->wrapcol = hd->z;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <H5> (Headings 5) element handler
- */
-int
-html_h5(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /*
- * Italic, normal font, indented as H4. One blank line
- * above.
- */
- hd->x = CENTER_BIT(hd->html_data); /* stop centering for now */
- CENTER_BIT(hd->html_data) = 0;
- hd->y = html_indent(hd->html_data, 6, HTML_ID_SET);
- hd->z = HD(hd->html_data)->wrapcol;
- HD(hd->html_data)->wrapcol = WRAP_COLS(hd->html_data) - 8;
- html_blank(hd->html_data, 1);
- }
- else if(cmd == GF_EOD){
- /*
- * restore previous centering, and indent level
- */
- html_indent(hd->html_data, (int) hd->y, HTML_ID_SET);
- html_blank(hd->html_data, 1);
- CENTER_BIT(hd->html_data) = hd->x;
- HD(hd->html_data)->wrapcol = hd->z;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <H6> (Headings 6) element handler
- */
-int
-html_h6(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /*
- * Bold, indented same as normal text, more than H5. One
- * blank line above.
- */
- hd->x = CENTER_BIT(hd->html_data); /* stop centering for now */
- CENTER_BIT(hd->html_data) = 0;
- hd->y = html_indent(hd->html_data, 8, HTML_ID_SET);
- hd->z = HD(hd->html_data)->wrapcol;
- HD(hd->html_data)->wrapcol = WRAP_COLS(hd->html_data) - 8;
- html_blank(hd->html_data, 1);
- }
- else if(cmd == GF_EOD){
- /*
- * restore previous centering, and indent level
- */
- html_indent(hd->html_data, (int) hd->y, HTML_ID_SET);
- html_blank(hd->html_data, 1);
- CENTER_BIT(hd->html_data) = hd->x;
- HD(hd->html_data)->wrapcol = hd->z;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <BlockQuote> element handler
- */
-int
-html_blockquote(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- int j;
-#define HTML_BQ_INDENT 6
-
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /*
- * A typical rendering might be a slight extra left and
- * right indent, and/or italic font. The Blockquote element
- * causes a paragraph break, and typically provides space
- * above and below the quote.
- */
- html_indent(hd->html_data, HTML_BQ_INDENT, HTML_ID_INC);
- j = HD(hd->html_data)->wrapstate;
- HD(hd->html_data)->wrapstate = 0;
- html_blank(hd->html_data, 1);
- HD(hd->html_data)->wrapstate = j;
- HD(hd->html_data)->wrapcol -= HTML_BQ_INDENT;
- }
- else if(cmd == GF_EOD){
- html_blank(hd->html_data, 1);
-
- j = HD(hd->html_data)->wrapstate;
- HD(hd->html_data)->wrapstate = 0;
- html_indent(hd->html_data, -(HTML_BQ_INDENT), HTML_ID_INC);
- HD(hd->html_data)->wrapstate = j;
- HD(hd->html_data)->wrapcol += HTML_BQ_INDENT;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <Address> element handler
- */
-int
-html_address(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- int j;
-#define HTML_ADD_INDENT 2
-
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /*
- * A typical rendering might be a slight extra left and
- * right indent, and/or italic font. The Blockquote element
- * causes a paragraph break, and typically provides space
- * above and below the quote.
- */
- html_indent(hd->html_data, HTML_ADD_INDENT, HTML_ID_INC);
- j = HD(hd->html_data)->wrapstate;
- HD(hd->html_data)->wrapstate = 0;
- html_blank(hd->html_data, 1);
- HD(hd->html_data)->wrapstate = j;
- }
- else if(cmd == GF_EOD){
- html_blank(hd->html_data, 1);
-
- j = HD(hd->html_data)->wrapstate;
- HD(hd->html_data)->wrapstate = 0;
- html_indent(hd->html_data, -(HTML_ADD_INDENT), HTML_ID_INC);
- HD(hd->html_data)->wrapstate = j;
- }
-
- return(1); /* get linked */
-}
-
-
-/*
- * HTML <PRE> (Preformatted Text) element handler
- */
-int
-html_pre(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- /*
- * remove CRLF after '>' in element.
- * We see CRLF because wrapstate is off.
- */
- switch(hd->y){
- case 2 :
- if(ch == '\012'){
- hd->y = 3;
- return(1);
- }
- else
- html_handoff(hd, '\015');
-
- break;
-
- case 1 :
- if(ch == '\015'){
- hd->y = 2;
- return(1);
- }
-
- default :
- hd->y = 0;
- break;
- }
-
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- html_blank(hd->html_data, 1);
- hd->x = HD(hd->html_data)->wrapstate;
- HD(hd->html_data)->wrapstate = 0;
- hd->y = 1;
- }
- else if(cmd == GF_EOD){
- HD(hd->html_data)->wrapstate = (hd->x != 0);
- html_blank(hd->html_data, 0);
- }
-
- return(1);
-}
-
-
-
-
-/*
- * HTML <CENTER> (Centerd Text) element handler
- */
-int
-html_center(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- /* turn ON the centered bit */
- CENTER_BIT(hd->html_data) = 1;
- }
- else if(cmd == GF_EOD){
- /* turn OFF the centered bit */
- CENTER_BIT(hd->html_data) = 0;
- }
-
- return(1);
-}
-
-
-
-/*
- * HTML <DIV> (Document Divisions) element handler
- */
-int
-html_div(hd, ch, cmd)
- HANDLER_S *hd;
- int ch, cmd;
-{
- if(cmd == GF_DATA){
- html_handoff(hd, ch);
- }
- else if(cmd == GF_RESET){
- PARAMETER *p;
-
- for(p = HD(hd->html_data)->el_data->attribs;
- p && p->attribute;
- p = p->next)
- if(!strucmp(p->attribute, "ALIGN")){
- if(p->value){
- /* remember previous values */
- hd->x = CENTER_BIT(hd->html_data);
- hd->y = html_indent(hd->html_data, 0, HTML_ID_GET);
-
- html_blank(hd->html_data, 0);
- CENTER_BIT(hd->html_data) = !strucmp(p->value, "CENTER");
- html_indent(hd->html_data, 0, HTML_ID_SET);
- /* NOTE: "RIGHT" not supported yet */
- }
- }
- }
- else if(cmd == GF_EOD){
- /* restore centered bit and indentiousness */
- CENTER_BIT(hd->html_data) = hd->y;
- html_indent(hd->html_data, hd->y, HTML_ID_SET);
- html_blank(hd->html_data, 0);
- }
-
- return(1);
-}
-
-
-
-/*
- * return the function associated with the given element name
- */
-html_f
-html_element_func(el_name)
- char *el_name;
-{
- register int i;
-
- for(i = 0; element_table[i].element; i++)
- if(!strucmp(el_name, element_table[i].element))
- return(element_table[i].handler);
-
- return(NULL);
-}
-
-
-/*
- * collect element's name and any attribute/value pairs then
- * dispatch to the appropriate handler.
- *
- * Returns 1 : got what we wanted
- * 0 : we need more data
- * -1 : bogus input
- */
-int
-html_element_collector(fd, ch)
- FILTER_S *fd;
- int ch;
-{
- if(ch == '>'){
- if(ED(fd)->overrun){
- /*
- * If problem processing, don't bother doing anything
- * internally, just return such that none of what we've
- * digested is displayed.
- */
- HTML_DEBUG_EL("too long", ED(fd));
- return(1); /* Let it go, Jim */
- }
- else if(ED(fd)->mkup_decl){
- if(ED(fd)->badform){
- dprint(2, (debugfile, "-- html <!-- BAD: %.*s\n",
- ED(fd)->len, ED(fd)->buf));
- /*
- * Invalid comment -- make some guesses as
- * to whether we should stop with this greater-than...
- */
- if(ED(fd)->buf[0] != '-'
- || ED(fd)->len < 4
- || (ED(fd)->buf[1] == '-'
- && ED(fd)->buf[ED(fd)->len - 1] == '-'
- && ED(fd)->buf[ED(fd)->len - 2] == '-'))
- return(1);
- }
- else{
- dprint(2, (debugfile, "-- html <!-- OK: %.*s\n",
- ED(fd)->len, ED(fd)->buf));
- if(ED(fd)->start_comment == ED(fd)->end_comment){
- if(ED(fd)->len > 10){
- ED(fd)->buf[ED(fd)->len - 2] = '\0';
- html_element_comment(fd, ED(fd)->buf + 2);
- }
-
- return(1);
- }
- /* else keep collecting comment below */
- }
- }
- else if(!ED(fd)->quoted || ED(fd)->badform){
- html_f f;
-
- /*
- * We either have the whole thing or all that we could
- * salvage from it. Try our best...
- */
-
- if(HD(fd)->bitbucket)
- return(1); /* element inside chtml clause! */
-
- if(!ED(fd)->badform && html_element_flush(ED(fd)))
- return(1); /* return without display... */
-
- /*
- * If we ran into an empty tag or we don't know how to deal
- * with it, just go on, ignoring it...
- */
- if(ED(fd)->element && (f = html_element_func(ED(fd)->element))){
- /* dispatch the element's handler */
- if(ED(fd)->end_tag)
- html_pop(fd, f); /* remove it's handler */
- else
- html_push(fd, f); /* add it's handler */
-
- HTML_DEBUG_EL(ED(fd)->end_tag ? "POP" : "PUSH", ED(fd));
- }
- else{ /* else, empty or unrecognized */
- HTML_DEBUG_EL("?", ED(fd));
- }
-
- return(1); /* all done! see, that didn't hurt */
- }
- }
-
- if(ED(fd)->mkup_decl){
- if((ch &= 0xff) == '-'){
- if(ED(fd)->hyphen){
- ED(fd)->hyphen = 0;
- if(ED(fd)->start_comment)
- ED(fd)->end_comment = 1;
- else
- ED(fd)->start_comment = 1;
- }
- else
- ED(fd)->hyphen = 1;
- }
- else{
- if(ED(fd)->end_comment)
- ED(fd)->start_comment = ED(fd)->end_comment = 0;
-
- /*
- * no "--" after ! or non-whitespace between comments - bad
- */
- if(ED(fd)->len < 2 || (!ED(fd)->start_comment
- && !isspace((unsigned char) ch)))
- ED(fd)->badform = 1; /* non-comment! */
-
- ED(fd)->hyphen = 0;
- }
-
- /*
- * Remember the comment for possible later processing, if
- * it get's too long, remember first and last few chars
- * so we know when to terminate (and throw some garbage
- * in between when we toss out what's between.
- */
- if(ED(fd)->len == HTML_BUF_LEN){
- ED(fd)->buf[2] = ED(fd)->buf[3] = 'X';
- ED(fd)->buf[4] = ED(fd)->buf[ED(fd)->len - 2];
- ED(fd)->buf[5] = ED(fd)->buf[ED(fd)->len - 1];
- ED(fd)->len = 6;
- }
-
- ED(fd)->buf[(ED(fd)->len)++] = ch;
- return(0); /* comments go in the bit bucket */
- }
- else if(ED(fd)->overrun || ED(fd)->badform){
- return(0); /* swallow char's until next '>' */
- }
- else if(!ED(fd)->element && !ED(fd)->len){
- if(ch == '/'){ /* validate leading chars */
- ED(fd)->end_tag = 1;
- return(0);
- }
- else if(ch == '!'){
- ED(fd)->mkup_decl = 1;
- return(0);
- }
- else if(!isalpha((unsigned char) ch))
- return(-1); /* can't be a tag! */
- }
- else if(ch == '\"' || ch == '\''){
- if(!ED(fd)->hit_equal){
- ED(fd)->badform = 1; /* quote in element name?!? */
- return(0);
- }
-
- if(ED(fd)->quoted){
- if(ED(fd)->quoted == (char) ch){
- ED(fd)->quoted = 0;
- return(0); /* continue collecting chars */
- }
- /* else fall thru writing other quoting char */
- }
- else{
- ED(fd)->quoted = (char) ch;
- return(0); /* need more data */
- }
- }
-
- ch &= 0xff; /* strip any "literal" high bits */
- if(ED(fd)->quoted
- || isalnum(ch)
- || strchr("-.!", ch)
- || (ED(fd)->hit_equal && !isspace((unsigned char) ch))){
- if(ED(fd)->len < ((ED(fd)->element || !ED(fd)->hit_equal)
- ? HTML_BUF_LEN:MAX_ELEMENT)){
- ED(fd)->buf[(ED(fd)->len)++] = ch;
- }
- else
- ED(fd)->overrun = 1; /* flag it broken */
- }
- else if(isspace((unsigned char) ch) || ch == '='){
- if(html_element_flush(ED(fd))){
- ED(fd)->badform = 1;
- return(0); /* else, we ain't done yet */
- }
-
- if(!ED(fd)->hit_equal)
- ED(fd)->hit_equal = (ch == '=');
- }
- else
- ED(fd)->badform = 1; /* unrecognized data?? */
-
- return(0); /* keep collecting */
-}
-
-
-/*
- * Element collector found complete string, integrate it and reset
- * internal collection buffer.
- *
- * Returns zero if element collection buffer flushed, error flag otherwise
- */
-int
-html_element_flush(el_data)
- CLCTR_S *el_data;
-{
- int rv = 0;
-
- if(el_data->hit_equal){ /* adding a value */
- el_data->hit_equal = 0;
- if(el_data->cur_attrib){
- if(!el_data->cur_attrib->value){
- el_data->cur_attrib->value = cpystr(el_data->len
- ? el_data->buf : "");
- }
- else{
- dprint(2, (debugfile,
- "** element: unexpected value: %.10s...\n",
- el_data->len ? el_data->buf : "\"\""));
- rv = 1;
- }
- }
- else{
- dprint(2, (debugfile,
- "** element: missing attribute name: %.10s...\n",
- el_data->len ? el_data->buf : "\"\""));
- rv = 2;
- }
-
- el_data->len = 0;
- memset(el_data->buf, 0, HTML_BUF_LEN);
- }
- else if(el_data->len){
- if(!el_data->element){
- el_data->element = cpystr(el_data->buf);
- }
- else{
- PARAMETER *p = (PARAMETER *)fs_get(sizeof(PARAMETER));
- memset(p, 0, sizeof(PARAMETER));
- if(el_data->attribs){
- el_data->cur_attrib->next = p;
- el_data->cur_attrib = p;
- }
- else
- el_data->attribs = el_data->cur_attrib = p;
-
- p->attribute = cpystr(el_data->buf);
- }
-
- el_data->len = 0;
- memset(el_data->buf, 0, HTML_BUF_LEN);
- }
-
- return(rv); /* report whatever happened above */
-}
-
-
-/*
- * html_element_comment - "Special" comment handling here
- */
-void
-html_element_comment(f, s)
- FILTER_S *f;
- char *s;
-{
- char *p;
-
- while(*s && isspace((unsigned char) *s))
- s++;
-
- /*
- * WARNING: "!--chtml" denotes "Conditional HTML", a UW-ism.
- */
- if(!struncmp(s, "chtml ", 6)){
- s += 6;
- if(!struncmp(s, "if ", 3)){
- HD(f)->bitbucket = 1; /* default is failure! */
- switch(*(s += 3)){
- case 'P' :
- case 'p' :
- if(!struncmp(s + 1, "inemode=", 8)){
- if(!strucmp(s = removing_quotes(s + 9), "function_key")
- && F_ON(F_USE_FK, ps_global))
- HD(f)->bitbucket = 0;
- else if(!strucmp(s, "running"))
- HD(f)->bitbucket = 0;
- else if(!strucmp(s, "phone_home") && ps_global->phone_home)
- HD(f)->bitbucket = 0;
-#ifdef _WINDOWS
- else if(!strucmp(s, "os_windows"))
- HD(f)->bitbucket = 0;
-#endif
- }
-
- break;
-
- case '[' : /* test */
- if(p = strindex(++s, ']')){
- *p = '\0'; /* tie off test string */
- removing_leading_white_space(s);
- removing_trailing_white_space(s);
- if(*s == '-' && *(s+1) == 'r'){ /* readable file? */
- for(s += 2; *s && isspace((unsigned char) *s); s++)
- ;
-
-
- HD(f)->bitbucket = (can_access(removing_quotes(s),
- READ_ACCESS) != 0);
- }
- }
-
- break;
-
- default :
- break;
- }
- }
- else if(!strucmp(s, "else")){
- HD(f)->bitbucket = !HD(f)->bitbucket;
- }
- else if(!strucmp(s, "endif")){
- /* Clean up after chtml here */
- HD(f)->bitbucket = 0;
- }
- }
- else if(!HD(f)->bitbucket){
- if(!struncmp(s, "#include ", 9)){
- char buf[MAILTMPLEN], *bufp;
- int len, end_of_line;
- FILE *fp;
-
- /* Include the named file */
- if(!struncmp(s += 9, "file=", 5)
- && (fp = fopen(removing_quotes(s+5), "r"))){
- html_element_output(f, HTML_NEWLINE);
-
- while(fgets(buf, MAILTMPLEN, fp)){
- if((len = strlen(buf)) && buf[len-1] == '\n'){
- end_of_line = 1;
- buf[--len] = '\0';
- }
- else
- end_of_line = 0;
-
- for(bufp = buf; len; bufp++, len--)
- html_element_output(f, (int) *bufp);
-
- if(end_of_line)
- html_element_output(f, HTML_NEWLINE);
- }
-
- fclose(fp);
- html_element_output(f, HTML_NEWLINE);
- HD(f)->blanks = 0;
- if(f->f1 == WSPACE)
- f->f1 = DFL;
- }
- }
- else if(!struncmp(s, "#echo ", 6)){
- if(!struncmp(s += 6, "var=", 4)){
- char *p, buf[MAILTMPLEN];
- ADDRESS *adr;
- extern char datestamp[];
-
- if(!strcmp(s = removing_quotes(s + 4), "PINE_VERSION")){
- p = pine_version;
- }
- else if(!strcmp(s, "PINE_COMPILE_DATE")){
- p = datestamp;
- }
- else if(!strcmp(s, "PINE_TODAYS_DATE")){
- rfc822_date(p = buf);
- }
- else if(!strcmp(s, "_LOCAL_FULLNAME_")){
- p = (ps_global->VAR_LOCAL_FULLNAME
- && ps_global->VAR_LOCAL_FULLNAME[0])
- ? ps_global->VAR_LOCAL_FULLNAME
- : "Local Support";
- }
- else if(!strcmp(s, "_LOCAL_ADDRESS_")){
- p = (ps_global->VAR_LOCAL_ADDRESS
- && ps_global->VAR_LOCAL_ADDRESS[0])
- ? ps_global->VAR_LOCAL_ADDRESS
- : "postmaster";
- adr = rfc822_parse_mailbox(&p, ps_global->maildomain);
- sprintf(p = buf, "%s@%s", adr->mailbox, adr->host);
- mail_free_address(&adr);
- }
- else if(!strcmp(s, "_BUGS_FULLNAME_")){
- p = (ps_global->VAR_BUGS_FULLNAME
- && ps_global->VAR_BUGS_FULLNAME[0])
- ? ps_global->VAR_BUGS_FULLNAME
- : "Place to report Pine Bugs";
- }
- else if(!strcmp(s, "_BUGS_ADDRESS_")){
- p = (ps_global->VAR_BUGS_ADDRESS
- && ps_global->VAR_BUGS_ADDRESS[0])
- ? ps_global->VAR_BUGS_ADDRESS : "postmaster";
- adr = rfc822_parse_mailbox(&p, ps_global->maildomain);
- sprintf(p = buf, "%s@%s", adr->mailbox, adr->host);
- mail_free_address(&adr);
- }
- else if(!strcmp(s, "CURRENT_DIR")){
- getcwd(p = buf, MAILTMPLEN);
- }
- else if(!strcmp(s, "HOME_DIR")){
- p = ps_global->home_dir;
- }
- else
- p = NULL;
-
- if(p){
- if(f->f1 == WSPACE){
- html_element_output(f, ' ');
- f->f1 = DFL; /* clear it */
- }
-
- while(*p)
- html_element_output(f, (int) *p++);
- }
- }
- }
- }
-}
-
-
-void
-html_element_output(f, ch)
- FILTER_S *f;
- int ch;
-{
- if(HANDLERS(f))
- (*HANDLERS(f)->f)(HANDLERS(f), ch, GF_DATA);
- else
- html_output(f, ch);
-}
-
-
-/*
- * collect html entities and return its value when done.
- *
- * Returns 0 : we need more data
- * 1-255 : char value of entity collected
- * HTML_BADVALUE : good data, but no named match or out of range
- * HTML_BADDATA : invalid input
- *
- * NOTES:
- * - entity format is "'&' tag ';'" and represents a literal char
- * - named entities are CASE SENSITIVE.
- * - numeric char references (where the tag is prefixed with a '#')
- * are a char with that numbers value
- * - numeric vals are 0-255 except for the ranges: 0-8, 11-31, 127-159.
- */
-int
-html_entity_collector(f, ch, alternate)
- FILTER_S *f;
- int ch;
- char **alternate;
-{
- static char len = 0;
- static char buf[MAX_ENTITY];
- int rv = 0, i;
-
- if((len == 0)
- ? (isalpha((unsigned char) ch) || ch == '#')
- : ((isdigit((unsigned char) ch)
- || (isalpha((unsigned char) ch) && buf[0] != '#'))
- && len < MAX_ENTITY - 1)){
- buf[len++] = ch;
- }
- else if((isspace((unsigned char) ch) || ch == ';') && len){
- buf[len] = '\0'; /* got something! */
- switch(buf[0]){
- case '#' :
- rv = atoi(&buf[1]);
- if(F_ON(F_PASS_CONTROL_CHARS, ps_global)
- || (rv == '\t' || rv == '\n' || rv == '\r'
- || (rv > 31 && rv < 127) || (rv > 159 && rv < 256))){
- if(alternate)
- for(i = 0, *alternate = NULL; entity_tab[i].name; i++)
- if(entity_tab[i].value == rv){
- *alternate = entity_tab[i].plain;
- break;
- }
- }
- else
- rv = HTML_BADVALUE;
-
- break;
-
- default :
- rv = HTML_BADVALUE; /* in case we fail below */
- for(i = 0; entity_tab[i].name; i++)
- if(strcmp(entity_tab[i].name, buf) == 0){
- rv = entity_tab[i].value;
- if(alternate)
- *alternate = entity_tab[i].plain;
-
- break;
- }
-
- break;
- }
- }
- else
- rv = HTML_BADDATA; /* bogus input! */
-
- if(rv){ /* nonzero return, clean up */
- if(rv > 0xff && alternate){ /* provide bogus data to caller */
- buf[len] = '\0';
- *alternate = buf;
- }
-
- len = 0;
- }
-
- return(rv);
-}
-
-
-/*----------------------------------------------------------------------
- HTML text to plain text filter
-
- This basically tries to do the best it can with HTML 2.0 (RFC1866)
- with bits of RFC 1942 (plus some HTML 3.2 thrown in as well) text
- formatting.
-
- ----*/
-void
-gf_html2plain(f, flg)
- FILTER_S *f;
- int flg;
-{
-/* BUG: qoute incoming \255 values (see "yuml" above!) */
- if(flg == GF_DATA){
- register int c;
- GF_INIT(f, f->next);
-
- while(GF_GETC(f, c)){
- /*
- * First we have to collect any literal entities...
- * that is, IF we're not already collecting one
- * AND we're not in element's text or, if we are, we're
- * not in quoted text. Whew.
- */
- if(f->t){
- int i;
- char *alt = NULL;
-
- switch(i = html_entity_collector(f, c, &alt)){
- case 0: /* more data required? */
- continue; /* go get another char */
-
- case HTML_BADVALUE :
- case HTML_BADDATA :
- /* if supplied, process bogus data */
- HTML_PROC(f, '&');
- for(; *alt; alt++)
- HTML_PROC(f, *alt);
-
- if(c == '&' && !HD(f)->quoted){
- f->t = '&';
- continue;
- }
- else
- f->t = 0; /* don't come back next time */
-
- break;
-
- default : /* thing to process */
- f->t = 0; /* don't come back */
-
- /*
- * Map some of the undisplayable entities?
- */
- if(HD(f)->alt_entity && i > 127 && alt && alt[0]){
- for(; *alt; alt++){
- c = MAKE_LITERAL(*alt);
- HTML_PROC(f, c);
- }
-
- continue;
- }
-
- c = MAKE_LITERAL(i);
- break;
- }
- }
- else if(c == '&' && !HD(f)->quoted){
- f->t = '&';
- continue;
- }
-
- /*
- * then we process whatever we got...
- */
-
- HTML_PROC(f, c);
- }
-
- GF_OP_END(f); /* clean up our input pointers */
- }
- else if(flg == GF_EOD){
- while(HANDLERS(f))
- /* BUG: should complain about "Unexpected end of HTML text." */
- html_pop(f, HANDLERS(f)->f);
-
- html_output(f, HTML_NEWLINE);
- HTML_FLUSH(f);
- fs_give((void **)&f->line);
- if(HD(f)->color)
- free_color_pair(&HD(f)->color);
-
- fs_give(&f->data);
- if(f->opt){
- if(((HTML_OPT_S *)f->opt)->base)
- fs_give((void **) &((HTML_OPT_S *)f->opt)->base);
-
- fs_give(&f->opt);
- }
-
- (*f->next->f)(f->next, GF_DATA);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset html2plain\n"));
- f->data = (HTML_DATA_S *) fs_get(sizeof(HTML_DATA_S));
- memset(f->data, 0, sizeof(HTML_DATA_S));
- HD(f)->wrapstate = 1; /* start with flowing text */
- HD(f)->wrapcol = WRAP_COLS(f) - 8;
- f->f1 = DFL; /* state */
- f->f2 = 0; /* chars in wrap buffer */
- f->n = 0L; /* chars on line so far */
- f->linep = f->line = (char *)fs_get(HTML_BUF_LEN * sizeof(char));
- HD(f)->alt_entity = (!ps_global->VAR_CHAR_SET
- || strucmp(ps_global->VAR_CHAR_SET,
- "iso-8859-1"));
- }
-}
-
-
-
-/*
- * html_indent - do the requested indent level function with appropriate
- * flushing and such.
- *
- * Returns: indent level prior to set/increment
- */
-int
-html_indent(f, val, func)
- FILTER_S *f;
- int val, func;
-{
- int old = HD(f)->indent_level;
-
- /* flush pending data at old indent level */
- switch(func){
- case HTML_ID_INC :
- html_output_flush(f);
- if((HD(f)->indent_level += val) < 0)
- HD(f)->indent_level = 0;
-
- break;
-
- case HTML_ID_SET :
- html_output_flush(f);
- HD(f)->indent_level = val;
- break;
-
- default :
- break;
- }
-
- return(old);
-}
-
-
-
-/*
- * html_blanks - Insert n blank lines into output
- */
-void
-html_blank(f, n)
- FILTER_S *f;
- int n;
-{
- /* Cap off any flowing text, and then write blank lines */
- if(f->f2 || f->n || CENTER_BIT(f) || HD(f)->centered || WRAPPED_LEN(f))
- html_output(f, HTML_NEWLINE);
-
- if(HD(f)->wrapstate)
- while(HD(f)->blanks < n) /* blanks inc'd by HTML_NEWLINE */
- html_output(f, HTML_NEWLINE);
-}
-
-
-
-/*
- * html_newline -- insert a newline mindful of embedded tags
- */
-void
-html_newline(f)
- FILTER_S *f;
-{
- html_write_newline(f); /* commit an actual newline */
-
- if(f->n){ /* and keep track of blank lines */
- HD(f)->blanks = 0;
- f->n = 0L;
- }
- else
- HD(f)->blanks++;
-}
-
-
-/*
- * output the given char, handling any requested wrapping.
- * It's understood that all whitespace handed us is written. In other
- * words, junk whitespace is weeded out before it's given to us here.
- *
- */
-void
-html_output(f, ch)
- FILTER_S *f;
- int ch;
-{
- if(CENTER_BIT(f)){ /* center incoming text */
- html_output_centered(f, ch);
- }
- else{
- static short embedded = 0; /* BUG: reset on entering filter */
- static char *color_ptr = NULL;
-
- if(HD(f)->centered){
- html_centered_flush(f);
- fs_give((void **) &HD(f)->centered->line.buf);
- fs_give((void **) &HD(f)->centered->word.buf);
- fs_give((void **) &HD(f)->centered);
- }
-
- if(HD(f)->wrapstate){
- if(ch == HTML_NEWLINE){ /* hard newline */
- html_output_flush(f);
- html_newline(f);
- }
- else
- HD(f)->blanks = 0; /* reset blank line counter */
-
- if(ch == TAG_EMBED){ /* takes up no space */
- embedded = 1;
- *(f->linep)++ = TAG_EMBED;
- }
- else if(embedded){ /* ditto */
- if(ch == TAG_HANDLE)
- embedded = -1; /* next ch is length */
- else if(ch == TAG_FGCOLOR || ch == TAG_BGCOLOR){
- if(!HD(f)->color)
- HD(f)->color = new_color_pair(NULL, NULL);
-
- if(ch == TAG_FGCOLOR)
- color_ptr = HD(f)->color->fg;
- else
- color_ptr = HD(f)->color->bg;
-
- embedded = 11;
- }
- else if(embedded < 0){
- embedded = ch; /* number of embedded chars */
- }
- else{
- embedded--;
- if(color_ptr)
- *color_ptr++ = ch;
-
- if(embedded == 0 && color_ptr){
- *color_ptr = '\0';
- color_ptr = NULL;
- }
- }
-
- *(f->linep)++ = ch;
- }
- else if(HTML_ISSPACE(ch)){
- html_output_flush(f);
- }
- else{
- if(HD(f)->prefix)
- html_a_prefix(f);
-
- if(++f->f2 >= WRAP_COLS(f)){
- HTML_FLUSH(f);
- html_newline(f);
- if(HD(f)->in_anchor)
- html_write_anchor(f, HD(f)->in_anchor);
- }
- else
- *(f->linep)++ = ch & 0xff;
- }
- }
- else{
- if(HD(f)->prefix)
- html_a_prefix(f);
-
- html_output_flush(f);
-
- switch(embedded){
- case 0 :
- switch(ch){
- default :
- f->n++; /* inc displayed char count */
- HD(f)->blanks = 0; /* reset blank line counter */
- html_putc(f, ch & 0xff);
- break;
-
- case TAG_EMBED : /* takes up no space */
- html_putc(f, TAG_EMBED);
- embedded = -2;
- break;
-
- case HTML_NEWLINE : /* newline handling */
- if(!f->n)
- break;
-
- case '\n' :
- html_newline(f);
-
- case '\r' :
- break;
- }
-
- break;
-
- case -2 :
- embedded = 0;
- switch(ch){
- case TAG_HANDLE :
- embedded = -1; /* next ch is length */
- break;
-
- case TAG_BOLDON :
- BOLD_BIT(f) = 1;
- break;
-
- case TAG_BOLDOFF :
- BOLD_BIT(f) = 0;
- break;
-
- case TAG_ULINEON :
- ULINE_BIT(f) = 1;
- break;
-
- case TAG_ULINEOFF :
- ULINE_BIT(f) = 0;
- break;
-
- case TAG_FGCOLOR :
- if(!HD(f)->color)
- HD(f)->color = new_color_pair(NULL, NULL);
-
- color_ptr = HD(f)->color->fg;
- embedded = 11;
- break;
-
- case TAG_BGCOLOR :
- if(!HD(f)->color)
- HD(f)->color = new_color_pair(NULL, NULL);
-
- color_ptr = HD(f)->color->bg;
- embedded = 11;
- break;
-
- case TAG_HANDLEOFF :
- ch = TAG_INVOFF;
- HD(f)->in_anchor = 0;
- break;
-
- default :
- break;
- }
-
- html_putc(f, ch);
- break;
-
- case -1 :
- embedded = ch; /* number of embedded chars */
- html_putc(f, ch);
- break;
-
- default :
- embedded--;
- if(color_ptr)
- *color_ptr++ = ch;
-
- if(embedded == 0 && color_ptr){
- *color_ptr = '\0';
- color_ptr = NULL;
- }
-
- html_putc(f, ch);
- break;
- }
- }
- }
-}
-
-
-/*
- * flush any buffered chars waiting for wrapping.
- */
-void
-html_output_flush(f)
- FILTER_S *f;
-{
- if(f->f2){
- if(f->n && ((int) f->n) + f->f2 > HD(f)->wrapcol)
- html_newline(f); /* wrap? */
-
- if(f->n){ /* text already on the line? */
- html_putc(f, ' ');
- f->n++; /* increment count */
- }
- else{
- /* write at start of new line */
- html_write_indent(f, HD(f)->indent_level);
-
- if(HD(f)->in_anchor)
- html_write_anchor(f, HD(f)->in_anchor);
- }
-
- f->n += f->f2;
- HTML_FLUSH(f);
- }
-}
-
-
-
-/*
- * html_output_centered - managed writing centered text
- */
-void
-html_output_centered(f, ch)
- FILTER_S *f;
- int ch;
-{
- if(!HD(f)->centered){ /* new text? */
- html_output_flush(f);
- if(f->n) /* start on blank line */
- html_newline(f);
-
- HD(f)->centered = (CENTER_S *) fs_get(sizeof(CENTER_S));
- memset(HD(f)->centered, 0, sizeof(CENTER_S));
- /* and grab a buf to start collecting centered text */
- HD(f)->centered->line.len = WRAP_COLS(f);
- HD(f)->centered->line.buf = (char *) fs_get(HD(f)->centered->line.len
- * sizeof(char));
- HD(f)->centered->line.used = HD(f)->centered->line.width = 0;
- HD(f)->centered->word.len = 32;
- HD(f)->centered->word.buf = (char *) fs_get(HD(f)->centered->word.len
- * sizeof(char));
- HD(f)->centered->word.used = HD(f)->centered->word.width = 0;
- }
-
- if(ch == HTML_NEWLINE){ /* hard newline */
- html_centered_flush(f);
- }
- else if(ch == TAG_EMBED){ /* takes up no space */
- HD(f)->centered->embedded = 1;
- html_centered_putc(&HD(f)->centered->word, TAG_EMBED);
- }
- else if(HD(f)->centered->embedded){
- static char *color_ptr = NULL;
-
- if(ch == TAG_HANDLE){
- HD(f)->centered->embedded = -1; /* next ch is length */
- }
- else if(ch == TAG_FGCOLOR || ch == TAG_BGCOLOR){
- if(!HD(f)->color)
- HD(f)->color = new_color_pair(NULL, NULL);
-
- if(ch == TAG_FGCOLOR)
- color_ptr = HD(f)->color->fg;
- else
- color_ptr = HD(f)->color->bg;
-
- HD(f)->centered->embedded = 11;
- }
- else if(HD(f)->centered->embedded < 0){
- HD(f)->centered->embedded = ch; /* number of embedded chars */
- }
- else{
- HD(f)->centered->embedded--;
- if(color_ptr)
- *color_ptr++ = ch;
-
- if(HD(f)->centered->embedded == 0 && color_ptr){
- *color_ptr = '\0';
- color_ptr = NULL;
- }
- }
-
- html_centered_putc(&HD(f)->centered->word, ch);
- }
- else if(isspace((unsigned char) ch)){
- if(!HD(f)->centered->space++){ /* end of a word? flush! */
- int i;
-
- if(WRAPPED_LEN(f) > HD(f)->wrapcol){
- html_centered_flush_line(f);
- /* fall thru to put current "word" on blank "line" */
- }
- else if(HD(f)->centered->line.width){
- /* put space char between line and appended word */
- html_centered_putc(&HD(f)->centered->line, ' ');
- HD(f)->centered->line.width++;
- }
-
- for(i = 0; i < HD(f)->centered->word.used; i++)
- html_centered_putc(&HD(f)->centered->line,
- HD(f)->centered->word.buf[i]);
-
- HD(f)->centered->line.width += HD(f)->centered->word.width;
- HD(f)->centered->word.used = 0;
- HD(f)->centered->word.width = 0;
- }
- }
- else{
- if(HD(f)->prefix)
- html_a_prefix(f);
-
- /* ch is start of next word */
- HD(f)->centered->space = 0;
- if(HD(f)->centered->word.width >= WRAP_COLS(f))
- html_centered_flush(f);
-
- html_centered_putc(&HD(f)->centered->word, ch);
- HD(f)->centered->word.width++;
- }
-}
-
-
-/*
- * html_centered_putc -- add given char to given WRAPLINE_S
- */
-void
-html_centered_putc(wp, ch)
- WRAPLINE_S *wp;
- int ch;
-{
- if(wp->used + 1 >= wp->len){
- wp->len += 64;
- fs_resize((void **) &wp->buf, wp->len * sizeof(char));
- }
-
- wp->buf[wp->used++] = ch;
-}
-
-
-
-/*
- * html_centered_flush - finish writing any pending centered output
- */
-void
-html_centered_flush(f)
- FILTER_S *f;
-{
- int i, h;
-
- /*
- * If word present (what about line?) we need to deal with
- * appending it...
- */
- if(HD(f)->centered->word.width && WRAPPED_LEN(f) > HD(f)->wrapcol)
- html_centered_flush_line(f);
-
- if(WRAPPED_LEN(f)){
- /* figure out how much to indent */
- if((i = (WRAP_COLS(f) - WRAPPED_LEN(f))/2) > 0)
- html_write_indent(f, i);
-
- if(HD(f)->centered->anchor)
- html_write_anchor(f, HD(f)->centered->anchor);
-
- html_centered_handle(&HD(f)->centered->anchor,
- HD(f)->centered->line.buf,
- HD(f)->centered->line.used);
- html_write(f, HD(f)->centered->line.buf, HD(f)->centered->line.used);
-
- if(HD(f)->centered->word.used){
- if(HD(f)->centered->line.width)
- html_putc(f, ' ');
-
- html_centered_handle(&HD(f)->centered->anchor,
- HD(f)->centered->word.buf,
- HD(f)->centered->word.used);
- html_write(f, HD(f)->centered->word.buf,
- HD(f)->centered->word.used);
- }
-
- HD(f)->centered->line.used = HD(f)->centered->word.used = 0;
- HD(f)->centered->line.width = HD(f)->centered->word.width = 0;
- }
- else
- HD(f)->blanks++; /* advance the blank line counter */
-
- html_newline(f); /* finish the line */
-}
-
-
-/*
- * html_centered_handle - scan the line for embedded handles
- */
-void
-html_centered_handle(h, line, len)
- int *h;
- char *line;
- int len;
-{
- int n;
-
- while(len-- > 0)
- if(*line++ == TAG_EMBED && len-- > 0)
- switch(*line++){
- case TAG_HANDLE :
- if((n = *line++) >= --len){
- *h = 0;
- len -= n;
- while(n--)
- *h = (*h * 10) + (*line++ - '0');
- }
- break;
-
- case TAG_HANDLEOFF :
- case TAG_INVOFF :
- *h = 0; /* assumption 23,342: inverse off ends tags */
- break;
-
- default :
- break;
- }
-}
-
-
-
-/*
- * html_centered_flush_line - flush the centered "line" only
- */
-void
-html_centered_flush_line(f)
- FILTER_S *f;
-{
- if(HD(f)->centered->line.used){
- int i, j;
-
- /* hide "word" from flush */
- i = HD(f)->centered->word.used;
- j = HD(f)->centered->word.width;
- HD(f)->centered->word.used = 0;
- HD(f)->centered->word.width = 0;
- html_centered_flush(f);
-
- HD(f)->centered->word.used = i;
- HD(f)->centered->word.width = j;
- }
-}
-
-
-/*
- * html_write_indent - write indention mindful of display attributes
- */
-void
-html_write_indent(f, indent)
- FILTER_S *f;
- int indent;
-{
- if(! STRIP(f)){
- if(BOLD_BIT(f)){
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_BOLDOFF);
- }
-
- if(ULINE_BIT(f)){
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_ULINEOFF);
- }
- }
-
- f->n = indent;
- while(indent-- > 0)
- html_putc(f, ' '); /* indent as needed */
-
- /*
- * Resume any previous embedded state
- */
- if(! STRIP(f)){
- if(BOLD_BIT(f)){
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_BOLDON);
- }
-
- if(ULINE_BIT(f)){
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_ULINEON);
- }
- }
-}
-
-
-/*
- *
- */
-void
-html_write_anchor(f, anchor)
- FILTER_S *f;
- int anchor;
-{
- char buf[256];
- int i;
-
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_HANDLE);
- sprintf(buf, "%d", anchor);
- html_putc(f, (int) strlen(buf));
-
- for(i = 0; buf[i]; i++)
- html_putc(f, buf[i]);
-}
-
-
-/*
- * html_write_newline - write a newline mindful of display attributes
- */
-void
-html_write_newline(f)
- FILTER_S *f;
-{
- if(! STRIP(f)){ /* First tie, off any embedded state */
- if(HD(f)->in_anchor){
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_INVOFF);
- }
-
- if(BOLD_BIT(f)){
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_BOLDOFF);
- }
-
- if(ULINE_BIT(f)){
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_ULINEOFF);
- }
-
- if(HD(f)->color && HD(f)->color->fg[0] && HD(f)->color->bg[0]){
- char *p;
- int i;
-
- p = color_embed(ps_global->VAR_NORM_FORE_COLOR,
- ps_global->VAR_NORM_BACK_COLOR);
- for(i = 0; i < 2 * (RGBLEN + 2); i++)
- html_putc(f, p[i]);
- }
- }
-
- html_write(f, "\015\012", 2);
-
- if(! STRIP(f)){ /* First tie, off any embedded state */
- if(BOLD_BIT(f)){
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_BOLDON);
- }
-
- if(ULINE_BIT(f)){
- html_putc(f, TAG_EMBED);
- html_putc(f, TAG_ULINEON);
- }
-
- if(HD(f)->color && HD(f)->color->fg[0] && HD(f)->color->bg[0]){
- char *p;
- int i;
- COLOR_PAIR *tmp;
-
- tmp = new_color_pair(HD(f)->color->fg, HD(f)->color->bg);
- if(pico_is_good_colorpair(tmp)){
- p = color_embed(HD(f)->color->fg, HD(f)->color->bg);
- for(i = 0; i < 2 * (RGBLEN + 2); i++)
- html_putc(f, p[i]);
- }
-
- HD(f)->color->fg[0] = '\0';
- HD(f)->color->bg[0] = '\0';
-
- if(tmp)
- free_color_pair(&tmp);
- }
- }
-}
-
-
-/*
- * html_write - write given int array to the next filter.
- */
-void
-html_write(f, s, n)
- FILTER_S *f;
- char *s;
- int n;
-{
- GF_INIT(f, f->next);
-
- while(n-- > 0){
- /* keep track of attribute state? Not if last char! */
- if(*s == TAG_EMBED && n-- > 0){
- GF_PUTC(f->next, TAG_EMBED);
- switch(*++s){
- case TAG_BOLDON :
- BOLD_BIT(f) = 1;
- break;
- case TAG_BOLDOFF :
- BOLD_BIT(f) = 0;
- break;
- case TAG_ULINEON :
- ULINE_BIT(f) = 1;
- break;
- case TAG_ULINEOFF :
- ULINE_BIT(f) = 0;
- break;
- case TAG_HANDLEOFF :
- HD(f)->in_anchor = 0;
- GF_PUTC(f->next, TAG_INVOFF);
- s++;
- continue;
- case TAG_HANDLE :
- if(n-- > 0){
- int i = *++s;
-
- GF_PUTC(f->next, TAG_HANDLE);
- if(i <= n){
- n -= i;
- GF_PUTC(f->next, i);
- HD(f)->in_anchor = 0;
- while(1){
- HD(f)->in_anchor = (HD(f)->in_anchor * 10)
- + (*++s - '0');
- if(--i)
- GF_PUTC(f->next, *s);
- else
- break;
- }
- }
- }
-
- break;
- default:
- break;
- }
- }
-
- GF_PUTC(f->next, (*s++) & 0xff);
- }
-
- GF_IP_END(f->next); /* clean up next's input pointers */
-}
-
-
-/*
- * html_putc -- actual work of writing to next filter.
- * NOTE: Small opt not using full GF_END since our input
- * pointers don't need adjusting.
- */
-void
-html_putc(f, ch)
- FILTER_S *f;
- int ch;
-{
- GF_INIT(f, f->next);
- GF_PUTC(f->next, ch & 0xff);
- GF_IP_END(f->next); /* clean up next's input pointers */
-}
-
-
-
-/*
- * Only current option is to turn on embedded data stripping for text
- * bound to a printer or composer.
- */
-void *
-gf_html2plain_opt(base, columns, flags)
- char *base;
- int columns, flags;
-{
- HTML_OPT_S *op;
-
- op = (HTML_OPT_S *) fs_get(sizeof(HTML_OPT_S));
-
- op->base = cpystr(base);
- op->columns = columns;
- op->strip = ((flags & GFHP_STRIPPED) == GFHP_STRIPPED);
- op->handles = ((flags & GFHP_HANDLES) == GFHP_HANDLES);
- op->handles_loc = ((flags & GFHP_LOCAL_HANDLES) == GFHP_LOCAL_HANDLES);
- return((void *) op);
-}
-
-
-/* END OF HTML-TO-PLAIN text filter */
-
-/*
- * ESCAPE CODE FILTER - remove unknown and possibly dangerous escape codes
- * from the text stream.
- */
-
-#define MAX_ESC_LEN 5
-
-/*
- * the simple filter, removes unknown escape codes from the stream
- */
-void
-gf_escape_filter(f, flg)
- FILTER_S *f;
- int flg;
-{
- register char *p;
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register int state = f->f1;
-
- while(GF_GETC(f, c)){
-
- if(state){
- if(c == '\033' || f->n == MAX_ESC_LEN){
- f->line[f->n] = '\0';
- f->n = 0L;
- if(!match_escapes(f->line)){
- GF_PUTC(f->next, '^');
- GF_PUTC(f->next, '[');
- }
- else
- GF_PUTC(f->next, '\033');
-
- p = f->line;
- while(*p)
- GF_PUTC(f->next, *p++);
-
- if(c == '\033')
- continue;
- else
- state = 0; /* fall thru */
- }
- else{
- f->line[f->n++] = c; /* collect */
- continue;
- }
- }
-
- if(c == '\033')
- state = 1;
- else
- GF_PUTC(f->next, c);
- }
-
- f->f1 = state;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- if(f->f1){
- if(!match_escapes(f->line)){
- GF_PUTC(f->next, '^');
- GF_PUTC(f->next, '[');
- }
- else
- GF_PUTC(f->next, '\033');
- }
-
- for(p = f->line; f->n; f->n--, p++)
- GF_PUTC(f->next, *p);
-
- fs_give((void **)&(f->line)); /* free temp line buffer */
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset escape\n"));
- f->f1 = 0;
- f->n = 0L;
- f->linep = f->line = (char *)fs_get((MAX_ESC_LEN + 1) * sizeof(char));
- }
-}
-
-
-
-/*
- * CONTROL CHARACTER FILTER - transmogrify control characters into their
- * corresponding string representations (you know, ^blah and such)...
- */
-
-/*
- * the simple filter transforms unknown control characters in the stream
- * into harmless strings.
- */
-void
-gf_control_filter(f, flg)
- FILTER_S *f;
- int flg;
-{
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
-
- while(GF_GETC(f, c)){
-
- if(iscntrl(c & 0x7f)
- && !(isspace((unsigned char) c)
- || c == '\016' || c == '\017' || c == '\033')){
- GF_PUTC(f->next, '^');
- GF_PUTC(f->next, c + '@');
- }
- else
- GF_PUTC(f->next, c);
- }
-
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
-}
-
-
-
-/*
- * LINEWRAP FILTER - insert CRLF's at end of nearest whitespace before
- * specified line width
- */
-
-
-typedef struct wrap_col_s {
- unsigned bold:1;
- unsigned uline:1;
- unsigned inverse:1;
- unsigned tags:1;
- unsigned do_indent:1;
- unsigned on_comma:1;
- unsigned quoted:1;
- COLOR_PAIR *color;
- short embedded,
- space_len;
- char *lineendp,
- space;
- int anchor;
- int wrap_col,
- wrap_max,
- indent;
- char special[256];
-} WRAP_S;
-
-
-#define WRAP_COL(F) (((WRAP_S *)(F)->opt)->wrap_col)
-#define WRAP_MAX_COL(F) (((WRAP_S *)(F)->opt)->wrap_max)
-#define WRAP_INDENT(F) (((WRAP_S *)(F)->opt)->indent)
-#define WRAP_DO_IND(F) (((WRAP_S *)(F)->opt)->do_indent)
-#define WRAP_COMMA(F) (((WRAP_S *)(F)->opt)->on_comma)
-#define WRAP_QUOTED(F) (((WRAP_S *)(F)->opt)->quoted)
-#define WRAP_TAGS(F) (((WRAP_S *)(F)->opt)->tags)
-#define WRAP_BOLD(F) (((WRAP_S *)(F)->opt)->bold)
-#define WRAP_ULINE(F) (((WRAP_S *)(F)->opt)->uline)
-#define WRAP_INVERSE(F) (((WRAP_S *)(F)->opt)->inverse)
-#define WRAP_COLOR(F) (((WRAP_S *)(F)->opt)->color)
-#define WRAP_LASTC(F) (((WRAP_S *)(F)->opt)->lineendp)
-#define WRAP_EMBED(F) (((WRAP_S *)(F)->opt)->embedded)
-#define WRAP_ANCHOR(F) (((WRAP_S *)(F)->opt)->anchor)
-#define WRAP_SPACE(F) (((WRAP_S *)(F)->opt)->space)
-#define WRAP_SPACES(F) (WRAP_SPACE(F) ? (((WRAP_S *)(F)->opt)->space_len): 0)
-#define WRAP_SPC_LEN(F) (((WRAP_S *)(F)->opt)->space_len)
-#define WRAP_SPEC(S, C) (S)[C]
-
-#define WRAP_EOL(F) { \
- if(WRAP_BOLD(F)){ \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_BOLDOFF); \
- } \
- if(WRAP_ULINE(F)){ \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_ULINEOFF); \
- } \
- if(WRAP_INVERSE(F) || WRAP_ANCHOR(F)){ \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_INVOFF); \
- } \
- if(WRAP_COLOR(F)){ \
- char *p; \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_FGCOLOR); \
- p = color_to_asciirgb(ps_global->VAR_NORM_FORE_COLOR);\
- for(; *p; p++) \
- GF_PUTC((F)->next, *p); \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_BGCOLOR); \
- p = color_to_asciirgb(ps_global->VAR_NORM_BACK_COLOR);\
- for(; *p; p++) \
- GF_PUTC((F)->next, *p); \
- } \
- GF_PUTC((F)->next, '\015'); \
- GF_PUTC((F)->next, '\012'); \
- f->n = 0L; \
- WRAP_SPACE(F) = 0; \
- }
-
-#define WRAP_BOL(F) { \
- if(WRAP_BOLD(F)){ \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_BOLDON); \
- } \
- if(WRAP_ULINE(F)){ \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_ULINEON); \
- } \
- if(WRAP_INVERSE(F)){ \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_INVON); \
- } \
- if(WRAP_COLOR(F)){ \
- char *p; \
- if(WRAP_COLOR(F)->fg[0]){ \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_FGCOLOR); \
- p = color_to_asciirgb(WRAP_COLOR(F)->fg);\
- for(; *p; p++) \
- GF_PUTC((F)->next, *p); \
- } \
- if(WRAP_COLOR(F)->bg[0]){ \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_BGCOLOR); \
- p = color_to_asciirgb(WRAP_COLOR(F)->bg);\
- for(; *p; p++) \
- GF_PUTC((F)->next, *p); \
- } \
- } \
- if(WRAP_ANCHOR(F)){ \
- char buf[64]; int i; \
- GF_PUTC((F)->next, TAG_EMBED); \
- GF_PUTC((F)->next, TAG_HANDLE); \
- sprintf(buf, "%d", WRAP_ANCHOR(F)); \
- GF_PUTC((F)->next, (int) strlen(buf)); \
- for(i = 0; buf[i]; i++) \
- GF_PUTC((F)->next, buf[i]); \
- } \
- }
-
-#define WRAP_PUTC(F,C) { \
- if((F)->linep == WRAP_LASTC(F)){ \
- size_t offset = (F)->linep - (F)->line; \
- fs_resize((void **) &(F)->line, \
- (2 * offset) * sizeof(char)); \
- (F)->linep = &(F)->line[offset]; \
- WRAP_LASTC(F) = &(F)->line[2*offset-1]; \
- } \
- *(F)->linep++ = (C); \
- }
-
-#define WRAP_FLUSH(F) { \
- register char *s = f->line; \
- register int n; \
- if(!f->n){ \
- if(WRAP_DO_IND(F)){ \
- if(f->n = (long)(n = WRAP_INDENT(F))) \
- while(n-- > 0) \
- GF_PUTC((F)->next, ' '); \
- WRAP_DO_IND(F) = 0; \
- } \
- WRAP_BOL(F); \
- } \
- if(WRAP_SPACE(F)){ \
- GF_PUTC(f->next, WRAP_SPACE(F)); \
- WRAP_SPACE(F) = 0; \
- f->n += WRAP_SPC_LEN(F); \
- } \
- for(n = f->linep - f->line; n > 0; n--){ \
- if(*s == TAG_EMBED){ \
- if(n-- > 0){ \
- GF_PUTC(f->next, TAG_EMBED); \
- switch(*++s){ \
- case TAG_BOLDON : \
- WRAP_BOLD(f) = 1; \
- break; \
- case TAG_BOLDOFF : \
- WRAP_BOLD(f) = 0; \
- break; \
- case TAG_ULINEON : \
- WRAP_ULINE(f) = 1; \
- break; \
- case TAG_ULINEOFF : \
- WRAP_ULINE(f) = 0; \
- break; \
- case TAG_INVOFF : \
- WRAP_ANCHOR(f) = 0; \
- break; \
- case TAG_HANDLE : \
- if(n-- > 0){ \
- int i = *++s; \
- GF_PUTC(f->next, TAG_HANDLE); \
- if(i <= n){ \
- n -= i; \
- GF_PUTC(f->next, i); \
- WRAP_ANCHOR(f) = 0; \
- while(1){ \
- WRAP_ANCHOR(f) \
- = (WRAP_ANCHOR(f) \
- * 10) \
- + (*++s-'0');\
- if(--i) \
- GF_PUTC(f->next,*s);\
- else \
- break; \
- } \
- } \
- } \
- break; \
- case TAG_FGCOLOR : \
- if(pico_usingcolor() \
- && n >= RGBLEN){ \
- if(!WRAP_COLOR(f)) \
- WRAP_COLOR(f)=new_color_pair(NULL,NULL); \
- strncpy(WRAP_COLOR(f)->fg, \
- s+1, RGBLEN); \
- WRAP_COLOR(f)->fg[RGBLEN]='\0'; \
- i = RGBLEN; \
- n -= i; \
- while(i-- > 0) \
- GF_PUTC(f->next, \
- (*s++) & 0xff); \
- } \
- break; \
- case TAG_BGCOLOR : \
- if(pico_usingcolor() \
- && n >= RGBLEN){ \
- if(!WRAP_COLOR(f)) \
- WRAP_COLOR(f)=new_color_pair(NULL,NULL); \
- strncpy(WRAP_COLOR(f)->bg,\
- s+1, RGBLEN); \
- WRAP_COLOR(f)->bg[RGBLEN]='\0'; \
- i = RGBLEN; \
- n -= i; \
- while(i-- > 0) \
- GF_PUTC(f->next, \
- (*s++) & 0xff); \
- } \
- break; \
- default : \
- break; \
- } \
- } \
- } \
- else \
- f->n++; \
- GF_PUTC(f->next, (*s++) & 0xff); \
- } \
- f->f2 = 0; \
- f->linep = f->line; \
- }
-
-
-
-
-/*
- * the simple filter, breaks lines at end of white space nearest
- * to global "gf_wrap_width" in length
- */
-void
-gf_wrap(f, flg)
- FILTER_S *f;
- int flg;
-{
- register long i;
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register int state = f->f1;
- int wrap_threshold = WRAP_MAX_COL(f) - WRAP_INDENT(f);
- char *special = ((WRAP_S *) f->opt)->special;
-
- while(GF_GETC(f, c)){
-
- switch(state){
- case CCR :
- state = DFL; /* CRLF or CR in text ? */
- WRAP_FLUSH(f); /* it's a newline to us */
- WRAP_EOL(f);
- WRAP_BOL(f);
- if(c == '\012') /* process anything but LF */
- break;
-
- case DFL :
- if(WRAP_SPEC(special, c))
- switch(c){
- default :
- if(WRAP_QUOTED(f))
- break;
-
- WRAP_FLUSH(f); /* flush buf */
- switch(WRAP_SPACE(f) = c){ /* remember separator */
- case ' ' :
- WRAP_SPC_LEN(f) = 1;
- break;
-
- case TAB :
- {
- int i = (int) f->n;
- while(++i & 0x07)
- ;
-
- WRAP_SPC_LEN(f) = i - (int) f->n;
- }
-
- break;
-
- default : /* some control char? */
- WRAP_SPC_LEN(f) = 2;
- break;
- }
-
- continue;
-
- case '\"' :
- WRAP_QUOTED(f) = !WRAP_QUOTED(f);
- break;
-
- case '\015' : /* already has newline? */
- state = CCR;
- continue;
-
- case '\012' : /* bare LF in text? */
- WRAP_FLUSH(f); /* they must've meant */
- WRAP_EOL(f); /* newline... */
- WRAP_BOL(f);
- continue;
-
- case (unsigned char) TAG_EMBED :
- WRAP_PUTC(f, TAG_EMBED);
- state = TAG;
- continue;
-
- case ',' :
- if(!WRAP_QUOTED(f)){
- WRAP_PUTC(f, ',');
- WRAP_FLUSH(f);
- WRAP_SPACE(f) = 0;
- continue;
- }
-
- break;
- }
-
- if(!f->n && (f->f2 >= wrap_threshold)){
- char *ep, *space = NULL;
- int cntr, new_f2;
-
- /* Flush the buf'd line up to last WS */
- if(WRAP_COMMA(f)){
- char *p;
-
- new_f2 = cntr = f->f2;
- for(p = f->line; p < f->linep; p++){
- /*
- * Don't split at WS which is in the middle
- * of a tag.
- */
- switch((unsigned char)*p){
- case (unsigned char)TAG_EMBED:
- if(++p >= f->linep)
- break;
-
- switch(*p){
- case TAG_FGCOLOR:
- case TAG_BGCOLOR:
- p += RGBLEN;
- break;
-
- case TAG_HANDLE:
- if(++p >= f->linep)
- break;
-
- p += (*p);
- break;
-
- default:
- break;
- }
-
- continue;
- break;
-
- default:
- break;
- }
-
- cntr--;
-
- if(p < f->linep && isspace((unsigned char)*p)){
- space = p;
- new_f2 = cntr;
- }
- }
-
- if(space){
- ep = f->linep;
- f->linep = space;
- }
- }
-
- WRAP_FLUSH(f); /* write buffered */
- WRAP_EOL(f); /* write end of line */
- WRAP_DO_IND(f) = 1; /* indent next line */
-
- if(space){
- f->linep = f->line;
- while(++space < ep)
- *f->linep++ = *space;
-
- f->f2 = new_f2;
- }
- }
-
- WRAP_PUTC(f, c);
-
- if(c == '\t' && WRAP_COMMA(f)){
- int i = (int) f->n;
- while(++i & 0x07)
- ;
-
- f->f2 += i - (int) f->n;
- }
- else
- f->f2++;
-
- if(f->n && (f->n + f->f2 + WRAP_SPACES(f) >= WRAP_COL(f))){
- WRAP_EOL(f); /* write end of line */
- WRAP_DO_IND(f) = 1; /* indent next line */
- }
-
- break;
-
- case TAG :
- WRAP_PUTC(f, c);
- switch(c){
- case TAG_HANDLE :
- WRAP_EMBED(f) = -1;
- state = HANDLE;
- break;
-
- case TAG_FGCOLOR :
- case TAG_BGCOLOR :
- WRAP_EMBED(f) = RGBLEN;
- state = HDATA;
- break;
-
- default :
- state = DFL;
- break;
- }
-
- break;
-
- case HANDLE :
- WRAP_PUTC(f, c);
- WRAP_EMBED(f) = c;
- state = HDATA;
- break;
-
- case HDATA :
- WRAP_PUTC(f, c);
- if(!(WRAP_EMBED(f) -= 1))
- state = DFL;
-
- break;
- }
- }
-
- f->f1 = state;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- WRAP_FLUSH(f);
- if(WRAP_COLOR(f))
- free_color_pair(&WRAP_COLOR(f));
-
- fs_give((void **) &f->line); /* free temp line buffer */
- fs_give((void **) &f->opt); /* free wrap widths struct */
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset wrap\n"));
- f->f1 = DFL;
- f->n = 0L; /* displayed length of line so far */
- f->f2 = 0; /* displayed length of buffered chars */
- if(! (WRAP_S *) f->opt)
- f->opt = gf_wrap_filter_opt(75, 80, 0, 0);
-
- while(WRAP_INDENT(f) >= WRAP_MAX_COL(f))
- WRAP_INDENT(f) /= 2;
-
- f->line = (char *) fs_get(WRAP_MAX_COL(f) * sizeof(char));
- f->linep = f->line;
- WRAP_LASTC(f) = &f->line[WRAP_MAX_COL(f) - 1];
-
- for(i = 0; i < 256; i++)
- ((WRAP_S *) f->opt)->special[i] = ((i == '\"' && WRAP_COMMA(f))
- || i == '\015'
- || i == '\012'
- || (i == (unsigned char) TAG_EMBED
- && WRAP_TAGS(f))
- || (i == ',' && WRAP_COMMA(f)
- && !WRAP_QUOTED(f))
- || (!WRAP_COMMA(f)
- && isspace((unsigned char) i)));
- }
-}
-
-
-/*
- * function called from the outside to set
- * wrap filter's width option
- */
-void *
-gf_wrap_filter_opt(width, width_max, indent, flags)
- int width, width_max, indent, flags;
-{
- WRAP_S *wrap;
-
- wrap = (WRAP_S *) fs_get(sizeof(WRAP_S));
- memset(wrap, 0, sizeof(WRAP_S));
- wrap->wrap_col = width;
- wrap->wrap_max = width_max;
- wrap->indent = indent;
- wrap->tags = (GFW_HANDLES & flags) == GFW_HANDLES;
- wrap->on_comma = (GFW_ONCOMMA & flags) == GFW_ONCOMMA;
- return((void *) wrap);
-}
-
-
-
-
-/*
- * LINE PREFIX FILTER - insert given text at beginning of each
- * line
- */
-
-
-#define GF_PREFIX_WRITE(s) { \
- register char *p; \
- if(p = (s)) \
- while(*p) \
- GF_PUTC(f->next, *p++); \
- }
-
-
-/*
- * the simple filter, prepends each line with the requested prefix.
- * if prefix is null, does nothing, and as with all filters, assumes
- * NVT end of lines.
- */
-void
-gf_prefix(f, flg)
- FILTER_S *f;
- int flg;
-{
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register int state = f->f1;
- register int first = f->f2;
-
- while(GF_GETC(f, c)){
-
- if(first){ /* write initial prefix!! */
- first = 0; /* but just once */
- GF_PREFIX_WRITE((char *) f->opt);
- }
- else if(state){
- state = 0;
- GF_PUTC(f->next, '\015');
- if(c == '\012'){
- GF_PUTC(f->next, '\012');
- GF_PREFIX_WRITE((char *) f->opt);
- continue;
- }
- /* else fall thru to handle 'c' */
- }
-
- if(c == '\015') /* already has newline? */
- state = 1;
- else
- GF_PUTC(f->next, c);
- }
-
- f->f1 = state;
- f->f2 = first;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset prefix\n"));
- f->f1 = 0;
- f->f2 = 1; /* nothing written yet */
- }
-}
-
-
-/*
- * function called from the outside to set
- * prefix filter's prefix string
- */
-void *
-gf_prefix_opt(prefix)
- char *prefix;
-{
- return((void *) prefix);
-}
-
-
-/*
- * LINE TEST FILTER - accumulate lines and offer each to the provided
- * test function.
- */
-
-typedef struct _linetest_s {
- linetest_t f;
- void *local;
-} LINETEST_S;
-
-
-/* accumulator growth increment */
-#define LINE_TEST_BLOCK 1024
-
-#define GF_LINE_TEST_EOB(f) \
- ((f)->line + ((f)->f2 - 1))
-
-#define GF_LINE_TEST_ADD(f, c) \
- { \
- if(p >= eobuf){ \
- f->f2 += LINE_TEST_BLOCK; \
- fs_resize((void **)&f->line, \
- (size_t) f->f2 * sizeof(char)); \
- eobuf = GF_LINE_TEST_EOB(f); \
- p = eobuf - LINE_TEST_BLOCK; \
- } \
- *p++ = c; \
- }
-
-#define GF_LINE_TEST_TEST(F, D) \
- { \
- unsigned char c; \
- register char *cp; \
- register int l; \
- LT_INS_S *ins = NULL, *insp; \
- *p = '\0'; \
- (D) = (*((LINETEST_S *) (F)->opt)->f)((F)->n++, \
- (F)->line, &ins, \
- ((LINETEST_S *) (F)->opt)->local); \
- if((D) < 2){ \
- for(insp = ins, cp = (F)->line; cp < p; ){ \
- while(insp && cp == insp->where){ \
- for(l = 0; l < insp->len; l++){ \
- c = (unsigned char) insp->text[l];\
- GF_PUTC((F)->next, c); \
- } \
- insp = insp->next; \
- } \
- GF_PUTC((F)->next, *cp); \
- cp++; \
- } \
- while(insp){ \
- for(l = 0; l < insp->len; l++){ \
- c = (unsigned char) insp->text[l]; \
- GF_PUTC((F)->next, c); \
- } \
- insp = insp->next; \
- } \
- gf_line_test_free_ins(&ins); \
- } \
- }
-
-
-
-/*
- * this simple filter accumulates characters until a newline, offers it
- * to the provided test function, and then passes it on. It assumes
- * NVT EOLs.
- */
-void
-gf_line_test(f, flg)
- FILTER_S *f;
- int flg;
-{
- register char *p = f->linep;
- register char *eobuf = GF_LINE_TEST_EOB(f);
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register int state = f->f1;
-
- while(GF_GETC(f, c)){
-
- if(state){
- state = 0;
- if(c == '\012'){
- int done;
-
- GF_LINE_TEST_TEST(f, done);
-
- p = (f)->line;
-
- if(done == 2) /* skip this line! */
- continue;
-
- GF_PUTC(f->next, '\015');
- GF_PUTC(f->next, '\012');
- /*
- * if the line tester returns TRUE, it's
- * telling us its seen enough and doesn't
- * want to see any more. Remove ourself
- * from the pipeline...
- */
- if(done){
- if(gf_master == f){
- gf_master = f->next;
- }
- else{
- FILTER_S *fprev;
-
- for(fprev = gf_master;
- fprev && fprev->next != f;
- fprev = fprev->next)
- ;
-
- if(fprev) /* wha??? */
- fprev->next = f->next;
- else
- continue;
- }
-
- while(GF_GETC(f, c)) /* pass input */
- GF_PUTC(f->next, c);
-
- GF_FLUSH(f->next); /* and drain queue */
- fs_give((void **)&f->line);
- fs_give((void **)&f); /* wax our data */
- return;
- }
- else
- continue;
- }
- else /* add CR to buffer */
- GF_LINE_TEST_ADD(f, '\015');
- } /* fall thru to handle 'c' */
-
- if(c == '\015') /* newline? */
- state = 1;
- else
- GF_LINE_TEST_ADD(f, c);
- }
-
- f->f1 = state;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- int i;
-
- GF_LINE_TEST_TEST(f, i); /* examine remaining data */
- fs_give((void **) &f->line); /* free line buffer */
- fs_give((void **) &f->opt); /* free test struct */
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset line_test\n"));
- f->f1 = 0; /* state */
- f->n = 0L; /* line number */
- f->f2 = LINE_TEST_BLOCK; /* size of alloc'd line */
- f->line = p = (char *) fs_get(f->f2 * sizeof(char));
- }
-
- f->linep = p;
-}
-
-
-/*
- * function called from the outside to operate on accumulated line.
- */
-void *
-gf_line_test_opt(test_f, local)
- linetest_t test_f;
- void *local;
-{
- LINETEST_S *ltp;
-
- ltp = (LINETEST_S *) fs_get(sizeof(LINETEST_S));
- memset(ltp, 0, sizeof(LINETEST_S));
- ltp->f = test_f;
- ltp->local = local;
- return((void *) ltp);
-}
-
-
-
-LT_INS_S **
-gf_line_test_new_ins(ins, p, s, n)
- LT_INS_S **ins;
- char *p, *s;
- int n;
-{
- *ins = (LT_INS_S *) fs_get(sizeof(LT_INS_S));
- if((*ins)->len = n)
- strncpy((*ins)->text = (char *) fs_get(n * sizeof(char)), s, n);
-
- (*ins)->where = p;
- (*ins)->next = NULL;
- return(&(*ins)->next);
-}
-
-
-void
-gf_line_test_free_ins(ins)
- LT_INS_S **ins;
-{
- if(ins && *ins){
- if((*ins)->next)
- gf_line_test_free_ins(&(*ins)->next);
-
- if((*ins)->text)
- fs_give((void **) &(*ins)->text);
-
- fs_give((void **) ins);
- }
-}
-
-
-/*
- * Network virtual terminal to local newline convention filter
- */
-void
-gf_nvtnl_local(f, flg)
- FILTER_S *f;
- int flg;
-{
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
- register int state = f->f1;
-
- while(GF_GETC(f, c)){
- if(state){
- state = 0;
- if(c == '\012'){
- GF_PUTC(f->next, '\012');
- continue;
- }
- else
- GF_PUTC(f->next, '\015');
- /* fall thru to deal with 'c' */
- }
-
- if(c == '\015')
- state = 1;
- else
- GF_PUTC(f->next, c);
- }
-
- f->f1 = state;
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset nvtnl_local\n"));
- f->f1 = 0;
- }
-}
-
-
-/*
- * local to network newline convention filter
- */
-void
-gf_local_nvtnl(f, flg)
- FILTER_S *f;
- int flg;
-{
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
-
- while(GF_GETC(f, c)){
- if(c == '\012'){
- GF_PUTC(f->next, '\015');
- GF_PUTC(f->next, '\012');
- }
- else
- GF_PUTC(f->next, c);
- }
-
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(GF_RESET){
- dprint(9, (debugfile, "-- gf_reset local_nvtnl\n"));
- /* no op */
- }
-
-}
-
-#if defined(DOS) || defined(OS2)
-/*
- * DOS CodePage to Character Set Translation (and back) filters
- */
-
-/*
- * Charset and CodePage mapping table pointer and length
- */
-static unsigned char *gf_xlate_tab;
-static unsigned gf_xlate_tab_len;
-
-/*
- * the simple filter takes DOS Code Page values and maps them into
- * the indicated external CharSet mapping or vice-versa.
- */
-void
-gf_translate(f, flg)
- FILTER_S *f;
- int flg;
-{
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
-
- while(GF_GETC(f, c))
- if((unsigned long) c < ((SIZEDTEXT *) (f->opt))->size)
- GF_PUTC(f->next, (int) ((SIZEDTEXT *) (f->opt))->data[c]);
-
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- fs_give((void **) &f->opt); /* free up table description */
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(GF_RESET){
- dprint(9, (debugfile, "-- gf_reset translate\n"));
- }
-}
-
-
-/*
- * function called from the outside to set
- * prefix filter's prefix string
- */
-void *
-gf_translate_opt(xlatetab, xlatetablen)
- unsigned char *xlatetab;
- unsigned xlatetablen;
-{
- SIZEDTEXT *xlate_tab = (SIZEDTEXT *) fs_get(sizeof(SIZEDTEXT));
-
- xlate_tab->data = xlatetab;
- xlate_tab->size = (unsigned long) xlatetablen;
-
- return((void *) xlate_tab);
-}
-#endif
-
-/*
- * display something indicating we're chewing on something
- *
- * NOTE : IF ANY OTHER FILTERS WRITE THE DISPLAY, THIS WILL NEED FIXING
- */
-void
-gf_busy(f, flg)
- FILTER_S *f;
- int flg;
-{
- static short x = 0;
- GF_INIT(f, f->next);
-
- if(flg == GF_DATA){
- register unsigned char c;
-
- while(GF_GETC(f, c)){
-
- if(!((++(f->f1))&0x7ff)){ /* ding the bell every 2K chars */
- MoveCursor(0, 1);
- f->f1 = 0;
- if((++x)&0x04) x = 0;
- Writechar((x == 0) ? '/' : /* CHEATING! */
- (x == 1) ? '-' :
- (x == 2) ? '\\' : '|', 0);
- }
-
- GF_PUTC(f->next, c);
- }
-
- GF_END(f, f->next);
- }
- else if(flg == GF_EOD){
- MoveCursor(0, 1);
- Writechar(' ', 0);
- EndInverse();
- GF_FLUSH(f->next);
- (*f->next->f)(f->next, GF_EOD);
- }
- else if(flg == GF_RESET){
- dprint(9, (debugfile, "-- gf_reset busy\n"));
- f->f1 = 0;
- x = 0;
- StartInverse();
- }
-
- fflush(stdout);
-}
diff --git a/net-mail/pine/files/os.c b/net-mail/pine/files/os.c
deleted file mode 100644
index 2fd967904207..000000000000
--- a/net-mail/pine/files/os.c
+++ /dev/null
@@ -1,5673 +0,0 @@
-/*----------------------------------------------------------------------
-
- T H E P I N E M A I L S Y S T E M
-
- Laurence Lundblade and Mike Seibel
- Networks and Distributed Computing
- Computing and Communications
- University of Washington
- Administration Builiding, AG-44
- Seattle, Washington, 98195, USA
- Internet: lgl@CAC.Washington.EDU
- mikes@CAC.Washington.EDU
-
- Please address all bugs and comments to "pine-bugs@cac.washington.edu"
-
-
- Pine and Pico are registered trademarks of the University of Washington.
- No commercial use of these trademarks may be made without prior written
- permission of the University of Washington.
-
- Pine, Pico, and Pilot software and its included text are Copyright
- 1989-1998 by the University of Washington.
-
- The full text of our legal notices is contained in the file called
- CPYRIGHT, included with this distribution.
-
-
- Pine is in part based on The Elm Mail System:
- ***********************************************************************
- * The Elm Mail System - Revision: 2.13 *
- * *
- * Copyright (c) 1986, 1987 Dave Taylor *
- * Copyright (c) 1988, 1989 USENET Community Trust *
- ***********************************************************************
-
-
- ----------------------------------------------------------------------*/
-
-/*======================================================================
-
- This contains most of Pine's interface to the local operating system
-and hardware. Hopefully this file, os-xxx.h and makefile.xxx are the
-only ones that have to be modified for most ports. Signals.c, ttyin.c,
-and ttyout.c also have some dependencies. See the doc/tech-notes for
-notes on porting Pine to other platforms. Here is a list of the functions
-required for an implementation:
-
-
- File System Access
- can_access -- See if a file can be accessed
- name_file_size -- Return the number of bytes in the file (by name)
- fp_file_size -- Return the number of bytes in the file (by FILE *)
- name_file_mtime -- Return the mtime of a file (by name)
- fp_file_mtime -- Return the mtime of a file (by FILE *)
- file_attrib_copy -- Copy attributes of one file to another.
- is_writable_dir -- Check to see if directory exists and is writable
- create_mail_dir -- Make a directory
- rename_file -- change name of a file
- build_path -- Put together a file system path
- last_cmpnt -- Returns pointer to last component of path
- expand_foldername -- Expand a folder name to full path
- fnexpand -- Do filename exansion for csh style "~"
- filter_filename -- Make sure file name hasn't got weird chars
- cntxt_allowed -- Check whether a pathname is allowed for read/write
- disk_quota -- Check the user's disk quota
- read_file -- Read whole file into memory (for small files)
- create_tmpfile -- Just like ANSI C tmpfile function
- temp_nam -- Almost like common tempnam function
- fget_pos,fset_pos -- Just like ANSI C fgetpos, fsetpos functions
-
- Abort
- coredump -- Abort running Pine dumping core if possible
-
- System Name and Domain
- hostname -- Figure out the system's host name, only
- used internally in this file.
- getdomainnames -- Figure out the system's domain name
- canonical_name -- Returns canonical form of host name
-
- Job Control
- have_job_control -- Returns 1 if job control exists
- stop_process -- What to do to stop process when it's time to stop
- (only used if have_job_control returns 1)
-
- System Error Messages (in case given one is a problem)
- error_description -- Returns string describing error
-
- System Password and Accounts
- gcos_name -- Parses full name from system, only used
- locally in this file so if you don't use it you
- don't need it
- get_user_info -- Finds in login name, full name, and homedir
- local_name_lookup -- Get full name of user on system
- change_passwd -- Calls system password changer
-
- MIME utilities
- mime_can_display -- Can we display this type/subtype?
- exec_mailcap_cmd -- Run the mailcap command to view a type/subtype.
- exec_mailcap_test_cmd -- Run mailcap test= test command.
-
- Other stuff
- srandom -- Dummy srandom if you don't have this function
- init_debug
- do_debug
- save_debug_on_crash
-
- ====*/
-
-
-#include "headers.h"
-
-
-
-/*----------------------------------------------------------------------
- Check if we can access a file in a given way
-
- Args: file -- The file to check
- mode -- The mode ala the access() system call, see ACCESS_EXISTS
- and friends in pine.h.
-
- Result: returns 0 if the user can access the file according to the mode,
- -1 if he can't (and errno is set).
- ----*/
-int
-can_access(file, mode)
- char *file;
- int mode;
-{
- return(access(file, mode));
-}
-
-
-/*----------------------------------------------------------------------
- Check if we can access a file in a given way in the given path
-
- Args: path -- The path to look for "file" in
- file -- The file to check
- mode -- The mode ala the access() system call, see ACCESS_EXISTS
- and friends in pine.h.
-
- Result: returns 0 if the user can access the file according to the mode,
- -1 if he can't (and errno is set).
- ----*/
-can_access_in_path(path, file, mode)
- char *path, *file;
- int mode;
-{
- char tmp[MAXPATH], *path_copy, *p, *t;
- int rv = -1;
-
- if(!path || !*path || *file == '/'){
- rv = access(file, mode);
- }
- else if(*file == '~'){
- strcpy(tmp, file);
- rv = fnexpand(tmp, sizeof(tmp)) ? access(tmp, mode) : -1;
- }
- else{
- for(p = path_copy = cpystr(path); p && *p; p = t){
- if(t = strindex(p, ':'))
- *t++ = '\0';
-
- sprintf(tmp, "%s/%s", p, file);
- if((rv = access(tmp, mode)) == 0)
- break;
- }
-
- fs_give((void **)&path_copy);
- }
-
- return(rv);
-}
-
-/*----------------------------------------------------------------------
- Return the number of bytes in given file
-
- Args: file -- file name
-
- Result: the number of bytes in the file is returned or
- -1 on error, in which case errno is valid
- ----*/
-long
-name_file_size(file)
- char *file;
-{
- struct stat buffer;
-
- if(stat(file, &buffer) != 0)
- return(-1L);
-
- return((long)buffer.st_size);
-}
-
-
-/*----------------------------------------------------------------------
- Return the number of bytes in given file
-
- Args: fp -- FILE * for open file
-
- Result: the number of bytes in the file is returned or
- -1 on error, in which case errno is valid
- ----*/
-long
-fp_file_size(fp)
- FILE *fp;
-{
- struct stat buffer;
-
- if(fstat(fileno(fp), &buffer) != 0)
- return(-1L);
-
- return((long)buffer.st_size);
-}
-
-
-/*----------------------------------------------------------------------
- Return the modification time of given file
-
- Args: file -- file name
-
- Result: the time of last modification (mtime) of the file is returned or
- -1 on error, in which case errno is valid
- ----*/
-time_t
-name_file_mtime(file)
- char *file;
-{
- struct stat buffer;
-
- if(stat(file, &buffer) != 0)
- return((time_t)(-1));
-
- return(buffer.st_mtime);
-}
-
-
-/*----------------------------------------------------------------------
- Return the modification time of given file
-
- Args: fp -- FILE * for open file
-
- Result: the time of last modification (mtime) of the file is returned or
- -1 on error, in which case errno is valid
- ----*/
-time_t
-fp_file_mtime(fp)
- FILE *fp;
-{
- struct stat buffer;
-
- if(fstat(fileno(fp), &buffer) != 0)
- return((time_t)(-1));
-
- return(buffer.st_mtime);
-}
-
-
-/*----------------------------------------------------------------------
- Copy the mode, owner, and group of sourcefile to targetfile.
-
- Args: targetfile --
- sourcefile --
-
- We don't bother keeping track of success or failure because we don't care.
- ----*/
-void
-file_attrib_copy(targetfile, sourcefile)
- char *targetfile;
- char *sourcefile;
-{
- struct stat buffer;
-
- if(stat(sourcefile, &buffer) == 0){
- chmod(targetfile, buffer.st_mode);
-#if !defined(DOS) && !defined(OS2)
- chown(targetfile, buffer.st_uid, buffer.st_gid);
-#endif
- }
-}
-
-
-
-/*----------------------------------------------------------------------
- Check to see if a directory exists and is writable by us
-
- Args: dir -- directory name
-
- Result: returns 0 if it exists and is writable
- 1 if it is a directory, but is not writable
- 2 if it is not a directory
- 3 it doesn't exist.
- ----*/
-is_writable_dir(dir)
- char *dir;
-{
- struct stat sb;
-
- if(stat(dir, &sb) < 0)
- /*--- It doesn't exist ---*/
- return(3);
-
- if(!(sb.st_mode & S_IFDIR))
- /*---- it's not a directory ---*/
- return(2);
-
- if(can_access(dir, 07))
- return(1);
- else
- return(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Create the mail subdirectory.
-
- Args: dir -- Name of the directory to create
-
- Result: Directory is created. Returns 0 on success, else -1 on error
- and errno is valid.
- ----*/
-create_mail_dir(dir)
- char *dir;
-{
- if(mkdir(dir, 0700) < 0)
- return(-1);
-
- (void)chmod(dir, 0700);
- /* Some systems need this, on others we don't care if it fails */
- (void)chown(dir, getuid(), getgid());
- return(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Rename a file
-
- Args: tmpfname -- Old name of file
- fname -- New name of file
-
- Result: File is renamed. Returns 0 on success, else -1 on error
- and errno is valid.
- ----*/
-rename_file(tmpfname, fname)
- char *tmpfname, *fname;
-{
- return(rename(tmpfname, fname));
-}
-
-
-
-/*----------------------------------------------------------------------
- Paste together two pieces of a file name path
-
- Args: pathbuf -- Put the result here
- first_part -- of path name
- second_part -- of path name
-
- Result: New path is in pathbuf. No check is made for overflow. Note that
- we don't have to check for /'s at end of first_part and beginning
- of second_part since multiple slashes are ok.
-
-BUGS: This is a first stab at dealing with fs naming dependencies, and others
-still exist.
- ----*/
-void
-build_path(pathbuf, first_part, second_part)
- char *pathbuf, *first_part, *second_part;
-{
- if(!first_part)
- strcpy(pathbuf, second_part);
- else
- sprintf(pathbuf, "%s%s%s", first_part,
- (*first_part && first_part[strlen(first_part)-1] != '/')
- ? "/" : "",
- second_part);
-}
-
-
-/*----------------------------------------------------------------------
- Test to see if the given file path is absolute
-
- Args: file -- file path to test
-
- Result: TRUE if absolute, FALSE otw
-
- ----*/
-int
-is_absolute_path(path)
- char *path;
-{
- return(path && (*path == '/' || *path == '~'));
-}
-
-
-
-/*----------------------------------------------------------------------
- Return pointer to last component of pathname.
-
- Args: filename -- The pathname.
-
- Result: Returned pointer points to last component in the input argument.
- ----*/
-char *
-last_cmpnt(filename)
- char *filename;
-{
- register char *p = NULL, *q = filename;
-
- while(q = strchr(q, '/'))
- if(*++q)
- p = q;
-
- return(p);
-}
-
-
-
-/*----------------------------------------------------------------------
- Expand a folder name, taking account of the folders_dir and `~'.
-
- Args: filename -- The name of the file that is the folder
-
- Result: The folder name is expanded in place.
- Returns 0 and queues status message if unsuccessful.
- Input string is overwritten with expanded name.
- Returns 1 if successful.
-
-BUG should limit length to MAXPATH
- ----*/
-int
-expand_foldername(filename)
- char *filename;
-{
- char temp_filename[MAXPATH+1];
-
- dprint(5, (debugfile, "=== expand_foldername called (%s) ===\n",filename));
-
- /*
- * We used to check for valid filename chars here if "filename"
- * didn't refer to a remote mailbox. This has been rethought
- */
-
- strcpy(temp_filename, filename);
- if(strucmp(temp_filename, "inbox") == 0) {
- strcpy(filename, ps_global->VAR_INBOX_PATH == NULL ? "inbox" :
- ps_global->VAR_INBOX_PATH);
- } else if(temp_filename[0] == '{') {
- strcpy(filename, temp_filename);
- } else if(ps_global->restricted
- && (strindex("./~", temp_filename[0]) != NULL
- || srchstr(temp_filename,"/../"))){
- q_status_message(SM_ORDER, 0, 3, "Can only open local folders");
- return(0);
- } else if(temp_filename[0] == '*') {
- strcpy(filename, temp_filename);
- } else if(ps_global->VAR_OPER_DIR && srchstr(temp_filename,"..")){
- q_status_message(SM_ORDER, 0, 3,
- "\"..\" not allowed in folder name");
- return(0);
- } else if (temp_filename[0] == '~'){
- if(fnexpand(temp_filename, sizeof(temp_filename)) == NULL) {
- char *p = strindex(temp_filename, '/');
- if(p != NULL)
- *p = '\0';
- q_status_message1(SM_ORDER, 3, 3,
- "Error expanding folder name: \"%s\" unknown user",
- temp_filename);
- return(0);
- }
- strcpy(filename, temp_filename);
- } else if(temp_filename[0] == '/') {
- strcpy(filename, temp_filename);
- } else if(F_ON(F_USE_CURRENT_DIR, ps_global)){
- strcpy(filename, temp_filename);
- } else if(ps_global->VAR_OPER_DIR){
- build_path(filename, ps_global->VAR_OPER_DIR, temp_filename);
- } else {
- build_path(filename, ps_global->home_dir, temp_filename);
- }
- dprint(5, (debugfile, "returning \"%s\"\n", filename));
- return(1);
-}
-
-
-
-struct passwd *getpwnam();
-
-/*----------------------------------------------------------------------
- Expand the ~ in a file ala the csh (as home directory)
-
- Args: buf -- The filename to expand (nothing happens unless begins with ~)
- len -- The length of the buffer passed in (expansion is in place)
-
- Result: Expanded string is returned using same storage as passed in.
- If expansion fails, NULL is returned
- ----*/
-char *
-fnexpand(buf, len)
- char *buf;
- int len;
-{
- struct passwd *pw;
- register char *x,*y;
- char name[20];
-
- if(*buf == '~') {
- for(x = buf+1, y = name; *x != '/' && *x != '\0'; *y++ = *x++);
- *y = '\0';
- if(x == buf + 1)
- pw = getpwuid(getuid());
- else
- pw = getpwnam(name);
- if(pw == NULL)
- return((char *)NULL);
- if(strlen(pw->pw_dir) + strlen(buf) > len) {
- return((char *)NULL);
- }
- rplstr(buf, x - buf, pw->pw_dir);
- }
- return(len ? buf : (char *)NULL);
-}
-
-
-
-/*----------------------------------------------------------------------
- Filter file names for strange characters
-
- Args: file -- the file name to check
-
- Result: Returns NULL if file name is OK
- Returns formatted error message if it is not
- ----*/
-char *
-filter_filename(file, fatal)
- char *file;
- int *fatal;
-{
-#ifdef ALLOW_WEIRD
- static char illegal[] = {'\177', '\0'};
-#else
- static char illegal[] = {'"', '#', '$', '%', '&', '\'','(', ')','*',
- ',', ':', ';', '<', '=', '>', '?', '[', ']',
- '\\', '^', '|', '\177', '\0'};
-#endif
- static char error[100];
- char ill_file[MAXPATH+1], *ill_char, *ptr, e2[10];
- int i;
-
- for(ptr = file; *ptr == ' '; ptr++) ; /* leading spaces gone */
-
- while(*ptr && (unsigned char)(*ptr) >= ' ' && strindex(illegal, *ptr) == 0)
- ptr++;
-
- *fatal = TRUE;
- if(*ptr != '\0') {
- if(*ptr == '\n') {
- ill_char = "<newline>";
- } else if(*ptr == '\r') {
- ill_char = "<carriage return>";
- } else if(*ptr == '\t') {
- ill_char = "<tab>";
- *fatal = FALSE; /* just whitespace */
- } else if(*ptr < ' ') {
- sprintf(e2, "control-%c", *ptr + '@');
- ill_char = e2;
- } else if (*ptr == '\177') {
- ill_char = "<del>";
- } else {
- e2[0] = *ptr;
- e2[1] = '\0';
- ill_char = e2;
- *fatal = FALSE; /* less offensive? */
- }
- if(!*fatal){
- strcpy(error, ill_char);
- }
- else if(ptr != file) {
- strncpy(ill_file, file, ptr - file);
- ill_file[ptr - file] = '\0';
- sprintf(error,
- "Character \"%s\" after \"%s\" not allowed in file name",
- ill_char, ill_file);
- } else {
- sprintf(error,
- "First character, \"%s\", not allowed in file name",
- ill_char);
- }
-
- return(error);
- }
-
- if((i=is_writable_dir(file)) == 0 || i == 1){
- sprintf(error, "\"%s\" is a directory", file);
- return(error);
- }
-
- if(ps_global->restricted || ps_global->VAR_OPER_DIR){
- for(ptr = file; *ptr == ' '; ptr++) ; /* leading spaces gone */
-
- if((ptr[0] == '.' && ptr[1] == '.') || srchstr(ptr, "/../")){
- sprintf(error, "\"..\" not allowed in filename");
- return(error);
- }
- }
-
- return((char *)NULL);
-}
-
-
-/*----------------------------------------------------------------------
- Check to see if user is allowed to read or write this folder.
-
- Args: s -- the name to check
-
- Result: Returns 1 if OK
- Returns 0 and posts an error message if access is denied
- ----*/
-int
-cntxt_allowed(s)
- char *s;
-{
- struct variable *vars = ps_global->vars;
- int retval = 1;
- MAILSTREAM stream; /* fake stream for error message in mm_notify */
-
- if(ps_global->restricted
- && (strindex("./~", s[0]) || srchstr(s, "/../"))){
- stream.mailbox = s;
- mm_notify(&stream, "Restricted mode doesn't allow operation", WARN);
- retval = 0;
- }
- else if(VAR_OPER_DIR
- && s[0] != '{' && !(s[0] == '*' && s[1] == '{')
- && strucmp(s,ps_global->inbox_name) != 0
- && strcmp(s, ps_global->VAR_INBOX_PATH) != 0){
- char *p, *free_this = NULL;
-
- p = s;
- if(strindex(s, '~')){
- p = strindex(s, '~');
- free_this = (char *)fs_get(strlen(p) + 200);
- strcpy(free_this, p);
- fnexpand(free_this, strlen(p)+200);
- p = free_this;
- }
- else if(p[0] != '/'){ /* add home dir to relative paths */
- free_this = p = (char *)fs_get(strlen(s)
- + strlen(ps_global->home_dir) + 2);
- build_path(p, ps_global->home_dir, s);
- }
-
- if(!in_dir(VAR_OPER_DIR, p)){
- char err[200];
-
- sprintf(err, "Not allowed outside of %s", VAR_OPER_DIR);
- stream.mailbox = p;
- mm_notify(&stream, err, WARN);
- retval = 0;
- }
- else if(srchstr(p, "/../")){ /* check for .. in path */
- stream.mailbox = p;
- mm_notify(&stream, "\"..\" not allowed in name", WARN);
- retval = 0;
- }
-
- if(free_this)
- fs_give((void **)&free_this);
- }
-
- return retval;
-}
-
-
-
-#if defined(USE_QUOTAS)
-
-/*----------------------------------------------------------------------
- This system doesn't have disk quotas.
- Return space left in disk quota on file system which given path is in.
-
- Args: path - Path name of file or directory on file system of concern
- over - pointer to flag that is set if the user is over quota
-
- Returns: If *over = 0, the number of bytes free in disk quota as per
- the soft limit.
- If *over = 1, the number of bytes *over* quota.
- -1 is returned on an error looking up quota
- 0 is returned if there is no quota
-
-BUG: If there's more than 2.1Gb free this function will break
- ----*/
-long
-disk_quota(path, over)
- char *path;
- int *over;
-{
- return(0L);
-}
-#endif /* USE_QUOTAS */
-
-
-
-/*----------------------------------------------------------------------
- Read whole file into memory
-
- Args: filename -- path name of file to read
-
- Result: Returns pointer to malloced memory with the contents of the file
- or NULL
-
-This won't work very well if the file has NULLs in it and is mostly
-intended for fairly small text files.
- ----*/
-char *
-read_file(filename)
- char *filename;
-{
- int fd;
- struct stat statbuf;
- char *buf;
- int nb;
-
- fd = open(filename, O_RDONLY);
- if(fd < 0)
- return((char *)NULL);
-
- fstat(fd, &statbuf);
-
- buf = fs_get((size_t)statbuf.st_size + 1);
-
- /*
- * On some systems might have to loop here, if one read isn't guaranteed
- * to get the whole thing.
- */
- if((nb = read(fd, buf, (int)statbuf.st_size)) < 0)
- fs_give((void **)&buf); /* NULL's buf */
- else
- buf[nb] = '\0';
-
- close(fd);
- return(buf);
-}
-
-
-
-/*----------------------------------------------------------------------
- Create a temporary file, the name of which we don't care about
-and that goes away when it is closed. Just like ANSI C tmpfile.
- ----*/
-FILE *
-create_tmpfile()
-{
- return(tmpfile());
-}
-
-
-
-/*----------------------------------------------------------------------
- Abort with a core dump
- ----*/
-void
-coredump()
-{
- abort();
-}
-
-
-
-/*----------------------------------------------------------------------
- Call system gethostname
-
- Args: hostname -- buffer to return host name in
- size -- Size of buffer hostname is to be returned in
-
- Result: returns 0 if the hostname is correctly set,
- -1 if not (and errno is set).
- ----*/
-hostname(hostname,size)
- char *hostname;
- int size;
-{
- return(gethostname(hostname, size));
-}
-
-
-
-/*----------------------------------------------------------------------
- Get the current host and domain names
-
- Args: hostname -- buffer to return the hostname in
- hsize -- size of buffer above
- domainname -- buffer to return domain name in
- dsize -- size of buffer above
-
- Result: The system host and domain names are returned. If the full host
- name is akbar.cac.washington.edu then the domainname is
- cac.washington.edu.
-
-On Internet connected hosts this look up uses /etc/hosts and DNS to
-figure all this out. On other less well connected machines some other
-file may be read. If there is no notion of a domain name the domain
-name may be left blank. On a PC where there really isn't a host name
-this should return blank strings. The .pinerc will take care of
-configuring the domain names. That is, this should only return the
-native system's idea of what the names are if the system has such
-a concept.
- ----*/
-void
-getdomainnames(hostname, hsize, domainname, dsize)
- char *hostname, *domainname;
- int hsize, dsize;
-{
- char *dn, hname[MAX_ADDRESS+1];
- struct hostent *he;
- char **alias;
- char *maybe = NULL;
-
- gethostname(hname, MAX_ADDRESS);
- he = gethostbyname(hname);
- hostname[0] = '\0';
-
- if(he == NULL)
- strncpy(hostname, hname, hsize-1);
- else{
- /*
- * If no dot in hostname it may be the case that there
- * is an alias which is really the fully-qualified
- * hostname. This could happen if the administrator has
- * (incorrectly) put the unqualified name first in the
- * hosts file, for example. The problem with looking for
- * an alias with a dot is that now we're guessing, since
- * the aliases aren't supposed to be the official hostname.
- * We'll compromise and only use an alias if the primary
- * name has no dot and exactly one of the aliases has a
- * dot.
- */
- strncpy(hostname, he->h_name, hsize-1);
- if(strindex(hostname, '.') == NULL){ /* no dot in hostname */
- for(alias = he->h_aliases; *alias; alias++){
- if(strindex(*alias, '.') != NULL){ /* found one */
- if(maybe){ /* oops, this is the second one */
- maybe = NULL;
- break;
- }
- else
- maybe = *alias;
- }
- }
-
- if(maybe)
- strncpy(hostname, maybe, hsize-1);
- }
- }
-
- hostname[hsize-1] = '\0';
-
-
- if((dn = strindex(hostname, '.')) != NULL)
- strncpy(domainname, dn+1, dsize-1);
- else
- strncpy(domainname, hostname, dsize-1);
-
- domainname[dsize-1] = '\0';
-}
-
-
-
-/*----------------------------------------------------------------------
- Return canonical form of host name ala c-client (UNIX version).
-
- Args: host -- The host name
-
- Result: Canonical form, or input argument (worst case)
- ----*/
-char *
-canonical_name(host)
- char *host;
-{
- struct hostent *hent;
- char hostname[MAILTMPLEN];
- char tmp[MAILTMPLEN];
- extern char *lcase();
- /* domain literal is easy */
- if (host[0] == '[' && host[(strlen (host))-1] == ']')
- return host;
-
- strcpy (hostname,host); /* UNIX requires lowercase */
- /* lookup name, return canonical form */
- return (hent = gethostbyname (lcase (strcpy (tmp,host)))) ?
- hent->h_name : host;
-}
-
-
-
-/*----------------------------------------------------------------------
- This routine returns 1 if job control is available. Note, thiis
- could be some type of fake job control. It doesn't have to be
- real BSD-style job control.
- ----*/
-have_job_control()
-{
- return 1;
-}
-
-
-/*----------------------------------------------------------------------
- If we don't have job control, this routine is never called.
- ----*/
-stop_process()
-{
- SigType (*save_usr2) SIG_PROTO((int));
-
- /*
- * Since we can't respond to KOD while stopped, the process that sent
- * the KOD is going to go read-only. Therefore, we can safely ignore
- * any KODs that come in before we are ready to respond...
- */
- save_usr2 = signal(SIGUSR2, SIG_IGN);
- kill(0, SIGSTOP);
- (void)signal(SIGUSR2, save_usr2);
-}
-
-
-
-/*----------------------------------------------------------------------
- Return string describing the error
-
- Args: errnumber -- The system error number (errno)
-
- Result: long string describing the error is returned
- ----*/
-char *
-error_description(errnumber)
- int errnumber;
-{
- static char buffer[50+1];
-
- if(errnumber >= 0 && errnumber < sys_nerr)
- sprintf(buffer, "%.*s", 50, sys_errlist[errnumber]);
- else
- sprintf(buffer, "Unknown error #%d", errnumber);
-
- return ( (char *) buffer);
-}
-
-
-
-/*----------------------------------------------------------------------
- Pull the name out of the gcos field if we have that sort of /etc/passwd
-
- Args: gcos_field -- The long name or GCOS field to be parsed
- logname -- Replaces occurances of & with logname string
-
- Result: returns pointer to buffer with name
- ----*/
-static char *
-gcos_name(gcos_field, logname)
- char *logname, *gcos_field;
-{
- static char fullname[MAX_FULLNAME+1];
- register char *fncp, *gcoscp, *lncp, *end;
-
- /* full name is all chars up to first ',' (or whole gcos, if no ',') */
- /* replace any & with logname in upper case */
-
- for(fncp = fullname, gcoscp= gcos_field, end = fullname + MAX_FULLNAME - 1;
- (*gcoscp != ',' && *gcoscp != '\0' && fncp != end);
- gcoscp++) {
-
- if(*gcoscp == '&') {
- for(lncp = logname; *lncp; fncp++, lncp++)
- *fncp = toupper((unsigned char)(*lncp));
- } else {
- *fncp++ = *gcoscp;
- }
- }
-
- *fncp = '\0';
- return(fullname);
-}
-
-
-/*----------------------------------------------------------------------
- Fill in homedir, login, and fullname for the logged in user.
- These are all pointers to static storage so need to be copied
- in the caller.
-
- Args: ui -- struct pointer to pass back answers
-
- Result: fills in the fields
- ----*/
-void
-get_user_info(ui)
- struct user_info *ui;
-{
- struct passwd *unix_pwd;
-
- unix_pwd = getpwuid(getuid());
- if(unix_pwd == NULL) {
- ui->homedir = cpystr("");
- ui->login = cpystr("");
- ui->fullname = cpystr("");
- }else {
- ui->homedir = cpystr(unix_pwd->pw_dir);
- ui->login = cpystr(unix_pwd->pw_name);
- ui->fullname = cpystr(gcos_name(unix_pwd->pw_gecos, unix_pwd->pw_name));
- }
-}
-
-
-/*----------------------------------------------------------------------
- Look up a userid on the local system and return rfc822 address
-
- Args: name -- possible login name on local system
-
- Result: returns NULL or pointer to alloc'd string rfc822 address.
- ----*/
-char *
-local_name_lookup(name)
- char *name;
-{
- struct passwd *pw = getpwnam(name);
-
- if(pw == NULL){
- char *p;
-
- for(p = name; *p; p++)
- if(isupper((unsigned char)*p))
- break;
-
- /* try changing it to all lower case */
- if(p && *p){
- char *lcase;
-
- lcase = cpystr(name);
- for(p = lcase; *p; p++)
- if(isupper((unsigned char)*p))
- *p = tolower((unsigned char)*p);
-
- pw = getpwnam(lcase);
-
- if(pw)
- strcpy(name, lcase);
-
- fs_give((void **)&lcase);
- }
- }
-
- if(pw == NULL)
- return((char *)NULL);
-
- return(cpystr(gcos_name(pw->pw_gecos, name)));
-}
-
-
-
-/*----------------------------------------------------------------------
- Call the system to change the passwd
-
-It would be nice to talk to the passwd program via a pipe or ptty so the
-user interface could be consistent, but we can't count on the the prompts
-and responses from the passwd program to be regular so we just let the user
-type at the passwd program with some screen space, hope he doesn't scroll
-off the top and repaint when he's done.
- ----*/
-change_passwd()
-{
- char cmd_buf[100];
-
- ClearLines(1, ps_global->ttyo->screen_rows - 1);
-
- MoveCursor(5, 0);
- fflush(stdout);
-
- PineRaw(0);
- strcpy(cmd_buf, PASSWD_PROG);
- system(cmd_buf);
- sleep(3);
- PineRaw(1);
-}
-
-
-
-/*----------------------------------------------------------------------
- Can we display this type/subtype?
-
- Args: type -- the MIME type to check
- subtype -- the MIME subtype
- params -- parameters
- use_viewer -- tell caller he should run external viewer cmd to view
-
- Result: Returns:
-
- MCD_NONE if we can't display this type at all
- MCD_INTERNAL if we can display it internally
- MCD_EXTERNAL if it can be displayed via an external viewer
-
- ----*/
-mime_can_display(type, subtype, params)
- int type;
- char *subtype;
- PARAMETER *params;
-{
- return((mailcap_can_display(type, subtype, params)
- ? MCD_EXTERNAL : MCD_NONE)
- | ((type == TYPETEXT || type == TYPEMESSAGE
- || MIME_VCARD(type,subtype))
- ? MCD_INTERNAL : MCD_NONE));
-}
-
-
-
-/*======================================================================
- pipe
-
- Initiate I/O to and from a process. These functions are similar to
- popen and pclose, but both an incoming stream and an output file are
- provided.
-
- ====*/
-
-#ifndef STDIN_FILENO
-#define STDIN_FILENO 0
-#endif
-#ifndef STDOUT_FILENO
-#define STDOUT_FILENO 1
-#endif
-#ifndef STDERR_FILENO
-#define STDERR_FILENO 2
-#endif
-
-
-/*
- * Defs to help fish child's exit status out of wait(2)
- */
-#ifdef HAVE_WAIT_UNION
-#define WaitType union wait
-#ifndef WIFEXITED
-#define WIFEXITED(X) (!(X).w_termsig) /* child exit by choice */
-#endif
-#ifndef WEXITSTATUS
-#define WEXITSTATUS(X) (X).w_retcode /* childs chosen exit value */
-#endif
-#else
-#define WaitType int
-#ifndef WIFEXITED
-#define WIFEXITED(X) (!((X) & 0xff)) /* low bits tell how it died */
-#endif
-#ifndef WEXITSTATUS
-#define WEXITSTATUS(X) (((X) >> 8) & 0xff) /* high bits tell exit value */
-#endif
-#endif
-
-
-/*
- * Global's to helpsignal handler tell us child's status has changed...
- */
-short child_signalled;
-short child_jump = 0;
-jmp_buf child_state;
-int child_pid;
-
-
-/*
- * Internal Protos
- */
-void pipe_error_cleanup PROTO((PIPE_S **, char *, char *, char *));
-void zot_pipe PROTO((PIPE_S **));
-static SigType pipe_alarm SIG_PROTO((int));
-
-
-
-
-/*----------------------------------------------------------------------
- Spawn a child process and optionally connect read/write pipes to it
-
- Args: command -- string to hand the shell
- outfile -- address of pointer containing file to receive output
- errfile -- address of pointer containing file to receive error output
- mode -- mode for type of shell, signal protection etc...
- Returns: pointer to alloc'd PIPE_S on success, NULL otherwise
-
- The outfile is either NULL, a pointer to a NULL value, or a pointer
- to the requested name for the output file. In the pointer-to-NULL case
- the caller doesn't care about the name, but wants to see the pipe's
- results so we make one up. It's up to the caller to make sure the
- free storage containing the name is cleaned up.
-
- Mode bits serve several purposes.
- PIPE_WRITE tells us we need to open a pipe to write the child's
- stdin.
- PIPE_READ tells us we need to open a pipe to read from the child's
- stdout/stderr. *NOTE* Having neither of the above set means
- we're not setting up any pipes, just forking the child and exec'ing
- the command. Also, this takes precedence over any named outfile.
- PIPE_STDERR means we're to tie the childs stderr to the same place
- stdout is going. *NOTE* This only makes sense then if PIPE_READ
- or an outfile is provided. Also, this takes precedence over any
- named errfile.
- PIPE_PROT means to protect the child from the usual nasty signals
- that might cause premature death. Otherwise, the default signals are
- set so the child can deal with the nasty signals in its own way.
- PIPE_NOSHELL means we're to exec the command without the aid of
- a system shell. *NOTE* This negates the affect of PIPE_USER.
- PIPE_USER means we're to try executing the command in the user's
- shell. Right now we only look in the environment, but that may get
- more sophisticated later.
- PIPE_RESET means we reset the terminal mode to what it was before
- we started pine and then exec the command.
- ----*/
-PIPE_S *
-open_system_pipe(command, outfile, errfile, mode, timeout)
- char *command;
- char **outfile, **errfile;
- int mode, timeout;
-{
- PIPE_S *syspipe = NULL;
- char shellpath[32], *shell;
- int p[2], oparentd = -1, ochildd = -1, iparentd = -1, ichildd = -1;
-
- dprint(5, (debugfile, "Opening pipe: \"%s\" (%s%s%s%s%s%s)\n", command,
- (mode & PIPE_WRITE) ? "W":"", (mode & PIPE_READ) ? "R":"",
- (mode & PIPE_NOSHELL) ? "N":"", (mode & PIPE_PROT) ? "P":"",
- (mode & PIPE_USER) ? "U":"", (mode & PIPE_RESET) ? "T":""));
-
- syspipe = (PIPE_S *)fs_get(sizeof(PIPE_S));
- memset(syspipe, 0, sizeof(PIPE_S));
-
- /*
- * If we're not using the shell's command parsing smarts, build
- * argv by hand...
- */
- if(mode & PIPE_NOSHELL){
- char **ap, *p;
- size_t n;
-
- /* parse the arguments into argv */
- for(p = command; *p && isspace((unsigned char)(*p)); p++)
- ; /* swallow leading ws */
-
- if(*p){
- syspipe->args = cpystr(p);
- }
- else{
- pipe_error_cleanup(&syspipe, "<null>", "execute",
- "No command name found");
- return(NULL);
- }
-
- for(p = syspipe->args, n = 2; *p; p++) /* count the args */
- if(isspace((unsigned char)(*p))
- && *(p+1) && !isspace((unsigned char)(*(p+1))))
- n++;
-
- syspipe->argv = ap = (char **)fs_get(n * sizeof(char *));
- memset(syspipe->argv, 0, n * sizeof(char *));
-
- for(p = syspipe->args; *p; ){ /* collect args */
- while(*p && isspace((unsigned char)(*p)))
- *p++ = '\0';
-
- *ap++ = (*p) ? p : NULL;
- while(*p && !isspace((unsigned char)(*p)))
- p++;
- }
-
- /* make sure argv[0] exists in $PATH */
- if(can_access_in_path(getenv("PATH"), syspipe->argv[0],
- EXECUTE_ACCESS) < 0){
- pipe_error_cleanup(&syspipe, syspipe->argv[0], "access",
- error_description(errno));
- return(NULL);
- }
- }
-
- /* fill in any output filenames */
- if(!(mode & PIPE_READ)){
- if(outfile && !*outfile)
- *outfile = temp_nam(NULL, "pine_p"); /* asked for, but not named? */
-
- if(errfile && !*errfile)
- *errfile = temp_nam(NULL, "pine_p"); /* ditto */
- }
-
- /* create pipes */
- if(mode & (PIPE_WRITE | PIPE_READ)){
- if(mode & PIPE_WRITE){
- pipe(p); /* alloc pipe to write child */
- oparentd = p[STDOUT_FILENO];
- ichildd = p[STDIN_FILENO];
- }
-
- if(mode & PIPE_READ){
- pipe(p); /* alloc pipe to read child */
- iparentd = p[STDIN_FILENO];
- ochildd = p[STDOUT_FILENO];
- }
- }
- else if(!(mode & PIPE_SILENT)){
- flush_status_messages(0); /* just clean up display */
- ClearScreen();
- fflush(stdout);
- }
-
- if((syspipe->mode = mode) & PIPE_RESET)
- PineRaw(0);
-
-#ifdef SIGCHLD
- /*
- * Prepare for demise of child. Use SIGCHLD if it's available so
- * we can do useful things, like keep the IMAP stream alive, while
- * we're waiting on the child.
- */
- child_signalled = child_jump = 0;
-#endif
-
- if((syspipe->pid = vfork()) == 0){
- /* reset child's handlers in requested fashion... */
- (void)signal(SIGINT, (mode & PIPE_PROT) ? SIG_IGN : SIG_DFL);
- (void)signal(SIGQUIT, (mode & PIPE_PROT) ? SIG_IGN : SIG_DFL);
- (void)signal(SIGHUP, (mode & PIPE_PROT) ? SIG_IGN : SIG_DFL);
-#ifdef SIGCHLD
- (void) signal(SIGCHLD, SIG_DFL);
-#endif
-
- /* if parent isn't reading, and we have a filename to write */
- if(!(mode & PIPE_READ) && outfile){ /* connect output to file */
- int output = creat(*outfile, 0600);
- dup2(output, STDOUT_FILENO);
- if(mode & PIPE_STDERR)
- dup2(output, STDERR_FILENO);
- else if(errfile)
- dup2(creat(*errfile, 0600), STDERR_FILENO);
- }
-
- if(mode & PIPE_WRITE){ /* connect process input */
- close(oparentd);
- dup2(ichildd, STDIN_FILENO); /* tie stdin to pipe */
- close(ichildd);
- }
-
- if(mode & PIPE_READ){ /* connect process output */
- close(iparentd);
- dup2(ochildd, STDOUT_FILENO); /* tie std{out,err} to pipe */
- if(mode & PIPE_STDERR)
- dup2(ochildd, STDERR_FILENO);
- else if(errfile)
- dup2(creat(*errfile, 0600), STDERR_FILENO);
-
- close(ochildd);
- }
-
- if(mode & PIPE_NOSHELL){
- execvp(syspipe->argv[0], syspipe->argv);
- }
- else{
- if(mode & PIPE_USER){
- char *env, *sh;
- if((env = getenv("SHELL")) && (sh = strrchr(env, '/'))){
- shell = sh + 1;
- strcpy(shellpath, env);
- }
- else{
- shell = "csh";
- strcpy(shellpath, "/bin/csh");
- }
- }
- else{
- shell = "sh";
- strcpy(shellpath, "/bin/sh");
- }
-
- execl(shellpath, shell, command ? "-c" : 0, command, 0);
- }
-
- fprintf(stderr, "Can't exec %s\nReason: %s",
- command, error_description(errno));
- _exit(-1);
- }
-
- if((child_pid = syspipe->pid) > 0){
- syspipe->isig = signal(SIGINT, SIG_IGN); /* Reset handlers to make */
- syspipe->qsig = signal(SIGQUIT, SIG_IGN); /* sure we don't come to */
- syspipe->hsig = signal(SIGHUP, SIG_IGN); /* a premature end... */
- if((syspipe->timeout = timeout) != 0){
- syspipe->alrm = signal(SIGALRM, pipe_alarm);
- syspipe->old_timeo = alarm(timeout);
- }
-
- if(mode & PIPE_WRITE){
- close(ichildd);
- if(mode & PIPE_DESC)
- syspipe->out.d = oparentd;
- else
- syspipe->out.f = fdopen(oparentd, "w");
- }
-
- if(mode & PIPE_READ){
- close(ochildd);
- if(mode & PIPE_DESC)
- syspipe->in.d = iparentd;
- else
- syspipe->in.f = fdopen(iparentd, "r");
- }
-
- dprint(5, (debugfile, "PID: %d, COMMAND: %s\n",syspipe->pid,command));
- }
- else{
- if(mode & (PIPE_WRITE | PIPE_READ)){
- if(mode & PIPE_WRITE){
- close(oparentd);
- close(ichildd);
- }
-
- if(mode & PIPE_READ){
- close(iparentd);
- close(ochildd);
- }
- }
- else if(!(mode & PIPE_SILENT)){
- ClearScreen();
- ps_global->mangled_screen = 1;
- }
-
- if(mode & PIPE_RESET)
- PineRaw(1);
-
-#ifdef SIGCHLD
- (void) signal(SIGCHLD, SIG_DFL);
-#endif
- if(outfile)
- fs_give((void **) outfile);
-
- pipe_error_cleanup(&syspipe, command, "fork",error_description(errno));
- }
-
- return(syspipe);
-}
-
-
-
-/*----------------------------------------------------------------------
- Write appropriate error messages and cleanup after pipe error
-
- Args: syspipe -- address of pointer to struct to clean up
- cmd -- command we were trying to exec
- op -- operation leading up to the exec
- res -- result of that operation
-
- ----*/
-void
-pipe_error_cleanup(syspipe, cmd, op, res)
- PIPE_S **syspipe;
- char *cmd, *op, *res;
-{
- q_status_message3(SM_ORDER, 3, 3, "Pipe can't %s \"%.20s\": %s",
- op, cmd, res);
- dprint(1, (debugfile, "* * PIPE CAN'T %s(%s): %s\n", op, cmd, res));
- zot_pipe(syspipe);
-}
-
-
-
-/*----------------------------------------------------------------------
- Free resources associated with the given pipe struct
-
- Args: syspipe -- address of pointer to struct to clean up
-
- ----*/
-void
-zot_pipe(syspipe)
- PIPE_S **syspipe;
-{
- if((*syspipe)->args)
- fs_give((void **) &(*syspipe)->args);
-
- if((*syspipe)->argv)
- fs_give((void **) &(*syspipe)->argv);
-
- if((*syspipe)->tmp)
- fs_give((void **) &(*syspipe)->tmp);
-
- fs_give((void **)syspipe);
-}
-
-
-
-/*----------------------------------------------------------------------
- Close pipe previously allocated and wait for child's death
-
- Args: syspipe -- address of pointer to struct returned by open_system_pipe
- Returns: returns exit status of child or -1 if invalid syspipe
- ----*/
-int
-close_system_pipe(syspipe)
- PIPE_S **syspipe;
-{
- WaitType stat;
- int status;
-
- if(!(syspipe && *syspipe))
- return(-1);
-
- if(((*syspipe)->mode) & PIPE_WRITE){
- if(((*syspipe)->mode) & PIPE_DESC){
- if((*syspipe)->out.d >= 0)
- close((*syspipe)->out.d);
- }
- else if((*syspipe)->out.f)
- fclose((*syspipe)->out.f);
- }
-
- if(((*syspipe)->mode) & PIPE_READ){
- if(((*syspipe)->mode) & PIPE_DESC){
- if((*syspipe)->in.d >= 0)
- close((*syspipe)->in.d);
- }
- else if((*syspipe)->in.f)
- fclose((*syspipe)->in.f);
- }
-
-#ifdef SIGCHLD
- {
- SigType (*alarm_sig)();
- int old_cue = F_ON(F_SHOW_DELAY_CUE, ps_global);
-
- /*
- * remember the current SIGALRM handler, and make sure it's
- * installed when we're finished just in case the longjmp
- * out of the SIGCHLD handler caused sleep() to lose it.
- * Don't pay any attention to that man behind the curtain.
- */
- alarm_sig = signal(SIGALRM, SIG_IGN);
- F_SET(F_SHOW_DELAY_CUE, ps_global, 0);
- ps_global->noshow_timeout = 1;
- while(!child_signalled){
- /* wake up and prod server */
- new_mail(0, 2, ((*syspipe)->mode & PIPE_RESET)
- ? NM_NONE : NM_DEFER_SORT);
-
- if(!child_signalled){
- if(setjmp(child_state) == 0){
- child_jump = 1; /* prepare to wake up */
- sleep(600); /* give it 5mins to happend */
- }
- else
- our_sigunblock(SIGCHLD);
- }
-
- child_jump = 0;
- }
-
- ps_global->noshow_timeout = 0;
- F_SET(F_SHOW_DELAY_CUE, ps_global, old_cue);
- (void) signal(SIGALRM, alarm_sig);
- }
-#endif
-
- /*
- * Call c-client's pid reaper to wait() on the demise of our child,
- * then fish out its exit status...
- */
- grim_pid_reap_status((*syspipe)->pid, 0, &stat);
- status = WIFEXITED(stat) ? WEXITSTATUS(stat) : -1;
-
- /*
- * restore original handlers...
- */
- (void)signal(SIGINT, (*syspipe)->isig);
- (void)signal(SIGHUP, (*syspipe)->hsig);
- (void)signal(SIGQUIT, (*syspipe)->qsig);
-
- if((*syspipe)->timeout){
- (void)signal(SIGALRM, (*syspipe)->alrm);
- alarm((*syspipe)->old_timeo);
- child_pid = 0;
- }
-
- if((*syspipe)->mode & PIPE_RESET) /* restore our tty modes */
- PineRaw(1);
-
- if(!((*syspipe)->mode & (PIPE_WRITE | PIPE_READ | PIPE_SILENT))){
- ClearScreen(); /* No I/O to forked child */
- ps_global->mangled_screen = 1;
- }
-
- zot_pipe(syspipe);
-
- return(status);
-}
-
-
-
-static SigType
-pipe_alarm SIG_PROTO((int sig))
-{
- if(child_pid)
- kill(child_pid, SIGINT);
-}
-
-/*======================================================================
- post_reap
-
- Manage exit status collection of a child spawned to handle posting
- ====*/
-
-
-
-#if defined(BACKGROUND_POST) && defined(SIGCHLD)
-/*----------------------------------------------------------------------
- Check to see if we have any posting processes to clean up after
-
- Args: none
- Returns: any finished posting process reaped
- ----*/
-post_reap()
-{
- WaitType stat;
- int r;
-
- if(ps_global->post && ps_global->post->pid){
- r = waitpid(ps_global->post->pid, &stat, WNOHANG);
- if(r == ps_global->post->pid){
- ps_global->post->status = WIFEXITED(stat) ? WEXITSTATUS(stat) : -1;
- ps_global->post->pid = 0;
- return(1);
- }
- else if(r < 0 && errno != EINTR){ /* pid's become bogus?? */
- fs_give((void **) &ps_global->post);
- }
- }
-
- return(0);
-}
-#endif
-
-/*----------------------------------------------------------------------
- Routines used to hand off messages to local agents for sending/posting
-
- The two exported routines are:
-
- 1) smtp_command() -- used to get local transport agent to invoke
- 2) post_handoff() -- used to pass messages to local posting agent
-
- ----*/
-
-
-
-/*
- * Protos for "sendmail" internal functions
- */
-static char *mta_parse_post PROTO((METAENV *, BODY *, char *, char *));
-static long pine_pipe_soutr_nl PROTO((void *, char *));
-
-
-
-/* ----------------------------------------------------------------------
- Figure out command to start local SMTP agent
-
- Args: errbuf -- buffer for reporting errors (assumed non-NULL)
-
- Returns an alloc'd copy of the local SMTP agent invocation or NULL
-
- ----*/
-char *
-smtp_command(errbuf)
- char *errbuf;
-{
-#if defined(SENDMAIL) && defined(SENDMAILFLAGS)
- char tmp[256];
-
- sprintf(tmp, "%s %s", SENDMAIL, SENDMAILFLAGS);
- return(cpystr(tmp));
-#else
- strcpy(errbuf, "No default posting command.");
- return(NULL);
-#endif
-}
-
-
-
-/*----------------------------------------------------------------------
- Hand off given message to local posting agent
-
- Args: envelope -- The envelope for the BCC and debugging
- header -- The text of the message header
- errbuf -- buffer for reporting errors (assumed non-NULL)
-
- ----*/
-int
-mta_handoff(header, body, errbuf)
- METAENV *header;
- BODY *body;
- char *errbuf;
-{
- char cmd_buf[256], *cmd = NULL;
-
- /*
- * A bit of complicated policy implemented here.
- * There are two posting variables sendmail-path and smtp-server.
- * Precedence is in that order.
- * They can be set one of 4 ways: fixed, command-line, user, or globally.
- * Precedence is in that order.
- * Said differently, the order goes something like what's below.
- *
- * NOTE: the fixed/command-line/user precendence handling is also
- * indicated by what's pointed to by ps_global->VAR_*, but since
- * that also includes the global defaults, it's not sufficient.
- */
-
- if(ps_global->FIX_SENDMAIL_PATH
- && ps_global->FIX_SENDMAIL_PATH[0]){
- cmd = ps_global->FIX_SENDMAIL_PATH;
- }
- else if(!(ps_global->FIX_SMTP_SERVER
- && ps_global->FIX_SMTP_SERVER[0])){
- if(ps_global->COM_SENDMAIL_PATH
- && ps_global->COM_SENDMAIL_PATH[0]){
- cmd = ps_global->COM_SENDMAIL_PATH;
- }
- else if(!(ps_global->COM_SMTP_SERVER
- && ps_global->COM_SMTP_SERVER[0])){
- if(ps_global->USR_SENDMAIL_PATH
- && ps_global->USR_SENDMAIL_PATH[0]){
- cmd = ps_global->USR_SENDMAIL_PATH;
- }
- else if(!(ps_global->USR_SMTP_SERVER
- && ps_global->USR_SMTP_SERVER[0])){
- if(ps_global->GLO_SENDMAIL_PATH
- && ps_global->GLO_SENDMAIL_PATH[0]){
- cmd = ps_global->GLO_SENDMAIL_PATH;
- }
-#ifdef DF_SENDMAIL_PATH
- /*
- * This defines the default method of posting. So,
- * unless we're told otherwise use it...
- */
- else if(!(ps_global->GLO_SMTP_SERVER
- && ps_global->GLO_SMTP_SERVER[0])){
- strcpy(cmd = cmd_buf, DF_SENDMAIL_PATH);
- }
-#endif
- }
- }
- }
-
- *errbuf = '\0';
- if(cmd){
- dprint(4, (debugfile, "call_mailer via cmd: %s\n", cmd));
-
- (void) mta_parse_post(header, body, cmd, errbuf);
- return(1);
- }
- else
- return(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Hand off given message to local posting agent
-
- Args: envelope -- The envelope for the BCC and debugging
- header -- The text of the message header
- errbuf -- buffer for reporting errors (assumed non-NULL)
-
- Fork off mailer process and pipe the message into it
- Called to post news via Inews when NNTP is unavailable
-
- ----*/
-char *
-post_handoff(header, body, errbuf)
- METAENV *header;
- BODY *body;
- char *errbuf;
-{
- char *err = NULL;
-#ifdef SENDNEWS
- char *s;
-
- if(s = strstr(header->env->date," (")) /* fix the date format for news */
- *s = '\0';
-
- if(err = mta_parse_post(header, body, SENDNEWS, errbuf))
- sprintf(err = errbuf, "News not posted: \"%s\": %s", SENDNEWS, err);
-
- if(s)
- *s = ' '; /* restore the date */
-
-#else /* !SENDNEWS */ /* this is the default case */
- sprintf(err = errbuf, "Can't post, NNTP-server must be defined!");
-#endif /* !SENDNEWS */
- return(err);
-}
-
-
-
-/*----------------------------------------------------------------------
- Hand off message to local MTA; it parses recipients from 822 header
-
- Args: header -- struct containing header data
- body -- struct containing message body data
- cmd -- command to use for handoff (%s says where file should go)
- errs -- pointer to buf to hold errors
-
- ----*/
-static char *
-mta_parse_post(header, body, cmd, errs)
- METAENV *header;
- BODY *body;
- char *cmd;
- char *errs;
-{
- char *result = NULL;
- PIPE_S *pipe;
-
- dprint(1, (debugfile, "=== mta_parse_post(%s) ===\n", cmd));
-
- if(pipe = open_system_pipe(cmd, &result, NULL,
- PIPE_STDERR|PIPE_WRITE|PIPE_PROT|PIPE_NOSHELL|PIPE_DESC, 0)){
- if(!pine_rfc822_output(header, body, pine_pipe_soutr_nl,
- (TCPSTREAM *) pipe))
- strcpy(errs, "Error posting.");
-
- if(close_system_pipe(&pipe) && !*errs){
- sprintf(errs, "Posting program %s returned error", cmd);
- if(result)
- display_output_file(result, "POSTING ERRORS", errs, 1);
- }
- }
- else
- sprintf(errs, "Error running \"%s\"", cmd);
-
- if(result){
- unlink(result);
- fs_give((void **)&result);
- }
-
- return(*errs ? errs : NULL);
-}
-
-
-/*
- * pine_pipe_soutr - Replacement for tcp_soutr that writes one of our
- * pipes rather than a tcp stream
- */
-static long
-pine_pipe_soutr_nl (stream,s)
- void *stream;
- char *s;
-{
- long rv = T;
- char *p;
- size_t n;
-
- while(*s && rv){
- if(n = (p = strstr(s, "\015\012")) ? p - s : strlen(s))
- while((rv = write(((PIPE_S *)stream)->out.d, s, n)) != n)
- if(rv < 0){
- if(errno != EINTR){
- rv = 0;
- break;
- }
- }
- else{
- s += rv;
- n -= rv;
- }
-
- if(p && rv){
- s = p + 2; /* write UNIX EOL */
- while((rv = write(((PIPE_S *)stream)->out.d,"\n",1)) != 1)
- if(rv < 0 && errno != EINTR){
- rv = 0;
- break;
- }
- }
- else
- break;
- }
-
- return(rv);
-}
-
-/* ----------------------------------------------------------------------
- Execute the given mailcap command
-
- Args: cmd -- the command to execute
- image_file -- the file the data is in
- needsterminal -- does this command want to take over the terminal?
- ----*/
-void
-exec_mailcap_cmd(cmd, image_file, needsterminal)
-char *cmd;
-char *image_file;
-int needsterminal;
-{
- char *command = NULL,
- *result_file = NULL,
- *p;
- char **r_file_h;
- PIPE_S *syspipe;
- int mode;
-
- p = command = (char *)fs_get((32 + strlen(cmd) + (2*strlen(image_file)))
- * sizeof(char));
- if(!needsterminal) /* put in background if it doesn't need terminal */
- *p++ = '(';
- sprintf(p, "%s ; rm -f %s", cmd, image_file);
- p += strlen(p);
- if(!needsterminal){
- *p++ = ')';
- *p++ = ' ';
- *p++ = '&';
- }
- *p++ = '\n';
- *p = '\0';
- dprint(9, (debugfile, "exec_mailcap_cmd: command=%s\n", command));
-
- mode = PIPE_RESET;
- if(needsterminal == 1)
- r_file_h = NULL;
- else{
- mode |= PIPE_WRITE | PIPE_STDERR;
- result_file = temp_nam(NULL, "pine_cmd");
- r_file_h = &result_file;
- }
-
- if(syspipe = open_system_pipe(command, r_file_h, NULL, mode, 0)){
- close_system_pipe(&syspipe);
- if(needsterminal == 1)
- q_status_message(SM_ORDER, 0, 4, "VIEWER command completed");
- else if(needsterminal == 2)
- display_output_file(result_file, "VIEWER", " command result", 1);
- else
- display_output_file(result_file, "VIEWER", " command launched", 1);
- }
- else
- q_status_message1(SM_ORDER, 3, 4, "Cannot spawn command : %s", cmd);
-
- fs_give((void **)&command);
- if(result_file)
- fs_give((void **)&result_file);
-}
-
-
-/* ----------------------------------------------------------------------
- Execute the given mailcap test= cmd
-
- Args: cmd -- command to execute
- Returns exit status
-
- ----*/
-int
-exec_mailcap_test_cmd(cmd)
- char *cmd;
-{
- PIPE_S *syspipe;
-
- return((syspipe = open_system_pipe(cmd, NULL, NULL, PIPE_SILENT, 0))
- ? close_system_pipe(&syspipe) : -1);
-}
-
-
-
-/*======================================================================
- print routines
-
- Functions having to do with printing on paper and forking of spoolers
-
- In general one calls open_printer() to start printing. One of
- the little print functions to send a line or string, and then
- call print_end() when complete. This takes care of forking off a spooler
- and piping the stuff down it. No handles or anything here because there's
- only one printer open at a time.
-
- ====*/
-
-
-
-static char *trailer; /* so both open and close_printer can see it */
-
-/*----------------------------------------------------------------------
- Open the printer
-
- Args: desc -- Description of item to print. Should have one trailing blank.
-
- Return value: < 0 is a failure.
- 0 a success.
-
-This does most of the work of popen so we can save the standard output of the
-command we execute and send it back to the user.
- ----*/
-int
-open_printer(desc)
- char *desc;
-{
- char command[201], prompt[200];
- int cmd, rc, just_one;
- char *p, *init, *nick;
- char aname[100];
- char *printer;
- int done = 0, i, lastprinter, cur_printer = 0;
- HelpType help;
- char **list;
- static ESCKEY_S ekey[] = {
- {'y', 'y', "Y", "Yes"},
- {'n', 'n', "N", "No"},
- {ctrl('P'), 10, "^P", "Prev Printer"},
- {ctrl('N'), 11, "^N", "Next Printer"},
- {-2, 0, NULL, NULL},
- {'c', 'c', "C", "CustomPrint"},
- {KEY_UP, 10, "", ""},
- {KEY_DOWN, 11, "", ""},
- {-1, 0, NULL, NULL}};
-#define PREV_KEY 2
-#define NEXT_KEY 3
-#define CUSTOM_KEY 5
-#define UP_KEY 6
-#define DOWN_KEY 7
-
- trailer = NULL;
- init = NULL;
- nick = NULL;
- command[200] = '\0';
-
- if(ps_global->VAR_PRINTER == NULL){
- q_status_message(SM_ORDER | SM_DING, 3, 5,
- "No printer has been chosen. Use SETUP on main menu to make choice.");
- return(-1);
- }
-
- /* Is there just one print command available? */
- just_one = (ps_global->printer_category!=3&&ps_global->printer_category!=2)
- || (ps_global->printer_category == 2
- && !(ps_global->VAR_STANDARD_PRINTER
- && ps_global->VAR_STANDARD_PRINTER[0]
- && ps_global->VAR_STANDARD_PRINTER[1]))
- || (ps_global->printer_category == 3
- && !(ps_global->VAR_PERSONAL_PRINT_COMMAND
- && ps_global->VAR_PERSONAL_PRINT_COMMAND[0]
- && ps_global->VAR_PERSONAL_PRINT_COMMAND[1]));
-
- if(F_ON(F_CUSTOM_PRINT, ps_global))
- ekey[CUSTOM_KEY].ch = 'c'; /* turn this key on */
- else
- ekey[CUSTOM_KEY].ch = -2; /* turn this key off */
-
- if(just_one){
- ekey[PREV_KEY].ch = -2; /* turn these keys off */
- ekey[NEXT_KEY].ch = -2;
- ekey[UP_KEY].ch = -2;
- ekey[DOWN_KEY].ch = -2;
- }
- else{
- ekey[PREV_KEY].ch = ctrl('P'); /* turn these keys on */
- ekey[NEXT_KEY].ch = ctrl('N');
- ekey[UP_KEY].ch = KEY_UP;
- ekey[DOWN_KEY].ch = KEY_DOWN;
- /*
- * count how many printers in list and find the default in the list
- */
- if(ps_global->printer_category == 2)
- list = ps_global->VAR_STANDARD_PRINTER;
- else
- list = ps_global->VAR_PERSONAL_PRINT_COMMAND;
-
- for(i = 0; list[i]; i++)
- if(strcmp(ps_global->VAR_PRINTER, list[i]) == 0)
- cur_printer = i;
-
- lastprinter = i - 1;
- }
-
- help = NO_HELP;
- ps_global->mangled_footer = 1;
-
- while(!done){
- if(init)
- fs_give((void **)&init);
-
- if(trailer)
- fs_give((void **)&trailer);
-
- if(just_one)
- printer = ps_global->VAR_PRINTER;
- else
- printer = list[cur_printer];
-
- parse_printer(printer, &nick, &p, &init, &trailer, NULL, NULL);
- strncpy(command, p, 200);
- fs_give((void **)&p);
- sprintf(prompt, "Print %.50s%susing \"%.50s\" ? ",
- desc ? desc : "",
- (desc && *desc && desc[strlen(desc) - 1] != ' ') ? " " : "",
- *nick ? nick : command);
-
- fs_give((void **)&nick);
-
- cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global),
- ekey, 'y', 'x', help, RB_NORM);
-
- switch(cmd){
- case 'y':
- q_status_message1(SM_ORDER, 0, 9,
- "Printing with command \"%s\"", command);
- done++;
- break;
-
- case 10:
- cur_printer = (cur_printer>0)
- ? (cur_printer-1)
- : lastprinter;
- break;
-
- case 11:
- cur_printer = (cur_printer<lastprinter)
- ? (cur_printer+1)
- : 0;
- break;
-
- case 'n':
- case 'x':
- done++;
- break;
-
- case 'c':
- done++;
- break;
-
- default:
- break;
- }
- }
-
- if(cmd == 'c'){
- if(init)
- fs_give((void **)&init);
-
- if(trailer)
- fs_give((void **)&trailer);
-
- sprintf(prompt, "Enter custom command : ");
- command[0] = '\0';
- rc = 1;
- help = NO_HELP;
- while(rc){
- int flags = OE_APPEND_CURRENT;
-
- rc = optionally_enter(command, -FOOTER_ROWS(ps_global), 0,
- 200, prompt, NULL, help, &flags);
-
- if(rc == 1){
- cmd = 'x';
- rc = 0;
- }
- else if(rc == 3)
- help = (help == NO_HELP) ? h_custom_print : NO_HELP;
- else if(rc == 0){
- removing_trailing_white_space(command);
- removing_leading_white_space(command);
- q_status_message1(SM_ORDER, 0, 9,
- "Printing with command \"%s\"", command);
- }
- }
- }
-
- if(cmd == 'x' || cmd == 'n'){
- q_status_message(SM_ORDER, 0, 2, "Print cancelled");
- if(init)
- fs_give((void **)&init);
-
- if(trailer)
- fs_give((void **)&trailer);
-
- return(-1);
- }
-
- display_message('x');
-
- ps_global->print = (PRINT_S *)fs_get(sizeof(PRINT_S));
- memset(ps_global->print, 0, sizeof(PRINT_S));
-
- strcat(strcpy(aname, ANSI_PRINTER), "-no-formfeed");
- if(strucmp(command, ANSI_PRINTER) == 0
- || strucmp(command, aname) == 0){
- /*----------- Printer attached to ansi device ---------*/
- q_status_message(SM_ORDER, 0, 9,
- "Printing to attached desktop printer...");
- display_message('x');
- xonxoff_proc(1); /* make sure XON/XOFF used */
- crlf_proc(1); /* AND LF->CR xlation */
- fputs("\033[5i", stdout);
- ps_global->print->fp = stdout;
- if(strucmp(command, ANSI_PRINTER) == 0){
- /* put formfeed at the end of the trailer string */
- if(trailer){
- int len = strlen(trailer);
-
- fs_resize((void **)&trailer, len+2);
- trailer[len] = '\f';
- trailer[len+1] = '\0';
- }
- else
- trailer = cpystr("\f");
- }
- }
- else{
- /*----------- Print by forking off a UNIX command ------------*/
- dprint(4, (debugfile, "Printing using command \"%s\"\n", command));
- ps_global->print->result = temp_nam(NULL, "pine_prt");
- if(ps_global->print->pipe = open_system_pipe(command,
- &ps_global->print->result, NULL,
- PIPE_WRITE | PIPE_STDERR, 0)){
- ps_global->print->fp = ps_global->print->pipe->out.f;
- }
- else{
- fs_give((void **)&ps_global->print->result);
- q_status_message1(SM_ORDER | SM_DING, 3, 4,
- "Error opening printer: %s",
- error_description(errno));
- dprint(2, (debugfile, "Error popening printer \"%s\"\n",
- error_description(errno)));
- if(init)
- fs_give((void **)&init);
-
- if(trailer)
- fs_give((void **)&trailer);
-
- return(-1);
- }
- }
-
- ps_global->print->err = 0;
- if(init){
- if(*init)
- fputs(init, ps_global->print->fp);
-
- fs_give((void **)&init);
- }
-
- return(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Close printer
-
- If we're piping to a spooler close down the pipe and wait for the process
-to finish. If we're sending to an attached printer send the escape sequence.
-Also let the user know the result of the print
- ----*/
-void
-close_printer()
-{
- if(trailer){
- if(*trailer)
- fputs(trailer, ps_global->print->fp);
-
- fs_give((void **)&trailer);
- }
-
- if(ps_global->print->fp == stdout) {
- fputs("\033[4i", stdout);
- fflush(stdout);
- if(F_OFF(F_PRESERVE_START_STOP, ps_global))
- xonxoff_proc(0); /* turn off XON/XOFF */
-
- crlf_proc(0); /* turn off CF->LF xlantion */
- } else {
- (void) close_system_pipe(&ps_global->print->pipe);
- display_output_file(ps_global->print->result, "PRINT", NULL, 1);
- fs_give((void **)&ps_global->print->result);
- }
-
- fs_give((void **)&ps_global->print);
-
- q_status_message(SM_ASYNC, 0, 3, "Print command completed");
- display_message('x');
-}
-
-
-
-/*----------------------------------------------------------------------
- Print a single character
-
- Args: c -- char to print
- Returns: 1 on success, 0 on ps_global->print->err
- ----*/
-int
-print_char(c)
- int c;
-{
- if(!ps_global->print->err && putc(c, ps_global->print->fp) == EOF)
- ps_global->print->err = 1;
-
- return(!ps_global->print->err);
-}
-
-
-
-/*----------------------------------------------------------------------
- Send a line of text to the printer
-
- Args: line -- Text to print
-
- ----*/
-
-void
-print_text(line)
- char *line;
-{
- if(!ps_global->print->err && fputs(line, ps_global->print->fp) == EOF)
- ps_global->print->err = 1;
-}
-
-
-
-/*----------------------------------------------------------------------
- printf style formatting with one arg for printer
-
- Args: line -- The printf control string
- a1 -- The 1st argument for printf
- ----*/
-void
-print_text1(line, a1)
- char *line, *a1;
-{
- if(!ps_global->print->err
- && fprintf(ps_global->print->fp, line, a1) < 0)
- ps_global->print->err = 1;
-}
-
-
-
-/*----------------------------------------------------------------------
- printf style formatting with one arg for printer
-
- Args: line -- The printf control string
- a1 -- The 1st argument for printf
- a2 -- The 2nd argument for printf
- ----*/
-void
-print_text2(line, a1, a2)
- char *line, *a1, *a2;
-{
- if(!ps_global->print->err
- && fprintf(ps_global->print->fp, line, a1, a2) < 0)
- ps_global->print->err = 1;
-}
-
-
-
-/*----------------------------------------------------------------------
- printf style formatting with one arg for printer
-
- Args: line -- The printf control string
- a1 -- The 1st argument for printf
- a2 -- The 2nd argument for printf
- a3 -- The 3rd argument for printf
- ----*/
-void
-print_text3(line, a1, a2, a3)
- char *line, *a1, *a2, *a3;
-{
- if(!ps_global->print->err
- && fprintf(ps_global->print->fp, line, a1, a2, a3) < 0)
- ps_global->print->err = 1;
-}
-
-#ifdef DEBUG
-/*----------------------------------------------------------------------
- Initialize debugging - open the debug log file
-
- Args: none
-
- Result: opens the debug logfile for dprints
-
- Opens the file "~/.pine-debug1. Also maintains .pine-debug[2-4]
- by renaming them each time so the last 4 sessions are saved.
- ----*/
-void
-init_debug()
-{
- char nbuf[5];
- char newfname[MAXPATH+1], filename[MAXPATH+1];
- int i, fd;
-
- if(!(debug || ps_global->debug_imap))
- return;
-
- for(i = ps_global->debug_nfiles - 1; i > 0; i--){
- build_path(filename, ps_global->home_dir, DEBUGFILE);
- strcpy(newfname, filename);
- sprintf(nbuf, "%d", i);
- strcat(filename, nbuf);
- sprintf(nbuf, "%d", i+1);
- strcat(newfname, nbuf);
- (void)rename_file(filename, newfname);
- }
-
- build_path(filename, ps_global->home_dir, DEBUGFILE);
- strcat(filename, "1");
-
- debugfile = NULL;
- if((fd = open(filename, O_TRUNC|O_RDWR|O_CREAT, 0600)) >= 0)
- debugfile = fdopen(fd, "w+");
-
- if(debugfile != NULL){
- time_t now = time((time_t *)0);
- if(ps_global->debug_flush)
- setbuf(debugfile, NULL);
-
- if(ps_global->debug_nfiles == 0){
- /*
- * If no debug files are asked for, make filename a tempfile
- * to be used for a record should pine later crash...
- */
- if(debug < 9 && !ps_global->debug_flush && ps_global->debug_imap<4)
- unlink(filename);
- }
-
- dprint(0, (debugfile,
- "Debug output of the Pine program (debug=%d debug_imap=%d). Version %s\n%s\n",
- debug, ps_global->debug_imap, pine_version, ctime(&now)));
- }
-}
-
-
-/*----------------------------------------------------------------------
- Try to save the debug file if we crash in a controlled way
-
- Args: dfile: pointer to open debug file
-
- Result: tries to move the appropriate .pine-debugx file to .pine-crash
-
- Looks through the four .pine-debug files hunting for the one that is
- associated with this pine, and then renames it.
- ----*/
-void
-save_debug_on_crash(dfile)
-FILE *dfile;
-{
- char nbuf[5], crashfile[MAXPATH+1], filename[MAXPATH+1];
- int i;
- struct stat dbuf, tbuf;
- time_t now = time((time_t *)0);
-
- if(!(dfile && fstat(fileno(dfile), &dbuf) != 0))
- return;
-
- fprintf(dfile, "\nsave_debug_on_crash: Version %s: debug level %d\n",
- pine_version, debug);
- fprintf(dfile, "\n : %s\n", ctime(&now));
-
- build_path(crashfile, ps_global->home_dir, ".pine-crash");
-
- fprintf(dfile, "\nAttempting to save debug file to %s\n", crashfile);
- fprintf(stderr,
- "\n\n Attempting to save debug file to %s\n\n", crashfile);
-
- /* Blat out last n keystrokes */
- fputs("========== Latest keystrokes ==========\n", dfile);
- while((i = key_playback(0)) != -1)
- fprintf(dfile, "\t%s\t(0x%04.4x)\n", pretty_command(i), i);
-
- /* look for existing debug file */
- for(i = 1; i <= ps_global->debug_nfiles; i++){
- build_path(filename, ps_global->home_dir, DEBUGFILE);
- sprintf(nbuf, "%d", i);
- strcat(filename, nbuf);
- if(stat(filename, &tbuf) != 0)
- continue;
-
- /* This must be the current debug file */
- if(tbuf.st_dev == dbuf.st_dev && tbuf.st_ino == dbuf.st_ino){
- rename_file(filename, crashfile);
- break;
- }
- }
-
- /* if current debug file name not found, write it by hand */
- if(i > ps_global->debug_nfiles){
- FILE *cfp;
- char buf[1025];
-
- /*
- * Copy the debug temp file into the
- */
- if(cfp = fopen(crashfile, "w")){
- buf[1024] = '\0';
- fseek(dfile, 0L, 0);
- while(fgets(buf, 1025, dfile) && fputs(buf, cfp) != EOF)
- ;
-
- fclose(cfp);
- }
- }
-
- fclose(dfile);
-}
-
-
-#define CHECK_EVERY_N_TIMES 100
-#define MAX_DEBUG_FILE_SIZE 200000L
-/*
- * This is just to catch runaway Pines that are looping spewing out
- * debugging (and filling up a file system). The stop doesn't have to be
- * at all precise, just soon enough to hopefully prevent filling the
- * file system. If the debugging level is high (9 for now), then we're
- * presumably looking for some problem, so don't truncate.
- */
-int
-do_debug(debug_fp)
-FILE *debug_fp;
-{
- static int counter = CHECK_EVERY_N_TIMES;
- static int ok = 1;
- long filesize;
-
- if(debug == DEFAULT_DEBUG
- && !ps_global->debug_flush
- && !ps_global->debug_timestamp
- && ps_global->debug_imap < 2
- && ok
- && --counter <= 0){
- if((filesize = fp_file_size(debug_fp)) != -1L)
- ok = (unsigned long)filesize < (unsigned long)MAX_DEBUG_FILE_SIZE;
-
- counter = CHECK_EVERY_N_TIMES;
- if(!ok){
- fprintf(debug_fp, "\n\n --- No more debugging ---\n");
- fprintf(debug_fp,
- " (debug file growing too large - over %ld bytes)\n\n",
- MAX_DEBUG_FILE_SIZE);
- fflush(debug_fp);
- }
- }
-
- if(ok && ps_global->debug_timestamp)
- fprintf(debug_fp, "\n%s\n", debug_time(0));
-
- return(ok);
-}
-
-
-/*
- * Returns a pointer to static string for a timestamp.
- *
- * If timestamp is set .subseconds are added if available.
- * If include_date is set the date is appended.
- */
-char *
-debug_time(include_date)
- int include_date;
-{
- time_t t;
- struct tm *tm_now;
- struct timeval tp;
- struct timezone tzp;
- static char timestring[23];
- char subsecond[8];
- char datestr[7];
-
- if(gettimeofday(&tp, &tzp) == 0){
- t = (time_t)tp.tv_sec;
- if(include_date){
- tm_now = localtime(&t);
- sprintf(datestr, " %d/%d", tm_now->tm_mon+1, tm_now->tm_mday);
- }
- else
- datestr[0] = '\0';
-
- if(ps_global->debug_timestamp)
- sprintf(subsecond, ".%06ld", tp.tv_usec);
- else
- subsecond[0] = '\0';
-
- sprintf(timestring, "%.8s%s%s", ctime(&t)+11, subsecond, datestr);
- }
- else
- timestring[0] = '\0';
-
- return(timestring);
-}
-#endif /* DEBUG */
-
-
-/*
- * Fills in the passed in structure with the current time.
- *
- * Returns 0 if ok
- * -1 if can't do it
- */
-int
-get_time(our_time_val)
- TIMEVAL_S *our_time_val;
-{
- struct timeval tp;
- struct timezone tzp;
-
- if(gettimeofday(&tp, &tzp) == 0){
- our_time_val->sec = tp.tv_sec;
- our_time_val->usec = tp.tv_usec;
- return 0;
- }
- else
- return -1;
-}
-
-
-/*
- * Returns the difference between the two values, in microseconds.
- * Value returned is first - second.
- */
-long
-time_diff(first, second)
- TIMEVAL_S *first,
- *second;
-{
- return(1000000L*(first->sec - second->sec) + (first->usec - second->usec));
-}
-
-
-
-/*======================================================================
- Things having to do with reading from the tty driver and keyboard
- - initialize tty driver and reset tty driver
- - read a character from terminal with keyboard escape seqence mapping
- - initialize keyboard (keypad or such) and reset keyboard
- - prompt user for a line of input
- - read a command from keyboard with timeouts.
-
- ====*/
-
-
-/*
- * Helpful definitions
- */
-#define RETURN_CH(X) return(key_recorder((X)))
-/*
- * Should really be using pico's TERM's t_getchar to read a character but
- * we're just calling ttgetc directly for now. Ttgetc is the same as
- * t_getchar whenever we use it so we're avoiding the trouble of initializing
- * the TERM struct and calling ttgetc directly.
- */
-#define READ_A_CHAR() ttgetc(NO_OP_COMMAND, key_recorder, read_bail)
-
-
-/*
- * Internal prototypes
- */
-int pine_simple_ttgetc PROTO((int (*)(), void (*)()));
-void line_paint PROTO((int, int *));
-int process_config_input PROTO((int *));
-int check_for_timeout PROTO((int));
-void read_bail PROTO((void));
-
-
-/*----------------------------------------------------------------------
- Initialize the tty driver to do single char I/O and whatever else (UNIX)
-
- Args: struct pine
-
- Result: tty driver is put in raw mode so characters can be read one
- at a time. Returns -1 if unsuccessful, 0 if successful.
-
-Some file descriptor voodoo to allow for pipes across vforks. See
-open_mailer for details.
- ----------------------------------------------------------------------*/
-init_tty_driver(ps)
- struct pine *ps;
-{
-#ifdef MOUSE
- if(F_ON(F_ENABLE_MOUSE, ps_global))
- init_mouse();
-#endif /* MOUSE */
-
- /* turn off talk permission by default */
-
- if(F_ON(F_ALLOW_TALK, ps))
- allow_talk(ps);
- else
- disallow_talk(ps);
-
- return(PineRaw(1));
-}
-
-
-
-/*----------------------------------------------------------------------
- Set or clear the specified tty mode
-
- Args: ps -- struct pine
- mode -- mode bits to modify
- clear -- whether or not to clear or set
-
- Result: tty driver mode change.
- ----------------------------------------------------------------------*/
-void
-tty_chmod(ps, mode, func)
- struct pine *ps;
- int mode;
- int func;
-{
- char *tty_name;
- int new_mode;
- struct stat sbuf;
- static int saved_mode = -1;
-
- /* if no problem figuring out tty's name & mode? */
- if((((tty_name = (char *) ttyname(STDIN_FD)) != NULL
- && fstat(STDIN_FD, &sbuf) == 0)
- || ((tty_name = (char *) ttyname(STDOUT_FD)) != NULL
- && fstat(STDOUT_FD, &sbuf) == 0))
- && !(func == TMD_RESET && saved_mode < 0)){
- new_mode = (func == TMD_RESET)
- ? saved_mode
- : (func == TMD_CLEAR)
- ? (sbuf.st_mode & ~mode)
- : (sbuf.st_mode | mode);
- /* assign tty new mode */
- if(chmod(tty_name, new_mode) == 0){
- if(func == TMD_RESET) /* forget we knew */
- saved_mode = -1;
- else if(saved_mode < 0)
- saved_mode = sbuf.st_mode; /* remember original */
- }
- }
-}
-
-
-
-/*----------------------------------------------------------------------
- End use of the tty, put it back into it's normal mode (UNIX)
-
- Args: ps -- struct pine
-
- Result: tty driver mode change.
- ----------------------------------------------------------------------*/
-void
-end_tty_driver(ps)
- struct pine *ps;
-{
- ps = ps; /* get rid of unused parameter warning */
-
-#ifdef MOUSE
- end_mouse();
-#endif /* MOUSE */
- fflush(stdout);
- dprint(2, (debugfile, "about to end_tty_driver\n"));
-
- tty_chmod(ps, 0, TMD_RESET);
- PineRaw(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Actually set up the tty driver (UNIX)
-
- Args: state -- which state to put it in. 1 means go into raw, 0 out of
-
- Result: returns 0 if successful and < 0 if not.
- ----*/
-
-PineRaw(state)
-int state;
-{
- int result;
-
- result = Raw(state);
-
- if(result == 0 && state == 1){
- /*
- * Only go into 8 bit mode if we are doing something other
- * than plain ASCII. This will save the folks that have
- * their parity on their serial lines wrong thr trouble of
- * getting it right
- */
- if(ps_global->VAR_CHAR_SET && ps_global->VAR_CHAR_SET[0] &&
- strucmp(ps_global->VAR_CHAR_SET, "us-ascii"))
- bit_strip_off();
-
-#ifdef DEBUG
- if(debug < 9) /* only on if full debugging set */
-#endif
- quit_char_off();
- ps_global->low_speed = ttisslow();
- crlf_proc(0);
- xonxoff_proc(F_ON(F_PRESERVE_START_STOP, ps_global));
- }
-
- return(result);
-}
-
-
-#ifdef RESIZING
-jmp_buf winch_state;
-int winch_occured = 0;
-int ready_for_winch = 0;
-#endif
-
-/*----------------------------------------------------------------------
- This checks whether or not a character (UNIX)
- is ready to be read, or it times out.
-
- Args: time_out -- number of seconds before it will timeout
-
- Result: Returns a NO_OP_IDLE or a NO_OP_COMMAND if the timeout expires
- before input is available, or a KEY_RESIZE if a resize event
- occurs, or READY_TO_READ if input is available before the timeout.
- ----*/
-int
-check_for_timeout(time_out)
- int time_out;
-{
- int res;
-
- fflush(stdout);
-
-#ifdef RESIZING
- if(!winch_occured){
- if(setjmp(winch_state) != 0){
- winch_occured = 1;
- ready_for_winch = 0;
-
- /*
- * Need to unblock signal after longjmp from handler, because
- * signal is normally unblocked upon routine exit from the handler.
- */
- our_sigunblock(SIGWINCH);
- }
- else
- ready_for_winch = 1;
- }
-
- if(winch_occured){
- winch_occured = ready_for_winch = 0;
- fix_windsize(ps_global);
- return(KEY_RESIZE);
- }
-#endif /* RESIZING */
-
- switch(res = input_ready(time_out)){
- case BAIL_OUT:
- read_bail(); /* non-tragic exit */
- /* NO RETURN */
-
- case PANIC_NOW:
- panic1("Select error: %s\n", error_description(errno));
- /* NO RETURN */
-
- case READ_INTR:
- res = NO_OP_COMMAND;
- /* fall through */
-
- case NO_OP_IDLE:
- case NO_OP_COMMAND:
- case READY_TO_READ:
-#ifdef RESIZING
- ready_for_winch = 0;
-#endif
- return(res);
- }
-}
-
-
-
-/*----------------------------------------------------------------------
- Read input characters with lots of processing for arrow keys and such (UNIX)
-
- Args: time_out -- The timeout to for the reads
-
- Result: returns the character read. Possible special chars.
-
- This deals with function and arrow keys as well.
-
- The idea is that this routine handles all escape codes so it done in
- only one place. Especially so the back arrow key can work when entering
- things on a line. Also so all function keys can be disabled and not
- cause weird things to happen.
- ---*/
-int
-read_char(time_out)
- int time_out;
-{
- int ch, status, cc;
-
- /* Get input from initial-keystrokes */
- if(process_config_input(&ch))
- return(ch);
-
- /*
- * We only check for timeouts at the start of read_char, not in the
- * middle of escape sequences.
- */
- if((ch = check_for_timeout(time_out)) != READY_TO_READ)
- goto done;
-
- ps_global->time_of_last_input = time((time_t *)0);
-
- switch(status = kbseq(pine_simple_ttgetc, key_recorder, read_bail, &ch)){
- case KEY_DOUBLE_ESC:
- /*
- * Special hack to get around comm devices eating control characters.
- */
- if(check_for_timeout(5) != READY_TO_READ){
- ch = KEY_JUNK; /* user typed ESC ESC, then stopped */
- goto done;
- }
- else
- ch = READ_A_CHAR();
-
- ch &= 0x7f;
- if(isdigit((unsigned char)ch)){
- int n = 0, i = ch - '0';
-
- if(i < 0 || i > 2){
- ch = KEY_JUNK;
- goto done; /* bogus literal char value */
- }
-
- while(n++ < 2){
- if(check_for_timeout(5) != READY_TO_READ
- || (!isdigit((unsigned char) (ch = READ_A_CHAR()))
- || (n == 1 && i == 2 && ch > '5')
- || (n == 2 && i == 25 && ch > '5'))){
- ch = KEY_JUNK; /* user typed ESC ESC #, stopped */
- goto done;
- }
-
- i = (i * 10) + (ch - '0');
- }
-
- ch = i;
- }
- else{
- if(islower((unsigned char)ch)) /* canonicalize if alpha */
- ch = toupper((unsigned char)ch);
-
- ch = (isalpha((unsigned char)ch) || ch == '@'
- || (ch >= '[' && ch <= '_'))
- ? ctrl(ch) : ((ch == SPACE) ? ctrl('@'): ch);
- }
-
- goto done;
-
-#ifdef MOUSE
- case KEY_XTERM_MOUSE:
- if(mouseexist()){
- /*
- * Special hack to get mouse events from an xterm.
- * Get the details, then pass it past the keymenu event
- * handler, and then to the installed handler if there
- * is one...
- */
- static int down = 0;
- int x, y, button;
- unsigned cmd;
-
- clear_cursor_pos();
- button = READ_A_CHAR() & 0x03;
-
- x = READ_A_CHAR() - '!';
- y = READ_A_CHAR() - '!';
-
- ch = NO_OP_COMMAND;
- if(button == 0){ /* xterm button 1 down */
- down = 1;
- if(checkmouse(&cmd, 1, x, y))
- ch = (int)cmd;
- }
- else if (down && button == 3){
- down = 0;
- if(checkmouse(&cmd, 0, x, y))
- ch = (int)cmd;
- }
-
- goto done;
- }
-
- break;
-#endif /* MOUSE */
-
- case KEY_UP :
- case KEY_DOWN :
- case KEY_RIGHT :
- case KEY_LEFT :
- case KEY_PGUP :
- case KEY_PGDN :
- case KEY_HOME :
- case KEY_END :
- case KEY_DEL :
- case PF1 :
- case PF2 :
- case PF3 :
- case PF4 :
- case PF5 :
- case PF6 :
- case PF7 :
- case PF8 :
- case PF9 :
- case PF10 :
- case PF11 :
- case PF12 :
- dprint(9, (debugfile, "Read char returning: %d %s\n",
- status, pretty_command(status)));
- return(status);
-
- case KEY_SWALLOW_Z:
- status = KEY_JUNK;
- case KEY_SWAL_UP:
- case KEY_SWAL_DOWN:
- case KEY_SWAL_LEFT:
- case KEY_SWAL_RIGHT:
- do
- if(check_for_timeout(2) != READY_TO_READ){
- status = KEY_JUNK;
- break;
- }
- while(!strchr("~qz", READ_A_CHAR()));
- ch = (status == KEY_JUNK) ? status : status - (KEY_SWAL_UP - KEY_UP);
- goto done;
-
- case KEY_KERMIT:
- do{
- cc = ch;
- if(check_for_timeout(2) != READY_TO_READ){
- status = KEY_JUNK;
- break;
- }
- else
- ch = READ_A_CHAR();
- }while(cc != '\033' && ch != '\\');
-
- ch = KEY_JUNK;
- goto done;
-
- case BADESC:
- ch = KEY_JUNK;
- goto done;
-
- case 0: /* regular character */
- default:
- /*
- * we used to strip (ch &= 0x7f;), but this seems much cleaner
- * in the face of line noise and has the benefit of making it
- * tougher to emit mistakenly labeled MIME...
- */
- if((ch & 0x80) && (!ps_global->VAR_CHAR_SET
- || !strucmp(ps_global->VAR_CHAR_SET, "US-ASCII"))){
- dprint(9, (debugfile, "Read char returning: %d %s\n",
- status, pretty_command(status)));
- return(KEY_JUNK);
- }
- else if(ch == ctrl('Z')){
- dprint(9, (debugfile, "Read char calling do_suspend\n"));
- return(do_suspend());
- }
-
-
- done:
- dprint(9, (debugfile, "Read char returning: %d %s\n",
- ch, pretty_command(ch)));
- return(ch);
- }
-}
-
-
-/*----------------------------------------------------------------------
- Reading input somehow failed and we need to shutdown now
-
- Args: none
-
- Result: pine exits
-
- ---*/
-void
-read_bail()
-{
- end_signals(1);
- if(ps_global->inbox_stream){
- if(ps_global->inbox_stream == ps_global->mail_stream)
- ps_global->mail_stream = NULL;
-
- if(!ps_global->inbox_stream->lock) /* shouldn't be... */
- pine_close_stream(ps_global->inbox_stream);
- }
-
- if(ps_global->mail_stream && !ps_global->mail_stream->lock)
- pine_close_stream(ps_global->mail_stream);
-
- end_keyboard(F_ON(F_USE_FK,ps_global));
- end_tty_driver(ps_global);
- if(filter_data_file(0))
- unlink(filter_data_file(0));
-
- exit(0);
-}
-
-
-int
-pine_simple_ttgetc(fi, fv)
- int (*fi)();
- void (*fv)();
-{
- int ch;
-
-#ifdef RESIZING
- if(!winch_occured){
- if(setjmp(winch_state) != 0){
- winch_occured = 1;
- ready_for_winch = 0;
-
- /*
- * Need to unblock signal after longjmp from handler, because
- * signal is normally unblocked upon routine exit from the handler.
- */
- our_sigunblock(SIGWINCH);
- }
- else
- ready_for_winch = 1;
- }
-
- if(winch_occured){
- winch_occured = ready_for_winch = 0;
- fix_windsize(ps_global);
- return(KEY_RESIZE);
- }
-#endif /* RESIZING */
-
- ch = simple_ttgetc(fi, fv);
-
-#ifdef RESIZING
- ready_for_winch = 0;
-#endif
-
- return(ch);
-}
-
-
-
-extern char term_name[];
-/* -------------------------------------------------------------------
- Set up the keyboard -- usually enable some function keys (UNIX)
-
- Args: struct pine
-
-So far all we do here is turn on keypad mode for certain terminals
-
-Hack for NCSA telnet on an IBM PC to put the keypad in the right mode.
-This is the same for a vtXXX terminal or [zh][12]9's which we have
-a lot of at UW
- ----*/
-void
-init_keyboard(use_fkeys)
- int use_fkeys;
-{
- if(use_fkeys && (!strucmp(term_name,"vt102")
- || !strucmp(term_name,"vt100")))
- printf("\033\133\071\071\150");
-}
-
-
-
-/*----------------------------------------------------------------------
- Clear keyboard, usually disable some function keys (UNIX)
-
- Args: pine state (terminal type)
-
- Result: keyboard state reset
- ----*/
-void
-end_keyboard(use_fkeys)
- int use_fkeys;
-{
- if(use_fkeys && (!strcmp(term_name, "vt102")
- || !strcmp(term_name, "vt100"))){
- printf("\033\133\071\071\154");
- fflush(stdout);
- }
-}
-
-
-#ifdef _WINDOWS
-#line 3 "osdep/termin.gen"
-
-static int g_mc_row, g_mc_col;
-
-int pcpine_oe_cursor PROTO((int, long));
-#endif
-
-
-/*
- * Generic tty input routines
- */
-
-
-/*----------------------------------------------------------------------
- Read a character from keyboard with timeout
- Input: none
-
- Result: Returns command read via read_char
- Times out and returns a null command every so often
-
- Calculates the timeout for the read, and does a few other house keeping
-things. The duration of the timeout is set in pine.c.
- ----------------------------------------------------------------------*/
-int
-read_command()
-{
- int ch, tm = 0;
- long dtime;
-
- cancel_busy_alarm(-1);
- tm = (messages_queued(&dtime) > 1) ? (int)dtime : timeo;
-
- /*
- * Before we sniff at the input queue, make sure no external event's
- * changed our picture of the message sequence mapping. If so,
- * recalculate the dang thing and run thru whatever processing loop
- * we're in again...
- */
- if(ps_global->expunge_count){
- q_status_message3(SM_ORDER, 3, 3,
- "%s message%s expunged from folder \"%s\"",
- long2string(ps_global->expunge_count),
- plural(ps_global->expunge_count),
- pretty_fn(ps_global->cur_folder));
- ps_global->expunge_count = 0L;
- display_message('x');
- }
-
- if(ps_global->inbox_expunge_count){
- q_status_message3(SM_ORDER, 3, 3,
- "%s message%s expunged from folder \"%s\"",
- long2string(ps_global->inbox_expunge_count),
- plural(ps_global->inbox_expunge_count),
- pretty_fn(ps_global->inbox_name));
- ps_global->inbox_expunge_count = 0L;
- display_message('x');
- }
-
- if(ps_global->mail_box_changed && ps_global->new_mail_count){
- dprint(2, (debugfile, "Noticed %ld new msgs! \n",
- ps_global->new_mail_count));
- return(NO_OP_COMMAND); /* cycle thru so caller can update */
- }
-
- ch = read_char(tm);
- dprint(9, (debugfile, "Read command returning: %d %s\n", ch,
- pretty_command(ch)));
- if(ch != NO_OP_COMMAND && ch != NO_OP_IDLE && ch != KEY_RESIZE)
- zero_new_mail_count();
-
-#ifdef BACKGROUND_POST
- /*
- * Any expired children to report on?
- */
- if(ps_global->post && ps_global->post->pid == 0){
- int winner = 0;
-
- if(ps_global->post->status < 0){
- q_status_message(SM_ORDER | SM_DING, 3, 3, "Abysmal failure!");
- }
- else{
- (void) pine_send_status(ps_global->post->status,
- ps_global->post->fcc, tmp_20k_buf,
- &winner);
- q_status_message(SM_ORDER | (winner ? 0 : SM_DING), 3, 3,
- tmp_20k_buf);
-
- }
-
- if(!winner)
- q_status_message(SM_ORDER, 0, 3,
- "Re-send via \"Compose\" then \"Yes\" to \"Continue INTERRUPTED?\"");
-
- if(ps_global->post->fcc)
- fs_give((void **) &ps_global->post->fcc);
-
- fs_give((void **) &ps_global->post);
- }
-#endif
-
- return(ch);
-}
-
-
-
-
-/*
- *
- */
-static struct display_line {
- int row, col; /* where display starts */
- int dlen; /* length of display line */
- char *dl; /* line on display */
- char *vl; /* virtual line */
- int vlen; /* length of virtual line */
- int vused; /* length of virtual line in use */
- int vbase; /* first virtual char on display */
-} dline;
-
-
-
-static struct key oe_keys[] =
- {{"^G","Help",KS_SCREENHELP}, {"^C","Cancel",KS_NONE},
- {"^T","xxx",KS_NONE}, {"Ret","Accept",KS_NONE},
- {NULL,NULL,KS_NONE}, {NULL,NULL,KS_NONE},
- {NULL,NULL,KS_NONE}, {NULL,NULL,KS_NONE},
- {NULL,NULL,KS_NONE}, {NULL,NULL,KS_NONE},
- {NULL,NULL,KS_NONE}, {NULL,NULL,KS_NONE}};
-INST_KEY_MENU(oe_keymenu, oe_keys);
-#define OE_HELP_KEY 0
-#define OE_CANCEL_KEY 1
-#define OE_CTRL_T_KEY 2
-#define OE_ENTER_KEY 3
-
-
-/*----------------------------------------------------------------------
- Prompt user for a string in status line with various options
-
- Args: string -- the buffer result is returned in, and original string (if
- any) is passed in.
- y_base -- y position on screen to start on. 0,0 is upper left
- negative numbers start from bottom
- x_base -- column position on screen to start on. 0,0 is upper left
- field_len -- Maximum length of string to accept
- prompt -- The string to prompt with
- escape_list -- pointer to array of ESCKEY_S's. input chars matching
- those in list return value from list.
- help -- Arrary of strings for help text in bottom screen lines
- flags -- pointer (because some are return values) to flags
- OE_USER_MODIFIED - Set on return if user modified buffer
- OE_DISALLOW_CANCEL - No cancel in menu.
- OE_DISALLOW_HELP - No help in menu.
- OE_KEEP_TRAILING_SPACE - Allow trailing space.
- OE_SEQ_SENSITIVE - Caller is sensitive to sequence
- number changes.
- OE_APPEND_CURRENT - String should not be truncated
- before accepting user input.
- OE_PASSWD - Don't echo on screen.
-
- Result: editing input string
- returns -1 unexpected errors
- returns 0 normal entry typed (editing and return or PF2)
- returns 1 typed ^C or PF2 (cancel)
- returns 3 typed ^G or PF1 (help)
- returns 4 typed ^L for a screen redraw
-
- WARNING: Care is required with regard to the escape_list processing.
- The passed array is terminated with an entry that has ch = -1.
- Function key labels and key strokes need to be setup externally!
- Traditionally, a return value of 2 is used for ^T escapes.
-
- Unless in escape_list, tabs are trapped by isprint().
-This allows near full weemacs style editing in the line
- ^A beginning of line
- ^E End of line
- ^R Redraw line
- ^G Help
- ^F forward
- ^B backward
- ^D delete
-----------------------------------------------------------------------*/
-
-optionally_enter(string, y_base, x_base, field_len,
- prompt, escape_list, help, flags)
- char *string, *prompt;
- ESCKEY_S *escape_list;
- HelpType help;
- int x_base, y_base, field_len;
- int *flags;
-{
- register char *s2;
- register int field_pos;
- int i, j, return_v, cols, ch, prompt_len, too_thin,
- real_y_base, km_popped, passwd;
- char *saved_original = NULL, *k, *kb;
- char *kill_buffer = NULL;
- char **help_text;
- int fkey_table[12];
- struct key_menu *km;
- bitmap_t bitmap;
- COLOR_PAIR *lastc = NULL, *promptc = NULL;
- struct variable *vars = ps_global->vars;
-#ifdef _WINDOWS
- int cursor_shown;
-#endif
-
- dprint(5, (debugfile, "=== optionally_enter called ===\n"));
- dprint(9, (debugfile, "string:\"%s\" y:%d x:%d length: %d append: %d\n",
- string, x_base, y_base, field_len,
- (flags && *flags & OE_APPEND_CURRENT)));
- dprint(9, (debugfile, "passwd:%d prompt:\"%s\" label:\"%s\"\n",
- (flags && *flags & OE_PASSWD),
- prompt, (escape_list && escape_list[0].ch != -1)
- ? escape_list[0].label: ""));
-
-#ifdef _WINDOWS
- if (mswin_usedialog ()) {
- MDlgButton button_list[12];
- int b;
- int i;
-
- memset (&button_list, 0, sizeof (MDlgButton) * 12);
- b = 0;
- for (i = 0; escape_list && escape_list[i].ch != -1 && i < 11; ++i) {
- if (escape_list[i].name != NULL
- && escape_list[i].ch > 0 && escape_list[i].ch < 256) {
- button_list[b].ch = escape_list[i].ch;
- button_list[b].rval = escape_list[i].rval;
- button_list[b].name = escape_list[i].name;
- button_list[b].label = escape_list[i].label;
- ++b;
- }
- }
- button_list[b].ch = -1;
-
-
- help_text = get_help_text (help);
- return_v = mswin_dialog (prompt, string, field_len,
- (flags && *flags & OE_APPEND_CURRENT),
- (flags && *flags & OE_PASSWD),
- button_list,
- help_text, flags ? *flags : OE_NONE);
- free_list_array (&help_text);
- return (return_v);
- }
-#endif
-
- suspend_busy_alarm();
- cols = ps_global->ttyo->screen_cols;
- prompt_len = strlen(prompt);
- too_thin = 0;
- km_popped = 0;
- if(y_base > 0) {
- real_y_base = y_base;
- } else {
- real_y_base= y_base + ps_global->ttyo->screen_rows;
- if(real_y_base < 2)
- real_y_base = ps_global->ttyo->screen_rows;
- }
-
- flush_ordered_messages();
- mark_status_dirty();
- if(flags && *flags & OE_APPEND_CURRENT) /* save a copy in case of cancel */
- saved_original = cpystr(string);
-
- /*
- * build the function key mapping table, skipping predefined keys...
- */
- memset(fkey_table, NO_OP_COMMAND, 12 * sizeof(int));
- for(i = 0, j = 0; escape_list && escape_list[i].ch != -1 && i+j < 12; i++){
- if(i+j == OE_HELP_KEY)
- j++;
-
- if(i+j == OE_CANCEL_KEY)
- j++;
-
- if(i+j == OE_ENTER_KEY)
- j++;
-
- fkey_table[i+j] = escape_list[i].ch;
- }
-
-#if defined(HELPFILE)
- help_text = (help != NO_HELP) ? get_help_text(help) : (char **)NULL;
-#else
- help_text = help;
-#endif
- if(help_text){ /*---- Show help text -----*/
- int width = ps_global->ttyo->screen_cols - x_base;
-
- if(FOOTER_ROWS(ps_global) == 1){
- km_popped++;
- FOOTER_ROWS(ps_global) = 3;
- clearfooter(ps_global);
-
- y_base = -3;
- real_y_base = y_base + ps_global->ttyo->screen_rows;
- }
-
- for(j = 0; j < 2 && help_text[j]; j++){
- MoveCursor(real_y_base + 1 + j, x_base);
- CleartoEOLN();
-
- if(width < strlen(help_text[j])){
- char *tmp = fs_get((width + 1) * sizeof(char));
- strncpy(tmp, help_text[j], width);
- tmp[width] = '\0';
- PutLine0(real_y_base + 1 + j, x_base, tmp);
- fs_give((void **)&tmp);
- }
- else
- PutLine0(real_y_base + 1 + j, x_base, help_text[j]);
- }
-
-#if defined(HELPFILE)
- free_list_array(&help_text);
-#endif
-
- } else {
- clrbitmap(bitmap);
- clrbitmap((km = &oe_keymenu)->bitmap); /* force formatting */
- if(!(flags && (*flags) & OE_DISALLOW_HELP))
- setbitn(OE_HELP_KEY, bitmap);
-
- setbitn(OE_ENTER_KEY, bitmap);
- if(!(flags && (*flags) & OE_DISALLOW_CANCEL))
- setbitn(OE_CANCEL_KEY, bitmap);
-
- setbitn(OE_CTRL_T_KEY, bitmap);
-
- /*---- Show the usual possible keys ----*/
- for(i=0,j=0; escape_list && escape_list[i].ch != -1 && i+j < 12; i++){
- if(i+j == OE_HELP_KEY)
- j++;
-
- if(i+j == OE_CANCEL_KEY)
- j++;
-
- if(i+j == OE_ENTER_KEY)
- j++;
-
- oe_keymenu.keys[i+j].label = escape_list[i].label;
- oe_keymenu.keys[i+j].name = escape_list[i].name;
- setbitn(i+j, bitmap);
- }
-
- for(i = i+j; i < 12; i++)
- if(!(i == OE_HELP_KEY || i == OE_ENTER_KEY || i == OE_CANCEL_KEY))
- oe_keymenu.keys[i].name = NULL;
-
- draw_keymenu(km, bitmap, cols, 1-FOOTER_ROWS(ps_global), 0, FirstMenu);
- }
-
- if(pico_usingcolor() && VAR_PROMPT_FORE_COLOR &&
- VAR_PROMPT_BACK_COLOR &&
- pico_is_good_color(VAR_PROMPT_FORE_COLOR) &&
- pico_is_good_color(VAR_PROMPT_BACK_COLOR)){
- lastc = pico_get_cur_color();
- if(lastc){
- promptc = new_color_pair(VAR_PROMPT_FORE_COLOR,
- VAR_PROMPT_BACK_COLOR);
- (void)pico_set_colorp(promptc, PSC_NONE);
- }
- }
- else
- StartInverse();
-
- /*
- * if display length isn't wide enough to support input,
- * shorten up the prompt...
- */
- if((dline.dlen = cols - (x_base + prompt_len + 1)) < 5){
- prompt_len += (dline.dlen - 5); /* adding negative numbers */
- prompt -= (dline.dlen - 5); /* subtracting negative numbers */
- dline.dlen = 5;
- }
-
- dline.dl = fs_get((size_t)dline.dlen + 1);
- memset((void *)dline.dl, 0, (size_t)(dline.dlen + 1) * sizeof(char));
- dline.row = real_y_base;
- dline.col = x_base + prompt_len;
- dline.vl = string;
- dline.vlen = --field_len; /* -1 for terminating NULL */
- dline.vbase = field_pos = 0;
-
-#ifdef _WINDOWS
- cursor_shown = mswin_showcaret(1);
-#endif
-
- PutLine0(real_y_base, x_base, prompt);
- /* make sure passed in string is shorter than field_len */
- /* and adjust field_pos.. */
-
- while((flags && *flags & OE_APPEND_CURRENT) &&
- field_pos < field_len && string[field_pos] != '\0')
- field_pos++;
-
- string[field_pos] = '\0';
- dline.vused = (int)(&string[field_pos] - string);
- passwd = (flags && *flags & OE_PASSWD) ? 1 : 0;
- line_paint(field_pos, &passwd);
-
- /*----------------------------------------------------------------------
- The main loop
-
- here field_pos is the position in the string.
- s always points to where we are in the string.
- loops until someone sets the return_v.
- ----------------------------------------------------------------------*/
- return_v = -10;
-
- while(return_v == -10) {
-
-#ifdef MOUSE
- mouse_in_content(KEY_MOUSE, -1, -1, 0x5, 0);
- register_mfunc(mouse_in_content,
- real_y_base, x_base + prompt_len,
- real_y_base, ps_global->ttyo->screen_cols);
-#endif
-#ifdef _WINDOWS
- mswin_allowpaste(MSWIN_PASTE_LINE);
- g_mc_row = real_y_base;
- g_mc_col = x_base + prompt_len;
- mswin_mousetrackcallback(pcpine_oe_cursor);
-#endif
-
- /* Timeout 10 min to keep imap mail stream alive */
- ch = read_char(600);
-
-#ifdef MOUSE
- clear_mfunc(mouse_in_content);
-#endif
-#ifdef _WINDOWS
- mswin_allowpaste(MSWIN_PASTE_DISABLE);
- mswin_mousetrackcallback(NULL);
-#endif
-
- /*
- * Don't want to intercept all characters if typing in passwd.
- * We select an ad hoc set that we will catch and let the rest
- * through. We would have caught the set below in the big switch
- * but we skip the switch instead. Still catch things like ^K,
- * DELETE, ^C, RETURN.
- */
- if(passwd)
- switch(ch) {
- case ctrl('F'):
- case KEY_RIGHT:
- case ctrl('B'):
- case KEY_LEFT:
- case ctrl('U'):
- case ctrl('A'):
- case KEY_HOME:
- case ctrl('E'):
- case KEY_END:
- case TAB:
- goto ok_for_passwd;
- }
-
- if(too_thin && ch != KEY_RESIZE && ch != ctrl('Z') && ch != ctrl('C'))
- goto bleep;
-
- switch(ch) {
-
- /*--------------- KEY RIGHT ---------------*/
- case ctrl('F'):
- case KEY_RIGHT:
- if(field_pos >= field_len || string[field_pos] == '\0')
- goto bleep;
-
- line_paint(++field_pos, &passwd);
- break;
-
- /*--------------- KEY LEFT ---------------*/
- case ctrl('B'):
- case KEY_LEFT:
- if(field_pos <= 0)
- goto bleep;
-
- line_paint(--field_pos, &passwd);
- break;
-
- /*-------------------- WORD SKIP --------------------*/
- case ctrl('@'):
- /*
- * Note: read_char *can* return NO_OP_COMMAND which is
- * the def'd with the same value as ^@ (NULL), BUT since
- * read_char has a big timeout (>25 secs) it won't.
- */
-
- /* skip thru current word */
- while(string[field_pos]
- && isalnum((unsigned char) string[field_pos]))
- field_pos++;
-
- /* skip thru current white space to next word */
- while(string[field_pos]
- && !isalnum((unsigned char) string[field_pos]))
- field_pos++;
-
- line_paint(field_pos, &passwd);
- break;
-
- /*-------------------- RETURN --------------------*/
- case PF4:
- if(F_OFF(F_USE_FK,ps_global)) goto bleep;
- case ctrl('J'):
- case ctrl('M'):
- return_v = 0;
- break;
-
- /*-------------------- Destructive backspace --------------------*/
- case '\177': /* DEL */
- case ctrl('H'):
- /* Try and do this with by telling the terminal to delete a
- a character. If that fails, then repaint the rest of the
- line, acheiving the same much less efficiently
- */
- if(field_pos <= 0)
- goto bleep;
-
- field_pos--;
- /* drop thru to pull line back ... */
-
- /*-------------------- Delete char --------------------*/
- case ctrl('D'):
- case KEY_DEL:
- if(field_pos >= field_len || !string[field_pos])
- goto bleep;
-
- dline.vused--;
- for(s2 = &string[field_pos]; *s2 != '\0'; s2++)
- *s2 = s2[1];
-
- *s2 = '\0'; /* Copy last NULL */
- line_paint(field_pos, &passwd);
- if(flags) /* record change if requested */
- *flags |= OE_USER_MODIFIED;
-
- break;
-
-
- /*--------------- Kill line -----------------*/
- case ctrl('K'):
- if(kill_buffer != NULL)
- fs_give((void **)&kill_buffer);
-
- if(field_pos != 0 || string[0]){
- if(!passwd && F_ON(F_DEL_FROM_DOT, ps_global))
- dline.vused -= strlen(&string[i = field_pos]);
- else
- dline.vused = i = 0;
-
- kill_buffer = cpystr(&string[field_pos = i]);
- string[field_pos] = '\0';
- line_paint(field_pos, &passwd);
- if(flags) /* record change if requested */
- *flags |= OE_USER_MODIFIED;
-
- }
-
- break;
-
- /*------------------- Undelete line --------------------*/
- case ctrl('U'):
- if(kill_buffer == NULL)
- goto bleep;
-
- /* Make string so it will fit */
- kb = cpystr(kill_buffer);
- dprint(2, (debugfile,
- "Undelete: %d %d\n", strlen(string), field_len));
- if(strlen(kb) + strlen(string) > field_len)
- kb[field_len - strlen(string)] = '\0';
- dprint(2, (debugfile,
- "Undelete: %d %d\n", field_len - strlen(string),
- strlen(kb)));
-
- if(string[field_pos] == '\0') {
- /*--- adding to the end of the string ----*/
- for(k = kb; *k; k++)
- string[field_pos++] = *k;
-
- string[field_pos] = '\0';
- } else {
- goto bleep;
- /* To lazy to do insert in middle of string now */
- }
-
- if(*kb && flags) /* record change if requested */
- *flags |= OE_USER_MODIFIED;
-
- dline.vused = strlen(string);
- fs_give((void **)&kb);
- line_paint(field_pos, &passwd);
- break;
-
-
- /*-------------------- Interrupt --------------------*/
- case ctrl('C'): /* ^C */
- if(F_ON(F_USE_FK,ps_global)
- || (flags && ((*flags) & OE_DISALLOW_CANCEL)))
- goto bleep;
-
- goto cancel;
-
- case PF2:
- if(F_OFF(F_USE_FK,ps_global)
- || (flags && ((*flags) & OE_DISALLOW_CANCEL)))
- goto bleep;
-
- cancel:
- return_v = 1;
- if(saved_original)
- strcpy(string, saved_original);
-
- break;
-
-
- case ctrl('A'):
- case KEY_HOME:
- /*-------------------- Start of line -------------*/
- line_paint(field_pos = 0, &passwd);
- break;
-
-
- case ctrl('E'):
- case KEY_END:
- /*-------------------- End of line ---------------*/
- line_paint(field_pos = dline.vused, &passwd);
- break;
-
-
- /*-------------------- Help --------------------*/
- case ctrl('G') :
- case PF1:
- if(flags && ((*flags) & OE_DISALLOW_HELP))
- goto bleep;
- else if(FOOTER_ROWS(ps_global) == 1 && km_popped == 0){
- km_popped++;
- FOOTER_ROWS(ps_global) = 3;
- clearfooter(ps_global);
- if(lastc)
- (void)pico_set_colorp(lastc, PSC_NONE);
- else
- EndInverse();
-
- draw_keymenu(km, bitmap, cols, 1-FOOTER_ROWS(ps_global),
- 0, FirstMenu);
-
- if(promptc)
- (void)pico_set_colorp(promptc, PSC_NONE);
- else
- StartInverse();
-
- mark_keymenu_dirty();
- y_base = -3;
- dline.row = real_y_base = y_base + ps_global->ttyo->screen_rows;
- PutLine0(real_y_base, x_base, prompt);
- fs_resize((void **)&dline.dl, (size_t)dline.dlen + 1);
- memset((void *)dline.dl, 0, (size_t)(dline.dlen + 1));
- line_paint(field_pos, &passwd);
- break;
- }
-
- if(FOOTER_ROWS(ps_global) > 1){
- mark_keymenu_dirty();
- return_v = 3;
- }
- else
- goto bleep;
-
- break;
-
-#ifdef MOUSE
- case KEY_MOUSE :
- {
- MOUSEPRESS mp;
-
- mouse_get_last (NULL, &mp);
-
- /* The clicked line have anything special on it? */
- switch(mp.button){
- case M_BUTTON_LEFT : /* position cursor */
- mp.col -= x_base + prompt_len; /* normalize column */
- if(dline.vbase + mp.col <= dline.vused)
- line_paint(field_pos = dline.vbase + mp.col, &passwd);
-
- break;
-
- case M_BUTTON_RIGHT :
-#ifdef _WINDOWS
- mp.col -= x_base + prompt_len; /* normalize column */
- if(dline.vbase + mp.col <= dline.vused)
- line_paint(field_pos = dline.vbase + mp.col, &passwd);
-
- mswin_allowpaste(MSWIN_PASTE_LINE);
- mswin_paste_popup();
- mswin_allowpaste(MSWIN_PASTE_DISABLE);
- break;
-#endif
-
- case M_BUTTON_MIDDLE : /* NO-OP for now */
- default: /* just ignore */
- break;
- }
- }
-
- break;
-#endif
-
- case NO_OP_IDLE:
- /* Keep mail stream alive */
- i = new_mail(0, 2, NM_DEFER_SORT);
- if(ps_global->expunge_count &&
- flags && ((*flags) & OE_SEQ_SENSITIVE))
- goto cancel;
-
- if(i < 0){
- line_paint(field_pos, &passwd);
- break; /* no changes, get on with life */
- }
- /* Else fall into redraw */
-
- /*-------------------- Redraw --------------------*/
- case ctrl('L'):
- /*---------------- re size ----------------*/
- case KEY_RESIZE:
-
- dline.row = real_y_base = y_base > 0 ? y_base :
- y_base + ps_global->ttyo->screen_rows;
- if(lastc)
- (void)pico_set_colorp(lastc, PSC_NONE);
- else
- EndInverse();
-
- ClearScreen();
- redraw_titlebar();
- if(ps_global->redrawer != (void (*)())NULL)
- (*ps_global->redrawer)();
-
- redraw_keymenu();
- if(promptc)
- (void)pico_set_colorp(promptc, PSC_NONE);
- else
- StartInverse();
-
- PutLine0(real_y_base, x_base, prompt);
- cols = ps_global->ttyo->screen_cols;
- too_thin = 0;
- if(cols < x_base + prompt_len + 4) {
- Writechar(BELL, 0);
- PutLine0(real_y_base, 0, "Screen's too thin. Ouch!");
- too_thin = 1;
- } else {
- dline.col = x_base + prompt_len;
- dline.dlen = cols - (x_base + prompt_len + 1);
- fs_resize((void **)&dline.dl, (size_t)dline.dlen + 1);
- memset((void *)dline.dl, 0, (size_t)(dline.dlen + 1));
- line_paint(field_pos, &passwd);
- }
- fflush(stdout);
-
- dprint(9, (debugfile,
- "optionally_enter RESIZE new_cols:%d too_thin: %d\n",
- cols, too_thin));
- break;
-
- case PF3 : /* input to potentially remap */
- case PF5 :
- case PF6 :
- case PF7 :
- case PF8 :
- case PF9 :
- case PF10 :
- case PF11 :
- case PF12 :
- if(F_ON(F_USE_FK,ps_global)
- && fkey_table[ch - PF1] != NO_OP_COMMAND)
- ch = fkey_table[ch - PF1]; /* remap function key input */
-
- default:
- if(escape_list){ /* in the escape key list? */
- for(j=0; escape_list[j].ch != -1; j++){
- if(escape_list[j].ch == ch){
- return_v = escape_list[j].rval;
- break;
- }
- }
-
- if(return_v != -10)
- break;
- }
-
- if(iscntrl(ch & 0x7f)){
- bleep:
- putc(BELL, stdout);
- continue;
- }
-
- ok_for_passwd:
- /*--- Insert a character -----*/
- if(dline.vused >= field_len)
- goto bleep;
-
- /*---- extending the length of the string ---*/
- for(s2 = &string[++dline.vused]; s2 - string > field_pos; s2--)
- *s2 = *(s2-1);
-
- string[field_pos++] = ch;
- line_paint(field_pos, &passwd);
- if(flags) /* record change if requested */
- *flags |= OE_USER_MODIFIED;
-
- } /*---- End of switch on char ----*/
- }
-
-#ifdef _WINDOWS
- if(!cursor_shown)
- mswin_showcaret(0);
-#endif
-
- fs_give((void **)&dline.dl);
- if(saved_original)
- fs_give((void **)&saved_original);
-
- if(kill_buffer)
- fs_give((void **)&kill_buffer);
-
- if (!(flags && (*flags) & OE_KEEP_TRAILING_SPACE))
- removing_trailing_white_space(string);
-
- if(lastc){
- (void)pico_set_colorp(lastc, PSC_NONE);
- free_color_pair(&lastc);
- if(promptc)
- free_color_pair(&promptc);
- }
- else
- EndInverse();
-
- MoveCursor(real_y_base, x_base); /* Move the cursor to show we're done */
- fflush(stdout);
- resume_busy_alarm(0);
- if(km_popped){
- FOOTER_ROWS(ps_global) = 1;
- clearfooter(ps_global);
- ps_global->mangled_body = 1;
- }
-
- return(return_v);
-}
-
-
-/*
- * line_paint - where the real work of managing what is displayed gets done.
- * The passwd variable is overloaded: if non-zero, don't
- * output anything, else only blat blank chars across line
- * once and use this var to tell us we've already written the
- * line.
- */
-void
-line_paint(offset, passwd)
- int offset; /* current dot offset into line */
- int *passwd; /* flag to hide display of chars */
-{
- register char *pfp, *pbp;
- register char *vfp, *vbp;
- int extra = 0;
-#define DLEN (dline.vbase + dline.dlen)
-
- /*
- * for now just leave line blank, but maybe do '*' for each char later
- */
- if(*passwd){
- if(*passwd > 1)
- return;
- else
- *passwd = 2; /* only blat once */
-
- extra = 0;
- MoveCursor(dline.row, dline.col);
- while(extra++ < dline.dlen)
- Writechar(' ', 0);
-
- MoveCursor(dline.row, dline.col);
- return;
- }
-
- /* adjust right margin */
- while(offset >= DLEN + ((dline.vused > DLEN) ? -1 : 1))
- dline.vbase += dline.dlen/2;
-
- /* adjust left margin */
- while(offset < dline.vbase + ((dline.vbase) ? 2 : 0))
- dline.vbase = max(dline.vbase - (dline.dlen/2), 0);
-
- if(dline.vbase){ /* off screen cue left */
- vfp = &dline.vl[dline.vbase+1];
- pfp = &dline.dl[1];
- if(dline.dl[0] != '<'){
- MoveCursor(dline.row, dline.col);
- Writechar(dline.dl[0] = '<', 0);
- }
- }
- else{
- vfp = dline.vl;
- pfp = dline.dl;
- if(dline.dl[0] == '<'){
- MoveCursor(dline.row, dline.col);
- Writechar(dline.dl[0] = ' ', 0);
- }
- }
-
- if(dline.vused > DLEN){ /* off screen right... */
- vbp = vfp + (long)(dline.dlen-(dline.vbase ? 2 : 1));
- pbp = pfp + (long)(dline.dlen-(dline.vbase ? 2 : 1));
- if(pbp[1] != '>'){
- MoveCursor(dline.row, dline.col+dline.dlen);
- Writechar(pbp[1] = '>', 0);
- }
- }
- else{
- extra = dline.dlen - (dline.vused - dline.vbase);
- vbp = &dline.vl[max(0, dline.vused-1)];
- pbp = &dline.dl[dline.dlen];
- if(pbp[0] == '>'){
- MoveCursor(dline.row, dline.col+dline.dlen);
- Writechar(pbp[0] = ' ', 0);
- }
- }
-
- while(*pfp == *vfp && vfp < vbp) /* skip like chars */
- pfp++, vfp++;
-
- if(pfp == pbp && *pfp == *vfp){ /* nothing to paint! */
- MoveCursor(dline.row, dline.col + (offset - dline.vbase));
- return;
- }
-
- /* move backward thru like characters */
- if(extra){
- while(extra >= 0 && *pbp == ' ') /* back over spaces */
- extra--, pbp--;
-
- while(extra >= 0) /* paint new ones */
- pbp[-(extra--)] = ' ';
- }
-
- if((vbp - vfp) == (pbp - pfp)){ /* space there? */
- while((*pbp == *vbp) && pbp != pfp) /* skip like chars */
- pbp--, vbp--;
- }
-
- if(pfp != pbp || *pfp != *vfp){ /* anything to paint?*/
- MoveCursor(dline.row, dline.col + (int)(pfp - dline.dl));
-
- do
- Writechar((unsigned char)((vfp <= vbp && *vfp)
- ? ((*pfp = *vfp++) == TAB) ? ' ' : *pfp
- : (*pfp = ' ')), 0);
- while(++pfp <= pbp);
- }
-
- MoveCursor(dline.row, dline.col + (offset - dline.vbase));
-}
-
-
-
-/*----------------------------------------------------------------------
- Check to see if the given command is reasonably valid
-
- Args: ch -- the character to check
-
- Result: A valid command is returned, or a well know bad command is returned.
-
- ---*/
-validatekeys(ch)
- int ch;
-{
-#ifndef _WINDOWS
- if(F_ON(F_USE_FK,ps_global)) {
- if(ch >= 'a' && ch <= 'z')
- return(KEY_JUNK);
- } else {
- if(ch >= PF1 && ch <= PF12)
- return(KEY_JUNK);
- }
-#else
- /*
- * In windows menu items are bound to a single key command which
- * gets inserted into the input stream as if the user had typed
- * that key. But all the menues are bonund to alphakey commands,
- * not PFkeys. to distinguish between a keyboard command and a
- * menu command we insert a flag (KEY_MENU_FLAG) into the
- * command value when setting up the bindings in
- * configure_menu_items(). Here we strip that flag.
- */
- if(F_ON(F_USE_FK,ps_global)) {
- if(ch >= 'a' && ch <= 'z' && !(ch & KEY_MENU_FLAG))
- return(KEY_JUNK);
- ch &= ~ KEY_MENU_FLAG;
- } else {
- ch &= ~ KEY_MENU_FLAG;
- if(ch >= PF1 && ch <= PF12)
- return(KEY_JUNK);
- }
-#endif
-
- return(ch);
-}
-
-
-
-/*----------------------------------------------------------------------
- Prepend config'd commands to keyboard input
-
- Args: ch -- pointer to storage for returned command
-
- Returns: TRUE if we're passing back a useful command, FALSE otherwise
-
- ---*/
-int
-process_config_input(ch)
- int *ch;
-{
- static char firsttime = (char) 1;
-
- /* commands in config file */
- if(ps_global->initial_cmds && *ps_global->initial_cmds) {
- /*
- * There are a few commands that may require keyboard input before
- * we enter the main command loop. That input should be interactive,
- * not from our list of initial keystrokes.
- */
- if(ps_global->dont_use_init_cmds)
- return(0);
-
- *ch = *ps_global->initial_cmds++;
- if(!*ps_global->initial_cmds && ps_global->free_initial_cmds){
- fs_give((void **)&(ps_global->free_initial_cmds));
- ps_global->initial_cmds = 0;
- }
-
- return(1);
- }
-
- if(firsttime) {
- firsttime = 0;
- if(ps_global->in_init_seq) {
- ps_global->in_init_seq = 0;
- ps_global->save_in_init_seq = 0;
- clear_cursor_pos();
- F_SET(F_USE_FK,ps_global,ps_global->orig_use_fkeys);
- /* draw screen */
- *ch = ctrl('L');
- return(1);
- }
- }
-
- return(0);
-}
-
-
-#define TAPELEN 256
-static int tape[TAPELEN];
-static long recorded = 0L;
-static short length = 0;
-
-
-/*
- * record user keystrokes
- *
- * Args: ch -- the character to record
- *
- * Returns: character recorded
- */
-int
-key_recorder(ch)
- int ch;
-{
- tape[recorded++ % TAPELEN] = ch;
- if(length < TAPELEN)
- length++;
-
- return(ch);
-}
-
-
-/*
- * playback user keystrokes
- *
- * Args: ch -- ignored
- *
- * Returns: character played back or -1 to indicate end of tape
- */
-int
-key_playback(ch)
- int ch;
-{
- ch = length ? tape[(recorded + TAPELEN - length--) % TAPELEN] : -1;
- return(ch);
-}
-
-
-#ifdef _WINDOWS
-int
-pcpine_oe_cursor(col, row)
- int col;
- long row;
-{
- return((row == g_mc_row
- && col >= g_mc_col
- && col < ps_global->ttyo->screen_cols)
- ? MSWIN_CURSOR_IBEAM
- : MSWIN_CURSOR_ARROW);
-}
-#endif
-
-/*======================================================================
- Routines for painting the screen
- - figure out what the terminal type is
- - deal with screen size changes
- - save special output sequences
- - the usual screen clearing, cursor addressing and scrolling
-
-
- This library gives programs the ability to easily access the
- termcap information and write screen oriented and raw input
- programs. The routines can be called as needed, except that
- to use the cursor / screen routines there must be a call to
- InitScreen() first. The 'Raw' input routine can be used
- independently, however. (Elm comment)
-
- Not sure what the original source of this code was. It got to be
- here as part of ELM. It has been changed significantly from the
- ELM version to be more robust in the face of inconsistent terminal
- autowrap behaviour. Also, the unused functions were removed, it was
- made to pay attention to the window size, and some code was made nicer
- (in my opinion anyways). It also outputs the terminal initialization
- strings and provides for minimal scrolling and detects terminals
- with out enough capabilities. (Pine comment, 1990)
-
-
-This code used to pay attention to the "am" auto margin and "xn"
-new line glitch fields, but they were so often incorrect because many
-terminals can be configured to do either that we've taken it out. It
-now assumes it dosn't know where the cursor is after outputing in the
-80th column.
-*/
-
-#define PUTLINE_BUFLEN 256
-
-static int _lines, _columns;
-static int _line = FARAWAY;
-static int _col = FARAWAY;
-static int _in_inverse;
-
-
-/*
- * Internal prototypes
- */
-static void moveabsolute PROTO((int, int));
-static void CursorUp PROTO((int));
-static void CursorDown PROTO((int));
-static void CursorLeft PROTO((int));
-static void CursorRight PROTO((int));
-
-
-extern char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
- *_setinverse, *_clearinverse,
- *_cleartoeoln, *_cleartoeos,
- *_startinsert, *_endinsert, *_insertchar, *_deletechar,
- *_deleteline, *_insertline,
- *_scrollregion, *_scrollup, *_scrolldown,
- *_termcap_init, *_termcap_end;
-extern char term_name[];
-extern int _tlines, _tcolumns, _bce;
-
-static enum {NoScroll,UseScrollRegion,InsertDelete} _scrollmode;
-
-char *tgoto(); /* and the goto stuff */
-
-
-
-/*----------------------------------------------------------------------
- Initialize the screen for output, set terminal type, etc
-
- Args: tt -- Pointer to variable to store the tty output structure.
-
- Result: terminal size is discovered and set in pine state
- termcap entry is fetched and stored
- make sure terminal has adequate capabilites
- evaluate scrolling situation
- returns status of indicating the state of the screen/termcap entry
-
- Returns:
- -1 indicating no terminal name associated with this shell,
- -2..-n No termcap for this terminal type known
- -3 Can't open termcap file
- -4 Terminal not powerful enough - missing clear to eoln or screen
- or cursor motion
- ----*/
-int
-config_screen(tt)
- struct ttyo **tt;
-{
- struct ttyo *ttyo;
- int err;
-
- ttyo = (struct ttyo *)fs_get(sizeof (struct ttyo));
-
- _line = 0; /* where are we right now?? */
- _col = 0; /* assume zero, zero... */
-
- /*
- * This is an ugly hack to let vtterminalinfo know it's being called
- * from pine.
- */
- Pmaster = (PICO *)1;
- if(err = vtterminalinfo(F_ON(F_TCAP_WINS, ps_global)))
- return(err);
-
- Pmaster = NULL;
-
- if(_tlines <= 0)
- _lines = DEFAULT_LINES_ON_TERMINAL;
- else
- _lines = _tlines;
-
- if(_tcolumns <= 0)
- _columns = DEFAULT_COLUMNS_ON_TERMINAL;
- else
- _columns = _tcolumns;
-
- get_windsize(ttyo);
-
- ttyo->header_rows = 2;
- ttyo->footer_rows = 3;
-
- /*---- Make sure this terminal has the capability.
- All we need is cursor address, clear line, and
- reverse video.
- ---*/
- if(_moveto == NULL || _cleartoeoln == NULL ||
- _setinverse == NULL || _clearinverse == NULL) {
- return(-4);
- }
-
- dprint(1, (debugfile, "Terminal type: %s\n", term_name));
-
- /*------ Figure out scrolling mode -----*/
- if(_scrollregion != NULL && _scrollregion[0] != '\0' &&
- _scrollup != NULL && _scrollup[0] != '\0'){
- _scrollmode = UseScrollRegion;
- } else if(_insertline != NULL && _insertline[0] != '\0' &&
- _deleteline != NULL && _deleteline[0] != '\0') {
- _scrollmode = InsertDelete;
- } else {
- _scrollmode = NoScroll;
- }
- dprint(7, (debugfile, "Scroll mode: %s\n",
- _scrollmode==NoScroll ? "No Scroll" :
- _scrollmode==InsertDelete ? "InsertDelete" : "Scroll Regions"));
-
- if (!_left) {
- _left = "\b";
- }
-
- *tt = ttyo;
-
- return(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Initialize the screen with the termcap string
- ----*/
-void
-init_screen()
-{
- if(_termcap_init) /* init using termcap's rule */
- tputs(_termcap_init, 1, outchar);
-
- /* and make sure there are no scrolling surprises! */
- BeginScroll(0, ps_global->ttyo->screen_rows - 1);
-
- pico_toggle_color(0);
- switch(ps_global->color_style){
- case COL_NONE:
- case COL_TERMDEF:
- pico_set_color_options(0);
- break;
- case COL_ANSI8:
- pico_set_color_options(COLOR_ANSI8_OPT);
- break;
- case COL_ANSI16:
- pico_set_color_options(COLOR_ANSI16_OPT);
- break;
- }
-
- if(ps_global->color_style != COL_NONE)
- pico_toggle_color(1);
-
- /* set colors */
- if(pico_usingcolor()){
- if(ps_global->VAR_NORM_FORE_COLOR)
- pico_nfcolor(ps_global->VAR_NORM_FORE_COLOR);
-
- if(ps_global->VAR_NORM_BACK_COLOR)
- pico_nbcolor(ps_global->VAR_NORM_BACK_COLOR);
-
- if(ps_global->VAR_REV_FORE_COLOR)
- pico_rfcolor(ps_global->VAR_REV_FORE_COLOR);
-
- if(ps_global->VAR_REV_BACK_COLOR)
- pico_rbcolor(ps_global->VAR_REV_BACK_COLOR);
-
- pico_set_normal_color();
- }
-
- /* and make sure icon text starts out consistent */
- icon_text(NULL);
- fflush(stdout);
-}
-
-
-
-
-/*----------------------------------------------------------------------
- Get the current window size
-
- Args: ttyo -- pointer to structure to store window size in
-
- NOTE: we don't override the given values unless we know better
- ----*/
-int
-get_windsize(ttyo)
-struct ttyo *ttyo;
-{
-#ifdef RESIZING
- struct winsize win;
-
- /*
- * Get the window size from the tty driver. If we can't fish it from
- * stdout (pine's output is directed someplace else), try stdin (which
- * *must* be associated with the terminal; see init_tty_driver)...
- */
- if(ioctl(1, TIOCGWINSZ, &win) >= 0 /* 1 is stdout */
- || ioctl(0, TIOCGWINSZ, &win) >= 0){ /* 0 is stdin */
- if(win.ws_row)
- _lines = min(win.ws_row, MAX_SCREEN_ROWS);
-
- if(win.ws_col)
- _columns = min(win.ws_col, MAX_SCREEN_COLS);
-
- dprint(2, (debugfile, "new win size -----<%d %d>------\n",
- _lines, _columns));
- }
- else
- /* Depending on the OS, the ioctl() may have failed because
- of a 0 rows, 0 columns setting. That happens on DYNIX/ptx 1.3
- (with a kernel patch that happens to involve the negotiation
- of window size in the telnet streams module.) In this case
- the error is EINVARG. Leave the default settings. */
- dprint(1, (debugfile, "ioctl(TIOCWINSZ) failed :%s\n",
- error_description(errno)));
-#endif
-
- ttyo->screen_cols = min(_columns, MAX_SCREEN_COLS);
- ttyo->screen_rows = min(_lines, MAX_SCREEN_ROWS);
- return(0);
-}
-
-
-/*----------------------------------------------------------------------
- End use of the screen.
- Print status message, if any.
- Flush status messages.
- ----*/
-void
-end_screen(message)
- char *message;
-{
- int footer_rows_was_one = 0;
-
- dprint(9, (debugfile, "end_screen called\n"));
-
- if(FOOTER_ROWS(ps_global) == 1){
- footer_rows_was_one++;
- FOOTER_ROWS(ps_global) = 3;
- mark_status_unknown();
- }
-
- flush_status_messages(1);
- blank_keymenu(_lines - 2, 0);
- MoveCursor(_lines - 2, 0);
-
- /* unset colors */
- if(pico_hascolor())
- pico_endcolor();
-
- if(_termcap_end != NULL)
- tputs(_termcap_end, 1, outchar);
-
- if(message){
- printf("%s\r\n", message);
- }
-
- if(F_ON(F_ENABLE_XTERM_NEWMAIL, ps_global) && getenv("DISPLAY"))
- icon_text("xterm");
-
- fflush(stdout);
-
- if(footer_rows_was_one){
- FOOTER_ROWS(ps_global) = 1;
- mark_status_unknown();
- }
-}
-
-
-
-/*----------------------------------------------------------------------
- Clear the terminal screen
-
- Result: The screen is cleared
- internal cursor position set to 0,0
- ----*/
-void
-ClearScreen()
-{
- _line = 0; /* clear leaves us at top... */
- _col = 0;
-
- if(ps_global->in_init_seq)
- return;
-
- mark_status_unknown();
- mark_keymenu_dirty();
- mark_titlebar_dirty();
-
- /*
- * If the terminal doesn't have back color erase, then we have to
- * erase manually to preserve the background color.
- */
- if(pico_usingcolor() && (!_bce || !_clearscreen)){
- ClearLines(0, _lines-1);
- MoveCursor(0, 0);
- }
- else if(_clearscreen){
- tputs(_clearscreen, 1, outchar);
- moveabsolute(0, 0); /* some clearscreens don't move correctly */
- }
-}
-
-
-/*----------------------------------------------------------------------
- Internal move cursor to absolute position
-
- Args: col -- column to move cursor to
- row -- row to move cursor to
-
- Result: cursor is moved (variables, not updates)
- ----*/
-
-static void
-moveabsolute(col, row)
-{
-
- char *stuff, *tgoto();
-
- stuff = tgoto(_moveto, col, row);
- tputs(stuff, 1, outchar);
-}
-
-
-/*----------------------------------------------------------------------
- Move the cursor to the row and column number
- Args: row number
- column number
-
- Result: Cursor moves
- internal position updated
- ----*/
-void
-MoveCursor(row, col)
- int row, col;
-{
- /** move cursor to the specified row column on the screen.
- 0,0 is the top left! **/
-
- int scrollafter = 0;
-
- /* we don't want to change "rows" or we'll mangle scrolling... */
-
- if(ps_global->in_init_seq)
- return;
-
- if (col < 0)
- col = 0;
- if (col >= ps_global->ttyo->screen_cols)
- col = ps_global->ttyo->screen_cols - 1;
- if (row < 0)
- row = 0;
- if (row > ps_global->ttyo->screen_rows) {
- if (col == 0)
- scrollafter = row - ps_global->ttyo->screen_rows;
- row = ps_global->ttyo->screen_rows;
- }
-
- if (!_moveto)
- return;
-
- if (row == _line) {
- if (col == _col)
- return; /* already there! */
-
- else if (abs(col - _col) < 5) { /* within 5 spaces... */
- if (col > _col && _right)
- CursorRight(col - _col);
- else if (col < _col && _left)
- CursorLeft(_col - col);
- else
- moveabsolute(col, row);
- }
- else /* move along to the new x,y loc */
- moveabsolute(col, row);
- }
- else if (col == _col && abs(row - _line) < 5) {
- if (row < _line && _up)
- CursorUp(_line - row);
- else if (_line > row && _down)
- CursorDown(row - _line);
- else
- moveabsolute(col, row);
- }
- else if (_line == row-1 && col == 0) {
- putchar('\n'); /* that's */
- putchar('\r'); /* easy! */
- }
- else
- moveabsolute(col, row);
-
- _line = row; /* to ensure we're really there... */
- _col = col;
-
- if (scrollafter) {
- while (scrollafter--) {
- putchar('\n');
- putchar('\r');
-
- }
- }
-
- return;
-}
-
-
-
-/*----------------------------------------------------------------------
- Newline, move the cursor to the start of next line
-
- Result: Cursor moves
- ----*/
-void
-NewLine()
-{
- /** move the cursor to the beginning of the next line **/
-
- Writechar('\n', 0);
- Writechar('\r', 0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Move cursor up n lines with terminal escape sequence
-
- Args: n -- number of lines to go up
-
- Result: cursor moves,
- internal position updated
-
- Only for ttyout use; not outside callers
- ----*/
-static void
-CursorUp(n)
-int n;
-{
- /** move the cursor up 'n' lines **/
- /** Calling function must check that _up is not null before calling **/
-
- _line = (_line-n > 0? _line - n: 0); /* up 'n' lines... */
-
- while (n-- > 0)
- tputs(_up, 1, outchar);
-}
-
-
-
-/*----------------------------------------------------------------------
- Move cursor down n lines with terminal escape sequence
-
- Arg: n -- number of lines to go down
-
- Result: cursor moves,
- internal position updated
-
- Only for ttyout use; not outside callers
- ----*/
-static void
-CursorDown(n)
- int n;
-{
- /** move the cursor down 'n' lines **/
- /** Caller must check that _down is not null before calling **/
-
- _line = (_line+n < ps_global->ttyo->screen_rows ? _line + n
- : ps_global->ttyo->screen_rows);
- /* down 'n' lines... */
-
- while (n-- > 0)
- tputs(_down, 1, outchar);
-}
-
-
-
-/*----------------------------------------------------------------------
- Move cursor left n lines with terminal escape sequence
-
- Args: n -- number of lines to go left
-
- Result: cursor moves,
- internal position updated
-
- Only for ttyout use; not outside callers
- ----*/
-static void
-CursorLeft(n)
-int n;
-{
- /** move the cursor 'n' characters to the left **/
- /** Caller must check that _left is not null before calling **/
-
- _col = (_col - n> 0? _col - n: 0); /* left 'n' chars... */
-
- while (n-- > 0)
- tputs(_left, 1, outchar);
-}
-
-
-/*----------------------------------------------------------------------
- Move cursor right n lines with terminal escape sequence
-
- Args: number of lines to go right
-
- Result: cursor moves,
- internal position updated
-
- Only for ttyout use; not outside callers
- ----*/
-static void
-CursorRight(n)
-int n;
-{
- /** move the cursor 'n' characters to the right (nondestructive) **/
- /** Caller must check that _right is not null before calling **/
-
- _col = (_col+n < ps_global->ttyo->screen_cols? _col + n :
- ps_global->ttyo->screen_cols); /* right 'n' chars... */
-
- while (n-- > 0)
- tputs(_right, 1, outchar);
-
-}
-
-
-
-/*----------------------------------------------------------------------
- Insert character on screen pushing others right
-
- Args: c -- character to insert
-
- Result: charcter is inserted if possible
- return -1 if it can't be done
- ----------------------------------------------------------------------*/
-InsertChar(c)
- int c;
-{
- if(_insertchar != NULL && *_insertchar != '\0') {
- tputs(_insertchar, 1, outchar);
- Writechar(c, 0);
- } else if(_startinsert != NULL && *_startinsert != '\0') {
- tputs(_startinsert, 1, outchar);
- Writechar(c, 0);
- tputs(_endinsert, 1, outchar);
- } else {
- return(-1);
- }
- return(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Delete n characters from line, sliding rest of line left
-
- Args: n -- number of characters to delete
-
-
- Result: characters deleted on screen
- returns -1 if it wasn't done
- ----------------------------------------------------------------------*/
-DeleteChar(n)
- int n;
-{
- if(_deletechar == NULL || *_deletechar == '\0')
- return(-1);
-
- while(n) {
- tputs(_deletechar, 1, outchar);
- n--;
- }
- return(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Go into scrolling mode, that is set scrolling region if applicable
-
- Args: top -- top line of region to scroll
- bottom -- bottom line of region to scroll
- (These are zero-origin numbers)
-
- Result: either set scrolling region or
- save values for later scrolling
- returns -1 if we can't scroll
-
- Unfortunately this seems to leave the cursor in an unpredictable place
- at least the manuals don't say where, so we force it here.
------*/
-static int __t, __b;
-
-BeginScroll(top, bottom)
- int top, bottom;
-{
- char *stuff;
-
- if(_scrollmode == NoScroll)
- return(-1);
-
- __t = top;
- __b = bottom;
- if(_scrollmode == UseScrollRegion){
- stuff = tgoto(_scrollregion, bottom, top);
- tputs(stuff, 1, outchar);
- /*-- a location very far away to force a cursor address --*/
- _line = FARAWAY;
- _col = FARAWAY;
- }
- return(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- End scrolling -- clear scrolling regions if necessary
-
- Result: Clear scrolling region on terminal
- -----*/
-void
-EndScroll()
-{
- if(_scrollmode == UseScrollRegion && _scrollregion != NULL){
- /* Use tgoto even though we're not cursor addressing because
- the format of the capability is the same.
- */
- char *stuff = tgoto(_scrollregion, ps_global->ttyo->screen_rows -1, 0);
- tputs(stuff, 1, outchar);
- /*-- a location very far away to force a cursor address --*/
- _line = FARAWAY;
- _col = FARAWAY;
- }
-}
-
-
-/* ----------------------------------------------------------------------
- Scroll the screen using insert/delete or scrolling regions
-
- Args: lines -- number of lines to scroll, positive forward
-
- Result: Screen scrolls
- returns 0 if scroll succesful, -1 if not
-
- positive lines goes foward (new lines come in at bottom
- Leaves cursor at the place to insert put new text
-
- 0,0 is the upper left
- -----*/
-ScrollRegion(lines)
- int lines;
-{
- int l;
-
- if(lines == 0)
- return(0);
-
- if(_scrollmode == UseScrollRegion) {
- if(lines > 0) {
- MoveCursor(__b, 0);
- for(l = lines ; l > 0 ; l--)
- tputs((_scrolldown == NULL || _scrolldown[0] =='\0') ? "\n" :
- _scrolldown, 1, outchar);
- } else {
- MoveCursor(__t, 0);
- for(l = -lines; l > 0; l--)
- tputs(_scrollup, 1, outchar);
- }
- } else if(_scrollmode == InsertDelete) {
- if(lines > 0) {
- MoveCursor(__t, 0);
- for(l = lines; l > 0; l--)
- tputs(_deleteline, 1, outchar);
- MoveCursor(__b, 0);
- for(l = lines; l > 0; l--)
- tputs(_insertline, 1, outchar);
- } else {
- for(l = -lines; l > 0; l--) {
- MoveCursor(__b, 0);
- tputs(_deleteline, 1, outchar);
- MoveCursor(__t, 0);
- tputs(_insertline, 1, outchar);
- }
- }
- } else {
- return(-1);
- }
- fflush(stdout);
- return(0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Write a character to the screen, keeping track of cursor position
-
- Args: ch -- character to output
-
- Result: character output
- cursor position variables updated
- ----*/
-void
-Writechar(ch, new_esc_len)
- register unsigned int ch;
- int new_esc_len;
-{
- static int esc_len = 0;
-
- if(ps_global->in_init_seq /* silent */
- || (F_ON(F_BLANK_KEYMENU, ps_global) /* or bottom, */
- && !esc_len /* right cell */
- && _line + 1 == ps_global->ttyo->screen_rows
- && _col + 1 == ps_global->ttyo->screen_cols))
- return;
-
- if(!iscntrl(ch & 0x7f)){
- putchar(ch);
- if(esc_len > 0)
- esc_len--;
- else
- _col++;
- }
- else{
- switch(ch){
- case LINE_FEED:
- /*-- Don't have to watch out for auto wrap or newline glitch
- because we never let it happen. See below
- ---*/
- putchar('\n');
- _line = min(_line+1,ps_global->ttyo->screen_rows);
- esc_len = 0;
- break;
-
- case RETURN : /* move to column 0 */
- putchar('\r');
- _col = 0;
- esc_len = 0;
- break;
-
- case BACKSPACE : /* move back a space if not in column 0 */
- if(_col != 0) {
- putchar('\b');
- _col--;
- } /* else BACKSPACE does nothing */
-
- break;
-
- case BELL : /* ring the bell but don't advance _col */
- putchar(ch);
- break;
-
- case TAB : /* if a tab, output it */
- do /* BUG? ignores tty driver's spacing */
- putchar(' ');
- while(_col < ps_global->ttyo->screen_cols - 1
- && ((++_col)&0x07) != 0);
- break;
-
- case ESCAPE :
- /* If we're outputting an escape here, it may be part of an iso2022
- escape sequence in which case take up no space on the screen.
- Unfortunately such sequences are variable in length.
- */
- esc_len = new_esc_len - 1;
- putchar(ch);
- break;
-
- default : /* Change remaining control characters to ? */
- if(F_ON(F_PASS_CONTROL_CHARS, ps_global))
- putchar(ch);
- else
- putchar('?');
-
- if(esc_len > 0)
- esc_len--;
- else
- _col++;
-
- break;
- }
- }
-
-
- /* Here we are at the end of the line. We've decided to make no
- assumptions about how the terminal behaves at this point.
- What can happen now are the following
- 1. Cursor is at start of next line, and next character will
- apear there. (autowrap, !newline glitch)
- 2. Cursor is at start of next line, and if a newline is output
- it'll be ignored. (autowrap, newline glitch)
- 3. Cursor is still at end of line and next char will apear
- there over the top of what is there now (no autowrap).
- We ignore all this and force the cursor to the next line, just
- like case 1. A little expensive but worth it to avoid problems
- with terminals configured so they don't match termcap
- */
- if(_col == ps_global->ttyo->screen_cols) {
- _col = 0;
- if(_line + 1 < ps_global->ttyo->screen_rows)
- _line++;
-
- moveabsolute(_col, _line);
- }
-}
-
-
-
-/*----------------------------------------------------------------------
- Write string to screen at current cursor position
-
- Args: string -- string to be output
-
- Result: String written to the screen
- ----*/
-void
-Write_to_screen(string) /* UNIX */
- register char *string;
-{
- while(*string)
- Writechar((unsigned char) *string++, 0);
-}
-
-
-/*----------------------------------------------------------------------
- Write no more than n chars of string to screen at current cursor position
-
- Args: string -- string to be output
- n -- number of chars to output
-
- Result: String written to the screen
- ----*/
-void
-Write_to_screen_n(string, n) /* UNIX */
- register char *string;
- int n;
-{
- while(n-- && *string)
- Writechar((unsigned char) *string++, 0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Clear screen to end of line on current line
-
- Result: Line is cleared
- ----*/
-void
-CleartoEOLN()
-{
- int c, starting_col, starting_line;
- char *last_bg_color;
-
- /*
- * If the terminal doesn't have back color erase, then we have to
- * erase manually to preserve the background color.
- */
- if(pico_usingcolor() && (!_bce || !_cleartoeoln)){
- starting_col = _col;
- starting_line = _line;
- last_bg_color = pico_get_last_bg_color();
- pico_set_nbg_color();
- for(c = _col; c < _columns; c++)
- Writechar(' ', 0);
-
- MoveCursor(starting_line, starting_col);
- if(last_bg_color){
- (void)pico_set_bg_color(last_bg_color);
- fs_give((void **)&last_bg_color);
- }
- }
- else if(_cleartoeoln)
- tputs(_cleartoeoln, 1, outchar);
-}
-
-
-
-/*----------------------------------------------------------------------
- Clear screen to end of screen from current point
-
- Result: screen is cleared
- ----*/
-CleartoEOS()
-{
- int starting_col, starting_line;
-
- /*
- * If the terminal doesn't have back color erase, then we have to
- * erase manually to preserve the background color.
- */
- if(pico_usingcolor() && (!_bce || !_cleartoeos)){
- starting_col = _col;
- starting_line = _line;
- CleartoEOLN();
- ClearLines(_line+1, _lines-1);
- MoveCursor(starting_line, starting_col);
- }
- else if(_cleartoeos)
- tputs(_cleartoeos, 1, outchar);
-}
-
-
-
-/*----------------------------------------------------------------------
- function to output character used by termcap
-
- Args: c -- character to output
-
- Result: character output to screen via stdio
- ----*/
-void
-outchar(c)
-int c;
-{
- /** output the given character. From tputs... **/
- /** Note: this CANNOT be a macro! **/
-
- putc((unsigned char)c, stdout);
-}
-
-
-
-/*----------------------------------------------------------------------
- function to output string such that it becomes icon text
-
- Args: s -- string to write
-
- Result: string indicated become our "icon" text
- ----*/
-void
-icon_text(s)
- char *s;
-{
- static char *old_s;
- static enum {ukn, yes, no} xterm;
-
- if(xterm == ukn)
- xterm = (getenv("DISPLAY") != NULL) ? yes : no;
-
- if(F_ON(F_ENABLE_XTERM_NEWMAIL,ps_global) && xterm == yes && (s || old_s)){
- fputs("\033]1;", stdout);
- fputs((old_s = s) ? s : ps_global->pine_name, stdout);
- fputs("\007", stdout);
- fflush(stdout);
- }
-}
-
-
-#ifdef _WINDOWS
-#line 3 "osdep/termout.gen"
-#endif
-
-/*
- * Generic tty output routines...
- */
-
-/*----------------------------------------------------------------------
- Printf style output line to the screen at given position, 0 args
-
- Args: x -- column position on the screen
- y -- row position on the screen
- line -- line of text to output
-
- Result: text is output
- cursor position is update
- ----*/
-void
-PutLine0(x, y, line)
- int x,y;
- register char *line;
-{
- MoveCursor(x,y);
- Write_to_screen(line);
-}
-
-
-
-/*----------------------------------------------------------------------
- Output line of length len to the display observing embedded attributes
-
- Args: x -- column position on the screen
- y -- column position on the screen
- line -- text to be output
- length -- length of text to be output
-
- Result: text is output
- cursor position is updated
- ----------------------------------------------------------------------*/
-void
-PutLine0n8b(x, y, line, length, handles)
- int x, y, length;
- register char *line;
- HANDLE_S *handles;
-{
- unsigned char c;
-#ifdef _WINDOWS
- int hkey = 0;
-#endif
-
- MoveCursor(x,y);
- while(length-- && (c = (unsigned char)*line++)){
-
- if(c == (unsigned char)TAG_EMBED && length){
- length--;
- switch(*line++){
- case TAG_INVON :
- StartInverse();
- break;
- case TAG_INVOFF :
- EndInverse();
- break;
- case TAG_BOLDON :
- StartBold();
- break;
- case TAG_BOLDOFF :
- EndBold();
- break;
- case TAG_ULINEON :
- StartUnderline();
- break;
- case TAG_ULINEOFF :
- EndUnderline();
- break;
- case TAG_HANDLE :
- length -= *line + 1; /* key length plus length tag */
- if(handles){
- int key, n;
-
- for(key = 0, n = *line++; n; n--) /* forget Horner? */
- key = (key * 10) + (*line++ - '0');
-
-#if _WINDOWS
- hkey = key;
-#endif
-
- if(key == handles->key){
- if(pico_usingcolor() &&
- ps_global->VAR_SLCTBL_FORE_COLOR &&
- ps_global->VAR_SLCTBL_BACK_COLOR){
- pico_set_normal_color();
- }
- else
- EndBold();
-
- StartInverse();
- }
- }
- else{
- /* BUG: complain? */
- line += *line + 1;
- }
-
- break;
- case TAG_FGCOLOR :
- if(length < RGBLEN){
- Writechar(TAG_EMBED, 0);
- Writechar(*(line-1), 0);
- break;
- }
-
- (void)pico_set_fg_color(line);
- length -= RGBLEN;
- line += RGBLEN;
- break;
- case TAG_BGCOLOR :
- if(length < RGBLEN){
- Writechar(TAG_EMBED, 0);
- Writechar(*(line-1), 0);
- break;
- }
-
- (void)pico_set_bg_color(line);
- length -= RGBLEN;
- line += RGBLEN;
- break;
- default : /* literal "embed" char? */
- Writechar(TAG_EMBED, 0);
- Writechar(*(line-1), 0);
- break;
- } /* tag with handle, skip it */
- }
- else if(c == '\033') /* check for iso-2022 escape */
- Writechar(c, match_escapes(line));
- else
- Writechar(c, 0);
- }
-
-
-#if _WINDOWS_X
- if(hkey) {
- char *tmp_file = NULL, ext[32], mtype[128];
- HANDLE_S *h;
- extern HANDLE_S *get_handle (HANDLE_S *, int);
-
- if((h = get_handle(handles, hkey)) && h->type == Attach){
- ext[0] = '\0';
- strcpy(mtype, body_type_names(h->h.attach->body->type));
- if (h->h.attach->body->subtype) {
- strcat (mtype, "/");
- strcat (mtype, h->h.attach->body->subtype);
- }
-
- if(!set_mime_extension_by_type(ext, mtype)){
- char *namep, *dotp, *p;
-
- if(namep = rfc2231_get_param(h->h.attach->body->parameter,
- "name", NULL, NULL)){
- for(dotp = NULL, p = namep; *p; p++)
- if(*p == '.')
- dotp = p + 1;
-
- if(dotp && strlen(dotp) < sizeof(ext) - 1)
- strcpy(ext, dotp);
-
- fs_give((void **) &namep);
- }
- }
-
- if(ext[0] && (tmp_file = temp_nam_ext(NULL, "im", ext))){
- FILE *f = fopen(tmp_file, "w");
-
- mswin_registericon(x, h->key, tmp_file);
-
- fclose(f);
- unlink(tmp_file);
- fs_give((void **)&tmp_file);
- }
- }
- }
-#endif
-}
-
-
-/*----------------------------------------------------------------------
- Printf style output line to the screen at given position, 1 arg
-
- Input: position on the screen
- line of text to output
-
- Result: text is output
- cursor position is update
- ----------------------------------------------------------------------*/
-void
-/*VARARGS2*/
-PutLine1(x, y, line, arg1)
- int x, y;
- char *line;
- void *arg1;
-{
- char buffer[PUTLINE_BUFLEN];
-
- sprintf(buffer, line, arg1);
- PutLine0(x, y, buffer);
-}
-
-
-/*----------------------------------------------------------------------
- Printf style output line to the screen at given position, 2 args
-
- Input: position on the screen
- line of text to output
-
- Result: text is output
- cursor position is update
- ----------------------------------------------------------------------*/
-void
-/*VARARGS3*/
-PutLine2(x, y, line, arg1, arg2)
- int x, y;
- char *line;
- void *arg1, *arg2;
-{
- char buffer[PUTLINE_BUFLEN];
-
- sprintf(buffer, line, arg1, arg2);
- PutLine0(x, y, buffer);
-}
-
-
-/*----------------------------------------------------------------------
- Printf style output line to the screen at given position, 3 args
-
- Input: position on the screen
- line of text to output
-
- Result: text is output
- cursor position is update
- ----------------------------------------------------------------------*/
-void
-/*VARARGS4*/
-PutLine3(x, y, line, arg1, arg2, arg3)
- int x, y;
- char *line;
- void *arg1, *arg2, *arg3;
-{
- char buffer[PUTLINE_BUFLEN];
-
- sprintf(buffer, line, arg1, arg2, arg3);
- PutLine0(x, y, buffer);
-}
-
-
-/*----------------------------------------------------------------------
- Printf style output line to the screen at given position, 4 args
-
- Args: x -- column position on the screen
- y -- column position on the screen
- line -- printf style line of text to output
-
- Result: text is output
- cursor position is update
- ----------------------------------------------------------------------*/
-void
-/*VARARGS5*/
-PutLine4(x, y, line, arg1, arg2, arg3, arg4)
- int x, y;
- char *line;
- void *arg1, *arg2, *arg3, *arg4;
-{
- char buffer[PUTLINE_BUFLEN];
-
- sprintf(buffer, line, arg1, arg2, arg3, arg4);
- PutLine0(x, y, buffer);
-}
-
-
-
-/*----------------------------------------------------------------------
- Printf style output line to the screen at given position, 5 args
-
- Args: x -- column position on the screen
- y -- column position on the screen
- line -- printf style line of text to output
-
- Result: text is output
- cursor position is update
- ----------------------------------------------------------------------*/
-void
-/*VARARGS6*/
-PutLine5(x, y, line, arg1, arg2, arg3, arg4, arg5)
- int x, y;
- char *line;
- void *arg1, *arg2, *arg3, *arg4, *arg5;
-{
- char buffer[PUTLINE_BUFLEN];
-
- sprintf(buffer, line, arg1, arg2, arg3, arg4, arg5);
- PutLine0(x, y, buffer);
-}
-
-
-
-/*----------------------------------------------------------------------
- Output a line to the screen, centered
-
- Input: Line number to print on, string to output
-
- Result: String is output to screen
- Returns column number line is output on
- ----------------------------------------------------------------------*/
-int
-Centerline(line, string)
- int line;
- char *string;
-{
- register int length, col;
-
- length = strlen(string);
-
- if (length > ps_global->ttyo->screen_cols)
- col = 0;
- else
- col = (ps_global->ttyo->screen_cols - length) / 2;
-
- PutLine0(line, col, string);
- return(col);
-}
-
-
-
-/*----------------------------------------------------------------------
- Clear specified line on the screen
-
- Result: The line is blanked and the cursor is left at column 0.
-
- ----*/
-void
-ClearLine(n)
- int n;
-{
- if(ps_global->in_init_seq)
- return;
-
- MoveCursor(n, 0);
- CleartoEOLN();
-}
-
-
-
-/*----------------------------------------------------------------------
- Clear specified lines on the screen
-
- Result: The lines starting at 'x' and ending at 'y' are blanked
- and the cursor is left at row 'x', column 0
-
- ----*/
-void
-ClearLines(x, y)
- int x, y;
-{
- int i;
-
- for(i = x; i <= y; i++)
- ClearLine(i);
-
- MoveCursor(x, 0);
-}
-
-
-
-/*----------------------------------------------------------------------
- Indicate to the screen painting here that the position of the cursor
- has been disturbed and isn't where these functions might think.
- ----*/
-void
-clear_cursor_pos()
-{
- _line = FARAWAY;
- _col = FARAWAY;
-}
-
-