/*
 *  hap -- a mail notification program
 * 
 *  copyright 1995 by Eric Fischer, etaoin@uchicago.edu
 * 
 *  copies of hap may be redistributed under the terms of the
 *  GNU public license, copies of which are available from
 *  the Free Software Foundation, 59 Temple Place, Boston, MA
 *  02111 USA.
 *
 */

#include "hap.h"

/************************************************************************

  SCREEN OUTPUT STUFF

************************************************************************/

/* terminals who claim not to be able to save and restore the
   cursor in their termcap entries, but who are emulating vt100s
   and therefore really can.

   It's possible there are ancient terminals by these names that
   really can't do it.  Too bad for them...
*/

char *brokentermcaplist[] = {
	"xterm",
	"iris-ansi-net",
	0
};

char *savecurs = 0;     /* not static because main() cares */
static char *homecurs = 0;
static char *restorecurs = 0;
static char *inverse = 0;
static char *normal = 0;
static char *cleareol = 0;
static char *movecurs = 0;
static char *leftcurs = 0;

int tcaplines;  /* used in ioctl.c as a last resort */
int tcapcols;   /* ditto */

/* print a single character to the standard output.  Return the character
   we were given, though I'm pretty sure it gets thrown away by tputs().
*/

int
outchar (what)
	int what;
{
	printf ("%c", what);
	return what;
}

/* get termcap stuff.  complain if we're missing something, but continue
   merrily onward and just do ugly output.

   contains special cases for xterm-type terminals which can save and
   restore the cursor but whose termcaps, for whatever insane reason,
   don't declare this fact.
*/

void
inittcap()
{
	static char tbuf[2048], ttmp[2048], *here = ttmp;
	char *TERM;

	TERM = getenv ("TERM");
	if (TERM == 0) {
		fprintf (stderr, "%s: %s %s", program,
		    "warning: you should set TERM if you want things to",
		    "work happily.\n");
		return;
	}

	if (tgetent (tbuf, TERM) != 1) {
		fprintf (stderr, "%s: %s ``%s''\n", program,
		    "warning: can't get the termcap entry for your terminal",
		    TERM);
		return;
	}

	savecurs = tgetstr ("sc", &here);
	restorecurs = tgetstr ("rc", &here);

	if (savecurs == 0 || restorecurs == 0) {

		/* help out these poor deprived termcap entries */

		char **maybe = brokentermcaplist;

		while (*maybe) {
			if (same (TERM, *maybe)) {
				savecurs = "\0337";
				restorecurs = "\0338";
				break;
			}

			maybe++;
		}
		
		if (savecurs == 0 || restorecurs == 0 ) {

			/* didn't work -- be boring */

			savecurs = 0, restorecurs = 0;  /* make sure *both* 
			                                   are 0 */
		}
	}

	inverse = tgetstr ("so", &here);
	normal = tgetstr ("se", &here);

	if (!inverse || !normal) {
		inverse = 0, normal = 0;
	}

	/* if standout mode is going to take up screen space,
	   we don't know how to deal with that.
	*/

	if (tgetnum ("sg") > 0) {
		inverse = 0, normal = 0;
	}

	tcaplines = tgetnum ("li");
	if (tcaplines <= 0) tcaplines = 24;

	tcapcols = tgetnum ("co");
	if (tcapcols <= 0) tcapcols = 80;

	homecurs = tgetstr ("ho", &here);
	cleareol = tgetstr ("ce", &here);
	movecurs = tgetstr ("cm", &here);

	if (homecurs == 0 && savecurs != 0) {
		fprintf (stderr, "%s: %s %s", program,
		    "warning: your terminal can save and restore the cursor\n",
		    "but not *move* it?  Weird.\n");
		savecurs = 0, restorecurs = 0;
	}

	leftcurs = tgetstr ("le", &here);
}

/* move the cursor to an arbitrary location.  for terse (-t). */

