Newsgroups: comp.sources.unix From: jmsellens@watdragon.waterloo.edu (John M. Sellens) Subject: v25i151: msgd - sends a one line message to another user or users Sender: unix-sources-moderator@pa.dec.com Approved: vixie@pa.dec.com Submitted-By: jmsellens@watdragon.waterloo.edu (John M. Sellens) Posting-Number: Volume 25, Issue 151 Archive-Name: msgd [ name changed from msg to msgd to prevent name collision from volume 4. i'm rethinking the archive index to see whether such collisions are neccessary. --vix ] MSG sends a one line message to another user or users, possibly over the network. We like it much more than write(1) and talk(1). jmsellens@watdragon.waterloo.edu (John M. Sellens) #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh './README' <<'END_OF_FILE' XMSG sends a one line message to another user or users, possibly over Xthe network. We like it much more than write(1) and talk(1). X XFor example, X % msg jdoe@othermachine X Let's go eat! X % X jdoe@othermachine: ok - where? X msg -r X msg: Replying to 'jdoe@othermachine' X How about the cafeteria? X % X XTo install, add the lines to /etc/services and /etc/inetd.conf, Xmodify the Makefile and */Makefile to your needs, and adjust XInclude/msgoptions.h to set the options that are appropriate for you. X Xmesg is a modified version of the Berkeley mesg program. The Tahoe Xversion appears with the Berkeley copyright - this version is based on X4.2 or 4.3, and so I added the Berkeley copyright notice, and assume Xthat distribution is ok. This version allows you to set an answerback Xmessage that will be given to any user trying to send you a message. XNote that this version has to be setuid root so that it can remove Xother users answerback message files. X XWe use this on Sun3, Sun4, BSD Vax, Ultrix Vax, MIPS, DEC MIPS, and Sequent. X XNote that the service number that we use has not been officially Xregistered. If I ever get off my butt, and register a real number, Xit should be relatively easy to update things. Or so I like to think. XI'd like to encourage everyone to use the same port number i.e. 1241/tcp, Xotherwise we won't be able to talk to each other. X XNaturally, no warranties, bug fixes and enhancements accepted, but Xno support committments. Available via anonymous ftp from Xwatmath.waterloo.edu in pub/msg.shar. X XJohn Sellens XMath Faculty Computing Facility XUniversity of Waterloo Xjmsellens@watmath.waterloo.edu END_OF_FILE if test 1625 -ne `wc -c <'./README'`; then echo shar: \"'./README'\" unpacked with wrong size! fi # end of './README' fi if test ! -d './Common' ; then echo shar: Creating directory \"'./Common'\" mkdir './Common' fi if test -f './Common/answerback.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Common/answerback.c'\" else echo shar: Extracting \"'./Common/answerback.c'\" \(2095 characters\) sed "s/^X//" >'./Common/answerback.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: /fsys4/usr/source/users/msg/Common/RCS/answerback.c,v 1.2 90/12/29 21:59:53 jmsellen Exp $"; X#endif X X#if 0 X/* X * $Log: answerback.c,v $ X * Revision 1.2 90/12/29 21:59:53 jmsellen X * Use ANSBACK define from Include/msg.h X * X * Revision 1.1 87/08/06 19:06:19 sahayman X * Initial revision X * X */ X#endif X X/* answerback.c X Return a user's answerback message to the person who sent him a X message. X*/ X X#include "msg.h" X#include X X#define MYBUFSIZ (BUFSIZ/2) /* BUFSIZ is max errmsg size */ X X X/* We may be sending to multiple instances of the same user, so it makes X since to remember the last user we looked up and his/her UID to avoid X searching the passwd file again. */ X Xanswerback( errcode, user, line ) Xint errcode; Xchar *user; Xchar *line; X{ X static char lastuser[25]; /* too hard to use sizeof() */ X static int lastuid = -1; X struct stat sbuf; X FILE *fp; X char answerbuf[sizeof(ANSBACK)+25]; /* lots of extra room */ X /* find name of answerback file */ X (void) sprintf( answerbuf, "%s%s", ANSBACK, line ); X /* Now make sure that if the answerback file exists, it belongs to X the user we're sending to */ X if ( stat( answerbuf, &sbuf ) == -1 ) X return; /* no answerback exists */ X if ( strcmp( user, lastuser ) != 0 ) { X /* we don't know this guy, so look him up */ X struct passwd *pw = getpwnam( user ); X endpwent(); X if ( pw == (struct passwd *)NULL ) X /* I know this guy exists, but ignore it */ X return; X (void) strcpy( lastuser, user ); X lastuid = pw->pw_uid; X } X if ( sbuf.st_uid != lastuid ) X return; /* not his file */ X /* we don't care if we can't read his message - it's his problem */ X if ( (fp=fopen(answerbuf,"r")) != FPNULL ) { X char buf[MYBUFSIZ+1]; X int len; X if ( (len=fread( buf, 1, MYBUFSIZ, fp )) > 0 ) { X if ( buf[len-1] =='\n' ) len--; X buf[len] = '\0'; /* make it terminated */ X if ( errcode == ANS_WARN ) X errmsg( errcode, user, line, buf ); X else X errmsg( errcode, user, hostname, line, buf ); X } X (void) fclose( fp ); X } X} END_OF_FILE if test 2095 -ne `wc -c <'./Common/answerback.c'`; then echo shar: \"'./Common/answerback.c'\" unpacked with wrong size! fi # end of './Common/answerback.c' fi if test -f './Common/deliver.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Common/deliver.c'\" else echo shar: Extracting \"'./Common/deliver.c'\" \(4264 characters\) sed "s/^X//" >'./Common/deliver.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: /fsys4/usr/source/users/msg/Common/RCS/deliver.c,v 1.4 90/12/29 21:59:07 jmsellen Exp $"; X#endif X X/* deliver.c X Deliver a message to a user on this machine. X*/ X X/* X * Old revision log: X * X * Revision 1.4 87/06/04 12:49:47 jmsellens X * Changes to put the msg save file in /usr/tmp X * rationalized the code a little, added the NO_STAT error condition X * X * Revision 1.3 87/04/13 09:46:09 sahayman X * Make sure to do answerback() on unsuccessful messages (mesg n) X * as well as successful. X * X * Revision 1.2 87/04/06 02:16:30 sahayman X * Print a "However ... " message when unable to deliver to some X * ttys but able to deliver to others. X * X */ X#include "msg.h" X#include X#include X#include X Xstatic jmp_buf timeout; X X Xstatic Xwakeup() X{ X longjmp( timeout, 1 ); X} X X X Xint Xdeliver( sender, user, message, fromroot ) Xchar *sender, *user, *message; X{ X struct utmp ut; X FILE *fp, *term; X char terminal[40]; /* should be enough ... */ X int found = 0, errcode = 0; X int however = 0; /* Should we print a "however ...." msg */ X struct stat sbuf; X char line[sizeof(ut.ut_line)+5]; X char successful_line[sizeof(ut.ut_line)+5]; X int (*osig)(); X#ifdef SAVEMSG X int uid = -1; X#endif X X successful_line[0] = '\0'; X X if ( (fp=fopen( UTMP, "r" )) == FPNULL ) { X errmsg( NO_UTMP, hostname, syserr() ); X return( NO_UTMP ); X } X /* keep on until end of file in case s/he's signed on more than once */ X while ( fread( &ut, sizeof(struct utmp), 1, fp ) == 1 ) { X if ( strncmp( user, ut.ut_name, sizeof(ut.ut_name) ) != 0 ) X continue; X#ifdef SYSV_UTMP X if ( ut.ut_type != USER_PROCESS ) X continue; X#endif X found++; X (void) strncpy( line, ut.ut_line, sizeof(ut.ut_line) ); X line[sizeof(ut.ut_line)] = '\0'; X (void) sprintf( terminal, "%s%s", DEV, line ); X /* stat it to see if we're allowed to write */ X if ( stat(terminal,&sbuf) == 0 ) { X#ifdef SAVEMSG X uid = sbuf.st_uid; X#endif X if ( ((sbuf.st_mode&ALLOW)==0) && !fromroot ) { X errmsg( MESG_OFF, user, hostname, line ); X however++; X errcode++; X } else { X if ( setjmp( timeout ) ) { X errmsg( TIMEOUT, user, hostname, line ); X however++; X } else { X osig = signal(SIGALRM, wakeup); X alarm( 5 ); X if ( (term=fopen(terminal,"w")) != NULL ) { X fprintf(term, "\n\007%s: %s\n", sender, message); X /* we need this fflush() or else it would hang in the X fclose() after we've dealt with the alarm() */ X fflush( term ); X strcpy( successful_line, line ); X } X } X alarm( 0 ); X signal(SIGALRM, osig); X if (term == NULL) { X errmsg( NO_WRITE, user, hostname, line, syserr() ); X however++; X errcode++; X } else X fclose( term ); X } X#ifdef ANSWERBACK X answerback( ANSWER, user, line ); X#endif X } else { X errmsg( NO_STAT, terminal, user, hostname, syserr() ); X however++; X errcode++; X } X } X (void) fclose( fp ); X#ifdef SAVEMSG X /* note that these saves it even if mesg n was set */ X if ( found && uid != -1 ) X savemsg( uid, user, sender, message ); X#endif X if ( !found ) { X errmsg( NOT_ON, user, hostname ); X errcode++; X } X /* X * A message like "so-and-so (ttyxx) is not receiving messages" X * is not too helpful when they are receiving messages X * on another terminal. So mention that. X * ..sah 87/04/06 X */ X X if ( however && successful_line[0] ) { X errmsg( HOWEVER, user, hostname, successful_line ); X } X return( errcode ); X} X X X#define DEL (127) X Xsanitize( mbuf, copy ) Xchar *mbuf; Xchar *copy; X{ X char *p, *r; X /* X * Remove control characters to prevent nasties. X * Previously allowed isspace(*p), but having a \r in a message X * is asking for forgeries. isprint() is sufficient. X * (And good programmers always use isascii() first, right?) X */ X for ( p = mbuf, r = copy; *p; p++,r++ ) { X if ( ! isascii( *p ) ) { X *r++ = '\\'; X *p = toascii( *p ); X } X if ( ! isprint(*p) ) { X if ( *p == '\t' ) X *r = ' '; X else if ( iscntrl( *p ) ) { X *r++ = '^'; X if ( *p == DEL ) X *r = '?'; X else X *r = *p + '@'; X } else /* this shouldn't happen, but what the hell */ X *r = 'X'; X } else X *r = *p; X } X} END_OF_FILE if test 4264 -ne `wc -c <'./Common/deliver.c'`; then echo shar: \"'./Common/deliver.c'\" unpacked with wrong size! fi # end of './Common/deliver.c' fi if test -f './Common/errtext.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Common/errtext.c'\" else echo shar: Extracting \"'./Common/errtext.c'\" \(2177 characters\) sed "s/^X//" >'./Common/errtext.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: /usr/source/mfcf/msg/common/RCS/errtext.c,v 1.3 89/01/08 03:16:36 jmsellens Exp $"; X#endif X X#if 0 X/* X * $Log: errtext.c,v $ X * Revision 1.3 89/01/08 03:16:36 jmsellens X * Changed BADHOST error message to not mention hosts file, since X * we don't use it any longer. X * X * Revision 1.2 88/09/25 02:40:49 jmsellens X * added message for BAD_VERSION X * X * Revision 1.1 87/08/06 19:06:32 sahayman X * Initial revision X * X */ X#endif X X/* msgtext.c X Text of error messages produced by the system X*/ X X#include "msg.h" X Xchar *errmessages[] = { X /* OK */ X "", X /* NOT_ON - user, host */ X "%s@%s is not signed on", X /* NO_WRITE - user, host, ut.u_line, syserr() */ X "couldn't write to %s@%s (%s): %s", X /* BAD_HOST - host */ X "host '%s' is unknown", X /* NO_UTMP - host, syserr() */ X "couldn't open utmp on host '%s': %s", X /* BAD_ARGS - not used I think */ X "bad argument(s)", X /* NO_CONNECT - host syserr() */ X "couldn't connect to daemon on host '%s': %s (not running?)", X /* FATAL - not used I think */ X "fatal error", X /* NO_ACK - host */ X "didn't receive acknowledgement from host '%s'", X /* REMOTE_WRITE - host, syserr() */ X "error writing to host '%s': %s", X /* REMOTE_READ - host, syserr() */ X "error writing from host '%s': %s", X /* MESG_OFF user, host, ut.u_line */ X "%s@%s (%s) is not receiving messages", X /* NO_REPLY user, ut.u_line */ X "WARNING: Your terminal (%s on %s) cannot be written to", X /* TIMEOUT user, host, ut.u_line */ X "timed out writing to %s@%s (%s) - terminal paging set?", X /* ANSWER user, host, line, answerbackmessage */ X "%s@%s (%s): %s", X /* ANS_WARN user, line, answerbackmessage */ X "%s on %s: Answerback message set to '%s'", X /* NO_TTY */ X "WARNING: You are not on a terminal", X /* HOWEVER */ X "However, %s@%s (%s) received the message", X /* NO_STAT - terminal, user, host, syserr() */ X "Couldn't stat '%s' of %s@%s: %s - message not delivered", X /* BAD_VERSION - remote version, our version */ X "Client version (%d) newer than server (%d) - can't understand you", X 0 X}; END_OF_FILE if test 2177 -ne `wc -c <'./Common/errtext.c'`; then echo shar: \"'./Common/errtext.c'\" unpacked with wrong size! fi # end of './Common/errtext.c' fi if test -f './Common/misc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Common/misc.c'\" else echo shar: Extracting \"'./Common/misc.c'\" \(457 characters\) sed "s/^X//" >'./Common/misc.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: misc.c,v 1.1 87/08/06 19:06:34 sahayman Exp $"; X#endif X X#if 0 X/* X * $Log: misc.c,v $ X * Revision 1.1 87/08/06 19:06:34 sahayman X * Initial revision X * X */ X#endif X X/* misc.c X miscellaneous routines X*/ X X Xextern int sys_nerr, errno; Xextern char *sys_errlist[], *sprintf(); X Xchar * Xsyserr() X{ X static char buf[80]; X X return( (errno'./Common/savemsg.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: /source/users/msg/Common/RCS/savemsg.c,v 1.8 91/08/13 23:57:35 jmsellens Exp $"; X#endif X X#if 0 X/* X * $Log: savemsg.c,v $ X * Revision 1.8 91/08/13 23:57:35 jmsellens X * s/eprintf/errprintf/ to avoid libuw clash X * X * Revision 1.7 91/08/13 23:57:05 jmsellens X * realuser stuff X * X * Revision 1.6 90/12/29 22:01:03 jmsellen X * Avoid PMBECOME, and handle DUMBSHORT machines X * X * Revision 1.5 88/09/25 03:03:29 jmsellens X * call syserr() is pmbecome() fails X * X * Revision 1.4 87/10/19 18:29:11 sahayman X * Use pmbecome() to become different users, since the simple X * seteuid( old_euid ) after you seteuid (someone) won't work. X * X * Revision 1.2 87/08/06 20:17:31 sahayman X * Write /usr/tmp/msg.user file by doing a seteuid(user) first, so that X * it has a chance of working when /usr/tmp is an NFS partition. X * No longer writes ~/.msg. X * X * Revision 1.1 87/08/06 19:06:40 sahayman X * Initial revision X * X */ X#endif X X#include "msg.h" X#include X#ifdef REALUSER X#include X#endif X X Xsavemsg( uid, recipient, sender, msg ) Xint uid; Xchar *recipient, *sender, *msg; X{ X char fname[100]; /* lots o' room */ X FILE *fp; X struct passwd *pwd; X#ifdef PMBECOME X int old_euid = geteuid(); X#endif /* PMBECOME */ X X /* X * Original code used to write into ~/.msg. No more. X */ X X /* truncate the recipient for lookup */ X if ( strlen(recipient) > sizeof(((struct utmp *)NULL)->ut_name) ) X recipient[sizeof(((struct utmp *)NULL)->ut_name)] = '\0'; X if ((pwd = getpwnam(recipient)) == (struct passwd *) NULL) { X#ifdef DUMBSHORT X /* loop through the whole passwd file looking for a X truncated match */ X struct utmp *ut; /* just for sizeof() */ X setpwent(); X while ( (pwd = getpwent()) != (struct passwd *) NULL ) { X if ( strncmp(recipient,pwd->pw_name,sizeof(ut->ut_name)) == 0 ) X break; X } X if ( pwd == (struct passwd *) NULL ) X return; X recipient = pwd->pw_name; X#else X return; X#endif X } X#ifdef REALUSER X recipient = realuser( pwd ); X#endif X X X /* now, put it where it really belongs, in MSGFILE */ X X#ifdef PMBECOME X /* X * This seteuid() business is so that this can work X * when /usr/tmp is an NFS thingy, and root on a client X * can only creat things there owned by -2, so the old X * scheme of opening the file and then chowning it wouldn't work. X */ X X#ifdef old X if ( seteuid( pwd->pw_uid ) == -1 ) { X errprintf("savemsg: Cannot seteuid(%d)", pwd->pw_uid); X#else X if ( pmbecome( pwd->pw_uid ) == -1 ) { X errprintf("savemsg: Cannot pmbecome(%d): %s", pwd->pw_uid, syserr()); X#endif X X /* X * Keep going, it might work... X */ X } X#endif /* PMBECOME */ X X strcpy( fname, MSGFILE ); X strcat( fname, recipient ); X X (void) unlink( fname ); /* in case it already exists */ X X if ( (fp = fopen( fname, "w" ) ) != NULL ) { X (void) fchmod( fileno(fp), 0600 ); X (void) fchown( fileno(fp), pwd->pw_uid, -1 ); X fprintf( fp, "%s: %s\n", sender, msg ); X (void) fclose( fp ); X } X X#ifdef PMBECOME X if ( pmbecome(0) == -1 ) X errprintf("savemsg: Cannot pmbecome(0): %s", syserr()); X#endif /* PMBECOME */ X} END_OF_FILE if test 3173 -ne `wc -c <'./Common/savemsg.c'`; then echo shar: \"'./Common/savemsg.c'\" unpacked with wrong size! fi # end of './Common/savemsg.c' fi if test ! -d './Include' ; then echo shar: Creating directory \"'./Include'\" mkdir './Include' fi if test -f './Include/msg.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Include/msg.h'\" else echo shar: Extracting \"'./Include/msg.h'\" \(2892 characters\) sed "s/^X//" >'./Include/msg.h' <<'END_OF_FILE' X/* msg.h X header file for msg and msgd X*/ X X/* X * $Header: /usr/source/users/msg/Include/RCS/msg.h,v 1.9 91/03/08 20:13:16 jmsellens Exp Locker: jmsellens $ X * X */ X X/* Options */ X#include "msgoptions.h" X X#include X#include X#include X#define UTMP "/etc/utmp" /* why isn't this in utmp.h?? */ X#ifdef USER_PROCESS X#define SYSV_UTMP X#endif X#include X#define ALLOW ((S_IWRITE>>3)|(S_IWRITE>>6)) X#ifdef VARARGS X#include X#endif X X#define DEV "/dev/" X#define MSGFILE "/usr/tmp/msg." /* where to save messages, append userid */ X#define PMSGFILE "/usr/tmp/pmsg." /* where to save outgoing messages */ X#define ANSBACK "/usr/tmp/mesg." /* where asnwerback message might be */ X X#define private static X Xextern char hostname[]; Xextern char *syserr(); X X/* X * Following are in network byte order. X */ Xtypedef struct header { X int slen; /* sender length */ X int ulen; /* userid length */ X int mlen; /* message length */ X} header; X X/* This version header was added after the original version of msg had X been installed and was running. To provide compatibility with versions X of msg that do not send a version as the first information, this X version struct must be twelve bytes long, and the first int is always X a 0, because if it is non-zero you can assume that it is a sender X length in a header, and not a version struct. X*/ Xtypedef union version { X header h; X struct v { X int zero; X int vnum; /* version number */ X int filler; X } v; X} version; X#define VERSION (1) /* current version */ X X Xextern char *errmessages[]; X/* error codes for message - msgtext.c relies on this ordering */ X#define OK (0) X#define VERSION_OK OK /* got a version, and we accept it */ X#define NOT_ON (1) /* user not signed on */ X#define NO_WRITE (2) /* couldn't write to terminal */ X#define BAD_HOST (3) /* host doesn't exist */ X#define NO_UTMP (4) /* couldn't open /etc/utmp */ X#define BAD_ARGS (5) /* bad arguments */ X#define NO_CONNECT (6) /* couldn't connect to remote host */ X#define FATAL (7) /* fatal error */ X#define NO_ACK (8) /* no result from remote host */ X#define REMOTE_WRITE (9) /* write error to remote host */ X#define REMOTE_READ (10) /* read error from remote host */ X#define MESG_OFF (11) /* dest user has mesg n set */ X#define NO_REPLY (12) /* can't get replies */ X#define TIMEOUT (13) /* timeout while writing to user's terminal */ X#define ANSWER (14) /* asnwerback message */ X#define ANS_WARN (15) /* user has answerback msg set */ X#define NO_TTY (16) /* user is not on a tty */ X#define HOWEVER (17) /* However, another tty was writable. */ X#define NO_STAT (18) /* couldn't stat tty */ X#define BAD_VERSION (19) /* client newer than server */ X X#define ERROR_MESSAGE (99) /* error message being returned from msgd */ X X#define FPNULL ((FILE *)NULL) X#define CPNULL ((char *)NULL) X#define TRUE (1) X#define FALSE (0) END_OF_FILE if test 2892 -ne `wc -c <'./Include/msg.h'`; then echo shar: \"'./Include/msg.h'\" unpacked with wrong size! fi # end of './Include/msg.h' fi if test -f './Include/msgoptions.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Include/msgoptions.h'\" else echo shar: Extracting \"'./Include/msgoptions.h'\" \(1588 characters\) sed "s/^X//" >'./Include/msgoptions.h' <<'END_OF_FILE' X/* msgoptions.h X separate options file, so I can #inlcude it in an Imakefile X*/ X X/* X * $Header: /usr/source/users/msg/Include/RCS/msg.h,v 1.9 91/03/08 20:13:16 jmsellens Exp Locker: jmsellens $ X * X */ X X/* Options */ X/* define PMBECOME if you want to use the Waterloo pmbecome() routine X which allows you to seteuid() to a user, and seteuid() back to root X later. Only needed if the MSGFILE is on a partition that root can't X write, such as on pre 4.0 SunOS diskless clients. */ X/* #define PMBECOME */ X X/* define SAVEMSG to save received messages in MSGFILE */ X#define SAVEMSG X X/* define ANSWERBACK to allow the use of answerback files set up by X mesg to send back to the sender when a message is received. */ X#define ANSWERBACK X X/* define REMOTE to always use the daemon to deliver instead of doing X local delivery when possible. This means msg doesn't have to be X setuid/setgid, but it's also slower. */ X/* #define REMOTE */ X X/* define VARARGS if you have the varargs stuff, including vprintf and X friends. */ X#define VARARGS X X/* define DUMBSHORT if you're silly enough to have long userids in the X passwd file, but short userids everywhere else. We were silly enough X to be doing this on our MIPS machines ... */ X/* #define DUMBSHORT */ X X/* define REALUSER if you want to use the MFCF realuser() routine to find X out your "real" campus-wide userid and use that as the return address. X This won't be useful outside Waterloo, and I hope I remembered to remove X the "-luw" from the Makefile before sending it into the outside world. */ X/* #define REALUSER */ END_OF_FILE if test 1588 -ne `wc -c <'./Include/msgoptions.h'`; then echo shar: \"'./Include/msgoptions.h'\" unpacked with wrong size! fi # end of './Include/msgoptions.h' fi if test -f './Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Makefile'\" else echo shar: Extracting \"'./Makefile'\" \(385 characters\) sed "s/^X//" >'./Makefile' <<'END_OF_FILE' X# Makes msg and msgd and mesg, one hopes. X XTOP = /software/users XBINDIR = $(TOP)/bin XSERVDIR = $(TOP)/servers XMANDIR = $(TOP)/man X XMACROS = BINDIR=$(BINDIR) SERVDIR=$(SERVDIR) MANDIR=$(MANDIR) X Xall\ Xclean\ Xinstall: X cd msg && $(MAKE) $(MFLAGS) $(MACROS) $@ X cd msgd && $(MAKE) $(MFLAGS) $(MACROS) $@ X cd mesg && $(MAKE) $(MFLAGS) $(MACROS) $@ X cd Man && $(MAKE) $(MFLAGS) $(MACROS) $@ END_OF_FILE if test 385 -ne `wc -c <'./Makefile'`; then echo shar: \"'./Makefile'\" unpacked with wrong size! fi # end of './Makefile' fi if test ! -d './Man' ; then echo shar: Creating directory \"'./Man'\" mkdir './Man' fi if test -f './Man/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Man/Makefile'\" else echo shar: Extracting \"'./Man/Makefile'\" \(448 characters\) sed "s/^X//" >'./Man/Makefile' <<'END_OF_FILE' XMANDIR = /software/users/man XMANUSER = bin XMANMODE = 444 X Xall: X echo All made in Man Xclean: X echo All clean in Man Xinstall: X cp -p msg.1 $(MANDIR)/man1 X chown $(MANUSER) $(MANDIR)/man1/msg.1 X chmod $(MANMODE) $(MANDIR)/man1/msg.1 X cp -p msgd.8 $(MANDIR)/man8 X chown $(MANUSER) $(MANDIR)/man8/msgd.8 X chmod $(MANMODE) $(MANDIR)/man8/msgd.8 X cp -p mesg.8 $(MANDIR)/man8 X chown $(MANUSER) $(MANDIR)/man8/mesg.8 X chmod $(MANMODE) $(MANDIR)/man8/mesg.8 END_OF_FILE if test 448 -ne `wc -c <'./Man/Makefile'`; then echo shar: \"'./Man/Makefile'\" unpacked with wrong size! fi # end of './Man/Makefile' fi if test -f './Man/mesg.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Man/mesg.1'\" else echo shar: Extracting \"'./Man/mesg.1'\" \(1937 characters\) sed "s/^X//" >'./Man/mesg.1' <<'END_OF_FILE' X.\" Copyright (c) 1987 Regents of the University of California. X.\" All rights reserved. X.\" X.\" Redistribution and use in source and binary forms are permitted X.\" provided that the above copyright notice and this paragraph are X.\" duplicated in all such forms and that any documentation, X.\" advertising materials, and other materials related to such X.\" distribution and use acknowledge that the software was developed X.\" by the University of California, Berkeley. The name of the X.\" University may not be used to endorse or promote products derived X.\" from this software without specific prior written permission. X.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X.\" X.\" @(#)mesg.1 6.3 (Berkeley) 7/9/88 X.\" X.TH MESG 1 "18 July 1983" X.SH NAME Xmesg \- permit or deny messages X.SH SYNOPSIS X.B mesg X[ X.B n X] [ X.B y X] X[answerback message] X.SH DESCRIPTION X.I Mesg Xwith argument X.B n Xforbids messages via X.I write Xand X.IR talk (1) Xby revoking non-user Xwrite permission on the user's terminal. X.I Mesg Xwith argument X.B y Xreinstates permission. XAll by itself, X.I mesg Xreports the current state and answerback message without changing it. X.PP XThe answerback message Xis used as an automatic response to anyone who tries to send you a msg. XThe existing answerback message is removed on subsequent X.I mesg Xcommand invocations (except when no arguments are given). X.SH EXAMPLE Xmesg n Please send me mail instead. X.SH BUGS X.I mesg Xwill not work within a X.IR script (1) Xsession because there is no way for it to find out what terminal Xyou are really signed on to. X.SH FILES X/dev/tty* X.br X/usr/tmp/mesg.tty* X.SH "SEE ALSO" Xwrite(1), talk(1) X.SH DIAGNOSTICS XExit status is 0 if messages are receivable, X1 if not, 2 on error. X.SH NOTE XAnswerback messages are a Waterloo addition. END_OF_FILE if test 1937 -ne `wc -c <'./Man/mesg.1'`; then echo shar: \"'./Man/mesg.1'\" unpacked with wrong size! fi # end of './Man/mesg.1' fi if test -f './Man/msg.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Man/msg.1'\" else echo shar: Extracting \"'./Man/msg.1'\" \(3411 characters\) sed "s/^X//" >'./Man/msg.1' <<'END_OF_FILE' X.TH MSG 1 "University of Waterloo" X.SH NAME Xmsg \- write a short message to other users X.SH SYNOPSIS X.B msg X[ X.B \-l X] X[ X.B \-m X.I message X] X[ X.B \-p X] X[ X.B \-r X] X[ X.B \-t X] Xuser ... X.SH DESCRIPTION X.I Msg Xwrites a one-line message to a given set of users. XIf a user is logged in more than once, each instance of that user will receive Xthe message. X.PP XPrevious versions of X.I msg Xallowed the last argument to be the message. This confusing behaviour Xis no longer available. X.PP XThe message is preceded by a beep, Xthe login name of the sender, Xand the name of the sender's machine. XIf the sender is set-userid to someone other than the super-user, Xthen the real (set-userid) name is printed in parentheses. XReplies should use the login name, not the parenthesized (set-userid) name, Xsince the login name is the way X.I msg Xfinds people. X.PP X.I Msg Xworks across machines, as long as the remote machine is running the X.IR msgd (8) Xmessage daemon. XTo do this, X.I user Xshould be of the form X.I person@machine X(or the old-style X.I machine!person X). X.PP XIt is very annoying to receive a message just before your screen clears, Xmaking it impossible to read the message. XTo help alleviate this problem, X.I msg Xwill save a copy of the message and you can use the X.I -l Xoption to repeat the last message you received. X.PP XIt is also annoying to discover a message on your screen but not know Xwhen it was sent. Use \fB\-t\fP to find out. X.SH OPTIONS X.TP 10 X.B \-r XIf the X.BR \-r , Xoption is given, X.I msg Xwill look in the file X.I /usr/tmp/msg.userid Xfile to find out the last person who sent you a message, Xand assume you want to reply to them. X(Additional recipients can still be specified, so the same Xrules apply about which arguments are messages and which are users. XThe easiest thing to use is X.I "msg -r" Xwith no other arguments; type the reply on the next line.) X.TP X.B \-l XList the last message received. XThis simply shows the file X.I /usr/tmp/msg.userid Xso that you don't have to remember the name. X.I "msg -lr" Xis a handy way to show the last message and prompt for a reply. X.TP X.B \-t XShow the time that the last message was received. Handy combinations are X.B \-tl Xand X.B \-tlr. X.TP X.B \-p XUse the text of the previous message you sent (saved in the file X.IR /usr/tmp/pmsg.userid ) Xas the text of this message. This is handy if you mistyped someone's Xuserid, and typed a long message only to have it fail. X.PP X.I Msg Xobeys the restrictions of X.IR mesg (1). X.SH "SEE ALSO" Xwrite(1), mail(1), talk(1), msgd(8) X.SH EXAMPLES X.TP 10 X% msg -m 'This is the message in quotes.' user1 user2 XQuoting a string makes it one argument as far as Unix is concerned. X.TP 10 X% msg user1 user2 X X.TP 10 X% msg -r X X.TP 10 X% msg -r -m 'Or you can put the reply here.' X.SH FILES X.TP X/usr/tmp/msg.userid XContains the last message received. X.TP X/usr/tmp/pmsg.userid XContains the text of the previous message sent or attempted. X.TP X/usr/tmp/mesg.userid XAnswerback message - set by mesg(1). X.SH AUTHOR XThe staff of the Math Faculty Computing Facility at the University Xof Waterloo, Waterloo, Ontario Canada. Bug reports can be sent Xto either or both of John Sellens (jmsellens@watmath.waterloo.edu) Xor uw.mfcf.bugs@watmath.waterloo.edu. X.SH COPYRIGHT XCopyright 1988, 1989, 1990 University of Waterloo X.br XRedistribution is permitted. END_OF_FILE if test 3411 -ne `wc -c <'./Man/msg.1'`; then echo shar: \"'./Man/msg.1'\" unpacked with wrong size! fi # end of './Man/msg.1' fi if test -f './Man/msgd.8' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./Man/msgd.8'\" else echo shar: Extracting \"'./Man/msgd.8'\" \(728 characters\) sed "s/^X//" >'./Man/msgd.8' <<'END_OF_FILE' X.TH MSGD 8 "University of Waterloo" X.SH NAME Xmsgd \- remote message daemon X.SH DESCRIPTION X.I Msgd Xaccepts connections from remote X.IR msg (1) Xcommands for delivery to users on the local system. X.PP X.I Msgd Xis normally run under X.IR inetd (8). X.SH FILES X.IP /etc/services Xdefines which port X.I msgd Xwill use X.IP /etc/inetd.conf Xconfig file for X.I inetd X.SH "SEE ALSO" Xmsg(1), mesg(1) X.SH AUTHOR XThe staff of the Math Faculty Computing Facility at the University Xof Waterloo, Waterloo, Ontario Canada. Bug reports can be sent Xto either or both of John Sellens (jmsellens@watmath.waterloo.edu) Xor uw.mfcf.bugs@watmath.waterloo.edu. X.SH COPYRIGHT XCopyright 1988, 1989, 1990 University of Waterloo X.br XRedistribution is permitted. END_OF_FILE if test 728 -ne `wc -c <'./Man/msgd.8'`; then echo shar: \"'./Man/msgd.8'\" unpacked with wrong size! fi # end of './Man/msgd.8' fi if test -f './inetd.conf' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./inetd.conf'\" else echo shar: Extracting \"'./inetd.conf'\" \(61 characters\) sed "s/^X//" >'./inetd.conf' <<'END_OF_FILE' Xmsg stream tcp nowait root /software/users/servers/msgd msgd END_OF_FILE if test 61 -ne `wc -c <'./inetd.conf'`; then echo shar: \"'./inetd.conf'\" unpacked with wrong size! fi # end of './inetd.conf' fi if test ! -d './mesg' ; then echo shar: Creating directory \"'./mesg'\" mkdir './mesg' fi if test -f './mesg/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./mesg/Makefile'\" else echo shar: Extracting \"'./mesg/Makefile'\" \(378 characters\) sed "s/^X//" >'./mesg/Makefile' <<'END_OF_FILE' X# Needs to be setuid root so we can remove others' answerback files X XBINDIR = /software/users/bin XMANDIR = /software/users/man X XNAME = mesg XOWNER=root XGROUP=staff XMODE=4755 X XOBJECT = mesg.o X Xall: $(NAME) X X$(NAME): $(OBJECT) X cc -o $(NAME) $(OBJECT) X Xinstall: $(NAME) X install -s -o $(OWNER) -g $(GROUP) -m $(MODE) $(NAME) $(BINDIR)/$(NAME) X Xclean: X rm -f a.out core *.o $(NAME) END_OF_FILE if test 378 -ne `wc -c <'./mesg/Makefile'`; then echo shar: \"'./mesg/Makefile'\" unpacked with wrong size! fi # end of './mesg/Makefile' fi if test -f './mesg/mesg.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./mesg/mesg.c'\" else echo shar: Extracting \"'./mesg/mesg.c'\" \(4528 characters\) sed "s/^X//" >'./mesg/mesg.c' <<'END_OF_FILE' X/* X * Copyright (c) 1987 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley. The name of the X * University may not be used to endorse or promote products derived X * from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#ifndef lint Xchar copyright[] = X"@(#) Copyright (c) 1987 Regents of the University of California.\n\ X All rights reserved.\n"; X#endif /* not lint */ X Xstatic char *sccsid = "@(#)mesg.c 4.2 (Berkeley) 10/18/80"; X/* X * mesg -- set current tty to accept or X * forbid write permission. X * X * mesg [yn] "answerback message" X * y allow messages X * n forbid messages X * answerback is what the other guy gets told (Waterloo) X * needs to be setuid root to get rid of other people's X * old answerback message files X * X */ X X#include X#include X#include X#include X#include X X#define ANSWERBACK_FMT "/usr/tmp/mesg.%s" X Xmain(argc, argv) X char **argv; X{ X int uid, mode, r=0; X char *tty, *p, *rindex(), *ttyname(); X FILE *fp; X int i_own_answerback = 0; X struct stat sbuf; X struct passwd *pw; X char answerback[200]; X X (void) umask(022); /* so we can read answerback file */ X tty = ttyname(2); X if (tty == 0) X error("Cannot determine name of current terminal", (char *)0); X if ( (p=rindex(tty,'/')) != NULL ) X p++; X else X p = tty; X /* X * If this isn't a login session, use of mesg is meaningless. X */ X uid = getuid(); X pw = getpwuid(uid); X if (pw == NULL) { X fprintf(stderr, "mesg: Can't find your uid (%d) in the password file\n", uid); X exit(2); X } X if (!in_utmp(pw->pw_name, p)) { X fprintf(stderr, "mesg: Current terminal session on %s is not a login session\n", tty); X exit(2); X } X /* find name of answerback file */ X (void) sprintf( answerback, ANSWERBACK_FMT, p ); X /* Now make sure that if the answerback file exists, it belongs to X the current user */ X if ( lstat( answerback, &sbuf ) == 0 ) { X if (sbuf.st_uid == uid) X i_own_answerback = 1; X else X (void) unlink(answerback); X } X if(stat(tty, &sbuf) < 0) error("cannot stat", tty); X /* X * must be root before here so we can get rid of other persons X * answerback file since sticky bit is on tmp directory. X * must be real user after here so he cant read/write *any* file X * by creating a link in the tmp directory. X */ X setuid(uid); X if(argc < 2) { X if(sbuf.st_mode & 020) X printf( "is y\n" ); X else { r=1; X printf( "is n\n" ); X } X if (i_own_answerback) { X if ( (fp=fopen(answerback,"r")) != NULL ) { X int c; X while ( (c=getc(fp)) != EOF ) X putc( c, stdout ); X (void) fclose( fp ); X } else X error("Can't read answerback file", answerback); X } X } else { X if (i_own_answerback) X (void) unlink(answerback); X if ( argv[1][0] == 'y' ) { X mode = sbuf.st_mode | 020; X } else if ( argv[1][0] == 'n' ) { X mode = sbuf.st_mode & ~022; X r = 1; X } else X error("usage: mesg [yn] [answerback message]", (char *)0); X if (chmod(tty, mode) < 0) X error("cannot change modes", tty); X if ( argc > 2 ) { /* write answerback message */ X int i; X if ( (fp=fopen(answerback,"w")) == (FILE *)NULL ) X error("Couldn't write answerback file", answerback); X for ( i=2; i2 ) X putc( ' ', fp ); X fputs( argv[i], fp ); X } X putc( '\n', fp ); X (void) fclose( fp ); X } X } X exit(r); X} X Xerror(s, arg) Xchar *s, *arg; X{ X fprintf(stderr,"mesg: %s", s); X if (arg) X perror(arg); X else X putc('\n', stderr); X exit(2); X} X X/* X * Does the given (user,tty) pair appear in the utmp file? X */ Xin_utmp(user, tty) X char *user, *tty; X{ X FILE *fp; X struct utmp utmp; X X if ((fp = fopen("/etc/utmp", "r")) == NULL) X return 0; X while (fread((char *)&utmp, sizeof utmp, 1, fp) == 1) { X if (strncmp(user, utmp.ut_name, sizeof utmp.ut_name) == 0 && X strncmp(tty, utmp.ut_line, sizeof utmp.ut_line) == 0) { X#ifdef USER_PROCESS X if ( utmp.ut_type != USER_PROCESS ) X continue; X#endif X fclose(fp); X return 1; X } X } X fclose(fp); X return 0; X} END_OF_FILE if test 4528 -ne `wc -c <'./mesg/mesg.c'`; then echo shar: \"'./mesg/mesg.c'\" unpacked with wrong size! fi # end of './mesg/mesg.c' fi if test ! -d './msg' ; then echo shar: Creating directory \"'./msg'\" mkdir './msg' fi if test -f './msg/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./msg/Makefile'\" else echo shar: Extracting \"'./msg/Makefile'\" \(927 characters\) sed "s/^X//" >'./msg/Makefile' <<'END_OF_FILE' X# Needs to be setuid root so that msg save files can be made and chown'd. X# Needs to be setgid tty so that we can write to ttys in /dev X XBINDIR = /software/users/bin XMANDIR = /software/users/man X XNAME = msg XOWNER=root XGROUP=tty XMODE=6555 XCFLAGS= -I../Include $(DBX) X XOBJECT = msg.o remote.o deliver.o misc.o errtext.o savemsg.o answerback.o X Xall: $(NAME) X X$(NAME): $(OBJECT) X cc -o $(NAME) $(OBJECT) X Xinstall: $(NAME) X install -s -o $(OWNER) -g $(GROUP) -m $(MODE) $(NAME) $(BINDIR)/$(NAME) X Xclean: X rm -f a.out core *.o $(NAME) X X$(OBJECT): ../Include/msg.h ../Include/msgoptions.h X Xanswerback.o: ../Common/answerback.c X cc $(CFLAGS) -c ../Common/answerback.c X Xdeliver.o: ../Common/deliver.c X cc $(CFLAGS) -c ../Common/deliver.c X Xerrtext.o: ../Common/errtext.c X cc $(CFLAGS) -c ../Common/errtext.c X Xmisc.o: ../Common/misc.c X cc $(CFLAGS) -c ../Common/misc.c X Xsavemsg.o: ../Common/savemsg.c X cc $(CFLAGS) -c ../Common/savemsg.c END_OF_FILE if test 927 -ne `wc -c <'./msg/Makefile'`; then echo shar: \"'./msg/Makefile'\" unpacked with wrong size! fi # end of './msg/Makefile' fi if test -f './msg/msg.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./msg/msg.c'\" else echo shar: Extracting \"'./msg/msg.c'\" \(12537 characters\) sed "s/^X//" >'./msg/msg.c' <<'END_OF_FILE' X/* X * $Header: /source/users/msg/msg/RCS/msg.c,v 1.24 91/08/18 18:37:29 dgharriss Exp $ X */ X X/* X * msg.c X * MSG re-written to use a daemon X * John Sellens, University of Waterloo X */ X X#include "msg.h" X#include X#include X X#ifdef REALUSER X#include X#endif X X/* global */ char hostname[80]; Xprivate char *progname; X#define USERIDSPACE (80) /* lots of room */ Xprivate char sender[USERIDSPACE]; Xprivate char loginname[USERIDSPACE]; Xprivate int uid; /* effective */ Xprivate int ruid; /* real */ X Xprivate char msg_file[80]; Xprivate char pmsg_file[80]; X Xextern char *syserr(); Xextern char *ttyname(); X Xprivate int getsender(), sendmsg(); Xprivate void replywarn(); Xprivate void usage(); Xprivate void getprevious(); Xprivate void putprevious(); Xextern void fatal(); X X#define SU (0) /* uid of super-user */ X Xmain( argc, argv ) Xint argc; Xchar *argv[]; X{ X register int i; X register int exitcode = 0; X int fromroot; X int useprevious = 0; /* send previous text as msg */ X int cmdlinemsg = 0; /* msg is on cmd line */ X char *p; X char message[1024]; /* to hold message */ X char rawmsg[1024]; /* to hold unclean message */ X char *tname; /* name of current tty */ X char *reply = NULL, *reply_to(); X X X int c; X extern int optind; X extern char *optarg; X X X progname = argv[0]; X if ( argc == 1 ) X usage(); X X if ( gethostname( hostname, (int)sizeof(hostname) ) ) X fatal( "Couldn't gethostname(): %s", syserr() ); X X fromroot = getsender(); X strcpy( msg_file, MSGFILE ); X strcat( msg_file, loginname ); X strcpy( pmsg_file, PMSGFILE ); X strcat( pmsg_file, loginname ); X X while (( c = getopt(argc, argv, "lm:prt")) != EOF ) { X switch( c ) { X case 'l': X list_msg(); X break; X case 'm': X strcpy( rawmsg, optarg ); /* hope they don't have a giant msg */ X cmdlinemsg++; X break; X case 'p': X useprevious++; X break; X case 'r': X if ( (reply = reply_to()) == NULL ) { X fatal( "Nobody to reply to in last message file '%s'", X msg_file ); X } X break; X case 't': X list_msgtime(); X break; X default: X usage(); X } X } X if ( useprevious && cmdlinemsg ) X fatal( "-m and -p can't be used together" ); X X /* Tell 'em now so that the lastmsg comes before you get the replying X message, and tell them so they know who they're sending to, in X case it's wrong. */ X if ( reply != NULL ) X errprintf("Replying to '%s'", reply); X X /* X * Simpler to pretend the options weren't there. Skip over 'em. X * argv/argc is now a vector of user names. X */ X argc -= optind; X argv += optind; X X X if ( (cmdlinemsg||useprevious) && reply == NULL && argc == 0 ) X fatal( "No one to send message to" ); X X /* X * Quietly exit if no recipients and no reply. This covers the case X * where all we got was the -l option. X */ X if ( reply == NULL && argc == 0 ) X exit(0); X X /* Old behaviour used - as last argument to indicate msg on stdin */ X if ( strcmp("-", argv[argc-1]) == 0 ) { X errprintf( "'-' as last argument is obsolete - ignored" ); X argc--; X } X X if ( useprevious ) { X getprevious( rawmsg, (int)sizeof(rawmsg) ); X } else if ( ! cmdlinemsg ) { X if ( fgets( rawmsg, (int)sizeof(rawmsg), stdin ) == NULL ) { X /* assume user changed their mind */ X return(0); X } X p = index(rawmsg, '\n'); X if (p == NULL) X errprintf("Message truncated to %d characters.", sizeof(rawmsg) ); X else X *p = NULL; X } X X if ( *rawmsg == '\0' ) /* No message to send. */ X return(0); X sanitize( rawmsg, message ); X X if ( useprevious ) X printf( "Sending: %s\n", message ); X else X putprevious( message ); X X if( (tname=ttyname(0)) || (tname=ttyname(1)) || (tname=ttyname(2)) ) X replywarn(tname); /* warn if can't get replies on this tty */ X#if 0 X /* Is this a good idea? -IAN! */ X else X errmsg( NO_TTY ); X#endif X X /* X * Send a reply if -r was used, also send to all other X * recipients on the command line. X */ X X if ( reply != NULL && sendmsg(reply, message, fromroot) != OK ) X exitcode++; X X while ( --argc >= 0 ) { X /* sendmsg() will destroy the argv[i] */ X if ( sendmsg( *argv++, message, fromroot ) != OK ) X exitcode++; X } X return( exitcode!=0 ); X} X X X/* X * Find out who the sender is. Try getlogin(), and if that X * differs from the REAL uid, make sure both names appear. X * Return 1 if we are root, 0 otherwise. X */ Xstatic int Xgetsender() X{ X extern char *getlogin(), *getenv(); X struct passwd *pw; X char pwname[USERIDSPACE]; X char *glog; X X ruid = uid = getuid(); X X /* Check out who we're running as */ X if ( (pw=getpwuid(uid)) == NULL ) X fatal("Your uid number (%d) isn't recognized.\n", uid); X if(pw->pw_name == NULL || pw->pw_name[0] == '\0') X fatal("No pwname is associated with uid %d.\n", uid); X#ifdef REALUSER X (void) strcpy( pwname, realuser( pw ) ); X#else X (void) strcpy( pwname, pw->pw_name ); X#endif X X /* see if we can use getlogin() to see who it is */ X (void) strcpy( loginname, (glog=getlogin()) == 0 ? "" : glog ); X if ( *loginname ) { X /* check the passwd file for this guy */ X pw = getpwnam( loginname ); X if ( pw ) { X ruid = pw->pw_uid; X#ifdef DUMBSHORT X { X struct utmp *ut; X if ( strncmp( pwname, loginname, sizeof(ut->ut_name) ) == 0 ) X (void) strcpy( loginname, pwname ); X } X#endif X#ifdef REALUSER X (void) strcpy( loginname, realuser( pw ) ); X#endif X } X } else { X /* no better guess at real identity, use USER if we're root */ X if ( uid == SU && (glog=getenv("USER"))!=(char *)NULL && *glog ) { X /* look up the pw entry for USER */ X if ( (pw=getpwnam(glog)) != (struct passwd *)NULL ) { X ruid = pw->pw_uid; X#ifdef REALUSER X glog = realuser( pw ); X#endif X } X strcpy( loginname, glog ); X } else X strcpy( loginname, pwname ); X } X X if ( X#ifdef REALUSER X ! sameuser( pwname, loginname ) X#else X strcmp( pwname, loginname ) != 0 X#endif X && uid != SU ) { X /* Names differ, and user isn't SU, so send both */ X (void) sprintf(sender, "%s(%s)@%s", loginname, pwname, hostname); X } else { X (void) sprintf(sender, "%s@%s", loginname, hostname); X } X X return( uid == SU ); X} X X Xprivate int Xsendmsg( recipient, message, fromroot ) Xchar *recipient, *message; Xint fromroot; X{ X register char *p, *user, *host; X#ifndef REMOTE X int local = FALSE; X#endif X int errcode; X if ( (p = index( recipient, '@' )) != CPNULL ) { X user = recipient; X host = p+1; X *p = '\0'; X } else if ( (p = index( recipient, '!' )) != CPNULL ) { X user = p+1; X host = recipient; X *p = '\0'; X } else { X user = recipient; X host = hostname; X } X/* always go via the daemon, because it means we don't have to be X setuid, and it makes things a little bit simpler. I hope - jms. X wrong - jms */ X#ifndef REMOTE X /* this only works if they use the full host name, not an alias, but X that's okay ... */ X if ( strcmp( host, hostname ) == 0 ) X local = TRUE; X if ( local ) X errcode = deliver( sender, user, message, fromroot ); X else X#endif X errcode = remote( sender, user, host, message ); X return( errcode ); X} X X X X/* Warn user on tname if he/she can't receive messages. X */ Xprivate void Xreplywarn(tname) X char *tname; X{ X struct utmp ut; X struct stat sbuf; X FILE *fp; X char *p; X char terminal[80]; /* should be enough ... */ X X if( (fp=fopen( UTMP, "r" )) == FPNULL ) { X errmsg( NO_UTMP, hostname, syserr() ); X } else { X if( (p=rindex(tname,'/')) != NULL ) X tname = p + 1; X while ( fread((char*)&ut,sizeof(struct utmp),1,fp) != 0 ){ X if( strncmp(tname,ut.ut_line,(int)sizeof(ut.ut_line)) == 0 ){ X (void) sprintf( terminal, "%s%s", DEV, tname ); X if ( stat(terminal,&sbuf)!=-1 && ((sbuf.st_mode&ALLOW)==0) ) X errmsg( NO_REPLY, loginname, tname ); X#ifdef ANSWERBACK X answerback( ANS_WARN, loginname, tname ); X#endif X break; /* only need to check the first match */ X } X } X (void) fclose( fp ); X } X} X X Xprivate void Xusage() X{ X errprintf( "Usage: %s [-l] [-m message] [-p] [-r] [-t] [user ...]", X progname ); X exit( BAD_ARGS ); X} X X X#ifdef VARARGS Xerrprintf( s, va_alist ) Xchar *s; Xva_dcl X{ X va_list ap; X (void) fprintf( stderr, "%s: ", progname ); X va_start( ap ); X (void) vfprintf( stderr, s, ap ); X va_end( ap ); X (void) fputc( '\n', stderr ); X} X Xvoid Xfatal( s, va_alist ) Xchar *s; Xva_dcl X{ X va_list ap; X (void) fprintf( stderr, "%s: ", progname ); X va_start( ap ); X (void) vfprintf( stderr, s, ap ); X va_end( ap ); X (void) fputc( '\n', stderr ); X exit( FATAL ); X} X X/* VARARGS1 */ Xerrmsg( msgnum, va_alist ) Xint msgnum; Xva_dcl X{ X va_list ap; X (void) fprintf( stderr, "%s: ", progname ); X va_start( ap ); X (void) vfprintf( stderr, errmessages[msgnum], ap ); X va_end( ap ); X (void) fputc( '\n', stderr ); X} X#else X/* VARARGS1 */ Xerrprintf( a, b, c, d, e, f, g, h, i, j, k ) Xchar *a; X{ X (void) fprintf( stderr, "%s: ", progname ); X fprintf( stderr, a, b, c, d, e, f, g, h, i, j, k ); X (void) fputc( '\n', stderr ); X} X X/* VARARGS1 */ Xvoid Xfatal( a, b, c, d, e, f, g, h, i, j, k ) Xchar *a; X{ X (void) fprintf( stderr, "%s: ", progname ); X fprintf( stderr, a, b, c, d, e, f, g, h, i, j, k ); X (void) fputc( '\n', stderr ); X exit( FATAL ); X} X X/* VARARGS1 */ Xerrmsg( msgnum, a, b, c, d, e ) Xint msgnum; Xchar *a, *b, *c, *d, *e; X{ X errprintf( errmessages[msgnum], a, b, c, d, e ); X} X#endif /* VARARGS */ X Xlist_msgtime() X{ X /* X * List time last msg was received. X */ X struct stat statbuf; X X if (stat(msg_file, &statbuf) == -1) X errprintf("can't get date of message file '%s': %s", X msg_file, syserr()); X else X printf("last message received %s", ctime(&statbuf.st_mtime)); X} X X Xlist_msg() X{ X /* X * List message to which we are replying. X * Just cat the last msg file. X */ X X FILE *fp; X int c; X X if ( (fp = fopen(msg_file, "r")) == NULL ) { X errprintf("Cannot read last message file '%s'", msg_file ); X } else { X while ( (c = getc(fp)) != EOF ) { X putchar(c); X } X } X} X X Xprivate void Xgetprevious( buf, size ) Xchar *buf; Xint size; X{ X struct stat sbuf; X FILE *pfp; X int count; X if ( stat( pmsg_file, &sbuf ) == -1 ) X fatal( "Could not stat previous message file '%s': %s", X pmsg_file, syserr() ); X if ( sbuf.st_uid != ruid ) X fatal( "You do not own previous message file '%s'", pmsg_file ); X if ( (pfp = fopen( pmsg_file, "r" )) == (FILE *)NULL ) X fatal( "Could not fopen previous message file '%s' for read: %s", X pmsg_file, syserr() ); X if ( fgets( buf, size, pfp ) == NULL ) X fatal( "Could not read previous message from file '%s' (empty?)", X pmsg_file ); X /* In case the file didn't end with a \n, we want to make sure that X we don't complain above that it has been truncated. This is kind X of gross. */ X if ( strlen( buf ) < size ) X strcat( buf, "\n" ); X (void) fclose( pfp ); X} X Xprivate void Xputprevious( msg ) Xchar *msg; X{ X FILE *pfp; X if ( (pfp = fopen( pmsg_file, "w" )) == (FILE *)NULL ) { X errprintf( "Could not fopen previous message file '%s' for write: %s", X pmsg_file, syserr() ); X } else { X fprintf( pfp, "%s\n", msg ); X fclose( pfp ); X chown( pmsg_file, ruid, -1 ); X chmod( pmsg_file, 0600 ); X } X} X X X X X/* X * reply_to - look in MSGFILE to see who sent us X * the last message. X */ X Xchar * Xreply_to() X{ X register char *p; X char *index(); X static char buf[80]; /* Static 'cause we return what's in it. */ X char userfrom[40], whocares[40], hostfrom[40]; X FILE *f; X X if ( (f = fopen(msg_file, "r")) == NULL ) { X return( NULL ); X } X X if ( fgets(buf, sizeof(buf),f) == NULL ) X return( NULL ); X /* X * The file can look like X * user@host: msg X * or X * user(somebody)@host: msg X * Scan this in a basically cheap way. X * I suppose some goofball exceptions could slip through X * here if people had () in their login or host name, blah. X */ X X X if ( (p = index(buf, ':')) == NULL ) { X return( NULL ); /* Bad format. */ X } X *p = '\0'; X X /* X * Now see which format we have. Strip out intermediate name. X * there are probably more rigorous ways to do this X */ X p = index(buf, '('); X X if ( p != NULL ) { X *p++ = '\0'; /* First part is username */ X p = index(p, ')'); /* Skip middle bit. */ X if ( p == NULL ) { X return(NULL); /* Bad format */ X } X X if ( *++p != '@' ) X return(NULL); X X strcat(buf, p); /* Tack on hostname. */ X } X X return( buf ); X} END_OF_FILE if test 12537 -ne `wc -c <'./msg/msg.c'`; then echo shar: \"'./msg/msg.c'\" unpacked with wrong size! fi # end of './msg/msg.c' fi if test -f './msg/remote.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./msg/remote.c'\" else echo shar: Extracting \"'./msg/remote.c'\" \(4372 characters\) sed "s/^X//" >'./msg/remote.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: /source/users/msg/msg/RCS/remote.c,v 1.5 91/08/13 23:59:09 jmsellens Exp $"; X#endif X X/* remote.c X Deliver a message to a user on a remote machine using TCP/IP. X*/ X X#include "msg.h" X#include X#include X#include X#include X#include X Xchar *syserr(); X Xprivate int sock = -1; /* the socket */ Xprivate struct sockaddr_in sin; X X Xprivate struct hostent * Xfind_host( desthost ) Xchar *desthost; X{ X /* stolen from finger */ X static struct hostent def; X static struct in_addr defaddr; X static char *alist[1]; X static char namebuf[128]; X struct hostent *hp; X X hp = gethostbyname(desthost); X if (hp == NULL) { X defaddr.s_addr = inet_addr(desthost); X if (defaddr.s_addr == -1) X return( (struct hostent *)NULL ); X strcpy(namebuf, desthost); X def.h_name = namebuf; X#ifdef h_addr X /* older things don't have this field. Newer ones #define h_addr */ X def.h_addr_list = alist; X#endif X def.h_addr = (char *)&defaddr; X def.h_length = sizeof (struct in_addr); X def.h_addrtype = AF_INET; X def.h_aliases = 0; X hp = &def; X } X return( hp ); X} X X Xprivate int Xstart_remote( desthost ) Xchar *desthost; X{ X static struct servent *sp = NULL; X struct hostent *hp; X char buf[BUFSIZ]; X version ver; X int errcode, i; X X if (sp == NULL) X sp = getservbyname( "msg", "tcp" ); X if (sp == NULL) X fatal( "msg/tcp not defined in services file" ); X hp = find_host( desthost ); X if (hp == NULL) { X errmsg( BAD_HOST, desthost ); X return( BAD_HOST ); X } X bzero( (char *)&sin, sizeof(sin) ); X bcopy( hp->h_addr, (char *)&sin.sin_addr, hp->h_length ); X sin.sin_family = hp->h_addrtype; X sin.sin_port = sp->s_port; X sock = socket( hp->h_addrtype, SOCK_STREAM, 0 ); X if (sock < 0) X fatal( "couldn't create socket: %s", syserr() ); X if (connect( sock, (char *)&sin, sizeof(sin) ) < 0) { X errmsg( NO_CONNECT, desthost, syserr() ); X (void) close(sock); X sock = -1; X return( NO_CONNECT ); X } X /* Now make sure we have a compatible version */ X ver.v.zero = htonl(0); X ver.v.vnum = htonl(VERSION); X if ( write( sock, &ver, sizeof(ver) ) < 0 ) X return( REMOTE_WRITE ); X errcode = readint( &i ); X if ( errcode == OK ) X errcode = i; X if ( errcode == VERSION_OK ) { X errcode = OK; X } else if ( errcode == ERROR_MESSAGE ) { X int code = readint( &i ); X if ( code == OK ) { X code = read( sock, buf, i ); X if ( code == -1 ) { X errcode = REMOTE_READ; X } else { X buf[i] = '\0'; X errprintf( buf ); X } X } else X errcode = code; X } X return( errcode ); X} X X Xprivate Xstop_remote() X{ X if ( sock >= 0 ) { X (void) close( sock ); X sock = -1; X } X} X X Xint Xremote( sender, user, desthost, message ) Xchar *sender, *user, *desthost, *message; X{ X char buf[BUFSIZ]; X int errcode; X if ( (errcode = start_remote( desthost )) == OK ) { X int writeerr = 0; X header h; X h.slen = htonl(strlen(sender)); X h.ulen = htonl(strlen(user)); X h.mlen = htonl(strlen(message)); X if ( write( sock, (char *)&h, sizeof(h) ) < 0 ) writeerr++; X if ( write( sock, sender, strlen(sender) ) < 0 ) writeerr++; X if ( write( sock, user, strlen(user) ) < 0 ) writeerr++; X if ( write( sock, message, strlen(message) ) < 0 ) writeerr++; X if ( writeerr ) { X errcode = REMOTE_WRITE; X } else { X do { X int i; X errcode = readint( &i ); X if ( errcode == OK ) errcode = i; X if ( errcode == ERROR_MESSAGE ) { X int code = readint( &i ); X if ( code == OK ) { X code = read( sock, buf, i ); X if ( code == -1 ) { X errcode = REMOTE_READ; X } else { X buf[i] = '\0'; X errprintf( buf ); X } X } else X errcode = code; X } X } while ( errcode == ERROR_MESSAGE ); X } X } X switch ( errcode ) { X case REMOTE_READ: X case REMOTE_WRITE: X errmsg( errcode, desthost, syserr() ); X break; X case NO_ACK: X errmsg( errcode, desthost ); X break; X default: /* do nothing - got message back from remote */ X break; X } X stop_remote(); /* hope close doesn't change errno */ X return( errcode ); X} X X Xint Xreadint(np) Xint *np; X{ X int n; X X switch (read(sock, &n, sizeof n)) { X case 0: X return( NO_ACK ); X case sizeof(n): X *np = ntohl(n); X return( OK ); X case -1: X default: /* for incomplete data */ X return( REMOTE_READ ); X } X /* NOTREACHED */ X} END_OF_FILE if test 4372 -ne `wc -c <'./msg/remote.c'`; then echo shar: \"'./msg/remote.c'\" unpacked with wrong size! fi # end of './msg/remote.c' fi if test ! -d './msgd' ; then echo shar: Creating directory \"'./msgd'\" mkdir './msgd' fi if test -f './msgd/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./msgd/Makefile'\" else echo shar: Extracting \"'./msgd/Makefile'\" \(755 characters\) sed "s/^X//" >'./msgd/Makefile' <<'END_OF_FILE' XNAME = msgd XSERVDIR = /software/users/servers XMANDIR = /software/users/man XMODE = 555 X XCFLAGS= -DINETD -I../Include X XOBJECT = msgd.o server.o deliver.o misc.o savemsg.o errtext.o answerback.o X Xall: $(NAME) X X$(NAME): $(OBJECT) X cc -o $(NAME) $(OBJECT) X Xinstall: $(NAME) X install -s -m $(MODE) $(NAME) $(SERVDIR)/$(NAME) X Xclean: X rm -f a.out core *.o $(NAME) X X$(OBJECT): ../Include/msg.h ../Include/msgoptions.h X Xanswerback.o: ../Common/answerback.c X cc $(CFLAGS) -c ../Common/answerback.c X Xdeliver.o: ../Common/deliver.c X cc $(CFLAGS) -c ../Common/deliver.c X Xerrtext.o: ../Common/errtext.c X cc $(CFLAGS) -c ../Common/errtext.c X Xmisc.o: ../Common/misc.c X cc $(CFLAGS) -c ../Common/misc.c X Xsavemsg.o: ../Common/savemsg.c X cc $(CFLAGS) -c ../Common/savemsg.c END_OF_FILE if test 755 -ne `wc -c <'./msgd/Makefile'`; then echo shar: \"'./msgd/Makefile'\" unpacked with wrong size! fi # end of './msgd/Makefile' fi if test -f './msgd/msgd.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./msgd/msgd.c'\" else echo shar: Extracting \"'./msgd/msgd.c'\" \(3944 characters\) sed "s/^X//" >'./msgd/msgd.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: /source/users/msg/msgd/RCS/msgd.c,v 1.3 91/08/14 00:00:14 jmsellens Exp $"; X#endif X X#if 0 X/* X * $Log: msgd.c,v $ X * Revision 1.3 91/08/14 00:00:14 jmsellens X * s/eprintf/errprintf/ to avoid libuw clash X * X * Revision 1.2 90/12/29 22:03:50 jmsellen X * VARARGS and logging changes X * X * Revision 1.1 87/08/06 19:06:38 sahayman X * Initial revision X * X */ X#endif X X/* msgd.c X msg daemon X John Sellens, University of Waterloo X*/ X X#include "msg.h" X#include X Xchar *syserr(); Xextern int errno; X Xchar *progname; Xchar hostname[BUFSIZ]; Xint client; X Xmain( argc, argv ) Xint argc; Xchar *argv[]; X{ X X progname = argv[0]; X if ( gethostname( hostname, sizeof(hostname) ) ) X fatal( "Couldn't gethostname(): %s", syserr() ); X (void) signal( SIGHUP, SIG_IGN ); X (void) signal( SIGINT, SIG_IGN ); X (void) signal( SIGALRM, SIG_IGN ); X (void) signal( SIGTTIN, SIG_IGN ); X (void) signal( SIGTTOU, SIG_IGN ); X#ifdef INETD X /* Inetd provides the client connection on fd 0. */ X client = 0; X server(); X exit(0); X#else X{ X#include X#include X#include X#include X#include X#include X#include X X struct servent *serv; X struct sockaddr_in sin; X int i, sock; X X if ( argc != 1 ) X errprintf( "all arguments ignored" ); X serv = getservbyname( "msg", "tcp" ); X if ( serv == (struct servent *)0 ) X fatal( "msg/tcp not defined in services file" ); X X#ifndef DEBUG X /* disconnect from tty */ X switch ( fork() ) { X case 0: /* child */ X break; X case -1: X fatal( "couldn't fork (%s), message daemon not started", syserr() ); X break; X default: /* parent */ X exit( 0 ); X } X for (i = 0; i < 10; i++) X close(i); X (void) open("/", 0); X dup2(0, 1); X dup2(0, 2); X i = open("/dev/tty", 2); X if (i >= 0) { X ioctl(i, TIOCNOTTY, (char *)0); X close(i); X } X#endif X X sin.sin_port = serv->s_port; X sock = socket( AF_INET, SOCK_STREAM, 0 ); X if ( sock == -1 ) X fatal( "couldn't create socket: %s", syserr() ); X if ( bind( sock, (caddr_t)&sin, sizeof(sin) ) == -1 ) X fatal( "couldn't bind socket: %s", syserr() ); X if ( listen( sock, 5 ) == -1 ) X fatal( "couldn't listen to socket: %s", syserr() ); X X for ( ;; ) { X client = accept(sock, (struct sockaddr *)0, (int *)0); X if ( client < 0 ) { X if ( errno != EINTR ) { X errprintf( "accept: %s", syserr() ); X sleep(5); X } X continue; X } X server(); X (void) close( client ); X } X /* NOTREACHED */ X } X#endif /* INETD */ X} X X#include X Xstatic int loglevel = LOG_WARNING; X Xstatic X#ifdef VARARGS Xdoerror( s, ap ) Xchar *s; Xva_list ap; X#else Xdoerror( a, b, c, d, e, f, g, h, i, j, k ) Xchar *a; X#endif X{ X#ifdef DEBUG X#ifdef VARARGS X vfprintf(stderr, s, ap); X#else X fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k); X#endif X putc('\n', stderr); /* syslog will add this */ X#else X static int first = 1; X X if (first) { X#ifdef LOG_DAEMON X openlog(progname, LOG_PID, LOG_DAEMON); X#else X openlog(progname, LOG_PID); X#endif X first = 0; X } X#ifdef VARARGS X { X char buf[BUFSIZ]; X vsprintf( buf, s, ap ); X syslog( loglevel, buf ); X } X#else X syslog(loglevel, a, b, c, d, e, f, g, h, i, j, k); X#endif X#endif X} X X/*VARARGS1*/ X#ifdef VARARGS Xerrprintf( s, va_alist ) Xchar *s; Xva_dcl X{ X va_list ap; X va_start( ap ); X doerror( s, ap ); X va_end( ap ); X} X#else Xerrprintf( a, b, c, d, e, f, g, h, i, j, k ) Xchar *a; X{ X doerror(a, b, c, d, e, f, g, h, i, j, k); X} X#endif X X/*VARARGS1*/ X#ifdef VARARGS Xfatal( s, va_alist ) Xchar *s; Xva_dcl X{ X va_list ap; X loglevel = LOG_ERR; X va_start( ap ); X doerror( s, ap ); X va_end( ap ); X exit( FATAL ); X} X#else Xfatal( a, b, c, d, e, f, g, h, i, j, k ) Xchar *a; X{ X loglevel = LOG_ERR; X doerror( a, b, c, d, e, f, g, h, i, j, k ); X exit( FATAL ); X} X#endif END_OF_FILE if test 3944 -ne `wc -c <'./msgd/msgd.c'`; then echo shar: \"'./msgd/msgd.c'\" unpacked with wrong size! fi # end of './msgd/msgd.c' fi if test -f './msgd/server.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./msgd/server.c'\" else echo shar: Extracting \"'./msgd/server.c'\" \(4063 characters\) sed "s/^X//" >'./msgd/server.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: /source/users/msg/msgd/RCS/server.c,v 1.5 91/08/14 00:00:19 jmsellens Exp $"; X#endif X X#if 0 X/* X * $Log: server.c,v $ X * Revision 1.5 91/08/14 00:00:19 jmsellens X * s/eprintf/errprintf/ to avoid libuw clash X * X * Revision 1.4 90/12/29 22:04:11 jmsellen X * VARARGS changes X * X * Revision 1.3 88/11/07 11:09:54 jmsellens X * Call new sanitize() routine to avoid control characters. This is X * necessary to avoid someone modifying the msg source and making X * their own nasty client that doesn't behave nicely. X * X * Revision 1.2 88/09/25 02:41:31 jmsellens X * Added stuff to accept version records in the future. Taught to X * look up the sender's machine name, so that we get the name that X * we use to get there, not the value of `hostname` on the remote X * machine, which probably isn't properly domain-ized if it's X * remote from us. X * X * Revision 1.1 87/08/06 19:06:43 sahayman X * Initial revision X * X */ X#endif X X/* server.c X read message coming from server, call deliver, and acknowledge with X result code X*/ X X/* We ignore any errors communicating with the client, since we figure X they just dies or broke out or something */ X X#include "msg.h" X#include X#include X#include X#include X Xextern int client; Xprivate int remote_ver = 0; X Xserver() X{ X version ver; X header h; X int err; X char sender[BUFSIZ], user[BUFSIZ], rawmsg[BUFSIZ], message[BUFSIZ]; X X if ( read( client, &ver, sizeof(ver) ) != sizeof(ver) ) goto done; X if ( ntohl(ver.v.zero) == 0 ) { X /* got a version struct */ X remote_ver = ntohl(ver.v.vnum); X if ( remote_ver > VERSION ) { X errmsg( BAD_VERSION, remote_ver, VERSION ); X goto done; X } X /* acknowledge that we agree on the version */ X err = htonl(VERSION_OK); X (void) write( client, &err, sizeof(err) ); X if ( read( client, &h, sizeof(h) ) != sizeof(h) ) goto done; X } else { X /* Not a version struct, so copy it into header struct */ X h = ver.h; X } X h.slen = ntohl(h.slen); X h.ulen = ntohl(h.ulen); X h.mlen = ntohl(h.mlen); X if ( read( client, sender, h.slen ) != h.slen ) goto done; X sender[h.slen] = '\0'; X if ( read( client, user, h.ulen ) != h.ulen ) goto done; X user[h.ulen] = '\0'; X if ( read( client, rawmsg, h.mlen ) != h.mlen ) goto done; X rawmsg[h.mlen] = '\0'; X get_real_sender(sender); X sanitize( rawmsg, message ); X err = deliver( sender, user, message, FALSE ); X /* deliver gave us a pgrp when it opened a tty... */ X setpgrp(0, 0); X err = htonl(err); X (void) write( client, &err, sizeof(err) ); Xdone: X ; X} X X X#ifdef VARARGS Xerrmsg( msgnum, va_alist ) Xint msgnum; Xva_dcl X#else Xerrmsg( msgnum, a, b, c, d, e ) Xint msgnum; Xchar *a, *b, *c, *d, *e; X#endif X{ X char buf[BUFSIZ]; X int i = htonl(ERROR_MESSAGE); X X (void) write( client, &i, sizeof(i) ); X#ifdef VARARGS X { X va_list ap; X va_start( ap ); X (void) vsprintf( buf, errmessages[msgnum], ap ); X va_end( ap ); X } X#else X (void) sprintf( buf, errmessages[msgnum], a, b, c, d, e ); X#endif X i = htonl(strlen( buf )); X (void) write( client, &i, sizeof(i) ); X (void) write( client, buf, strlen(buf) ); X} X X X X Xget_real_sender( sender ) Xchar *sender; X{ X struct sockaddr_in from; X struct hostent *hp; X char *p; X int fromlen; X fromlen = sizeof(from); X X p = index( sender, '@' ); X if ( p == CPNULL ) { X errprintf( "sender '%s' contains no '@'", sender ); X (void) strcat( sender, "@" ); X p = index( sender, '@' ); X } X p++; X if ( index( p, '@' ) != CPNULL ) { X errprintf( "sender '%s' contains multiple '@'s", sender ); X p = rindex( sender, '@' ); X p++; X } X if ( getpeername( client, &from, &fromlen ) < 0 ) { X errprintf( "couldn't getpeername(): %s", syserr() ); X (void) strcat( sender, "" ); X } else { X hp = gethostbyaddr( (char *)&from.sin_addr, sizeof(struct in_addr), X from.sin_family ); X if ( hp ) X (void) strcpy( p, hp->h_name ); X else X (void) strcpy( p, inet_ntoa( from.sin_addr ) ); X } X} END_OF_FILE if test 4063 -ne `wc -c <'./msgd/server.c'`; then echo shar: \"'./msgd/server.c'\" unpacked with wrong size! fi # end of './msgd/server.c' fi if test -f './services' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./services'\" else echo shar: Extracting \"'./services'\" \(40 characters\) sed "s/^X//" >'./services' <<'END_OF_FILE' Xmsg 1241/tcp # msgd(8) (under inetd) END_OF_FILE if test 40 -ne `wc -c <'./services'`; then echo shar: \"'./services'\" unpacked with wrong size! fi # end of './services' fi echo shar: End of shell archive. exit 0