home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 May / PCW596.iso / wtest / clico / sunsoft / pcnfs51 / src / rfcmsg.taz / rfcmsg / msgclnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-27  |  16.6 KB  |  718 lines

  1. /* RE_SID: @(%)/usr/re/builds/pcnfs/unix/rfcmsg/SCCS/s.msgclnt.c 1.7 93/08/20 16:12:35 SMI */
  2. /* @(#)msgclnt.c    1.7 8/20/93 */
  3. /*
  4.  * msgclnt.c
  5.  *
  6.  * Copyright (c) 1991-1993 Sun Microsystems, Inc. 
  7.  *
  8.  * This is a client implementation of the Message Send protocol
  9.  * defined in RFCxxxx. This implementation may be freely
  10.  * copied, modified, and redistributed, provided that this
  11.  * comment and the Sun Microsystems copyright are retained.
  12.  * Anyone installing, modifying, or documenting this
  13.  * software is advised to read the section in the RFC which
  14.  * deals with security issues.
  15.  */
  16. #include <sys/types.h>
  17. #include <sys/time.h>
  18. #ifdef SVR4
  19. #include <sys/select.h>
  20. #include <memory.h>
  21. #define bcopy(from, to, howmuch)    memcpy(to, from, howmuch)
  22. #endif
  23. #include <sys/socket.h>
  24. #include <sys/sockio.h>
  25. #include <netinet/in.h>
  26. #include <net/if.h>
  27. #include <arpa/inet.h>
  28. #include <netdb.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32. #include <time.h>
  33.  
  34. char *prog;            /* points to program name for messages */
  35. int debug = 0;
  36. int verbose = 0;
  37. char *empty_arg = "";        /* used to encode an empty message part */
  38.  
  39. int msg_len = 0;        /* the cumulative length of the message */
  40. char msg[1024];            /* message assembly buffer */
  41.  
  42. /*
  43.  * types for all procedures. for ANSI standard C, these should
  44.  * be edited into full-blown prototypes.
  45.  */
  46. void usage();
  47. int main();
  48. void assemble_message();
  49. void do_line();
  50. void tcp_msg();
  51. void udp_msg();
  52. void broadcast_msg();
  53. void find_broadcast_addresses();
  54. void filter();
  55.  
  56. extern char *getlogin();
  57. extern char *ttyname();
  58.  
  59.  
  60. void
  61. usage()
  62. {
  63.     fprintf(stderr, "usage: %s [-t][-d][-v][-rN][-pN] recipient ['message']\n", prog);
  64.     fprintf(stderr, "  -t    - use TCP; default is UDP. (ignored for broadcasts)\n");
  65.     fprintf(stderr, "  -d    - turn on debugging (implies -v)\n");
  66.     fprintf(stderr, "  -v    - verbose mode\n");
  67.     fprintf(stderr, "  -rN   - UDP retransmissions (default: 3)\n");
  68.     fprintf(stderr, "  -pN   - use port N (default: 18)\n");
  69.     fprintf(stderr, "  recipient may have any of the following forms:\n");
  70.     fprintf(stderr, "   user           - broadcast for user at any host\n");
  71.     fprintf(stderr, "   user@host      - directed to user at given host\n");
  72.     fprintf(stderr, "   @host          - default dest. at given host\n");
  73.     fprintf(stderr, "   @              - default dest. on all hosts\n");
  74.     fprintf(stderr, "   user:term@host - user logged in to term on host\n");
  75.     fprintf(stderr, "   :term@host     - specified terminal on host\n");
  76.     fprintf(stderr, "   :all@host      - all terminals on given host\n");
  77.     fprintf(stderr, "   :all           - all terminals on all hosts\n");
  78.     fprintf(stderr, "If there is no message argument, ");
  79.     fprintf(stderr, "the message is read from standard input.\n");
  80. }
  81.  
  82. int
  83. main(argc, argv)
  84. int argc;
  85. char *argv[];
  86. {
  87.  
  88.     int    use_tcp = 0;
  89.     int    retries = 3;
  90.     short port = 0;
  91.     int broadcasting = 0;
  92.  
  93.     char *recipient;
  94.     char *user;
  95.     char *term;
  96.     char *host;
  97.     char *msg_text;
  98.  
  99.     struct sockaddr_in sin;
  100.     struct servent *sp;
  101.     struct hostent *hp;
  102.     struct netent *np;
  103.  
  104.  
  105.     prog = *argv++;
  106.     argc--;
  107.  
  108.     /* process options:
  109.      * -d (debug)
  110.      * -t (use TCP)
  111.      * -rN (set retransmission count)
  112.      * -pN (use port N instead of 18)
  113.      */
  114.  
  115.     while(argc && *argv[0] == '-') {
  116.         (*argv)++;
  117.         switch (toupper(*argv[0])){
  118.             case 'D':
  119.                 debug++;
  120.                 verbose++;
  121.                 break;
  122.             case 'V':
  123.                 verbose++;
  124.                 break;
  125.             case 'T':
  126.                 use_tcp++;
  127.                 break;
  128.             case 'R':
  129.                 (*argv)++;
  130.                 retries = atoi(*argv);
  131.                 break;
  132.             case 'P':
  133.                 (*argv)++;
  134.                 port = atoi(*argv);
  135.                 break;
  136.             default:
  137.                 usage();
  138.                 exit(1);
  139.                 /*NOTREACHED*/
  140.         }
  141.         argv++;
  142.         argc--;
  143.     }
  144.     if((argc < 1) || (argc > 2)) {
  145.         usage();
  146.         exit(1);
  147.         /*NOTREACHED*/
  148.     }
  149.  
  150.     /*
  151.      * Rip apart the recipient field and set the user, term,
  152.      * and host pointers.
  153.      */
  154.     recipient = argv[0];
  155.  
  156.     msg_text = argc == 2 ? argv[1] : NULL;
  157.  
  158.     if(debug) printf("recipient is '%s'\n", recipient);
  159.  
  160.     host = strchr(recipient, '@');
  161.     if(host == NULL)
  162.         host = empty_arg;
  163.     else
  164.         *host++ = '\0';
  165.  
  166.     term = strchr(recipient, ':');
  167.     if(term == NULL)
  168.         term = empty_arg;
  169.     else
  170.         *term++ = '\0';
  171.     if(!strcmp(term, "all"))    /* external form is "all" */
  172.         strcpy(term, "*");        /* protocol uses "*" */
  173.  
  174.     user = recipient;
  175.  
  176.     if(debug) printf("user = '%s', term='%s', host = '%s'\n",
  177.         user, term, host);
  178.  
  179.     broadcasting = (host[0] == '\0');
  180.  
  181.     sin.sin_family = AF_INET;
  182.  
  183.     /*
  184.      * compute the port to use: consult /etc/services, but if not
  185.      * found use 18 (from the RFC). the -pN option overrides
  186.      */
  187.  
  188.     if(port == 0) {
  189.         sp = getservbyname("message", (use_tcp ? "tcp" : "udp"));
  190.         if(sp)
  191.             sin.sin_port = sp->s_port;
  192.         else
  193.             sin.sin_port = htons(18);    /* from the RFC */
  194.     }
  195.     else
  196.         sin.sin_port = htons(port);
  197.  
  198.  
  199.     if(debug) printf("using port %d\n", htons(sin.sin_port));
  200.  
  201.     /*
  202.      * check to see if we're broadcasting; if so, ignore use_tcp and
  203.      * build a broadcast address. otherwise build an address for
  204.      * the designated host
  205.      */
  206.  
  207.     if(broadcasting) {
  208.         if(use_tcp)
  209.             fprintf(stderr, "%s: broadcast requested, so -t is ignored\n", prog);
  210.         use_tcp = 0;
  211.     }
  212.     else {
  213.         hp = gethostbyname(host);
  214.         if(hp == NULL) {
  215.             /* XXX need to add stuff to handle dotted IP addresses */
  216.             fprintf(stderr, "%s: unknown host: %s\n", prog, host);
  217.             exit(2);
  218.         }
  219.         memcpy((char *)&sin.sin_addr, (char *)hp->h_addr, hp->h_length);
  220.     }
  221.  
  222.     /*
  223.      * now assemble the message. note that this procedure will only
  224.      * return if the assembly is successful
  225.      */
  226.     assemble_message(user, term, msg_text);
  227.  
  228.     /*
  229.      * if broadcast, invoke broadcast_msg
  230.      */
  231.     if(broadcasting) {
  232.         broadcast_msg(&sin, retries);
  233.         exit(0);
  234.         /*NOTREACHED*/
  235.     }
  236.  
  237.  
  238.     /*
  239.      * if requested, attempt to send message via TCP
  240.      */
  241.     if(use_tcp)
  242.         tcp_msg(&sin);
  243.     /*
  244.      * If tcp_msg returns, it means that it was unable to bind
  245.      * to the port on the server. In this case, revert to UDP.
  246.      */
  247.     udp_msg(&sin, retries);
  248.     exit(0);
  249. }
  250.  
  251. /*
  252.  * assemble_message assembles a complete message in the buffer
  253.  * msg and stores the length in msg_len. Note that, as defined
  254.  * by the RFC, the message buffer includes embedded nulls.
  255.  */
  256.  
  257. void
  258. assemble_message(user, term, msg_text)
  259. char *user;
  260. char *term;
  261. char *msg_text;
  262. {
  263.     char *cp;
  264.     int i;
  265.     int j;
  266.     char linebuff[256];
  267.     struct utmp *utp;
  268.     char *dp;
  269.  
  270.     cp = msg;
  271.  
  272.     *cp++ = 'B';    /* per RFC */
  273.     msg_len = 1;
  274.  
  275. #define APPEND(s)    {strcpy(cp, s); j = strlen(s); cp += j; *cp++ = '\0'; msg_len += j + 1; }
  276.  
  277.     filter(user);
  278.     APPEND(user);
  279.     filter(term);
  280.     APPEND(term);
  281.  
  282.     if (msg_text)
  283.         do_line(msg_text, &cp, &msg_len);
  284.     else {
  285.         while(gets(linebuff) != NULL) {
  286.             do_line(linebuff, &cp, &msg_len);
  287.         }
  288.     }
  289.     
  290.     *cp++ = '\0';
  291.     msg_len++;
  292.  
  293.     dp = getlogin();
  294.     if (dp == NULL) {
  295.         APPEND(empty_arg);
  296.     } else {
  297.         APPEND(dp);
  298.     }
  299.     if(debug) printf("sender username is '%s'\n", (dp ? dp : empty_arg));
  300.     dp = ttyname(2); /* check standard error */
  301.     if (dp == NULL) {
  302.         APPEND(empty_arg);
  303.     } else {
  304.         APPEND(dp);
  305.     }
  306.     if(debug) printf("sender terminal is '%s'\n", (dp ? dp : empty_arg));
  307.     
  308.     sprintf(linebuff, "%ld", time(NULL));
  309.     APPEND(linebuff);
  310.     if(debug) printf("cookie is '%s'\n", linebuff);
  311.  
  312.     /*
  313.      * In this version, we always generate an empty signature part
  314.      */
  315.     if(debug) printf("signature is '%s'\n", empty_arg);
  316.     APPEND(empty_arg);    /* null signature */
  317.  
  318.  
  319.     if(debug) printf("total message length is %d\n", msg_len);
  320.     if(msg_len > 512) {
  321.         fprintf(stderr, "%s: message (inc. control fields) exceeds 512 byte limit\n", prog);
  322.         exit(2);
  323.     }
  324. }
  325.  
  326. void
  327. do_line(linebuff, cpp, msg_lenp)
  328. char *linebuff;
  329. char **cpp;
  330. int *msg_lenp;
  331. {
  332.     int j;
  333.     char *cp = *cpp;
  334.     int msg_len = *msg_lenp;
  335.  
  336.     filter(linebuff);
  337.     j = strlen(linebuff);
  338.     if((msg_len + j) > (512-28-3)) {
  339.         fprintf(stderr, "%s: message (inc. control fields) exceeds 512 byte limit\n", prog);
  340.         exit(2);
  341.         /*NOTREACHED*/
  342.     }
  343.     strcpy(cp, linebuff);
  344.     cp += j;
  345.     *cp++ = '\015';
  346.     *cp++ = '\012';
  347.     msg_len += j + 2;
  348.  
  349.     *cpp = cp;
  350.     *msg_lenp = msg_len;
  351. }
  352.  
  353. /*
  354.  * tcp_msg(sp)
  355.  *      sp points at a sockaddr_in which contains the
  356.  *      port to be used.
  357.  *
  358.  * Send the assembled message using TCP. If the attempt is
  359.  * successful, the program exits with a status of 0. If a client-
  360.  * side error occurs (e.g. unable to open a socket) the program
  361.  * exits with a positive non-zero status. If it proves impossible
  362.  * to connect to the server, an error message is displayed and
  363.  * the procedure returns. This allows the caller to retry using
  364.  * UDP.
  365.  */
  366.      
  367. void
  368. tcp_msg (sp)
  369. struct sockaddr_in *sp;
  370.  
  371. {
  372.     int    s;
  373.     int on = 1;
  374.     struct sockaddr_in sin;
  375.     char rcvbuf[256];
  376.     int rval;
  377.  
  378. if(debug) printf("invoked tcp_msg()\n");
  379.  
  380.     if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  381.         fprintf(stderr, "%s: unable to open socket.\n", prog);
  382.         perror("Reason");
  383.         exit(3);
  384.     }
  385.  
  386.     sin.sin_family = AF_INET;
  387.     sin.sin_addr.s_addr = htonl(INADDR_ANY);
  388.     sin.sin_port = htons(0);
  389.  
  390.     if(bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
  391.         fprintf(stderr, "%s: unable to set local socket address.\n", prog);
  392.         perror("Reason");
  393.         exit(3);
  394.     }
  395.  
  396.     if(connect(s, (struct sockaddr *)sp, sizeof (*sp)) < 0) {
  397.         fprintf(stderr, "%s: unable to connect to TCP server.\n", 
  398.             prog);
  399.         perror("Reason");
  400.         return;
  401.         /*NOTREACHED*/
  402.     }
  403.  
  404.     if(verbose)
  405.         printf("sending message...\n");
  406.     if(write(s, msg, msg_len) < 0) {
  407.         fprintf(stderr, "%s: unable to send message.\n", prog);
  408.         perror("Reason");
  409.         exit(3);
  410.     }
  411.         /*
  412.          * wait for reply
  413.          */
  414.     rval = read(s, rcvbuf, 256);
  415.     if(rval < 1) {
  416.         fprintf(stderr, "%s: no reply received.\n", prog);
  417.         perror("Reason");
  418.         exit(3);
  419.     }
  420.     rcvbuf[rval] = '\0';
  421.     if(debug) printf("reply:'%s'\n", rcvbuf);
  422.     if(rcvbuf[0] == '+') {
  423.         if(verbose) printf("message delivered to recipient\n");
  424.         exit(0);
  425.         /*NOTREACHED*/
  426.     } else {
  427.         if(verbose) printf("message not delivered\n");
  428.         exit(5);
  429.         /*NOTREACHED*/
  430.     }
  431. }
  432.  
  433. /*
  434.  * udp_msg(sp, r)
  435.  *      sp points at a sockaddr_in which contains the
  436.  *      port to be used.
  437.  *      r is the retry count to be used.
  438.  *
  439.  * Send the assembled message to a specific destination using UDP.
  440.  * This procedure will never return - it always exits with an
  441.  * appropriate status code.
  442.  */
  443.  
  444. void
  445. udp_msg (sp, r)
  446. struct sockaddr_in *sp;
  447. int r;
  448.  
  449. {
  450.     int    s;
  451.     int on = 1;
  452.     struct sockaddr_in sin;
  453.     fd_set ready;
  454.     struct timeval to;
  455.     char rcvbuf[256];
  456.     int rval;
  457.  
  458. if(debug) printf("invoked udp_msg(...,%d)\n", r);
  459.  
  460.     if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  461.         fprintf(stderr, "%s: unable to open socket.\n", prog);
  462.         perror("Reason");
  463.         exit(3);
  464.     }
  465.  
  466.     sin.sin_family = AF_INET;
  467.     sin.sin_addr.s_addr = htonl(INADDR_ANY);
  468.     sin.sin_port = htons(0);
  469.  
  470.     if(bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
  471.         fprintf(stderr, "%s: unable to set local socket address.\n", prog);
  472.         perror("Reason");
  473.         exit(3);
  474.     }
  475.     while(r--) {
  476.         if(verbose)
  477.             printf("sending message...\n");
  478.         if(sendto(s, msg, msg_len, 0, (struct sockaddr *)sp, sizeof(*sp)) < 0) {
  479.             fprintf(stderr, "%s: unable to send message.\n", prog);
  480.             perror("Reason");
  481.             exit(3);
  482.         }
  483.         if(r) {
  484.             /*
  485.              * wait for reply or timeout
  486.              */
  487.             to.tv_sec = 2;
  488.             to.tv_usec = 0;
  489.             FD_ZERO(&ready);
  490.             FD_SET(s, &ready);
  491.             rval = select(20, &ready, (fd_set *)0, (fd_set *)0, &to);
  492.             if(rval < 0)
  493.                  fprintf(stderr, "%s: interrupt\n", prog);
  494.             if(rval == 1) {
  495.             /* XXX to do  : read and decode result */
  496.                 if(verbose)
  497.                     printf("%s: message receipt acknowledgement received\n", prog);
  498.                 break;
  499.             }
  500.             /*
  501.              * falling through, must be interrupt or timeout
  502.              */
  503.         }
  504.     }
  505.     if(debug) printf("closing and exiting\n");
  506.     close(s);
  507.     exit(0);
  508.     /*NOTREACHED*/
  509. }
  510.  
  511. /*
  512.  * find_broadcast_addresses
  513.  *
  514.  * This procedure is used by broadcast_msg to determine all of the
  515.  * network interfaces configred on the local system, so that the
  516.  * message can be broadcast over each of them. This logic is derived
  517.  * from the SunOS documentation, and has also been tested on SVR4:
  518.  * anyone porting this program to significantly different systems
  519.  * should check this area carefully.
  520.  *
  521.  * The procedure uses the SIOCGIFCONF ioctl to retrieve the
  522.  * interfaces. For each one, it retrieves the flags via SIOCGIFFLAGS.
  523.  * For a point-to-point interface, the peer address is fetched using
  524.  * SIOCGIFDSTADDR. For a broadcast inteface, the broadcast address
  525.  * is obtained using SIOCGIFBRDADDR. The addresses are accumulated
  526.  * in the array if_a, and if_n holds the count of addresses found.
  527.  */
  528.  
  529. #define INTERFACES 32
  530. int if_n;
  531. struct sockaddr_in if_a[INTERFACES];
  532.  
  533. void
  534. find_broadcast_addresses(s)
  535. int s;
  536. {
  537.     struct ifconf ifc;
  538.     struct ifreq *ifr;
  539.     char buf[4096];
  540.     int n;
  541.  
  542.     if_n = 0;
  543.  
  544.     ifc.ifc_len = sizeof buf;
  545.     ifc.ifc_buf = buf;
  546.  
  547.     if(ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
  548.         fprintf(stderr, "%s: SIOCGIFCONF failed.\n", prog);
  549.         perror("Reason");
  550.         exit(3);
  551.     }
  552.     ifr = ifc.ifc_req;
  553.     n = ifc.ifc_len/sizeof(struct ifreq);
  554.     if(debug)
  555.         printf("checking %d interfaces returned by SIOCGIFCONF...\n",
  556.             n);
  557.  
  558.     for (; --n >= 0; ifr++) {
  559.         if(ifr->ifr_addr.sa_family != AF_INET)
  560.             continue;
  561.         if(ioctl(s, SIOCGIFFLAGS, (char *)ifr) < 0){
  562.             perror("SIOCGIFFLAGS");
  563.             continue;
  564.         }
  565.         if((ifr->ifr_flags & IFF_UP) == 0 ||
  566.            (ifr->ifr_flags & IFF_LOOPBACK) ||
  567.            (ifr->ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
  568.             continue;
  569.         if(ifr->ifr_flags & IFF_POINTOPOINT) {
  570.             if(ioctl(s, SIOCGIFDSTADDR, (char *)ifr) < 0) {
  571.                 perror("SIOCGIFDSTADDR");
  572.                 continue;
  573.             }
  574.             bcopy((char *)&ifr->ifr_dstaddr, (char *)&if_a[if_n++],
  575.                 sizeof ifr->ifr_dstaddr);
  576.         } else if(ifr->ifr_flags & IFF_BROADCAST) {
  577.             if(ioctl(s, SIOCGIFBRDADDR, (char *)ifr) < 0) {
  578.                 perror("SIOCGIFBRDADDR");
  579.                 continue;
  580.             }
  581.             bcopy((char *)&ifr->ifr_broadaddr, (char *)&if_a[if_n++],
  582.                 sizeof ifr->ifr_broadaddr);
  583.         }
  584.     }
  585.     if(debug)
  586.         printf("found %d interfaces\n", if_n);    
  587.     if(if_n == 0) {
  588.         fprintf(stderr, "%s: no applicable network interfaces\n", prog);
  589.         exit(3);
  590.         /*NOTREACHED*/
  591.     } 
  592. }
  593.  
  594. /*
  595.  * broadcast_msg(sp, r)
  596.  *      sp points at a sockaddr_in which contains the
  597.  *      port to be used.
  598.  *      r is the retry count to be used.
  599.  *
  600.  * Broadcast the message 'r' times over all network interfaces.
  601.  * This procedure never returns: it will eventually exit with a suitable
  602.  * status code. Broadcasts are sent at intervals of 2 seconds.
  603.  * (It might be advisable to make this parameter adjustable.)
  604.  *
  605.  * Normally a broadcast message will not elicit a reply. However
  606.  * if it does, we assume that we've reached the right destination
  607.  * and we quit without further ado.
  608.  */
  609.  
  610. void
  611. broadcast_msg (sp, r)
  612. struct sockaddr_in *sp;
  613. int r;
  614.  
  615. {
  616.     int    s;
  617.     int on = 1;
  618.     struct sockaddr_in sin;
  619.     fd_set ready;
  620.     struct timeval to;
  621.     char rcvbuf[256];
  622.     int rval;
  623.     int i;
  624.  
  625. if(debug) printf("invoked broadcast_msg(...,%d)\n", r);
  626.  
  627.     if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  628.         fprintf(stderr, "%s: unable to open socket.\n", prog);
  629.         perror("Reason");
  630.         exit(3);
  631.     }
  632.  
  633.     i = 1;
  634.     if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof i) < 0) {
  635.         fprintf(stderr, "%s: unable to configure socket for broadcast.\n", prog);
  636.         perror("Reason");
  637.         exit(3);
  638.     }
  639.  
  640.     find_broadcast_addresses(s);
  641.  
  642.     sin.sin_family = AF_INET;
  643.     sin.sin_addr.s_addr = htonl(INADDR_ANY);
  644.     sin.sin_port = htons(0);
  645.  
  646.     if(bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
  647.         fprintf(stderr, "%s: unable to set local socket address.\n", prog);
  648.         perror("Reason");
  649.         exit(3);
  650.     }
  651.     while(r--) {
  652.         for (i = 0; i < if_n; i++){
  653.             if_a[i].sin_port = sp->sin_port;
  654.             if(verbose) printf("sending message to %s\n",
  655.                 inet_ntoa(if_a[i].sin_addr));
  656.             if(sendto(s, msg, msg_len, 0
  657.             , (struct sockaddr *)&(if_a[i]), sizeof if_a[i]) < 0) {
  658.                 fprintf(stderr, "%s: unable to send message.\n", prog);
  659.                 perror("Reason");
  660.                 exit(3);
  661.             }
  662.         }
  663.         if(r) {
  664.             /*
  665.              * wait for reply or timeout
  666.              */
  667.             to.tv_sec = 2;
  668.             to.tv_usec = 0;
  669.             FD_ZERO(&ready);
  670.             FD_SET(s, &ready);
  671.             rval = select(20, &ready, (fd_set *)0, (fd_set *)0, &to);
  672.             if(rval < 0)
  673.                  fprintf(stderr, "%s: interrupt\n", prog);
  674.             if(rval == 1) {
  675.             /* XXX to do  : read and decode result */
  676.                 if(verbose)
  677.                     printf("%s: message receipt acknowledgement received\n", prog);
  678.                 break;
  679.             }
  680.             /*
  681.              * falling through, must be interrupt or timeout
  682.              */
  683.         }
  684.     }
  685.     if(debug) printf("closing and exiting\n");
  686.     close(s);
  687.     exit(0);
  688.     /*NOTREACHED*/
  689. }
  690.  
  691. /*
  692.  * As noted in the RFC, it is important to filter out control
  693.  * chracters and suchlike, since there may exist terminals
  694.  * which will behave in bizarre and security-violating ways
  695.  * if presented with certain control code sequences. The
  696.  * server will also be filtering messages, but it is incumbent
  697.  * upon a well-written client implementation to send only "clean"
  698.  * messages. After all, there may exist servers which will reject
  699.  * any message which does not filter cleanly.
  700.  *
  701.  * It is an open question as to how the filtering should be done.
  702.  * One approach might be to squeeze out any invalid characters
  703.  * silently. This would make debugging difficult. This implementation
  704.  * replaces all non-printable characters with '?' characters.
  705.  */
  706.  
  707. void
  708. filter(text)
  709. char *text;
  710. {
  711.     while (*text) {
  712.         if(!isprint(*text) && !isspace(*text))
  713.             *text = '?';
  714.         text++;
  715.     }
  716. }
  717.  
  718.