home *** CD-ROM | disk | FTP | other *** search
- /* 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;
- }
- }
- }
- }
- }
-
-