1015 lines
27 KiB
C
1015 lines
27 KiB
C
static char sccsid[] = "@(#)14 1.16.1.7 src/bos/usr/bin/write/write.c, cmdwrite, bos411, 9433B411a 8/16/94 16:47:57";
|
||
/*
|
||
* COMPONENT_NAME: (CMDCOMM) user to user communication
|
||
*
|
||
* FUNCTIONS: write
|
||
*
|
||
* ORIGINS: 3, 26, 27
|
||
*
|
||
* This module contains IBM CONFIDENTIAL code. -- (IBM
|
||
* Confidential Restricted when combined with the aggregated
|
||
* modules for this product)
|
||
* SOURCE MATERIALS
|
||
* (C) COPYRIGHT International Business Machines Corp. 1989, 1994
|
||
* All Rights Reserved
|
||
*
|
||
* US Government Users Restricted Rights - Use, duplication or
|
||
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
||
*
|
||
* Copyright (c) 1984 AT&T
|
||
* All Rights Reserved
|
||
*
|
||
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
|
||
* The copyright notice above does not evidence any
|
||
* actual or intended publication of such source code.
|
||
*
|
||
* Copyright (c) 1980 Regents of the University of California.
|
||
* All rights reserved. The Berkeley software License Agreement
|
||
* specifies the terms and conditions for redistribution.
|
||
*/
|
||
#define _ILS_MACROS
|
||
#include <errno.h>
|
||
#include <stdio.h>
|
||
#include <locale.h>
|
||
#include <fcntl.h>
|
||
#include <string.h>
|
||
#include <netdb.h>
|
||
#include <sys/types.h>
|
||
#include <netinet/in.h>
|
||
#include <sys/socket.h>
|
||
#include <utmp.h>
|
||
#include <pwd.h>
|
||
#include <sys/limits.h>
|
||
#include <unistd.h>
|
||
#include <signal.h>
|
||
#include <time.h>
|
||
#include <ctype.h>
|
||
#include <stdlib.h>
|
||
#include "write.h"
|
||
#include "write_msg.h"
|
||
nl_catd catd; /* Cat descriptor for scmc conversion */
|
||
#define MSGSTR(Num,Str) catgets(catd,MS_write,Num,Str)
|
||
|
||
extern errno;
|
||
|
||
#define USAGE MSGSTR(M_MSG_35 \
|
||
,"write [-r|-q|-h handle,%s|%s|%s] [-n host] [user][@host] [line]\n")
|
||
|
||
#define BUF_LEN 5*MAX_INPUT /* a 5-byte octal sequence is
|
||
displayed for non-printable
|
||
chars so the buffer must be able
|
||
to handle the expansion */
|
||
|
||
|
||
struct flag {
|
||
short int nflag; /* remote node flag */
|
||
short int rflag; /* wait for rely flag */
|
||
short int qflag; /* query flag */
|
||
short int hflag; /* handle flag */
|
||
long int handle; /* handle */
|
||
};
|
||
|
||
struct userinfo {
|
||
char host[MAX_HOST_LEN];
|
||
char user[MAX_USERID_LEN+1];
|
||
char tty[PATH_MAX];
|
||
int fldes;
|
||
};
|
||
|
||
void getoptions(),validoptions(),gettargetinfo(),openlink(),exshell(),
|
||
sendreply(),srvinfo(),getuserinfo(),myread(),mywrite(),uzero(),
|
||
timeread();
|
||
|
||
int sigpipe(void);
|
||
int timeout(void);
|
||
struct utmp *getutent();
|
||
|
||
/*
|
||
* NAME: write [-r] [-q] [-h handle,reply] [-n host] [user][@host] [line]
|
||
* FUNCTION: Sends messages to other users on the system.
|
||
* RETURN VALUE DESCRIPTION: exits with 0 if everything is ok
|
||
* exits with 1 if reply = "cancel"
|
||
* exits with -1 if error.
|
||
*/
|
||
|
||
/*
|
||
* change from old style signals (call to signal) to
|
||
* call sigaction. From ksh/sh/fault.c
|
||
*/
|
||
|
||
void (*new_signal( int sig, void (*func)(int))) (int)
|
||
{
|
||
struct sigaction act, oact;
|
||
|
||
sigaction(sig, (struct sigaction *)NULL, &act); /* get current signal */
|
||
act.sa_handler = func; /* set new handler */
|
||
switch (sig) {
|
||
case SIGCONT:
|
||
case SIGTTIN:
|
||
case SIGTTOU:
|
||
case SIGTSTP:
|
||
case SIGSTOP:
|
||
/* system calls are restartable after a job control signal */
|
||
act.sa_flags |= SA_RESTART;
|
||
break;
|
||
}
|
||
sigaction(sig, &act, &oact);
|
||
return(oact.sa_handler); /* return old signal handler */
|
||
}
|
||
|
||
|
||
main(argc,argv)
|
||
int argc;
|
||
char *argv[];
|
||
{
|
||
struct flag flags;
|
||
struct userinfo userinfo,targetinfo;
|
||
char message[BUF_LEN];
|
||
char msg2[BUF_LEN + 1];
|
||
char *host;
|
||
int reply = 0, length;
|
||
char *eof = NULL;
|
||
char mbchar[10]; /* to store partial multibyte
|
||
char from fgets if necessary */
|
||
int mberror = 0, offset = 0; /* always 0 if MB_CUR_MAX == 1 */
|
||
struct hostent *hp;
|
||
char user_name[MAX_HOST_LEN];
|
||
char target_name[MAX_HOST_LEN];
|
||
|
||
(void ) setlocale(LC_ALL,"");
|
||
catd = catopen(MF_WRITE, NL_CAT_LOCALE);
|
||
|
||
new_signal(SIGCONT, SIG_IGN); /*
|
||
* This keeps read from failing
|
||
* it may not be necessary in the future
|
||
*/
|
||
new_signal(SIGPIPE,(void (*)(int))sigpipe);
|
||
getoptions(argc,argv,&flags,&targetinfo,message);
|
||
validoptions(flags,targetinfo);
|
||
getuserinfo(&userinfo);
|
||
if (targetinfo.host[0] != '\0')
|
||
host = targetinfo.host;
|
||
else
|
||
host = userinfo.host;
|
||
if (flags.hflag) {
|
||
sendreply(flags.handle,encoder(message),host);
|
||
exit(0);
|
||
}
|
||
if (flags.qflag) {
|
||
srvinfo(host,userinfo.host);
|
||
exit(0);
|
||
}
|
||
/* This section of code is added to prevent "write -n localhost user"
|
||
go thru writesrv, this enable local root write to local user
|
||
regardless of what local user mesg is set to. D48768 */
|
||
if (flags.nflag) {
|
||
if ((hp = gethostbyname(userinfo.host)) == NULL) {
|
||
fprintf(stderr,MSGSTR(M_MSG_26,"write: unknown host\n"));
|
||
exit(-1);
|
||
}
|
||
strncpy(user_name, hp->h_name, sizeof(user_name));
|
||
if ((hp = gethostbyname(targetinfo.host)) == NULL) {
|
||
fprintf(stderr,MSGSTR(M_MSG_26,"write: unknown host\n"));
|
||
exit(-1);
|
||
}
|
||
strncpy(target_name, hp->h_name, sizeof(target_name));
|
||
if (!strcmp(user_name, target_name))
|
||
flags.nflag--;
|
||
}
|
||
gettargetinfo(&targetinfo,&flags);
|
||
if (targetinfo.host[0] == '\0')
|
||
strcpy(targetinfo.host,userinfo.host);
|
||
openlink(&userinfo,&targetinfo,&flags);
|
||
printf("");
|
||
do {
|
||
bzero(message,sizeof(message));
|
||
bzero (msg2, sizeof(msg2));
|
||
if (mberror) /* previous fgets split a multibyte char */
|
||
strcpy (message, mbchar);
|
||
if ((eof = fgets((message+offset),(MAX_INPUT - offset),stdin)) == NULL)
|
||
strcpy(message,MSGSTR(M_MSG_39,"<EOT>\n"));
|
||
if (message[0] == '!' && flags.rflag == 0) {
|
||
exshell(message);
|
||
continue;
|
||
}
|
||
mberror = expand_control ( message, strlen(message), msg2 ); /* expand control characters */
|
||
offset = 0;
|
||
if ( mberror ) {
|
||
/* fgets returns at most MAX_INPUT - 1 chars */
|
||
offset = MAX_INPUT - mberror - 1;
|
||
strncpy (mbchar, (message+mberror), (size_t)offset);
|
||
}
|
||
length = strlen (msg2);
|
||
mywrite (targetinfo.fldes,msg2,((length==0)?1:length));
|
||
} while (eof != NULL);
|
||
if (flags.nflag || flags.rflag ) {
|
||
bzero(message,sizeof(message));
|
||
message[0] ='\0';
|
||
mywrite (targetinfo.fldes,message,sizeof(message));
|
||
}
|
||
if (flags.rflag)
|
||
reply = getreply(targetinfo.fldes);
|
||
close(targetinfo.fldes);
|
||
exit(reply);
|
||
}
|
||
|
||
/*
|
||
* NAME: getoptions
|
||
* FUNCTION: get the options from the command line and set the proper
|
||
* flags and target information. calls Usage if an error is
|
||
* detected.
|
||
*/
|
||
void getoptions(argc,argv,flags,tarinfo,message)
|
||
int argc;
|
||
char *argv[];
|
||
struct flag *flags;
|
||
struct userinfo *tarinfo;
|
||
char *message;
|
||
{
|
||
int j,k;
|
||
extern int optind;
|
||
extern char *optarg;
|
||
int c;
|
||
char *h;
|
||
|
||
if (argc < 2) {
|
||
Usage();
|
||
}
|
||
flags->nflag = 0; /* initialize flags */
|
||
flags->rflag = 0;
|
||
flags->qflag = 0;
|
||
flags->hflag = 0;
|
||
flags->handle = 0;
|
||
tarinfo->user[0] = '\0';
|
||
tarinfo->host[0] = '\0';
|
||
tarinfo->tty[0] = '\0';
|
||
tarinfo->fldes = 0;
|
||
message[0] = '\0';
|
||
|
||
while ((c = getopt(argc,argv,"n:rqh:@:")) != EOF) {
|
||
switch (c) {
|
||
case 'n':
|
||
strcpy(tarinfo->host,optarg);
|
||
flags->nflag++;
|
||
break;
|
||
case 'r':
|
||
flags->rflag++;
|
||
break;
|
||
case 'q':
|
||
flags->qflag++;
|
||
break;
|
||
case 'h':
|
||
flags->hflag++;
|
||
j = 0;
|
||
h = optarg;
|
||
while (h[j] != '\0'){
|
||
if (h[j] == ',') {
|
||
message[j] = '\0';
|
||
flags->handle = atoi(message);
|
||
j++;
|
||
break;
|
||
}
|
||
else {
|
||
message[j] = h[j];
|
||
j++;
|
||
}
|
||
}
|
||
strcpy(message,h+j);
|
||
break;
|
||
case '@':
|
||
tarinfo->user[0] = '-';
|
||
strcpy(tarinfo->host,optarg);
|
||
flags->nflag++;
|
||
break;
|
||
default:
|
||
Usage();
|
||
break;
|
||
}
|
||
}
|
||
|
||
for (; optind < argc; optind++){
|
||
if (tarinfo->user[0] != '\0') { /* get tty */
|
||
if (tarinfo->tty[0] != '\0') Usage();
|
||
strcpy(tarinfo->tty,argv[optind]);
|
||
continue;
|
||
}
|
||
if (argv[optind][0] == '@') {
|
||
if (argv[optind][1] == '\0') Usage();
|
||
flags->nflag++;
|
||
if (tarinfo->host[0] != '\0') Usage();
|
||
strcpy(tarinfo->host,argv[optind] + 1);
|
||
continue;
|
||
}
|
||
k=0;
|
||
while (argv[optind][k] != '\0'){
|
||
if (argv[optind][k] == '@') { /* remote host */
|
||
flags->nflag++;
|
||
if (tarinfo->host[0] != '\0') Usage();
|
||
strcpy(tarinfo->host,argv[optind] + k + 1);
|
||
argv[optind][k] = '\0';
|
||
break;
|
||
}
|
||
k++;
|
||
} /* end of while loop */
|
||
if (k > 0) {
|
||
if (tarinfo->user[0] != '\0') Usage();
|
||
strcpy(tarinfo->user,argv[optind]);
|
||
}
|
||
} /*end of for loop */
|
||
} /* end of getoptions */
|
||
|
||
/*
|
||
* NAME: Usage
|
||
* FUNCTION: prints the usage statement to stderr and then exits.
|
||
*/
|
||
Usage()
|
||
{
|
||
fprintf(stderr,USAGE,"ok","cancel","query");
|
||
exit(-1);
|
||
}
|
||
|
||
/*
|
||
* NAME: validoptions
|
||
* FUNCTION: Checks for incompatible flags. If incompatible options are
|
||
* found then validoptions will issue an error message and exit
|
||
* the program.
|
||
*/
|
||
void validoptions(flags,targetinfo)
|
||
struct flag flags;
|
||
struct userinfo targetinfo;
|
||
{
|
||
if (flags.rflag + flags.qflag + flags.hflag > 1)
|
||
Usage();
|
||
if (flags.hflag + flags.qflag > 0 && targetinfo.user[0] != '\0')
|
||
Usage();
|
||
if (targetinfo.user[0] == '-' && targetinfo.tty[0] == '\0')
|
||
Usage();
|
||
if (flags.rflag > 0 && targetinfo.user[0] == '\0')
|
||
Usage();
|
||
if (flags.rflag + flags.qflag + flags.hflag == 0
|
||
&& targetinfo.user[0] == '\0')
|
||
Usage();
|
||
if (flags.nflag > 0 && targetinfo.host[0] == '\0')
|
||
Usage();
|
||
if (flags.hflag > 0 && flags.handle == 0)
|
||
Usage();
|
||
if(flags.hflag > 0 && targetinfo.tty[0] != '\0')
|
||
Usage();
|
||
}
|
||
|
||
/*
|
||
* NAME: getuserinfo
|
||
* FUNCTION: This function will get the user information (i.e. user id,
|
||
* host name and tty).
|
||
*/
|
||
void getuserinfo(userinfo)
|
||
struct userinfo *userinfo;
|
||
{
|
||
struct passwd *pbuf;
|
||
char *tty;
|
||
|
||
pbuf = getpwuid(getuid()); /* get user id */
|
||
if (pbuf == NULL) {
|
||
fprintf (stderr, MSGSTR(M_MSG_2,
|
||
"write: unable to find you login ID\n") );
|
||
exit(-1);
|
||
}
|
||
strcpy(userinfo->user,pbuf->pw_name);
|
||
tty = ttyname((int)fileno(stdin));
|
||
if (tty == NULL)
|
||
tty = ttyname((int)fileno(stdout));
|
||
if (tty == NULL)
|
||
tty = ttyname((int)fileno(stderr));
|
||
if (tty == NULL) {
|
||
fprintf(stdout, MSGSTR(M_MSG_3,
|
||
"write: unable to determine your tty\n") );
|
||
strcpy(userinfo->tty,"/dev/");
|
||
strncat(userinfo->tty,MSGSTR(UNKNOWN,"UNKNOWN"),(size_t)(MAX_TTY_LEN-5));
|
||
}
|
||
else
|
||
strncpy(userinfo->tty,tty,(size_t)MAX_TTY_LEN);
|
||
if (gethostname(userinfo->host,sizeof(userinfo->host)) < 0) {
|
||
fprintf(stderr, MSGSTR(M_MSG_4,
|
||
"write: unable to determine your host name\n") );
|
||
exit(-1);
|
||
}
|
||
userinfo->fldes = fileno(stdin);
|
||
}
|
||
|
||
/*
|
||
* NAME: encoder
|
||
* FUNCTION: encode the message into 0 for 'ok'
|
||
* 1 for 'cancel'
|
||
* 2 for 'query'
|
||
* exit if anything else
|
||
*/
|
||
int encoder(message)
|
||
char *message;
|
||
{
|
||
if (message[0] == 'o' || message[0] == 'O')
|
||
return(OK);
|
||
else if (message[0] == 'c' || message[0] == 'C')
|
||
return(CANCEL);
|
||
else if (message[0] == 'q' || message[0] == 'Q')
|
||
return(MQUERY);
|
||
else {
|
||
fprintf(stderr,MSGSTR(M_MSG_5,
|
||
"Invalid reply, must be %s, %s or %s\n"),
|
||
SOK,SCANCEL,SQUERY);
|
||
exit(-1);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* NAME: sendreply
|
||
* FUNCTION: This function will send the handle and the encoded reply to
|
||
* writesrv.
|
||
*/
|
||
void sendreply(handle,code,host)
|
||
int handle, code;
|
||
char *host;
|
||
{
|
||
char service[MAX_INPUT];
|
||
char serv2[MAX_INPUT + 1];
|
||
int sock,r;
|
||
int status;
|
||
|
||
bzero(serv2,sizeof(serv2));
|
||
sock = setupsock(host); /* set up link to host */
|
||
bzero(service,sizeof(service));
|
||
sprintf(service,"%c%s",HWRITE,host);
|
||
mywrite(sock,service,sizeof(service)); /* send service request */
|
||
bzero(service,sizeof(service));
|
||
sprintf(service,"%d %d",handle,code);
|
||
mywrite(sock,service,sizeof(service)); /* send handle and code */
|
||
bzero(service,sizeof(service));
|
||
timeread(sock,service,sizeof(service)); /* get status */
|
||
status = atoi(service);
|
||
if (status == 2) { /* get original message */
|
||
mywrite(sock,service,sizeof(service)); /* sync */
|
||
do { /* get original message */
|
||
bzero(service,sizeof(service));
|
||
myread(sock,service,sizeof(service));
|
||
|
||
/* If buffer is full, copy to another buffer to
|
||
ensure there is always a terminating NULL. */
|
||
if (strlen(service) >= MAX_INPUT)
|
||
{
|
||
strncpy (serv2, service, MAX_INPUT);
|
||
printf ("%s",serv2);
|
||
}
|
||
else
|
||
if (service[0] != '\0') printf("%s",service);
|
||
} while (service[0] != '\0');
|
||
bzero(service,sizeof(service));
|
||
myread(sock,service,sizeof(service)); /* get status */
|
||
status = atoi(service);
|
||
}
|
||
if (status < 0) error(status,"",host,0);
|
||
mywrite(sock,service,sizeof(service)); /* use as sync */
|
||
close(sock);
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* NAME: srvinfo
|
||
* FUNCTION: This function gets a list of all messages a waiting a reply,
|
||
* from the writesrv and then displays them.
|
||
* RETURN: returns -1 if error
|
||
* else 0
|
||
*/
|
||
void srvinfo(tohost,fromhost)
|
||
char *tohost;
|
||
char *fromhost;
|
||
{
|
||
int sock;
|
||
char service[MAX_INPUT];
|
||
|
||
bzero(service,sizeof(service));
|
||
sock = setupsock(tohost); /* set up link to host */
|
||
service[0] = QUERY;
|
||
strcat(service,fromhost);
|
||
mywrite (sock,service,sizeof(service)); /* send service request */
|
||
bzero(service,sizeof(service));
|
||
timeread(sock,service,sizeof(service));
|
||
do { /* get list */
|
||
if (service[0] != '\0') printf("%s",service);
|
||
bzero(service,sizeof(service));
|
||
myread(sock,service,sizeof(service));
|
||
} while (service[0] != '\0');
|
||
mywrite(sock,service,sizeof(service)); /* use as sync */
|
||
close(sock);
|
||
}
|
||
|
||
/*
|
||
* NAME: gettargetinfo
|
||
* FUNCTION: This function will verify all target information that
|
||
* was recieved from the command line and then it will gather any
|
||
* remaining information it needs.
|
||
*/
|
||
void gettargetinfo(targetinfo,flags)
|
||
struct userinfo *targetinfo;
|
||
struct flag *flags;
|
||
{
|
||
struct utmp *ubuf;
|
||
int found = 0;
|
||
char tty[PATH_MAX];
|
||
struct ttys *head = NULL,*current = NULL,*test = NULL;
|
||
|
||
targetinfo->fldes = 0;
|
||
if (flags->nflag == 0 && flags->rflag == 0) { /* for local only */
|
||
if (targetinfo->user[0] == '-' && targetinfo->tty[0] != '\0') {
|
||
if (targetinfo->tty[0] != '/') {
|
||
strcpy(tty,targetinfo->tty);
|
||
strcpy(targetinfo->tty,"/dev/");
|
||
strcat(targetinfo->tty,tty);
|
||
} /* end of if */
|
||
return;
|
||
} /* end of if */
|
||
if ((ubuf = getutent()) == NULL) { /* open utmp file */
|
||
fprintf (stderr, MSGSTR(M_MSG_8,
|
||
"write: Can't open %s\n") ,UTMP_FILE);
|
||
if (targetinfo->tty[0] == '\0'){
|
||
fprintf (stderr, MSGSTR(M_MSG_9,
|
||
"write: can not continue\n") );
|
||
exit(-1);
|
||
} /* end of if */
|
||
} /* end of if */
|
||
else { /* check entry in utmp file */
|
||
while (ubuf != NULL) {
|
||
if (
|
||
ubuf->ut_type == USER_PROCESS &&
|
||
strncmp(ubuf->ut_user,targetinfo->user,(size_t)MAX_USERID_LEN) == 0
|
||
) {
|
||
if (targetinfo->tty[0] == '\0') {
|
||
errno = 0;
|
||
test = (struct ttys *) malloc (sizeof(struct ttys));
|
||
if (test == NULL) {
|
||
if (errno == 0) error(MALLOC,"","",0);
|
||
perror (MSGSTR(M_MSG_38,"malloc"));
|
||
exit(-1);
|
||
}
|
||
if (current == NULL)
|
||
current = test;
|
||
else {
|
||
current->next = test;
|
||
current = current->next;
|
||
} /* end of else */
|
||
current->next = NULL;
|
||
if (head == NULL) head = current;
|
||
strncpy(current->tty,ubuf->ut_line,(size_t)MAX_TTY_LEN);
|
||
found++;
|
||
} /* end of if */
|
||
else if (strncmp(targetinfo->tty, ubuf->ut_line,
|
||
(size_t)MAX_TTY_LEN) == 0) {
|
||
found++;
|
||
break;
|
||
} /* end of else if */
|
||
} /* end of if */
|
||
ubuf = getutent();
|
||
} /* end of while */
|
||
endutent();
|
||
if (found == 0){
|
||
if(targetinfo->tty[0])
|
||
fprintf(stderr,MSGSTR(M_MSG_44,
|
||
"%s is not logged in on %s.\n"),targetinfo->user,targetinfo->tty);
|
||
else
|
||
fprintf(stderr,MSGSTR(M_MSG_10,
|
||
"%s is not logged on.\n"),targetinfo->user);
|
||
exit(-1);
|
||
} /* end of if */
|
||
} /* end of else */
|
||
if (targetinfo->tty[0] == '\0')
|
||
strcpy(targetinfo->tty,head->tty);
|
||
if (targetinfo->tty[0] != '/' && targetinfo->tty[0] != '\0') {
|
||
strcpy(tty,targetinfo->tty);
|
||
strcpy(targetinfo->tty,"/dev/");
|
||
strcat(targetinfo->tty,tty);
|
||
} /* end of if */
|
||
if (head != NULL && head->next != NULL) {
|
||
fprintf(stdout, MSGSTR(M_MSG_11,
|
||
"%s is logged on more than one place.\n") ,
|
||
targetinfo->user);
|
||
fprintf(stdout, MSGSTR(M_MSG_12,
|
||
"You are connected to %s.\n") ,
|
||
targetinfo->tty);
|
||
fprintf(stdout, MSGSTR(M_MSG_13,
|
||
"Other locations are:\n") );
|
||
head = head->next;
|
||
found--;
|
||
while(head != NULL) {
|
||
fprintf(stdout,"%s\n",head->tty);
|
||
head = head->next;
|
||
} /* end of while */
|
||
} /* end of if */
|
||
} /* end of if */
|
||
} /* end of gettargetinfo */
|
||
|
||
/*
|
||
* NAME: openlink
|
||
* FUNCTION: This function opens the target tty or sends a service repuest to
|
||
* the remote writesrv to open it's target tty. In either case after it is
|
||
* opened, the header informing the target user of a incoming message will
|
||
* be displayed. The file descriptor of the target will be set.
|
||
*/
|
||
void openlink (userinfo,targetinfo,flags)
|
||
struct userinfo *userinfo,*targetinfo;
|
||
struct flag *flags;
|
||
{
|
||
time_t timet;
|
||
char date[MB_DATE_LEN],errs[MAX_INPUT],nums[MAX_INPUT];
|
||
int err,num,i;
|
||
int sock;
|
||
char service[MAX_INPUT];
|
||
struct tm *tm_time;
|
||
|
||
if (flags->nflag > 0 || flags->rflag > 0) { /* remote */
|
||
bzero(service,sizeof(service));
|
||
sock = setupsock(targetinfo->host);
|
||
if (flags->rflag > 0) service[0] = RWRITE;
|
||
else service[0] = RELAY;
|
||
strcat(service,userinfo->host);
|
||
mywrite(sock,service,sizeof(service));/* send service request */
|
||
targetinfo->fldes = sock;
|
||
bzero(service,sizeof(service));
|
||
strcpy(service,targetinfo->user);
|
||
mywrite(sock,service,sizeof(service)); /* send user */
|
||
bzero(service,sizeof(service));
|
||
if (targetinfo->tty[0] == '\0') strcpy(service,".");
|
||
else strcpy(service,targetinfo->tty);
|
||
mywrite(sock,service,sizeof(service)); /* send tty */
|
||
bzero(service,sizeof(service));
|
||
timeread(sock,service,sizeof(service)); /* get status */
|
||
sscanf(service,"%s%s",errs,nums);
|
||
err = atoi(errs);
|
||
num = atoi(nums);
|
||
if (err <= 0)
|
||
error(err,targetinfo->user,targetinfo->host,flags->rflag);
|
||
if (num > 1) { /* get list of ttys user is using */
|
||
bzero(service,sizeof(service));
|
||
myread(sock,service,sizeof(service));
|
||
fprintf(stderr, MSGSTR(M_MSG_15,
|
||
"%s on %s is logged on more than one place.\n"),
|
||
targetinfo->user,targetinfo->host);
|
||
fprintf(stderr, MSGSTR(M_MSG_16,
|
||
"You are connected to %s.\n"),service);
|
||
fprintf(stderr, MSGSTR(M_MSG_17,
|
||
"Other locations are:\n"));
|
||
for (i=1;i<num;i++) {
|
||
bzero(service,sizeof(service));
|
||
myread(sock,service,sizeof(service));
|
||
printf("%s\n",service);
|
||
}
|
||
}
|
||
}
|
||
else { /* open local tty */
|
||
if (access(targetinfo->tty,F_OK) < 0) {
|
||
fprintf(stderr,MSGSTR(M_MSG_19,
|
||
"write: No such tty\n"));
|
||
exit(-1);
|
||
}
|
||
targetinfo->fldes = open (targetinfo->tty,O_WRONLY,0);
|
||
if (targetinfo->fldes < 0) {
|
||
fprintf(stderr, MSGSTR(M_MSG_21,
|
||
"write: Permission denied\n"));
|
||
exit(-1);
|
||
}
|
||
}
|
||
timet = time((long *) 0);
|
||
tm_time = localtime(&timet);
|
||
(void) strftime(date,MB_DATE_LEN,"%c",tm_time);
|
||
trunc_str (date, DATE_LEN);
|
||
bzero(service,sizeof(service));
|
||
service[0] = '\n';
|
||
mywrite(targetinfo->fldes,service,sizeof(service)); /* send blank line */
|
||
bzero(service,sizeof(service));
|
||
sprintf(service,
|
||
MSGSTR(M_MSG_1,
|
||
" Message from %s on %s (%s) [%s] ...\n")
|
||
,userinfo->user,userinfo->host,userinfo->tty+5,date);
|
||
mywrite(targetinfo->fldes,service,sizeof(service)); /* send header */
|
||
}
|
||
|
||
|
||
/*
|
||
* NAME: trunc_str
|
||
* FUNCTION: This function will truncate a string to a specified
|
||
* number of characters. It checks for multibyte characters and
|
||
* truncates to the last multibyte character in the string such that
|
||
* the total number of bytes is <= length. Assumes that the buffer
|
||
* size of str is > length, though the string length itself may
|
||
* be < length.
|
||
*/
|
||
trunc_str ( str, length)
|
||
char *str;
|
||
int length;
|
||
{
|
||
int count=0, i=0, wclen;
|
||
wchar_t wc;
|
||
|
||
if ( MB_CUR_MAX != 1 )
|
||
{
|
||
do {
|
||
if ( (wclen = mbtowc(&wc, &str[count], MB_CUR_MAX)) == -1 ) {
|
||
fprintf(stderr,MSGSTR(M_MSG_43, "Error in multibyte character conversion.\n"));
|
||
exit(-1);
|
||
}
|
||
else {
|
||
if ( (count + wclen) <= length )
|
||
count += wclen;
|
||
else {
|
||
str[count] = '\0';
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
while ( (count <= length) && (wclen != 0) );
|
||
}
|
||
else str[length] = '\0';
|
||
}
|
||
|
||
|
||
/*
|
||
* NAME: exshell
|
||
* FUNCTION: This function will execute the rest of the message line as
|
||
* a shell command.
|
||
*/
|
||
void exshell(message)
|
||
char *message;
|
||
{
|
||
int pid;
|
||
|
||
pid = fork();
|
||
if (pid < 0) {
|
||
perror(MSGSTR(M_MSG_22,"execute shell command"));
|
||
return;
|
||
}
|
||
if (pid == 0) { /* inside of child */
|
||
execl(getenv("SHELL") ?
|
||
getenv("SHELL") : "/usr/bin/sh", "sh", "-c", ++message, 0);
|
||
exit(0);
|
||
}
|
||
while (wait((int *)NULL) != pid) /* in parent */
|
||
;
|
||
printf("!\n");
|
||
}
|
||
|
||
/*
|
||
* NAME: getreply
|
||
* FUNCTION: This function will wait for writesrv to send an encoded reply.
|
||
* This encoded reply will then be returned.
|
||
*/
|
||
int getreply(fldes)
|
||
int fldes;
|
||
{
|
||
char buf[MAX_INPUT];
|
||
int reply;
|
||
|
||
bzero(buf,sizeof(buf));
|
||
myread(fldes,buf,sizeof(buf));
|
||
reply=atoi(buf);
|
||
if (reply < 0)
|
||
error(reply,"","",0);
|
||
mywrite(fldes,buf,sizeof(buf)); /* send acknowledgement */
|
||
return(reply);
|
||
}
|
||
|
||
/*
|
||
* NAME: setupsock:
|
||
* FUCNTION: sets up the connection to proper socket.
|
||
*/
|
||
int setupsock(host)
|
||
char *host;
|
||
{
|
||
struct servent *sp;
|
||
struct sockaddr_in server;
|
||
struct hostent *hp;
|
||
int sock;
|
||
|
||
sp = getservbyname("writesrv","tcp");
|
||
if (sp == NULL) {
|
||
fprintf(stderr,MSGSTR(M_MSG_24,"writesrv: unknown service\n"));
|
||
exit(-1);
|
||
}
|
||
sock = socket(AF_INET,SOCK_STREAM,0);
|
||
if (sock < 0) {
|
||
perror( MSGSTR(E_MSG_25, "opening stream socket") );
|
||
exit(-1);
|
||
}
|
||
server.sin_family = AF_INET;
|
||
server.sin_addr.s_addr = inet_addr(host); /* if internet address */
|
||
if ( server.sin_addr.s_addr == -1) { /* if hostname */
|
||
hp = gethostbyname(host);
|
||
if (hp == 0) {
|
||
fprintf(stderr,MSGSTR(M_MSG_26,"write: unknown host\n"));
|
||
exit(-1);
|
||
}
|
||
bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
|
||
}
|
||
server.sin_port = sp->s_port;
|
||
if (connect(sock,&server,sizeof(server)) < 0) {
|
||
perror ( MSGSTR(E_MSG_27, "connecting stream socket") );
|
||
exit(-1);
|
||
}
|
||
return(sock);
|
||
}
|
||
|
||
/*
|
||
* NAME: error
|
||
* FUNCTION: Displays the proper error message based on the status
|
||
* returned by a remote host.
|
||
*/
|
||
error(err,user,host,rflag)
|
||
int err;
|
||
char *user,*host;
|
||
int rflag;
|
||
{
|
||
if ( err == NOTLOG && rflag > 0)
|
||
exit(2);
|
||
else if ( err == NOTLOG) fprintf(stderr,MSGSTR(M_MSG_28,
|
||
"%s not logged in on %s\n") ,user,host);
|
||
else if (err == NOTTY)
|
||
fprintf(stderr,MSGSTR(M_MSG_29,"No such tty\n") );
|
||
else if (err == NOPERM ) fprintf(stderr,MSGSTR(M_MSG_30,
|
||
"Permission denied\n"));
|
||
else if (err == NOOPEN) fprintf(stderr,MSGSTR(M_MSG_31,
|
||
"write: Can't open %s on %s\n"),UTMP_FILE,host);
|
||
else if (err == MALLOC) fprintf(stderr, MSGSTR(M_MSG_32,
|
||
"malloc: FATAL ERROR\n") );
|
||
else if (err == BADHAND) fprintf(stderr,MSGSTR(M_MSG_33,
|
||
"Invalid handle on %s\n"),host);
|
||
else if (err == SNDRPLY) fprintf(stderr,MSGSTR(M_MSG_34,
|
||
"Could not send reply\n"));
|
||
else if (err == GETRPLY) fprintf(stderr,MSGSTR(M_MSG_36,
|
||
"Could not get reply\n"));
|
||
else if (err == NOSERVICE) {
|
||
fprintf(stderr,MSGSTR(M_MSG_41,
|
||
"writesrv can not provide this service right now.\n"));
|
||
fprintf(stderr,MSGSTR(M_MSG_42,
|
||
"writesrv is shutting down\n"));
|
||
}
|
||
exit(-1);
|
||
|
||
}
|
||
|
||
/*
|
||
* NAME: myread
|
||
* FUNCTION: perform the read and checks the return code.
|
||
*/
|
||
void myread (fldes,buf,len)
|
||
int fldes;
|
||
char *buf;
|
||
int len;
|
||
{
|
||
int nchar;
|
||
|
||
nchar = read(fldes,buf,(unsigned)len);
|
||
if ((nchar == -1) && (errno != EINTR)) {
|
||
fprintf(stderr,MSGSTR(M_MSG_37,
|
||
"Can not communicate with the daemon writesrv\n"));
|
||
perror("read() in myread()");
|
||
exit(-1);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* NAME: mywrite
|
||
* FUNCTION: perform the write and checks the return code.
|
||
*/
|
||
void mywrite (fldes,buf,len)
|
||
int fldes;
|
||
char *buf;
|
||
int len;
|
||
{
|
||
int nchar;
|
||
|
||
nchar = write(fldes,buf,(unsigned)len);
|
||
if (nchar != len) {
|
||
fprintf(stderr,MSGSTR(M_MSG_37,
|
||
"Can not communicate with the daemon writesrv\n"));
|
||
perror("write() in mywrite()");
|
||
exit(-1);
|
||
}
|
||
}
|
||
/*
|
||
* NAME: sigpipe
|
||
* FUNCTION: catches SIGPIPE, issues error message and exits.
|
||
*/
|
||
sigpipe(void)
|
||
{
|
||
fprintf(stderr,MSGSTR(M_MSG_37,
|
||
"Can not communicate with the daemon writesrv\n"));
|
||
exit(-1);
|
||
}
|
||
|
||
/*
|
||
* NAME: timeout
|
||
* FUNCTION: catches the alarm signal prints error message and exits
|
||
*/
|
||
int timeout(void)
|
||
{
|
||
fprintf(stderr,MSGSTR(M_MSG_40,"%s must not be running\n"),"writsrv");
|
||
exit(-1);
|
||
}
|
||
/*
|
||
* NAME: timeread
|
||
* FUNCTION: only wait 1 miniute for a response from writesrv
|
||
* this function is only used for the first read from writesrv for a
|
||
* connection.
|
||
*/
|
||
void timeread(fldes,buf,len)
|
||
int fldes;
|
||
char *buf;
|
||
int len;
|
||
{
|
||
new_signal (SIGALRM,(void (*)(int))timeout);
|
||
alarm ((unsigned)60);
|
||
myread(fldes,buf,len);
|
||
alarm ((unsigned)0);
|
||
}
|
||
|
||
expand_control ( str, length, str2 )
|
||
|
||
char str[];
|
||
int length;
|
||
char str2[];
|
||
{
|
||
int count,wclen;
|
||
int i = 0;
|
||
int j = 0;
|
||
char c;
|
||
wchar_t wc;
|
||
char octstr[32]; /* will hold octal version of non-printable chars */
|
||
bzero ( octstr, 32 );
|
||
if ( MB_CUR_MAX == 1 )
|
||
{
|
||
while ( ( i < length ) && ( j < BUF_LEN ) )
|
||
{
|
||
c = str[i];
|
||
if ( ( isprint ( c ) ) || ( c == WRT_BELL ) ||
|
||
( c == WRT_NEWLINE ) ||
|
||
( c == '\t') ) /* p35972 */
|
||
str2[j++] = c;
|
||
else
|
||
{
|
||
/* Print octal sequence for non-printable chars */
|
||
if ( (c != '\0') && (BUF_LEN-j > 5) )
|
||
{
|
||
sprintf (octstr,"\\o%3o",c);
|
||
strcat(str2,octstr);
|
||
j+=5; /* for \o plus 3 octal chars */
|
||
}
|
||
}
|
||
++i;
|
||
} /* while */
|
||
}
|
||
else { /* multibyte characters */
|
||
while ( ( i < length ) && ( j < BUF_LEN ) )
|
||
{
|
||
c = str[i];
|
||
if ( (wclen = mbtowc(&wc, &str[i], MB_CUR_MAX)) == -1 ) {
|
||
/* length is a maximum of MAX_INPUT-1 from the fgets */
|
||
if ( (length == (MAX_INPUT-1)) && ((MAX_INPUT-i-1) < MB_CUR_MAX) ) /* split a multibyte char */
|
||
return (i);
|
||
else {
|
||
fprintf(stderr,MSGSTR(M_MSG_43, "Error in multibyte character conversion.\n"));
|
||
exit(-1);
|
||
}
|
||
}
|
||
else {
|
||
if ( ( iswprint ( wc ) ) || ( wc == WRT_BELL ) ||
|
||
( wc == WRT_NEWLINE ) ||
|
||
( wc == '\t') ) { /* p35972 */
|
||
if ( (j + wclen) < BUF_LEN ) {
|
||
for (count = 0; count < wclen; count++)
|
||
{
|
||
str2[j++] = c;
|
||
c = str[++i];
|
||
}
|
||
}
|
||
else break;
|
||
}
|
||
else
|
||
{
|
||
if ( wc != '\0' )
|
||
{
|
||
/* Print octal sequence for non-printable chars */
|
||
for (count = 0; count < wclen; count++)
|
||
if ( BUF_LEN-j >=5 ) {
|
||
sprintf (octstr,"\\o%3o",c);
|
||
strcat(str2,octstr);
|
||
j+=5; /* for \o plus 3 octal chars */
|
||
c = str[++i];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} /* while */
|
||
} /* else */
|
||
|
||
if ( length == (MAX_INPUT - 1) )
|
||
str2[j] = WRT_NEWLINE;
|
||
|
||
return (0);
|
||
}
|