#module NNTP_CLIENT "V5.5"

/*
**++
**  FACILITY:
**
**      NNTP_CLIENT
**
**  ABSTRACT:
**
**      Implementation of RFC977 client as an interactive program. This is
**      provided as an example of using the NNTP protocols. It is not
**      intended as a interactive user facility, but as an example program
**      which communicates with the remote server using NNTP.
**
**  AUTHOR:
**
**      Geoff Huston
**
**  COPYRIGHT:
**
**      Copyright © 1988
**
**  MODIFICATION HISTORY:
**
**      V5.5     7-Oct-1988     GIH
**          Included modifications for WIN TCP/IP V3.0 support by Jim Patterson
**          (jimp@cognos.uucp)
**          NOTE: I have NOT tested the WIN support modifications
**--
**/

#include ctype
#include descrip
#include iodef
#include ssdef
#include stdio

                                /* Add definition of WIN TCP modules */
#ifdef TWG
#include <types.h>
#include <socket.h>
#include <netdb.h>
#include <in.h>
#include <inetiodef.h>
#define NNTP_PORT       (119)
struct hostent dest_host
struct sockaddr_in data_socket = {0};
#endif

                        /* i/o channels, and status blocks */
unsigned short chan,
               net_chan;

unsigned int iosb[2],
             read_iosb[2];

                        /* input and output buffers */
char inpline[256],
     outl[1048],
     *nr_pos = outl;

                        /* system call return status */
int status,
    net_chan_tcp = 0;


int *c$_tmphead = 0;    /* head of side list */

int *c$alloc_tmp(size)
    int size;
{
    int *tmp;

    tmp = malloc(size + 4);
    *tmp = c$_tmphead;
    c$_tmphead = tmp;
    return(c$_tmphead + 1);
}

c$dsc(c$_str)
    char *c$_str;
{
    struct dsc$descriptor *c$_tmpdesc;

    c$_tmpdesc = c$alloc_tmp(8);
    c$_tmpdesc->dsc$w_length = strlen(c$_str);
    c$_tmpdesc->dsc$b_dtype = DSC$K_DTYPE_T;
    c$_tmpdesc->dsc$b_class = DSC$K_CLASS_S;
    c$_tmpdesc->dsc$a_pointer = c$_str;
    return(c$_tmpdesc);
}

c$cks(c$_status)
    int c$_status;
{
    int *c$_tmp;

    if (!(c$_status & 1)) lib$stop(c$_status);
    while (c$_tmphead) {
        c$_tmp = *c$_tmphead;
        free(c$_tmphead);
        c$_tmphead = c$_tmp;
        }
    return(c$_status);
}

/*
 *  read_complete
 *
 *  AST routine from tty read. Add crlf and call sync write to server
 *  object.  Re-establish outstanding async tty read call.
 */

read_complete()
{
    unsigned short *i_o_size;
    int i;

    i_o_size = iosb;
    if ((!(*(i_o_size + 1))) && (inpline[0] == 26)) {
        sys$cancel(net_chan);
        sys$qiow(0,net_chan,IO$_DELETE,0,0,0,0,0,0,0,0,0);
        sys$dassgn(net_chan);
        sys$dassgn(chan);
        sys$exit(1);
        }
    c$cks(*i_o_size);
    inpline[*(i_o_size + 1)] = '\0';
    strcat(inpline,"\r\n");
    c$cks(sys$qiow(0,net_chan,IO$_WRITEVBLK,iosb,0,0,
        inpline,strlen(inpline),0,net_chan_tcp,0,0));
    c$cks(*i_o_size);
    c$cks(sys$qio(0,chan,IO$_READVBLK,iosb,read_complete,0,
        inpline,132,0,0,0,0));
}

/*
 *  net_read
 *
 *  AST routine from net read - check on carriage control then write
 *  out to screen - add additional line feed if this is a break line.
 *  Recall outstanding async net read routine.
 */

