home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / inews / clientlib.c next >
C/C++ Source or Header  |  1995-04-29  |  12KB  |  544 lines

  1. #ifndef lint
  2. static char    *sccsid = "@(#)clientlib.c    1.11    (Berkeley) 10/27/89";
  3. #endif
  4.  
  5. /*
  6.  * NNTP client routines.
  7.  */
  8.  
  9. /*
  10.  * Include configuration parameters only if we're made in the nntp tree.
  11.  */
  12.  
  13. #ifdef FOR_NN
  14. #include "conf.h"
  15. #endif
  16.  
  17. #ifdef NNTPSRC
  18. #include "../config.h"
  19. #endif NNTPSRC
  20.  
  21. #include <stdio.h>
  22. #ifndef FOR_NN
  23. #include <sys/types.h>
  24. #endif
  25. #include <sys/socket.h>
  26. #ifdef FOR_NN
  27. #if !defined(NETWORK_DATABASE) || defined(NETWORK_BYTE_ORDER)
  28. #include <netinet/in.h>
  29. #endif
  30. #else
  31. #include <netinet/in.h>
  32. #endif
  33. #ifndef EXCELAN
  34. # include <netdb.h>
  35. #endif not EXCELAN
  36.  
  37. #ifndef FOR_NN
  38. #ifdef USG
  39. # define    index    strchr
  40. # define        bcopy(a,b,c)   memcpy(b,a,c)
  41. # define        bzero(a,b)     memset(a,'\0',b)
  42. #endif USG
  43. #endif
  44.  
  45. #ifdef EXCELAN
  46. # define    IPPORT_NNTP    119
  47. #endif
  48.  
  49. #ifdef DECNET
  50. #include <netdnet/dn.h>
  51. #include <netdnet/dnetdb.h>
  52. #endif DECNET
  53.  
  54. #include "nntp.h"
  55.  
  56. FILE    *ser_rd_fp = NULL;
  57. FILE    *ser_wr_fp = NULL;
  58.  
  59. /*
  60.  * getserverbyfile    Get the name of a server from a named file.
  61.  *            Handle white space and comments.
  62.  *            Use NNTPSERVER environment variable if set.
  63.  *
  64.  *    Parameters:    "file" is the name of the file to read.
  65.  *
  66.  *    Returns:    Pointer to static data area containing the
  67.  *            first non-ws/comment line in the file.
  68.  *            NULL on error (or lack of entry in file).
  69.  *
  70.  *    Side effects:    None.
  71.  */
  72.  
  73. char *
  74. getserverbyfile(file)
  75. char    *file;
  76. {
  77.     register FILE    *fp;
  78.     register char    *cp;
  79.     static char    buf[256];
  80.     char        *index();
  81.     char        *getenv();
  82.     char        *strcpy();
  83.  
  84.     if (cp = getenv("NNTPSERVER")) {
  85.         (void) strcpy(buf, cp);
  86.         return (buf);
  87.     }
  88.  
  89.     if (file == NULL)
  90.         return (NULL);
  91.  
  92.     fp = fopen(file, "r");
  93.     if (fp == NULL)
  94.         return (NULL);
  95.  
  96.     while (fgets(buf, sizeof (buf), fp) != NULL) {
  97.         if (*buf == '\n' || *buf == '#')
  98.             continue;
  99.         cp = index(buf, '\n');
  100.         if (cp)
  101.             *cp = '\0';
  102.         (void) fclose(fp);
  103.         return (buf);
  104.     }
  105.  
  106.     (void) fclose(fp);
  107.     return (NULL);             /* No entry */
  108. }
  109.  
  110.  
  111. /*
  112.  * server_init  Get a connection to the remote news server.
  113.  *
  114.  *    Parameters:    "machine" is the machine to connect to.
  115.  *
  116.  *    Returns:    -1 on error
  117.  *            server's initial response code on success.
  118.  *
  119.  *    Side effects:    Connects to server.
  120.  *            "ser_rd_fp" and "ser_wr_fp" are fp's
  121.  *            for reading and writing to server.
  122.  */
  123.  
  124. server_init(machine)
  125. char    *machine;
  126. {
  127.     int    sockt_rd, sockt_wr;
  128.     char    line[256];
  129.     char    *index();
  130. #ifdef DECNET
  131.     char    *cp;
  132.  
  133.     cp = index(machine, ':');
  134.  
  135.     if (cp && cp[1] == ':') {
  136.         *cp = '\0';
  137.         sockt_rd = get_dnet_socket(machine);
  138.     } else
  139.         sockt_rd = get_tcp_socket(machine);
  140. #else
  141.     sockt_rd = get_tcp_socket(machine);
  142. #endif
  143.  
  144.     if (sockt_rd < 0)
  145.         return (-1);
  146.  
  147.     /*
  148.      * Now we'll make file pointers (i.e., buffered I/O) out of
  149.      * the socket file descriptor.  Note that we can't just
  150.      * open a fp for reading and writing -- we have to open
  151.      * up two separate fp's, one for reading, one for writing.
  152.      */
  153.  
  154.     if ((ser_rd_fp = fdopen(sockt_rd, "r")) == NULL) {
  155.         perror("server_init: fdopen #1");
  156.         return (-1);
  157.     }
  158.  
  159.     sockt_wr = dup(sockt_rd);
  160.     if ((ser_wr_fp = fdopen(sockt_wr, "w")) == NULL) {
  161.         perror("server_init: fdopen #2");
  162.         ser_rd_fp = NULL;        /* from above */
  163.         return (-1);
  164.     }
  165.  
  166.     /* Now get the server's signon message */
  167.  
  168.     (void) get_server(line, sizeof(line));
  169.     return (atoi(line));
  170. }
  171.  
  172.  
  173. /*
  174.  * get_tcp_socket -- get us a socket connected to the news server.
  175.  *
  176.  *    Parameters:    "machine" is the machine the server is running on.
  177.  *
  178.  *    Returns:    Socket connected to the news server if
  179.  *            all is ok, else -1 on error.
  180.  *
  181.  *    Side effects:    Connects to server.
  182.  *
  183.  *    Errors:        Printed via perror.
  184.  */
  185.  
  186. get_tcp_socket(machine)
  187. char    *machine;
  188. {
  189.     int    s;
  190.     struct    sockaddr_in sin;
  191. #ifndef EXCELAN
  192.     struct    servent *getservbyname(), *sp;
  193.     struct    hostent *gethostbyname(), *hp;
  194. #ifdef h_addr
  195.     int    x = 0;
  196.     register char **cp;
  197. #endif h_addr
  198.  
  199.     if ((sp = getservbyname("nntp", "tcp")) ==  NULL) {
  200.         fprintf(stderr, "nntp/tcp: Unknown service.\n");
  201.         return (-1);
  202.     }
  203.  
  204.        /*
  205.         * Name resolution doesn't quite go as far as it should.  Take things
  206.         * one stage further to allow nnn.nnn.nnn.nnn addresses if all else
  207.         * fails.
  208.         */
  209.        if( (hp = gethostbyname( machine ) ) == NULL ) {
  210.                unsigned long inet_addr();
  211.                static struct hostent def;
  212.                static struct in_addr defaddr;
  213.                static char *alist[1];
  214.                static char namebuf[ 256 ];
  215.                defaddr.s_addr = inet_addr( machine );
  216.                if( defaddr.s_addr != -1 ) {
  217.                        strcpy( namebuf, machine );
  218.                        def.h_name = namebuf;
  219. #ifdef h_addr
  220.                        def.h_addr_list = alist;
  221. #endif
  222.                        def.h_addr = (char *)&defaddr;
  223.                        def.h_length = sizeof( struct in_addr );
  224.                        def.h_addrtype = AF_INET;
  225.                        def.h_aliases = 0;
  226.                        hp = &def;
  227.                }
  228.        }
  229.        if (hp == NULL) {
  230.         fprintf(stderr, "%s: Unknown host.\n", machine);
  231.         return (-1);
  232.     }
  233.  
  234.     bzero((char *) &sin, sizeof(sin));
  235.     sin.sin_family = hp->h_addrtype;
  236.     sin.sin_port = sp->s_port;
  237. #else EXCELAN
  238.     bzero((char *) &sin, sizeof(sin));
  239.     sin.sin_family = AF_INET;
  240.     sin.sin_port = htons(IPPORT_NNTP);
  241. #endif EXCELAN
  242.  
  243.     /*
  244.      * The following is kinda gross.  The name server under 4.3
  245.      * returns a list of addresses, each of which should be tried
  246.      * in turn if the previous one fails.  However, 4.2 hostent
  247.      * structure doesn't have this list of addresses.
  248.      * Under 4.3, h_addr is a #define to h_addr_list[0].
  249.      * We use this to figure out whether to include the NS specific
  250.      * code...
  251.      */
  252.  
  253. #ifdef    h_addr
  254.  
  255.     /* get a socket and initiate connection -- use multiple addresses */
  256.  
  257.     for (cp = hp->h_addr_list; cp && *cp; cp++) {
  258.         s = socket(hp->h_addrtype, SOCK_STREAM, 0);
  259.         if (s < 0) {
  260.             perror("socket");
  261.             return (-1);
  262.         }
  263.             bcopy(*cp, (char *)&sin.sin_addr, hp->h_length);
  264.  
  265.         if (x < 0)
  266.             fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr));
  267.         while ((x = connect(s, (struct sockaddr *)&sin, sizeof (sin))) < 0 && errno == EINTR) sleep(1);
  268.         if (x == 0)
  269.             break;
  270.                 fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr));
  271.         perror("");
  272.         (void) close(s);
  273.     }
  274.     if (x < 0) {
  275.         fprintf(stderr, "giving up...\n");
  276.         return (-1);
  277.     }
  278. #else    /* no name server */
  279. #ifdef EXCELAN
  280.     if ((s = rresvport(SO_KEEPALIVE)) < 0)
  281.     {
  282.         /* Get the socket */
  283.         perror("socket");
  284.         return (-1);
  285.     }
  286.     /* set up addr for the connect */
  287.     sin.sin_addr.s_addr = rhost(machine);
  288.     if (sin.sin_addr.s_addr < 0){
  289.         fprintf(stderr, "%s: Unknown host.\n", machine);
  290.         return (-1);
  291.     }
  292.     /* And then connect */
  293.  
  294.     if (connect(s, &sin) < 0) {
  295.         perror("connect");
  296.         (void) close(s);
  297.         return (-1);
  298.     }
  299. #else not EXCELAN
  300.     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  301.         perror("socket");
  302.         return (-1);
  303.     }
  304.  
  305.     /* And then connect */
  306.  
  307.     bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
  308.     while (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  309.         if (errno == EINTR) {
  310.             sleep(1);
  311.             continue;    /* try again */
  312.         }
  313.         perror("connect");
  314.         (void) close(s);
  315.         return (-1);
  316.     }
  317.  
  318. #endif not EXCELAN
  319. #endif
  320.  
  321.     return (s);
  322. }
  323.  
  324. #ifdef DECNET
  325. /*
  326.  * get_dnet_socket -- get us a socket connected to the news server.
  327.  *
  328.  *    Parameters:    "machine" is the machine the server is running on.
  329.  *
  330.  *    Returns:    Socket connected to the news server if
  331.  *            all is ok, else -1 on error.
  332.  *
  333.  *    Side effects:    Connects to server.
  334.  *
  335.  *    Errors:        Printed via nerror.
  336.  */
  337.  
  338. get_dnet_socket(machine)
  339. char    *machine;
  340. {
  341.     int    s, area, node;
  342.     struct    sockaddr_dn sdn;
  343.     struct    nodeent *getnodebyname(), *np;
  344.  
  345.     bzero((char *) &sdn, sizeof(sdn));
  346.  
  347.     switch (s = sscanf( machine, "%d%*[.]%d", &area, &node )) {
  348.         case 1:
  349.             node = area;
  350.             area = 0;
  351.         case 2:
  352.             node += area*1024;
  353.             sdn.sdn_add.a_len = 2;
  354.             sdn.sdn_family = AF_DECnet;
  355.             sdn.sdn_add.a_addr[0] = node % 256;
  356.             sdn.sdn_add.a_addr[1] = node / 256;
  357.             break;
  358.         default:
  359.             if ((np = getnodebyname(machine)) == NULL) {
  360.                 fprintf(stderr,
  361.                     "%s: Unknown host.\n", machine);
  362.                 return (-1);
  363.             } else {
  364.                 bcopy(np->n_addr,
  365.                     (char *) sdn.sdn_add.a_addr,
  366.                     np->n_length);
  367.                 sdn.sdn_add.a_len = np->n_length;
  368.                 sdn.sdn_family = np->n_addrtype;
  369.             }
  370.             break;
  371.     }
  372.     sdn.sdn_objnum = 0;
  373.     sdn.sdn_flags = 0;
  374.     sdn.sdn_objnamel = strlen("NNTP");
  375.     bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
  376.  
  377.     if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
  378.         nerror("socket");
  379.         return (-1);
  380.     }
  381.  
  382.     /* And then connect */
  383.  
  384.     while (connect(s, (struct sockaddr *) &sdn, sizeof(sdn)) < 0) {
  385.         if (errno == EINTR) {
  386.             sleep(1);
  387.             continue;    /* try again */
  388.         }
  389.         nerror("connect");
  390.         close(s);
  391.         return (-1);
  392.     }
  393.  
  394.     return (s);
  395. }
  396. #endif
  397.  
  398.  
  399.  
  400. /*
  401.  * handle_server_response
  402.  *
  403.  *    Print some informative messages based on the server's initial
  404.  *    response code.  This is here so inews, rn, etc. can share
  405.  *    the code.
  406.  *
  407.  *    Parameters:    "response" is the response code which the
  408.  *            server sent us, presumably from "server_init",
  409.  *            above.
  410.  *            "server" is the news server we got the
  411.  *            response code from.
  412.  *
  413.  *    Returns:    -1 if the error is fatal (and we should exit).
  414.  *            0 otherwise.
  415.  *
  416.  *    Side effects:    None.
  417.  */
  418.  
  419. handle_server_response(response, server)
  420. int    response;
  421. char    *server;
  422. {
  423.     switch (response) {
  424.     case OK_NOPOST:        /* fall through */
  425.             printf(
  426.     "NOTE: This machine does not have permission to post articles.\n");
  427.         printf(
  428.     "      Please don't waste your time trying.\n\n");
  429.  
  430.     case OK_CANPOST:
  431.         return (0);
  432.         break;
  433.  
  434.     case ERR_ACCESS:
  435.         printf(
  436.    "This machine does not have permission to use the %s news server.\n",
  437.         server);
  438.         return (-1);
  439.         break;
  440.  
  441.     default:
  442.         printf("Unexpected response code from %s news server: %d\n",
  443.             server, response);
  444.         return (-1);
  445.         break;
  446.     }
  447.     /*NOTREACHED*/
  448. }
  449.  
  450.  
  451. /*
  452.  * put_server -- send a line of text to the server, terminating it
  453.  * with CR and LF, as per ARPA standard.
  454.  *
  455.  *    Parameters:    "string" is the string to be sent to the
  456.  *            server.
  457.  *
  458.  *    Returns:    Nothing.
  459.  *
  460.  *    Side effects:    Talks to the server.
  461.  *
  462.  *    Note:        This routine flushes the buffer each time
  463.  *            it is called.  For large transmissions
  464.  *            (i.e., posting news) don't use it.  Instead,
  465.  *            do the fprintf's yourself, and then a final
  466.  *            fflush.
  467.  */
  468.  
  469. void
  470. put_server(string)
  471. char *string;
  472. {
  473. #ifdef DEBUG
  474.     fprintf(stderr, ">>> %s\n", string);
  475. #endif
  476.     fprintf(ser_wr_fp, "%s\r\n", string);
  477.     (void) fflush(ser_wr_fp);
  478. }
  479.  
  480.  
  481. /*
  482.  * get_server -- get a line of text from the server.  Strips
  483.  * CR's and LF's.
  484.  *
  485.  *    Parameters:    "string" has the buffer space for the
  486.  *            line received.
  487.  *            "size" is the size of the buffer.
  488.  *
  489.  *    Returns:    -1 on error, 0 otherwise.
  490.  *
  491.  *    Side effects:    Talks to server, changes contents of "string".
  492.  */
  493.  
  494. get_server(string, size)
  495. char    *string;
  496. int    size;
  497. {
  498.     register char *cp;
  499.     char    *index();
  500.  
  501.     if (fgets(string, size, ser_rd_fp) == NULL)
  502.         return (-1);
  503.  
  504.     if ((cp = index(string, '\r')) != NULL)
  505.         *cp = '\0';
  506.     else if ((cp = index(string, '\n')) != NULL)
  507.         *cp = '\0';
  508. #ifdef DEBUG
  509.     fprintf(stderr, "<<< %s\n", string);
  510. #endif
  511.  
  512.     return (0);
  513. }
  514.  
  515.  
  516. /*
  517.  * close_server -- close the connection to the server, after sending
  518.  *        the "quit" command.
  519.  *
  520.  *    Parameters:    None.
  521.  *
  522.  *    Returns:    Nothing.
  523.  *
  524.  *    Side effects:    Closes the connection with the server.
  525.  *            You can't use "put_server" or "get_server"
  526.  *            after this routine is called.
  527.  */
  528.  
  529. void
  530. close_server()
  531. {
  532.     char    ser_line[256];
  533.  
  534.     if (ser_wr_fp == NULL || ser_rd_fp == NULL)
  535.         return;
  536.  
  537.     put_server("QUIT");
  538.     (void) get_server(ser_line, sizeof(ser_line));
  539.  
  540.     (void) fclose(ser_wr_fp);
  541.     (void) fclose(ser_rd_fp);
  542. }
  543.  
  544.