home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
1
/
1625
/
say.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-28
|
9KB
|
341 lines
/*
** say - front-end for write(1) that records messages
**
** Copyright (C) 1990 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*/
#ifndef lint
static char rcsid[] = "@(#) $Header: say.c,v 1.7 90/07/24 16:39:48 jef Exp $";
#endif
#include <stdio.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <utmp.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <pwd.h>
#include <ctype.h>
#include <errno.h>
#include "libsaywha.h"
#ifndef _PATH_UTMP
#define _PATH_UTMP "/etc/utmp"
#endif
/* External routines. */
extern int dup2(), fprintf(), printf(), strlen(), strncmp(), system(), vfork();
extern time_t time();
extern char *ctime(), *getenv(), *getlogin(), *mktemp(), *sprintf(), *strcpy(),
*ttyname();
extern int errno; /* in case errno.h fails to declare it */
/* Forward routines. */
int cleanup();
int search_utmp();
/* Private globals. */
static char *tmpfilename = "/tmp/say.XXXXXX";
static int unlinktmpfile = 0;
main( argc, argv )
int argc;
char *argv[];
{
struct stat termstat;
char filename[200], buf[1000];
FILE *fp;
int fd, child, wval;
union wait waitstatus;
sw_argv0 = argv[0];
/* Initialize. */
(void) signal( SIGINT, cleanup );
(void) signal( SIGHUP, cleanup );
if ( sw_check_sayrc( ) < 0 )
(void) cleanup( 1 );
if ( sw_check_my_sayfile( ) < 0 )
(void) cleanup( 1 );
/* Cursory check of args - let write(1) do the rigorous check. */
if ( argc != 2 && argc != 3 )
{
(void) fprintf( stderr, "usage: %s <user> [ <tty> ]\n", sw_argv0 );
(void) cleanup( 1 );
}
if ( search_utmp( argv[1] ) < 0 )
{
(void) fprintf( stderr,
"%s: there is no user \"%s\" logged in right now\n",
sw_argv0, argv[1] );
(void) cleanup( 1 );
}
if ( stat( ttyname( fileno( stderr ) ), &termstat ) >= 0 )
{
if ( ( termstat.st_mode & (S_IWRITE>>3) ) == 0 ) /* group write bit */
{
(void) fprintf( stderr,
"%s: you have write permission turned off\n", sw_argv0 );
(void) cleanup( 1 );
}
}
/* Read in the message and save it to a temp file. */
(void) mktemp( tmpfilename );
if ( ( fp = fopen( tmpfilename, "w" ) ) == NULL )
{
(void) fprintf( stderr, "%s: couldn't open temp file ", sw_argv0 );
perror( tmpfilename );
(void) cleanup( 1 );
}
unlinktmpfile = 1;
(void) fchmod( fileno( fp ), 0600 );
#ifdef MAIL_EDITOR
if ( sw_mail_editor )
{
(void) sprintf( buf, "%s %s", MAIL_EDITOR, tmpfilename );
(void) system( buf );
}
else
{
#endif
if ( ! sw_terse )
(void) printf( "Enter message, '^D' or '.' to end.\n" );
while ( fgets( buf, sizeof(buf), stdin ) != NULL )
{
int i;
if ( buf[0] == '.' && buf[1] == '\n' && buf[2] == '\0' )
break;
/* Write the line with control characters made visible. */
for ( i = 0; buf[i] != '\0'; ++i )
{
char c;
c = toascii( buf[i] );
if ( ! isprint( c ) && ! isspace( c ) && c != '\n' && c != '\007' )
{
(void) putc( '^', fp );
(void) putc( c ^ 0x40, fp ); /* DEL to ?, others to alpha */
}
else
(void) putc( c, fp );
}
}
if ( fclose( fp ) == EOF )
{
(void) fprintf( stderr, "%s: error closing temp file ", sw_argv0 );
perror( tmpfilename );
(void) cleanup( 1 );
}
#ifdef MAIL_EDITOR
}
#endif
/* Try sending it. */
if ( ( child = vfork() ) == 0 )
{
if ( ( fd = open( tmpfilename, O_RDONLY ) ) < 0 )
{
(void) fputs( sw_argv0, stderr );
perror( ": couldn't re-open temp file" );
exit( 1 );
}
(void) dup2( fd, fileno( stdin ) );
if ( argc == 2 )
(void) execlp( WRITE, WRITE, argv[1], NULL );
else
(void) execlp( WRITE, WRITE, argv[1], argv[2], NULL );
(void) fputs( sw_argv0, stderr );
perror( ": exec failed" );
exit( 1 );
}
while ( ( wval = wait( &waitstatus ) ) != child && wval != -1 )
;
if ( wval == child && waitstatus.w_termsig == 0 &&
waitstatus.w_retcode == 0 )
{
/* Success. Now save a copy in the recipient's .sayfile, and the
** sender's too if sw_savemine is set. */
struct passwd *pw;
char *home, *login, *nows;
int myfd;
char myfilename[200], host[100];
time_t now;
if ( ( pw = getpwnam( argv[1] ) ) == NULL )
{
(void) fprintf( stderr, "%s: couldn't find home directory for %s\n",
sw_argv0, argv[1] );
(void) cleanup( 1 );
}
(void) sprintf( filename, "%s/.sayfile", pw->pw_dir );
if ( ( fd = open( filename, O_WRONLY|O_APPEND ) ) < 0 )
{
if ( errno != ENOENT ) /* don't bother reporting lack of .sayfile */
{
(void) fprintf(
stderr, "%s: warning, couldn't open ", sw_argv0 );
perror( filename );
}
}
if ( ( login = getlogin() ) == NULL )
if ( pw = getpwuid( getuid() ) )
login = pw->pw_name;
else
login = "???";
if ( sw_savemine && strcmp( argv[1], login ) != 0 )
{
if ( ( home = getenv( "HOME" ) ) == NULL )
{
(void) fprintf(
stderr, "%s: can't find home directory\n", sw_argv0 );
(void) cleanup( 1 );
}
(void) sprintf( myfilename, "%s/.sayfile", home );
if ( ( myfd = open( myfilename, O_WRONLY|O_APPEND ) ) < 0 )
{
if ( errno != ENOENT ) /* don't bother reporting lack of .sayfile */
{
(void) fprintf(
stderr, "%s: warning, couldn't open ", sw_argv0 );
perror( myfilename );
}
}
}
else
myfd = -1;
if ( fd >= 0 || myfd >= 0 )
{
if ( ( fp = fopen( tmpfilename, "r" ) ) == NULL )
{
(void) fputs( sw_argv0, stderr );
perror( ": couldn't re-open temp file" );
(void) cleanup( 1 );
}
/* Greeting code extracted from BSD write(1). */
if ( gethostname( host, sizeof(host) ) < 0 )
(void) strcpy( host, "???" );
now = time( (time_t *) NULL );
nows = ctime( &now );
nows[16] = '\0';
/* Message separator - a control-A, a timestamp, and the sender. */
(void) sprintf( buf, "%c%d,%s\n", MSGSEP, (int) now, login );
if ( fd >= 0 )
if ( write( fd, buf, strlen(buf) ) < 0 )
{
(void) fprintf( stderr, "%s: error writing on ", sw_argv0 );
perror( filename );
(void) cleanup( 1 );
}
if ( myfd >= 0 )
if ( write( myfd, buf, strlen(buf) ) < 0 )
{
(void) fprintf( stderr, "%s: error writing on ", sw_argv0 );
perror( myfilename );
(void) cleanup( 1 );
}
(void) sprintf( buf, WRITE_HEAD, login, host,
ttyname( fileno( stderr ) ) + 5, nows + 11 );
if ( fd >= 0 )
(void) write( fd, buf, strlen(buf) );
if ( myfd >= 0 )
(void) write( myfd, buf, strlen(buf) );
/* And copy in the message. */
while ( fgets( buf, sizeof(buf), fp ) != NULL )
{
if ( fd >= 0 )
(void) write( fd, buf, strlen(buf) );
if ( myfd >= 0 )
(void) write( myfd, buf, strlen(buf) );
}
if ( fd >= 0 )
(void) write( fd, WRITE_TAIL, strlen(WRITE_TAIL) );
if ( myfd >= 0 )
(void) write( myfd, WRITE_TAIL, strlen(WRITE_TAIL) );
if ( fclose( fp ) == EOF )
{
(void) fprintf(
stderr, "%s: error closing temp file ", sw_argv0 );
perror( tmpfilename );
(void) cleanup( 1 );
}
if ( fd >= 0 )
if ( close( fd ) < 0 )
{
(void) fprintf( stderr, "%s: error closing ", sw_argv0 );
perror( filename );
(void) cleanup( 1 );
}
if ( myfd >= 0 )
if ( close( myfd ) < 0 )
{
(void) fprintf( stderr, "%s: error closing ", sw_argv0 );
perror( myfilename );
(void) cleanup( 1 );
}
}
}
else
{
/* Write failed. */
(void) printf(
"Your message could not be delivered for some reason.\n" );
(void) printf( "I will mail it instead.\n" );
(void) sprintf( buf, "mail -s 'this was a failing say' %s < %s",
argv[1], tmpfilename );
(void) system( buf );
}
/* All done. */
(void) cleanup( 0 );
}
int
search_utmp( user )
char *user;
{
struct utmp u;
int ufd;
if ( ( ufd = open( _PATH_UTMP, O_RDONLY ) ) < 0 )
{
perror( _PATH_UTMP );
(void) cleanup( 1 );
}
while ( read( ufd, (char *) &u, sizeof(u) ) == sizeof(u) )
{
if ( strncmp( user, u.ut_name, sizeof(u.ut_name) ) == 0 )
{
(void) close( ufd );
return 0;
}
}
(void) close( ufd );
return -1;
}
int
cleanup( status )
int status;
{
sw_cleanup( );
if ( unlinktmpfile )
(void) unlink( tmpfilename );
unlinktmpfile = 0;
exit( status );
}