exit(code);
}
-void verify_ssh_host_key(char *host, int port, char *keytype,
+void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
char *keystr, char *fingerprint)
{
int ret;
* below the configured 'warn' threshold).
* cs: 0 = both ways, 1 = client->server, 2 = server->client
*/
-void askcipher(char *ciphername, int cs)
+void askcipher(void *frontend, char *ciphername, int cs)
{
HANDLE hin;
DWORD savemode, i;
* Ask whether to wipe a session log file before writing to it.
* Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
*/
-int askappend(char *filename)
+int askappend(void *frontend, char *filename)
{
HANDLE hin;
DWORD savemode, i;
/*
* Warn about the obsolescent key file format.
+ *
+ * Uniquely among these functions, this one does _not_ expect a
+ * frontend handle. This means that if PuTTY is ported to a
+ * platform which requires frontend handles, this function will be
+ * an anomaly. Fortunately, the problem it addresses will not have
+ * been present on that platform, so it can plausibly be
+ * implemented as an empty function.
*/
void old_keyfile_warning(void)
{
fputs(message, stderr);
}
-void logevent(char *string)
+void logevent(void *frontend, char *string)
{
}
#include "putty.h"
/* log session to file stuff ... */
-static FILE *lgfp = NULL;
-static char currlogfilename[FILENAME_MAX];
+struct LogContext {
+ FILE *lgfp;
+ char currlogfilename[FILENAME_MAX];
+ void *frontend;
+};
static void xlatlognam(char *d, char *s, char *hostname, struct tm *tm);
/*
* Log session traffic.
*/
-void logtraffic(unsigned char c, int logmode)
+void logtraffic(void *handle, unsigned char c, int logmode)
{
+ struct LogContext *ctx = (struct LogContext *)handle;
if (cfg.logtype > 0) {
if (cfg.logtype == logmode) {
/* deferred open file from pgm start? */
- if (!lgfp)
- logfopen();
- if (lgfp)
- fputc(c, lgfp);
+ if (!ctx->lgfp)
+ logfopen(ctx);
+ if (ctx->lgfp)
+ fputc(c, ctx->lgfp);
}
}
}
/*
* Log an Event Log entry (used in SSH packet logging mode).
*/
-void log_eventlog(char *event)
+void log_eventlog(void *handle, char *event)
{
+ struct LogContext *ctx = (struct LogContext *)handle;
if (cfg.logtype != LGTYP_PACKETS)
return;
- if (!lgfp)
- logfopen();
- if (lgfp)
- fprintf(lgfp, "Event Log: %s\n", event);
+ if (!ctx->lgfp)
+ logfopen(ctx);
+ if (ctx->lgfp)
+ fprintf(ctx->lgfp, "Event Log: %s\n", event);
}
/*
* Log an SSH packet.
*/
-void log_packet(int direction, int type, char *texttype, void *data, int len)
+void log_packet(void *handle, int direction, int type,
+ char *texttype, void *data, int len)
{
+ struct LogContext *ctx = (struct LogContext *)handle;
int i, j;
char dumpdata[80], smalldata[5];
if (cfg.logtype != LGTYP_PACKETS)
return;
- if (!lgfp)
- logfopen();
- if (lgfp) {
- fprintf(lgfp, "%s packet type %d / 0x%02x (%s)\n",
+ if (!ctx->lgfp)
+ logfopen(ctx);
+ if (ctx->lgfp) {
+ fprintf(ctx->lgfp, "%s packet type %d / 0x%02x (%s)\n",
direction == PKT_INCOMING ? "Incoming" : "Outgoing",
type, type, texttype);
for (i = 0; i < len; i += 16) {
dumpdata[10+1+3*16+2+j] = (isprint(c) ? c : '.');
}
strcpy(dumpdata + 10+1+3*16+2+j, "\n");
- fputs(dumpdata, lgfp);
+ fputs(dumpdata, ctx->lgfp);
}
- fflush(lgfp);
+ fflush(ctx->lgfp);
}
}
/* open log file append/overwrite mode */
-void logfopen(void)
+void logfopen(void *handle)
{
+ struct LogContext *ctx = (struct LogContext *)handle;
char buf[256];
time_t t;
struct tm tm;
char writemod[4];
/* Prevent repeat calls */
- if (lgfp)
+ if (ctx->lgfp)
return;
if (!cfg.logtype)
tm = *localtime(&t);
/* substitute special codes in file name */
- xlatlognam(currlogfilename,cfg.logfilename,cfg.host, &tm);
+ xlatlognam(ctx->currlogfilename, cfg.logfilename,cfg.host, &tm);
- lgfp = fopen(currlogfilename, "r"); /* file already present? */
- if (lgfp) {
+ ctx->lgfp = fopen(ctx->currlogfilename, "r"); /* file already present? */
+ if (ctx->lgfp) {
int i;
- fclose(lgfp);
- i = askappend(currlogfilename);
+ fclose(ctx->lgfp);
+ i = askappend(ctx->frontend, ctx->currlogfilename);
if (i == 1)
writemod[0] = 'a'; /* set append mode */
else if (i == 0) { /* cancelled */
- lgfp = NULL;
+ ctx->lgfp = NULL;
cfg.logtype = 0; /* disable logging */
return;
}
}
- lgfp = fopen(currlogfilename, writemod);
- if (lgfp) { /* enter into event log */
+ ctx->lgfp = fopen(ctx->currlogfilename, writemod);
+ if (ctx->lgfp) { /* enter into event log */
/* --- write header line into log file */
- fputs("=~=~=~=~=~=~=~=~=~=~=~= PuTTY log ", lgfp);
+ fputs("=~=~=~=~=~=~=~=~=~=~=~= PuTTY log ", ctx->lgfp);
strftime(buf, 24, "%Y.%m.%d %H:%M:%S", &tm);
- fputs(buf, lgfp);
- fputs(" =~=~=~=~=~=~=~=~=~=~=~=\r\n", lgfp);
+ fputs(buf, ctx->lgfp);
+ fputs(" =~=~=~=~=~=~=~=~=~=~=~=\r\n", ctx->lgfp);
sprintf(buf, "%s session log (%s mode) to file: ",
(writemod[0] == 'a') ? "Appending" : "Writing new",
cfg.logtype == LGTYP_DEBUG ? "raw" :
cfg.logtype == LGTYP_PACKETS ? "SSH packets" : "<ukwn>"));
/* Make sure we do not exceed the output buffer size */
- strncat(buf, currlogfilename, 128);
+ strncat(buf, ctx->currlogfilename, 128);
buf[strlen(buf)] = '\0';
- logevent(buf);
+ logevent(ctx->frontend, buf);
}
}
-void logfclose(void)
+void logfclose(void *handle)
{
- if (lgfp) {
- fclose(lgfp);
- lgfp = NULL;
+ struct LogContext *ctx = (struct LogContext *)handle;
+ if (ctx->lgfp) {
+ fclose(ctx->lgfp);
+ ctx->lgfp = NULL;
}
}
+void *log_init(void *frontend)
+{
+ struct LogContext *ctx = smalloc(sizeof(struct LogContext));
+ ctx->lgfp = NULL;
+ ctx->frontend = frontend;
+ return ctx;
+}
+
/*
* translate format codes into time/date strings
* and insert them into log file name
};
static int cmpkeys_ssh2_asymm(void *av, void *bv);
-/*
- * This function is needed to link with the DES code. We need not
- * have it do anything at all.
- */
-void logevent(char *msg)
-{
-}
-
#define GET_32BIT(cp) \
(((unsigned long)(unsigned char)(cp)[0] << 24) | \
((unsigned long)(unsigned char)(cp)[1] << 16) | \
WSACleanup();
cleanup_exit(1);
}
-void connection_fatal(char *p, ...)
+void connection_fatal(void *frontend, char *p, ...)
{
va_list ap;
fprintf(stderr, "FATAL ERROR: ");
fprintf(stderr, "Unable to open connection:\n%s", error);
return 1;
}
+ logctx = log_init(NULL);
+ back->provide_logctx(backhandle, logctx);
sfree(realhost);
}
connopen = 1;
cleanup_exit(1);
}
-void connection_fatal(char *fmt, ...)
+void connection_fatal(void *frontend, char *fmt, ...)
{
char str[0x100]; /* Make the size big enough */
va_list ap;
fprintf(stderr, "ssh_init: %s\n", err);
return 1;
}
+ logctx = log_init(NULL);
+ back->provide_logctx(backhandle, logctx);
ssh_sftp_init();
if (verbose && realhost != NULL)
printf("Connected to %s\n", realhost);
#endif
#endif
+#ifndef DONE_TYPEDEFS
+#define DONE_TYPEDEFS
typedef struct config_tag Config;
typedef struct backend_tag Backend;
typedef struct terminal_tag Terminal;
+#endif
#include "puttyps.h"
#include "network.h"
int (*sendok) (void *handle);
int (*ldisc) (void *handle, int);
void (*provide_ldisc) (void *handle, void *ldisc);
+ void (*provide_logctx) (void *handle, void *logctx);
/*
* back->unthrottle() tells the back end that the front end
* buffer is clearing.
/*
* Exports from window.c.
*/
-void request_resize(int, int);
+void request_resize(void *frontend, int, int);
void do_text(Context, int, int, char *, int, unsigned long, int);
void do_cursor(Context, int, int, char *, int, unsigned long, int);
int CharWidth(Context ctx, int uc);
-void set_title(char *);
-void set_icon(char *);
-void set_sbar(int, int, int);
-Context get_ctx(void);
+void set_title(void *frontend, char *);
+void set_icon(void *frontend, char *);
+void set_sbar(void *frontend, int, int, int);
+Context get_ctx(void *frontend);
void free_ctx(Context);
-void palette_set(int, int, int, int);
-void palette_reset(void);
-void write_aclip(char *, int, int);
-void write_clip(wchar_t *, int, int);
-void get_clip(wchar_t **, int *);
-void optimised_move(int, int, int);
-void set_raw_mouse_mode(int);
-Mouse_Button translate_button(Mouse_Button b);
-void connection_fatal(char *, ...);
+void palette_set(void *frontend, int, int, int, int);
+void palette_reset(void *frontend);
+void write_aclip(void *frontend, char *, int, int);
+void write_clip(void *frontend, wchar_t *, int, int);
+void get_clip(void *frontend, wchar_t **, int *);
+void optimised_move(void *frontend, int, int, int);
+void set_raw_mouse_mode(void *frontend, int);
+Mouse_Button translate_button(void *frontend, Mouse_Button b);
+void connection_fatal(void *frontend, char *, ...);
void fatalbox(char *, ...);
void modalfatalbox(char *, ...);
-void beep(int);
-void begin_session(void);
-void sys_cursor(int x, int y);
-void request_paste(void);
+void beep(void *frontend, int);
+void begin_session(void *frontend);
+void sys_cursor(void *frontend, int x, int y);
+void request_paste(void *frontend);
void frontend_keypress(void *frontend);
void ldisc_update(void *frontend, int echo, int edit);
#define OPTIMISE_IS_SCROLL 1
-void set_iconic(int iconic);
-void move_window(int x, int y);
-void set_zorder(int top);
-void refresh_window(void);
-void set_zoomed(int zoomed);
-int is_iconic(void);
-void get_window_pos(int *x, int *y);
-void get_window_pixels(int *x, int *y);
-char *get_window_title(int icon);
+void set_iconic(void *frontend, int iconic);
+void move_window(void *frontend, int x, int y);
+void set_zorder(void *frontend, int top);
+void refresh_window(void *frontend);
+void set_zoomed(void *frontend, int zoomed);
+int is_iconic(void *frontend);
+void get_window_pos(void *frontend, int *x, int *y);
+void get_window_pixels(void *frontend, int *x, int *y);
+char *get_window_title(void *frontend, int icon);
void cleanup_exit(int);
* Exports from terminal.c.
*/
-Terminal *term_init(void);
+Terminal *term_init(void *frontend);
void term_size(Terminal *, int, int, int);
void term_out(Terminal *);
void term_paint(Terminal *, Context, int, int, int, int);
void term_provide_resize_fn(Terminal *term,
void (*resize_fn)(void *, int, int),
void *resize_ctx);
+void term_provide_logctx(Terminal *term, void *logctx);
/*
* Exports from logging.c.
*/
-void logfopen();
-void logfclose();
-void logtraffic(unsigned char c, int logmode);
+void *log_init(void *frontend);
+void logfopen(void *logctx);
+void logfclose(void *logctx);
+void logtraffic(void *logctx, unsigned char c, int logmode);
+void log_eventlog(void *logctx, char *string);
enum { PKT_INCOMING, PKT_OUTGOING };
-void log_eventlog(char *string);
-void log_packet(int direction, int type, char *texttype, void *data, int len);
+void log_packet(void *logctx, int direction, int type,
+ char *texttype, void *data, int len);
/*
* Exports from raw.c.
/*
* Exports from windlg.c
*/
-void logevent(char *);
-void verify_ssh_host_key(char *host, int port, char *keytype,
+void logevent(void *frontend, char *);
+void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
char *keystr, char *fingerprint);
-void askcipher(char *ciphername, int cs);
-int askappend(char *filename);
+void askcipher(void *frontend, char *ciphername, int cs);
+int askappend(void *frontend, char *filename);
/*
* Exports from console.c (that aren't equivalents to things in
}
/*
- * This function is needed to link with the DES code. We need not
- * have it do anything at all.
- */
-void logevent(char *msg)
-{
-}
-
-/*
* Dialog-box function for the Licence box.
*/
static int CALLBACK LicenceProc(HWND hwnd, UINT msg,
}
if (error_msg) {
/* A socket error has occurred. */
- logevent(error_msg);
+ logevent(raw->frontend, error_msg);
connection_fatal("%s", error_msg);
} /* Otherwise, the remote side closed the connection normally. */
return 0;
{
char buf[200];
sprintf(buf, "Looking up host \"%.170s\"", host);
- logevent(buf);
+ logevent(raw->frontend, buf);
}
addr = sk_namelookup(host, realhost);
if ((err = sk_addr_error(addr)))
char buf[200], addrbuf[100];
sk_getaddr(addr, addrbuf, 100);
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
- logevent(buf);
+ logevent(raw->frontend, buf);
}
raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, (Plug) raw);
if ((err = sk_socket_error(raw->s)))
/* This is a stub. */
}
+static void raw_provide_logctx(void *handle, void *logctx)
+{
+ /* This is a stub. */
+}
+
static int raw_exitcode(void *handle)
{
/* Exit codes are a meaningless concept in the Raw protocol */
raw_sendok,
raw_ldisc,
raw_provide_ldisc,
+ raw_provide_logctx,
raw_unthrottle,
1
};
}
if (error_msg) {
/* A socket error has occurred. */
- logevent(error_msg);
+ logevent(rlogin->frontend, error_msg);
connection_fatal("%s", error_msg);
} /* Otherwise, the remote side closed the connection normally. */
return 0;
{
char buf[200];
sprintf(buf, "Looking up host \"%.170s\"", host);
- logevent(buf);
+ logevent(rlogin->frontend, buf);
}
addr = sk_namelookup(host, realhost);
if ((err = sk_addr_error(addr)))
char buf[200], addrbuf[100];
sk_getaddr(addr, addrbuf, 100);
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
- logevent(buf);
+ logevent(rlogin->frontend, buf);
}
rlogin->s = new_connection(addr, *realhost, port, 1, 0,
nodelay, (Plug) rlogin);
/* This is a stub. */
}
+static void rlogin_provide_logctx(void *handle, void *logctx)
+{
+ /* This is a stub. */
+}
+
static int rlogin_exitcode(void *handle)
{
Rlogin rlogin = (Rlogin) handle;
rlogin_sendok,
rlogin_ldisc,
rlogin_provide_ldisc,
+ rlogin_provide_logctx,
rlogin_unthrottle,
1
};
cleanup_exit(1);
}
-void connection_fatal(char *fmt, ...)
+void connection_fatal(void *frontend, char *fmt, ...)
{
char str[0x100]; /* Make the size big enough */
va_list ap;
err = back->init(NULL, &backhandle, cfg.host, cfg.port, &realhost, 0);
if (err != NULL)
bump("ssh_init: %s", err);
+ logctx = log_init(NULL);
+ back->provide_logctx(backhandle, logctx);
ssh_scp_init();
if (verbose && realhost != NULL)
tell_user(stderr, "Connected to %s\n", realhost);
*/
void fxp_free_name(struct fxp_name *name)
{
- int i;
-
sfree(name->filename);
sfree(name->longname);
sfree(name);
#define TRUE 1
#endif
-#define logevent(s) { logevent(s); \
- if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \
- { fprintf(stderr, "%s\n", s); fflush(stderr); } }
-
-/* logevent, only printf-formatted. */
-void logeventf(char *fmt, ...)
-{
- va_list ap;
- char stuff[200];
-
- va_start(ap, fmt);
- vsprintf(stuff, fmt, ap);
- va_end(ap);
- logevent(stuff);
-}
-
-#define bombout(msg) ( ssh->state = SSH_STATE_CLOSED, \
- (ssh->s ? sk_close(ssh->s), ssh->s = NULL : 0), \
- logeventf msg, connection_fatal msg )
-
#define SSH1_MSG_DISCONNECT 1 /* 0x1 */
#define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */
#define SSH1_CMSG_SESSION_KEY 3 /* 0x3 */
Socket s;
void *ldisc;
+ void *logctx;
unsigned char session_key[32];
int v1_compressing;
int (*s_rdpkt) (Ssh ssh, unsigned char **data, int *datalen);
};
+#define logevent(s) { logevent(ssh->frontend, s); \
+ if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \
+ { fprintf(stderr, "%s\n", s); fflush(stderr); } }
+
+/* logevent, only printf-formatted. */
+void logeventf(Ssh ssh, char *fmt, ...)
+{
+ va_list ap;
+ char stuff[200];
+
+ va_start(ap, fmt);
+ vsprintf(stuff, fmt, ap);
+ va_end(ap);
+ logevent(stuff);
+}
+
+#define bombout(msg) ( ssh->state = SSH_STATE_CLOSED, \
+ (ssh->s ? sk_close(ssh->s), ssh->s = NULL : 0), \
+ logeventf msg, connection_fatal msg )
+
static int ssh_channelcmp(void *av, void *bv)
{
struct ssh_channel *a = (struct ssh_channel *) av;
if (ssh->cipher && detect_attack(ssh->crcda_ctx, ssh->pktin.data,
st->biglen, NULL)) {
- bombout(("Network attack (CRC compensation) detected!"));
+ bombout((ssh,"Network attack (CRC compensation) detected!"));
crReturn(0);
}
st->realcrc = crc32(ssh->pktin.data, st->biglen - 4);
st->gotcrc = GET_32BIT(ssh->pktin.data + st->biglen - 4);
if (st->gotcrc != st->realcrc) {
- bombout(("Incorrect CRC received on packet"));
+ bombout((ssh,"Incorrect CRC received on packet"));
crReturn(0);
}
ssh->pktin.type = ssh->pktin.body[-1];
- log_packet(PKT_INCOMING, ssh->pktin.type, ssh1_pkt_type(ssh->pktin.type),
- ssh->pktin.body, ssh->pktin.length);
+ if (ssh->logctx)
+ log_packet(ssh->logctx,
+ PKT_INCOMING, ssh->pktin.type,
+ ssh1_pkt_type(ssh->pktin.type),
+ ssh->pktin.body, ssh->pktin.length);
if (ssh->pktin.type == SSH1_SMSG_STDOUT_DATA ||
ssh->pktin.type == SSH1_SMSG_STDERR_DATA ||
ssh->pktin.type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
long stringlen = GET_32BIT(ssh->pktin.body);
if (stringlen + 4 != ssh->pktin.length) {
- bombout(("Received data packet with bogus string length"));
+ bombout((ssh,"Received data packet with bogus string length"));
crReturn(0);
}
}
memcpy(buf + nowlen, ssh->pktin.body + 4, msglen);
buf[nowlen + msglen] = '\0';
/* logevent(buf); (this is now done within the bombout macro) */
- bombout(("Server sent disconnect message:\n\"%s\"", buf+nowlen));
+ bombout((ssh,"Server sent disconnect message:\n\"%s\"", buf+nowlen));
crReturn(0);
}
* do us any more damage.
*/
if (st->len < 0 || st->pad < 0 || st->len + st->pad < 0) {
- bombout(("Incoming packet was garbled on decryption"));
+ bombout((ssh,"Incoming packet was garbled on decryption"));
crReturn(0);
}
if (ssh->scmac
&& !ssh->scmac->verify(ssh->sc_mac_ctx, ssh->pktin.data, st->len + 4,
st->incoming_sequence)) {
- bombout(("Incorrect MAC received on packet"));
+ bombout((ssh,"Incorrect MAC received on packet"));
crReturn(0);
}
st->incoming_sequence++; /* whether or not we MACed */
ssh->pktin.savedpos = 6;
ssh->pktin.type = ssh->pktin.data[5];
- log_packet(PKT_INCOMING, ssh->pktin.type,
- ssh2_pkt_type(ssh->pkt_ctx, ssh->pktin.type),
- ssh->pktin.data+6, ssh->pktin.length-6);
+ if (ssh->logctx)
+ log_packet(ssh->logctx, PKT_INCOMING, ssh->pktin.type,
+ ssh2_pkt_type(ssh->pkt_ctx, ssh->pktin.type),
+ ssh->pktin.data+6, ssh->pktin.length-6);
switch (ssh->pktin.type) {
/*
memcpy(buf + nowlen, ssh->pktin.data + 14, msglen);
buf[nowlen + msglen] = '\0';
logevent(buf);
- bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"",
+ bombout((ssh,"Server sent disconnect message\ntype %d (%s):\n\"%s\"",
reason,
(reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ?
ssh2_disconnect_reasons[reason] : "unknown",
ssh->pktout.body[-1] = ssh->pktout.type;
- log_packet(PKT_OUTGOING, ssh->pktout.type, ssh1_pkt_type(ssh->pktout.type),
- ssh->pktout.body, ssh->pktout.length);
+ if (ssh->logctx)
+ log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.type,
+ ssh1_pkt_type(ssh->pktout.type),
+ ssh->pktout.body, ssh->pktout.length);
if (ssh->v1_compressing) {
unsigned char *compblk;
{
int cipherblk, maclen, padding, i;
- log_packet(PKT_OUTGOING, ssh->pktout.data[5],
- ssh2_pkt_type(ssh->pkt_ctx, ssh->pktout.data[5]),
- ssh->pktout.data + 6, ssh->pktout.length - 6);
+ if (ssh->logctx)
+ log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.data[5],
+ ssh2_pkt_type(ssh->pkt_ctx, ssh->pktout.data[5]),
+ ssh->pktout.data + 6, ssh->pktout.length - 6);
/*
* Compress packet payload.
if (!p)
return NULL;
if (p[0] & 0x80) {
- bombout(("internal error: Can't handle negative mpints"));
+ bombout((ssh,"internal error: Can't handle negative mpints"));
return NULL;
}
b = bignum_from_bytes(p, length);
s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0;
if (cfg.sshprot == 0 && !s->proto1) {
- bombout(("SSH protocol version 1 required by user but not provided by server"));
+ bombout((ssh,"SSH protocol version 1 required by user but not provided by server"));
crReturn(0);
}
if (cfg.sshprot == 3 && !s->proto2) {
- bombout(("SSH protocol version 2 required by user but not provided by server"));
+ bombout((ssh,"SSH protocol version 2 required by user but not provided by server"));
crReturn(0);
}
if (error_msg) {
/* A socket error has occurred. */
logevent(error_msg);
- connection_fatal(error_msg);
+ connection_fatal(ssh->frontend, error_msg);
} else {
/* Otherwise, the remote side closed the connection normally. */
}
crWaitUntil(ispkt);
if (ssh->pktin.type != SSH1_SMSG_PUBLIC_KEY) {
- bombout(("Public key packet not received"));
+ bombout((ssh,"Public key packet not received"));
crReturn(0);
}
fatalbox("Out of memory");
rsastr_fmt(keystr, &hostkey);
rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey);
- verify_ssh_host_key(ssh->savedhost, ssh->savedport, "rsa", keystr,
+ verify_ssh_host_key(ssh->frontend,
+ ssh->savedhost, ssh->savedport, "rsa", keystr,
fingerprint);
sfree(keystr);
}
}
if (!cipher_chosen) {
if ((s->supported_ciphers_mask & (1 << SSH_CIPHER_3DES)) == 0)
- bombout(("Server violates SSH 1 protocol by not "
+ bombout((ssh,"Server violates SSH 1 protocol by not "
"supporting 3DES encryption"));
else
/* shouldn't happen */
- bombout(("No supported ciphers found"));
+ bombout((ssh,"No supported ciphers found"));
crReturn(0);
}
/* Warn about chosen cipher if necessary. */
if (warn)
- askcipher(cipher_string, 0);
+ askcipher(ssh->frontend, cipher_string, 0);
}
switch (s->cipher_type) {
crWaitUntil(ispkt);
if (ssh->pktin.type != SSH1_SMSG_SUCCESS) {
- bombout(("Encryption not successfully enabled"));
+ bombout((ssh,"Encryption not successfully enabled"));
crReturn(0);
}
PKT_STR, "No more passwords available to try",
PKT_END);
logevent("Unable to authenticate");
- connection_fatal("Unable to authenticate");
+ connection_fatal(ssh->frontend, "Unable to authenticate");
ssh->state = SSH_STATE_CLOSED;
crReturn(1);
}
continue; /* go and try password */
}
if (ssh->pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
- bombout(("Bizarre response to offer of public key"));
+ bombout((ssh,"Bizarre response to offer of public key"));
crReturn(0);
}
" our public key.\r\n");
continue; /* go and try password */
} else if (ssh->pktin.type != SSH1_SMSG_SUCCESS) {
- bombout(("Bizarre response to RSA authentication response"));
+ bombout((ssh,"Bizarre response to RSA authentication response"));
crReturn(0);
}
c_write_str(ssh, "Access denied\r\n");
logevent("Authentication refused");
} else if (ssh->pktin.type != SSH1_SMSG_SUCCESS) {
- bombout(("Strange packet received, type %d", ssh->pktin.type));
+ bombout((ssh,"Strange packet received, type %d", ssh->pktin.type));
crReturn(0);
}
}
} while (!ispkt);
if (ssh->pktin.type != SSH1_SMSG_SUCCESS
&& ssh->pktin.type != SSH1_SMSG_FAILURE) {
- bombout(("Protocol confusion"));
+ bombout((ssh,"Protocol confusion"));
crReturnV;
} else if (ssh->pktin.type == SSH1_SMSG_FAILURE) {
logevent("Agent forwarding refused");
} while (!ispkt);
if (ssh->pktin.type != SSH1_SMSG_SUCCESS
&& ssh->pktin.type != SSH1_SMSG_FAILURE) {
- bombout(("Protocol confusion"));
+ bombout((ssh,"Protocol confusion"));
crReturnV;
} else if (ssh->pktin.type == SSH1_SMSG_FAILURE) {
logevent("X11 forwarding refused");
} while (!ispkt);
if (ssh->pktin.type != SSH1_SMSG_SUCCESS
&& ssh->pktin.type != SSH1_SMSG_FAILURE) {
- bombout(("Protocol confusion"));
+ bombout((ssh,"Protocol confusion"));
crReturnV;
} else if (ssh->pktin.type == SSH1_SMSG_FAILURE) {
c_write_str(ssh, "Server refused port"
} while (!ispkt);
if (ssh->pktin.type != SSH1_SMSG_SUCCESS
&& ssh->pktin.type != SSH1_SMSG_FAILURE) {
- bombout(("Protocol confusion"));
+ bombout((ssh,"Protocol confusion"));
crReturnV;
} else if (ssh->pktin.type == SSH1_SMSG_FAILURE) {
c_write_str(ssh, "Server refused to allocate pty\r\n");
} while (!ispkt);
if (ssh->pktin.type != SSH1_SMSG_SUCCESS
&& ssh->pktin.type != SSH1_SMSG_FAILURE) {
- bombout(("Protocol confusion"));
+ bombout((ssh,"Protocol confusion"));
crReturnV;
} else if (ssh->pktin.type == SSH1_SMSG_FAILURE) {
c_write_str(ssh, "Server refused to compress\r\n");
sfree(c);
}
} else {
- bombout(("Received CHANNEL_CLOSE%s for %s channel %d\n",
+ bombout((ssh,"Received CHANNEL_CLOSE%s for %s channel %d\n",
ssh->pktin.type == SSH1_MSG_CHANNEL_CLOSE ? "" :
"_CONFIRMATION", c ? "half-open" : "nonexistent",
i));
ssh->state = SSH_STATE_CLOSED;
crReturnV;
} else {
- bombout(("Strange packet received: type %d", ssh->pktin.type));
+ bombout((ssh,"Strange packet received: type %d", ssh->pktin.type));
crReturnV;
}
} else {
int i, j, len;
if (ssh->pktin.type != SSH2_MSG_KEXINIT) {
- bombout(("expected key exchange packet from server"));
+ bombout((ssh,"expected key exchange packet from server"));
crReturn(0);
}
ssh->kex = NULL;
}
if (s->cscipher_tobe) {
if (s->warn)
- askcipher(s->cscipher_tobe->name, 1);
+ askcipher(ssh->frontend, s->cscipher_tobe->name, 1);
break;
}
}
if (!s->cscipher_tobe) {
- bombout(("Couldn't agree a client-to-server cipher (available: %s)", str));
+ bombout((ssh,"Couldn't agree a client-to-server cipher (available: %s)", str));
crReturn(0);
}
}
if (s->sccipher_tobe) {
if (s->warn)
- askcipher(s->sccipher_tobe->name, 2);
+ askcipher(ssh->frontend, s->sccipher_tobe->name, 2);
break;
}
}
if (!s->sccipher_tobe) {
- bombout(("Couldn't agree a server-to-client cipher (available: %s)", str));
+ bombout((ssh,"Couldn't agree a server-to-client cipher (available: %s)", str));
crReturn(0);
}
crWaitUntil(ispkt);
if (ssh->pktin.type != SSH2_MSG_KEX_DH_GEX_GROUP) {
- bombout(("expected key exchange group packet from server"));
+ bombout((ssh,"expected key exchange group packet from server"));
crReturn(0);
}
s->p = ssh2_pkt_getmp(ssh);
crWaitUntil(ispkt);
if (ssh->pktin.type != s->kex_reply_value) {
- bombout(("expected key exchange reply packet from server"));
+ bombout((ssh,"expected key exchange reply packet from server"));
crReturn(0);
}
ssh2_pkt_getstring(ssh, &s->hostkeydata, &s->hostkeylen);
if (!s->hkey ||
!ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen,
s->exchange_hash, 20)) {
- bombout(("Server's host key did not match the signature supplied"));
+ bombout((ssh,"Server's host key did not match the signature supplied"));
crReturn(0);
}
*/
s->keystr = ssh->hostkey->fmtkey(s->hkey);
s->fingerprint = ssh->hostkey->fingerprint(s->hkey);
- verify_ssh_host_key(ssh->savedhost, ssh->savedport, ssh->hostkey->keytype,
+ verify_ssh_host_key(ssh->frontend,
+ ssh->savedhost, ssh->savedport, ssh->hostkey->keytype,
s->keystr, s->fingerprint);
if (s->first_kex) { /* don't bother logging this in rekeys */
logevent("Host key fingerprint is:");
*/
crWaitUntil(ispkt);
if (ssh->pktin.type != SSH2_MSG_NEWKEYS) {
- bombout(("expected new-keys packet from server"));
+ bombout((ssh,"expected new-keys packet from server"));
crReturn(0);
}
ssh2_pkt_send(ssh);
crWaitUntilV(ispkt);
if (ssh->pktin.type != SSH2_MSG_SERVICE_ACCEPT) {
- bombout(("Server refused user authentication protocol"));
+ bombout((ssh,"Server refused user authentication protocol"));
crReturnV;
}
/* Load the pub half of cfg.keyfile so we notice if it's in Pageant */
if (*cfg.keyfile) {
int keytype;
- logeventf("Reading private key file \"%.150s\"", cfg.keyfile);
+ logeventf(ssh->frontend,
+ "Reading private key file \"%.150s\"", cfg.keyfile);
keytype = key_type(cfg.keyfile);
if (keytype == SSH_KEYTYPE_SSH2) {
s->publickey_blob =
&s->publickey_bloblen);
} else {
char msgbuf[256];
- logeventf("Unable to use this key file (%s)",
- key_type_to_str(keytype));
+ logeventf(ssh->frontend,
+ "Unable to use this key file (%s)",
+ key_type_to_str(keytype));
sprintf(msgbuf, "Unable to use key file \"%.150s\" (%s)\r\n",
cfg.keyfile, key_type_to_str(keytype));
c_write_str(ssh, msgbuf);
if (!s->gotit)
s->curr_prompt = 0;
} else if (ssh->pktin.type != SSH2_MSG_USERAUTH_FAILURE) {
- bombout(("Strange packet received during authentication: type %d",
+ bombout((ssh,"Strange packet received during authentication: type %d",
ssh->pktin.type));
crReturnV;
}
ssh2_pkt_addstring(ssh, "en"); /* language tag */
ssh2_pkt_send(ssh);
logevent("Unable to authenticate");
- connection_fatal("Unable to authenticate");
+ connection_fatal(ssh->frontend,
+ "Unable to authenticate");
ssh->state = SSH_STATE_CLOSED;
crReturnV;
}
ssh2_pkt_send(ssh);
crWaitUntilV(ispkt);
if (ssh->pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
- bombout(("Server refused to open a session"));
+ bombout((ssh,"Server refused to open a session"));
crReturnV;
/* FIXME: error data comes back in FAILURE packet */
}
if (ssh2_pkt_getuint32(ssh) != ssh->mainchan->localid) {
- bombout(("Server's channel confirmation cited wrong channel"));
+ bombout((ssh,"Server's channel confirmation cited wrong channel"));
crReturnV;
}
ssh->mainchan->remoteid = ssh2_pkt_getuint32(ssh);
if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
- bombout(("Unexpected response to X11 forwarding request:"
+ bombout((ssh,"Unexpected response to X11 forwarding request:"
" packet type %d", ssh->pktin.type));
crReturnV;
}
if (ssh->pktin.type != SSH2_MSG_REQUEST_SUCCESS) {
if (ssh->pktin.type != SSH2_MSG_REQUEST_FAILURE) {
- bombout(("Unexpected response to port "
+ bombout((ssh,"Unexpected response to port "
"forwarding request: packet type %d",
ssh->pktin.type));
crReturnV;
if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
- bombout(("Unexpected response to agent forwarding request:"
+ bombout((ssh,"Unexpected response to agent forwarding request:"
" packet type %d", ssh->pktin.type));
crReturnV;
}
if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
- bombout(("Unexpected response to pty request:"
+ bombout((ssh,"Unexpected response to pty request:"
" packet type %d", ssh->pktin.type));
crReturnV;
}
} while (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
- bombout(("Unexpected response to shell/command request:"
+ bombout((ssh,"Unexpected response to shell/command request:"
" packet type %d", ssh->pktin.type));
crReturnV;
}
ssh->fallback_cmd = TRUE;
continue;
}
- bombout(("Server refused to start a shell/command"));
+ bombout((ssh,"Server refused to start a shell/command"));
crReturnV;
} else {
logevent("Started a shell/command");
c = find234(ssh->channels, &i, ssh_channelfind);
if (!c || ((int)c->remoteid) == -1) {
- bombout(("Received CHANNEL_CLOSE for %s channel %d\n",
+ bombout((ssh,"Received CHANNEL_CLOSE for %s channel %d\n",
c ? "half-open" : "nonexistent", i));
}
/* Do pre-close processing on the channel. */
ssh2_pkt_send(ssh);
}
} else {
- bombout(("Strange packet received: type %d", ssh->pktin.type));
+ bombout((ssh,"Strange packet received: type %d", ssh->pktin.type));
crReturnV;
}
} else {
ssh->sccipher = NULL;
ssh->sc_cipher_ctx = NULL;
ssh->csmac = NULL;
- ssh->sc_mac_ctx = NULL;
+ ssh->cs_mac_ctx = NULL;
ssh->scmac = NULL;
ssh->sc_mac_ctx = NULL;
ssh->cscomp = NULL;
ssh->size_needed = FALSE;
ssh->eof_needed = FALSE;
ssh->ldisc = NULL;
+ ssh->logctx = NULL;
{
static const struct Packet empty = { 0, 0, NULL, NULL, 0 };
ssh->pktin = ssh->pktout = empty;
ssh->ldisc = ldisc;
}
+static void ssh_provide_logctx(void *handle, void *logctx)
+{
+ Ssh ssh = (Ssh) handle;
+ ssh->logctx = logctx;
+}
+
static int ssh_return_exitcode(void *handle)
{
Ssh ssh = (Ssh) handle;
ssh_sendok,
ssh_ldisc,
ssh_provide_ldisc,
+ ssh_provide_logctx,
ssh_unthrottle,
22
};
void random_add_noise(void *noise, int length);
void random_add_heavynoise(void *noise, int length);
-void logevent(char *);
+void logevent(void *, char *);
/* Allocate and register a new channel for port forwarding */
void *new_sock_channel(void *handle, Socket s);
dctx->currlentable = dctx->currdisttable = dctx->lenlentable = NULL;
dctx->bits = 0;
dctx->nbits = 0;
+ dctx->winpos = 0;
return dctx;
}
sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG);
}
-static void log_option(char *sender, int cmd, int option)
+static void log_option(Telnet telnet, char *sender, int cmd, int option)
{
char buf[50];
sprintf(buf, "%s:\t%s %s", sender,
(cmd == WILL ? "WILL" : cmd == WONT ? "WONT" :
cmd == DO ? "DO" : cmd == DONT ? "DONT" : "<??>"),
telopt(option));
- logevent(buf);
+ logevent(telnet->frontend, buf);
}
static void send_opt(Telnet telnet, int cmd, int option)
b[1] = cmd;
b[2] = option;
telnet->bufsize = sk_write(telnet->s, b, 3);
- log_option("client", cmd, option);
+ log_option(telnet, "client", cmd, option);
}
static void deactivate_option(Telnet telnet, const struct Opt *o)
{
const struct Opt *const *o;
- log_option("server", cmd, option);
+ log_option(telnet, "server", cmd, option);
for (o = opts; *o; o++) {
if ((*o)->option == option && (*o)->ack == cmd) {
switch (telnet->opt_states[(*o)->index]) {
b[n] = IAC;
b[n + 1] = SE;
telnet->bufsize = sk_write(telnet->s, b, n + 2);
- logevent("server:\tSB TSPEED SEND");
+ logevent(telnet->frontend, "server:\tSB TSPEED SEND");
sprintf(logbuf, "client:\tSB TSPEED IS %s", cfg.termspeed);
- logevent(logbuf);
+ logevent(telnet->frontend, logbuf);
} else
- logevent("server:\tSB TSPEED <something weird>");
+ logevent(telnet->frontend, "server:\tSB TSPEED <something weird>");
break;
case TELOPT_TTYPE:
if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) {
b[n + 5] = SE;
telnet->bufsize = sk_write(telnet->s, b, n + 6);
b[n + 4] = 0;
- logevent("server:\tSB TTYPE SEND");
+ logevent(telnet->frontend, "server:\tSB TTYPE SEND");
sprintf(logbuf, "client:\tSB TTYPE IS %s", b + 4);
- logevent(logbuf);
+ logevent(telnet->frontend, logbuf);
} else
- logevent("server:\tSB TTYPE <something weird>\r\n");
+ logevent(telnet->frontend, "server:\tSB TTYPE <something weird>\r\n");
break;
case TELOPT_OLD_ENVIRON:
case TELOPT_NEW_ENVIRON:
char logbuf[50];
p++;
sprintf(logbuf, "server:\tSB %s SEND", telopt(telnet->sb_opt));
- logevent(logbuf);
+ logevent(telnet->frontend, logbuf);
if (telnet->sb_opt == TELOPT_OLD_ENVIRON) {
if (cfg.rfc_environ) {
value = RFC_VALUE;
telnet->bufsize = sk_write(telnet->s, b, n);
sprintf(logbuf, "client:\tSB %s IS %s", telopt(telnet->sb_opt),
n == 6 ? "<nothing>" : "<stuff>");
- logevent(logbuf);
+ logevent(telnet->frontend, logbuf);
}
break;
}
}
if (error_msg) {
/* A socket error has occurred. */
- logevent(error_msg);
+ logevent(telnet->frontend, error_msg);
connection_fatal("%s", error_msg);
} /* Otherwise, the remote side closed the connection normally. */
return 0;
{
char buf[200];
sprintf(buf, "Looking up host \"%.170s\"", host);
- logevent(buf);
+ logevent(telnet->frontend, buf);
}
addr = sk_namelookup(host, realhost);
if ((err = sk_addr_error(addr)))
char buf[200], addrbuf[100];
sk_getaddr(addr, addrbuf, 100);
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
- logevent(buf);
+ logevent(telnet->frontend, buf);
}
telnet->s = new_connection(addr, *realhost, port, 0, 1,
nodelay, (Plug) telnet);
sprintf(logbuf, "client:\tSB NAWS %d,%d",
((unsigned char) b[3] << 8) + (unsigned char) b[4],
((unsigned char) b[5] << 8) + (unsigned char) b[6]);
- logevent(logbuf);
+ logevent(telnet->frontend, logbuf);
}
/*
telnet->ldisc = ldisc;
}
+static void telnet_provide_logctx(void *handle, void *logctx)
+{
+ /* This is a stub. */
+}
+
static int telnet_exitcode(void *handle)
{
Telnet telnet = (Telnet) handle;
telnet_sendok,
telnet_ldisc,
telnet_provide_ldisc,
+ telnet_provide_logctx,
telnet_unthrottle,
23
};
void term_update(Terminal *term)
{
Context ctx;
- ctx = get_ctx();
+ ctx = get_ctx(term->frontend);
if (ctx) {
int need_sbar_update = term->seen_disp_event;
if (term->seen_disp_event && cfg.scroll_on_disp) {
if (need_sbar_update)
update_sbar(term);
do_paint(term, ctx, TRUE);
- sys_cursor(term->curs.x, term->curs.y - term->disptop);
+ sys_cursor(term->frontend, term->curs.x, term->curs.y - term->disptop);
free_ctx(ctx);
}
}
swap_screen(term, 0, FALSE, FALSE);
if (cfg.no_mouse_rep) {
term->xterm_mouse = 0;
- set_raw_mouse_mode(0);
+ set_raw_mouse_mode(term->frontend, 0);
}
if (cfg.no_remote_charset) {
term->cset_attr[0] = term->cset_attr[1] = ATTR_ASCII;
/*
* Initialise the terminal.
*/
-Terminal *term_init(void)
+Terminal *term_init(void *frontend)
{
Terminal *term;
* that need it.
*/
term = smalloc(sizeof(Terminal));
+ term->frontend = frontend;
+ term->logctx = NULL;
term->compatibility_level = TM_PUTTY;
strcpy(term->id_string, "\033[?6c");
term->last_blink = term->last_tblink = 0;
nscroll = count234(term->scrollback);
- set_sbar(nscroll + term->rows, nscroll + term->disptop, term->rows);
+ set_sbar(term->frontend, nscroll + term->rows,
+ nscroll + term->disptop, term->rows);
}
/*
case 3: /* 80/132 columns */
deselect(term);
if (!cfg.no_remote_resize)
- request_resize(state ? 132 : 80, term->rows);
+ request_resize(term->frontend, state ? 132 : 80, term->rows);
term->reset_132 = state;
break;
case 5: /* reverse video */
break;
case 1000: /* xterm mouse 1 */
term->xterm_mouse = state ? 1 : 0;
- set_raw_mouse_mode(state);
+ set_raw_mouse_mode(term->frontend, state);
break;
case 1002: /* xterm mouse 2 */
term->xterm_mouse = state ? 2 : 0;
- set_raw_mouse_mode(state);
+ set_raw_mouse_mode(term->frontend, state);
break;
case 1047: /* alternate screen */
compatibility(OTHER);
case 0:
case 1:
if (!cfg.no_remote_wintitle)
- set_icon(term->osc_string);
+ set_icon(term->frontend, term->osc_string);
if (term->esc_args[0] == 1)
break;
/* fall through: parameter 0 means set both */
case 2:
case 21:
if (!cfg.no_remote_wintitle)
- set_title(term->osc_string);
+ set_title(term->frontend, term->osc_string);
break;
}
}
* Optionally log the session traffic to a file. Useful for
* debugging and possibly also useful for actual logging.
*/
- if (cfg.logtype == LGTYP_DEBUG)
- logtraffic((unsigned char) c, LGTYP_DEBUG);
+ if (cfg.logtype == LGTYP_DEBUG && term->logctx)
+ logtraffic(term->logctx, (unsigned char) c, LGTYP_DEBUG);
} else {
c = unget;
unget = -1;
term->vbell_startpoint = ticks;
term_update(term);
} else
- beep(cfg.beep);
+ beep(term->frontend, cfg.beep);
}
term->disptop = 0;
}
fix_cpos;
term->seen_disp_event = TRUE;
term->paste_hold = 0;
- logtraffic((unsigned char) c, LGTYP_ASCII);
+ if (term->logctx)
+ logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
break;
case '\014':
if (has_compat(SCOANSI)) {
term->wrapnext = FALSE;
term->seen_disp_event = 1;
term->paste_hold = 0;
- logtraffic((unsigned char) c, LGTYP_ASCII);
+ if (term->logctx)
+ logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
break;
case '\t':
{
incpos(cursplus);
check_selection(term, term->curs, cursplus);
}
- if ((c & CSET_MASK) == ATTR_ASCII || (c & CSET_MASK) == 0)
- logtraffic((unsigned char) c, LGTYP_ASCII);
+ if (((c & CSET_MASK) == ATTR_ASCII || (c & CSET_MASK) == 0) &&
+ term->logctx)
+ logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
{
extern int wcwidth(wchar_t ucs);
int width = 0;
ldisc_send(term->ldisc, NULL, 0, 0);
if (term->reset_132) {
if (!cfg.no_remote_resize)
- request_resize(80, term->rows);
+ request_resize(term->frontend, 80, term->rows);
term->reset_132 = 0;
}
fix_cpos;
term->esc_args[0] >= 24)) {
compatibility(VT340TEXT);
if (!cfg.no_remote_resize)
- request_resize(term->cols,
+ request_resize(term->frontend, term->cols,
def(term->esc_args[0], 24));
deselect(term);
} else if (term->esc_nargs >= 1 &&
int x, y, len;
char buf[80], *p;
case 1:
- set_iconic(FALSE);
+ set_iconic(term->frontend, FALSE);
break;
case 2:
- set_iconic(TRUE);
+ set_iconic(term->frontend, TRUE);
break;
case 3:
if (term->esc_nargs >= 3) {
if (!cfg.no_remote_resize)
- move_window(def(term->esc_args[1], 0),
+ move_window(term->frontend,
+ def(term->esc_args[1], 0),
def(term->esc_args[2], 0));
}
break;
* manage it. */
break;
case 5:
- set_zorder(TRUE); /* move to top */
+ /* move to top */
+ set_zorder(term->frontend, TRUE);
break;
case 6:
- set_zorder(FALSE); /* move to bottom */
+ /* move to bottom */
+ set_zorder(term->frontend, FALSE);
break;
case 7:
- refresh_window();
+ refresh_window(term->frontend);
break;
case 8:
if (term->esc_nargs >= 3) {
if (!cfg.no_remote_resize)
- request_resize(def(term->esc_args[2], cfg.width),
+ request_resize(term->frontend,
+ def(term->esc_args[2], cfg.width),
def(term->esc_args[1], cfg.height));
}
break;
case 9:
if (term->esc_nargs >= 2)
- set_zoomed(term->esc_args[1] ?
+ set_zoomed(term->frontend,
+ term->esc_args[1] ?
TRUE : FALSE);
break;
case 11:
if (term->ldisc)
ldisc_send(term->ldisc,
- is_iconic() ? "\033[1t" :
- "\033[2t", 4, 0);
+ is_iconic(term->frontend) ?
+ "\033[1t" : "\033[2t", 4, 0);
break;
case 13:
if (term->ldisc) {
- get_window_pos(&x, &y);
+ get_window_pos(term->frontend, &x, &y);
len = sprintf(buf, "\033[3;%d;%dt", x, y);
ldisc_send(term->ldisc, buf, len, 0);
}
break;
case 14:
if (term->ldisc) {
- get_window_pixels(&x, &y);
+ get_window_pixels(term->frontend, &x, &y);
len = sprintf(buf, "\033[4;%d;%dt", x, y);
ldisc_send(term->ldisc, buf, len, 0);
}
break;
case 20:
if (term->ldisc) {
- p = get_window_title(TRUE);
+ p = get_window_title(term->frontend, TRUE);
len = strlen(p);
ldisc_send(term->ldisc, "\033]L", 3, 0);
ldisc_send(term->ldisc, p, len, 0);
break;
case 21:
if (term->ldisc) {
- p = get_window_title(FALSE);
+ p = get_window_title(term->frontend,FALSE);
len = strlen(p);
ldisc_send(term->ldisc, "\033]l", 3, 0);
ldisc_send(term->ldisc, p, len, 0);
compatibility(VT420);
if (term->esc_nargs == 1 && term->esc_args[0] > 0) {
if (!cfg.no_remote_resize)
- request_resize(term->cols,
+ request_resize(term->frontend, term->cols,
def(term->esc_args[0],
cfg.height));
deselect(term);
compatibility(VT340TEXT);
if (term->esc_nargs <= 1) {
if (!cfg.no_remote_resize)
- request_resize(def(term->esc_args[0],
+ request_resize(term->frontend,
+ def(term->esc_args[0],
cfg.width), term->rows);
deselect(term);
}
term->osc_strlen = 0;
break;
case 'R': /* Linux palette reset */
- palette_reset();
+ palette_reset(term->frontend);
term_invalidate(term);
term->termstate = TOPLEVEL;
break;
}
term->osc_string[term->osc_strlen++] = val;
if (term->osc_strlen >= 7) {
- palette_set(term->osc_string[0],
+ palette_set(term->frontend, term->osc_string[0],
term->osc_string[1] * 16 + term->osc_string[2],
term->osc_string[3] * 16 + term->osc_string[4],
term->osc_string[5] * 16 + term->osc_string[6]);
wblen++;
*wbptr++ = 0;
#endif
- write_clip(workbuf, wblen, FALSE); /* transfer to clipboard */
+ write_clip(term->frontend, workbuf, wblen, FALSE); /* transfer to clipbd */
if (buflen > 0) /* indicates we allocated this buffer */
sfree(workbuf);
}
wchar_t *data;
int len;
- get_clip(&data, &len);
+ get_clip(term->frontend, &data, &len);
if (data && len > 0) {
wchar_t *p, *q;
term->paste_pos = term->paste_hold = term->paste_len = 0;
}
}
- get_clip(NULL, NULL);
+ get_clip(term->frontend, NULL, NULL);
}
void term_mouse(Terminal *term, Mouse_Button b, Mouse_Action a, int x, int y,
return;
}
- b = translate_button(b);
+ b = translate_button(term->frontend, b);
/*
* Set the selection type (rectangular or normal) at the start
|| a == MA_2CLK || a == MA_3CLK
#endif
)) {
- request_paste();
+ request_paste(term->frontend);
}
term_update(term);
*/
return 0;
}
+
+void term_provide_logctx(Terminal *term, void *logctx)
+{
+ term->logctx = logctx;
+}
void *resize_ctx;
void *ldisc;
+
+ void *frontend;
+
+ void *logctx;
};
#define in_utf(term) ((term)->utf || line_codepage==CP_UTF8)
Backend *back;
void *backhandle;
Terminal *term;
+ void *logctx;
+};
+
+struct draw_ctx {
+ GdkGC *gc;
+ struct gui_data *inst;
};
-static struct gui_data the_inst;
-static struct gui_data *inst = &the_inst; /* so we always write `inst->' */
static int send_raw_mouse;
void ldisc_update(void *frontend, int echo, int edit)
*/
}
-int askappend(char *filename)
+int askappend(void *frontend, char *filename)
{
/*
* Logging in an xterm-alike is liable to be something you only
return 2;
}
-void logevent(char *string)
+void logevent(void *frontend, char *string)
{
/*
* This is not a very helpful function: events are logged
*/
}
-int font_dimension(int which) /* 0 for width, 1 for height */
+int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */
{
+ struct gui_data *inst = (struct gui_data *)frontend;
+
if (which)
return inst->font_height;
else
* mouse or a means of faking it, and there is no need to switch
* buttons around at all.
*/
-Mouse_Button translate_button(Mouse_Button button)
+Mouse_Button translate_button(void *frontend, Mouse_Button button)
{
+ /* struct gui_data *inst = (struct gui_data *)frontend; */
+
if (button == MBT_LEFT)
return MBT_SELECT;
if (button == MBT_MIDDLE)
* Minimise or restore the window in response to a server-side
* request.
*/
-void set_iconic(int iconic)
+void set_iconic(void *frontend, int iconic)
{
/*
* GTK 1.2 doesn't know how to do this.
*/
#if GTK_CHECK_VERSION(2,0,0)
+ struct gui_data *inst = (struct gui_data *)frontend;
if (iconic)
gtk_window_iconify(GTK_WINDOW(inst->window));
else
/*
* Move the window in response to a server-side request.
*/
-void move_window(int x, int y)
+void move_window(void *frontend, int x, int y)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
/*
* I assume that when the GTK version of this call is available
* we should use it. Not sure how it differs from the GDK one,
* Move the window to the top or bottom of the z-order in response
* to a server-side request.
*/
-void set_zorder(int top)
+void set_zorder(void *frontend, int top)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
if (top)
gdk_window_raise(inst->window->window);
else
/*
* Refresh the window in response to a server-side request.
*/
-void refresh_window(void)
+void refresh_window(void *frontend)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
term_invalidate(inst->term);
}
* Maximise or restore the window in response to a server-side
* request.
*/
-void set_zoomed(int zoomed)
+void set_zoomed(void *frontend, int zoomed)
{
/*
* GTK 1.2 doesn't know how to do this.
*/
#if GTK_CHECK_VERSION(2,0,0)
+ struct gui_data *inst = (struct gui_data *)frontend;
if (iconic)
gtk_window_maximize(GTK_WINDOW(inst->window));
else
/*
* Report whether the window is iconic, for terminal reports.
*/
-int is_iconic(void)
+int is_iconic(void *frontend)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
return !gdk_window_is_viewable(inst->window->window);
}
/*
* Report the window's position, for terminal reports.
*/
-void get_window_pos(int *x, int *y)
+void get_window_pos(void *frontend, int *x, int *y)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
/*
* I assume that when the GTK version of this call is available
* we should use it. Not sure how it differs from the GDK one,
/*
* Report the window's pixel size, for terminal reports.
*/
-void get_window_pixels(int *x, int *y)
+void get_window_pixels(void *frontend, int *x, int *y)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
/*
* I assume that when the GTK version of this call is available
* we should use it. Not sure how it differs from the GDK one,
/*
* Return the window or icon title.
*/
-char *get_window_title(int icon)
+char *get_window_title(void *frontend, int icon)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
return icon ? inst->wintitle : inst->icontitle;
}
return FALSE;
}
-void show_mouseptr(int show)
+static void show_mouseptr(struct gui_data *inst, int show)
{
if (!cfg.hide_mouseptr)
show = 1;
gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
- /* struct gui_data *inst = (struct gui_data *)data; */
+ struct gui_data *inst = (struct gui_data *)data;
/*
* Pass the exposed rectangle to terminal.c, which will call us
gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
- /* struct gui_data *inst = (struct gui_data *)data; */
+ struct gui_data *inst = (struct gui_data *)data;
char output[32];
int start, end;
* Neither does Shift-Ins.
*/
if (event->keyval == GDK_Insert && (event->state & GDK_SHIFT_MASK)) {
- request_paste();
+ request_paste(inst);
return TRUE;
}
#endif
ldisc_send(inst->ldisc, output+start, end-start, 1);
- show_mouseptr(0);
+ show_mouseptr(inst, 0);
term_seen_key_event(inst->term);
term_out(inst->term);
}
struct gui_data *inst = (struct gui_data *)data;
int shift, ctrl, alt, x, y, button, act;
- show_mouseptr(1);
+ show_mouseptr(inst, 1);
if (event->button == 4 && event->type == GDK_BUTTON_PRESS) {
term_scroll(inst->term, 0, -5);
struct gui_data *inst = (struct gui_data *)data;
int shift, ctrl, alt, x, y, button;
- show_mouseptr(1);
+ show_mouseptr(inst, 1);
shift = event->state & GDK_SHIFT_MASK;
ctrl = event->state & GDK_CONTROL_MASK;
gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
{
+ struct gui_data *inst = (struct gui_data *)data;
inst->term->has_focus = event->in;
term_out(inst->term);
term_update(inst->term);
- show_mouseptr(1);
+ show_mouseptr(inst, 1);
return FALSE;
}
/*
* set or clear the "raw mouse message" mode
*/
-void set_raw_mouse_mode(int activate)
+void set_raw_mouse_mode(void *frontend, int activate)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
activate = activate && !cfg.no_mouse_rep;
send_raw_mouse = activate;
if (send_raw_mouse)
inst->currcursor = inst->rawcursor;
else
inst->currcursor = inst->textcursor;
- show_mouseptr(inst->mouseptr_visible);
+ show_mouseptr(inst, inst->mouseptr_visible);
}
-void request_resize(int w, int h)
+void request_resize(void *frontend, int w, int h)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
int large_x, large_y;
int offset_x, offset_y;
int area_x, area_y;
* bogus size request which guarantees to be bigger than the
* current size of the drawing area.
*/
- get_window_pixels(&large_x, &large_y);
+ get_window_pixels(inst, &large_x, &large_y);
large_x += 32;
large_y += 32;
#endif
}
-void real_palette_set(int n, int r, int g, int b)
+static void real_palette_set(struct gui_data *inst, int n, int r, int g, int b)
{
gboolean success[1];
n, r, g, b);
}
-void set_window_background(void)
+void set_window_background(struct gui_data *inst)
{
if (inst->area && inst->area->window)
gdk_window_set_background(inst->area->window, &inst->cols[18]);
gdk_window_set_background(inst->window->window, &inst->cols[18]);
}
-void palette_set(int n, int r, int g, int b)
+void palette_set(void *frontend, int n, int r, int g, int b)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
static const int first[21] = {
0, 2, 4, 6, 8, 10, 12, 14,
1, 3, 5, 7, 9, 11, 13, 15,
16, 17, 18, 20, 22
};
- real_palette_set(first[n], r, g, b);
+ real_palette_set(inst, first[n], r, g, b);
if (first[n] >= 18)
- real_palette_set(first[n] + 1, r, g, b);
+ real_palette_set(inst, first[n] + 1, r, g, b);
if (first[n] == 18)
- set_window_background();
+ set_window_background(inst);
}
-void palette_reset(void)
+void palette_reset(void *frontend)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
/* This maps colour indices in cfg to those used in inst->cols. */
static const int ww[] = {
6, 7, 8, 9, 10, 11, 12, 13,
i, cfg.colours[i][0], cfg.colours[i][1], cfg.colours[i][2]);
}
- set_window_background();
+ set_window_background(inst);
}
-void write_clip(wchar_t * data, int len, int must_deselect)
+void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
if (inst->pasteout_data)
sfree(inst->pasteout_data);
inst->pasteout_data = smalloc(len);
void selection_get(GtkWidget *widget, GtkSelectionData *seldata,
guint info, guint time_stamp, gpointer data)
{
+ struct gui_data *inst = (struct gui_data *)data;
gtk_selection_data_set(seldata, GDK_SELECTION_TYPE_STRING, 8,
inst->pasteout_data, inst->pasteout_data_len);
}
gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata,
gpointer data)
{
+ struct gui_data *inst = (struct gui_data *)data;
term_deselect(inst->term);
if (inst->pasteout_data)
sfree(inst->pasteout_data);
return TRUE;
}
-void request_paste(void)
+void request_paste(void *frontend)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
/*
* In Unix, pasting is asynchronous: all we can do at the
* moment is to call gtk_selection_convert(), and when the data
void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
gpointer data)
{
+ struct gui_data *inst = (struct gui_data *)data;
+
if (seldata->length <= 0 ||
seldata->type != GDK_SELECTION_TYPE_STRING)
return; /* Nothing happens. */
}
-void get_clip(wchar_t ** p, int *len)
+void get_clip(void *frontend, wchar_t ** p, int *len)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
+
if (p) {
*p = inst->pastein_data;
*len = inst->pastein_data_len;
}
}
-void set_title(char *title)
+void set_title(void *frontend, char *title)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
strncpy(inst->wintitle, title, lenof(inst->wintitle));
inst->wintitle[lenof(inst->wintitle)-1] = '\0';
gtk_window_set_title(GTK_WINDOW(inst->window), inst->wintitle);
}
-void set_icon(char *title)
+void set_icon(void *frontend, char *title)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
strncpy(inst->icontitle, title, lenof(inst->icontitle));
inst->icontitle[lenof(inst->icontitle)-1] = '\0';
gdk_window_set_icon_name(inst->window->window, inst->icontitle);
}
-void set_sbar(int total, int start, int page)
+void set_sbar(void *frontend, int total, int start, int page)
{
+ struct gui_data *inst = (struct gui_data *)frontend;
if (!cfg.scrollbar)
return;
inst->sbar_adjust->lower = 0;
void scrollbar_moved(GtkAdjustment *adj, gpointer data)
{
+ struct gui_data *inst = (struct gui_data *)data;
+
if (!cfg.scrollbar)
return;
if (!inst->ignore_sbar)
term_scroll(inst->term, 1, (int)adj->value);
}
-void sys_cursor(int x, int y)
+void sys_cursor(void *frontend, int x, int y)
{
/*
* This is meaningless under X.
*/
}
-void beep(int mode)
+void beep(void *frontend, int mode)
{
gdk_beep();
}
return 1;
}
-Context get_ctx(void)
+Context get_ctx(void *frontend)
{
- GdkGC *gc;
+ struct gui_data *inst = (struct gui_data *)frontend;
+ struct draw_ctx *dctx;
+
if (!inst->area->window)
return NULL;
- gc = gdk_gc_new(inst->area->window);
- return gc;
+
+ dctx = smalloc(sizeof(*dctx));
+ dctx->inst = inst;
+ dctx->gc = gdk_gc_new(inst->area->window);
+ return dctx;
}
void free_ctx(Context ctx)
{
- GdkGC *gc = (GdkGC *)ctx;
+ struct draw_ctx *dctx = (struct draw_ctx *)ctx;
+ /* struct gui_data *inst = dctx->inst; */
+ GdkGC *gc = dctx->gc;
gdk_gc_unref(gc);
+ sfree(dctx);
}
/*
void do_text_internal(Context ctx, int x, int y, char *text, int len,
unsigned long attr, int lattr)
{
+ struct draw_ctx *dctx = (struct draw_ctx *)ctx;
+ struct gui_data *inst = dctx->inst;
+ GdkGC *gc = dctx->gc;
+
int nfg, nbg, t, fontid, shadow;
- GdkGC *gc = (GdkGC *)ctx;
/*
* NYI:
void do_text(Context ctx, int x, int y, char *text, int len,
unsigned long attr, int lattr)
{
- GdkGC *gc = (GdkGC *)ctx;
+ struct draw_ctx *dctx = (struct draw_ctx *)ctx;
+ struct gui_data *inst = dctx->inst;
+ GdkGC *gc = dctx->gc;
do_text_internal(ctx, x, y, text, len, attr, lattr);
void do_cursor(Context ctx, int x, int y, char *text, int len,
unsigned long attr, int lattr)
{
+ struct draw_ctx *dctx = (struct draw_ctx *)ctx;
+ struct gui_data *inst = dctx->inst;
+ GdkGC *gc = dctx->gc;
+
int passive;
- GdkGC *gc = (GdkGC *)ctx;
if (attr & TATTR_PASCURS) {
attr &= ~TATTR_PASCURS;
len*inst->font_width, inst->font_height);
}
-GdkCursor *make_mouse_ptr(int cursor_val)
+GdkCursor *make_mouse_ptr(struct gui_data *inst, int cursor_val)
{
/*
* Truly hideous hack: GTK doesn't allow us to set the mouse
exit(1);
}
-char *get_x_display(void)
+char *get_x_display(void *frontend)
{
return gdk_get_display();
}
{
extern int pty_master_fd; /* declared in pty.c */
extern void pty_pre_init(void); /* declared in pty.c */
+ struct gui_data *inst;
pty_pre_init();
exit(1);
/*
- * Initialise the whole instance structure to zeroes
+ * Create an instance structure and initialise to zeroes
*/
+ inst = smalloc(sizeof(*inst));
memset(inst, 0, sizeof(*inst));
inst->fonts[0] = gdk_font_load(cfg.font);
inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
if (cfg.wintitle[0])
- set_title(cfg.wintitle);
+ set_title(inst, cfg.wintitle);
else
- set_title("pterm");
+ set_title(inst, "pterm");
/*
* Set up the colour map.
*/
- palette_reset();
+ palette_reset(inst);
inst->area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area),
gtk_widget_show(GTK_WIDGET(inst->hbox));
gtk_widget_show(inst->window);
- set_window_background();
+ set_window_background(inst);
- inst->textcursor = make_mouse_ptr(GDK_XTERM);
- inst->rawcursor = make_mouse_ptr(GDK_LEFT_PTR);
- inst->blankcursor = make_mouse_ptr(-1);
- make_mouse_ptr(-2); /* clean up cursor font */
+ inst->textcursor = make_mouse_ptr(inst, GDK_XTERM);
+ inst->rawcursor = make_mouse_ptr(inst, GDK_LEFT_PTR);
+ inst->blankcursor = make_mouse_ptr(inst, -1);
+ make_mouse_ptr(inst, -2); /* clean up cursor font */
inst->currcursor = inst->textcursor;
- show_mouseptr(1);
+ show_mouseptr(inst, 1);
- inst->term = term_init();
+ inst->term = term_init(inst);
+ inst->logctx = log_init(inst);
+ term_provide_logctx(inst->term, inst->logctx);
inst->back = &pty_backend;
inst->back->init((void *)inst->term, &inst->backhandle, NULL, 0, NULL, 0);
+ inst->back->provide_logctx(inst->backhandle, inst->logctx);
term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle);
#endif
int pty_master_fd;
+static void *pty_frontend;
static char pty_name[FILENAME_MAX];
static int pty_stamped_utmp = 0;
static int pty_child_pid;
int slavefd;
pid_t pid, pgrp;
+ pty_frontend = frontend;
*backend_handle = NULL; /* we can't sensibly use this, sadly */
pty_term_width = cfg.width;
if (!cfg.stamp_utmp)
close(pty_utmp_helper_pipe); /* just let the child process die */
else {
- char *location = get_x_display();
+ char *location = get_x_display(pty_frontend);
int len = strlen(location)+1, pos = 0; /* +1 to include NUL */
while (pos < len) {
int ret = write(pty_utmp_helper_pipe, location+pos, len - pos);
size.ws_row = (unsigned short)pty_term_height;
size.ws_col = (unsigned short)pty_term_width;
- size.ws_xpixel = (unsigned short) pty_term_width * font_dimension(0);
- size.ws_ypixel = (unsigned short) pty_term_height * font_dimension(1);
+ size.ws_xpixel = (unsigned short) pty_term_width *
+ font_dimension(pty_frontend, 0);
+ size.ws_ypixel = (unsigned short) pty_term_height *
+ font_dimension(pty_frontend, 1);
ioctl(pty_master_fd, TIOCSWINSZ, (void *)&size);
return;
}
/* This is a stub. */
}
+static void pty_provide_logctx(void *handle, void *logctx)
+{
+ /* This is a stub. */
+}
+
static int pty_exitcode(void *handle)
{
if (!pty_child_dead)
pty_sendok,
pty_ldisc,
pty_provide_ldisc,
+ pty_provide_logctx,
pty_unthrottle,
1
};
#define BYTE unsigned char
/* Things pty.c needs from pterm.c */
-char *get_x_display(void);
-int font_dimension(int which); /* 0 for width, 1 for height */
+char *get_x_display(void *frontend);
+int font_dimension(void *frontend, int which);/* 0 for width, 1 for height */
/* Things uxstore.c needs from pterm.c */
char *app_name; /* for doing resource lookups */
memcpy(p, sel_nl, sizeof(sel_nl));
p += sizeof(sel_nl);
}
- write_aclip(clipdata, size, TRUE);
+ write_aclip(NULL, clipdata, size, TRUE);
sfree(clipdata);
}
sfree(selitems);
return ret;
}
-void logevent(char *string)
+void logevent(void *frontend, char *string)
{
char timebuf[40];
time_t t;
- log_eventlog(string);
+ log_eventlog(logctx, string);
if (nevents >= negsize) {
negsize += 64;
DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc);
}
-void verify_ssh_host_key(char *host, int port, char *keytype,
+void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
char *keystr, char *fingerprint)
{
int ret;
* below the configured 'warn' threshold).
* cs: 0 = both ways, 1 = client->server, 2 = server->client
*/
-void askcipher(char *ciphername, int cs)
+void askcipher(void *frontend, char *ciphername, int cs)
{
static const char mbtitle[] = "PuTTY Security Alert";
static const char msg[] =
* Ask whether to wipe a session log file before writing to it.
* Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
*/
-int askappend(char *filename)
+int askappend(void *frontend, char *filename)
{
static const char mbtitle[] = "PuTTY Log to File";
static const char msgtemplate[] =
/*
* Warn about the obsolescent key file format.
+ *
+ * Uniquely among these functions, this one does _not_ expect a
+ * frontend handle. This means that if PuTTY is ported to a
+ * platform which requires frontend handles, this function will be
+ * an anomaly. Fortunately, the problem it addresses will not have
+ * been present on that platform, so it can plausibly be
+ * implemented as an empty function.
*/
void old_keyfile_warning(void)
{
static void *ldisc;
static Backend *back;
static void *backhandle;
-static Terminal *term;
#define FONT_NORMAL 0
#define FONT_BOLD 1
hwnd = NULL;
- term = term_init();
+ term = term_init(NULL);
+ logctx = log_init(NULL);
+ term_provide_logctx(term, logctx);
cfgtopalette();
error = back->init((void *)term, &backhandle,
cfg.host, cfg.port, &realhost, cfg.tcp_nodelay);
+ back->provide_logctx(backhandle, logctx);
if (error) {
sprintf(msg, "Unable to open connection to\n"
"%.800s\n" "%s", cfg.host, error);
title = msg;
}
sfree(realhost);
- set_title(title);
- set_icon(title);
+ set_title(NULL, title);
+ set_icon(NULL, title);
}
/*
/*
* Open the initial log file if there is one.
*/
- logfopen();
+ logfopen(logctx);
/*
* Finally show the window!
/*
* set or clear the "raw mouse message" mode
*/
-void set_raw_mouse_mode(int activate)
+void set_raw_mouse_mode(void *frontend, int activate)
{
activate = activate && !cfg.no_mouse_rep;
send_raw_mouse = activate;
/*
* Print a message box and close the connection.
*/
-void connection_fatal(char *fmt, ...)
+void connection_fatal(void *frontend, char *fmt, ...)
{
va_list ap;
char stuff[200];
}
}
-void request_resize(int w, int h)
+void request_resize(void *frontend, int w, int h)
{
int width, height;
* Translate a raw mouse button designation (LEFT, MIDDLE, RIGHT)
* into a cooked one (SELECT, EXTEND, PASTE).
*/
-Mouse_Button translate_button(Mouse_Button button)
+Mouse_Button translate_button(void *frontend, Mouse_Button button)
{
if (button == MBT_LEFT)
return MBT_SELECT;
if (strcmp(prev_cfg.logfilename, cfg.logfilename) ||
prev_cfg.logtype != cfg.logtype) {
- logfclose(); /* reset logging */
- logfopen();
+ logfclose(logctx); /* reset logging */
+ logfopen(logctx);
}
sfree(logpal);
init_lvl = 2;
}
- set_title(cfg.wintitle);
+ set_title(NULL, cfg.wintitle);
if (IsIconic(hwnd)) {
SetWindowText(hwnd,
cfg.win_name_always ? window_name :
break;
case WM_PALETTECHANGED:
if ((HWND) wParam != hwnd && pal != NULL) {
- HDC hdc = get_ctx();
+ HDC hdc = get_ctx(NULL);
if (hdc) {
if (RealizePalette(hdc) > 0)
UpdateColors(hdc);
break;
case WM_QUERYNEWPALETTE:
if (pal != NULL) {
- HDC hdc = get_ctx();
+ HDC hdc = get_ctx(NULL);
if (hdc) {
if (RealizePalette(hdc) > 0)
UpdateColors(hdc);
* helper software tracks the system caret, so we should arrange to
* have one.)
*/
-void sys_cursor(int x, int y)
+void sys_cursor(void *frontend, int x, int y)
{
int cx, cy;
return -1;
}
-void request_paste(void)
+void request_paste(void *frontend)
{
/*
* In Windows, pasting is synchronous: we can read the
term_do_paste(term);
}
-void set_title(char *title)
+void set_title(void *frontend, char *title)
{
sfree(window_name);
window_name = smalloc(1 + strlen(title));
SetWindowText(hwnd, title);
}
-void set_icon(char *title)
+void set_icon(void *frontend, char *title)
{
sfree(icon_name);
icon_name = smalloc(1 + strlen(title));
SetWindowText(hwnd, title);
}
-void set_sbar(int total, int start, int page)
+void set_sbar(void *frontend, int total, int start, int page)
{
SCROLLINFO si;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}
-Context get_ctx(void)
+Context get_ctx(void *frontend)
{
HDC hdc;
if (hwnd) {
colours[n] = RGB(r, g, b);
}
-void palette_set(int n, int r, int g, int b)
+void palette_set(void *frontend, int n, int r, int g, int b)
{
static const int first[21] = {
0, 2, 4, 6, 8, 10, 12, 14,
if (first[n] >= 18)
real_palette_set(first[n] + 1, r, g, b);
if (pal) {
- HDC hdc = get_ctx();
+ HDC hdc = get_ctx(frontend);
UnrealizeObject(pal);
RealizePalette(hdc);
free_ctx(hdc);
}
}
-void palette_reset(void)
+void palette_reset(void *frontend)
{
int i;
if (pal) {
HDC hdc;
SetPaletteEntries(pal, 0, NCOLOURS, logpal->palPalEntry);
- hdc = get_ctx();
+ hdc = get_ctx(frontend);
RealizePalette(hdc);
free_ctx(hdc);
}
}
-void write_aclip(char *data, int len, int must_deselect)
+void write_aclip(void *frontend, char *data, int len, int must_deselect)
{
HGLOBAL clipdata;
void *lock;
/*
* Note: unlike write_aclip() this will not append a nul.
*/
-void write_clip(wchar_t * data, int len, int must_deselect)
+void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
{
HGLOBAL clipdata, clipdata2, clipdata3;
int len2;
SendMessage(hwnd, WM_IGNORE_CLIP, FALSE, 0);
}
-void get_clip(wchar_t ** p, int *len)
+void get_clip(void *frontend, wchar_t ** p, int *len)
{
static HGLOBAL clipdata = NULL;
static wchar_t *converted = 0;
* Move `lines' lines from position `from' to position `to' in the
* window.
*/
-void optimised_move(int to, int from, int lines)
+void optimised_move(void *frontend, int to, int from, int lines)
{
RECT r;
int min, max;
/*
* Beep.
*/
-void beep(int mode)
+void beep(void *frontend, int mode)
{
if (mode == BELL_DEFAULT) {
/*
* Minimise or restore the window in response to a server-side
* request.
*/
-void set_iconic(int iconic)
+void set_iconic(void *frontend, int iconic)
{
if (IsIconic(hwnd)) {
if (!iconic)
/*
* Move the window in response to a server-side request.
*/
-void move_window(int x, int y)
+void move_window(void *frontend, int x, int y)
{
if (cfg.resize_action == RESIZE_DISABLED ||
cfg.resize_action == RESIZE_FONT ||
* Move the window to the top or bottom of the z-order in response
* to a server-side request.
*/
-void set_zorder(int top)
+void set_zorder(void *frontend, int top)
{
if (cfg.alwaysontop)
return; /* ignore */
/*
* Refresh the window in response to a server-side request.
*/
-void refresh_window(void)
+void refresh_window(void *frontend)
{
InvalidateRect(hwnd, NULL, TRUE);
}
* Maximise or restore the window in response to a server-side
* request.
*/
-void set_zoomed(int zoomed)
+void set_zoomed(void *frontend, int zoomed)
{
if (IsZoomed(hwnd)) {
if (!zoomed)
/*
* Report whether the window is iconic, for terminal reports.
*/
-int is_iconic(void)
+int is_iconic(void *frontend)
{
return IsIconic(hwnd);
}
/*
* Report the window's position, for terminal reports.
*/
-void get_window_pos(int *x, int *y)
+void get_window_pos(void *frontend, int *x, int *y)
{
RECT r;
GetWindowRect(hwnd, &r);
/*
* Report the window's pixel size, for terminal reports.
*/
-void get_window_pixels(int *x, int *y)
+void get_window_pixels(void *frontend, int *x, int *y)
{
RECT r;
GetWindowRect(hwnd, &r);
/*
* Return the window or icon title.
*/
-char *get_window_title(int icon)
+char *get_window_title(void *frontend, int icon)
{
return icon ? icon_name : window_name;
}
s->pending_error = err;
return;
} else {
- logevent(winsock_error_string(err));
+ /* We're inside the Windows frontend here, so we know
+ * that the frontend handle is unnecessary. */
+ logevent(NULL, winsock_error_string(err));
fatalbox("%s", winsock_error_string(err));
}
} else {
if (ret <= 0) {
char *str = (ret == 0 ? "Internal networking trouble" :
winsock_error_string(WSAGetLastError()));
- logevent(str);
+ /* We're inside the Windows frontend here, so we know
+ * that the frontend handle is unnecessary. */
+ logevent(NULL, str);
fatalbox("%s", str);
} else {
return plug_receive(s->plug, 2, buf, ret);
#endif
#endif
+#ifndef DONE_TYPEDEFS
+#define DONE_TYPEDEFS
+typedef struct config_tag Config;
+typedef struct backend_tag Backend;
+typedef struct terminal_tag Terminal;
+#endif
+
#define PUTTY_REG_POS "Software\\SimonTatham\\PuTTY"
#define PUTTY_REG_PARENT "Software\\SimonTatham"
#define PUTTY_REG_PARENT_CHILD "PuTTY"
GLOBAL int help_has_contents;
/*
+ * The terminal and logging context are notionally local to the
+ * Windows front end, but they must be shared between window.c and
+ * windlg.c.
+ */
+GLOBAL Terminal *term;
+GLOBAL void *logctx;
+
+/*
* I've just looked in the windows standard headr files for WM_USER, there
* are hundreds of flags defined using the form WM_USER+123 so I've
* renumbered this NETEVENT value and the two in window.c