diff --git a/defs.h b/defs.h index e5d3fefe..172a30b7 100644 --- a/defs.h +++ b/defs.h @@ -101,6 +101,8 @@ typedef struct SocketPeerInfo SocketPeerInfo; typedef struct Backend Backend; typedef struct BackendVtable BackendVtable; +typedef struct Interactor Interactor; +typedef struct InteractorVtable InteractorVtable; typedef struct Ldisc_tag Ldisc; typedef struct LogContext LogContext; diff --git a/network.h b/network.h index 0b600f63..099895bc 100644 --- a/network.h +++ b/network.h @@ -129,26 +129,6 @@ struct PlugVtable { * want the connection for some reason, or 0 on success. */ int (*accepting)(Plug *p, accept_fn_t constructor, accept_ctx_t ctx); - - /* - * Returns a user-facing description of the nature of the network - * connection being made. Used in interactive proxy authentication - * to announce which connection attempt is now in control of the - * Seat. - * - * The idea is not just to be written in natural language, but to - * connect with the user's idea of _why_ they think some - * connection is being made. For example, instead of saying 'TCP - * connection to 123.45.67.89 port 22', you might say 'SSH - * connection to [logical host name for SSH host key purposes]'. - * - * This function pointer may be NULL, or may exist but return - * NULL, in which case no user-facing description is available. - * - * If a non-NULL string is returned, it must be freed by the - * caller. - */ - char *(*description)(Plug *p); }; /* Proxy indirection layer. @@ -256,8 +236,6 @@ static inline void plug_sent (Plug *p, size_t bufsize) { p->vt->sent(p, bufsize); } static inline int plug_accepting(Plug *p, accept_fn_t cons, accept_ctx_t ctx) { return p->vt->accepting(p, cons, ctx); } -static inline char *plug_description(Plug *p) -{ return p->vt->description ? p->vt->description(p) : NULL; } /* * Special error values are returned from sk_namelookup and sk_new diff --git a/otherbackends/raw.c b/otherbackends/raw.c index 569d2c62..9a391d94 100644 --- a/otherbackends/raw.c +++ b/otherbackends/raw.c @@ -25,6 +25,7 @@ struct Raw { Plug plug; Backend backend; + Interactor interactor; }; static void raw_size(Backend *be, int width, int height); @@ -116,24 +117,21 @@ static void raw_sent(Plug *plug, size_t bufsize) seat_sent(raw->seat, raw->bufsize); } -static char *raw_plug_description(Plug *plug) -{ - Raw *raw = container_of(plug, Raw, plug); - return dupstr(raw->description); -} - -static char *raw_backend_description(Backend *backend) -{ - Raw *raw = container_of(backend, Raw, backend); - return dupstr(raw->description); -} - static const PlugVtable Raw_plugvt = { .log = raw_log, .closing = raw_closing, .receive = raw_receive, .sent = raw_sent, - .description = raw_plug_description, +}; + +static char *raw_description(Interactor *itr) +{ + Raw *raw = container_of(itr, Raw, interactor); + return dupstr(raw->description); +} + +static const InteractorVtable Raw_interactorvt = { + .description = raw_description, }; /* @@ -159,6 +157,8 @@ static char *raw_init(const BackendVtable *vt, Seat *seat, memset(raw, 0, sizeof(Raw)); raw->plug.vt = &Raw_plugvt; raw->backend.vt = vt; + raw->interactor.vt = &Raw_interactorvt; + raw->backend.interactor = &raw->interactor; raw->s = NULL; raw->closed_on_socket_error = false; *backend_handle = &raw->backend; @@ -354,7 +354,6 @@ const BackendVtable raw_backend = { .provide_ldisc = raw_provide_ldisc, .unthrottle = raw_unthrottle, .cfg_info = raw_cfg_info, - .description = raw_backend_description, .id = "raw", .displayname_tc = "Raw", .displayname_lc = "raw", diff --git a/otherbackends/rlogin.c b/otherbackends/rlogin.c index b9b21786..3ab3c070 100644 --- a/otherbackends/rlogin.c +++ b/otherbackends/rlogin.c @@ -32,6 +32,7 @@ struct Rlogin { Plug plug; Backend backend; + Interactor interactor; }; static void rlogin_startup(Rlogin *rlogin, int prompt_result, @@ -193,24 +194,21 @@ static void rlogin_startup(Rlogin *rlogin, int prompt_result, ldisc_check_sendok(rlogin->ldisc); } -static char *rlogin_plug_description(Plug *plug) -{ - Rlogin *rlogin = container_of(plug, Rlogin, plug); - return dupstr(rlogin->description); -} - -static char *rlogin_backend_description(Backend *backend) -{ - Rlogin *rlogin = container_of(backend, Rlogin, backend); - return dupstr(rlogin->description); -} - static const PlugVtable Rlogin_plugvt = { .log = rlogin_log, .closing = rlogin_closing, .receive = rlogin_receive, .sent = rlogin_sent, - .description = rlogin_plug_description, +}; + +static char *rlogin_description(Interactor *itr) +{ + Rlogin *rlogin = container_of(itr, Rlogin, interactor); + return dupstr(rlogin->description); +} + +static const InteractorVtable Rlogin_interactorvt = { + .description = rlogin_description, }; /* @@ -236,6 +234,8 @@ static char *rlogin_init(const BackendVtable *vt, Seat *seat, memset(rlogin, 0, sizeof(Rlogin)); rlogin->plug.vt = &Rlogin_plugvt; rlogin->backend.vt = vt; + rlogin->interactor.vt = &Rlogin_interactorvt; + rlogin->backend.interactor = &rlogin->interactor; rlogin->s = NULL; rlogin->closed_on_socket_error = false; rlogin->seat = seat; @@ -461,7 +461,6 @@ const BackendVtable rlogin_backend = { .provide_ldisc = rlogin_provide_ldisc, .unthrottle = rlogin_unthrottle, .cfg_info = rlogin_cfg_info, - .description = rlogin_backend_description, .id = "rlogin", .displayname_tc = "Rlogin", .displayname_lc = "Rlogin", /* proper name, so capitalise it anyway */ diff --git a/otherbackends/supdup.c b/otherbackends/supdup.c index 3bde828e..3588e9f3 100644 --- a/otherbackends/supdup.c +++ b/otherbackends/supdup.c @@ -107,6 +107,7 @@ struct supdup_tag Plug plug; Backend backend; + Interactor interactor; }; #define SUPDUP_MAX_BACKLOG 4096 @@ -642,17 +643,15 @@ static void supdup_send_config(Supdup *supdup) supdup_send_36bits(supdup, TTYROL); // scroll amount } -static char *supdup_plug_description(Plug *plug) +static char *supdup_description(Interactor *itr) { - Supdup *supdup = container_of(plug, Supdup, plug); + Supdup *supdup = container_of(itr, Supdup, interactor); return dupstr(supdup->description); } -static char *supdup_backend_description(Backend *backend) -{ - Supdup *supdup = container_of(backend, Supdup, backend); - return dupstr(supdup->description); -} +static const InteractorVtable Supdup_interactorvt = { + .description = supdup_description, +}; /* * Called to set up the Supdup connection. @@ -673,7 +672,6 @@ static char *supdup_init(const BackendVtable *x, Seat *seat, .closing = supdup_closing, .receive = supdup_receive, .sent = supdup_sent, - .description = supdup_plug_description, }; SockAddr *addr; const char *err; @@ -686,6 +684,8 @@ static char *supdup_init(const BackendVtable *x, Seat *seat, memset(supdup, 0, sizeof(Supdup)); supdup->plug.vt = &fn_table; supdup->backend.vt = &supdup_backend; + supdup->interactor.vt = &Supdup_interactorvt; + supdup->backend.interactor = &supdup->interactor; supdup->logctx = logctx; supdup->conf = conf_copy(conf); supdup->s = NULL; @@ -952,7 +952,6 @@ const BackendVtable supdup_backend = { .provide_ldisc = supdup_provide_ldisc, .unthrottle = supdup_unthrottle, .cfg_info = supdup_cfg_info, - .description = supdup_backend_description, .id = "supdup", .displayname_tc = "SUPDUP", .displayname_lc = "SUPDUP", /* proper name, so capitalise it anyway */ diff --git a/otherbackends/telnet.c b/otherbackends/telnet.c index 819cbcb0..bbf539c9 100644 --- a/otherbackends/telnet.c +++ b/otherbackends/telnet.c @@ -200,6 +200,7 @@ struct Telnet { Plug plug; Backend backend; + Interactor interactor; }; #define TELNET_MAX_BACKLOG 4096 @@ -681,24 +682,21 @@ static void telnet_sent(Plug *plug, size_t bufsize) seat_sent(telnet->seat, telnet->bufsize); } -static char *telnet_plug_description(Plug *plug) -{ - Telnet *telnet = container_of(plug, Telnet, plug); - return dupstr(telnet->description); -} - -static char *telnet_backend_description(Backend *backend) -{ - Telnet *telnet = container_of(backend, Telnet, backend); - return dupstr(telnet->description); -} - static const PlugVtable Telnet_plugvt = { .log = telnet_log, .closing = telnet_closing, .receive = telnet_receive, .sent = telnet_sent, - .description = telnet_plug_description, +}; + +static char *telnet_description(Interactor *itr) +{ + Telnet *telnet = container_of(itr, Telnet, interactor); + return dupstr(telnet->description); +} + +static const InteractorVtable Telnet_interactorvt = { + .description = telnet_description, }; /* @@ -724,6 +722,8 @@ static char *telnet_init(const BackendVtable *vt, Seat *seat, memset(telnet, 0, sizeof(Telnet)); telnet->plug.vt = &Telnet_plugvt; telnet->backend.vt = vt; + telnet->interactor.vt = &Telnet_interactorvt; + telnet->backend.interactor = &telnet->interactor; telnet->conf = conf_copy(conf); telnet->s = NULL; telnet->socket_connected = false; @@ -1098,7 +1098,6 @@ const BackendVtable telnet_backend = { .provide_ldisc = telnet_provide_ldisc, .unthrottle = telnet_unthrottle, .cfg_info = telnet_cfg_info, - .description = telnet_backend_description, .id = "telnet", .displayname_tc = "Telnet", .displayname_lc = "Telnet", /* proper name, so capitalise it anyway */ diff --git a/putty.h b/putty.h index 4e1f9dde..ffbfa000 100644 --- a/putty.h +++ b/putty.h @@ -633,8 +633,56 @@ enum { /* In (no)sshproxy.c */ extern const bool ssh_proxy_supported; +/* + * The Interactor trait is implemented by anything that is capable of + * presenting interactive prompts or questions to the user during + * network connection setup. Every Backend that ever needs to do this + * is an Interactor, but also, while a Backend is making its initial + * network connection, it may go via network proxy code which is also + * an Interactor and can ask questions of its own. + */ +struct Interactor { + const InteractorVtable *vt; +}; + +struct InteractorVtable { + /* + * Returns a user-facing description of the nature of the network + * connection being made. Used in interactive proxy authentication + * to announce which connection attempt is now in control of the + * Seat. + * + * The idea is not just to be written in natural language, but to + * connect with the user's idea of _why_ they think some + * connection is being made. For example, instead of saying 'TCP + * connection to 123.45.67.89 port 22', you might say 'SSH + * connection to [logical host name for SSH host key purposes]'. + * + * The returned string must be freed by the caller. + */ + char *(*description)(Interactor *itr); +}; + +static inline char *interactor_description(Interactor *itr) +{ return itr->vt->description(itr); } + +/* Interactors that are Backends will find this helper function useful + * in constructing their description strings */ +char *default_description(const BackendVtable *backvt, + const char *host, int port); + +/* + * The Backend trait is the top-level one that governs each of the + * user-facing main modes that PuTTY can use to talk to some + * destination: SSH, Telnet, serial port, pty, etc. + */ + struct Backend { const BackendVtable *vt; + + /* Many Backends are also Interactors. If this one is, a pointer + * to its Interactor trait lives here. */ + Interactor *interactor; }; struct BackendVtable { char *(*init) (const BackendVtable *vt, Seat *seat, @@ -680,28 +728,6 @@ struct BackendVtable { * connections that would be lost if this one were terminated. */ char *(*close_warn_text)(Backend *be); - /* - * Returns a user-facing description of the nature of the network - * connection being made. Used in interactive proxy authentication - * to announce which connection attempt is now in control of the - * Seat. - * - * The idea is not just to be written in natural language, but to - * connect with the user's idea of _why_ they think some - * connection is being made. For example, instead of saying 'TCP - * connection to 123.45.67.89 port 22', you might say 'SSH - * connection to [logical host name for SSH host key purposes]'. - * - * This function pointer may be NULL, or may exist but return - * NULL, in which case no user-facing description is available. - * (Backends which are never proxied, such as pty and ConPTY, need - * not bother to fill this in.) - * - * If a non-NULL string is returned, it must be freed by the - * caller. - */ - char *(*description)(Backend *be); - /* 'id' is a machine-readable name for the backend, used in * saved-session storage. 'displayname_tc' and 'displayname_lc' * are human-readable names, one in title-case for config boxes, @@ -750,11 +776,6 @@ static inline void backend_unthrottle(Backend *be, size_t bufsize) { be->vt->unthrottle(be, bufsize); } static inline int backend_cfg_info(Backend *be) { return be->vt->cfg_info(be); } -static inline char *backend_description(Backend *be) -{ return be->vt->description ? be->vt->description(be) : NULL; } - -char *default_description(const BackendVtable *backvt, - const char *host, int port); extern const struct BackendVtable *const backends[]; /* diff --git a/ssh/ssh.c b/ssh/ssh.c index c9ce2b0b..e240c0c7 100644 --- a/ssh/ssh.c +++ b/ssh/ssh.c @@ -39,6 +39,7 @@ struct Ssh { Plug plug; Backend backend; + Interactor interactor; Ldisc *ldisc; LogContext *logctx; @@ -718,24 +719,21 @@ static char *ssh_close_warn_text(Backend *be) return msg; } -static char *ssh_plug_description(Plug *plug) -{ - Ssh *ssh = container_of(plug, Ssh, plug); - return dupstr(ssh->description); -} - -static char *ssh_backend_description(Backend *backend) -{ - Ssh *ssh = container_of(backend, Ssh, backend); - return dupstr(ssh->description); -} - static const PlugVtable Ssh_plugvt = { .log = ssh_socket_log, .closing = ssh_closing, .receive = ssh_receive, .sent = ssh_sent, - .description = ssh_plug_description, +}; + +static char *ssh_description(Interactor *itr) +{ + Ssh *ssh = container_of(itr, Ssh, interactor); + return dupstr(ssh->description); +} + +static const InteractorVtable Ssh_interactorvt = { + .description = ssh_description, }; /* @@ -940,6 +938,8 @@ static char *ssh_init(const BackendVtable *vt, Seat *seat, ssh->term_height = conf_get_int(ssh->conf, CONF_height); ssh->backend.vt = vt; + ssh->interactor.vt = &Ssh_interactorvt; + ssh->backend.interactor = &ssh->interactor; *backend_handle = &ssh->backend; ssh->bare_connection = (vt->protocol == PROT_SSHCONN); @@ -1264,7 +1264,6 @@ const BackendVtable ssh_backend = { .cfg_info = ssh_cfg_info, .test_for_upstream = ssh_test_for_upstream, .close_warn_text = ssh_close_warn_text, - .description = ssh_backend_description, .id = "ssh", .displayname_tc = "SSH", .displayname_lc = "SSH", /* proper name, so capitalise it anyway */ @@ -1291,7 +1290,6 @@ const BackendVtable sshconn_backend = { .cfg_info = ssh_cfg_info, .test_for_upstream = ssh_test_for_upstream, .close_warn_text = ssh_close_warn_text, - .description = ssh_backend_description, .id = "ssh-connection", .displayname_tc = "Bare ssh-connection", .displayname_lc = "bare ssh-connection",