[comp.sources.sun] v02i018: baff - but another folder flasher

mcgrew@aramis.rutgers.edu (Charles Mcgrew) (08/25/90)

Submitted-by: jcb@frisbee.eng.sun.com (Jim Becker)
Posting-number: Volume 2, Issue 18
Archive-name: baff



Since sometimes one want's to preview  mail  headers  without  getting
involved  in obscured console windows or loading up your favorite mail
reader, this program was developed.

Baff is a folder flasher, flat out. It watches  your  spool  file  and
displays  the  user  and  subject  of non-read mail messages onto your
frame buffer. I know that frame buffers are naughty to write  to,  but
how this works makes me happy. So it reads the spool file, then rolls
down the current messages, pauses, then rolls 'em back up.

There are a number of settable things in it. I'm sure there are plenty
more things that can be hung off baff also. See the usage message for
details. Since I use gnuemacs to suck in my spool file, there may need
to be tweaking for mail readers that don't do this.


Yes, you too can be a flasher - Enjoy!


-Jim Becker


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/*
 *
 *	baff.c		-- But Another Folder Flasher
 *
 *	This program runs in the background looking at the user's 
 *	mail spool file. When it detects that there has been a change
 *	to the file, or at periodical intervals when there is outstanding
 *	mail for the user, it blits the author/subject onto the frame
 *	buffer directly. these lines are left up for a period then erased,
 *	via the magic of Xor. 
 *
 *	This depends on using the pixrect library, and there is a hardcoded
 *	default font/fontpath within also. Suns only at this point.
 *
 *	Since the application writes to the frame buffer directly it can be 
 *	used under either SunView or X11/News servers, as well as at the console
 *	level. This will baff*le people that don't know how it's done!
 *
 *	Most things are now flexible for paths and names. See usage message.
 *
 *	To build:	cc -o baff baff.c -lpixrect
 *
 *	Jim Becker	jcb%frisbee@sun.com	-- released Spring 1990
 *
 */

#include	<ctype.h>
#include	<strings.h>
#include	<stdio.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include 	<signal.h>
#include 	<pixrect/pixrect_hs.h>


#define	DELAY_TIME	10		/* time between checks	*/
#define	THRESHHOLD	6		/* #times before show it*/
#define	WAIT_TIME	3		/* how long on screen	*/

#define	FONT_DIR	"/usr/lib/fonts/fixedwidthfonts";
#define	FONT_NAME	"cour.r.16";

#define	STR_MAX		128
#define	MAX_LETTERS	50

#define	TRUE		1
#define	FALSE		0

#define	EQUALN(a,b)	(strncmp((char*)a,(char*)b,strlen(a))==0)

typedef	struct {
	char		user[80];
	char		subject[80];
}	letter;

/*	the following can be changed by the user	*/
static	int		delay_time		= DELAY_TIME;
static	int		threshhold		= THRESHHOLD;
static	int		wait_time		= WAIT_TIME;

static	char		font_dir[STR_MAX]	= FONT_DIR;
static	char		font_name[STR_MAX]	= FONT_NAME;
static	char		font_path[STR_MAX];

static	letter		letter_stack[MAX_LETTERS];
static	int		letter_count;

static	char		file_name[STR_MAX];
static	int		last_file_time, current_file_time;
static	short		user_active;
static	short		subject_active;

static	struct pixrect	*screen;
struct  pixfont		*font_info;
struct  pr_prpos	location;
static	char		message[STR_MAX];

static 	int		ypos = 30, xpos = 30;
static	int		ysize;

static	char		*usage_msg[]	= {
    "\n\t\tBaff	- \"But Another Folder Flasher\"\n\n",

    "This  program  runs in the background looking at the user's mail spool\n",
    "file. When it detects that there has been a change to the file, or  at\n",
    "periodical  intervals  when there is outstanding mail for the user, it\n",
    "blits  the  author/subject onto the frame buffer directly. These lines\n",
    "are left up for a period then erased, Minor visual damage is possible,\n",
    "but harmless. This can also `baff'le those that think it's done in X..\n\n",

    "There are tweakable things, of course, with command line options:\n\n",

    "    -d <nn>	(delay_time)	delay for <nn> seconds between mail checks\n",
    "    -t <nn>	(threshhold)	every <nn> times checked display old info\n",
    "    -w <nn>	(wait_for)	wait for <nn> seconds before erasing info\n\n",

    "The font can be changed with:\n\n",

    "    -font <fontname>		name of a valid SunView style font\n",
    "    -fdir <fontdir>		where the fonts live in system\n\n",
    NULL};

mail_file_time()
{
struct	stat		file_stat;

	if( stat( file_name, &file_stat) != 0 )
		return -1;
	else
		return (int)file_stat.st_mtime;
}

add_current_record()
{
	letter_count++;

	user_active	= FALSE;
	subject_active	= FALSE;	
}		

