This is msend.c in view mode; [Download] [Up]
/* msend.c:
*
* user interface
*
* (c) Copyright 1988, 1989, 1990 Jim Frost. All Rights Reserved. Please see
* the accompanying file "Copyright" for more information.
*/
#include "Copyright"
#include "config.h"
#include "msend.h"
#include "patchlevel"
static void huh(i)
int i;
{ char d[10];
char spoolfile[MAXFILENAME+1];
struct stat stb;
sprintf(d,"-%d",i);
#ifdef SPOOLDIR
if (getuid() == ROOTUID)
seteuid(ROOTUID);
sprintf(spoolfile,"%s/%s",SPOOLDIR,whoami());
#else
if (gethome(whoami()))
sprintf(spoolfile,"%s/.msendmsgs",gethome(whoami()));
else {
printf("Can't find your home directory\n");
exit(1);
}
#endif
if (stat(spoolfile,&stb) == -1) {
printf("No old messages\n");
exit(0);
}
execlp("tail","tail",d,spoolfile,0);
perror("huh");
exit(0);
}
/* wipe out a user's spool file on demand
*/
static void rmspool()
{ char s[MAXFILENAME+1];
#ifdef SPOOLDIR
if (getuid() == ROOTUID)
seteuid(ROOTUID);
sprintf(s,"%s/%s",SPOOLDIR,whoami());
#else
if (gethome(whoami()))
sprintf(s,"%s/.msendmsgs",gethome(whoami()));
else {
printf("Can't find your home directory\n");
exit(1);
}
#endif
if (unlink(s) < 0)
perror(s);
exit(0);
}
/* "documentation"
*/
static void version() {
printf(" msend version %s patchlevel %s\n",VERSION,PATCHLEVEL);
printf(" by Jim Frost (%s) & Joe Ilacqua (%s)\n",MADD,SPIKE);
printf(" %s\n",Copyright);
}
static void usage()
{
version();
#ifndef GNUREADLINE
printf("Usage: msend username[@host] [message]\n");
printf(" msend . [message]\n");
#else
printf("Usage: msend [-edit] username[@host] [message]\n");
printf(" msend [-edit] . [message]\n");
#endif
printf(" msend -huh [# of messages to display]\n");
printf(" msend -clean\n");
printf(" msend -T tty [@host] [message]\n");
printf(" msend -version [@host]\n");
#ifdef CBROADCAST
printf(" msend -B @host [message]\n");
#endif
exit(0);
}
static void bigsig()
{ printf("Signature too big\n");
exit(1);
}
static void sigalrm()
{
printf("Inactivity timeout\n");
exit(1);
}
/* user breaks aren't really wanted, but we let the user break out if
* he or she REALLY wants to
*/
static void sigint()
{ static wasint= 0;
if (wasint) {
printf("\nConnection broken\n");
exit(1);
}
else {
wasint= 1;
printf("\nInterrupt received -- one more to kill\n");
}
}
main(argc,argv)
int argc;
char *argv[];
{ int a,b;
int broadcast;
int totty;
int uid;
long when;
char sig[MAXSIGNATURE+1];
char sigfmt[MAXSIGNATURE+1];
char line[MAXLINE+1];
char token[MAXTOKEN+1];
char fname[MAXFILENAME+1];
char localhost[MAXHOSTNAME+1];
char tmphost[MAXHOSTNAME+1];
struct hostent *hp;
#ifdef GNUREADLINE
char *gnubuf, *GNUGets();
extern int rl_insert();
short edit = EDIT;
#endif
FILE *f;
struct simsg si;
struct rimsg ri;
/* find out who we really are before becoming effectively root
*/
whoami();
/* since tty termination requests can leave hanging daemons, ignore
* them. user can still force termination, but not so easy.
*/
signal(SIGINT,sigint);
/* daemon will timeout after 10 minutes of inactivity, so we might
* as well do it too.
*/
alarm(LIFETIME);
signal(SIGALRM,sigalrm);
/* swap ruid and euid so our real id is root. this enables us to toggle
* between root uid-ness and nonroot uid-ness as necessary.
*/
if (geteuid() == ROOTUID) {
uid= getuid();
setruid(geteuid());
seteuid(uid);
}
/* please, no piping
*/
if (!isatty(0)) {
printf("Input must be a tty\n");
exit(1);
}
gethostname(tmphost,MAXHOSTNAME);
if ((hp = gethostbyname(tmphost)) != NULL)
(void) strncpy(localhost,hp->h_name,MAXHOSTNAME);
else /* better than nothing */
(void) strncpy(localhost,tmphost,MAXHOSTNAME);
/* defaults
*/
broadcast= 0;
totty= 0;
sprintf(sig,"%s@%s (%s): ",whoami(),localhost,ttyname(0)+5);
si.ttty[0]= '\0'; /* ttyname(0)+5 to strip "/dev/" */
/* look at options file
*/
sprintf(fname,"%s/.msendrc",gethome(whoami()));
if ((f= fopen(fname,"r")) != NULL) {
while (fgets(line,MAXLINE,f) != NULL) {
sscanf(line,"%s",token);
/* user define history size - the default is unlimited
*/
if (!strcmp(token,"history")) {
/* If we are not using the GNU readline stuff history is meaningless,
* but that is no reason for it to cause an error...
*/
#ifdef GNUREADLINE
int n;
if (sscanf (line, "%*s %d", &n) == 1)
stifle_history (n);
else {
printf("Bad history value in .msendrc\n");
exit(1);
}
#endif
continue;
}
if (!strcmp(token,"editing_mode")) {
/* If we are not using the GNU readline stuff history is meaningless,
* but that is no reason for it to cause an error...
*/
#ifdef GNUREADLINE
char buf[10];
if (sscanf (line, "%*s \"%s\"", buf) == 1) {
if (!strncmp(buf,"vi",2))
rl_vi_editing_mode();
else if (!strncmp(buf,"emacs",5)) /* The default is emacs, but...*/
rl_emacs_editing_mode();
else {
printf("Bad editor value in .msendrc\n");
exit(1);
}
}
else {
printf("Bad editor value in .msendrc\n");
exit(1);
}
#endif
continue;
}
if (!strcmp(token,"edit")) {
/* If we are not using the GNU readline stuff history is meaningless,
* but that is no reason for it to cause an error...
*/
#ifdef GNUREADLINE
char buf[10];
if (sscanf (line, "%*s \"%s\"", buf) == 1) {
if (!strncmp(buf,"on",2))
edit = 1;
else if (!strncmp(buf,"off",3)) /* The default is emacs, but...*/
edit = 0;
else {
printf("Bad editor value in .msendrc\n");
exit(1);
}
}
else {
printf("Bad editor value in .msendrc\n");
exit(1);
}
#endif
continue;
}
/* user defined signature
*/
if (!strcmp(token,"signature")) {
for (a= 0; (line[a] != '\0') && (line[a] != '"'); a++)
;
if (line[a] == '\0') {
printf("Signature needs a quoted string\n");
exit(1);
}
for (a++, b= 0; (line[a] != '\0') && (line[a] != '"')
&& (b <= MAXSIGNATURE); a++)
sigfmt[b++]= line[a];
if (line[a] != '"') {
printf("Signature format string has no end quotes or is too long\n");
exit(1);
}
sigfmt[b]= '\0';
/* parse signature format and build the signature
*/
sprintf(sig,"%s@%s ",whoami(),localhost); /* always include this */
for (b= 0; sigfmt[b] != '\0'; b++)
if (sigfmt[b] == '%')
switch (sigfmt[++b]) {
case '%' :
if (strlen(sig) >= MAXSIGNATURE)
bigsig();
strcat(sig,"%");
break;
case 'd' : /* date and time */
if (strlen(sig) + strlen(ctime(&when)) > MAXSIGNATURE)
bigsig();
time(&when);
strcat(sig,ctime(&when));
sig[strlen(sig)-9]= '\0';
break;
case 't' : /* tty */
if (strlen(sig) + strlen(ttyname(0)+5) > MAXSIGNATURE)
bigsig();
strcat(sig,ttyname(0)+5);
break;
default :
a= strlen(sig);
sig[a]= sigfmt[b];
sig[a+1]= '\0';
}
else {
a= strlen(sig);
sig[a]= sigfmt[b];
sig[a+1]= '\0';
}
strcat(sig,": ");
}
}
fclose(f);
}
/* figure out options
*/
for (a= 1; (a < argc) && (*argv[a] == '-'); a++) {
/* the "huh" function
*/
if (!strcmp(argv[a],"-huh")) {
if (++a < argc)
huh(atoi(argv[a]));
else
huh(1);
}
/* deliberate forgetfulness option
*/
if (!strcmp(argv[a],"-clean"))
rmspool();
else if (!strcmp(argv[a],"-edit"))
#ifdef GNUREADLINE
edit = !edit;
#else
;
#endif
else if ((!strcmp(argv[a],"-version")) || *(argv[a]+1) == 'v') {
if (argc == 2) {
version();
exit(0);
} else if ( argc == 3 ) {
if (*argv[2] != '@')
usage();
strcpy(si.taddr,argv[2]);
(void) striphost(si.taddr,si.tohost);
si.fwdcount= 0;
si.msg[0]= '\0';
sendmessage(&si,&ri,SM_CLOSE|SM_VERSION);
if (ri.msg[0] == '\0') {
while(striphost(si.taddr,si.tohost))
strcpy(si.taddr,si.tohost);
printf ("%s is running a pre-1.0 version of msend\n",si.taddr);
} else
printf("%s\n",ri.msg);
exit(0);
} else
usage();
}
/* decode option(s)
*/
else switch (*(argv[a]+1)) {
case 'B' :
#ifdef CBROADCAST
broadcast= SM_BROADCAST;
break;
#else
printf("Broadcasting is not allowed from this host\n");
exit(1);
#endif
case 'c' : /* short form of -clean for lazy people like me */
rmspool();
break;
case 'e' : /* short form of -edit for lazy people like jim */
#ifdef GNUREADLINE
edit = !edit;
#endif
break;
case 'T' :
totty= SM_TTY;
if (*(argv[a]+2) == '\0') {
if (++a == argc) {
printf("Tty name missing\n");
exit(1);
}
else if (strlen(argv[a]) > MAXTTY) {
printf("Tty name too long\n");
exit(1);
}
else
strcpy(si.ttty,argv[a]);
}
else if (strlen(argv[a]+2) > MAXTTY) {
printf("Tty name too long\n");
exit(1);
}
else
strcpy(si.ttty,argv[a]+2);
break;
default :
usage();
}
}
if ((!totty) && (a == argc))
usage();
if (broadcast && totty) {
printf("Broadcast and tty selection functions are mutually exclusive\n");
exit(1);
}
/* argument verification and "last send" function
*/
if ((!totty) && (!broadcast)) {
sprintf(fname,"%s/.lastmsend",gethome(whoami()));
if (!strcmp(argv[a],".")) {
if ((f= fopen(fname,"r")) == NULL) {
printf("Last recipient name unknown\n");
exit(1);
}
else {
fscanf(f,"%s",si.taddr);
fclose(f);
if (!striphost(si.taddr,si.tohost))
strcpy(si.tohost,localhost);
}
a++;
}
else {
/* get name from command line argument and save it if we can
*/
if (*argv[a] == '@') {
printf("You must specify a username\n");
exit(1);
}
strcpy(si.taddr,argv[a]);
if ((f= fopen(fname,"w")) != NULL) {
fprintf(f,"%s\n",argv[a]);
fclose(f);
}
if (!striphost(si.taddr,si.tohost))
strcpy(si.tohost,localhost);
a++;
}
}
else if (totty) {
if ((a < argc) && (*argv[a] == '@'))
strcpy(si.tohost,argv[a++]+1);
else
strcpy(si.tohost,localhost);
}
else if (*argv[a] != '@') { /* broadcast */
printf("You must indicate '@host' for a broadcast\n");
exit(1);
}
else {
strcpy(si.taddr,argv[a++]);
(void) striphost(si.taddr,si.tohost);
}
if (a < argc) {
/* command line mode
*/
strcpy(&si.msg[0],sig); /* copy signature into message area */
for (; a < argc; a++) {
strcat(si.msg,argv[a]);
if (a != argc-1)
strcat(si.msg," ");
}
si.fwdcount= 0;
sendmessage(&si,&ri,SM_CLOSE|broadcast|totty);
if (ri.h.errno != RE_OK)
printf("%s\n",ri.msg);
exit(0);
}
/* make initial connection to see if we can
*/
si.msg[0]= '\0';
sendmessage(&si,&ri,0);
if (ri.h.errno != RE_OK) {
printf("%s\n",ri.msg);
exit(1);
}
strcpy(&si.msg[0],sig); /* copy signature into message area */
for (;;) {
int once = 0;
#ifdef GNUREADLINE
if (!edit) {
#endif
printf("msend>");
if (fgets(&si.msg[strlen(sig)],MAXMSG-strlen(sig),stdin) == NULL) {
printf("^D\n"); /* EOF */
si.msg[0]= '\0'; /* send null message to close */
sendmessage(&si,&ri,SM_CLOSE); /* the connection */
exit(0);
}
#ifdef GNUREADLINE
} else {
rl_bind_key('\t',rl_insert); /* The default is "complete" */
bzero(&si.msg[strlen(sig)],MAXMSG-strlen(sig));
if((gnubuf = GNUGets("msend>")) == NULL) {
printf("^D\n"); /* EOF */
si.msg[0]= '\0'; /* send null message to close */
sendmessage(&si,&ri,SM_CLOSE); /* the connection */
exit(0);
} else {
strncpy(&si.msg[strlen(sig)],gnubuf,MAXMSG-strlen(sig)-1);
free(gnubuf);
}
}
#endif
alarm(LIFETIME); /* reset idle out timer */
#ifdef GNUREADLINE
if (!edit)
#endif
si.msg[strlen(si.msg)-1]= '\0'; /* strip newline */
if (!strcmp(&si.msg[strlen(sig)],".")) { /* exit command */
si.msg[0]= '\0';
sendmessage(&si,&ri,SM_CLOSE);
exit(0);
}
if (si.msg[strlen(sig)] != '\0') {
si.fwdcount= 0;
sendmessage(&si,&ri,broadcast|totty);
switch (ri.h.errno) {
case RE_OK :
break;
case RE_NOTFATAL:
printf("%s\n",ri.msg);
break;
default :
printf("%s\n",ri.msg);
exit(1); /* connection is already broken */
}
}
if (!once) {
/* This is some code to strip off the domain name of the host
* after we have sent one message. It works because we know the
* signature is in the form "<user>@<host><SPACE>...". If that
* format changes this will break...
*/
int i,j;
once++;
for (i = 0; sig[i] != ' '; i++) {
if (sig[i] == '.') {
for (j = i+1; sig[j] != ' '; j++);
strcpy(&sig[i],&sig[j]);
strcpy(&si.msg[0],sig); /* copy signature into message area */
break;
}
}
}
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.