home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NNTP-1.000 / NNTP-1 / nntp.1.5.11t / common / clientlib.c next >
Encoding:
C/C++ Source or Header  |  1993-10-17  |  13.7 KB  |  636 lines

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