void
gotoyx (y, x)
	int y;
	int x;
{
	char *move = tgoto (movecurs, x, y);

	if (move) {
		tputs (move, 1, outchar);
	}
}

/*  echo as many dashes as the width of the screen and a newline */

void
spewlines()
{
	int cols = screenwid();

	while (cols--) {
		printf ("-");
	}

	printf ("\n\r");
}

/* print fewer lines, so that the cursor doesn't fall off the right
   side of the screen when we can't get it back to where it belongs.
*/

void
spewfewerlines()
{
	int cols = screenwid() - 1;

	while (cols--) {
		printf ("-");
	}

	printf ("\n\r");
}

/* start a message display: save the cursor and move to upper left */

void
startmessage()
{
	if (savecurs) {
		tputs (savecurs, 1, outchar);
		if (homecurs) tputs (homecurs, 1, outchar);
		if (normal) tputs (normal, 1, outchar);
	} else {
		printf ("\n\r");
		if (!inverse || !likeinverse) spewfewerlines();
	}
}

/* end of the message.  lay down a line of dashes, put the cursor back,
   and throw all this output to the terminal in one fell swoop
*/

void
endmessage()
{
	if (restorecurs) {
		if (!likeinverse) {
		/*	if (inverse) tputs (inverse, 1, outchar); */
			spewlines();
		/*	if (normal) tputs (normal, 1, outchar); */
		}

		tputs (restorecurs, 1, outchar);
	} else {
		if (!inverse || !likeinverse) spewfewerlines();
	}
	fflush (stdout);
}

/* newline.  if we have clear to eol, use it; do both \n and \r in
   case the terminal is in raw mode and nobody told us.
*/

void
crlf()
{
	if (cleareol) tputs (cleareol, 1, outchar);
	printf ("\n\r");
}


/* output a string to the screen.  make sure we don't fall off the end
   of the display, or take up too much vertical space, and handle the
   biff emulation if we're doing that.

   control characters other than \n will not be pretty.

   automatically reduces streams of \n characters to a single \n;
   if you want blank lines make sure to include a space or something
   on them.
*/

void
spew (what)
	char *what;
{
	int c = 0;

	int wid = screenwid() - 1; 
	int high = screenhigh() / 2 - 1;
	int msglines;
	int theline = 0;

	if (what == 0) return;

	if (debug) {
		printf ("%s", what);
		return;
	}

	msglines = numlns (what);
	if (msglines > high) {
		what = skiplines (what, msglines - high);
	}

	if (likeinverse) {
		if (inverse) tputs (inverse, 1, outchar);
	}

	while (*what) {
		unsigned char uwhat = *((unsigned char *) what);

		if (*what == '\n') {
			if (likeinverse) {
				while (c < wid) {
					printf (" ");
					c++;
				}

				c = 0;

				if (savecurs && movecurs) {
					printf (" ");
					gotoyx (++theline, 0);
				} else {
					crlf();
				}
			} else {
				c = 0;
				crlf();
			}

			/* elide blank lines */

			while (what[1] == '\n') what++;
		} else if (uwhat < ' ' || (uwhat >= 127 && uwhat < 128 + ' ')) {
			if (c+5 < wid) {
				printf ("\\%3.3o", uwhat);
				c += 4;
			} else if (c < wid) {
				printf ("^");
				c++;
			}
		} else if (c < wid) {
			if (biff) {
				char w = *what;

				if      (w == '!'
				&&       c < wid-8) printf (".");
				else if (w == 'o'
				||       w == 'O') printf ("0");
				else if (w == 'e'
				||       w == 'E') printf ("3");
				else if (w == 'i'
				||       w == 'I') printf ("1");
				else if (w == 's'
				||       w == 'S') printf ("Z");
				else if (w == '/') printf ("\\");
				else if (islower (w)) printf ("%c", toupper(w));
				else if (isupper (w)) printf ("%c", tolower(w));
				else if (w == '\'') c--;  /* nothing */
				else if (w == '.'
				&&       !isdigit(what[1])) printf ("!");
				else printf ("%c", w);
			} else {
				printf ("%c", *what);
			}

			c++;  /* heh.  they said c++.  heh heh. */
		}

		what++;
	}

	if (likeinverse) {
		if (normal) tputs (normal, 1, outchar);
	}
}

