ftp.nice.ch/pub/next/unix/admin/msend.1.0.N.bs.tar.gz#/msend/msend.c

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.