/*
* File: sendmsg.c
*
* Author: Ulli Horlacher (framstag@rus.uni-stuttgart.de)
*
* History:
*
* 1995-08-11 Framstag initial version
* 1995-08-12 Framstag elm alias support
* 1995-11-02 Framstag added minimal chat mode
* 1995-11-14 Framstag added message receiving modes
* 1995-12-21 Framstag avoid unnecessary error message while
* configuring the own tty
* 1995-12-21 Framstag better server connect testing
* 1996-02-20 Framstag changed msg-tty file to support NFS
* 1996-04-01 Framstag added multiline mode
* 1996-04-17 Framstag new error handling for open_connection
* 1996-05-02 Framstag fixed stupid shutdown() programming bug
* 1996-05-03 Framstag fixed bug with gethostname()
* 1996-05-24 Framstag sendmsg no longer tries to configure the tty
* when there is none (sending via pipe)
* 1996-08-12 Framstag no questions asked when in batch mode (no tty)
* 1996-11-13 Framstag faster mesg/tty handling
* 1996-11-26 Framstag added -n option
* 1997-01-04 Framstag added saft_connect()-call
* 1997-02-03 Framstag better tty configuration
* sprintf() -> snprintf()
* added -u and -f options
* added -u and -f options
* changed tty permission testing and -m behaviour
* 1997-02-23 Framstag modified str_* function names
* 1997-06-19 Framstag changend tty testing and behaviour
* 1997-06-23 Framstag added readline support
* 1997-06-24 Framstag fixed some prompt bugs
* 1997-07-04 Framstag added cleanup signal handler
* 1998-01-03 Framstag better tty configuration
* 1998-01-17 Framstag check SAFT-URL for alternative tcp port
* 1998-03-29 Framstag "sendmsg -m 2>/dev/null" now works
* 1998-04-06 Framstag added -s message option
* 1998-07-12 Framstag added option -r
* 1998-08-21 Framstag fixed bug if tty can receive msg
* 1998-09-17 Framstag added option -q
*
* The sendmessage client of the sendfile package.
* Sends a single line text message to the SAFT-server of the destination
* system to be displayed on the recipients terminal.
*
* Copyright © 1995-1998 Ulli Horlacher
* This file is covered by the GNU General Public License
*/
#include "config.h" /* various #defines */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include "string.h" /* extended string functions */
#include "net.h" /* the network routines */
#include "io.h" /* (socket) read/write */
#include "message.h" /* information, warning and error messages */
#include "utf7.h" /* UTF-7 coding */
#include "address.h" /* address checking */
#include "getline.h" /* get a line of text from stdin */
#if defined(HAVE_GETOPT_H)
#include <getopt.h>
#else
int getopt(int, char * const *, const char *);
extern int opterr;
extern int optind;
extern int optopt;
extern char *optarg;
#endif
#if defined(SOLARIS2)
int gethostname(char *, int);
#endif
#if defined(LINUX)
int gethostname(char *, size_t);
#endif
#ifndef AIX3
#ifndef CONVEXOS
FILE *popen(const char *, const char *);
#endif
int pclose(FILE *);
#else
#include "bsd.h"
#endif
#ifdef NEXT
int shutdown(int, int);
#endif
/* print short help usage text */
int usage();
/* clean termination routine */
void cleanup();
/* global variables */
int
client=1, /* flag to determine client or server */
quiet=0, /* quiet mode */
verbose=0, /* flag for verbose mode */
packet_size; /* only needed for linking */
char
*prg; /* name of the game */
int main(int argc, char *argv[]) {
int
sockfd, /* socket file descriptor */
chat, /* flag for chat mode */
reply, /* flag for reply mode */
force, /* flag for force sending */
receive, /* receiving flag */
multiline, /* flag for sending a multiline message */
opt; /* option to test for */
char
*cp, /* simple character pointer */
*tty, /* the tty device with path */
ttyt[FLEN], /* the tty on which sendfiled will write (see msgcf) */
recipient[FLEN], /* recipient at serverhost */
user[FLEN], /* local user name */
from[FLEN], /* alternative from name */
host[FLEN], /* name of serverhost */
localhost[FLEN], /* name of the local host */
msgcf[FLEN], /* message control file */
msg[MAXLEN], /* message from ARGV */
line[MAXLEN], /* input or output string */
login[MAXLEN], /* login user name */
tmp[3*MAXLEN]; /* temporary string */
char
utf_msg[LEN_UTF], /* msg in UTF-7 format */
iso_msg[LEN_ISO]; /* msg in ISO Latin-1 format */
FILE
*inf, /* input file */
*outf; /* output file */
struct stat finfo; /* information about a file */
chat=0;
force=0;
reply=0;
sockfd=0;
verbose=0;
receive=0;
multiline=0;
*msg=0;
*host=0;
*user=0;
*from=0;
*line=0;
*ttyt=0;
*iso_msg=0;
*recipient=0;
tty=NULL;
prg=argv[0];
if ((cp=strrchr(prg,'/'))) prg=cp+1;
/* scan the command line on options */
while ((opt=getopt(argc,argv,"rcvVmMlhq?fs:u:")) > 0) {
switch (opt) {
case ':':
case 'h':
case '?': return(usage());
case 'c': chat=1; break;
case 'r': reply=1; break;
case 'q': quiet=2; break;
case 'v': verbose=1; break;
case 'm': receive=1; break;
case 'M': receive=2; break;
case 'l': multiline=1; break;
case 'f': force=1; break;
case 's': strcpy(msg,optarg); break;
case 'u': strcpy(from,optarg); break;
case 'V': message(prg,'I',"version "VERSION" revision "REVISION); return(0);
}
}
/* too few arguments? */
if (argc-optind<1 && receive==0 && reply==0) return(usage());
/* incompatible options? */
if (*msg && (multiline || chat)) {
multiline=chat=0;
message(prg,'W',"you cannot specify option -s together with -c or -l");
}
/* get the local host name */
if (gethostname(localhost,FLEN-1)<0) strcpy(localhost,"localhost");
/* get own user name, recipient name and host */
if (reply) argc=0;
destination(argc,argv,user,recipient,host,NULL);
if (reply && !*recipient) {
errno=0;
message(prg,'F',"no reply address found");
}
if (*from) iso2utf(user,from);
strcpy(login,user);
if ((cp=strchr(login,' '))) *cp=0;
/* enable simple interrupt handler */
signal(SIGTERM,cleanup);
signal(SIGABRT,cleanup);
signal(SIGQUIT,cleanup);
signal(SIGHUP,cleanup);
signal(SIGINT,cleanup);
if (!force) {
/* test the local sendfiled */
if (verbose) printf("testing local SAFT server:\n");
sockfd=open_connection("127.0.0.1",SAFT);
sock_getline(sockfd,line);
/* no local server? */
if (!str_beq(line,"220 ") || !strstr(line,"SAFT"))
message(prg,'W',"there is no local SAFT server - "
"you cannot receive messages");
else {
/* test if you can receive messages */
snprintf(MAXS(line),"FROM %s",login);
sock_putline(sockfd,line);
sock_getline(sockfd,line);
snprintf(MAXS(line),"TO %s",login);
sock_putline(sockfd,line);
sock_getline(sockfd,line);
if (str_beq(line,"521 ")) {
errno=0;
message(prg,'F',"You are not allowed to use the sendmsg service");
}
if (!str_beq(line,"200 "))
message(prg,'W',"local server error - you cannot receive messages");
if (isatty(fileno(stdin))) {
/* get tty name */
if (!(tty=ttyname(fileno(stdin))) || *tty!='/')
message(prg,'F',"cannot determine your tty name");
else {
/* the message tty config file */
snprintf(MAXS(msgcf),"%s/%s/config/tty@%s",SPOOL,login,localhost);
/* open tty write permissions if necessary */
if (receive) {
if (receive==1) {
/* mark current tty as active for receiving */
if ((outf=rfopen(msgcf,"w"))) {
fprintf(outf,"%s\n",tty);
fclose(outf);
if (chmod(tty,S_IRUSR|S_IWUSR|S_IWGRP)<0) {
snprintf(MAXS(tmp),"cannot open your tty %s for writing",tty);
message(prg,'W',tmp);
} else if (argc-optind<1) {
message(prg,'I',
"receiving messages is now restricted to this tty");
}
} else {
snprintf(MAXS(tmp),"cannot configure your tty "
"(no write access to %s)",msgcf);
message(prg,'W',tmp);
}
}
if (receive==2) {
unlink(msgcf);
if (argc-optind<1)
message(prg,'I',
"receiving messages is now possible on all ttys");
}
} else { /* keep tty status and mode */
/* is the current tty writable? */
if (stat(tty,&finfo)<0 || !(finfo.st_mode&S_IWGRP)) {
errno=0;
snprintf(MAXS(tmp),"your tty %s is write protected; "
"try sendmsg -m",tty);
message(prg,'F',tmp);
}
/* read the receiving tty from the message config file */
if ((inf=rfopen(msgcf,"r"))) {
fgetl(ttyt,inf);
fclose(inf);
if ((cp=strchr(ttyt,'\n'))) *cp=0;
} else {
strcpy(ttyt,tty);
/* mark current tty as active for receiving */
if ((outf=rfopen(msgcf,"w"))) {
fprintf(outf,tty);
fclose(outf);
}
}
/* is the current tty active for sendfiled? */
if (!str_eq(tty,ttyt)) {
errno=0;
message(prg,'F',
"you cannot receive an answer message on this tty; "
"try sendmsg -m or sendmsg -f");
}
}
}
}
}
shutdown(sockfd,2);
}
if (argc-optind<1 && !reply) return(0);
/* name the local host */
if (str_eq(host,"127.0.0.1")) strcpy(host,localhost);
/* look for correct SAFT server and open connection */
sockfd=saft_connect("msg",recipient,user,host,tmp);
/* send several lines at once? */
if (multiline) {
if (isatty(fileno(stdin)))
printf("Enter multiline message (max 10 lines! End with Ctrl-D):\n");
/* read until EOF */
while (*line=0,getpromptline(line,LEN_ISO-1)) {
if ((cp=strchr(line,'\n'))) *cp=0;
/* message text too long? */
if (strlen(iso_msg)+strlen(line)>LEN_ISO*.8) {
errno=0;
message(prg,'F',"message line too long");
}
/* add a new line if necessary */
if (*iso_msg || !*line) strcat(iso_msg,"\r\n");
/* add the text line */
strncat(iso_msg,line,LEN_ISO-1);
iso_msg[LEN_ISO-1]=0;
}
if (*iso_msg) {
/* encode to UTF-7 */
iso2utf(utf_msg,iso_msg);
/* message text too long? */
if (strlen(utf_msg)>MAXLEN-10) {
errno=0;
message(prg,'F',"message line too long");
}
/* send the message */
snprintf(MAXS(tmp),"MSG %s",utf_msg);
sendheader(sockfd,tmp);
}
} else { /* single line or chat mode */
do {
/* read the message */
*iso_msg=0;
/* message given by -s option? */
if (*msg)
strcpy(iso_msg,msg);
else { /* prompt for message */
if (isatty(fileno(stdin))) strcpy(iso_msg,"message: ");
if (!getpromptline(iso_msg,LEN_ISO-1)) {
printf("\n");
break;
}
}
if (!*iso_msg) break;
/* strip off new line */
cp=strrchr(iso_msg,'\n');
if (cp && (cp!=(char *)iso_msg)) *cp=0;
/* encode to UTF-7 */
iso2utf(utf_msg,iso_msg);
/* send the message */
snprintf(MAXS(tmp),"MSG %s",utf_msg);
sendheader(sockfd,tmp);
} while (chat);
}
/* close the connection */
sock_putline(sockfd,"QUIT");
getreply(sockfd);
close(sockfd);
return(0);
}
/* cleanup - clean termination routine */
void cleanup() {
printf("\r\n");
exit(0);
}
/*
* usage - print short help usage text
*/
int usage() {
fprintf(stderr,"usage: %s [-vfmMr] [-s 'message' ] user[@host]\n",prg);
fprintf(stderr,"options: -v verbose mode\n");
fprintf(stderr," -f force sending of messages and ignore the tty status\n");
fprintf(stderr," -m allow receiving messages only on this tty\n");
fprintf(stderr," -M allow receiving messages on other ttys, too\n");
fprintf(stderr," -s send 'message'\n");
fprintf(stderr," -r reply to last received message\n");
fprintf(stderr,"example: %s framstag@bofh.belwue.de\n",prg);
return(2);
}
syntax highlighted by Code2HTML, v. 0.9.1