home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume36 / msend / part01 / msend.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-22  |  13.5 KB  |  592 lines

  1. /* msend.c:
  2.  *
  3.  * user interface
  4.  *
  5.  * (c) Copyright 1988, 1989, 1990 Jim Frost.  All Rights Reserved.  Please see
  6.  * the accompanying file "Copyright" for more information.
  7.  */
  8.  
  9. #include "Copyright"
  10. #include "config.h"
  11. #include "msend.h"
  12. #include "patchlevel"
  13.  
  14. static void huh(i)
  15. int i;
  16. { char   d[10];
  17.   char   spoolfile[MAXFILENAME+1];
  18.   struct stat   stb;
  19.  
  20.   sprintf(d,"-%d",i);
  21.  
  22. #ifdef SPOOLDIR
  23.   if (getuid() == ROOTUID)
  24.     seteuid(ROOTUID);
  25.   sprintf(spoolfile,"%s/%s",SPOOLDIR,whoami());
  26. #else
  27.   if (gethome(whoami()))
  28.     sprintf(spoolfile,"%s/.msendmsgs",gethome(whoami()));
  29.   else {
  30.     printf("Can't find your home directory\n");
  31.     exit(1);
  32.   }
  33. #endif
  34.  
  35.   if (stat(spoolfile,&stb) == -1) {
  36.     printf("No old messages\n");
  37.     exit(0);
  38.   }
  39.  
  40.   execlp("tail","tail",d,spoolfile,0);
  41.   perror("huh");
  42.   exit(0);
  43. }
  44.  
  45. /* wipe out a user's spool file on demand
  46.  */
  47.  
  48. static void rmspool()
  49. { char s[MAXFILENAME+1];
  50.  
  51. #ifdef SPOOLDIR
  52.   if (getuid() == ROOTUID)
  53.     seteuid(ROOTUID);
  54.   sprintf(s,"%s/%s",SPOOLDIR,whoami());
  55. #else
  56.   if (gethome(whoami()))
  57.     sprintf(s,"%s/.msendmsgs",gethome(whoami()));
  58.   else {
  59.     printf("Can't find your home directory\n");
  60.     exit(1);
  61.   }
  62. #endif
  63.  
  64.   if (unlink(s) < 0)
  65.     perror(s);
  66.   exit(0);
  67. }
  68.  
  69. /* "documentation"
  70.  */
  71.  
  72. static void version() {
  73.   printf("   msend version %s patchlevel %s\n",VERSION,PATCHLEVEL);
  74.   printf("   by Jim Frost (%s) & Joe Ilacqua (%s)\n",MADD,SPIKE);
  75.   printf("   %s\n",Copyright);
  76. }
  77.  
  78. static void usage()
  79.   version();
  80. #ifndef GNUREADLINE
  81.   printf("Usage: msend username[@host] [message]\n");
  82.   printf("       msend . [message]\n");
  83. #else
  84.   printf("Usage: msend [-edit] username[@host] [message]\n");
  85.   printf("       msend [-edit] . [message]\n");
  86. #endif
  87.   printf("       msend -huh [# of messages to display]\n");
  88.   printf("       msend -clean\n");
  89.   printf("       msend -T tty [@host] [message]\n");
  90.   printf("       msend -version [@host]\n");
  91. #ifdef CBROADCAST
  92.   printf("       msend -B @host [message]\n");
  93. #endif
  94.   exit(0);
  95. }
  96.  
  97. static void bigsig()
  98. { printf("Signature too big\n");
  99.   exit(1);
  100. }
  101.  
  102. static void sigalrm()
  103. {
  104.   printf("Inactivity timeout\n");
  105.   exit(1);
  106. }
  107.  
  108. /* user breaks aren't really wanted, but we let the user break out if
  109.  * he or she REALLY wants to
  110.  */
  111.  
  112. static void sigint()
  113. { static wasint= 0;
  114.  
  115.   if (wasint) {
  116.     printf("\nConnection broken\n");
  117.     exit(1);
  118.   }
  119.   else {
  120.     wasint= 1;
  121.     printf("\nInterrupt received -- one more to kill\n");
  122.   }
  123. }
  124.  
  125. main(argc,argv)
  126. int  argc;
  127. char *argv[];
  128. { int    a,b;
  129.   int    broadcast;
  130.   int    totty;
  131.   int    uid;
  132.   long   when;
  133.   char   sig[MAXSIGNATURE+1];
  134.   char   sigfmt[MAXSIGNATURE+1];
  135.   char   line[MAXLINE+1];
  136.   char   token[MAXTOKEN+1];
  137.   char   fname[MAXFILENAME+1];
  138.   char   localhost[MAXHOSTNAME+1];
  139.   char   tmphost[MAXHOSTNAME+1];
  140.   struct hostent *hp;
  141. #ifdef GNUREADLINE
  142.   char *gnubuf, *GNUGets();
  143.   extern int rl_insert();
  144.   short edit = EDIT;
  145. #endif
  146.   FILE   *f;
  147.   struct simsg  si;
  148.   struct rimsg  ri;
  149.  
  150.   /* find out who we really are before becoming effectively root
  151.    */
  152.  
  153.   whoami();
  154.  
  155.   /* since tty termination requests can leave hanging daemons, ignore
  156.    * them.  user can still force termination, but not so easy.
  157.    */
  158.  
  159.   signal(SIGINT,sigint);
  160.  
  161.   /* daemon will timeout after 10 minutes of inactivity, so we might
  162.    * as well do it too.
  163.    */
  164.  
  165.   alarm(LIFETIME);
  166.   signal(SIGALRM,sigalrm);
  167.  
  168.   /* swap ruid and euid so our real id is root.  this enables us to toggle
  169.    * between root uid-ness and nonroot uid-ness as necessary.
  170.    */
  171.  
  172.   if (geteuid() == ROOTUID) {
  173.     uid= getuid();
  174.     setruid(geteuid());
  175.     seteuid(uid);
  176.   }
  177.  
  178.   /* please, no piping
  179.    */
  180.  
  181.   if (!isatty(0)) {
  182.     printf("Input must be a tty\n");
  183.     exit(1);
  184.   }
  185.  
  186.   gethostname(tmphost,MAXHOSTNAME);
  187.   if ((hp = gethostbyname(tmphost)) != NULL)
  188.     (void) strncpy(localhost,hp->h_name,MAXHOSTNAME);
  189.   else /* better than nothing */
  190.     (void) strncpy(localhost,tmphost,MAXHOSTNAME);
  191.   /* defaults
  192.    */
  193.  
  194.   broadcast= 0;
  195.   totty= 0;
  196.   sprintf(sig,"%s@%s (%s): ",whoami(),localhost,ttyname(0)+5);
  197.   si.ttty[0]= '\0';                /* ttyname(0)+5 to strip "/dev/" */
  198.  
  199.   /* look at options file
  200.    */
  201.  
  202.   sprintf(fname,"%s/.msendrc",gethome(whoami()));
  203.   if ((f= fopen(fname,"r")) != NULL) {
  204.     while (fgets(line,MAXLINE,f) != NULL) {
  205.       sscanf(line,"%s",token);
  206.  
  207.  
  208.       /* user define history size - the default is unlimited
  209.        */
  210.       if (!strcmp(token,"history")) {
  211.     /* If we are not using the GNU readline stuff history is meaningless,
  212.      * but that is no reason for it to cause an error...
  213.      */
  214. #ifdef GNUREADLINE
  215.     int n;
  216.     if (sscanf (line, "%*s %d", &n) == 1) 
  217.       stifle_history (n);
  218.     else {
  219.       printf("Bad history value in .msendrc\n");
  220.       exit(1);
  221.     }
  222. #endif
  223.     continue;
  224.       }
  225.       if (!strcmp(token,"editing_mode")) {
  226.     /* If we are not using the GNU readline stuff history is meaningless,
  227.      * but that is no reason for it to cause an error...
  228.      */
  229. #ifdef GNUREADLINE
  230.     char buf[10];
  231.     if (sscanf (line, "%*s \"%s\"", buf) == 1) {
  232.       if (!strncmp(buf,"vi",2))
  233.         rl_vi_editing_mode();
  234.       else if (!strncmp(buf,"emacs",5)) /* The default is emacs, but...*/
  235.         rl_emacs_editing_mode();
  236.       else {
  237.         printf("Bad editor value in .msendrc\n");
  238.         exit(1);
  239.       }
  240.     }
  241.     else {
  242.       printf("Bad editor value in .msendrc\n");
  243.       exit(1);
  244.     }
  245. #endif
  246.     continue;
  247.       }
  248.       if (!strcmp(token,"edit")) {
  249.     /* If we are not using the GNU readline stuff history is meaningless,
  250.      * but that is no reason for it to cause an error...
  251.      */
  252. #ifdef GNUREADLINE
  253.     char buf[10];
  254.     if (sscanf (line, "%*s \"%s\"", buf) == 1) {
  255.       if (!strncmp(buf,"on",2))
  256.         edit = 1;
  257.       else if (!strncmp(buf,"off",3)) /* The default is emacs, but...*/
  258.         edit = 0;
  259.       else {
  260.         printf("Bad editor value in .msendrc\n");
  261.         exit(1);
  262.       }
  263.     }
  264.     else {
  265.       printf("Bad editor value in .msendrc\n");
  266.       exit(1);
  267.     }
  268. #endif
  269.     continue;
  270.       }
  271.  
  272.       /* user defined signature
  273.        */
  274.  
  275.       if (!strcmp(token,"signature")) {
  276.         for (a= 0; (line[a] != '\0') && (line[a] != '"'); a++)
  277.           ;
  278.         if (line[a] == '\0') {
  279.           printf("Signature needs a quoted string\n");
  280.           exit(1);
  281.         }
  282.         for (a++, b= 0; (line[a] != '\0') && (line[a] != '"')
  283.                          && (b <= MAXSIGNATURE); a++)
  284.           sigfmt[b++]= line[a];
  285.         if (line[a] != '"') {
  286.           printf("Signature format string has no end quotes or is too long\n");
  287.           exit(1);
  288.         }
  289.         sigfmt[b]= '\0';
  290.  
  291.         /* parse signature format and build the signature
  292.          */
  293.  
  294.         sprintf(sig,"%s@%s ",whoami(),localhost); /* always include this */
  295.         for (b= 0; sigfmt[b] != '\0'; b++)
  296.           if (sigfmt[b] == '%')
  297.             switch (sigfmt[++b]) {
  298.               case '%' :
  299.                 if (strlen(sig) >= MAXSIGNATURE)
  300.                   bigsig();
  301.                 strcat(sig,"%");
  302.                 break;
  303.               case 'd' : /* date and time */
  304.                 if (strlen(sig) + strlen(ctime(&when)) > MAXSIGNATURE)
  305.                   bigsig();
  306.                 time(&when);
  307.                 strcat(sig,ctime(&when));
  308.                 sig[strlen(sig)-9]= '\0';
  309.                 break;
  310.               case 't' : /* tty */
  311.                 if (strlen(sig) + strlen(ttyname(0)+5) > MAXSIGNATURE)
  312.                   bigsig();
  313.                 strcat(sig,ttyname(0)+5);
  314.                 break;
  315.               default :
  316.                 a= strlen(sig);
  317.                 sig[a]= sigfmt[b];
  318.                 sig[a+1]= '\0';
  319.             }
  320.           else {
  321.             a= strlen(sig);
  322.             sig[a]= sigfmt[b];
  323.             sig[a+1]= '\0';
  324.           }
  325.         strcat(sig,": ");
  326.       }
  327.     }
  328.   fclose(f);
  329.   }
  330.  
  331.   /* figure out options
  332.    */
  333.  
  334.   for (a= 1; (a < argc) && (*argv[a] == '-'); a++) {
  335.  
  336.     /* the "huh" function
  337.      */
  338.  
  339.     if (!strcmp(argv[a],"-huh")) {
  340.       if (++a < argc)
  341.         huh(atoi(argv[a]));
  342.       else
  343.         huh(1);
  344.     }
  345.  
  346.     /* deliberate forgetfulness option
  347.      */
  348.  
  349.     if (!strcmp(argv[a],"-clean"))
  350.       rmspool();
  351.  
  352.     else if (!strcmp(argv[a],"-edit"))
  353. #ifdef GNUREADLINE
  354.       edit = !edit;
  355. #else
  356.     ;
  357. #endif
  358.     else if ((!strcmp(argv[a],"-version")) || *(argv[a]+1) == 'v') {
  359.       if (argc == 2) {
  360.     version();
  361.     exit(0);
  362.       } else if ( argc == 3 ) {
  363.     if (*argv[2] != '@')
  364.       usage();
  365.     strcpy(si.taddr,argv[2]);
  366.         (void) striphost(si.taddr,si.tohost);
  367.     si.fwdcount= 0;
  368.     si.msg[0]= '\0';
  369.     sendmessage(&si,&ri,SM_CLOSE|SM_VERSION);
  370.     if (ri.msg[0] == '\0') {
  371.       while(striphost(si.taddr,si.tohost))
  372.         strcpy(si.taddr,si.tohost);
  373.       printf ("%s is running a pre-1.0 version of msend\n",si.taddr);
  374.     } else
  375.       printf("%s\n",ri.msg);
  376.     exit(0);
  377.       } else
  378.     usage();
  379.     }
  380.  
  381.     /* decode option(s)
  382.      */
  383.  
  384.     else switch (*(argv[a]+1)) {
  385.       case 'B' :
  386. #ifdef CBROADCAST
  387.         broadcast= SM_BROADCAST;
  388.         break;
  389. #else
  390.         printf("Broadcasting is not allowed from this host\n");
  391.         exit(1);
  392. #endif
  393.       case 'c' : /* short form of -clean for lazy people like me */
  394.         rmspool();
  395.     break;
  396.       case 'e' : /* short form of -edit for lazy people like jim */
  397. #ifdef GNUREADLINE
  398.     edit = !edit;
  399. #endif
  400.     break;
  401.       case 'T' :
  402.         totty= SM_TTY;
  403.         if (*(argv[a]+2) == '\0') {
  404.           if (++a == argc) {
  405.             printf("Tty name missing\n");
  406.             exit(1);
  407.           }
  408.           else if (strlen(argv[a]) > MAXTTY) {
  409.             printf("Tty name too long\n");
  410.             exit(1);
  411.           }
  412.           else
  413.             strcpy(si.ttty,argv[a]);
  414.         }
  415.         else if (strlen(argv[a]+2) > MAXTTY) {
  416.           printf("Tty name too long\n");
  417.           exit(1);
  418.         }
  419.         else
  420.           strcpy(si.ttty,argv[a]+2);
  421.         break;
  422.       default :
  423.         usage();
  424.     }
  425.   }
  426.  
  427.   if ((!totty) && (a == argc))
  428.     usage();
  429.  
  430.   if (broadcast && totty) {
  431.     printf("Broadcast and tty selection functions are mutually exclusive\n");
  432.     exit(1);
  433.   }
  434.  
  435.   /* argument verification and "last send" function
  436.    */
  437.  
  438.   if ((!totty) && (!broadcast)) {
  439.     sprintf(fname,"%s/.lastmsend",gethome(whoami()));
  440.     if (!strcmp(argv[a],".")) {
  441.       if ((f= fopen(fname,"r")) == NULL) {
  442.         printf("Last recipient name unknown\n");
  443.         exit(1);
  444.       }
  445.       else {
  446.         fscanf(f,"%s",si.taddr);
  447.         fclose(f);
  448.         if (!striphost(si.taddr,si.tohost))
  449.           strcpy(si.tohost,localhost);
  450.       }
  451.       a++;
  452.     }
  453.     else {
  454.  
  455.       /* get name from command line argument and save it if we can
  456.        */
  457.  
  458.       if (*argv[a] == '@') {
  459.         printf("You must specify a username\n");
  460.         exit(1);
  461.       }
  462.       strcpy(si.taddr,argv[a]);
  463.       if ((f= fopen(fname,"w")) != NULL) {
  464.         fprintf(f,"%s\n",argv[a]);
  465.         fclose(f);
  466.       }
  467.       if (!striphost(si.taddr,si.tohost))
  468.         strcpy(si.tohost,localhost);
  469.       a++;
  470.     }
  471.   }
  472.   else if (totty) {
  473.     if ((a < argc) && (*argv[a] == '@'))
  474.       strcpy(si.tohost,argv[a++]+1);
  475.     else
  476.       strcpy(si.tohost,localhost);
  477.   }
  478.   else if (*argv[a] != '@') { /* broadcast */
  479.     printf("You must indicate '@host' for a broadcast\n");
  480.     exit(1);
  481.   }
  482.   else {
  483.     strcpy(si.taddr,argv[a++]);
  484.     (void) striphost(si.taddr,si.tohost);
  485.   }
  486.  
  487.   if (a < argc) {
  488.  
  489.     /* command line mode
  490.      */
  491.  
  492.     strcpy(&si.msg[0],sig); /* copy signature into message area */
  493.     for (; a < argc; a++) {
  494.       strcat(si.msg,argv[a]);
  495.       if (a != argc-1)
  496.         strcat(si.msg," ");
  497.     }
  498.     si.fwdcount= 0;
  499.     sendmessage(&si,&ri,SM_CLOSE|broadcast|totty);
  500.     if (ri.h.errno != RE_OK)
  501.       printf("%s\n",ri.msg);
  502.     exit(0);
  503.   }
  504.  
  505.   /* make initial connection to see if we can
  506.    */
  507.  
  508.   si.msg[0]= '\0';
  509.   sendmessage(&si,&ri,0);
  510.   if (ri.h.errno != RE_OK) {
  511.     printf("%s\n",ri.msg);
  512.     exit(1);
  513.   }
  514.  
  515.   strcpy(&si.msg[0],sig); /* copy signature into message area */
  516.  
  517.   for (;;) {
  518.     int once = 0;
  519. #ifdef GNUREADLINE
  520.     if (!edit) {
  521. #endif
  522.       printf("msend>");
  523.       if (fgets(&si.msg[strlen(sig)],MAXMSG-strlen(sig),stdin) == NULL) {
  524.     printf("^D\n");                       /* EOF */
  525.     si.msg[0]= '\0';                      /* send null message to close */
  526.     sendmessage(&si,&ri,SM_CLOSE);        /* the connection */
  527.     exit(0);
  528.       }
  529. #ifdef GNUREADLINE
  530.     } else {
  531.       rl_bind_key('\t',rl_insert); /* The default is "complete" */
  532.       bzero(&si.msg[strlen(sig)],MAXMSG-strlen(sig));
  533.       if((gnubuf = GNUGets("msend>")) == NULL) {
  534.     printf("^D\n");                       /* EOF */
  535.     si.msg[0]= '\0';                      /* send null message to close */
  536.     sendmessage(&si,&ri,SM_CLOSE);        /* the connection */
  537.     exit(0);
  538.       } else  {
  539.     strncpy(&si.msg[strlen(sig)],gnubuf,MAXMSG-strlen(sig)-1);
  540.     free(gnubuf);
  541.       }
  542.     }
  543. #endif
  544.     
  545.     alarm(LIFETIME);                         /* reset idle out timer */
  546. #ifdef GNUREADLINE
  547.     if (!edit)
  548. #endif
  549.       si.msg[strlen(si.msg)-1]= '\0';          /* strip newline */
  550.  
  551.     if (!strcmp(&si.msg[strlen(sig)],".")) { /* exit command */
  552.       si.msg[0]= '\0';
  553.       sendmessage(&si,&ri,SM_CLOSE);
  554.       exit(0);
  555.     }
  556.       
  557.     if (si.msg[strlen(sig)] != '\0') {
  558.       si.fwdcount= 0;
  559.       sendmessage(&si,&ri,broadcast|totty);
  560.       switch (ri.h.errno) {
  561.         case RE_OK :
  562.           break;
  563.     case RE_NOTFATAL:
  564.           printf("%s\n",ri.msg);
  565.       break;
  566.         default :
  567.           printf("%s\n",ri.msg);
  568.           exit(1);               /* connection is already broken */
  569.       }
  570.     }
  571.     if (!once) {
  572.       /* This is some code to strip off the domain name of the host 
  573.        * after we have sent one message.  It works because we know the 
  574.        * signature is in the form "<user>@<host><SPACE>...".  If that 
  575.        * format changes this will break...
  576.        */
  577.       int i,j;
  578.       once++;
  579.       for (i = 0; sig[i] != ' '; i++) {
  580.     if (sig[i] == '.') {
  581.       for (j = i+1; sig[j] != ' '; j++);
  582.       strcpy(&sig[i],&sig[j]);
  583.       strcpy(&si.msg[0],sig); /* copy signature into message area */
  584.       break;
  585.     }
  586.       }
  587.     }    
  588.   }
  589. }
  590.  
  591.