home *** CD-ROM | disk | FTP | other *** search
- /*
- ** 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 );
- }
-
-