* PLink - a command-line (stdin/stdout) variant of PuTTY.
*/
+#ifndef AUTO_WINSOCK
#include <winsock2.h>
+#endif
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
exit(1);
}
+static char *password = NULL;
+
+/*
+ * Stubs for linking with other modules.
+ */
+void write_clip (void *data, int len) { }
+void term_deselect(void) { }
+
HANDLE outhandle;
DWORD orig_console_mode;
HANDLE hin, hout;
DWORD savemode, i;
-#if 0 /* this allows specifying a password some other way */
if (password) {
static int tried_once = 0;
return 1;
}
}
-#endif
hin = GetStdHandle(STD_INPUT_HANDLE);
hout = GetStdHandle(STD_OUTPUT_HANDLE);
return 0;
}
+/*
+ * Short description of parameters.
+ */
+static void usage(void)
+{
+ printf("PuTTY Link: command-line connection utility\n");
+ printf("%s\n", ver);
+ printf("Usage: plink [options] [user@]host [command]\n");
+ printf("Options:\n");
+ printf(" -v show verbose messages\n");
+ printf(" -ssh force use of ssh protocol\n");
+ printf(" -P port connect to specified port\n");
+ printf(" -pw passw login with specified password\n");
+ exit(1);
+}
+
int main(int argc, char **argv) {
WSADATA wsadata;
WORD winsock_ver;
DWORD threadid;
struct input_data idata;
int sending;
+ int portnumber = -1;
ssh_get_password = get_password;
/*
* Process the command line.
*/
- default_protocol = DEFAULT_PROTOCOL;
- default_port = DEFAULT_PORT;
do_defaults(NULL);
+ default_protocol = cfg.protocol;
+ default_port = cfg.port;
+ {
+ /*
+ * Override the default protocol if PLINK_PROTOCOL is set.
+ */
+ char *p = getenv("PLINK_PROTOCOL");
+ int i;
+ if (p) {
+ for (i = 0; backends[i].backend != NULL; i++) {
+ if (!strcmp(backends[i].name, p)) {
+ default_protocol = cfg.protocol = backends[i].protocol;
+ default_port = cfg.port = backends[i].backend->default_port;
+ break;
+ }
+ }
+ }
+ }
while (--argc) {
char *p = *++argv;
if (*p == '-') {
if (!strcmp(p, "-ssh")) {
default_protocol = cfg.protocol = PROT_SSH;
default_port = cfg.port = 22;
+ } else if (!strcmp(p, "-telnet")) {
+ default_protocol = cfg.protocol = PROT_TELNET;
+ default_port = cfg.port = 23;
+ } else if (!strcmp(p, "-raw")) {
+ default_protocol = cfg.protocol = PROT_RAW;
} else if (!strcmp(p, "-v")) {
flags |= FLAG_VERBOSE;
} else if (!strcmp(p, "-log")) {
logfile = "putty.log";
- }
+ } else if (!strcmp(p, "-pw") && argc > 1) {
+ --argc, password = *++argv;
+ } else if (!strcmp(p, "-l") && argc > 1) {
+ char *username;
+ --argc, username = *++argv;
+ strncpy(cfg.username, username, sizeof(cfg.username));
+ cfg.username[sizeof(cfg.username)-1] = '\0';
+ } else if (!strcmp(p, "-P") && argc > 1) {
+ --argc, portnumber = atoi(*++argv);
+ }
} else if (*p) {
if (!*cfg.host) {
char *q = p;
strncpy (cfg.host, q, sizeof(cfg.host)-1);
cfg.host[sizeof(cfg.host)-1] = '\0';
} else {
+ char *r;
+ /*
+ * Before we process the [user@]host string, we
+ * first check for the presence of a protocol
+ * prefix (a protocol name followed by ",").
+ */
+ r = strchr(p, ',');
+ if (r) {
+ int i, j;
+ for (i = 0; backends[i].backend != NULL; i++) {
+ j = strlen(backends[i].name);
+ if (j == r-p &&
+ !memcmp(backends[i].name, p, j)) {
+ default_protocol = cfg.protocol = backends[i].protocol;
+ portnumber = backends[i].backend->default_port;
+ p = r+1;
+ break;
+ }
+ }
+ }
+
/*
* Three cases. Either (a) there's a nonzero
* length string followed by an @, in which
* string and it _doesn't_ exist in the
* database.
*/
- char *r = strrchr(p, '@');
+ r = strrchr(p, '@');
if (r == p) p++, r = NULL; /* discount initial @ */
if (r == NULL) {
/*
}
}
+ if (!*cfg.host) {
+ usage();
+ }
+
if (!*cfg.remote_cmd)
flags |= FLAG_INTERACTIVE;
}
/*
+ * Select port.
+ */
+ if (portnumber != -1)
+ cfg.port = portnumber;
+
+ /*
* Initialise WinSock.
*/
winsock_ver = MAKEWORD(2, 0);
sending = FALSE;
while (1) {
int n;
+
+ if (!sending && back->sendok()) {
+ /*
+ * Create a separate thread to read from stdin. This is
+ * a total pain, but I can't find another way to do it:
+ *
+ * - an overlapped ReadFile or ReadFileEx just doesn't
+ * happen; we get failure from ReadFileEx, and
+ * ReadFile blocks despite being given an OVERLAPPED
+ * structure. Perhaps we can't do overlapped reads
+ * on consoles. WHY THE HELL NOT?
+ *
+ * - WaitForMultipleObjects(netevent, console) doesn't
+ * work, because it signals the console when
+ * _anything_ happens, including mouse motions and
+ * other things that don't cause data to be readable
+ * - so we're back to ReadFile blocking.
+ */
+ idata.event = stdinevent;
+ if (!CreateThread(NULL, 0, stdin_read_thread,
+ &idata, 0, &threadid)) {
+ fprintf(stderr, "Unable to create second thread\n");
+ exit(1);
+ }
+ sending = TRUE;
+ }
+
n = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (n == 0) {
WSANETWORKEVENTS things;
}
}
term_out();
- if (!sending && back->sendok()) {
- /*
- * Create a separate thread to read from stdin.
- * This is a total pain, but I can't find another
- * way to do it:
- *
- * - an overlapped ReadFile or ReadFileEx just
- * doesn't happen; we get failure from
- * ReadFileEx, and ReadFile blocks despite being
- * given an OVERLAPPED structure. Perhaps we
- * can't do overlapped reads on consoles. WHY
- * THE HELL NOT?
- *
- * - WaitForMultipleObjects(netevent, console)
- * doesn't work, because it signals the console
- * when _anything_ happens, including mouse
- * motions and other things that don't cause
- * data to be readable - so we're back to
- * ReadFile blocking.
- */
- idata.event = stdinevent;
- if (!CreateThread(NULL, 0, stdin_read_thread,
- &idata, 0, &threadid)) {
- fprintf(stderr, "Unable to create second thread\n");
- exit(1);
- }
- sending = TRUE;
- }
} else if (n == 1) {
if (idata.len > 0) {
back->send(idata.buffer, idata.len);