/* cmd-tn.c */ /* Copyright 1998 by Eberhard Mattes Donated to the public domain. No warranty. Version 0.1 1998-01-31 Initial version Version 0.2 1998-03-16 Don't use quotes if clearly unnecessary */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef INADDR_NONE #define INADDR_NONE (in_addr_t) -1 #endif static int fd; static int output_count; static char output_buffer[1024]; static void output_flush (void) { if (output_count != 0) { int nwritten = write (fd, output_buffer, output_count); if (nwritten == -1) { perror ("write()"); exit (2); } if (nwritten != output_count) { fputs ("write(): short write\n", stderr); exit (2); } output_count = 0; } } static void output (const void *s, int n) { int i; const char *p = (const char *)s; while (n > 0) { if (output_count == sizeof (output_buffer)) output_flush (); i = sizeof (output_buffer) - output_count; if (n < i) i = n; memcpy (output_buffer + output_count, p, i); output_count += i; p += i; n -= i; } } static void output_word (const char *s) { const unsigned char *t; int quote = 0; for (t = (const unsigned char *)s; *t != 0; ++t) { if (!isspace (*t) && !isprint (*t)) { fputs ("Sorry, unprintable characters are not supported.\n", stderr); exit (2); } if (isspace (*t) || *t == '"' || *t == '\'') quote = 1; } output (" \"", quote ? 2 : 1); for (t = (const unsigned char *)s; *t != 0; ++t) { if (*t == '"' || *t == '\\') output ("\\", 1); output (t, 1); } if (quote) output ("\"", 1); } static void server_syntax (void) { fputs ("Incorrect syntax in CMDGWSERVER, expected: host:port\n", stderr); exit (1); } static int dot_count (const char *s) { int n = 0; while (*s != 0) if (*s++ == '.') ++n; return n; } static void open_connection (void) { static char buffer[512]; static struct sockaddr_in sad; const char *server = getenv ("CMDGWSERVER"); const char *colon; char *end; long port; unsigned long ip; if (server == NULL || *server == 0) { fputs ("Environment variable CMDGWSERVER is not set\n", stderr); exit (2); } colon = strchr (server, ':'); if (colon == NULL || colon == server || colon - server >= sizeof (buffer)) server_syntax (); port = strtol (colon + 1, &end, 10); if (port < 1 || port > 65535 || *end != 0) server_syntax (); memcpy (buffer, server, colon - server); buffer[colon-server] = 0; memset (&sad, 0, sizeof (sad)); sad.sin_port = htons ((int)port); sad.sin_family = AF_INET; ip = inet_addr (buffer); if (ip != INADDR_NONE && dot_count (buffer) == 3) sad.sin_addr.s_addr = ip; else { struct hostent *host = gethostbyname (buffer); if (host == NULL) { herror ("gethostbyname()"); exit (1); } /* TODO: try all IP addresses. */ if (host->h_length != 4 || host->h_addrtype != AF_INET) memcpy (&sad.sin_addr, host->h_addr, host->h_length); } fd = socket (AF_INET, SOCK_STREAM, 0); if (fd == -1) { perror ("socket()"); exit (2); } if (connect (fd, (struct sockaddr *)&sad, sizeof (sad)) != 0) { perror ("connect()"); exit (2); } } static void copy_output (void) { FILE *f = fdopen (fd, "r"); int c, lines; if (f == NULL) { perror ("fdopen()"); exit (2); } lines = 0; /* Ignore first two lines (banner & command) */ while ((c = getc (f)) != EOF) { if (c == IAC) { c = getc (f); if (c == EOF) break; if (c != IAC) { if (c == DO || c == DONT || c == WILL || c == WONT) { c = getc (f); if (c == EOF) break; } continue; } } if (c == '\r') { c = getc (f); if (c == EOF) break; /* We don't care about dropping the CR */ if (c != '\n' && lines == 2) putchar ('\r'); } if (lines == 2 && putchar (c) == EOF) break; if (c == '\n' && lines < 2) ++lines; } if (ferror (f)) { perror ("read()"); exit (2); } if (ferror (stdout) || fflush (stdout) != 0) { perror ("stdout"); exit (2); } fclose (f); } int main (int argc, char *argv[]) { int i; if (argc < 2 || strcmp (argv[1], "-help") == 0 || strcmp (argv[1], "-?") == 0 || strcmp (argv[1], "--help") == 0) { fprintf (stderr, "Usage: %s [...]\n", argv[0]); fprintf (stderr, "Example: %s help\n", argv[0]); exit (1); } open_connection (); output_word ("once"); for (i = 1; i < argc; ++i) output_word (argv[i]); output ("\r\n", 2); /* TODO: use octal */ output_flush (); copy_output (); return 0; /* The termination code is not transmitted */ }