/*-
 * Copyright (c) 2000 Russell Vincent
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

/*
 * Program to connect to a news server and execute commands and optionally
 * report on the performance handling the commands
*/

#include "defs.h"

int verbose = 0;
char *hostname;
int s;
struct timeval connectstart;
struct timeval connectend;
struct timeval commandstart;
struct timeval commandend;
struct timeval totaltime;
FILE *fp;
char line[512];
int response;
int numarts;
int lowmark;
int highmark;

void
usage(char *progname) {
    printf("Usage: %s [-f filename] [-p port] [-v] hostname [command]\n\n", progname);
    printf(" Execute a command on an NNTP server and write output to stdout\n");
    printf(" If no command is specified then read commands from STDIN\n\n");
    printf("\t-f file = read NNTP commands from a file and send them to server\n");
    printf("\t-v      = be more verbose in output\n");
    printf("\t-p port = specify the remote port (default: 119)\n");
    exit(1);
}

void
connectnews(char *hostname, char *port) {
    struct hostent *hp;
    struct servent *sp;
    struct sockaddr_in sin;
    char line[512];

    if ((hp = gethostbyname(hostname)) != NULL) {
	memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
    } else {
	perror("gethostbyname");
	exit(1);
    }
    if ((sin.sin_port = atoi(port)) == 0) {
	if (!(sp = getservbyname(port, "tcp"))) {
	    perror("getservbyname");
	    exit(1);
	}
	sin.sin_port = sp->s_port;
    }
    sin.sin_port = htons(sin.sin_port);
    sin.sin_family = AF_INET;
    if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
	perror("socket");
	exit(1);
    }

    gettimeofday(&connectstart, NULL);
    if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
	perror("connect");
	exit(1);
    }
    if ((fp = fdopen(s, "r+")) == NULL) {
	perror("fdopen");
	exit(1);
    }
    fgets((char *)&line, 512, fp);
    if (verbose)
	printf("%s", line);
    if (strncmp(line, "200 ", 4) != 0 && strncmp(line, "201 ", 4) != 0) {
	printf("Unexpected response from server: %s", line);
	exit(2);
    }
}

void
newscommand(char *command) {
    char line[MAXLINE];
    char inp[MAXLINE];

    if (verbose)
	printf(">>%s\r\n", command ? command : "STDIN");

    while (command || fgets(inp, sizeof(inp), stdin) != NULL) {
	if (command)
	    fprintf(fp, "%s\r\n", command);
	else
	    fprintf(fp, "%s\r\n", inp);
	while (fgets(line, MAXLINE, fp) != NULL) {
	    printf("%s", line);
	    if (strncmp(line, ".\r\n", 3) == 0)
		break;
	}
	if (command)
	    break;
    }
}

void
dodumpfile(char *filename)
{
    FILE *f;
    char line[MAXLINE];

    if ((f = fopen(filename, "r")) == NULL) {
	printf("Unable to open %s\n", filename);
	exit(1);    
    }
    while (fgets(line, sizeof(line), f) != NULL) {
	fprintf(fp, "%s", line);
    }
    fclose(f);
}

void
newsquit(void) {
    char line[512];

    fprintf(fp,"QUIT\r\n");

    fgets((char *)&line, 512, fp);
    if (verbose)
	printf("%s", line);
    if (strncmp(line, "205 ", 4) != 0 && strncmp(line, "238 ", 4) != 0) {
	printf("Unexpected response from server: %s", line);
	exit(2);
    }
}

int
main(int argc, char **argv) {
    extern char *optarg;
    extern int optind;
    char ch;
    char *progname;
    char *port = "119";
    char *command;
    char *dumpfile = NULL;

    progname = *argv;

    optind = 1;
    while ((ch = getopt(argc, argv, "f:p:Vv")) != -1) {
	switch(ch) {
	    case 'f':
		dumpfile = optarg;
		break;
	    case 'p':
		port  = optarg;
		break;
	    case 'V':
		PrintVersion();
		break;
	    case 'v':
		verbose = 1;
		break;
	    default:
		usage(argv[0]);
	}
    }

    argv += optind;
    if (*argv == NULL)
	usage(progname);
    hostname = *argv++;
    if (*argv != NULL)
	command = *argv++;
    else
	command = NULL;

    connectnews(hostname, port);
    gettimeofday(&connectend, NULL);

    gettimeofday(&commandstart, NULL);
    if (dumpfile != NULL)
	dodumpfile(dumpfile);
    else
	newscommand(command);
    gettimeofday(&commandend, NULL);

    newsquit();

    gettimeofday(&totaltime, NULL);

    if (verbose) {
    	printf("Connect time: %3.3f\n",
		(((connectend.tv_sec * 1000000.0) + connectend.tv_usec) -
		((connectstart.tv_sec * 1000000.0) + connectstart.tv_usec)) /
				1000000);
	printf("Elapsed time: %3.3f\n",
		(((totaltime.tv_sec * 1000000.0) + totaltime.tv_usec) -
		((connectstart.tv_sec * 1000000.0) + connectstart.tv_usec)) /
				1000000);
	printf("Command time: %3.3f\n",
		(((commandend.tv_sec * 1000000.0) + commandend.tv_usec) -
		((commandstart.tv_sec * 1000000.0) + commandstart.tv_usec)) /
				1000000);
    }
    exit(0);
}



syntax highlighted by Code2HTML, v. 0.9.1