/* * 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 #include #include #include #include #include #include #include #include #include #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 #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); }