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.