clear_current_record()
{
	user_active	= FALSE;
	subject_active	= FALSE;	

	if( letter_count > 0 )
		letter_count--;
}		

set_current_user( user )
char		*user;
{
	strcpy( letter_stack[letter_count].user, user );

	user_active	= TRUE;
}

set_current_subject( subject )
char		*subject;
{
	strcpy( letter_stack[letter_count].subject, subject );

	subject_active	= TRUE;
}

open_parse_file()
{
	FILE		*mail;
	char		line[STR_MAX];

	mail	= fopen( file_name, "r" );

	letter_count	= 0;
	clear_current_record();

	if( mail == NULL )
		return letter_count;

	while( fgets( line, sizeof(line), mail ) != NULL ) {

		line[strlen(line)-1] = '\0';

		if( user_active && subject_active ) 
			add_current_record();

		if( EQUALN( "From:", 	line ) )
			set_current_user( &line[6] );
		else
		if( EQUALN( "Subject:", line ) )
			set_current_subject( &line[9] );
		else
		if( EQUALN( "Status:", 	line ) )
			clear_current_record();
	}						

	if( user_active && subject_active ) 
	  	add_current_record();

	fclose(mail);

	return letter_count;
}

/*
 *	write a single line to the display
 */
update_line( lineno )
int	lineno;
{
	sprintf(message, "%-36s \"%s\"\n",
		letter_stack[lineno].user, letter_stack[lineno].subject );
		
	location.pos.x	= xpos;
	location.pos.y	= lineno * ysize + ypos;
		
	pf_ttext( location, PIX_NOT(PIX_DST) | PIX_COLOR( 1 ), 
		 font_info, message );

}

/*
 *	update entire display, first on with the lines then off
 */
update_display()
{
	int		i;

	location.pr = screen;

	/* two loops, cause it looks better to take 'em off in reverse */
	for( i = 0; i < letter_count; i++ ) 
		update_line( i );

	/* let the user see the messages */
	sleep(wait_time);

	for( i = letter_count-1; i >= 0; i-- ) 
		update_line( i );
}

/*
 *	this spits out the message on how to use the demo program.
 */
static	void
usage()
{
	char		**string 	= usage_msg;

	while( *string != NULL )
		printf( *string++ );
}

parse_args( argc, argv )
int		argc;
char		**argv;
{
	char		*arg;
	int		i, j;
	short		error		= FALSE;

	for( i = 1; i < argc; i++ ) {

		arg	= argv[i];

		if( arg[0] == '-' ) {
			switch( arg[1] ) {
			case 	't':
				if( i < (argc-1) ) {
					arg		= argv[++i];
					threshhold	= atoi(arg);
				}
				break;
			case 	'w':
				if( i < (argc-1) ) {
					arg		= argv[++i];
					wait_time	= atoi(arg);
				}
				break;
			case	'd':
				if( i < (argc-1) ) {
					arg		= argv[++i];
					delay_time	= atoi(arg);
				}
				break;
			case	'f':
				if( i < (argc-1) ) {
					if( arg[2] == 'o' ) {
						arg	= argv[++i];
						strcpy( font_name, arg );
					} 
					else if( arg[2] == 'd' ) {
						arg	= argv[++i];
						strcpy( font_dir, arg );
						
						/* trim trailing / if there */
						j	= strlen(font_dir)-1;
						if( font_dir[j] == '/' )
							font_dir[j]	= '\0';
					}
				}
				break;
			default:
				printf("don't understand argument `%s'\n", arg);
			case 	'-':
			case	'h':
				usage();
				error 	= TRUE;
			}
		}
	}

	return !error;
}
	

main( argc, argv )
int		argc;
char		**argv;
{
	int	refresh_count	= 0;

	/* a little hardcoding for the hacker in me.. */
	sprintf( file_name, "/usr/spool/mail/%s", getenv("USER") );

	screen = pr_open( "/dev/fb" );

	if( screen == NULL ) {
		printf("No frame buffer access to /dev/fb..\n");
		exit(1);
	}

	if( argc > 1 ) {
		if( !parse_args( argc, argv ) )
			exit(1);
	}

	/* construct the default fontname */
	sprintf( font_path, "%s/%s", font_dir, font_name );

	font_info = pf_open( font_path );

	if( font_info == NULL ){
		printf("Font `%s' not available..\n", font_path );
		exit(1);
	}

	/* this is the space between lines */
	ysize	= font_info->pf_defaultsize.y;
	ysize  += ysize / 3;	/* spacing */

	while(TRUE) {

		current_file_time	= mail_file_time();

		if( current_file_time > last_file_time || 
		    ++refresh_count   > threshhold ) {

			/* get new letter stack */
			if( open_parse_file() ) 
				update_display();
			  
			last_file_time	= current_file_time;
			refresh_count	= 0;
		}

		sleep(delay_time);
	}
}

-- EOF --
--
--    
	 Jim Becker / jcb%frisbee@sun.com  / Sun Microsystems