/* combine two strings into a temp one, spew them */

void
spewtwo (one, two)
	char *one;
	char *two;
{
	static char *foo = 0;

	if (foo) free (foo), foo = 0;

	foo = addtostr (foo, one);
	foo = addtostr (foo, two);
	spew (foo);
}

/* spew a string as tersely as we can manage.  Loses everything but
   the first word of each line and crams everything into the upper
   right hand corner of the screen.  If it's too big to fit, chop
   off words from the start until it does.

   if we don't have cursor save and restore, just print '(mail)' and
   enough backspaces to get us back to where we were.
*/

void
tespew (s)
	char *s;
{
	/* this function uses "@" as padding because we specifically
	   never let a word contain an @
	 */

	static char *temp = 0;
	char *here;
	int fullwid = screenwid();
	int wid = fullwid / 2;

	if (temp) free (temp), temp = 0;
	temp = xmalloc ((strlen (s) + 1) * sizeof (char));

	here = temp;

	*here = ' ';
	here++;

	while (*s) {
		if (starts (s, "New mail")) {  /* skip such lines */
			while (*s && (*s != '\n')) s++;
			while (*s == '\n') s++;
		}

		while (isspace (*s)) s++;   /* skip leading spaces */
		while (isdigit (*s)) s++;   /* skip message number */
		while (isspace (*s)) s++;   /* skip more spaces... */

		while (*s == '-') s++;      /* if no sender, skip the -- */
		while (isspace (*s)) s++;   /* ...and get to the 1st word */

		while (*s == '"') s++;      /* some mailers quote names */

		while ((!isspace (*s)) 
		&&     (*s)
		&&     (*s != '@')
		&&     (*s != '"')) {   /* copy 1st word */
			*here = *s;
			s++, here++;
		}

		while ((*s) && (*s != '\n')) {   /* skip to end of line */
			s++;
		}

		while (*s == '\n') s++;        /* skip newline */

		if (*s) {    /* if not at end of string, add spaces */
			*here++ = ' ';
			*here++ = '@';
			*here++ = ' ';
		}
	}

	*here = ' ';
	here++;

	*here = 0;

	here = temp;
	while (strlen (here) > wid) {
		while (*here && *here != '@') here++;  /* chop a word */
		while (*here && *here == '@') here++;  /* and a space */
	}

	if (savecurs && movecurs) {
		tputs (savecurs, 1, outchar);
		gotoyx (0, fullwid - strlen (here) - 2);
		printf ("  ");
		if (inverse && likeinverse) tputs (inverse, 1, outchar);

		while (*here) {
			if (*here == '@') {
				if (inverse && likeinverse) 
			 	    tputs (normal, 1, outchar);
				printf (" ");
				if (normal && likeinverse) 
				    tputs (inverse, 1, outchar);
			} else {
				if (*here < ' ' || *here >= 127) {
					printf ("^");
				} else {
					printf ("%c", *here);
				}
			}

			here++;
		}

		if (normal && likeinverse) tputs (normal, 1, outchar);
		tputs (restorecurs, 1, outchar);
	} else {
		int i;

		printf ("(mail)");
		for (i = 0; i < 6; i++) {
			if (leftcurs) {
				tputs (leftcurs, 1, outchar);
			} else {
				printf ("\b");
			}
		}
	}

	fflush (stdout);
}

/* spew two strings, tersely */

void
tespewtwo (one, two)
	char *one;
	char *two;
{
	static char *foo = 0;

	if (foo) free (foo), foo = 0;

	foo = addtostr (foo, one);
	foo = addtostr (foo, two);
	tespew (foo);
}

