1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Having created and used uxsel, it actually turns out to be

practically trivial to put all the pieces together and create a
working prototype of Unix PuTTY! It's missing a lot of things -
notably GUI request boxes for host keys and logfiles and so forth,
the Event Log, mid-session reconfiguration, session loading and
saving, sensible population of the character sets drop-down list and
probably other fiddly little things too - but it will put up a
config box and then create a GUI window containing an SSH connection
to the host you specified, so it's _basically_ there. Woo!

[originally from svn r3020]
This commit is contained in:
Simon Tatham 2003-03-29 19:52:50 +00:00
parent 54aff83bf0
commit a3428ae953
6 changed files with 322 additions and 21 deletions

7
Recipe
View File

@ -97,6 +97,9 @@
GUITERM = window windlg winctrls terminal sizetip wcwidth unicode ldiscucs
+ logging printing winutils dialog config wincfg tree234
# Config box on Unix.
UXCFG = config uxcfg dialog gtkdlg gtkcols gtkpanel
# Non-SSH back ends (putty, puttytel, plink).
NONSSH = telnet raw rlogin ldisc
@ -151,6 +154,10 @@ puttygen : [G] puttygen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
pterm : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs
+ logging uxprint settings pty uxsel be_none uxstore signal CHARSET
+ ptermm
putty : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs
+ logging uxprint settings pty uxsel be_all uxstore signal CHARSET
+ uxputty NONSSH UXSSH UXMISC logging ux_x11 UXCFG
plink : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC signal ux_x11

View File