net_read()
{
    unsigned short *i_o_size;
    char *cp,
         *il = outl;
    int bsize = 1024;

    i_o_size = read_iosb;
    c$cks(*i_o_size);
    nr_pos[*(i_o_size + 1)] = '\0';

    cp = il;
    while (cp) {
        if (cp = strchr(il,'\n')) *cp = '\0';
        if ((cp) && (*(cp - 1) == '\r')) *(cp - 1) = '\0';
        if (cp) {
            cp++;
            puts(il);
            if (!strcmp(il,".")) printf("\n");
            else if ((strlen(il) > 5) && isdigit(il[0]) && isdigit(il[1])
                     && isdigit(il[2]) && (il[3] == ' '))
                printf("\n");
            il = cp;
            }
        }
    cp = outl;
    while (*cp++ = *il++) --bsize;
    nr_pos = cp - 1;
    c$cks(sys$qio(0,net_chan,IO$_READVBLK,read_iosb,net_read,0,
        nr_pos,bsize,0,0,0,0));
}

/*
 *  main
 *
 *  Open channels to tty and decnet server. Request node name and channel
 *  protocol (DECNET or TCP). Call async readers (using ast completion
 *  routines), then sit back and wait for the asts to fire.
 */

main()
{
    char *c,
         newsserver[80],
         chan_type[80];
    short *ioptr = iosb;

    c$cks(sys$assign(c$dsc("TT:"),&chan,0,0));
    printf("Node: ");
    c$cks(sys$qiow(0,chan,IO$_READVBLK,iosb,0,0,inpline,80,0,0,0,0));
    c$cks(*ioptr);
    inpline[*(ioptr + 1)] = '\0';
    if (c = strchr(inpline,':')) *c = '\0';
#ifdef TWG
    printf("Channel (CMUTCP, WINTCP, or DECNET)? [DECNET]: ");
#else
    printf("Channel (TCP or DECNET)? [DECNET]: ");
#endif
    c$cks(sys$qiow(0,chan,IO$_READVBLK,iosb,0,0,chan_type,80,0,0,0,0));
    c$cks(*ioptr);
    chan_type[*(ioptr + 1)] = '\0';
    if ((*chan_type == 'T') || (*chan_type == 't') ||
        (*chan_type == 'C') || (*chan_type == 'c')) {
        net_chan_tcp = 1;
        c$cks(sys$assign(c$dsc("IP:"),&net_chan,0,0));
        c$cks(sys$qiow(0,net_chan,IO$_CREATE,iosb,0,0,inpline,119,0,1,0,300));
        if (!(*ioptr & 1)) {
            if (*ioptr == SS$_ABORT) lib$signal(iosb[1]);
            else lib$signal(*ioptr);
            }
        }
#ifdef TWG
    else if ((*chan_type == 'W') || (*chan_type == 'w')) {
        c$cks(sys$assign(c$dsc("INET:"),&net_chan,0,0));
        c$cks(sys$qiow(0,net_chan,IO$_SOCKET,iosb,0,0,
                AF_INET,SOCK_STREAM,0,0,0,0));
        dest_host = *gethostbyname(inpline);
        data_socket.sin_addr.s_addr = *((u_long *)dest_host.h_addr);
        data_socket.sin_family = AF_INET;
        data_socket.sin_port = htons(NNTP_PORT);
        c$cks(sys$qiow(0,net_chan,IO$_CONNECT,iosb,0,
                &data_socket,sizeof(data_socket),0,0,0,0));
        }
#endif
    else {
        sprintf(newsserver,"%s::\"TASK=NNTP\"",inpline);
        c$cks(sys$assign(c$dsc(newsserver),&net_chan,0,0));
        }

    c$cks(sys$qio(0,chan,IO$_READVBLK,iosb,read_complete,0,
        inpline,132,0,0,0,0));
    c$cks(sys$qio(0,net_chan,IO$_READVBLK,read_iosb,net_read,0,
        outl,1024,0,0,0,0));
    sys$hiber();
}