@ -716,7 +716,7 @@ void dlg_end(void *dlg, int value)
{
struct dlgparam *dp = (struct dlgparam *)dlg;
dp->retval = value;
gtk_main_quit();
gtk_widget_destroy(dp->window);
}
void dlg_refresh(union control *ctrl, void *dlg)
@ -910,7 +910,6 @@ static int listitem_key(GtkWidget *item, GdkEventKey *event, gpointer data,
event->keyval==GDK_Page_Up || event->keyval==GDK_KP_Page_Up)
? 2 : 1;
int i, n;
GtkWidget *thisitem;
GList *children, *chead;
chead = children = gtk_container_children(GTK_CONTAINER(list));
@ -964,13 +963,13 @@ static int listitem_key(GtkWidget *item, GdkEventKey *event, gpointer data,
static int listitem_single_key(GtkWidget *item, GdkEventKey *event,
gpointer data)
{
listitem_key(item, event, data, FALSE);
return listitem_key(item, event, data, FALSE);
}
static int listitem_multi_key(GtkWidget *item, GdkEventKey *event,
gpointer data)
{
listitem_key(item, event, data, TRUE);
return listitem_key(item, event, data, TRUE);
}
static int listitem_button(GtkWidget *item, GdkEventButton *event,
@ -1043,7 +1042,7 @@ static void draglist_down(GtkButton *button, gpointer data)
static void filesel_ok(GtkButton *button, gpointer data)
{
struct dlgparam *dp = (struct dlgparam *)data;
/* struct dlgparam *dp = (struct dlgparam *)data; */
gpointer filesel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(filesel), "user-data");
char *name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel));
@ -1052,7 +1051,7 @@ static void filesel_ok(GtkButton *button, gpointer data)
static void fontsel_ok(GtkButton *button, gpointer data)
{
struct dlgparam *dp = (struct dlgparam *)data;
/* struct dlgparam *dp = (struct dlgparam *)data; */
gpointer fontsel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(fontsel), "user-data");
char *name = gtk_font_selection_dialog_get_font_name
@ -1808,7 +1807,7 @@ int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
GtkWidget *w = dp->treeitems[i];
int vis = TRUE;
while (w && GTK_IS_TREE_ITEM(w) || GTK_IS_TREE(w)) {
while (w && (GTK_IS_TREE_ITEM(w) || GTK_IS_TREE(w))) {
if (!GTK_WIDGET_VISIBLE(w)) {
vis = FALSE;
break;
@ -1825,7 +1824,6 @@ int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
gtk_signal_emit_stop_by_name(GTK_OBJECT(widget),
"key_press_event");
if (j >= 0) {
gint return_val;
gtk_signal_emit_by_name(GTK_OBJECT(dp->treeitems[j]), "toggle");
gtk_widget_grab_focus(dp->treeitems[j]);
}
@ -1892,7 +1890,7 @@ void shortcut_add(struct Shortcuts *scs, GtkWidget *labelw,
}
}
int do_config_box(const char *title)
int do_config_box(const char *title, Config *cfg)
{
GtkWidget *window, *hbox, *vbox, *cols, *label,
*tree, *treescroll, *panels, *panelvbox;
@ -1901,7 +1899,6 @@ int do_config_box(const char *title)
char *path;
GtkTreeItem *treeitemlevels[8];
GtkTree *treelevels[8];
Config cfg;
struct dlgparam dp;
struct sesslist sl;
struct Shortcuts scs;
@ -1909,7 +1906,7 @@ int do_config_box(const char *title)
struct selparam *selparams = NULL;
int nselparams = 0, selparamsize = 0;
do_defaults(NULL, &cfg);
do_defaults(NULL, cfg);
dlg_init(&dp);
@ -2072,7 +2069,7 @@ int do_config_box(const char *title)
dp.treeitems[index] = selparams[index].treeitem;
}
dp.data = &cfg;
dp.data = cfg;
dlg_refresh(NULL, &dp);
dp.shortcuts = &selparams[0].shortcuts;
@ -2218,8 +2215,9 @@ char *x_get_default(const char *key)
int main(int argc, char **argv)
{
Config cfg;
gtk_init(&argc, &argv);
printf("returned %d\n", do_config_box("PuTTY Configuration"));
printf("returned %d\n", do_config_box("PuTTY Configuration", &cfg));
return 0;
}

View File

@ -1948,6 +1948,7 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg)
{
int err = 0;
extern char **pty_argv; /* declared in pty.c */
extern int use_pty_argv;
/*
* Macros to make argument handling easier. Note that because
@ -2054,7 +2055,7 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg)
cfg->colours[index][2] = col.blue / 256;
}
} else if (!strcmp(p, "-e")) {
} else if (use_pty_argv && !strcmp(p, "-e")) {
/* This option swallows all further arguments. */
if (!do_everything)
break;
@ -2219,9 +2220,10 @@ void uxsel_input_remove(int id) {
gdk_input_remove(id);
}
int main(int argc, char **argv)
int pt_main(int argc, char **argv)
{
extern void pty_pre_init(void); /* declared in pty.c */
extern Backend *select_backend(Config *cfg);
extern int cfgbox(Config *cfg);
struct gui_data *inst;
int font_charset;
@ -2229,8 +2231,6 @@ int main(int argc, char **argv)
* it */
block_signal(SIGCHLD, 1);
pty_pre_init();
gtk_init(&argc, &argv);
/*
@ -2246,6 +2246,9 @@ int main(int argc, char **argv)
if (do_cmdline(argc, argv, 1, &inst->cfg))
exit(1); /* post-defaults, do everything */
if (!cfgbox(&inst->cfg))
exit(0); /* config box hit Cancel */
inst->fonts[0] = gdk_font_load(inst->cfg.font.name);
if (!inst->fonts[0]) {
fprintf(stderr, "pterm: unable to load font \"%s\"\n",
@ -2397,9 +2400,13 @@ int main(int argc, char **argv)
uxsel_init();
inst->back = &pty_backend;
inst->back->init((void *)inst->term, &inst->backhandle, &inst->cfg,
NULL, 0, NULL, 0);
inst->back = select_backend(&inst->cfg);
{
char *realhost; /* FIXME: don't ignore this! */
inst->back->init((void *)inst->term, &inst->backhandle, &inst->cfg,
inst->cfg.host, inst->cfg.port, &realhost,
inst->cfg.tcp_nodelay);
}
inst->back->provide_logctx(inst->backhandle, inst->logctx);
term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle);

27
unix/ptermm.c Normal file
View File

@ -0,0 +1,27 @@
/*
* pterm main program.
*/
#include <stdio.h>
#include "putty.h"
Backend *select_backend(Config *cfg)
{
return &pty_backend;
}
int cfgbox(Config *cfg)
{
return 1; /* no-op in pterm */
}
int main(int argc, char **argv)
{
extern int pt_main(int argc, char **argv);
extern void pty_pre_init(void); /* declared in pty.c */
pty_pre_init();
return pt_main(argc, argv);
}

View File

@ -84,6 +84,7 @@ static int pty_exit_code;
static struct utmp utmp_entry;
#endif
char **pty_argv;
int use_pty_argv = TRUE;
static void pty_close(void);

261
unix/uxputty.c Normal file
View File

@ -0,0 +1,261 @@
/*
* Unix PuTTY main program.
*/
#include <stdio.h>
#include <assert.h>
#include <termios.h>
#include <unistd.h>
#include "putty.h"
#include "storage.h"
/*
* FIXME: At least some of these functions should be replaced with
* GTK GUI error-box-type things.
*
* In particular, all the termios-type things must go, and
* termios.h should disappear from the above #include list.
*/
void fatalbox(char *p, ...)
{
va_list ap;
fprintf(stderr, "FATAL ERROR: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
cleanup_exit(1);
}
void connection_fatal(void *frontend, char *p, ...)
{
va_list ap;
fprintf(stderr, "FATAL ERROR: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
cleanup_exit(1);
}
void cmdline_error(char *p, ...)
{
va_list ap;
fprintf(stderr, "plink: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
exit(1);
}
/*
* Clean up and exit.
*/
void cleanup_exit(int code)
{
/*
* Clean up.
*/
sk_cleanup();
random_save_seed();
exit(code);
}
void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
char *keystr, char *fingerprint)
{
int ret;
static const char absentmsg[] =
"The server's host key is not cached. You have no guarantee\n"
"that the server is the computer you think it is.\n"
"The server's key fingerprint is:\n"
"%s\n"
"If you trust this host, enter \"y\" to add the key to\n"
"PuTTY's cache and carry on connecting.\n"
"If you want to carry on connecting just once, without\n"
"adding the key to the cache, enter \"n\".\n"
"If you do not trust this host, press Return to abandon the\n"
"connection.\n"
"Store key in cache? (y/n) ";
static const char wrongmsg[] =
"WARNING - POTENTIAL SECURITY BREACH!\n"
"The server's host key does not match the one PuTTY has\n"
"cached. This means that either the server administrator\n"
"has changed the host key, or you have actually connected\n"
"to another computer pretending to be the server.\n"
"The new key fingerprint is:\n"
"%s\n"
"If you were expecting this change and trust the new key,\n"
"enter \"y\" to update PuTTY's cache and continue connecting.\n"
"If you want to carry on connecting but without updating\n"
"the cache, enter \"n\".\n"
"If you want to abandon the connection completely, press\n"
"Return to cancel. Pressing Return is the ONLY guaranteed\n"
"safe choice.\n"
"Update cached key? (y/n, Return cancels connection) ";
static const char abandoned[] = "Connection abandoned.\n";
char line[32];
/*
* Verify the key.
*/
ret = verify_host_key(host, port, keytype, keystr);
if (ret == 0) /* success - key matched OK */
return;
if (ret == 2) { /* key was different */
fprintf(stderr, wrongmsg, fingerprint);
fflush(stderr);
}
if (ret == 1) { /* key was absent */
fprintf(stderr, absentmsg, fingerprint);
fflush(stderr);
}
{
struct termios oldmode, newmode;
tcgetattr(0, &oldmode);
newmode = oldmode;
newmode.c_lflag |= ECHO | ISIG | ICANON;
tcsetattr(0, TCSANOW, &newmode);
line[0] = '\0';
read(0, line, sizeof(line) - 1);
tcsetattr(0, TCSANOW, &oldmode);
}
if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
if (line[0] == 'y' || line[0] == 'Y')
store_host_key(host, port, keytype, keystr);
} else {
fprintf(stderr, abandoned);
cleanup_exit(0);
}
}
/*
* Ask whether the selected cipher is acceptable (since it was
* below the configured 'warn' threshold).
* cs: 0 = both ways, 1 = client->server, 2 = server->client
*/
void askcipher(void *frontend, char *ciphername, int cs)
{
static const char msg[] =
"The first %scipher supported by the server is\n"
"%s, which is below the configured warning threshold.\n"
"Continue with connection? (y/n) ";
static const char abandoned[] = "Connection abandoned.\n";
char line[32];
fprintf(stderr, msg,
(cs == 0) ? "" :
(cs == 1) ? "client-to-server " : "server-to-client ",
ciphername);
fflush(stderr);
{
struct termios oldmode, newmode;
tcgetattr(0, &oldmode);
newmode = oldmode;
newmode.c_lflag |= ECHO | ISIG | ICANON;
tcsetattr(0, TCSANOW, &newmode);
line[0] = '\0';
read(0, line, sizeof(line) - 1);
tcsetattr(0, TCSANOW, &oldmode);
}
if (line[0] == 'y' || line[0] == 'Y') {
return;
} else {
fprintf(stderr, abandoned);
cleanup_exit(0);
}
}
void old_keyfile_warning(void)
{
static const char message[] =
"You are loading an SSH 2 private key which has an\n"
"old version of the file format. This means your key\n"
"file is not fully tamperproof. Future versions of\n"
"PuTTY may stop supporting this private key format,\n"
"so we recommend you convert your key to the new\n"
"format.\n"
"\n"
"Once the key is loaded into PuTTYgen, you can perform\n"
"this conversion simply by saving it again.\n";
fputs(message, stderr);
}
/*
* Another bunch of temporary stub functions. These ones will want
* removing by means of implementing them properly: libcharset
* should invent its own sensible format for codepage names and a
* means of enumerating them, and printer_enum needs to be dealt
* with somehow or other too.
*/
char *cp_name(int codepage)
{
return "";
}
char *cp_enumerate(int index)
{
return NULL;
}
int decode_codepage(char *cp_name)
{
return -2;
}
printer_enum *printer_start_enum(int *nprinters_ptr) {
*nprinters_ptr = 0;
return NULL;
}
char *printer_get_name(printer_enum *pe, int i) { return NULL;
}
void printer_finish_enum(printer_enum *pe) { }
Backend *select_backend(Config *cfg)
{
int i;
Backend *back = NULL;
for (i = 0; backends[i].backend != NULL; i++)
if (backends[i].protocol == cfg->protocol) {
back = backends[i].backend;
break;
}
assert(back != NULL);
return back;
}
int cfgbox(Config *cfg)
{
extern int do_config_box(const char *title, Config *cfg);
return do_config_box("PuTTY Configuration", cfg);
}
int main(int argc, char **argv)
{
extern int pt_main(int argc, char **argv);
sk_init();
flags = FLAG_VERBOSE | FLAG_INTERACTIVE;
default_protocol = be_default_protocol;
/* Find the appropriate default port. */
{
int i;
default_port = 0; /* illegal */
for (i = 0; backends[i].backend != NULL; i++)
if (backends[i].protocol == default_protocol) {
default_port = backends[i].backend->default_port;
break;
}
}
return pt_main(argc, argv);
}