If you want to provide feedback on this manual
+or on the PuTTY tools themselves, see the
+Feedback
+page.
}
+
+\cfg{html-template-fragment}{%k}{%b}
+
+\cfg{info-max-file-size}{0}
+
+\cfg{xhtml-contents-filename}{index.html}
+\cfg{text-filename}{puttydoc.txt}
+\cfg{winhelp-filename}{putty.hlp}
+\cfg{info-filename}{putty.info}
+
+PuTTY is a free (MIT-licensed) Win32 Telnet and SSH client. This
+manual documents PuTTY, and its companion utilities PSCP, PSFTP,
+Plink, Pageant and PuTTYgen.
+
+\e{Note to Unix users:} this manual currently primarily documents the
+Windows versions of the PuTTY utilities. Some options are therefore
+mentioned that are absent from the \i{Unix version}; the Unix version has
+features not described here; and the \i\cw{pterm} and command-line
+\cw{puttygen} utilities are not described at all. The only
+Unix-specific documentation that currently exists is the
+\I{man pages for PuTTY tools}man pages.
+
+\copyright This manual is copyright 2001-2007 Simon Tatham. All
+rights reserved. You may distribute this documentation under the MIT
+licence. See \k{licence} for the licence text in full.
diff --git a/puttysrc/DOC/CHM.BUT b/puttysrc/DOC/CHM.BUT
new file mode 100644
index 0000000..ae4d402
--- /dev/null
+++ b/puttysrc/DOC/CHM.BUT
@@ -0,0 +1,23 @@
+\# File containing the magic HTML configuration directives to create
+\# an MS HTML Help project. We put this on the end of the PuTTY
+\# docs build command line to build the HHP and friends.
+
+\cfg{html-leaf-level}{infinite}
+\cfg{html-leaf-contains-contents}{false}
+\cfg{html-suppress-navlinks}{true}
+\cfg{html-suppress-address}{true}
+
+\cfg{html-contents-filename}{index.html}
+\cfg{html-template-filename}{%k.html}
+\cfg{html-template-fragment}{%k}
+
+\cfg{html-mshtmlhelp-chm}{putty.chm}
+\cfg{html-mshtmlhelp-project}{putty.hhp}
+\cfg{html-mshtmlhelp-contents}{putty.hhc}
+\cfg{html-mshtmlhelp-index}{putty.hhk}
+
+\cfg{html-body-end}{}
+
+\cfg{html-head-end}{}
+
+\versionid $Id: chm.but 7272 2007-02-11 18:13:56Z jacob $
diff --git a/puttysrc/DOC/CHM.CSS b/puttysrc/DOC/CHM.CSS
new file mode 100644
index 0000000..6e49b94
--- /dev/null
+++ b/puttysrc/DOC/CHM.CSS
@@ -0,0 +1,7 @@
+/* Stylesheet for a Windows .CHM help file */
+
+body { font-size: 75%; font-family: Verdana, Arial, Helvetica, Sans-Serif; }
+
+h1 { font-weight: bold; font-size: 150%; }
+h2 { font-weight: bold; font-size: 130%; }
+h3 { font-weight: bold; font-size: 120%; }
diff --git a/puttysrc/DOC/CONFIG.BUT b/puttysrc/DOC/CONFIG.BUT
new file mode 100644
index 0000000..4c518c6
--- /dev/null
+++ b/puttysrc/DOC/CONFIG.BUT
@@ -0,0 +1,3097 @@
+\define{versionidconfig} \versionid $Id: config.but 7345 2007-02-28 21:30:06Z jacob $
+
+\C{config} Configuring PuTTY
+
+This chapter describes all the \i{configuration options} in PuTTY.
+
+PuTTY is configured using the control panel that comes up before you
+start a session. Some options can also be changed in the middle of a
+session, by selecting \q{Change Settings} from the window menu.
+
+\H{config-session} The Session panel
+
+The Session configuration panel contains the basic options you need
+to specify in order to open a session at all, and also allows you to
+save your settings to be reloaded later.
+
+\S{config-hostname} The \i{host name} section
+
+\cfg{winhelp-topic}{session.hostname}
+
+The top box on the Session panel, labelled \q{Specify your
+connection by host name}, contains the details that need to be
+filled in before PuTTY can open a session at all.
+
+\b The \q{Host Name} box is where you type the name, or the \i{IP
+address}, of the server you want to connect to.
+
+\b The \q{Connection type} radio buttons let you choose what type of
+connection you want to make: a \I{raw TCP connections}raw
+connection, a \i{Telnet} connection, an \i{Rlogin} connection, an
+\i{SSH} connection, or a connection to a local \i{serial line}. (See
+\k{which-one} for a summary of the differences between SSH, Telnet
+and rlogin; see \k{using-rawprot} for an explanation of \q{raw}
+connections; see \k{using-serial} for information about using a
+serial line.)
+
+\b The \q{Port} box lets you specify which \i{port number} on the
+server to connect to. If you select Telnet, Rlogin, or SSH, this box
+will be filled in automatically to the usual value, and you will
+only need to change it if you have an unusual server. If you select
+Raw mode, you will almost certainly need to fill in the \q{Port} box
+yourself.
+
+If you select \q{Serial} from the \q{Connection type} radio buttons,
+the \q{Host Name} and \q{Port} boxes are replaced by \q{Serial line}
+and \q{Speed}; see \k{config-serial} for more details of these.
+
+\S{config-saving} \ii{Loading and storing saved sessions}
+
+\cfg{winhelp-topic}{session.saved}
+
+The next part of the Session configuration panel allows you to save
+your preferred PuTTY options so they will appear automatically the
+next time you start PuTTY. It also allows you to create \e{saved
+sessions}, which contain a full set of configuration options plus a
+host name and protocol. A saved session contains all the information
+PuTTY needs to start exactly the session you want.
+
+\b To save your default settings: first set up the settings the way
+you want them saved. Then come back to the Session panel. Select the
+\q{\i{Default Settings}} entry in the saved sessions list, with a single
+click. Then press the \q{Save} button.
+
+\lcont{
+Note that PuTTY does not allow you to save a host name into the
+Default Settings entry. This ensures that when PuTTY is started up,
+the host name box is always empty, so a user can always just type in
+a host name and connect.
+}
+
+If there is a specific host you want to store the details of how to
+connect to, you should create a saved session, which will be
+separate from the Default Settings.
+
+\b To save a session: first go through the rest of the configuration
+box setting up all the options you want. Then come back to the
+Session panel. Enter a name for the saved session in the \q{Saved
+Sessions} input box. (The server name is often a good choice for a
+saved session name.) Then press the \q{Save} button. Your saved
+session name should now appear in the list box.
+
+\lcont{
+You can also save settings in mid-session, from the \q{Change Settings}
+dialog. Settings changed since the start of the session will be saved
+with their current values; as well as settings changed through the
+dialog, this includes changes in window size, window title changes
+sent by the server, and so on.
+}
+
+\b To reload a saved session: single-click to select the session
+name in the list box, and then press the \q{Load} button. Your saved
+settings should all appear in the configuration panel.
+
+\b To modify a saved session: first load it as described above. Then
+make the changes you want. Come back to the Session panel, and press
+the \q{Save} button. The new settings will be saved over the top of
+the old ones.
+
+\lcont{
+To save the new settings under a different name, you can enter the new
+name in the \q{Saved Sessions} box, or single-click to select a
+session name in the list box to overwrite that session. To save
+\q{Default Settings}, you must single-click the name before saving.
+}
+
+\b To start a saved session immediately: double-click on the session
+name in the list box.
+
+\b To delete a saved session: single-click to select the session
+name in the list box, and then press the \q{Delete} button.
+
+Each saved session is independent of the Default Settings
+configuration. If you change your preferences and update Default
+Settings, you must also update every saved session separately.
+
+Saved sessions are stored in the \i{Registry}, at the location
+
+\c HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions
+
+If you need to store them in a file, you could try the method
+described in \k{config-file}.
+
+\S{config-closeonexit} \q{\ii{Close Window} on Exit}
+
+\cfg{winhelp-topic}{session.coe}
+
+Finally in the Session panel, there is an option labelled \q{Close
+Window on Exit}. This controls whether the PuTTY \i{terminal window}
+disappears as soon as the session inside it terminates. If you are
+likely to want to copy and paste text out of the session after it
+has terminated, or restart the session, you should arrange for this
+option to be off.
+
+\q{Close Window On Exit} has three settings. \q{Always} means always
+close the window on exit; \q{Never} means never close on exit
+(always leave the window open, but \I{inactive window}inactive). The
+third setting, and the default one, is \q{Only on clean exit}. In this
+mode, a session which terminates normally will cause its window to
+close, but one which is aborted unexpectedly by network trouble or a
+confusing message from the server will leave the window up.
+
+\H{config-logging} The Logging panel
+
+\cfg{winhelp-topic}{logging.main}
+
+The Logging configuration panel allows you to save \i{log file}s of your
+PuTTY sessions, for debugging, analysis or future reference.
+
+The main option is a radio-button set that specifies whether PuTTY
+will log anything at all. The options are:
+
+\b \q{None}. This is the default option; in this mode PuTTY will not
+create a log file at all.
+
+\b \q{Printable output}. In this mode, a log file will be
+created and written to, but only printable text will be saved into
+it. The various terminal control codes that are typically sent down
+an interactive session alongside the printable text will be omitted.
+This might be a useful mode if you want to read a log file in a text
+editor and hope to be able to make sense of it.
+
+\b \q{All session output}. In this mode, \e{everything} sent by
+the server into your terminal session is logged. If you view the log
+file in a text editor, therefore, you may well find it full of
+strange control characters. This is a particularly useful mode if
+you are experiencing problems with PuTTY's terminal handling: you
+can record everything that went to the terminal, so that someone
+else can replay the session later in slow motion and watch to see
+what went wrong.
+
+\b \I{SSH packet log}\q{SSH packets}. In this mode (which is only used
+by SSH connections), the SSH message packets sent over the encrypted
+connection are written to the log file (as well as \i{Event Log}
+entries). You might need this to debug a network-level problem, or
+more likely to send to the PuTTY authors as part of a bug report.
+\e{BE WARNED} that if you log in using a password, the password can
+appear in the log file; see \k{config-logssh} for options that may
+help to remove sensitive material from the log file before you send it
+to anyone else.
+
+\b \q{SSH packets and raw data}. In this mode, as well as the
+decrypted packets (as in the previous mode), the \e{raw} (encrypted,
+compressed, etc) packets are \e{also} logged. This could be useful to
+diagnose corruption in transit. (The same caveats as the previous mode
+apply, of course.)
+
+Note that the non-SSH logging options (\q{Printable output} and
+\q{All session output}) only work with PuTTY proper; in programs
+without terminal emulation (such as Plink), they will have no effect,
+even if enabled via saved settings.
+
+\S{config-logfilename} \q{Log file name}
+
+\cfg{winhelp-topic}{logging.filename}
+
+In this edit box you enter the name of the file you want to log the
+session to. The \q{Browse} button will let you look around your file
+system to find the right place to put the file; or if you already
+know exactly where you want it to go, you can just type a pathname
+into the edit box.
+
+There are a few special features in this box. If you use the \c{&}
+character in the file name box, PuTTY will insert details of the
+current session in the name of the file it actually opens. The
+precise replacements it will do are:
+
+\b \c{&Y} will be replaced by the current year, as four digits.
+
+\b \c{&M} will be replaced by the current month, as two digits.
+
+\b \c{&D} will be replaced by the current day of the month, as two
+digits.
+
+\b \c{&T} will be replaced by the current time, as six digits
+(HHMMSS) with no punctuation.
+
+\b \c{&H} will be replaced by the host name you are connecting to.
+
+For example, if you enter the host name
+\c{c:\\puttylogs\\log-&h-&y&m&d-&t.dat}, you will end up with files looking
+like
+
+\c log-server1.example.com-20010528-110859.dat
+\c log-unixbox.somewhere.org-20010611-221001.dat
+
+\S{config-logfileexists} \q{What to do if the log file already exists}
+
+\cfg{winhelp-topic}{logging.exists}
+
+This control allows you to specify what PuTTY should do if it tries
+to start writing to a log file and it finds the file already exists.
+You might want to automatically destroy the existing log file and
+start a new one with the same name. Alternatively, you might want to
+open the existing log file and add data to the \e{end} of it.
+Finally (the default option), you might not want to have any
+automatic behaviour, but to ask the user every time the problem
+comes up.
+
+\S{config-logflush} \I{log file, flushing}\q{Flush log file frequently}
+
+\cfg{winhelp-topic}{logging.flush}
+
+This option allows you to control how frequently logged data is
+flushed to disc. By default, PuTTY will flush data as soon as it is
+displayed, so that if you view the log file while a session is still
+open, it will be up to date; and if the client system crashes, there's
+a greater chance that the data will be preserved.
+
+However, this can incur a performance penalty. If PuTTY is running
+slowly with logging enabled, you could try unchecking this option. Be
+warned that the log file may not always be up to date as a result
+(although it will of course be flushed when it is closed, for instance
+at the end of a session).
+
+\S{config-logssh} Options specific to \i{SSH packet log}ging
+
+These options only apply if SSH packet data is being logged.
+
+The following options allow particularly sensitive portions of
+unencrypted packets to be automatically left out of the log file.
+They are only intended to deter casual nosiness; an attacker could
+glean a lot of useful information from even these obfuscated logs
+(e.g., length of password).
+
+\S2{config-logssh-omitpw} \q{Omit known password fields}
+
+\cfg{winhelp-topic}{logging.ssh.omitpassword}
+
+When checked, decrypted password fields are removed from the log of
+transmitted packets. (This includes any user responses to
+challenge-response authentication methods such as
+\q{keyboard-interactive}.) This does not include X11 authentication
+data if using X11 forwarding.
+
+Note that this will only omit data that PuTTY \e{knows} to be a
+password. However, if you start another login session within your
+PuTTY session, for instance, any password used will appear in the
+clear in the packet log. The next option may be of use to protect
+against this.
+
+This option is enabled by default.
+
+\S2{config-logssh-omitdata} \q{Omit session data}
+
+\cfg{winhelp-topic}{logging.ssh.omitdata}
+
+When checked, all decrypted \q{session data} is omitted; this is
+defined as data in terminal sessions and in forwarded channels (TCP,
+X11, and authentication agent). This will usually substantially reduce
+the size of the resulting log file.
+
+This option is disabled by default.
+
+\H{config-terminal} The Terminal panel
+
+The Terminal configuration panel allows you to control the behaviour
+of PuTTY's \i{terminal emulation}.
+
+\S{config-autowrap} \q{Auto wrap mode initially on}
+
+\cfg{winhelp-topic}{terminal.autowrap}
+
+\ii{Auto wrap mode} controls what happens when text printed in a PuTTY
+window reaches the right-hand edge of the window.
+
+With auto wrap mode on, if a long line of text reaches the
+right-hand edge, it will wrap over on to the next line so you can
+still see all the text. With auto wrap mode off, the cursor will
+stay at the right-hand edge of the screen, and all the characters in
+the line will be printed on top of each other.
+
+If you are running a full-screen application and you occasionally
+find the screen scrolling up when it looks as if it shouldn't, you
+could try turning this option off.
+
+Auto wrap mode can be turned on and off by \i{control sequence}s sent by
+the server. This configuration option controls the \e{default}
+state, which will be restored when you reset the terminal (see
+\k{reset-terminal}). However, if you modify this option in
+mid-session using \q{Change Settings}, it will take effect
+immediately.
+
+\S{config-decom} \q{DEC Origin Mode initially on}
+
+\cfg{winhelp-topic}{terminal.decom}
+
+\i{DEC Origin Mode} is a minor option which controls how PuTTY
+interprets cursor-position \i{control sequence}s sent by the server.
+
+The server can send a control sequence that restricts the \i{scrolling
+region} of the display. For example, in an editor, the server might
+reserve a line at the top of the screen and a line at the bottom,
+and might send a control sequence that causes scrolling operations
+to affect only the remaining lines.
+
+With DEC Origin Mode on, \i{cursor coordinates} are counted from the top
+of the scrolling region. With it turned off, cursor coordinates are
+counted from the top of the whole screen regardless of the scrolling
+region.
+
+It is unlikely you would need to change this option, but if you find
+a full-screen application is displaying pieces of text in what looks
+like the wrong part of the screen, you could try turning DEC Origin
+Mode on to see whether that helps.
+
+DEC Origin Mode can be turned on and off by control sequences sent
+by the server. This configuration option controls the \e{default}
+state, which will be restored when you reset the terminal (see
+\k{reset-terminal}). However, if you modify this option in
+mid-session using \q{Change Settings}, it will take effect
+immediately.
+
+\S{config-crlf} \q{Implicit CR in every LF}
+
+\cfg{winhelp-topic}{terminal.lfhascr}
+
+Most servers send two control characters, \i{CR} and \i{LF}, to start a
+\i{new line} of the screen. The CR character makes the cursor return to the
+left-hand side of the screen. The LF character makes the cursor move
+one line down (and might make the screen scroll).
+
+Some servers only send LF, and expect the terminal to move the
+cursor over to the left automatically. If you come across a server
+that does this, you will see a \I{stair-stepping}stepped effect on the
+screen, like this:
+
+\c First line of text
+\c Second line
+\c Third line
+
+If this happens to you, try enabling the \q{Implicit CR in every LF}
+option, and things might go back to normal:
+
+\c First line of text
+\c Second line
+\c Third line
+
+\S{config-erase} \q{Use \i{background colour} to erase screen}
+
+\cfg{winhelp-topic}{terminal.bce}
+
+Not all terminals agree on what colour to turn the screen when the
+server sends a \q{\i{clear screen}} sequence. Some terminals believe the
+screen should always be cleared to the \e{default} background
+colour. Others believe the screen should be cleared to whatever the
+server has selected as a background colour.
+
+There exist applications that expect both kinds of behaviour.
+Therefore, PuTTY can be configured to do either.
+
+With this option disabled, screen clearing is always done in the
+default background colour. With this option enabled, it is done in
+the \e{current} background colour.
+
+Background-colour erase can be turned on and off by \i{control
+sequences} sent by the server. This configuration option controls the
+\e{default} state, which will be restored when you reset the
+terminal (see \k{reset-terminal}). However, if you modify this
+option in mid-session using \q{Change Settings}, it will take effect
+immediately.
+
+\S{config-blink} \q{Enable \i{blinking text}}
+
+\cfg{winhelp-topic}{terminal.blink}
+
+The server can ask PuTTY to display text that blinks on and off.
+This is very distracting, so PuTTY allows you to turn blinking text
+off completely.
+
+When blinking text is disabled and the server attempts to make some
+text blink, PuTTY will instead display the text with a \I{background
+colour, bright}bolded background colour.
+
+Blinking text can be turned on and off by \i{control sequence}s sent by
+the server. This configuration option controls the \e{default}
+state, which will be restored when you reset the terminal (see
+\k{reset-terminal}). However, if you modify this option in
+mid-session using \q{Change Settings}, it will take effect
+immediately.
+
+\S{config-answerback} \q{\ii{Answerback} to ^E}
+
+\cfg{winhelp-topic}{terminal.answerback}
+
+This option controls what PuTTY will send back to the server if the
+server sends it the ^E \i{enquiry character}. Normally it just sends
+the string \q{PuTTY}.
+
+If you accidentally write the contents of a binary file to your
+terminal, you will probably find that it contains more than one ^E
+character, and as a result your next command line will probably read
+\q{PuTTYPuTTYPuTTY...} as if you had typed the answerback string
+multiple times at the keyboard. If you set the answerback string to
+be empty, this problem should go away, but doing so might cause
+other problems.
+
+Note that this is \e{not} the feature of PuTTY which the server will
+typically use to determine your terminal type. That feature is the
+\q{\ii{Terminal-type} string} in the Connection panel; see
+\k{config-termtype} for details.
+
+You can include control characters in the answerback string using
+\c{^C} notation. (Use \c{^~} to get a literal \c{^}.)
+
+\S{config-localecho} \q{\ii{Local echo}}
+
+\cfg{winhelp-topic}{terminal.localecho}
+
+With local echo disabled, characters you type into the PuTTY window
+are not echoed in the window \e{by PuTTY}. They are simply sent to
+the server. (The \e{server} might choose to \I{remote echo}echo them
+back to you; this can't be controlled from the PuTTY control panel.)
+
+Some types of session need local echo, and many do not. In its
+default mode, PuTTY will automatically attempt to deduce whether or
+not local echo is appropriate for the session you are working in. If
+you find it has made the wrong decision, you can use this
+configuration option to override its choice: you can force local
+echo to be turned on, or force it to be turned off, instead of
+relying on the automatic detection.
+
+\S{config-localedit} \q{\ii{Local line editing}}
+
+\cfg{winhelp-topic}{terminal.localedit}
+
+Normally, every character you type into the PuTTY window is sent
+immediately to the server the moment you type it.
+
+If you enable local line editing, this changes. PuTTY will let you
+edit a whole line at a time locally, and the line will only be sent
+to the server when you press Return. If you make a mistake, you can
+use the Backspace key to correct it before you press Return, and the
+server will never see the mistake.
+
+Since it is hard to edit a line locally without being able to see
+it, local line editing is mostly used in conjunction with \i{local echo}
+(\k{config-localecho}). This makes it ideal for use in raw mode
+\#{FIXME} or when connecting to \i{MUD}s or \i{talker}s. (Although some more
+advanced MUDs do occasionally turn local line editing on and turn
+local echo off, in order to accept a password from the user.)
+
+Some types of session need local line editing, and many do not. In
+its default mode, PuTTY will automatically attempt to deduce whether
+or not local line editing is appropriate for the session you are
+working in. If you find it has made the wrong decision, you can use
+this configuration option to override its choice: you can force
+local line editing to be turned on, or force it to be turned off,
+instead of relying on the automatic detection.
+
+\S{config-printing} \ii{Remote-controlled printing}
+
+\cfg{winhelp-topic}{terminal.printing}
+
+A lot of VT100-compatible terminals support printing under control
+of the remote server. PuTTY supports this feature as well, but it is
+turned off by default.
+
+To enable remote-controlled printing, choose a printer from the
+\q{Printer to send ANSI printer output to} drop-down list box. This
+should allow you to select from all the printers you have installed
+drivers for on your computer. Alternatively, you can type the
+network name of a networked printer (for example,
+\c{\\\\printserver\\printer1}) even if you haven't already
+installed a driver for it on your own machine.
+
+When the remote server attempts to print some data, PuTTY will send
+that data to the printer \e{raw} - without translating it,
+attempting to format it, or doing anything else to it. It is up to
+you to ensure your remote server knows what type of printer it is
+talking to.
+
+Since PuTTY sends data to the printer raw, it cannot offer options
+such as portrait versus landscape, print quality, or paper tray
+selection. All these things would be done by your PC printer driver
+(which PuTTY bypasses); if you need them done, you will have to find
+a way to configure your remote server to do them.
+
+To disable remote printing again, choose \q{None (printing
+disabled)} from the printer selection list. This is the default
+state.
+
+\H{config-keyboard} The Keyboard panel
+
+The Keyboard configuration panel allows you to control the behaviour
+of the \i{keyboard} in PuTTY. The correct state for many of these
+settings depends on what the server to which PuTTY is connecting
+expects. With a \i{Unix} server, this is likely to depend on the
+\i\c{termcap} or \i\c{terminfo} entry it uses, which in turn is likely to
+be controlled by the \q{\ii{Terminal-type} string} setting in the Connection
+panel; see \k{config-termtype} for details. If none of the settings here
+seems to help, you may find \k{faq-keyboard} to be useful.
+
+\S{config-backspace} Changing the action of the \ii{Backspace key}
+
+\cfg{winhelp-topic}{keyboard.backspace}
+
+Some terminals believe that the Backspace key should send the same
+thing to the server as \i{Control-H} (ASCII code 8). Other terminals
+believe that the Backspace key should send ASCII code 127 (usually
+known as \i{Control-?}) so that it can be distinguished from Control-H.
+This option allows you to choose which code PuTTY generates when you
+press Backspace.
+
+If you are connecting over SSH, PuTTY by default tells the server
+the value of this option (see \k{config-ttymodes}), so you may find
+that the Backspace key does the right thing either way. Similarly,
+if you are connecting to a \i{Unix} system, you will probably find that
+the Unix \i\c{stty} command lets you configure which the server
+expects to see, so again you might not need to change which one PuTTY
+generates. On other systems, the server's expectation might be fixed
+and you might have no choice but to configure PuTTY.
+
+If you do have the choice, we recommend configuring PuTTY to
+generate Control-? and configuring the server to expect it, because
+that allows applications such as \c{emacs} to use Control-H for
+help.
+
+(Typing \i{Shift-Backspace} will cause PuTTY to send whichever code
+isn't configured here as the default.)
+
+\S{config-homeend} Changing the action of the \i{Home and End keys}
+
+\cfg{winhelp-topic}{keyboard.homeend}
+
+The Unix terminal emulator \i\c{rxvt} disagrees with the rest of the
+world about what character sequences should be sent to the server by
+the Home and End keys.
+
+\i\c{xterm}, and other terminals, send \c{ESC [1~} for the Home key,
+and \c{ESC [4~} for the End key. \c{rxvt} sends \c{ESC [H} for the
+Home key and \c{ESC [Ow} for the End key.
+
+If you find an application on which the Home and End keys aren't
+working, you could try switching this option to see if it helps.
+
+\S{config-funkeys} Changing the action of the \i{function keys} and
+\i{keypad}
+
+\cfg{winhelp-topic}{keyboard.funkeys}
+
+This option affects the function keys (F1 to F12) and the top row of
+the numeric keypad.
+
+\b In the default mode, labelled \c{ESC [n~}, the function keys
+generate sequences like \c{ESC [11~}, \c{ESC [12~} and so on. This
+matches the general behaviour of Digital's terminals.
+
+\b In Linux mode, F6 to F12 behave just like the default mode, but
+F1 to F5 generate \c{ESC [[A} through to \c{ESC [[E}. This mimics the
+\i{Linux virtual console}.
+
+\b In \I{xterm}Xterm R6 mode, F5 to F12 behave like the default mode, but F1
+to F4 generate \c{ESC OP} through to \c{ESC OS}, which are the
+sequences produced by the top row of the \e{keypad} on Digital's
+terminals.
+
+\b In \i{VT400} mode, all the function keys behave like the default
+mode, but the actual top row of the numeric keypad generates \c{ESC
+OP} through to \c{ESC OS}.
+
+\b In \i{VT100+} mode, the function keys generate \c{ESC OP} through to
+\c{ESC O[}
+
+\b In \i{SCO} mode, the function keys F1 to F12 generate \c{ESC [M}
+through to \c{ESC [X}. Together with shift, they generate \c{ESC [Y}
+through to \c{ESC [j}. With control they generate \c{ESC [k} through
+to \c{ESC [v}, and with shift and control together they generate
+\c{ESC [w} through to \c{ESC [\{}.
+
+If you don't know what any of this means, you probably don't need to
+fiddle with it.
+
+\S{config-appcursor} Controlling \i{Application Cursor Keys} mode
+
+\cfg{winhelp-topic}{keyboard.appcursor}
+
+Application Cursor Keys mode is a way for the server to change the
+control sequences sent by the arrow keys. In normal mode, the arrow
+keys send \c{ESC [A} through to \c{ESC [D}. In application mode,
+they send \c{ESC OA} through to \c{ESC OD}.
+
+Application Cursor Keys mode can be turned on and off by the server,
+depending on the application. PuTTY allows you to configure the
+initial state.
+
+You can also disable application cursor keys mode completely, using
+the \q{Features} configuration panel; see
+\k{config-features-application}.
+
+\S{config-appkeypad} Controlling \i{Application Keypad} mode
+
+\cfg{winhelp-topic}{keyboard.appkeypad}
+
+Application Keypad mode is a way for the server to change the
+behaviour of the numeric keypad.
+
+In normal mode, the keypad behaves like a normal Windows keypad:
+with \i{NumLock} on, the number keys generate numbers, and with NumLock
+off they act like the arrow keys and Home, End etc.
+
+In application mode, all the keypad keys send special control
+sequences, \e{including} Num Lock. Num Lock stops behaving like Num
+Lock and becomes another function key.
+
+Depending on which version of Windows you run, you may find the Num
+Lock light still flashes on and off every time you press Num Lock,
+even when application mode is active and Num Lock is acting like a
+function key. This is unavoidable.
+
+Application keypad mode can be turned on and off by the server,
+depending on the application. PuTTY allows you to configure the
+initial state.
+
+You can also disable application keypad mode completely, using the
+\q{Features} configuration panel; see
+\k{config-features-application}.
+
+\S{config-nethack} Using \i{NetHack keypad mode}
+
+\cfg{winhelp-topic}{keyboard.nethack}
+
+PuTTY has a special mode for playing NetHack. You can enable it by
+selecting \q{NetHack} in the \q{Initial state of numeric keypad}
+control.
+
+In this mode, the numeric keypad keys 1-9 generate the NetHack
+movement commands (\cw{hjklyubn}). The 5 key generates the \c{.}
+command (do nothing).
+
+In addition, pressing Shift or Ctrl with the keypad keys generate
+the Shift- or Ctrl-keys you would expect (e.g. keypad-7 generates
+\cq{y}, so Shift-keypad-7 generates \cq{Y} and Ctrl-keypad-7
+generates Ctrl-Y); these commands tell NetHack to keep moving you in
+the same direction until you encounter something interesting.
+
+For some reason, this feature only works properly when \i{Num Lock} is
+on. We don't know why.
+
+\S{config-compose} Enabling a DEC-like \ii{Compose key}
+
+\cfg{winhelp-topic}{keyboard.compose}
+
+DEC terminals have a Compose key, which provides an easy-to-remember
+way of typing \i{accented characters}. You press Compose and then type
+two more characters. The two characters are \q{combined} to produce
+an accented character. The choices of character are designed to be
+easy to remember; for example, composing \q{e} and \q{`} produces
+the \q{\u00e8{e-grave}} character.
+
+If your keyboard has a Windows \i{Application key}, it acts as a Compose
+key in PuTTY. Alternatively, if you enable the \q{\i{AltGr} acts as
+Compose key} option, the AltGr key will become a Compose key.
+
+\S{config-ctrlalt} \q{Control-Alt is different from \i{AltGr}}
+
+\cfg{winhelp-topic}{keyboard.ctrlalt}
+
+Some old keyboards do not have an AltGr key, which can make it
+difficult to type some characters. PuTTY can be configured to treat
+the key combination Ctrl + Left Alt the same way as the AltGr key.
+
+By default, this checkbox is checked, and the key combination Ctrl +
+Left Alt does something completely different. PuTTY's usual handling
+of the left Alt key is to prefix the Escape (Control-\cw{[})
+character to whatever character sequence the rest of the keypress
+would generate. For example, Alt-A generates Escape followed by
+\c{a}. So Alt-Ctrl-A would generate Escape, followed by Control-A.
+
+If you uncheck this box, Ctrl-Alt will become a synonym for AltGr,
+so you can use it to type extra graphic characters if your keyboard
+has any.
+
+(However, Ctrl-Alt will never act as a Compose key, regardless of the
+setting of \q{AltGr acts as Compose key} described in
+\k{config-compose}.)
+
+\H{config-bell} The Bell panel
+
+The Bell panel controls the \i{terminal bell} feature: the server's
+ability to cause PuTTY to beep at you.
+
+In the default configuration, when the server sends the character
+with ASCII code 7 (Control-G), PuTTY will play the \i{Windows Default
+Beep} sound. This is not always what you want the terminal bell
+feature to do; the Bell panel allows you to configure alternative
+actions.
+
+\S{config-bellstyle} \q{Set the style of bell}
+
+\cfg{winhelp-topic}{bell.style}
+
+This control allows you to select various different actions to occur
+on a terminal bell:
+
+\b Selecting \q{None} \I{terminal bell, disabling}disables the bell
+completely. In this mode, the server can send as many Control-G
+characters as it likes and nothing at all will happen.
+
+\b \q{Make default system alert sound} is the default setting. It
+causes the Windows \q{Default Beep} sound to be played. To change
+what this sound is, or to test it if nothing seems to be happening,
+use the Sound configurer in the Windows Control Panel.
+
+\b \q{\ii{Visual bell}} is a silent alternative to a beeping computer. In
+this mode, when the server sends a Control-G, the whole PuTTY window
+will flash white for a fraction of a second.
+
+\b \q{Beep using the \i{PC speaker}} is self-explanatory.
+
+\b \q{Play a custom \i{sound file}} allows you to specify a particular
+sound file to be used by PuTTY alone, or even by a particular
+individual PuTTY session. This allows you to distinguish your PuTTY
+beeps from any other beeps on the system. If you select this option,
+you will also need to enter the name of your sound file in the edit
+control \q{Custom sound file to play as a bell}.
+
+\S{config-belltaskbar} \q{\ii{Taskbar}/\I{window caption}caption
+indication on bell}
+
+\cfg{winhelp-topic}{bell.taskbar}
+
+This feature controls what happens to the PuTTY window's entry in
+the Windows Taskbar if a bell occurs while the window does not have
+the input focus.
+
+In the default state (\q{Disabled}) nothing unusual happens.
+
+If you select \q{Steady}, then when a bell occurs and the window is
+not in focus, the window's Taskbar entry and its title bar will
+change colour to let you know that PuTTY session is asking for your
+attention. The change of colour will persist until you select the
+window, so you can leave several PuTTY windows minimised in your
+terminal, go away from your keyboard, and be sure not to have missed
+any important beeps when you get back.
+
+\q{Flashing} is even more eye-catching: the Taskbar entry will
+continuously flash on and off until you select the window.
+
+\S{config-bellovl} \q{Control the \i{bell overload} behaviour}
+
+\cfg{winhelp-topic}{bell.overload}
+
+A common user error in a terminal session is to accidentally run the
+Unix command \c{cat} (or equivalent) on an inappropriate file type,
+such as an executable, image file, or ZIP file. This produces a huge
+stream of non-text characters sent to the terminal, which typically
+includes a lot of bell characters. As a result of this the terminal
+often doesn't stop beeping for ten minutes, and everybody else in
+the office gets annoyed.
+
+To try to avoid this behaviour, or any other cause of excessive
+beeping, PuTTY includes a bell overload management feature. In the
+default configuration, receiving more than five bell characters in a
+two-second period will cause the overload feature to activate. Once
+the overload feature is active, further bells will \I{terminal bell,
+disabling} have no effect at all, so the rest of your binary file
+will be sent to the screen in silence. After a period of five seconds
+during which no further bells are received, the overload feature will
+turn itself off again and bells will be re-enabled.
+
+If you want this feature completely disabled, you can turn it off
+using the checkbox \q{Bell is temporarily disabled when over-used}.
+
+Alternatively, if you like the bell overload feature but don't agree
+with the settings, you can configure the details: how many bells
+constitute an overload, how short a time period they have to arrive
+in to do so, and how much silent time is required before the
+overload feature will deactivate itself.
+
+Bell overload mode is always deactivated by any keypress in the
+terminal. This means it can respond to large unexpected streams of
+data, but does not interfere with ordinary command-line activities
+that generate beeps (such as filename completion).
+
+\H{config-features} The Features panel
+
+PuTTY's \i{terminal emulation} is very highly featured, and can do a lot
+of things under remote server control. Some of these features can
+cause problems due to buggy or strangely configured server
+applications.
+
+The Features configuration panel allows you to disable some of
+PuTTY's more advanced terminal features, in case they cause trouble.
+
+\S{config-features-application} Disabling application keypad and cursor keys
+
+\cfg{winhelp-topic}{features.application}
+
+\I{Application Keypad}Application keypad mode (see
+\k{config-appkeypad}) and \I{Application Cursor Keys}application
+cursor keys mode (see \k{config-appcursor}) alter the behaviour of
+the keypad and cursor keys. Some applications enable these modes but
+then do not deal correctly with the modified keys. You can force
+these modes to be permanently disabled no matter what the server
+tries to do.
+
+\S{config-features-mouse} Disabling \cw{xterm}-style \i{mouse reporting}
+
+\cfg{winhelp-topic}{features.mouse}
+
+PuTTY allows the server to send \i{control codes} that let it take over
+the mouse and use it for purposes other than \i{copy and paste}.
+Applications which use this feature include the text-mode web
+browser \i\c{links}, the Usenet newsreader \i\c{trn} version 4, and the
+file manager \i\c{mc} (Midnight Commander).
+
+If you find this feature inconvenient, you can disable it using the
+\q{Disable xterm-style mouse reporting} control. With this box
+ticked, the mouse will \e{always} do copy and paste in the normal
+way.
+
+Note that even if the application takes over the mouse, you can
+still manage PuTTY's copy and paste by holding down the Shift key
+while you select and paste, unless you have deliberately turned this
+feature off (see \k{config-mouseshift}).
+
+\S{config-features-resize} Disabling remote \i{terminal resizing}
+
+\cfg{winhelp-topic}{features.resize}
+
+PuTTY has the ability to change the terminal's size and position in
+response to commands from the server. If you find PuTTY is doing
+this unexpectedly or inconveniently, you can tell PuTTY not to
+respond to those server commands.
+
+\S{config-features-altscreen} Disabling switching to the \i{alternate screen}
+
+\cfg{winhelp-topic}{features.altscreen}
+
+Many terminals, including PuTTY, support an \q{alternate screen}.
+This is the same size as the ordinary terminal screen, but separate.
+Typically a screen-based program such as a text editor might switch
+the terminal to the alternate screen before starting up. Then at the
+end of the run, it switches back to the primary screen, and you see
+the screen contents just as they were before starting the editor.
+
+Some people prefer this not to happen. If you want your editor to
+run in the same screen as the rest of your terminal activity, you
+can disable the alternate screen feature completely.
+
+\S{config-features-retitle} Disabling remote \i{window title} changing
+
+\cfg{winhelp-topic}{features.retitle}
+
+PuTTY has the ability to change the window title in response to
+commands from the server. If you find PuTTY is doing this
+unexpectedly or inconveniently, you can tell PuTTY not to respond to
+those server commands.
+
+\S{config-features-qtitle} Response to remote \i{window title} querying
+
+\cfg{winhelp-topic}{features.qtitle}
+
+PuTTY can optionally provide the xterm service of allowing server
+applications to find out the local window title. This feature is
+disabled by default, but you can turn it on if you really want it.
+
+NOTE that this feature is a \e{potential \i{security hazard}}. If a
+malicious application can write data to your terminal (for example,
+if you merely \c{cat} a file owned by someone else on the server
+machine), it can change your window title (unless you have disabled
+this as mentioned in \k{config-features-retitle}) and then use this
+service to have the new window title sent back to the server as if
+typed at the keyboard. This allows an attacker to fake keypresses
+and potentially cause your server-side applications to do things you
+didn't want. Therefore this feature is disabled by default, and we
+recommend you do not set it to \q{Window title} unless you \e{really}
+know what you are doing.
+
+There are three settings for this option:
+
+\dt \q{None}
+
+\dd PuTTY makes no response whatsoever to the relevant escape
+sequence. This may upset server-side software that is expecting some
+sort of response.
+
+\dt \q{Empty string}
+
+\dd PuTTY makes a well-formed response, but leaves it blank. Thus,
+server-side software that expects a response is kept happy, but an
+attacker cannot influence the response string. This is probably the
+setting you want if you have no better ideas.
+
+\dt \q{Window title}
+
+\dd PuTTY responds with the actual window title. This is dangerous for
+the reasons described above.
+
+\S{config-features-dbackspace} Disabling \i{destructive backspace}
+
+\cfg{winhelp-topic}{features.dbackspace}
+
+Normally, when PuTTY receives character 127 (^?) from the server, it
+will perform a \q{destructive backspace}: move the cursor one space
+left and delete the character under it. This can apparently cause
+problems in some applications, so PuTTY provides the ability to
+configure character 127 to perform a normal backspace (without
+deleting a character) instead.
+
+\S{config-features-charset} Disabling remote \i{character set}
+configuration
+
+\cfg{winhelp-topic}{features.charset}
+
+PuTTY has the ability to change its character set configuration in
+response to commands from the server. Some programs send these
+commands unexpectedly or inconveniently. In particular, \I{BitchX} (an
+IRC client) seems to have a habit of reconfiguring the character set
+to something other than the user intended.
+
+If you find that accented characters are not showing up the way you
+expect them to, particularly if you're running BitchX, you could try
+disabling the remote character set configuration commands.
+
+\S{config-features-shaping} Disabling \i{Arabic text shaping}
+
+\cfg{winhelp-topic}{features.arabicshaping}
+
+PuTTY supports shaping of Arabic text, which means that if your
+server sends text written in the basic \i{Unicode} Arabic alphabet then
+it will convert it to the correct display forms before printing it
+on the screen.
+
+If you are using full-screen software which was not expecting this
+to happen (especially if you are not an Arabic speaker and you
+unexpectedly find yourself dealing with Arabic text files in
+applications which are not Arabic-aware), you might find that the
+\i{display becomes corrupted}. By ticking this box, you can disable
+Arabic text shaping so that PuTTY displays precisely the characters
+it is told to display.
+
+You may also find you need to disable bidirectional text display;
+see \k{config-features-bidi}.
+
+\S{config-features-bidi} Disabling \i{bidirectional text} display
+
+\cfg{winhelp-topic}{features.bidi}
+
+PuTTY supports bidirectional text display, which means that if your
+server sends text written in a language which is usually displayed
+from right to left (such as \i{Arabic} or \i{Hebrew}) then PuTTY will
+automatically flip it round so that it is displayed in the right
+direction on the screen.
+
+If you are using full-screen software which was not expecting this
+to happen (especially if you are not an Arabic speaker and you
+unexpectedly find yourself dealing with Arabic text files in
+applications which are not Arabic-aware), you might find that the
+\i{display becomes corrupted}. By ticking this box, you can disable
+bidirectional text display, so that PuTTY displays text from left to
+right in all situations.
+
+You may also find you need to disable Arabic text shaping;
+see \k{config-features-shaping}.
+
+\H{config-window} The Window panel
+
+The Window configuration panel allows you to control aspects of the
+\i{PuTTY window}.
+
+\S{config-winsize} Setting the \I{window size}size of the PuTTY window
+
+\cfg{winhelp-topic}{window.size}
+
+The \q{\ii{Columns}} and \q{\ii{Rows}} boxes let you set the PuTTY
+window to a precise size. Of course you can also \I{window resizing}drag
+the window to a new size while a session is running.
+
+\S{config-winsizelock} What to do when the window is resized
+
+\cfg{winhelp-topic}{window.resize}
+
+These options allow you to control what happens when the user tries
+to \I{window resizing}resize the PuTTY window using its window furniture.
+
+There are four options here:
+
+\b \q{Change the number of rows and columns}: the font size will not
+change. (This is the default.)
+
+\b \q{Change the size of the font}: the number of rows and columns in
+the terminal will stay the same, and the \i{font size} will change.
+
+\b \q{Change font size when maximised}: when the window is resized,
+the number of rows and columns will change, \e{except} when the window
+is \i{maximise}d (or restored), when the font size will change.
+
+\b \q{Forbid resizing completely}: the terminal will refuse to be
+resized at all.
+
+\S{config-scrollback} Controlling \i{scrollback}
+
+\cfg{winhelp-topic}{window.scrollback}
+
+These options let you configure the way PuTTY keeps text after it
+scrolls off the top of the screen (see \k{using-scrollback}).
+
+The \q{Lines of scrollback} box lets you configure how many lines of
+text PuTTY keeps. The \q{Display scrollbar} options allow you to
+hide the \i{scrollbar} (although you can still view the scrollback using
+the keyboard as described in \k{using-scrollback}). You can separately
+configure whether the scrollbar is shown in \i{full-screen} mode and in
+normal modes.
+
+If you are viewing part of the scrollback when the server sends more
+text to PuTTY, the screen will revert to showing the current
+terminal contents. You can disable this behaviour by turning off
+\q{Reset scrollback on display activity}. You can also make the
+screen revert when you press a key, by turning on \q{Reset
+scrollback on keypress}.
+
+\S{config-erasetoscrollback} \q{Push erased text into scrollback}
+
+\cfg{winhelp-topic}{window.erased}
+
+When this option is enabled, the contents of the terminal screen
+will be pushed into the scrollback when a server-side application
+clears the screen, so that your scrollback will contain a better
+record of what was on your screen in the past.
+
+If the application switches to the \i{alternate screen} (see
+\k{config-features-altscreen} for more about this), then the
+contents of the primary screen will be visible in the scrollback
+until the application switches back again.
+
+This option is enabled by default.
+
+\H{config-appearance} The Appearance panel
+
+The Appearance configuration panel allows you to control aspects of
+the appearance of \I{PuTTY window}PuTTY's window.
+
+\S{config-cursor} Controlling the appearance of the \i{cursor}
+
+\cfg{winhelp-topic}{appearance.cursor}
+
+The \q{Cursor appearance} option lets you configure the cursor to be
+a block, an underline, or a vertical line. A block cursor becomes an
+empty box when the window loses focus; an underline or a vertical
+line becomes dotted.
+
+The \q{\ii{Cursor blinks}} option makes the cursor blink on and off. This
+works in any of the cursor modes.
+
+\S{config-font} Controlling the \i{font} used in the terminal window
+
+\cfg{winhelp-topic}{appearance.font}
+
+This option allows you to choose what font, in what \I{font size}size,
+the PuTTY terminal window uses to display the text in the session. You
+will be offered a choice from all the fixed-width fonts installed on the
+system. (VT100-style terminal handling can only deal with fixed-width
+fonts.)
+
+\S{config-mouseptr} \q{Hide \i{mouse pointer} when typing in window}
+
+\cfg{winhelp-topic}{appearance.hidemouse}
+
+If you enable this option, the mouse pointer will disappear if the
+PuTTY window is selected and you press a key. This way, it will not
+obscure any of the text in the window while you work in your
+session. As soon as you move the mouse, the pointer will reappear.
+
+This option is disabled by default, so the mouse pointer remains
+visible at all times.
+
+\S{config-winborder} Controlling the \i{window border}
+
+\cfg{winhelp-topic}{appearance.border}
+
+PuTTY allows you to configure the appearance of the window border to
+some extent.
+
+The checkbox marked \q{Sunken-edge border} changes the appearance of
+the window border to something more like a DOS box: the inside edge
+of the border is highlighted as if it sank down to meet the surface
+inside the window. This makes the border a little bit thicker as
+well. It's hard to describe well. Try it and see if you like it.
+
+You can also configure a completely blank gap between the text in
+the window and the border, using the \q{Gap between text and window
+edge} control. By default this is set at one pixel. You can reduce
+it to zero, or increase it further.
+
+\H{config-behaviour} The Behaviour panel
+
+The Behaviour configuration panel allows you to control aspects of
+the behaviour of \I{PuTTY window}PuTTY's window.
+
+\S{config-title} Controlling the \i{window title}
+
+\cfg{winhelp-topic}{appearance.title}
+
+The \q{Window title} edit box allows you to set the title of the
+PuTTY window. By default the window title will contain the \i{host name}
+followed by \q{PuTTY}, for example \c{server1.example.com - PuTTY}.
+If you want a different window title, this is where to set it.
+
+PuTTY allows the server to send \c{xterm} \i{control sequence}s which
+modify the title of the window in mid-session (unless this is disabled -
+see \k{config-features-retitle}); the title string set here
+is therefore only the \e{initial} window title.
+
+As well as the \e{window} title, there is also an \c{xterm}
+sequence to modify the \I{icon title}title of the window's \e{icon}.
+This makes sense in a windowing system where the window becomes an
+icon when minimised, such as Windows 3.1 or most X Window System
+setups; but in the Windows 95-like user interface it isn't as
+applicable.
+
+By default, PuTTY only uses the server-supplied \e{window} title, and
+ignores the icon title entirely. If for some reason you want to see
+both titles, check the box marked \q{Separate window and icon titles}.
+If you do this, PuTTY's window title and Taskbar \I{window caption}caption will
+change into the server-supplied icon title if you \i{minimise} the PuTTY
+window, and change back to the server-supplied window title if you
+restore it. (If the server has not bothered to supply a window or
+icon title, none of this will happen.)
+
+\S{config-warnonclose} \q{Warn before \i{closing window}}
+
+\cfg{winhelp-topic}{behaviour.closewarn}
+
+If you press the \i{Close button} in a PuTTY window that contains a
+running session, PuTTY will put up a warning window asking if you
+really meant to close the window. A window whose session has already
+terminated can always be closed without a warning.
+
+If you want to be able to close a window quickly, you can disable
+the \q{Warn before closing window} option.
+
+\S{config-altf4} \q{Window closes on \i{ALT-F4}}
+
+\cfg{winhelp-topic}{behaviour.altf4}
+
+By default, pressing ALT-F4 causes the \I{closing window}window to
+close (or a warning box to appear; see \k{config-warnonclose}). If you
+disable the \q{Window closes on ALT-F4} option, then pressing ALT-F4
+will simply send a key sequence to the server.
+
+\S{config-altspace} \q{\ii{System menu} appears on \i{ALT-Space}}
+
+\cfg{winhelp-topic}{behaviour.altspace}
+
+If this option is enabled, then pressing ALT-Space will bring up the
+PuTTY window's menu, like clicking on the top left corner. If it is
+disabled, then pressing ALT-Space will just send \c{ESC SPACE} to
+the server.
+
+Some \i{accessibility} programs for Windows may need this option
+enabling to be able to control PuTTY's window successfully. For
+instance, \i{Dragon NaturallySpeaking} requires it both to open the
+system menu via voice, and to close, minimise, maximise and restore
+the window.
+
+\S{config-altonly} \q{\ii{System menu} appears on \i{Alt} alone}
+
+\cfg{winhelp-topic}{behaviour.altonly}
+
+If this option is enabled, then pressing and releasing ALT will
+bring up the PuTTY window's menu, like clicking on the top left
+corner. If it is disabled, then pressing and releasing ALT will have
+no effect.
+
+\S{config-alwaysontop} \q{Ensure window is \i{always on top}}
+
+\cfg{winhelp-topic}{behaviour.alwaysontop}
+
+If this option is enabled, the PuTTY window will stay on top of all
+other windows.
+
+\S{config-fullscreen} \q{\ii{Full screen} on Alt-Enter}
+
+\cfg{winhelp-topic}{behaviour.altenter}
+
+If this option is enabled, then pressing Alt-Enter will cause the
+PuTTY window to become full-screen. Pressing Alt-Enter again will
+restore the previous window size.
+
+The full-screen feature is also available from the \ii{System menu}, even
+when it is configured not to be available on the Alt-Enter key. See
+\k{using-fullscreen}.
+
+\H{config-translation} The Translation panel
+
+The Translation configuration panel allows you to control the
+translation between the \i{character set} understood by the server and
+the character set understood by PuTTY.
+
+\S{config-charset} Controlling character set translation
+
+\cfg{winhelp-topic}{translation.codepage}
+
+During an interactive session, PuTTY receives a stream of 8-bit
+bytes from the server, and in order to display them on the screen it
+needs to know what character set to interpret them in.
+
+There are a lot of character sets to choose from. The \q{Received
+data assumed to be in which character set} option lets you select
+one. By default PuTTY will attempt to choose a character set that is
+right for your \i{locale} as reported by Windows; if it gets it wrong,
+you can select a different one using this control.
+
+A few notable character sets are:
+
+\b The \i{ISO-8859} series are all standard character sets that include
+various accented characters appropriate for different sets of
+languages.
+
+\b The \i{Win125x} series are defined by Microsoft, for similar
+purposes. In particular Win1252 is almost equivalent to ISO-8859-1,
+but contains a few extra characters such as matched quotes and the
+Euro symbol.
+
+\b If you want the old IBM PC character set with block graphics and
+line-drawing characters, you can select \q{\i{CP437}}.
+
+\b PuTTY also supports \i{Unicode} mode, in which the data coming from
+the server is interpreted as being in the \i{UTF-8} encoding of Unicode.
+If you select \q{UTF-8} as a character set you can use this mode.
+Not all server-side applications will support it.
+
+If you need support for a numeric \i{code page} which is not listed in
+the drop-down list, such as code page 866, then you can try entering
+its name manually (\c{\i{CP866}} for example) in the list box. If the
+underlying version of Windows has the appropriate translation table
+installed, PuTTY will use it.
+
+\S{config-cjk-ambig-wide} \q{Treat \i{CJK} ambiguous characters as wide}
+
+\cfg{winhelp-topic}{translation.cjkambigwide}
+
+There are \I{East Asian Ambiguous characters}some Unicode characters
+whose \I{character width}width is not well-defined. In most contexts, such
+characters should be treated as single-width for the purposes of \I{wrapping,
+terminal}wrapping and so on; however, in some CJK contexts, they are better
+treated as double-width for historical reasons, and some server-side
+applications may expect them to be displayed as such. Setting this option
+will cause PuTTY to take the double-width interpretation.
+
+If you use legacy CJK applications, and you find your lines are
+wrapping in the wrong places, or you are having other display
+problems, you might want to play with this setting.
+
+This option only has any effect in \i{UTF-8} mode (see \k{config-charset}).
+
+\S{config-cyr} \q{\i{Caps Lock} acts as \i{Cyrillic} switch}
+
+\cfg{winhelp-topic}{translation.cyrillic}
+
+This feature allows you to switch between a US/UK keyboard layout
+and a Cyrillic keyboard layout by using the Caps Lock key, if you
+need to type (for example) \i{Russian} and English side by side in the
+same document.
+
+Currently this feature is not expected to work properly if your
+native keyboard layout is not US or UK.
+
+\S{config-linedraw} Controlling display of \i{line-drawing characters}
+
+\cfg{winhelp-topic}{translation.linedraw}
+
+VT100-series terminals allow the server to send \i{control sequence}s that
+shift temporarily into a separate character set for drawing simple
+lines and boxes. However, there are a variety of ways in which PuTTY
+can attempt to find appropriate characters, and the right one to use
+depends on the locally configured \i{font}. In general you should probably
+try lots of options until you find one that your particular font
+supports.
+
+\b \q{Use Unicode line drawing code points} tries to use the box
+characters that are present in \i{Unicode}. For good Unicode-supporting
+fonts this is probably the most reliable and functional option.
+
+\b \q{Poor man's line drawing} assumes that the font \e{cannot}
+generate the line and box characters at all, so it will use the
+\c{+}, \c{-} and \c{|} characters to draw approximations to boxes.
+You should use this option if none of the other options works.
+
+\b \q{Font has XWindows encoding} is for use with fonts that have a
+special encoding, where the lowest 32 character positions (below the
+ASCII printable range) contain the line-drawing characters. This is
+unlikely to be the case with any standard Windows font; it will
+probably only apply to custom-built fonts or fonts that have been
+automatically converted from the X Window System.
+
+\b \q{Use font in both ANSI and OEM modes} tries to use the same
+font in two different character sets, to obtain a wider range of
+characters. This doesn't always work; some fonts claim to be a
+different size depending on which character set you try to use.
+
+\b \q{Use font in OEM mode only} is more reliable than that, but can
+miss out other characters from the main character set.
+
+\S{config-linedrawpaste} Controlling \i{copy and paste} of line drawing
+characters
+
+\cfg{winhelp-topic}{selection.linedraw}
+
+By default, when you copy and paste a piece of the PuTTY screen that
+contains VT100 line and box drawing characters, PuTTY will paste
+them in the form they appear on the screen: either \i{Unicode} line
+drawing code points, or the \q{poor man's} line-drawing characters
+\c{+}, \c{-} and \c{|}. The checkbox \q{Copy and paste VT100 line
+drawing chars as lqqqk} disables this feature, so line-drawing
+characters will be pasted as the \i{ASCII} characters that were printed
+to produce them. This will typically mean they come out mostly as
+\c{q} and \c{x}, with a scattering of \c{jklmntuvw} at the corners.
+This might be useful if you were trying to recreate the same box
+layout in another program, for example.
+
+Note that this option only applies to line-drawing characters which
+\e{were} printed by using the VT100 mechanism. Line-drawing
+characters that were received as Unicode code points will paste as
+Unicode always.
+
+\H{config-selection} The Selection panel
+
+The Selection panel allows you to control the way \i{copy and paste}
+work in the PuTTY window.
+
+\S{config-rtfpaste} Pasting in \i{Rich Text Format}
+
+\cfg{winhelp-topic}{selection.rtf}
+
+If you enable \q{Paste to clipboard in RTF as well as plain text},
+PuTTY will write formatting information to the clipboard as well as
+the actual text you copy. The effect of this is
+that if you paste into (say) a word processor, the text will appear
+in the word processor in the same \i{font}, \i{colour}, and style
+(e.g. bold, underline) PuTTY was using to display it.
+
+This option can easily be inconvenient, so by default it is
+disabled.
+
+\S{config-mouse} Changing the actions of the mouse buttons
+
+\cfg{winhelp-topic}{selection.buttons}
+
+PuTTY's copy and paste mechanism is by default modelled on the Unix
+\c{xterm} application. The X Window System uses a three-button mouse,
+and the convention is that the \i{left button} \I{selecting text}selects,
+the \i{right button} extends an existing selection, and the
+\i{middle button} pastes.
+
+Windows often only has two mouse buttons, so in PuTTY's default
+configuration (\q{Compromise}), the \e{right} button pastes, and the
+\e{middle} button (if you have one) \I{adjusting a selection}extends
+a selection.
+
+If you have a \i{three-button mouse} and you are already used to the
+\c{xterm} arrangement, you can select it using the \q{Action of
+mouse buttons} control.
+
+Alternatively, with the \q{Windows} option selected, the middle
+button extends, and the right button brings up a \i{context menu} (on
+which one of the options is \q{Paste}). (This context menu is always
+available by holding down Ctrl and right-clicking, regardless of the
+setting of this option.)
+
+\S{config-mouseshift} \q{Shift overrides application's use of mouse}
+
+\cfg{winhelp-topic}{selection.shiftdrag}
+
+PuTTY allows the server to send \i{control codes} that let it
+\I{mouse reporting}take over the mouse and use it for purposes other
+than \i{copy and paste}.
+Applications which use this feature include the text-mode web
+browser \c{links}, the Usenet newsreader \c{trn} version 4, and the
+file manager \c{mc} (Midnight Commander).
+
+When running one of these applications, pressing the mouse buttons
+no longer performs copy and paste. If you do need to copy and paste,
+you can still do so if you hold down Shift while you do your mouse
+clicks.
+
+However, it is possible in theory for applications to even detect
+and make use of Shift + mouse clicks. We don't know of any
+applications that do this, but in case someone ever writes one,
+unchecking the \q{Shift overrides application's use of mouse}
+checkbox will cause Shift + mouse clicks to go to the server as well
+(so that mouse-driven copy and paste will be completely disabled).
+
+If you want to prevent the application from taking over the mouse at
+all, you can do this using the Features control panel; see
+\k{config-features-mouse}.
+
+\S{config-rectselect} Default selection mode
+
+\cfg{winhelp-topic}{selection.rect}
+
+As described in \k{using-selection}, PuTTY has two modes of
+selecting text to be copied to the clipboard. In the default mode
+(\q{Normal}), dragging the mouse from point A to point B selects to
+the end of the line containing A, all the lines in between, and from
+the very beginning of the line containing B. In the other mode
+(\q{Rectangular block}), dragging the mouse between two points
+defines a rectangle, and everything within that rectangle is copied.
+
+Normally, you have to hold down Alt while dragging the mouse to
+select a rectangular block. Using the \q{Default selection mode}
+control, you can set \i{rectangular selection} as the default, and then
+you have to hold down Alt to get the \e{normal} behaviour.
+
+\S{config-charclasses} Configuring \i{word-by-word selection}
+
+\cfg{winhelp-topic}{selection.charclasses}
+
+PuTTY will select a word at a time in the terminal window if you
+\i{double-click} to begin the drag. This panel allows you to control
+precisely what is considered to be a word.
+
+Each character is given a \e{class}, which is a small number
+(typically 0, 1 or 2). PuTTY considers a single word to be any
+number of adjacent characters in the same class. So by modifying the
+assignment of characters to classes, you can modify the word-by-word
+selection behaviour.
+
+In the default configuration, the \i{character classes} are:
+
+\b Class 0 contains \i{white space} and control characters.
+
+\b Class 1 contains most \i{punctuation}.
+
+\b Class 2 contains letters, numbers and a few pieces of punctuation
+(the double quote, minus sign, period, forward slash and
+underscore).
+
+So, for example, if you assign the \c{@} symbol into character class
+2, you will be able to select an e-mail address with just a double
+click.
+
+In order to adjust these assignments, you start by selecting a group
+of characters in the list box. Then enter a class number in the edit
+box below, and press the \q{Set} button.
+
+This mechanism currently only covers ASCII characters, because it
+isn't feasible to expand the list to cover the whole of Unicode.
+
+Character class definitions can be modified by \i{control sequence}s
+sent by the server. This configuration option controls the
+\e{default} state, which will be restored when you reset the
+terminal (see \k{reset-terminal}). However, if you modify this
+option in mid-session using \q{Change Settings}, it will take effect
+immediately.
+
+\H{config-colours} The Colours panel
+
+The Colours panel allows you to control PuTTY's use of \i{colour}.
+
+\S{config-ansicolour} \q{Allow terminal to specify \i{ANSI colours}}
+
+\cfg{winhelp-topic}{colours.ansi}
+
+This option is enabled by default. If it is disabled, PuTTY will
+ignore any \i{control sequence}s sent by the server to request coloured
+text.
+
+If you have a particularly garish application, you might want to
+turn this option off and make PuTTY only use the default foreground
+and background colours.
+
+\S{config-xtermcolour} \q{Allow terminal to use xterm \i{256-colour mode}}
+
+\cfg{winhelp-topic}{colours.xterm256}
+
+This option is enabled by default. If it is disabled, PuTTY will
+ignore any control sequences sent by the server which use the
+extended 256-colour mode supported by recent versions of \cw{xterm}.
+
+If you have an application which is supposed to use 256-colour mode
+and it isn't working, you may find you need to tell your server that
+your terminal supports 256 colours. On Unix, you do this by ensuring
+that the setting of \i\cw{TERM} describes a 256-colour-capable
+terminal. You can check this using a command such as \c{infocmp}:
+
+\c $ infocmp | grep colors
+\c colors#256, cols#80, it#8, lines#24, pairs#256,
+\e bbbbbbbbbb
+
+If you do not see \cq{colors#256} in the output, you may need to
+change your terminal setting. On modern Linux machines, you could
+try \cq{xterm-256color}.
+
+\S{config-boldcolour} \q{Bolded text is a different colour}
+
+\cfg{winhelp-topic}{colours.bold}
+
+When the server sends a \i{control sequence} indicating that some text
+should be displayed in \i{bold}, PuTTY can handle this two ways. It can
+either change the \i{font} for a bold version, or use the same font in a
+brighter colour. This control lets you choose which.
+
+By default the box is checked, so non-bold text is displayed in
+light grey and bold text is displayed in bright white (and similarly
+in other colours). If you uncheck the box, bold and non-bold text
+will be displayed in the same colour, and instead the font will
+change to indicate the difference.
+
+\S{config-logpalette} \q{Attempt to use \i{logical palettes}}
+
+\cfg{winhelp-topic}{colours.logpal}
+
+Logical palettes are a mechanism by which a Windows application
+running on an \i{8-bit colour} display can select precisely the colours
+it wants instead of going with the Windows standard defaults.
+
+If you are not getting the colours you ask for on an 8-bit display,
+you can try enabling this option. However, be warned that it's never
+worked very well.
+
+\S{config-syscolour} \q{Use \i{system colours}}
+
+\cfg{winhelp-topic}{colours.system}
+
+Enabling this option will cause PuTTY to ignore the configured colours
+for \I{default background}\I{default foreground}\q{Default
+Background/Foreground} and \I{cursor colour}\q{Cursor Colour/Text} (see
+\k{config-colourcfg}), instead going with the system-wide defaults.
+
+Note that non-bold and \i{bold text} will be the same colour if this
+option is enabled. You might want to change to indicating bold text
+by font changes (see \k{config-boldcolour}).
+
+\S{config-colourcfg} Adjusting the colours in the \i{terminal window}
+
+\cfg{winhelp-topic}{colours.config}
+
+The main colour control allows you to specify exactly what colours
+things should be displayed in. To modify one of the PuTTY colours,
+use the list box to select which colour you want to modify. The \i{RGB
+values} for that colour will appear on the right-hand side of the
+list box. Now, if you press the \q{Modify} button, you will be
+presented with a colour selector, in which you can choose a new
+colour to go in place of the old one. (You may also edit the RGB
+values directly in the edit boxes, if you wish; each value is an
+integer from 0 to 255.)
+
+PuTTY allows you to set the \i{cursor colour}, the \i{default foreground}
+and \I{default background}background, and the precise shades of all the
+\I{ANSI colours}ANSI configurable colours (black, red, green, yellow, blue,
+magenta, cyan, and white). You can also modify the precise shades used for
+the \i{bold} versions of these colours; these are used to display bold text
+if you have selected \q{Bolded text is a different colour}, and can also be
+used if the server asks specifically to use them. (Note that \q{Default
+Bold Background} is \e{not} the background colour used for bold text;
+it is only used if the server specifically asks for a bold
+background.)
+
+\H{config-connection} The Connection panel
+
+The Connection panel allows you to configure options that apply to
+more than one type of \i{connection}.
+
+\S{config-keepalive} Using \i{keepalives} to prevent disconnection
+
+\cfg{winhelp-topic}{connection.keepalive}
+
+If you find your sessions are closing unexpectedly (most often with
+\q{Connection reset by peer}) after they have been idle for a while,
+you might want to try using this option.
+
+Some network \i{routers} and \i{firewalls} need to keep track of all
+connections through them. Usually, these firewalls will assume a
+connection is dead if no data is transferred in either direction
+after a certain time interval. This can cause PuTTY sessions to be
+unexpectedly closed by the firewall if no traffic is seen in the
+session for some time.
+
+The keepalive option (\q{Seconds between keepalives}) allows you to
+configure PuTTY to send data through the session at regular
+intervals, in a way that does not disrupt the actual terminal
+session. If you find your firewall is cutting \i{idle connections} off,
+you can try entering a non-zero value in this field. The value is
+measured in seconds; so, for example, if your firewall cuts
+connections off after ten minutes then you might want to enter 300
+seconds (5 minutes) in the box.
+
+Note that keepalives are not always helpful. They help if you have a
+firewall which drops your connection after an idle period; but if
+the network between you and the server suffers from \i{breaks in
+connectivity} then keepalives can actually make things worse. If a
+session is idle, and connectivity is temporarily lost between the
+endpoints, but the connectivity is restored before either side tries
+to send anything, then there will be no problem - neither endpoint
+will notice that anything was wrong. However, if one side does send
+something during the break, it will repeatedly try to re-send, and
+eventually give up and abandon the connection. Then when
+connectivity is restored, the other side will find that the first
+side doesn't believe there is an open connection any more.
+Keepalives can make this sort of problem worse, because they
+increase the probability that PuTTY will attempt to send data during
+a break in connectivity. (Other types of periodic network activity
+can cause this behaviour; in particular, SSH-2 re-keys can have
+this effect. See \k{config-ssh-kex-rekey}.)
+
+Therefore, you might find that keepalives help
+connection loss, or you might find they make it worse, depending on
+what \e{kind} of network problems you have between you and the
+server.
+
+Keepalives are only supported in Telnet and SSH; the Rlogin and Raw
+protocols offer no way of implementing them. (For an alternative, see
+\k{config-tcp-keepalives}.)
+
+Note that if you are using \i{SSH-1} and the server has a bug that makes
+it unable to deal with SSH-1 ignore messages (see
+\k{config-ssh-bug-ignore1}), enabling keepalives will have no effect.
+
+\S{config-nodelay} \q{Disable \i{Nagle's algorithm}}
+
+\cfg{winhelp-topic}{connection.nodelay}
+
+Nagle's algorithm is a detail of TCP/IP implementations that tries
+to minimise the number of small data packets sent down a network
+connection. With Nagle's algorithm enabled, PuTTY's \i{bandwidth} usage
+will be slightly more efficient; with it disabled, you may find you
+get a faster response to your keystrokes when connecting to some
+types of server.
+
+The Nagle algorithm is disabled by default for \i{interactive connections}.
+
+\S{config-tcp-keepalives} \q{Enable \i{TCP keepalives}}
+
+\cfg{winhelp-topic}{connection.tcpkeepalive}
+
+\e{NOTE:} TCP keepalives should not be confused with the
+application-level keepalives described in \k{config-keepalive}. If in
+doubt, you probably want application-level keepalives; TCP keepalives
+are provided for completeness.
+
+The idea of TCP keepalives is similar to application-level keepalives,
+and the same caveats apply. The main differences are:
+
+\b TCP keepalives are available on \e{all} connection types, including
+Raw and Rlogin.
+
+\b The interval between TCP keepalives is usually much longer,
+typically two hours; this is set by the operating system, and cannot
+be configured within PuTTY.
+
+\b If the operating system does not receive a response to a keepalive,
+it may send out more in quick succession and terminate the connection
+if no response is received.
+
+TCP keepalives may be more useful for ensuring that \i{half-open connections}
+are terminated than for keeping a connection alive.
+
+TCP keepalives are disabled by default.
+
+\S{config-address-family} \I{Internet protocol version}\q{Internet protocol}
+
+\cfg{winhelp-topic}{connection.ipversion}
+
+This option allows the user to select between the old and new
+Internet protocols and addressing schemes (\i{IPv4} and \i{IPv6}). The
+default setting is \q{Auto}, which means PuTTY will do something
+sensible and try to guess which protocol you wanted. (If you specify
+a literal \i{Internet address}, it will use whichever protocol that
+address implies. If you provide a \i{hostname}, it will see what kinds
+of address exist for that hostname; it will use IPv6 if there is an
+IPv6 address available, and fall back to IPv4 if not.)
+
+If you need to force PuTTY to use a particular protocol, you can
+explicitly set this to \q{IPv4} or \q{IPv6}.
+
+\H{config-data} The Data panel
+
+The Data panel allows you to configure various pieces of data which
+can be sent to the server to affect your connection at the far end.
+
+Each option on this panel applies to more than one protocol.
+Options which apply to only one protocol appear on that protocol's
+configuration panels.
+
+\S{config-username} \q{\ii{Auto-login username}}
+
+\cfg{winhelp-topic}{connection.username}
+
+All three of the SSH, Telnet and Rlogin protocols allow you to
+specify what user name you want to log in as, without having to type
+it explicitly every time. (Some Telnet servers don't support this.)
+
+In this box you can type that user name.
+
+\S{config-termtype} \q{\ii{Terminal-type} string}
+
+\cfg{winhelp-topic}{connection.termtype}
+
+Most servers you might connect to with PuTTY are designed to be
+connected to from lots of different types of terminal. In order to
+send the right \i{control sequence}s to each one, the server will need
+to know what type of terminal it is dealing with. Therefore, each of
+the SSH, Telnet and Rlogin protocols allow a text string to be sent
+down the connection describing the terminal. On a \i{Unix} server,
+this selects an entry from the \i\c{termcap} or \i\c{terminfo} database
+that tells applications what \i{control sequences} to send to the
+terminal, and what character sequences to expect the \i{keyboard}
+to generate.
+
+PuTTY attempts to emulate the Unix \i\c{xterm} program, and by default
+it reflects this by sending \c{xterm} as a terminal-type string. If
+you find this is not doing what you want - perhaps the remote
+system reports \q{Unknown terminal type} - you could try setting
+this to something different, such as \i\c{vt220}.
+
+If you're not sure whether a problem is due to the terminal type
+setting or not, you probably need to consult the manual for your
+application or your server.
+
+\S{config-termspeed} \q{\ii{Terminal speed}s}
+
+\cfg{winhelp-topic}{connection.termspeed}
+
+The Telnet, Rlogin, and SSH protocols allow the client to specify
+terminal speeds to the server.
+
+This parameter does \e{not} affect the actual speed of the connection,
+which is always \q{as fast as possible}; it is just a hint that is
+sometimes used by server software to modify its behaviour. For
+instance, if a slow speed is indicated, the server may switch to a
+less \i{bandwidth}-hungry display mode.
+
+The value is usually meaningless in a network environment, but
+PuTTY lets you configure it, in case you find the server is reacting
+badly to the default value.
+
+The format is a pair of numbers separated by a comma, for instance,
+\c{38400,38400}. The first number represents the output speed
+(\e{from} the server) in bits per second, and the second is the input
+speed (\e{to} the server). (Only the first is used in the Rlogin
+protocol.)
+
+This option has no effect on Raw connections.
+
+\S{config-environ} Setting \i{environment variables} on the server
+
+\cfg{winhelp-topic}{telnet.environ}
+
+The Telnet protocol provides a means for the client to pass
+environment variables to the server. Many Telnet servers have
+stopped supporting this feature due to security flaws, but PuTTY
+still supports it for the benefit of any servers which have found
+other ways around the security problems than just disabling the
+whole mechanism.
+
+Version 2 of the SSH protocol also provides a similar mechanism,
+which is easier to implement without security flaws. Newer \i{SSH-2}
+servers are more likely to support it than older ones.
+
+This configuration data is not used in the SSH-1, rlogin or raw
+protocols.
+
+To add an environment variable to the list transmitted down the
+connection, you enter the variable name in the \q{Variable} box,
+enter its value in the \q{Value} box, and press the \q{Add} button.
+To remove one from the list, select it in the list box and press
+\q{Remove}.
+
+\H{config-proxy} The Proxy panel
+
+\cfg{winhelp-topic}{proxy.main}
+
+The \ii{Proxy} panel allows you to configure PuTTY to use various types
+of proxy in order to make its network connections. The settings in
+this panel affect the primary network connection forming your PuTTY
+session, and also any extra connections made as a result of SSH \i{port
+forwarding} (see \k{using-port-forwarding}).
+
+\S{config-proxy-type} Setting the proxy type
+
+\cfg{winhelp-topic}{proxy.type}
+
+The \q{Proxy type} radio buttons allow you to configure what type of
+proxy you want PuTTY to use for its network connections. The default
+setting is \q{None}; in this mode no proxy is used for any
+connection.
+
+\b Selecting \I{HTTP proxy}\q{HTTP} allows you to proxy your connections
+through a web server supporting the HTTP \cw{CONNECT} command, as documented
+in \W{http://www.ietf.org/rfc/rfc2817.txt}{RFC 2817}.
+
+\b Selecting \q{SOCKS 4} or \q{SOCKS 5} allows you to proxy your
+connections through a \i{SOCKS server}.
+
+\b Many firewalls implement a less formal type of proxy in which a
+user can make a Telnet connection directly to the firewall machine
+and enter a command such as \c{connect myhost.com 22} to connect
+through to an external host. Selecting \I{Telnet proxy}\q{Telnet}
+allows you to tell PuTTY to use this type of proxy.
+
+\b Selecting \I{Local proxy}\q{Local} allows you to specify an arbitrary
+command on the local machine to act as a proxy. When the session is
+started, instead of creating a TCP connection, PuTTY runs the command
+(specified in \k{config-proxy-command}), and uses its standard input and
+output streams.
+
+\lcont{
+This could be used, for instance, to talk to some kind of network proxy
+that PuTTY does not natively support; or you could tunnel a connection
+over something other than TCP/IP entirely.
+
+If you want your local proxy command to make a secondary SSH
+connection to a proxy host and then tunnel the primary connection
+over that, you might well want the \c{-nc} command-line option in
+Plink. See \k{using-cmdline-ncmode} for more information.
+}
+
+\S{config-proxy-exclude} Excluding parts of the network from proxying
+
+\cfg{winhelp-topic}{proxy.exclude}
+
+Typically you will only need to use a proxy to connect to non-local
+parts of your network; for example, your proxy might be required for
+connections outside your company's internal network. In the
+\q{Exclude Hosts/IPs} box you can enter ranges of IP addresses, or
+ranges of DNS names, for which PuTTY will avoid using the proxy and
+make a direct connection instead.
+
+The \q{Exclude Hosts/IPs} box may contain more than one exclusion
+range, separated by commas. Each range can be an IP address or a DNS
+name, with a \c{*} character allowing wildcards. For example:
+
+\c *.example.com
+
+This excludes any host with a name ending in \c{.example.com} from
+proxying.
+
+\c 192.168.88.*
+
+This excludes any host with an IP address starting with 192.168.88
+from proxying.
+
+\c 192.168.88.*,*.example.com
+
+This excludes both of the above ranges at once.
+
+Connections to the local host (the host name \i\c{localhost}, and any
+\i{loopback IP address}) are never proxied, even if the proxy exclude
+list does not explicitly contain them. It is very unlikely that this
+behaviour would ever cause problems, but if it does you can change
+it by enabling \q{Consider proxying local host connections}.
+
+Note that if you are doing \I{proxy DNS}DNS at the proxy (see
+\k{config-proxy-dns}), you should make sure that your proxy
+exclusion settings do not depend on knowing the IP address of a
+host. If the name is passed on to the proxy without PuTTY looking it
+up, it will never know the IP address and cannot check it against
+your list.
+
+\S{config-proxy-dns} \I{proxy DNS}\ii{Name resolution} when using a proxy
+
+\cfg{winhelp-topic}{proxy.dns}
+
+If you are using a proxy to access a private network, it can make a
+difference whether \i{DNS} name resolution is performed by PuTTY itself
+(on the client machine) or performed by the proxy.
+
+The \q{Do DNS name lookup at proxy end} configuration option allows
+you to control this. If you set it to \q{No}, PuTTY will always do
+its own DNS, and will always pass an IP address to the proxy. If you
+set it to \q{Yes}, PuTTY will always pass host names straight to the
+proxy without trying to look them up first.
+
+If you set this option to \q{Auto} (the default), PuTTY will do
+something it considers appropriate for each type of proxy. Telnet,
+HTTP, and SOCKS5 proxies will have host names passed straight to
+them; SOCKS4 proxies will not.
+
+Note that if you are doing DNS at the proxy, you should make sure
+that your proxy exclusion settings (see \k{config-proxy-exclude}) do
+not depend on knowing the IP address of a host. If the name is
+passed on to the proxy without PuTTY looking it up, it will never
+know the IP address and cannot check it against your list.
+
+The original SOCKS 4 protocol does not support proxy-side DNS. There
+is a protocol extension (SOCKS 4A) which does support it, but not
+all SOCKS 4 servers provide this extension. If you enable proxy DNS
+and your SOCKS 4 server cannot deal with it, this might be why.
+
+\S{config-proxy-auth} \I{proxy username}Username and \I{proxy password}password
+
+\cfg{winhelp-topic}{proxy.auth}
+
+If your proxy requires \I{proxy authentication}authentication, you can
+enter a username and a password in the \q{Username} and \q{Password} boxes.
+
+\I{security hazard}Note that if you save your session, the proxy
+password will be saved in plain text, so anyone who can access your PuTTY
+configuration data will be able to discover it.
+
+Authentication is not fully supported for all forms of proxy:
+
+\b Username and password authentication is supported for HTTP
+proxies and SOCKS 5 proxies.
+
+\lcont{
+
+\b With SOCKS 5, authentication is via \i{CHAP} if the proxy
+supports it (this is not supported in \i{PuTTYtel}); otherwise the
+password is sent to the proxy in \I{plaintext password}plain text.
+
+\b With HTTP proxying, the only currently supported authentication
+method is \I{HTTP basic}\q{basic}, where the password is sent to the proxy
+in \I{plaintext password}plain text.
+
+}
+
+\b SOCKS 4 can use the \q{Username} field, but does not support
+passwords.
+
+\b You can specify a way to include a username and password in the
+Telnet/Local proxy command (see \k{config-proxy-command}).
+
+\S{config-proxy-command} Specifying the Telnet or Local proxy command
+
+\cfg{winhelp-topic}{proxy.command}
+
+If you are using the \i{Telnet proxy} type, the usual command required
+by the firewall's Telnet server is \c{connect}, followed by a host
+name and a port number. If your proxy needs a different command,
+you can enter an alternative here.
+
+If you are using the \i{Local proxy} type, the local command to run
+is specified here.
+
+In this string, you can use \c{\\n} to represent a new-line, \c{\\r}
+to represent a carriage return, \c{\\t} to represent a tab
+character, and \c{\\x} followed by two hex digits to represent any
+other character. \c{\\\\} is used to encode the \c{\\} character
+itself.
+
+Also, the special strings \c{%host} and \c{%port} will be replaced
+by the host name and port number you want to connect to. The strings
+\c{%user} and \c{%pass} will be replaced by the proxy username and
+password you specify. The strings \c{%proxyhost} and \c{%proxyport}
+will be replaced by the host details specified on the \e{Proxy} panel,
+if any (this is most likely to be useful for the Local proxy type).
+To get a literal \c{%} sign, enter \c{%%}.
+
+If a Telnet proxy server prompts for a username and password
+before commands can be sent, you can use a command such as:
+
+\c %user\n%pass\nconnect %host %port\n
+
+This will send your username and password as the first two lines to
+the proxy, followed by a command to connect to the desired host and
+port. Note that if you do not include the \c{%user} or \c{%pass}
+tokens in the Telnet command, then the \q{Username} and \q{Password}
+configuration fields will be ignored.
+
+\H{config-telnet} The \i{Telnet} panel
+
+The Telnet panel allows you to configure options that only apply to
+Telnet sessions.
+
+\S{config-oldenviron} \q{Handling of OLD_ENVIRON ambiguity}
+
+\cfg{winhelp-topic}{telnet.oldenviron}
+
+The original Telnet mechanism for passing \i{environment variables} was
+badly specified. At the time the standard (RFC 1408) was written,
+BSD telnet implementations were already supporting the feature, and
+the intention of the standard was to describe the behaviour the BSD
+implementations were already using.
+
+Sadly there was a typing error in the standard when it was issued,
+and two vital function codes were specified the wrong way round. BSD
+implementations did not change, and the standard was not corrected.
+Therefore, it's possible you might find either \i{BSD} or \i{RFC}-compliant
+implementations out there. This switch allows you to choose which
+one PuTTY claims to be.
+
+The problem was solved by issuing a second standard, defining a new
+Telnet mechanism called \i\cw{NEW_ENVIRON}, which behaved exactly like
+the original \i\cw{OLD_ENVIRON} but was not encumbered by existing
+implementations. Most Telnet servers now support this, and it's
+unambiguous. This feature should only be needed if you have trouble
+passing environment variables to quite an old server.
+
+\S{config-ptelnet} Passive and active \i{Telnet negotiation} modes
+
+\cfg{winhelp-topic}{telnet.passive}
+
+In a Telnet connection, there are two types of data passed between
+the client and the server: actual text, and \e{negotiations} about
+which Telnet extra features to use.
+
+PuTTY can use two different strategies for negotiation:
+
+\b In \I{active Telnet negotiation}\e{active} mode, PuTTY starts to send
+negotiations as soon as the connection is opened.
+
+\b In \I{passive Telnet negotiation}\e{passive} mode, PuTTY will wait to
+negotiate until it sees a negotiation from the server.
+
+The obvious disadvantage of passive mode is that if the server is
+also operating in a passive mode, then negotiation will never begin
+at all. For this reason PuTTY defaults to active mode.
+
+However, sometimes passive mode is required in order to successfully
+get through certain types of firewall and \i{Telnet proxy} server. If
+you have confusing trouble with a \i{firewall}, you could try enabling
+passive mode to see if it helps.
+
+\S{config-telnetkey} \q{Keyboard sends \i{Telnet special commands}}
+
+\cfg{winhelp-topic}{telnet.specialkeys}
+
+If this box is checked, several key sequences will have their normal
+actions modified:
+
+\b the Backspace key on the keyboard will send the \I{Erase Character,
+Telnet special command}Telnet special backspace code;
+
+\b Control-C will send the Telnet special \I{Interrupt Process, Telnet
+special command}Interrupt Process code;
+
+\b Control-Z will send the Telnet special \I{Suspend Process, Telnet
+special command}Suspend Process code.
+
+You probably shouldn't enable this
+unless you know what you're doing.
+
+\S{config-telnetnl} \q{Return key sends \i{Telnet New Line} instead of ^M}
+
+\cfg{winhelp-topic}{telnet.newline}
+
+Unlike most other remote login protocols, the Telnet protocol has a
+special \q{\i{new line}} code that is not the same as the usual line
+endings of Control-M or Control-J. By default, PuTTY sends the
+Telnet New Line code when you press Return, instead of sending
+Control-M as it does in most other protocols.
+
+Most Unix-style Telnet servers don't mind whether they receive
+Telnet New Line or Control-M; some servers do expect New Line, and
+some servers prefer to see ^M. If you are seeing surprising
+behaviour when you press Return in a Telnet session, you might try
+turning this option off to see if it helps.
+
+\H{config-rlogin} The Rlogin panel
+
+The \i{Rlogin} panel allows you to configure options that only apply to
+Rlogin sessions.
+
+\S{config-rlogin-localuser} \I{local username in Rlogin}\q{Local username}
+
+\cfg{winhelp-topic}{rlogin.localuser}
+
+Rlogin allows an automated (password-free) form of login by means of
+a file called \i\c{.rhosts} on the server. You put a line in your
+\c{.rhosts} file saying something like \c{jbloggs@pc1.example.com},
+and then when you make an Rlogin connection the client transmits the
+username of the user running the Rlogin client. The server checks
+the username and hostname against \c{.rhosts}, and if they match it
+\I{passwordless login}does not ask for a password.
+
+This only works because Unix systems contain a safeguard to stop a
+user from pretending to be another user in an Rlogin connection.
+Rlogin connections have to come from \I{privileged port}port numbers below
+1024, and Unix systems prohibit this to unprivileged processes; so when the
+server sees a connection from a low-numbered port, it assumes the
+client end of the connection is held by a privileged (and therefore
+trusted) process, so it believes the claim of who the user is.
+
+Windows does not have this restriction: \e{any} user can initiate an
+outgoing connection from a low-numbered port. Hence, the Rlogin
+\c{.rhosts} mechanism is completely useless for securely
+distinguishing several different users on a Windows machine. If you
+have a \c{.rhosts} entry pointing at a Windows PC, you should assume
+that \e{anyone} using that PC can \i{spoof} your username in
+an Rlogin connection and access your account on the server.
+
+The \q{Local username} control allows you to specify what user name
+PuTTY should claim you have, in case it doesn't match your \i{Windows
+user name} (or in case you didn't bother to set up a Windows user
+name).
+
+\H{config-ssh} The SSH panel
+
+The \i{SSH} panel allows you to configure options that only apply to
+SSH sessions.
+
+\S{config-command} Executing a specific command on the server
+
+\cfg{winhelp-topic}{ssh.command}
+
+In SSH, you don't have to run a general shell session on the server.
+Instead, you can choose to run a single specific command (such as a
+mail user agent, for example). If you want to do this, enter the
+command in the \q{\ii{Remote command}} box.
+
+Note that most servers will close the session after executing the
+command.
+
+\S{config-ssh-noshell} \q{Don't start a \I{remote shell}shell or
+\I{remote command}command at all}
+
+\cfg{winhelp-topic}{ssh.noshell}
+
+If you tick this box, PuTTY will not attempt to run a shell or
+command after connecting to the remote server. You might want to use
+this option if you are only using the SSH connection for \i{port
+forwarding}, and your user account on the server does not have the
+ability to run a shell.
+
+This feature is only available in \i{SSH protocol version 2} (since the
+version 1 protocol assumes you will always want to run a shell).
+
+This feature can also be enabled using the \c{-N} command-line
+option; see \k{using-cmdline-noshell}.
+
+If you use this feature in Plink, you will not be able to terminate
+the Plink process by any graceful means; the only way to kill it
+will be by pressing Control-C or sending a kill signal from another
+program.
+
+\S{config-ssh-comp} \q{Enable \i{compression}}
+
+\cfg{winhelp-topic}{ssh.compress}
+
+This enables data compression in the SSH connection: data sent by
+the server is compressed before sending, and decompressed at the
+client end. Likewise, data sent by PuTTY to the server is compressed
+first and the server decompresses it at the other end. This can help
+make the most of a low-\i{bandwidth} connection.
+
+\S{config-ssh-prot} \q{Preferred \i{SSH protocol version}}
+
+\cfg{winhelp-topic}{ssh.protocol}
+
+This allows you to select whether you would like to use \i{SSH protocol
+version 1} or \I{SSH-2}version 2. \#{FIXME: say something about this elsewhere?}
+
+PuTTY will attempt to use protocol 1 if the server you connect to
+does not offer protocol 2, and vice versa.
+
+If you select \q{1 only} or \q{2 only} here, PuTTY will only connect
+if the server you connect to offers the SSH protocol version you
+have specified.
+
+\S{config-ssh-encryption} \ii{Encryption} algorithm selection
+
+\cfg{winhelp-topic}{ssh.ciphers}
+
+PuTTY supports a variety of different \i{encryption algorithm}s, and
+allows you to choose which one you prefer to use. You can do this by
+dragging the algorithms up and down in the list box (or moving them
+using the Up and Down buttons) to specify a preference order. When
+you make an SSH connection, PuTTY will search down the list from the
+top until it finds an algorithm supported by the server, and then
+use that.
+
+PuTTY currently supports the following algorithms:
+
+\b \i{AES} (Rijndael) - 256, 192, or 128-bit SDCTR or CBC (SSH-2 only)
+
+\b \i{Arcfour} (RC4) - 256 or 128-bit stream cipher (SSH-2 only)
+
+\b \i{Blowfish} - 256-bit SDCTR (SSH-2 only) or 128-bit CBC
+
+\b \ii{Triple-DES} - 168-bit SDCTR (SSH-2 only) or CBC
+
+\b \ii{Single-DES} - 56-bit CBC (see below for SSH-2)
+
+If the algorithm PuTTY finds is below the \q{warn below here} line,
+you will see a warning box when you make the connection:
+
+\c The first cipher supported by the server
+\c is single-DES, which is below the configured
+\c warning threshold.
+\c Do you want to continue with this connection?
+
+This warns you that the first available encryption is not a very
+secure one. Typically you would put the \q{warn below here} line
+between the encryptions you consider secure and the ones you
+consider substandard. By default, PuTTY supplies a preference order
+intended to reflect a reasonable preference in terms of security and
+speed.
+
+In SSH-2, the encryption algorithm is negotiated independently for
+each direction of the connection, although PuTTY does not support
+separate configuration of the preference orders. As a result you may
+get two warnings similar to the one above, possibly with different
+encryptions.
+
+Single-DES is not recommended in the SSH-2 protocol
+standards, but one or two server implementations do support it.
+PuTTY can use single-DES to interoperate with
+these servers if you enable the \q{Enable legacy use of single-DES in
+SSH-2} option; by default this is disabled and PuTTY will stick to
+recommended ciphers.
+
+\H{config-ssh-kex} The Kex panel
+
+\# FIXME: This whole section is draft. Feel free to revise.
+
+The Kex panel (short for \q{\i{key exchange}}) allows you to configure
+options related to SSH-2 key exchange.
+
+Key exchange occurs at the start of an SSH connection (and
+occasionally thereafter); it establishes a \i{shared secret} that is used
+as the basis for all of SSH's security features. It is therefore very
+important for the security of the connection that the key exchange is
+secure.
+
+Key exchange is a cryptographically intensive process; if either the
+client or the server is a relatively slow machine, the slower methods
+may take several tens of seconds to complete.
+
+If connection startup is too slow, or the connection hangs
+periodically, you may want to try changing these settings.
+
+If you don't understand what any of this means, it's safe to leave
+these settings alone.
+
+This entire panel is only relevant to SSH protocol version 2; none of
+these settings affect SSH-1 at all.
+
+\S{config-ssh-kex-order} \ii{Key exchange algorithm} selection
+
+\cfg{winhelp-topic}{ssh.kex.order}
+
+PuTTY supports a variety of SSH-2 key exchange methods, and allows you
+to choose which one you prefer to use; configuration is similar to
+cipher selection (see \k{config-ssh-encryption}).
+
+PuTTY currently supports the following varieties of \i{Diffie-Hellman key
+exchange}:
+
+\b \q{Group 14}: a well-known 2048-bit group.
+
+\b \q{Group 1}: a well-known 1024-bit group. This is less secure
+\#{FIXME better words} than group 14, but may be faster with slow
+client or server machines, and may be the only method supported by
+older server software.
+
+\b \q{\ii{Group exchange}}: with this method, instead of using a fixed
+group, PuTTY requests that the server suggest a group to use for key
+exchange; the server can avoid groups known to be weak, and possibly
+invent new ones over time, without any changes required to PuTTY's
+configuration. We recommend use of this method, if possible.
+
+If the first algorithm PuTTY finds is below the \q{warn below here}
+line, you will see a warning box when you make the connection, similar
+to that for cipher selection (see \k{config-ssh-encryption}).
+
+\S{config-ssh-kex-rekey} \ii{Repeat key exchange}
+
+\cfg{winhelp-topic}{ssh.kex.repeat}
+
+If the session key negotiated at connection startup is used too much
+or for too long, it may become feasible to mount attacks against the
+SSH connection. Therefore, the SSH-2 protocol specifies that a new key
+exchange should take place every so often; this can be initiated by
+either the client or the server.
+
+While this renegotiation is taking place, no data can pass through
+the SSH connection, so it may appear to \q{freeze}. (The occurrence of
+repeat key exchange is noted in the Event Log; see
+\k{using-eventlog}.) Usually the same algorithm is used as at the
+start of the connection, with a similar overhead.
+
+These options control how often PuTTY will initiate a repeat key
+exchange (\q{rekey}). You can also force a key exchange at any time
+from the Special Commands menu (see \k{using-specials}).
+
+\# FIXME: do we have any additions to the SSH-2 specs' advice on
+these values? Do we want to enforce any limits?
+
+\b \q{Max minutes before rekey} specifies the amount of time that is
+allowed to elapse before a rekey is initiated. If this is set to zero,
+PuTTY will not rekey due to elapsed time. The SSH-2 protocol
+specification recommends a timeout of at most 60 minutes.
+
+You might have a need to disable time-based rekeys completely for the same
+reasons that \i{keepalives} aren't always helpful. If you anticipate
+suffering a network dropout of several hours in the middle of an SSH
+connection, but were not actually planning to send \e{data} down
+that connection during those hours, then an attempted rekey in the
+middle of the dropout will probably cause the connection to be
+abandoned, whereas if rekeys are disabled then the connection should
+in principle survive (in the absence of interfering \i{firewalls}). See
+\k{config-keepalive} for more discussion of these issues; for these
+purposes, rekeys have much the same properties as keepalives.
+(Except that rekeys have cryptographic value in themselves, so you
+should bear that in mind when deciding whether to turn them off.)
+Note, however, the the SSH \e{server} can still initiate rekeys.
+
+\b \q{Max data before rekey} specifies the amount of data (in bytes)
+that is permitted to flow in either direction before a rekey is
+initiated. If this is set to zero, PuTTY will not rekey due to
+transferred data. The SSH-2 protocol specification recommends a limit
+of at most 1 gigabyte.
+
+\lcont{
+
+As well as specifying a value in bytes, the following shorthand can be
+used:
+
+\b \cq{1k} specifies 1 kilobyte (1024 bytes).
+
+\b \cq{1M} specifies 1 megabyte (1024 kilobytes).
+
+\b \cq{1G} specifies 1 gigabyte (1024 megabytes).
+
+}
+
+Disabling data-based rekeys entirely is a bad idea. The \i{integrity},
+and to a lesser extent, \i{confidentiality} of the SSH-2 protocol depend
+in part on rekeys occuring before a 32-bit packet sequence number
+wraps around. Unlike time-based rekeys, data-based rekeys won't occur
+when the SSH connection is idle, so they shouldn't cause the same
+problems. The SSH-1 protocol, incidentally, has even weaker integrity
+protection than SSH-2 without rekeys.
+
+\H{config-ssh-auth} The Auth panel
+
+The Auth panel allows you to configure \i{authentication} options for
+SSH sessions.
+
+\S{config-ssh-noauth} \q{Bypass authentication entirely}
+
+\cfg{winhelp-topic}{ssh.auth.bypass}
+
+In SSH-2, it is possible to establish a connection without using SSH's
+mechanisms to identify or authenticate oneself to the server. Some
+servers may prefer to handle authentication in the data channel, for
+instance, or may simply require no authentication whatsoever.
+
+By default, PuTTY assumes the server requires authentication (most
+do), and thus must provide a username. If you find you are getting
+unwanted username prompts, you could try checking this option.
+
+This option only affects SSH-2 connections. SSH-1 connections always
+require an authentication step.
+
+\S{config-ssh-tryagent} \q{Attempt authentication using Pageant}
+
+\cfg{winhelp-topic}{ssh.auth.pageant}
+
+If this option is enabled, then PuTTY will look for Pageant (the SSH
+private-key storage agent) and attempt to authenticate with any
+suitable public keys Pageant currently holds.
+
+This behaviour is almost always desirable, and is therefore enabled
+by default. In rare cases you might need to turn it off in order to
+force authentication by some non-public-key method such as
+passwords.
+
+This option can also be controlled using the \c{-noagent}
+command-line option. See \k{using-cmdline-agentauth}.
+
+See \k{pageant} for more information about Pageant in general.
+
+\S{config-ssh-tis} \q{Attempt \I{TIS authentication}TIS or
+\i{CryptoCard authentication}}
+
+\cfg{winhelp-topic}{ssh.auth.tis}
+
+TIS and CryptoCard authentication are (despite their names) generic
+forms of simple \I{challenge/response authentication}challenge/response
+authentication available in SSH protocol version 1 only. You might use
+them if you were using \i{S/Key} \i{one-time passwords}, for example,
+or if you had a physical \i{security token} that generated responses
+to authentication challenges.
+
+With this switch enabled, PuTTY will attempt these forms of
+authentication if the server is willing to try them. You will be
+presented with a challenge string (which will be different every
+time) and must supply the correct response in order to log in. If
+your server supports this, you should talk to your system
+administrator about precisely what form these challenges and
+responses take.
+
+\S{config-ssh-ki} \q{Attempt \i{keyboard-interactive authentication}}
+
+\cfg{winhelp-topic}{ssh.auth.ki}
+
+The SSH-2 equivalent of TIS authentication is called
+\q{keyboard-interactive}. It is a flexible authentication method
+using an arbitrary sequence of requests and responses; so it is not
+only useful for \I{challenge/response authentication}challenge/response
+mechanisms such as \i{S/Key}, but it can also be used for (for example)
+asking the user for a \I{password expiry}new password when the old one
+has expired.
+
+PuTTY leaves this option enabled by default, but supplies a switch
+to turn it off in case you should have trouble with it.
+
+\S{config-ssh-agentfwd} \q{Allow \i{agent forwarding}}
+
+\cfg{winhelp-topic}{ssh.auth.agentfwd}
+
+This option allows the SSH server to open forwarded connections back
+to your local copy of \i{Pageant}. If you are not running Pageant, this
+option will do nothing.
+
+See \k{pageant} for general information on Pageant, and
+\k{pageant-forward} for information on agent forwarding. Note that
+there is a security risk involved with enabling this option; see
+\k{pageant-security} for details.
+
+\S{config-ssh-changeuser} \q{Allow attempted \i{changes of username} in SSH-2}
+
+\cfg{winhelp-topic}{ssh.auth.changeuser}
+
+In the SSH-1 protocol, it is impossible to change username after
+failing to authenticate. So if you mis-type your username at the
+PuTTY \q{login as:} prompt, you will not be able to change it except
+by restarting PuTTY.
+
+The SSH-2 protocol \e{does} allow changes of username, in principle,
+but does not make it mandatory for SSH-2 servers to accept them. In
+particular, \i{OpenSSH} does not accept a change of username; once you
+have sent one username, it will reject attempts to try to
+authenticate as another user. (Depending on the version of OpenSSH,
+it may quietly return failure for all login attempts, or it may send
+an error message.)
+
+For this reason, PuTTY will by default not prompt you for your
+username more than once, in case the server complains. If you know
+your server can cope with it, you can enable the \q{Allow attempted
+changes of username} option to modify PuTTY's behaviour.
+
+\S{config-ssh-privkey} \q{\ii{Private key} file for authentication}
+
+\cfg{winhelp-topic}{ssh.auth.privkey}
+
+This box is where you enter the name of your private key file if you
+are using \i{public key authentication}. See \k{pubkey} for information
+about public key authentication in SSH.
+
+This key must be in PuTTY's native format (\c{*.\i{PPK}}). If you have a
+private key in another format that you want to use with PuTTY, see
+\k{puttygen-conversions}.
+
+If a key file is specified here, and \i{Pageant} is running (see
+\k{pageant}), PuTTY will first try asking Pageant to authenticate with
+that key, and ignore any other keys Pageant may have. If that fails,
+PuTTY will ask for a passphrase as normal.
+
+\H{config-ssh-tty} The TTY panel
+
+The TTY panel lets you configure the remote pseudo-terminal.
+
+\S{config-ssh-pty} \I{pseudo-terminal allocation}\q{Don't allocate
+a pseudo-terminal}
+
+\cfg{winhelp-topic}{ssh.nopty}
+
+When connecting to a \i{Unix} system, most \I{interactive
+connections}interactive shell sessions are run in a \e{pseudo-terminal},
+which allows the Unix system to pretend it's talking to a real physical
+terminal device but allows the SSH server to catch all the data coming
+from that fake device and send it back to the client.
+
+Occasionally you might find you have a need to run a session \e{not}
+in a pseudo-terminal. In PuTTY, this is generally only useful for
+very specialist purposes; although in Plink (see \k{plink}) it is
+the usual way of working.
+
+\S{config-ttymodes} Sending \i{terminal modes}
+
+\cfg{winhelp-topic}{ssh.ttymodes}
+
+The SSH protocol allows the client to send \q{terminal modes} for
+the remote pseudo-terminal. These usually control the server's
+expectation of the local terminal's behaviour.
+
+If your server does not have sensible defaults for these modes, you
+may find that changing them here helps. If you don't understand any of
+this, it's safe to leave these settings alone.
+
+(None of these settings will have any effect if no pseudo-terminal
+is requested or allocated.)
+
+You can add or modify a mode by selecting it from the drop-down list,
+choosing whether it's set automatically or to a specific value with
+the radio buttons and edit box, and hitting \q{Add}. A mode (or
+several) can be removed from the list by selecting them and hitting
+\q{Remove}. The effect of the mode list is as follows:
+
+\b If a mode is not on the list, it will not be specified to the
+server under any circumstances.
+
+\b If a mode is on the list:
+
+\lcont{
+
+\b If the \q{Auto} option is selected, the PuTTY tools will decide
+whether to specify that mode to the server, and if so, will send
+a sensible value.
+
+\lcont{
+
+PuTTY proper will send modes that it has an opinion on (currently only
+the code for the Backspace key, \cw{ERASE}). Plink on Unix
+will propagate appropriate modes from the local terminal, if any.
+
+}
+
+\b If a value is specified, it will be sent to the server under all
+circumstances. The precise syntax of the value box depends on the
+mode.
+
+}
+
+By default, all of the available modes are listed as \q{Auto},
+which should do the right thing in most circumstances.
+
+The precise effect of each setting, if any, is up to the server. Their
+names come from \i{POSIX} and other Unix systems, and they are most
+likely to have a useful effect on such systems. (These are the same
+settings that can usually be changed using the \i\c{stty} command once
+logged in to such servers.)
+
+Some notable modes are described below; for fuller explanations, see
+your server documentation.
+
+\b \I{ERASE special character}\cw{ERASE} is the character that when typed
+by the user will delete one space to the left. When set to \q{Auto}
+(the default setting), this follows the setting of the local Backspace
+key in PuTTY (see \k{config-backspace}).
+
+\lcont{
+This and other \i{special character}s are specified using \c{^C} notation
+for Ctrl-C, and so on. Use \c{^<27>} or \c{^<0x1B>} to specify a
+character numerically, and \c{^~} to get a literal \c{^}. Other
+non-control characters are denoted by themselves. Leaving the box
+entirely blank indicates that \e{no} character should be assigned to
+the specified function, although this may not be supported by all
+servers.
+}
+
+\b \I{QUIT special character}\cw{QUIT} is a special character that
+usually forcefully ends the current process on the server
+(\cw{SIGQUIT}). On many servers its default setting is Ctrl-backslash
+(\c{^\\}), which is easy to accidentally invoke on many keyboards. If
+this is getting in your way, you may want to change it to another
+character or turn it off entirely.
+
+\b Boolean modes such as \cw{ECHO} and \cw{ICANON} can be specified in
+PuTTY in a variety of ways, such as \cw{true}/\cw{false},
+\cw{yes}/\cw{no}, and \cw{0}/\cw{1}.
+
+\b Terminal speeds are configured elsewhere; see \k{config-termspeed}.
+
+\H{config-ssh-x11} The X11 panel
+
+\cfg{winhelp-topic}{ssh.tunnels.x11}
+
+The X11 panel allows you to configure \i{forwarding of X11} over an
+SSH connection.
+
+If your server lets you run X Window System applications, X11
+forwarding allows you to securely give those applications access to
+a local X display on your PC.
+
+To enable X11 forwarding, check the \q{Enable X11 forwarding} box.
+If your X display is somewhere unusual, you will need to enter its
+location in the \q{X display location} box; if this is left blank,
+PuTTY will try to find a sensible default in the environment, or use the
+primary local display (\c{:0}) if that fails.
+
+See \k{using-x-forwarding} for more information about X11
+forwarding.
+
+\S{config-ssh-x11auth} Remote \i{X11 authentication}
+
+\cfg{winhelp-topic}{ssh.tunnels.x11auth}
+
+If you are using X11 forwarding, the virtual X server created on the
+SSH server machine will be protected by authorisation data. This
+data is invented, and checked, by PuTTY.
+
+The usual authorisation method used for this is called
+\i\cw{MIT-MAGIC-COOKIE-1}. This is a simple password-style protocol:
+the X client sends some cookie data to the server, and the server
+checks that it matches the real cookie. The cookie data is sent over
+an unencrypted X11 connection; so if you allow a client on a third
+machine to access the virtual X server, then the cookie will be sent
+in the clear.
+
+PuTTY offers the alternative protocol \i\cw{XDM-AUTHORIZATION-1}. This
+is a cryptographically authenticated protocol: the data sent by the
+X client is different every time, and it depends on the IP address
+and port of the client's end of the connection and is also stamped
+with the current time. So an eavesdropper who captures an
+\cw{XDM-AUTHORIZATION-1} string cannot immediately re-use it for
+their own X connection.
+
+PuTTY's support for \cw{XDM-AUTHORIZATION-1} is a somewhat
+experimental feature, and may encounter several problems:
+
+\b Some X clients probably do not even support
+\cw{XDM-AUTHORIZATION-1}, so they will not know what to do with the
+data PuTTY has provided.
+
+\b This authentication mechanism will only work in SSH-2. In SSH-1,
+the SSH server does not tell the client the source address of
+a forwarded connection in a machine-readable format, so it's
+impossible to verify the \cw{XDM-AUTHORIZATION-1} data.
+
+\b You may find this feature causes problems with some SSH servers,
+which will not clean up \cw{XDM-AUTHORIZATION-1} data after a
+session, so that if you then connect to the same server using
+a client which only does \cw{MIT-MAGIC-COOKIE-1} and are allocated
+the same remote display number, you might find that out-of-date
+authentication data is still present on your server and your X
+connections fail.
+
+PuTTY's default is \cw{MIT-MAGIC-COOKIE-1}. If you change it, you
+should be sure you know what you're doing.
+
+\H{config-ssh-portfwd} \I{port forwarding}The Tunnels panel
+
+\cfg{winhelp-topic}{ssh.tunnels.portfwd}
+
+The Tunnels panel allows you to configure tunnelling of arbitrary
+connection types through an SSH connection.
+
+Port forwarding allows you to tunnel other types of \i{network
+connection} down an SSH session. See \k{using-port-forwarding} for a
+general discussion of port forwarding and how it works.
+
+The port forwarding section in the Tunnels panel shows a list of all
+the port forwardings that PuTTY will try to set up when it connects
+to the server. By default no port forwardings are set up, so this
+list is empty.
+
+To add a port forwarding:
+
+\b Set one of the \q{Local} or \q{Remote} radio buttons, depending
+on whether you want to \I{local port forwarding}forward a local port
+to a remote destination (\q{Local}) or \I{remote port forwarding}forward
+a remote port to a local destination (\q{Remote}). Alternatively,
+select \q{Dynamic} if you want PuTTY to \I{dynamic port forwarding}provide
+a local SOCKS 4/4A/5 proxy on a local port (note that this proxy only
+supports TCP connections; the SSH protocol does not support forwarding
+\i{UDP}).
+
+\b Enter a source \i{port number} into the \q{Source port} box. For
+local forwardings, PuTTY will listen on this port of your PC. For
+remote forwardings, your SSH server will listen on this port of the
+remote machine. Note that most servers will not allow you to listen
+on \I{privileged port}port numbers less than 1024.
+
+\b If you have selected \q{Local} or \q{Remote} (this step is not
+needed with \q{Dynamic}), enter a hostname and port number separated
+by a colon, in the \q{Destination} box. Connections received on the
+source port will be directed to this destination. For example, to
+connect to a POP-3 server, you might enter
+\c{popserver.example.com:110}.
+
+\b Click the \q{Add} button. Your forwarding details should appear
+in the list box.
+
+To remove a port forwarding, simply select its details in the list
+box, and click the \q{Remove} button.
+
+In the \q{Source port} box, you can also optionally enter an \I{listen
+address}IP address to listen on, by specifying (for instance)
+\c{127.0.0.5:79}.
+See \k{using-port-forwarding} for more information on how this
+works and its restrictions.
+
+In place of port numbers, you can enter \i{service names}, if they are
+known to the local system. For instance, in the \q{Destination} box,
+you could enter \c{popserver.example.com:pop3}.
+
+You can \I{port forwarding, changing mid-session}modify the currently
+active set of port forwardings in mid-session using \q{Change
+Settings} (see \k{using-changesettings}). If you delete a local or
+dynamic port forwarding in mid-session, PuTTY will stop listening for
+connections on that port, so it can be re-used by another program. If
+you delete a remote port forwarding, note that:
+
+\b The SSH-1 protocol contains no mechanism for asking the server to
+stop listening on a remote port.
+
+\b The SSH-2 protocol does contain such a mechanism, but not all SSH
+servers support it. (In particular, \i{OpenSSH} does not support it in
+any version earlier than 3.9.)
+
+If you ask to delete a remote port forwarding and PuTTY cannot make
+the server actually stop listening on the port, it will instead just
+start refusing incoming connections on that port. Therefore,
+although the port cannot be reused by another program, you can at
+least be reasonably sure that server-side programs can no longer
+access the service at your end of the port forwarding.
+
+If you delete a forwarding, any existing connections established using
+that forwarding remain open. Similarly, changes to global settings
+such as \q{Local ports accept connections from other hosts} only take
+effect on new forwardings.
+
+\S{config-ssh-portfwd-localhost} Controlling the visibility of
+forwarded ports
+
+\cfg{winhelp-topic}{ssh.tunnels.portfwd.localhost}
+
+The source port for a forwarded connection usually does not accept
+connections from any machine except the \I{localhost}SSH client or
+server machine itself (for local and remote forwardings respectively).
+There are controls in the Tunnels panel to change this:
+
+\b The \q{Local ports accept connections from other hosts} option
+allows you to set up local-to-remote port forwardings in such a way
+that machines other than your client PC can connect to the forwarded
+port. (This also applies to dynamic SOCKS forwarding.)
+
+\b The \q{Remote ports do the same} option does the same thing for
+remote-to-local port forwardings (so that machines other than the
+SSH server machine can connect to the forwarded port.) Note that
+this feature is only available in the SSH-2 protocol, and not all
+SSH-2 servers support it (\i{OpenSSH} 3.0 does not, for example).
+
+\S{config-ssh-portfwd-address-family} Selecting \i{Internet protocol
+version} for forwarded ports
+
+\cfg{winhelp-topic}{ssh.tunnels.portfwd.ipversion}
+
+This switch allows you to select a specific Internet protocol (\i{IPv4}
+or \i{IPv6}) for the local end of a forwarded port. By default, it is
+set on \q{Auto}, which means that:
+
+\b for a local-to-remote port forwarding, PuTTY will listen for
+incoming connections in both IPv4 and (if available) IPv6
+
+\b for a remote-to-local port forwarding, PuTTY will choose a
+sensible protocol for the outgoing connection.
+
+Note that some operating systems may listen for incoming connections
+in IPv4 even if you specifically asked for IPv6, because their IPv4
+and IPv6 protocol stacks are linked together. Apparently \i{Linux} does
+this, and Windows does not. So if you're running PuTTY on Windows
+and you tick \q{IPv6} for a local or dynamic port forwarding, it
+will \e{only} be usable by connecting to it using IPv6; whereas if
+you do the same on Linux, you can also use it with IPv4. However,
+ticking \q{Auto} should always give you a port which you can connect
+to using either protocol.
+
+\H{config-ssh-bugs} \I{SSH server bugs}The Bugs panel
+
+Not all SSH servers work properly. Various existing servers have
+bugs in them, which can make it impossible for a client to talk to
+them unless it knows about the bug and works around it.
+
+Since most servers announce their software version number at the
+beginning of the SSH connection, PuTTY will attempt to detect which
+bugs it can expect to see in the server and automatically enable
+workarounds. However, sometimes it will make mistakes; if the server
+has been deliberately configured to conceal its version number, or
+if the server is a version which PuTTY's bug database does not know
+about, then PuTTY will not know what bugs to expect.
+
+The Bugs panel allows you to manually configure the bugs PuTTY
+expects to see in the server. Each bug can be configured in three
+states:
+
+\b \q{Off}: PuTTY will assume the server does not have the bug.
+
+\b \q{On}: PuTTY will assume the server \e{does} have the bug.
+
+\b \q{Auto}: PuTTY will use the server's version number announcement
+to try to guess whether or not the server has the bug.
+
+\S{config-ssh-bug-ignore1} \q{Chokes on SSH-1 \i{ignore message}s}
+
+\cfg{winhelp-topic}{ssh.bugs.ignore1}
+
+An ignore message (SSH_MSG_IGNORE) is a message in the SSH protocol
+which can be sent from the client to the server, or from the server
+to the client, at any time. Either side is required to ignore the
+message whenever it receives it. PuTTY uses ignore messages to
+\I{password camouflage}hide the password packet in SSH-1, so that
+a listener cannot tell the length of the user's password; it also
+uses ignore messages for connection \i{keepalives} (see
+\k{config-keepalive}).
+
+If this bug is detected, PuTTY will stop using ignore messages. This
+means that keepalives will stop working, and PuTTY will have to fall
+back to a secondary defence against SSH-1 password-length
+eavesdropping. See \k{config-ssh-bug-plainpw1}. If this bug is
+enabled when talking to a correct server, the session will succeed,
+but keepalives will not work and the session might be more
+vulnerable to eavesdroppers than it could be.
+
+This is an SSH-1-specific bug. No known SSH-2 server fails to deal
+with SSH-2 ignore messages.
+
+\S{config-ssh-bug-plainpw1} \q{Refuses all SSH-1 \i{password camouflage}}
+
+\cfg{winhelp-topic}{ssh.bugs.plainpw1}
+
+When talking to an SSH-1 server which cannot deal with ignore
+messages (see \k{config-ssh-bug-ignore1}), PuTTY will attempt to
+disguise the length of the user's password by sending additional
+padding \e{within} the password packet. This is technically a
+violation of the SSH-1 specification, and so PuTTY will only do it
+when it cannot use standards-compliant ignore messages as
+camouflage. In this sense, for a server to refuse to accept a padded
+password packet is not really a bug, but it does make life
+inconvenient if the server can also not handle ignore messages.
+
+If this \q{bug} is detected, PuTTY will assume that neither ignore
+messages nor padding are acceptable, and that it thus has no choice
+but to send the user's password with no form of camouflage, so that
+an eavesdropping user will be easily able to find out the exact length
+of the password. If this bug is enabled when talking to a correct
+server, the session will succeed, but will be more vulnerable to
+eavesdroppers than it could be.
+
+This is an SSH-1-specific bug. SSH-2 is secure against this type of
+attack.
+
+\S{config-ssh-bug-rsa1} \q{Chokes on SSH-1 \i{RSA} authentication}
+
+\cfg{winhelp-topic}{ssh.bugs.rsa1}
+
+Some SSH-1 servers cannot deal with RSA authentication messages at
+all. If \i{Pageant} is running and contains any SSH-1 keys, PuTTY will
+normally automatically try RSA authentication before falling back to
+passwords, so these servers will crash when they see the RSA attempt.
+
+If this bug is detected, PuTTY will go straight to password
+authentication. If this bug is enabled when talking to a correct
+server, the session will succeed, but of course RSA authentication
+will be impossible.
+
+This is an SSH-1-specific bug.
+
+\S{config-ssh-bug-hmac2} \q{Miscomputes SSH-2 HMAC keys}
+
+\cfg{winhelp-topic}{ssh.bugs.hmac2}
+
+Versions 2.3.0 and below of the SSH server software from
+\cw{ssh.com} compute the keys for their \i{HMAC} \i{message authentication
+code}s incorrectly. A typical symptom of this problem is that PuTTY
+dies unexpectedly at the beginning of the session, saying
+\q{Incorrect MAC received on packet}.
+
+If this bug is detected, PuTTY will compute its HMAC keys in the
+same way as the buggy server, so that communication will still be
+possible. If this bug is enabled when talking to a correct server,
+communication will fail.
+
+This is an SSH-2-specific bug.
+
+\S{config-ssh-bug-derivekey2} \q{Miscomputes SSH-2 \i{encryption} keys}
+
+\cfg{winhelp-topic}{ssh.bugs.derivekey2}
+
+Versions below 2.0.11 of the SSH server software from \i\cw{ssh.com}
+compute the keys for the session encryption incorrectly. This
+problem can cause various error messages, such as \q{Incoming packet
+was garbled on decryption}, or possibly even \q{Out of memory}.
+
+If this bug is detected, PuTTY will compute its encryption keys in
+the same way as the buggy server, so that communication will still
+be possible. If this bug is enabled when talking to a correct
+server, communication will fail.
+
+This is an SSH-2-specific bug.
+
+\S{config-ssh-bug-sig} \q{Requires padding on SSH-2 \i{RSA} \i{signatures}}
+
+\cfg{winhelp-topic}{ssh.bugs.rsapad2}
+
+Versions below 3.3 of \i{OpenSSH} require SSH-2 RSA signatures to be
+padded with zero bytes to the same length as the RSA key modulus.
+The SSH-2 specification says that an unpadded signature MUST be
+accepted, so this is a bug. A typical symptom of this problem is
+that PuTTY mysteriously fails RSA authentication once in every few
+hundred attempts, and falls back to passwords.
+
+If this bug is detected, PuTTY will pad its signatures in the way
+OpenSSH expects. If this bug is enabled when talking to a correct
+server, it is likely that no damage will be done, since correct
+servers usually still accept padded signatures because they're used
+to talking to OpenSSH.
+
+This is an SSH-2-specific bug.
+
+\S{config-ssh-bug-pksessid2} \q{Misuses the \i{session ID} in SSH-2 PK auth}
+
+\cfg{winhelp-topic}{ssh.bugs.pksessid2}
+
+Versions below 2.3 of \i{OpenSSH} require SSH-2 \i{public-key authentication}
+to be done slightly differently: the data to be signed by the client
+contains the session ID formatted in a different way. If public-key
+authentication mysteriously does not work but the Event Log (see
+\k{using-eventlog}) thinks it has successfully sent a signature, it
+might be worth enabling the workaround for this bug to see if it
+helps.
+
+If this bug is detected, PuTTY will sign data in the way OpenSSH
+expects. If this bug is enabled when talking to a correct server,
+SSH-2 public-key authentication will fail.
+
+This is an SSH-2-specific bug.
+
+\S{config-ssh-bug-rekey} \q{Handles SSH-2 key re-exchange badly}
+
+\cfg{winhelp-topic}{ssh.bugs.rekey2}
+
+Some SSH servers cannot cope with \i{repeat key exchange} at
+all, and will ignore attempts by the client to start one. Since
+PuTTY pauses the session while performing a repeat key exchange, the
+effect of this would be to cause the session to hang after an hour
+(unless you have your rekey timeout set differently; see
+\k{config-ssh-kex-rekey} for more about rekeys).
+Other, very old, SSH servers handle repeat key exchange even more
+badly, and disconnect upon receiving a repeat key exchange request.
+
+If this bug is detected, PuTTY will never initiate a repeat key
+exchange. If this bug is enabled when talking to a correct server,
+the session should still function, but may be less secure than you
+would expect.
+
+This is an SSH-2-specific bug.
+
+\H{config-serial} The Serial panel
+
+The \i{Serial} panel allows you to configure options that only apply
+when PuTTY is connecting to a local \I{serial port}\i{serial line}.
+
+\S{config-serial-line} Selecting a serial line to connect to
+
+\cfg{winhelp-topic}{serial.line}
+
+The \q{Serial line to connect to} box allows you to choose which
+serial line you want PuTTY to talk to, if your computer has more
+than one serial port.
+
+On Windows, the first serial line is called \i\cw{COM1}, and if there
+is a second it is called \cw{COM2}, and so on.
+
+This configuration setting is also visible on the Session panel,
+where it replaces the \q{Host Name} box (see \k{config-hostname}) if
+the connection type is set to \q{Serial}.
+
+\S{config-serial-speed} Selecting the speed of your serial line
+
+\cfg{winhelp-topic}{serial.speed}
+
+The \q{Speed} box allows you to choose the speed (or \q{baud rate})
+at which to talk to the serial line. Typical values might be 9600,
+19200, 38400 or 57600. Which one you need will depend on the device
+at the other end of the serial cable; consult the manual for that
+device if you are in doubt.
+
+This configuration setting is also visible on the Session panel,
+where it replaces the \q{Port} box (see \k{config-hostname}) if the
+connection type is set to \q{Serial}.
+
+\S{config-serial-databits} Selecting the number of data bits
+
+\cfg{winhelp-topic}{serial.databits}
+
+The \q{Data bits} box allows you to choose how many data bits are
+transmitted in each byte sent or received through the serial line.
+Typical values are 7 or 8.
+
+\S{config-serial-stopbits} Selecting the number of stop bits
+
+\cfg{winhelp-topic}{serial.stopbits}
+
+The \q{Stop bits} box allows you to choose how many stop bits are
+used in the serial line protocol. Typical values are 1, 1.5 or 2.
+
+\S{config-serial-parity} Selecting the serial parity checking scheme
+
+\cfg{winhelp-topic}{serial.parity}
+
+The \q{Parity} box allows you to choose what type of parity checking
+is used on the serial line. The settings are:
+
+\b \q{None}: no parity bit is sent at all.
+
+\b \q{Odd}: an extra parity bit is sent alongside each byte, and
+arranged so that the total number of 1 bits is odd.
+
+\b \q{Even}: an extra parity bit is sent alongside each byte, and
+arranged so that the total number of 1 bits is even.
+
+\b \q{Mark}: an extra parity bit is sent alongside each byte, and
+always set to 1.
+
+\b \q{Space}: an extra parity bit is sent alongside each byte, and
+always set to 0.
+
+\S{config-serial-flow} Selecting the serial flow control scheme
+
+\cfg{winhelp-topic}{serial.flow}
+
+The \q{Flow control} box allows you to choose what type of flow
+control checking is used on the serial line. The settings are:
+
+\b \q{None}: no flow control is done. Data may be lost if either
+side attempts to send faster than the serial line permits.
+
+\b \q{XON/XOFF}: flow control is done by sending XON and XOFF
+characters within the data stream.
+
+\b \q{RTS/CTS}: flow control is done using the RTS and CTS wires on
+the serial line.
+
+\b \q{DSR/DTR}: flow control is done using the DSR and DTR wires on
+the serial line.
+
+\H{config-file} \ii{Storing configuration in a file}
+
+PuTTY does not currently support storing its configuration in a file
+instead of the \i{Registry}. However, you can work around this with a
+couple of \i{batch file}s.
+
+You will need a file called (say) \c{PUTTY.BAT} which imports the
+contents of a file into the Registry, then runs PuTTY, exports the
+contents of the Registry back into the file, and deletes the
+Registry entries. This can all be done using the Regedit command
+line options, so it's all automatic. Here is what you need in
+\c{PUTTY.BAT}:
+
+\c @ECHO OFF
+\c regedit /s putty.reg
+\c regedit /s puttyrnd.reg
+\c start /w putty.exe
+\c regedit /ea new.reg HKEY_CURRENT_USER\Software\SimonTatham\PuTTY
+\c copy new.reg putty.reg
+\c del new.reg
+\c regedit /s puttydel.reg
+
+This batch file needs two auxiliary files: \c{PUTTYRND.REG} which
+sets up an initial safe location for the \c{PUTTY.RND} random seed
+file, and \c{PUTTYDEL.REG} which destroys everything in the Registry
+once it's been successfully saved back to the file.
+
+Here is \c{PUTTYDEL.REG}:
+
+\c REGEDIT4
+\c
+\c [-HKEY_CURRENT_USER\Software\SimonTatham\PuTTY]
+
+Here is an example \c{PUTTYRND.REG} file:
+
+\c REGEDIT4
+\c
+\c [HKEY_CURRENT_USER\Software\SimonTatham\PuTTY]
+\c "RandSeedFile"="a:\\putty.rnd"
+
+You should replace \c{a:\\putty.rnd} with the location where you
+want to store your random number data. If the aim is to carry around
+PuTTY and its settings on one floppy, you probably want to store it
+on the floppy.
diff --git a/puttysrc/DOC/ERRORS.BUT b/puttysrc/DOC/ERRORS.BUT
new file mode 100644
index 0000000..240a611
--- /dev/null
+++ b/puttysrc/DOC/ERRORS.BUT
@@ -0,0 +1,334 @@
+\define{versioniderrors} \versionid $Id: errors.but 6461 2005-11-14 09:41:42Z jacob $
+
+\C{errors} Common \i{error messages}
+
+This chapter lists a number of common error messages which PuTTY and
+its associated tools can produce, and explains what they mean in
+more detail.
+
+We do not attempt to list \e{all} error messages here: there are
+many which should never occur, and some which should be
+self-explanatory. If you get an error message which is not listed in
+this chapter and which you don't understand, report it to us as a
+bug (see \k{feedback}) and we will add documentation for it.
+
+\H{errors-hostkey-absent} \q{The server's host key is not cached in
+the registry}
+
+\cfg{winhelp-topic}{errors.hostkey.absent}
+
+This error message occurs when PuTTY connects to a new SSH server.
+Every server identifies itself by means of a host key; once PuTTY
+knows the host key for a server, it will be able to detect if a
+malicious attacker redirects your connection to another machine.
+
+If you see this message, it means that PuTTY has not seen this host
+key before, and has no way of knowing whether it is correct or not.
+You should attempt to verify the host key by other means, such as
+asking the machine's administrator.
+
+If you see this message and you know that your installation of PuTTY
+\e{has} connected to the same server before, it may have been
+recently upgraded to SSH protocol version 2. SSH protocols 1 and 2
+use separate host keys, so when you first use \i{SSH-2} with a server
+you have only used SSH-1 with before, you will see this message
+again. You should verify the correctness of the key as before.
+
+See \k{gs-hostkey} for more information on host keys.
+
+\H{errors-hostkey-wrong} \q{WARNING - POTENTIAL SECURITY BREACH!}
+
+\cfg{winhelp-topic}{errors.hostkey.changed}
+
+This message, followed by \q{The server's host key does not match
+the one PuTTY has cached in the registry}, means that PuTTY has
+connected to the SSH server before, knows what its host key
+\e{should} be, but has found a different one.
+
+This may mean that a malicious attacker has replaced your server
+with a different one, or has redirected your network connection to
+their own machine. On the other hand, it may simply mean that the
+administrator of your server has accidentally changed the key while
+upgrading the SSH software; this \e{shouldn't} happen but it is
+unfortunately possible.
+
+You should contact your server's administrator and see whether they
+expect the host key to have changed. If so, verify the new host key
+in the same way as you would if it was new.
+
+See \k{gs-hostkey} for more information on host keys.
+
+\H{errors-portfwd-space} \q{Out of space for port forwardings}
+
+PuTTY has a fixed-size buffer which it uses to store the details of
+all \i{port forwardings} you have set up in an SSH session. If you
+specify too many port forwardings on the PuTTY or Plink command line
+and this buffer becomes full, you will see this error message.
+
+We need to fix this (fixed-size buffers are almost always a mistake)
+but we haven't got round to it. If you actually have trouble with
+this, let us know and we'll move it up our priority list.
+
+\H{errors-cipher-warning} \q{The first cipher supported by the server is
+... below the configured warning threshold}
+
+This occurs when the SSH server does not offer any ciphers which you
+have configured PuTTY to consider strong enough. By default, PuTTY
+puts up this warning only for \ii{single-DES} and \i{Arcfour} encryption.
+
+See \k{config-ssh-encryption} for more information on this message.
+
+\H{errors-toomanyauth} \q{Server sent disconnect message type 2
+(protocol error): "Too many authentication failures for root"}
+
+This message is produced by an \i{OpenSSH} (or \i{Sun SSH}) server if it
+receives more failed authentication attempts than it is willing to
+tolerate.
+
+This can easily happen if you are using Pageant and have a
+large number of keys loaded into it, since these servers count each
+offer of a public key as an authentication attempt. This can be worked
+around by specifying the key that's required for the authentication in
+the PuTTY configuration (see \k{config-ssh-privkey}); PuTTY will ignore
+any other keys Pageant may have, but will ask Pageant to do the
+authentication, so that you don't have to type your passphrase.
+
+On the server, this can be worked around by disabling public-key
+authentication or (for Sun SSH only) by increasing \c{MaxAuthTries} in
+\c{sshd_config}.
+
+\H{errors-memory} \q{\ii{Out of memory}}
+
+This occurs when PuTTY tries to allocate more memory than the system
+can give it. This \e{may} happen for genuine reasons: if the
+computer really has run out of memory, or if you have configured an
+extremely large number of lines of scrollback in your terminal.
+PuTTY is not able to recover from running out of memory; it will
+terminate immediately after giving this error.
+
+However, this error can also occur when memory is not running out at
+all, because PuTTY receives data in the wrong format. In SSH-2 and
+also in SFTP, the server sends the length of each message before the
+message itself; so PuTTY will receive the length, try to allocate
+space for the message, and then receive the rest of the message. If
+the length PuTTY receives is garbage, it will try to allocate a
+ridiculous amount of memory, and will terminate with an \q{Out of
+memory} error.
+
+This can happen in SSH-2, if PuTTY and the server have not enabled
+encryption in the same way (see \k{faq-outofmem} in the FAQ). Some
+versions of \i{OpenSSH} have a known problem with this: see
+\k{faq-openssh-bad-openssl}.
+
+This can also happen in PSCP or PSFTP, if your \i{login scripts} on the
+server generate output: the client program will be expecting an SFTP
+message starting with a length, and if it receives some text from
+your login scripts instead it will try to interpret them as a
+message length. See \k{faq-outofmem2} for details of this.
+
+\H{errors-internal} \q{\ii{Internal error}}, \q{\ii{Internal fault}},
+\q{\ii{Assertion failed}}
+
+Any error beginning with the word \q{Internal} should \e{never}
+occur. If it does, there is a bug in PuTTY by definition; please see
+\k{feedback} and report it to us.
+
+Similarly, any error message starting with \q{Assertion failed} is a
+bug in PuTTY. Please report it to us, and include the exact text
+from the error message box.
+
+\H{errors-cant-load-key} \q{Unable to use this private key file},
+\q{Couldn't load private key}, \q{Key is of wrong type}
+
+\cfg{winhelp-topic}{errors.cantloadkey}
+
+Various forms of this error are printed in the PuTTY window, or
+written to the PuTTY Event Log (see \k{using-eventlog}) when trying
+public-key authentication, or given by Pageant when trying to load a
+private key.
+
+If you see one of these messages, it often indicates that you've tried
+to load a key of an inappropriate type into PuTTY, Plink, PSCP, PSFTP,
+or Pageant.
+
+You may have specified a key that's inappropriate for the connection
+you're making. The SSH-1 and SSH-2 protocols require different private
+key formats, and a SSH-1 key can't be used for a SSH-2 connection (or
+vice versa).
+
+Alternatively, you may have tried to load an SSH-2 key in a \q{foreign}
+format (OpenSSH or \cw{ssh.com}) directly into one of the PuTTY tools,
+in which case you need to import it into PuTTY's native format
+(\c{*.PPK}) using PuTTYgen - see \k{puttygen-conversions}.
+
+\H{errors-refused} \q{Server refused our public key} or \q{Key
+refused}
+
+Various forms of this error are printed in the PuTTY window, or
+written to the PuTTY Event Log (see \k{using-eventlog}) when trying
+public-key authentication.
+
+If you see one of these messages, it means that PuTTY has sent a
+public key to the server and offered to authenticate with it, and
+the server has refused to accept authentication. This usually means
+that the server is not configured to accept this key to authenticate
+this user.
+
+This is almost certainly not a problem with PuTTY. If you see this
+type of message, the first thing you should do is check your
+\e{server} configuration carefully. Common errors include having
+the wrong permissions or ownership set on the public key or the
+user's home directory on the server. Also, read the PuTTY Event Log;
+the server may have sent diagnostic messages explaining exactly what
+problem it had with your setup.
+
+\H{errors-access-denied} \q{Access denied}, \q{Authentication refused}
+
+Various forms of this error are printed in the PuTTY window, or
+written to the PuTTY Event Log (see \k{using-eventlog}) during
+authentication.
+
+If you see one of these messages, it means that the server has refused
+all the forms of authentication PuTTY has tried and it has no further
+ideas.
+
+It may be worth checking the Event Log for diagnostic messages from
+the server giving more detail.
+
+This error can be caused by buggy SSH-1 servers that fail to cope with
+the various strategies we use for camouflaging passwords in transit.
+Upgrade your server, or use the workarounds described in
+\k{config-ssh-bug-ignore1} and possibly \k{config-ssh-bug-plainpw1}.
+
+\H{errors-crc} \q{Incorrect \i{CRC} received on packet} or \q{Incorrect
+MAC received on packet}
+
+This error occurs when PuTTY decrypts an SSH packet and its checksum
+is not correct. This probably means something has gone wrong in the
+encryption or decryption process. It's difficult to tell from this
+error message whether the problem is in the client, in the server,
+or in between.
+
+A known server problem which can cause this error is described in
+\k{faq-openssh-bad-openssl} in the FAQ.
+
+\H{errors-garbled} \q{Incoming packet was garbled on decryption}
+
+This error occurs when PuTTY decrypts an SSH packet and the
+decrypted data makes no sense. This probably means something has
+gone wrong in the encryption or decryption process. It's difficult
+to tell from this error message whether the problem is in the client,
+in the server, or in between.
+
+If you get this error, one thing you could try would be to fiddle
+with the setting of \q{Miscomputes SSH-2 encryption keys} on the Bugs
+panel (see \k{config-ssh-bug-derivekey2}).
+
+Another known server problem which can cause this error is described
+in \k{faq-openssh-bad-openssl} in the FAQ.
+
+\H{errors-x11-proxy} \q{PuTTY X11 proxy: \e{various errors}}
+
+This family of errors are reported when PuTTY is doing X forwarding.
+They are sent back to the X application running on the SSH server,
+which will usually report the error to the user.
+
+When PuTTY enables X forwarding (see \k{using-x-forwarding}) it
+creates a virtual X display running on the SSH server. This display
+requires authentication to connect to it (this is how PuTTY prevents
+other users on your server machine from connecting through the PuTTY
+proxy to your real X display). PuTTY also sends the server the
+details it needs to enable clients to connect, and the server should
+put this mechanism in place automatically, so your X applications
+should just work.
+
+A common reason why people see one of these messages is because they
+used SSH to log in as one user (let's say \q{fred}), and then used
+the Unix \c{su} command to become another user (typically \q{root}).
+The original user, \q{fred}, has access to the X authentication data
+provided by the SSH server, and can run X applications which are
+forwarded over the SSH connection. However, the second user
+(\q{root}) does not automatically have the authentication data
+passed on to it, so attempting to run an X application as that user
+often fails with this error.
+
+If this happens, \e{it is not a problem with PuTTY}. You need to
+arrange for your X authentication data to be passed from the user
+you logged in as to the user you used \c{su} to become. How you do
+this depends on your particular system; in fact many modern versions
+of \c{su} do it automatically.
+
+\H{errors-connaborted} \q{Network error: Software caused connection
+abort}
+
+This is a generic error produced by the Windows network code when it
+kills an established connection for some reason. For example, it might
+happen if you pull the network cable out of the back of an
+Ethernet-connected computer, or if Windows has any other similar
+reason to believe the entire network has become unreachable.
+
+Windows also generates this error if it has given up on the machine
+at the other end of the connection ever responding to it. If the
+network between your client and server goes down and your client
+then tries to send some data, Windows will make several attempts to
+send the data and will then give up and kill the connection. In
+particular, this can occur even if you didn't type anything, if you
+are using SSH-2 and PuTTY attempts a key re-exchange. (See
+\k{config-ssh-kex-rekey} for more about key re-exchange.)
+
+(It can also occur if you are using keepalives in your connection.
+Other people have reported that keepalives \e{fix} this error for
+them. See \k{config-keepalive} for a discussion of the pros and cons
+of keepalives.)
+
+We are not aware of any reason why this error might occur that would
+represent a bug in PuTTY. The problem is between you, your Windows
+system, your network and the remote system.
+
+\H{errors-connreset} \q{Network error: Connection reset by peer}
+
+This error occurs when the machines at each end of a network
+connection lose track of the state of the connection between them.
+For example, you might see it if your SSH server crashes, and
+manages to reboot fully before you next attempt to send data to it.
+
+However, the most common reason to see this message is if you are
+connecting through a \i{firewall} or a \i{NAT router} which has timed the
+connection out. See \k{faq-idleout} in the FAQ for more details. You
+may be able to improve the situation by using keepalives; see
+\k{config-keepalive} for details on this.
+
+Note that Windows can produce this error in some circumstances without
+seeing a connection reset from the server, for instance if the
+connection to the network is lost.
+
+\H{errors-connrefused} \q{Network error: Connection refused}
+
+This error means that the network connection PuTTY tried to make to
+your server was rejected by the server. Usually this happens because
+the server does not provide the service which PuTTY is trying to
+access.
+
+Check that you are connecting with the correct protocol (SSH, Telnet
+or Rlogin), and check that the port number is correct. If that
+fails, consult the administrator of your server.
+
+\H{errors-conntimedout} \q{Network error: Connection timed out}
+
+This error means that the network connection PuTTY tried to make to
+your server received no response at all from the server. Usually
+this happens because the server machine is completely isolated from
+the network, or because it is turned off.
+
+Check that you have correctly entered the host name or IP address of
+your server machine. If that fails, consult the administrator of
+your server.
+
+\i{Unix} also generates this error when it tries to send data down a
+connection and contact with the server has been completely lost
+during a connection. (There is a delay of minutes before Unix gives
+up on receiving a reply from the server.) This can occur if you type
+things into PuTTY while the network is down, but it can also occur
+if PuTTY decides of its own accord to send data: due to a repeat key
+exchange in SSH-2 (see \k{config-ssh-kex-rekey}) or due to
+keepalives (\k{config-keepalive}).
diff --git a/puttysrc/DOC/FAQ.BUT b/puttysrc/DOC/FAQ.BUT
new file mode 100644
index 0000000..7922ce3
--- /dev/null
+++ b/puttysrc/DOC/FAQ.BUT
@@ -0,0 +1,1430 @@
+\define{versionidfaq} \versionid $Id: faq.but 7146 2007-01-24 20:16:33Z simon $
+
+\A{faq} PuTTY \i{FAQ}
+
+This FAQ is published on the PuTTY web site, and also provided as an
+appendix in the manual.
+
+\H{faq-intro} Introduction
+
+\S{faq-what}{Question} What is PuTTY?
+
+PuTTY is a client program for the SSH, Telnet and Rlogin network
+protocols.
+
+These protocols are all used to run a remote session on a computer,
+over a network. PuTTY implements the client end of that session: the
+end at which the session is displayed, rather than the end at which
+it runs.
+
+In really simple terms: you run PuTTY on a Windows machine, and tell
+it to connect to (for example) a Unix machine. PuTTY opens a window.
+Then, anything you type into that window is sent straight to the
+Unix machine, and everything the Unix machine sends back is
+displayed in the window. So you can work on the Unix machine as if
+you were sitting at its console, while actually sitting somewhere
+else.
+
+\H{faq-support} Features supported in PuTTY
+
+\I{supported features}In general, if you want to know if PuTTY supports
+a particular feature, you should look for it on the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}{PuTTY web site}.
+In particular:
+
+\b try the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html}{changes
+page}, and see if you can find the feature on there. If a feature is
+listed there, it's been implemented. If it's listed as a change made
+\e{since} the latest version, it should be available in the
+development snapshots, in which case testing will be very welcome.
+
+\b try the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/}{Wishlist
+page}, and see if you can find the feature there. If it's on there,
+and not in the \q{Recently fixed} section, it probably \e{hasn't} been
+implemented.
+
+\S{faq-ssh2}{Question} Does PuTTY support SSH-2?
+
+Yes. SSH-2 support has been available in PuTTY since version 0.50.
+
+Public key authentication (both RSA and DSA) in SSH-2 is new in
+version 0.52.
+
+\S{faq-ssh2-keyfmt}{Question} Does PuTTY support reading OpenSSH or
+\cw{ssh.com} SSH-2 private key files?
+
+PuTTY doesn't support this natively (see
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/key-formats-natively.html}{the wishlist entry}
+for reasons why not), but as of 0.53
+PuTTYgen can convert both OpenSSH and \cw{ssh.com} private key
+files into PuTTY's format.
+
+\S{faq-ssh1}{Question} Does PuTTY support SSH-1?
+
+Yes. SSH-1 support has always been available in PuTTY.
+
+\S{faq-localecho}{Question} Does PuTTY support \i{local echo}?
+
+Yes. Version 0.52 has proper support for local echo.
+
+In version 0.51 and before, local echo could not be separated from
+local line editing (where you type a line of text locally, and it is
+not sent to the server until you press Return, so you have the
+chance to edit it and correct mistakes \e{before} the server sees
+it). New in version 0.52, local echo and local line editing are
+separate options, and by default PuTTY will try to determine
+automatically whether to enable them or not, based on which protocol
+you have selected and also based on hints from the server. If you
+have a problem with PuTTY's default choice, you can force each
+option to be enabled or disabled as you choose. The controls are in
+the Terminal panel, in the section marked \q{Line discipline
+options}.
+
+\S{faq-savedsettings}{Question} Does PuTTY support storing settings,
+so I don't have to change them every time?
+
+Yes, all of PuTTY's settings can be saved in named session profiles.
+You can also change the default settings that are used for new sessions.
+See \k{config-saving} in the documentation for how to do this.
+
+\S{faq-disksettings}{Question} Does PuTTY support storing its
+settings in a disk file?
+
+Not at present, although \k{config-file} in the documentation gives
+a method of achieving the same effect.
+
+\S{faq-fullscreen}{Question} Does PuTTY support full-screen mode,
+like a DOS box?
+
+Yes; this is a new feature in version 0.52.
+
+\S{faq-password-remember}{Question} Does PuTTY have the ability to
+\i{remember my password} so I don't have to type it every time?
+
+No, it doesn't.
+
+Remembering your password is a bad plan for obvious security
+reasons: anyone who gains access to your machine while you're away
+from your desk can find out the remembered password, and use it,
+abuse it or change it.
+
+In addition, it's not even \e{possible} for PuTTY to automatically
+send your password in a Telnet session, because Telnet doesn't give
+the client software any indication of which part of the login
+process is the password prompt. PuTTY would have to guess, by
+looking for words like \q{password} in the session data; and if your
+login program is written in something other than English, this won't
+work.
+
+In SSH, remembering your password would be possible in theory, but
+there doesn't seem to be much point since SSH supports public key
+authentication, which is more flexible and more secure. See
+\k{pubkey} in the documentation for a full discussion of public key
+authentication.
+
+\S{faq-hostkeys}{Question} Is there an option to turn off the
+\I{verifying the host key}annoying host key prompts?
+
+No, there isn't. And there won't be. Even if you write it yourself
+and send us the patch, we won't accept it.
+
+Those annoying host key prompts are the \e{whole point} of SSH.
+Without them, all the cryptographic technology SSH uses to secure
+your session is doing nothing more than making an attacker's job
+slightly harder; instead of sitting between you and the server with
+a packet sniffer, the attacker must actually subvert a router and
+start modifying the packets going back and forth. But that's not all
+that much harder than just sniffing; and without host key checking,
+it will go completely undetected by client or server.
+
+Host key checking is your guarantee that the encryption you put on
+your data at the client end is the \e{same} encryption taken off the
+data at the server end; it's your guarantee that it hasn't been
+removed and replaced somewhere on the way. Host key checking makes
+the attacker's job \e{astronomically} hard, compared to packet
+sniffing, and even compared to subverting a router. Instead of
+applying a little intelligence and keeping an eye on Bugtraq, the
+attacker must now perform a brute-force attack against at least one
+military-strength cipher. That insignificant host key prompt really
+does make \e{that} much difference.
+
+If you're having a specific problem with host key checking - perhaps
+you want an automated batch job to make use of PSCP or Plink, and
+the interactive host key prompt is hanging the batch process - then
+the right way to fix it is to add the correct host key to the
+Registry in advance. That way, you retain the \e{important} feature
+of host key checking: the right key will be accepted and the wrong
+ones will not. Adding an option to turn host key checking off
+completely is the wrong solution and we will not do it.
+
+If you have host keys available in the common \i\c{known_hosts} format,
+we have a script called
+\W{http://www.tartarus.org/~simon-anonsvn/viewcvs.cgi/putty/contrib/kh2reg.py?view=markup}\c{kh2reg.py}
+to convert them to a Windows .REG file, which can be installed ahead of
+time by double-clicking or using \c{REGEDIT}.
+
+\S{faq-server}{Question} Will you write an SSH server for the PuTTY
+suite, to go with the client?
+
+No. The only reason we might want to would be if we could easily
+re-use existing code and significantly cut down the effort. We don't
+believe this is the case; there just isn't enough common ground
+between an SSH client and server to make it worthwhile.
+
+If someone else wants to use bits of PuTTY in the process of writing
+a Windows SSH server, they'd be perfectly welcome to of course, but
+I really can't see it being a lot less effort for us to do that than
+it would be for us to write a server from the ground up. We don't
+have time, and we don't have motivation. The code is available if
+anyone else wants to try it.
+
+\S{faq-pscp-ascii}{Question} Can PSCP or PSFTP transfer files in
+\i{ASCII} mode?
+
+Unfortunately not.
+
+Until recently, this was a limitation of the file transfer protocols:
+the SCP and SFTP protocols had no notion of transferring a file in
+anything other than binary mode. (This is still true of SCP.)
+
+The current draft protocol spec of SFTP proposes a means of
+implementing ASCII transfer. At some point PSCP/PSFTP may implement
+this proposal.
+
+\H{faq-ports} Ports to other operating systems
+
+The eventual goal is for PuTTY to be a multi-platform program, able
+to run on at least Windows, Mac OS and Unix.
+
+Porting will become easier once PuTTY has a generalised porting
+layer, drawing a clear line between platform-dependent and
+platform-independent code. The general intention was for this
+porting layer to evolve naturally as part of the process of doing
+the first port; a Unix port has now been released and the plan
+seems to be working so far.
+
+\S{faq-ports-general}{Question} What ports of PuTTY exist?
+
+Currently, release versions of PuTTY tools only run on full Win32
+systems and Unix. \q{Win32} includes Windows 95, 98, and ME, and it
+includes Windows NT, Windows 2000 and Windows XP.
+
+In the development code, a partial port to the Mac OS (see
+\k{faq-mac-port}) is under way.
+
+Currently PuTTY does \e{not} run on Windows CE (see \k{faq-wince}),
+and it does not quite run on the Win32s environment under Windows
+3.1 (see \k{faq-win31}).
+
+We do not have release-quality ports for any other systems at the
+present time. If anyone told you we had an EPOC port, or an iPaq port,
+or any other port of PuTTY, they were mistaken. We don't.
+
+There are some third-party ports to various platforms, mentioned
+on the Links page of our website.
+
+\S{faq-unix}{Question} \I{Unix version}Is there a port to Unix?
+
+As of 0.54, there are Unix ports of most of the traditional PuTTY
+tools, and also one entirely new application.
+
+If you look at the source release, you should find a \c{unix}
+subdirectory containing \c{Makefile.gtk}, which should build you Unix
+ports of Plink, PuTTY itself, PuTTYgen, PSCP, PSFTP, and also
+\i\c{pterm} - an \cw{xterm}-type program which supports the same
+terminal emulation as PuTTY. We do not yet have a Unix port of
+Pageant.
+
+If you don't have \i{Gtk}, you should still be able to build the
+command-line tools.
+
+Note that Unix PuTTY has mostly only been tested on Linux so far;
+portability problems such as BSD-style ptys or different header file
+requirements are expected.
+
+\S{faq-unix-why}{Question} What's the point of the Unix port? Unix
+has OpenSSH.
+
+All sorts of little things. \c{pterm} is directly useful to anyone
+who prefers PuTTY's terminal emulation to \c{xterm}'s, which at
+least some people do. Unix Plink has apparently found a niche among
+people who find the complexity of OpenSSL makes OpenSSH hard to
+install (and who don't mind Plink not having as many features). Some
+users want to generate a large number of SSH keys on Unix and then
+copy them all into PuTTY, and the Unix PuTTYgen should allow them to
+automate that conversion process.
+
+There were development advantages as well; porting PuTTY to Unix was
+a valuable path-finding effort for other future ports, and also
+allowed us to use the excellent Linux tool
+\W{http://valgrind.kde.org/}{Valgrind} to help with debugging, which
+has already improved PuTTY's stability on \e{all} platforms.
+
+However, if you're a Unix user and you can see no reason to switch
+from OpenSSH to PuTTY/Plink, then you're probably right. We don't
+expect our Unix port to be the right thing for everybody.
+
+\S{faq-wince}{Question} Will there be a port to Windows CE or PocketPC?
+
+We have done some work on such a port, but it only reached an early
+stage, and certainly not a useful one. It's no longer being actively
+worked on.
+
+However, there's a third-party port at
+\W{http://www.pocketputty.net/}\c{http://www.pocketputty.net/}.
+
+\S{faq-win31}{Question} Is there a port to \i{Windows 3.1}?
+
+PuTTY is a 32-bit application from the ground up, so it won't run on
+Windows 3.1 as a native 16-bit program; and it would be \e{very}
+hard to port it to do so, because of Windows 3.1's vile memory
+allocation mechanisms.
+
+However, it is possible in theory to compile the existing PuTTY
+source in such a way that it will run under \i{Win32s} (an extension to
+Windows 3.1 to let you run 32-bit programs). In order to do this
+you'll need the right kind of C compiler - modern versions of Visual
+C at least have stopped being backwards compatible to Win32s. Also,
+the last time we tried this it didn't work very well.
+
+If you're interested in running PuTTY under Windows 3.1, help and
+testing in this area would be very welcome!
+
+\S{faq-mac-port}{Question} Will there be a port to the \I{Mac OS}Mac?
+
+There are several answers to this question:
+
+\b The Unix/Gtk port is already fully working under Mac OS X as an X11
+application.
+
+\b A native (Cocoa) Mac OS X port has been started. It's just about
+usable, but is of nowhere near release quality yet, and is likely to
+behave in unexpected ways. Currently it's unlikely to be completed
+unless someone steps in to help.
+
+\b A separate port to the classic Mac OS (pre-OSX) is also in
+progress; it too is not ready yet.
+
+\S{faq-epoc}{Question} Will there be a port to EPOC?
+
+I hope so, but given that ports aren't really progressing very fast
+even on systems the developers \e{do} already know how to program
+for, it might be a long time before any of us get round to learning
+a new system and doing the port for that.
+
+However, some of the work has been done by other people, and a beta
+port of PuTTY for the Nokia 9200 Communicator series is available
+from \W{http://s2putty.sourceforge.net/}\cw{http://s2putty.sourceforge.net/}
+
+\H{faq-embedding} Embedding PuTTY in other programs
+
+\S{faq-dll}{Question} Is the SSH or Telnet code available as a DLL?
+
+No, it isn't. It would take a reasonable amount of rewriting for
+this to be possible, and since the PuTTY project itself doesn't
+believe in DLLs (they make installation more error-prone) none of us
+has taken the time to do it.
+
+Most of the code cleanup work would be a good thing to happen in
+general, so if anyone feels like helping, we wouldn't say no.
+
+\S{faq-vb}{Question} Is the SSH or Telnet code available as a Visual
+Basic component?
+
+No, it isn't. None of the PuTTY team uses Visual Basic, and none of
+us has any particular need to make SSH connections from a Visual
+Basic application. In addition, all the preliminary work to turn it
+into a DLL would be necessary first; and furthermore, we don't even
+know how to write VB components.
+
+If someone offers to do some of this work for us, we might consider
+it, but unless that happens I can't see VB integration being
+anywhere other than the very bottom of our priority list.
+
+\S{faq-ipc}{Question} How can I use PuTTY to make an SSH connection
+from within another program?
+
+Probably your best bet is to use Plink, the command-line connection
+tool. If you can start Plink as a second Windows process, and
+arrange for your primary process to be able to send data to the
+Plink process, and receive data from it, through pipes, then you
+should be able to make SSH connections from your program.
+
+This is what CVS for Windows does, for example.
+
+\H{faq-details} Details of PuTTY's operation
+
+\S{faq-term}{Question} What \i{terminal type} does PuTTY use?
+
+For most purposes, PuTTY can be considered to be an \cw{xterm}
+terminal.
+
+PuTTY also supports some terminal \i{control sequences} not supported by
+the real \cw{xterm}: notably the Linux console sequences that
+reconfigure the colour palette, and the title bar control sequences
+used by \i\cw{DECterm} (which are different from the \cw{xterm} ones;
+PuTTY supports both).
+
+By default, PuTTY announces its terminal type to the server as
+\c{xterm}. If you have a problem with this, you can reconfigure it
+to say something else; \c{vt220} might help if you have trouble.
+
+\S{faq-settings}{Question} Where does PuTTY store its data?
+
+On Windows, PuTTY stores most of its data (saved sessions, SSH host
+keys) in the \i{Registry}. The precise location is
+
+\c HKEY_CURRENT_USER\Software\SimonTatham\PuTTY
+
+and within that area, saved sessions are stored under \c{Sessions}
+while host keys are stored under \c{SshHostKeys}.
+
+PuTTY also requires a random number seed file, to improve the
+unpredictability of randomly chosen data needed as part of the SSH
+cryptography. This is stored by default in a file called \i\c{PUTTY.RND}
+in your Windows home directory (\c{%HOMEDRIVE%\\%HOMEPATH%}), or in
+the actual Windows directory (such as \c{C:\\WINDOWS}) if the home
+directory doesn't exist, for example if you're using Win95. If you
+want to change the location of the random number seed file, you can
+put your chosen pathname in the Registry, at
+
+\c HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\RandSeedFile
+
+You can ask PuTTY to delete all this data; see \k{faq-cleanup}.
+
+On Unix, PuTTY stores all of this data in a directory \cw{~/.putty}.
+
+\H{faq-howto} HOWTO questions
+
+\S{faq-login}{Question} What login name / password should I use?
+
+This is not a question you should be asking \e{us}.
+
+PuTTY is a communications tool, for making connections to other
+computers. We maintain the tool; we \e{don't} administer any computers
+that you're likely to be able to use, in the same way that the people
+who make web browsers aren't responsible for most of the content you can
+view in them. \#{FIXME: less technical analogy?} We cannot help with
+questions of this sort.
+
+If you know the name of the computer you want to connect to, but don't
+know what login name or password to use, you should talk to whoever
+administers that computer. If you don't know who that is, see the next
+question for some possible ways to find out.
+
+\# FIXME: some people ask us to provide them with a login name
+apparently as random members of the public rather than in the
+belief that we run a server belonging to an organisation they already
+have some relationship with. Not sure what to say to such people.
+
+\S{faq-commands}{Question} \I{commands on the server}What commands
+can I type into my PuTTY terminal window?
+
+Again, this is not a question you should be asking \e{us}. You need
+to read the manuals, or ask the administrator, of \e{the computer
+you have connected to}.
+
+PuTTY does not process the commands you type into it. It's only a
+communications tool. It makes a connection to another computer; it
+passes the commands you type to that other computer; and it passes
+the other computer's responses back to you. Therefore, the precise
+range of commands you can use will not depend on PuTTY, but on what
+kind of computer you have connected to and what software is running
+on it. The PuTTY team cannot help you with that.
+
+(Think of PuTTY as being a bit like a telephone. If you phone
+somebody up and you don't know what language to speak to make them
+understand you, it isn't \e{the telephone company}'s job to find
+that out for you. We just provide the means for you to get in touch;
+making yourself understood is somebody else's problem.)
+
+If you are unsure of where to start looking for the administrator of
+your server, a good place to start might be to remember how you
+found out the host name in the PuTTY configuration. If you were
+given that host name by e-mail, for example, you could try asking
+the person who sent you that e-mail. If your company's IT department
+provided you with ready-made PuTTY saved sessions, then that IT
+department can probably also tell you something about what commands
+you can type during those sessions. But the PuTTY maintainer team
+does not administer any server you are likely to be connecting to,
+and cannot help you with questions of this type.
+
+\S{faq-startmax}{Question} How can I make PuTTY start up \i{maximise}d?
+
+Create a Windows shortcut to start PuTTY from, and set it as \q{Run
+Maximized}.
+
+\S{faq-startsess}{Question} How can I create a \i{Windows shortcut} to
+start a particular saved session directly?
+
+To run a PuTTY session saved under the name \q{\cw{mysession}},
+create a Windows shortcut that invokes PuTTY with a command line
+like
+
+\c \path\name\to\putty.exe -load "mysession"
+
+(Note: prior to 0.53, the syntax was \c{@session}. This is now
+deprecated and may be removed at some point.)
+
+\S{faq-startssh}{Question} How can I start an SSH session straight
+from the command line?
+
+Use the command line \c{putty -ssh host.name}. Alternatively, create
+a saved session that specifies the SSH protocol, and start the saved
+session as shown in \k{faq-startsess}.
+
+\S{faq-cutpaste}{Question} How do I \i{copy and paste} between PuTTY and
+other Windows applications?
+
+Copy and paste works similarly to the X Window System. You use the
+left mouse button to select text in the PuTTY window. The act of
+selection \e{automatically} copies the text to the clipboard: there
+is no need to press Ctrl-Ins or Ctrl-C or anything else. In fact,
+pressing Ctrl-C will send a Ctrl-C character to the other end of
+your connection (just like it does the rest of the time), which may
+have unpleasant effects. The \e{only} thing you need to do, to copy
+text to the clipboard, is to select it.
+
+To paste the clipboard contents into a PuTTY window, by default you
+click the right mouse button. If you have a three-button mouse and
+are used to X applications, you can configure pasting to be done by
+the middle button instead, but this is not the default because most
+Windows users don't have a middle button at all.
+
+You can also paste by pressing Shift-Ins.
+
+\S{faq-options}{Question} How do I use all PuTTY's features (public
+keys, proxying, cipher selection, etc.) in PSCP, PSFTP and Plink?
+
+Most major features (e.g., public keys, port forwarding) are available
+through command line options. See the documentation.
+
+Not all features are accessible from the command line yet, although
+we'd like to fix this. In the meantime, you can use most of
+PuTTY's features if you create a PuTTY saved session, and then use
+the name of the saved session on the command line in place of a
+hostname. This works for PSCP, PSFTP and Plink (but don't expect
+port forwarding in the file transfer applications!).
+
+\S{faq-pscp}{Question} How do I use PSCP.EXE? When I double-click it
+gives me a command prompt window which then closes instantly.
+
+PSCP is a command-line application, not a GUI application. If you
+run it without arguments, it will simply print a help message and
+terminate.
+
+To use PSCP properly, run it from a Command Prompt window. See
+\k{pscp} in the documentation for more details.
+
+\S{faq-pscp-spaces}{Question} \I{spaces in filenames}How do I use
+PSCP to copy a file whose name has spaces in?
+
+If PSCP is using the traditional SCP protocol, this is confusing. If
+you're specifying a file at the local end, you just use one set of
+quotes as you would normally do:
+
+\c pscp "local filename with spaces" user@host:
+\c pscp user@host:myfile "local filename with spaces"
+
+But if the filename you're specifying is on the \e{remote} side, you
+have to use backslashes and two sets of quotes:
+
+\c pscp user@host:"\"remote filename with spaces\"" local_filename
+\c pscp local_filename user@host:"\"remote filename with spaces\""
+
+Worse still, in a remote-to-local copy you have to specify the local
+file name explicitly, otherwise PSCP will complain that they don't
+match (unless you specified the \c{-unsafe} option). The following
+command will give an error message:
+
+\c c:\>pscp user@host:"\"oo er\"" .
+\c warning: remote host tried to write to a file called 'oo er'
+\c when we requested a file called '"oo er"'.
+
+Instead, you need to specify the local file name in full:
+
+\c c:\>pscp user@host:"\"oo er\"" "oo er"
+
+If PSCP is using the newer SFTP protocol, none of this is a problem,
+and all filenames with spaces in are specified using a single pair
+of quotes in the obvious way:
+
+\c pscp "local file" user@host:
+\c pscp user@host:"remote file" .
+
+\H{faq-trouble} Troubleshooting
+
+\S{faq-incorrect-mac}{Question} Why do I see \q{Incorrect MAC
+received on packet}?
+
+One possible cause of this that used to be common is a bug in old
+SSH-2 servers distributed by \cw{ssh.com}. (This is not the only
+possible cause; see \k{errors-crc} in the documentation.)
+Version 2.3.0 and below of their SSH-2 server
+constructs Message Authentication Codes in the wrong way, and
+expects the client to construct them in the same wrong way. PuTTY
+constructs the MACs correctly by default, and hence these old
+servers will fail to work with it.
+
+If you are using PuTTY version 0.52 or better, this should work
+automatically: PuTTY should detect the buggy servers from their
+version number announcement, and automatically start to construct
+its MACs in the same incorrect manner as they do, so it will be able
+to work with them.
+
+If you are using PuTTY version 0.51 or below, you can enable the
+workaround by going to the SSH panel and ticking the box labelled
+\q{Imitate SSH2 MAC bug}. It's possible that you might have to do
+this with 0.52 as well, if a buggy server exists that PuTTY doesn't
+know about.
+
+In this context MAC stands for \ii{Message Authentication Code}. It's a
+cryptographic term, and it has nothing at all to do with Ethernet
+MAC (Media Access Control) addresses.
+
+\S{faq-pscp-protocol}{Question} Why do I see \q{Fatal: Protocol
+error: Expected control record} in PSCP?
+
+This happens because PSCP was expecting to see data from the server
+that was part of the PSCP protocol exchange, and instead it saw data
+that it couldn't make any sense of at all.
+
+This almost always happens because the \i{startup scripts} in your
+account on the server machine are generating output. This is
+impossible for PSCP, or any other SCP client, to work around. You
+should never use startup files (\c{.bashrc}, \c{.cshrc} and so on)
+which generate output in non-interactive sessions.
+
+This is not actually a PuTTY problem. If PSCP fails in this way,
+then all other SCP clients are likely to fail in exactly the same
+way. The problem is at the server end.
+
+\S{faq-colours}{Question} I clicked on a colour in the \ii{Colours}
+panel, and the colour didn't change in my terminal.
+
+That isn't how you're supposed to use the Colours panel.
+
+During the course of a session, PuTTY potentially uses \e{all} the
+colours listed in the Colours panel. It's not a question of using
+only one of them and you choosing which one; PuTTY will use them
+\e{all}. The purpose of the Colours panel is to let you adjust the
+appearance of all the colours. So to change the colour of the
+cursor, for example, you would select \q{Cursor Colour}, press the
+\q{Modify} button, and select a new colour from the dialog box that
+appeared. Similarly, if you want your session to appear in green,
+you should select \q{Default Foreground} and press \q{Modify}.
+Clicking on \q{ANSI Green} won't turn your session green; it will
+only allow you to adjust the \e{shade} of green used when PuTTY is
+instructed by the server to display green text.
+
+\S{faq-winsock2}{Question} Plink on \i{Windows 95} says it can't find
+\i\cw{WS2_32.DLL}.
+
+Plink requires the extended Windows network library, WinSock version
+2. This is installed as standard on Windows 98 and above, and on
+Windows NT, and even on later versions of Windows 95; but early
+Win95 installations don't have it.
+
+In order to use Plink on these systems, you will need to download
+the
+\W{http://www.microsoft.com/windows95/downloads/contents/wuadmintools/s_wunetworkingtools/w95sockets2/}{WinSock 2 upgrade}:
+
+\c http://www.microsoft.com/windows95/downloads/contents/
+\c wuadmintools/s_wunetworkingtools/w95sockets2/
+
+\S{faq-outofmem}{Question} After trying to establish an SSH-2
+connection, PuTTY says \q{\ii{Out of memory}} and dies.
+
+If this happens just while the connection is starting up, this often
+indicates that for some reason the client and server have failed to
+establish a session encryption key. Somehow, they have performed
+calculations that should have given each of them the same key, but
+have ended up with different keys; so data encrypted by one and
+decrypted by the other looks like random garbage.
+
+This causes an \q{out of memory} error because the first encrypted
+data PuTTY expects to see is the length of an SSH message. Normally
+this will be something well under 100 bytes. If the decryption has
+failed, PuTTY will see a completely random length in the region of
+two \e{gigabytes}, and will try to allocate enough memory to store
+this non-existent message. This will immediately lead to it thinking
+it doesn't have enough memory, and panicking.
+
+If this happens to you, it is quite likely to still be a PuTTY bug
+and you should report it (although it might be a bug in your SSH
+server instead); but it doesn't necessarily mean you've actually run
+out of memory.
+
+\S{faq-outofmem2}{Question} When attempting a file transfer, either
+PSCP or PSFTP says \q{\ii{Out of memory}} and dies.
+
+This is almost always caused by your \i{login scripts} on the server
+generating output. PSCP or PSFTP will receive that output when they
+were expecting to see the start of a file transfer protocol, and
+they will attempt to interpret the output as file-transfer protocol.
+This will usually lead to an \q{out of memory} error for much the
+same reasons as given in \k{faq-outofmem}.
+
+This is a setup problem in your account on your server, \e{not} a
+PSCP/PSFTP bug. Your login scripts should \e{never} generate output
+during non-interactive sessions; secure file transfer is not the
+only form of remote access that will break if they do.
+
+On Unix, a simple fix is to ensure that all the parts of your login
+script that might generate output are in \c{.profile} (if you use a
+Bourne shell derivative) or \c{.login} (if you use a C shell).
+Putting them in more general files such as \c{.bashrc} or \c{.cshrc}
+is liable to lead to problems.
+
+\S{faq-psftp-slow}{Question} PSFTP transfers files much slower than PSCP.
+
+The throughput of PSFTP 0.54 should be much better than 0.53b and
+prior; we've added code to the SFTP backend to queue several blocks
+of data rather than waiting for an acknowledgement for each. (The
+SCP backend did not suffer from this performance issue because SCP
+is a much simpler protocol.)
+
+\S{faq-bce}{Question} When I run full-colour applications, I see
+areas of black space where colour ought to be, or vice versa.
+
+You almost certainly need to change the \q{Use \i{background colour} to
+erase screen} setting in the Terminal panel. If there is too much
+black space (the commoner situation), you should enable it, while if
+there is too much colour, you should disable it. (See \k{config-erase}.)
+
+In old versions of PuTTY, this was disabled by default, and would not
+take effect until you reset the terminal (see \k{faq-resetterm}).
+Since 0.54, it is enabled by default, and changes take effect
+immediately.
+
+\S{faq-resetterm}{Question} When I change some terminal settings,
+nothing happens.
+
+Some of the terminal options (notably \ii{Auto Wrap} and
+background-colour screen erase) actually represent the \e{default}
+setting, rather than the currently active setting. The server can
+send sequences that modify these options in mid-session, but when
+the terminal is reset (by server action, or by you choosing \q{Reset
+Terminal} from the System menu) the defaults are restored.
+
+In versions 0.53b and prior, if you change one of these options in
+the middle of a session, you will find that the change does not
+immediately take effect. It will only take effect once you reset
+the terminal.
+
+In version 0.54, the behaviour has changed - changes to these
+settings take effect immediately.
+
+\S{faq-idleout}{Question} My PuTTY sessions unexpectedly close after
+they are \I{idle connections}idle for a while.
+
+Some types of \i{firewall}, and almost any router doing Network Address
+Translation (\i{NAT}, also known as IP masquerading), will forget about
+a connection through them if the connection does nothing for too
+long. This will cause the connection to be rudely cut off when
+contact is resumed.
+
+You can try to combat this by telling PuTTY to send \e{keepalives}:
+packets of data which have no effect on the actual session, but
+which reassure the router or firewall that the network connection is
+still active and worth remembering about.
+
+Keepalives don't solve everything, unfortunately; although they
+cause greater robustness against this sort of router, they can also
+cause a \e{loss} of robustness against network dropouts. See
+\k{config-keepalive} in the documentation for more discussion of
+this.
+
+\S{faq-timeout}{Question} PuTTY's network connections time out too
+quickly when \I{breaks in connectivity}network connectivity is
+temporarily lost.
+
+This is a Windows problem, not a PuTTY problem. The timeout value
+can't be set on per application or per session basis. To increase
+the TCP timeout globally, you need to tinker with the Registry.
+
+On Windows 95, 98 or ME, the registry key you need to create or
+change is
+
+\c HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\
+\c MSTCP\MaxDataRetries
+
+(it must be of type DWORD in Win95, or String in Win98/ME).
+(See MS Knowledge Base article
+\W{http://support.microsoft.com/default.aspx?scid=kb;en-us;158474}{158474}
+for more information.)
+
+On Windows NT, 2000, or XP, the registry key to create or change is
+
+\c HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\
+\c Parameters\TcpMaxDataRetransmissions
+
+and it must be of type DWORD.
+(See MS Knowledge Base articles
+\W{http://support.microsoft.com/default.aspx?scid=kb;en-us;120642}{120642}
+and
+\W{http://support.microsoft.com/default.aspx?scid=kb;en-us;314053}{314053}
+for more information.)
+
+Set the key's value to something like 10. This will cause Windows to
+try harder to keep connections alive instead of abandoning them.
+
+\S{faq-puttyputty}{Question} When I \cw{cat} a binary file, I get
+\q{PuTTYPuTTYPuTTY} on my command line.
+
+Don't do that, then.
+
+This is designed behaviour; when PuTTY receives the character
+Control-E from the remote server, it interprets it as a request to
+identify itself, and so it sends back the string \q{\cw{PuTTY}} as
+if that string had been entered at the keyboard. Control-E should
+only be sent by programs that are prepared to deal with the
+response. Writing a binary file to your terminal is likely to output
+many Control-E characters, and cause this behaviour. Don't do it.
+It's a bad plan.
+
+To mitigate the effects, you could configure the answerback string
+to be empty (see \k{config-answerback}); but writing binary files to
+your terminal is likely to cause various other unpleasant behaviour,
+so this is only a small remedy.
+
+\S{faq-wintitle}{Question} When I \cw{cat} a binary file, my \i{window
+title} changes to a nonsense string.
+
+Don't do that, then.
+
+It is designed behaviour that PuTTY should have the ability to
+adjust the window title on instructions from the server. Normally
+the control sequence that does this should only be sent
+deliberately, by programs that know what they are doing and intend
+to put meaningful text in the window title. Writing a binary file to
+your terminal runs the risk of sending the same control sequence by
+accident, and cause unexpected changes in the window title. Don't do
+it.
+
+\S{faq-password-fails}{Question} My \i{keyboard} stops working once
+PuTTY displays the \i{password prompt}.
+
+No, it doesn't. PuTTY just doesn't display the password you type, so
+that someone looking at your screen can't see what it is.
+
+Unlike the Windows login prompts, PuTTY doesn't display the password
+as a row of asterisks either. This is so that someone looking at
+your screen can't even tell how \e{long} your password is, which
+might be valuable information.
+
+\S{faq-keyboard}{Question} One or more \I{keyboard}\i{function keys}
+don't do what I expected in a server-side application.
+
+If you've already tried all the relevant options in the PuTTY
+Keyboard panel, you may need to mail the PuTTY maintainers and ask.
+
+It is \e{not} usually helpful just to tell us which application,
+which server operating system, and which key isn't working; in order
+to replicate the problem we would need to have a copy of every
+operating system, and every application, that anyone has ever
+complained about.
+
+PuTTY responds to function key presses by sending a sequence of
+control characters to the server. If a function key isn't doing what
+you expect, it's likely that the character sequence your application
+is expecting to receive is not the same as the one PuTTY is sending.
+Therefore what we really need to know is \e{what} sequence the
+application is expecting.
+
+The simplest way to investigate this is to find some other terminal
+environment, in which that function key \e{does} work; and then
+investigate what sequence the function key is sending in that
+situation. One reasonably easy way to do this on a \i{Unix} system is to
+type the command \i\c{cat}, and then press the function key. This is
+likely to produce output of the form \c{^[[11~}. You can also do
+this in PuTTY, to find out what sequence the function key is
+producing in that. Then you can mail the PuTTY maintainers and tell
+us \q{I wanted the F1 key to send \c{^[[11~}, but instead it's
+sending \c{^[OP}, can this be done?}, or something similar.
+
+You should still read the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/feedback.html}{Feedback
+page} on the PuTTY website (also provided as \k{feedback} in the
+manual), and follow the guidelines contained in that.
+
+\S{faq-openssh-bad-openssl}{Question} Since my SSH server was upgraded
+to \i{OpenSSH} 3.1p1/3.4p1, I can no longer connect with PuTTY.
+
+There is a known problem when OpenSSH has been built against an
+incorrect version of OpenSSL; the quick workaround is to configure
+PuTTY to use SSH protocol 2 and the Blowfish cipher.
+
+For more details and OpenSSH patches, see
+\W{http://bugzilla.mindrot.org/show_bug.cgi?id=138}{bug 138} in the
+OpenSSH BTS.
+
+This is not a PuTTY-specific problem; if you try to connect with
+another client you'll likely have similar problems. (Although PuTTY's
+default cipher differs from many other clients.)
+
+\e{OpenSSH 3.1p1:} configurations known to be broken (and symptoms):
+
+\b SSH-2 with AES cipher (PuTTY says \q{Assertion failed! Expression:
+(len & 15) == 0} in \cw{sshaes.c}, or \q{Out of memory}, or crashes)
+
+\b SSH-2 with 3DES (PuTTY says \q{Incorrect MAC received on packet})
+
+\b SSH-1 with Blowfish (PuTTY says \q{Incorrect CRC received on
+packet})
+
+\b SSH-1 with 3DES
+
+\e{OpenSSH 3.4p1:} as of 3.4p1, only the problem with SSH-1 and
+Blowfish remains. Rebuild your server, apply the patch linked to from
+bug 138 above, or use another cipher (e.g., 3DES) instead.
+
+\e{Other versions:} we occasionally get reports of the same symptom
+and workarounds with older versions of OpenSSH, although it's not
+clear the underlying cause is the same.
+
+\S{faq-ssh2key-ssh1conn}{Question} Why do I see \q{Couldn't load
+private key from ...}? Why can PuTTYgen load my key but not PuTTY?
+
+It's likely that you've generated an SSH protocol 2 key with PuTTYgen,
+but you're trying to use it in an SSH-1 connection. SSH-1 and SSH-2 keys
+have different formats, and (at least in 0.52) PuTTY's reporting of a
+key in the wrong format isn't optimal.
+
+To connect using SSH-2 to a server that supports both versions, you
+need to change the configuration from the default (see \k{faq-ssh2}).
+
+\S{faq-rh8-utf8}{Question} When I'm connected to a \i{Red Hat Linux} 8.0
+system, some characters don't display properly.
+
+A common complaint is that hyphens in man pages show up as a-acute.
+
+With release 8.0, Red Hat appear to have made \i{UTF-8} the default
+character set. There appears to be no way for terminal emulators such
+as PuTTY to know this (as far as we know, the appropriate escape
+sequence to switch into UTF-8 mode isn't sent).
+
+A fix is to configure sessions to RH8 systems to use UTF-8
+translation - see \k{config-charset} in the documentation. (Note that
+if you use \q{Change Settings}, changes may not take place immediately
+- see \k{faq-resetterm}.)
+
+If you really want to change the character set used by the server, the
+right place is \c{/etc/sysconfig/i18n}, but this shouldn't be
+necessary.
+
+\S{faq-screen}{Question} Since I upgraded to PuTTY 0.54, the
+scrollback has stopped working when I run \c{screen}.
+
+PuTTY's terminal emulator has always had the policy that when the
+\q{\i{alternate screen}} is in use, nothing is added to the scrollback.
+This is because the usual sorts of programs which use the alternate
+screen are things like text editors, which tend to scroll back and
+forth in the same document a lot; so (a) they would fill up the
+scrollback with a large amount of unhelpfully disordered text, and
+(b) they contain their \e{own} method for the user to scroll back to
+the bit they were interested in. We have generally found this policy
+to do the Right Thing in almost all situations.
+
+Unfortunately, \c{screen} is one exception: it uses the alternate
+screen, but it's still usually helpful to have PuTTY's scrollback
+continue working. The simplest solution is to go to the Features
+control panel and tick \q{Disable switching to alternate terminal
+screen}. (See \k{config-features-altscreen} for more details.)
+Alternatively, you can tell \c{screen} itself not to use the
+alternate screen: the
+\W{http://www4.informatik.uni-erlangen.de/~jnweiger/screen-faq.html}{\c{screen}
+FAQ} suggests adding the line \cq{termcapinfo xterm ti@:te@} to your
+\cw{.screenrc} file.
+
+The reason why this only started to be a problem in 0.54 is because
+\c{screen} typically uses an unusual control sequence to switch to
+the alternate screen, and previous versions of PuTTY did not support
+this sequence.
+
+\S{faq-alternate-localhost}{Question} Since I upgraded \i{Windows XP}
+to Service Pack 2, I can't use addresses like \cw{127.0.0.2}.
+
+Some people who ask PuTTY to listen on \i{localhost} addresses other
+than \cw{127.0.0.1} to forward services such as \i{SMB} and \i{Windows
+Terminal Services} have found that doing so no longer works since
+they upgraded to WinXP SP2.
+
+This is apparently an issue with SP2 that is acknowledged by Microsoft
+in MS Knowledge Base article
+\W{http://support.microsoft.com/default.aspx?scid=kb;en-us;884020}{884020}.
+The article links to a fix you can download.
+
+(\e{However}, we've been told that SP2 \e{also} fixes the bug that
+means you need to use non-\cw{127.0.0.1} addresses to forward
+Terminal Services in the first place.)
+
+\S{faq-missing-slash}{Question} PSFTP commands seem to be missing a
+directory separator (slash).
+
+Some people have reported the following incorrect behaviour with
+PSFTP:
+
+\c psftp> pwd
+\e iii
+\c Remote directory is /dir1/dir2
+\c psftp> get filename.ext
+\e iiiiiiiiiiiiiiii
+\c /dir1/dir2filename.ext: no such file or directory
+
+This is not a bug in PSFTP. There is a known bug in some versions of
+portable \i{OpenSSH}
+(\W{http://bugzilla.mindrot.org/show_bug.cgi?id=697}{bug 697}) that
+causes these symptoms; it appears to have been introduced around
+3.7.x. It manifests only on certain platforms (AIX is what has been
+reported to us).
+
+There is a patch for OpenSSH attached to that bug; it's also fixed in
+recent versions of portable OpenSSH (from around 3.8).
+
+\S{faq-connaborted}{Question} Do you want to hear about \q{Software
+caused connection abort}?
+
+In the documentation for PuTTY 0.53 and 0.53b, we mentioned that we'd
+like to hear about any occurrences of this error. Since the release
+of PuTTY 0.54, however, we've been convinced that this error doesn't
+indicate that PuTTY's doing anything wrong, and we don't need to hear
+about further occurrences. See \k{errors-connaborted} for our current
+documentation of this error.
+
+\S{faq-rekey}{Question} My SSH-2 session \I{locking up, SSH-2
+sessions}locks up for a few seconds every so often.
+
+Recent versions of PuTTY automatically initiate \i{repeat key
+exchange} once per hour, to improve session security. If your client
+or server machine is slow, you may experience this as a delay of
+anything up to thirty seconds or so.
+
+These \I{delays, in SSH-2 sessions}delays are inconvenient, but they
+are there for your protection. If they really cause you a problem,
+you can choose to turn off periodic rekeying using the \q{Kex}
+configuration panel (see \k{config-ssh-kex}), but be aware that you
+will be sacrificing security for this. (Falling back to SSH-1 would
+also remove the delays, but would lose a \e{lot} more security
+still. We do not recommend it.)
+
+\S{faq-xpwontrun}{Question} PuTTY fails to start up. Windows claims that
+\q{the application configuration is incorrect}.
+
+This is caused by a bug in certain versions of \i{Windows XP} which
+is triggered by PuTTY 0.58. This was fixed in 0.59. The
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/xp-wont-run}{\q{xp-wont-run}}
+entry in PuTTY's wishlist has more details.
+
+\H{faq-secure} Security questions
+
+\S{faq-publicpc}{Question} Is it safe for me to download PuTTY and
+use it on a public PC?
+
+It depends on whether you trust that PC. If you don't trust the
+public PC, don't use PuTTY on it, and don't use any other software
+you plan to type passwords into either. It might be watching your
+keystrokes, or it might tamper with the PuTTY binary you download.
+There is \e{no} program safe enough that you can run it on an
+actively malicious PC and get away with typing passwords into it.
+
+If you do trust the PC, then it's probably OK to use PuTTY on it
+(but if you don't trust the network, then the PuTTY download might
+be tampered with, so it would be better to carry PuTTY with you on a
+floppy).
+
+\S{faq-cleanup}{Question} What does PuTTY leave on a system? How can
+I \i{clean up} after it?
+
+PuTTY will leave some Registry entries, and a random seed file, on
+the PC (see \k{faq-settings}). If you are using PuTTY on a public
+PC, or somebody else's PC, you might want to clean these up when you
+leave. You can do that automatically, by running the command
+\c{putty -cleanup}. (Note that this only removes settings for
+the currently logged-in user on \i{multi-user systems}.)
+
+If PuTTY was installed from the installer package, it will also
+appear in \q{Add/Remove Programs}. Older versions of the uninstaller
+do not remove the above-mentioned registry entries and file.
+
+\S{faq-dsa}{Question} How come PuTTY now supports \i{DSA}, when the
+website used to say how insecure it was?
+
+DSA has a major weakness \e{if badly implemented}: it relies on a
+random number generator to far too great an extent. If the random
+number generator produces a number an attacker can predict, the DSA
+private key is exposed - meaning that the attacker can log in as you
+on all systems that accept that key.
+
+The PuTTY policy changed because the developers were informed of
+ways to implement DSA which do not suffer nearly as badly from this
+weakness, and indeed which don't need to rely on random numbers at
+all. For this reason we now believe PuTTY's DSA implementation is
+probably OK. However, if you have the choice, we still recommend you
+use RSA instead.
+
+\S{faq-virtuallock}{Question} Couldn't Pageant use
+\cw{VirtualLock()} to stop private keys being written to disk?
+
+Unfortunately not. The \cw{VirtualLock()} function in the Windows
+API doesn't do a proper job: it may prevent small pieces of a
+process's memory from being paged to disk while the process is
+running, but it doesn't stop the process's memory as a whole from
+being swapped completely out to disk when the process is long-term
+inactive. And Pageant spends most of its time inactive.
+
+\H{faq-admin} Administrative questions
+
+\S{faq-domain}{Question} Would you like me to register you a nicer
+domain name?
+
+No, thank you. Even if you can find one (most of them seem to have
+been registered already, by people who didn't ask whether we
+actually wanted it before they applied), we're happy with the PuTTY
+web site being exactly where it is. It's not hard to find (just type
+\q{putty} into \W{http://www.google.com/}{google.com} and we're the
+first link returned), and we don't believe the administrative hassle
+of moving the site would be worth the benefit.
+
+In addition, if we \e{did} want a custom domain name, we would want
+to run it ourselves, so we knew for certain that it would continue
+to point where we wanted it, and wouldn't suddenly change or do
+strange things. Having it registered for us by a third party who we
+don't even know is not the best way to achieve this.
+
+\S{faq-webhosting}{Question} Would you like free web hosting for the
+PuTTY web site?
+
+We already have some, thanks.
+
+\S{faq-link}{Question} Would you link to my web site from the PuTTY
+web site?
+
+Only if the content of your web page is of definite direct interest
+to PuTTY users. If your content is unrelated, or only tangentially
+related, to PuTTY, then the link would simply be advertising for
+you.
+
+One very nice effect of the Google ranking mechanism is that by and
+large, the most popular web sites get the highest rankings. This
+means that when an ordinary person does a search, the top item in
+the search is very likely to be a high-quality site or the site they
+actually wanted, rather than the site which paid the most money for
+its ranking.
+
+The PuTTY web site is held in high esteem by Google, for precisely
+this reason: lots of people have linked to it simply because they
+like PuTTY, without us ever having to ask anyone to link to us. We
+feel that it would be an abuse of this esteem to use it to boost the
+ranking of random advertisers' web sites. If you want your web site
+to have a high Google ranking, we'd prefer that you achieve this the
+way we did - by being good enough at what you do that people will
+link to you simply because they like you.
+
+In particular, we aren't interested in trading links for money (see
+above), and we \e{certainly} aren't interested in trading links for
+other links (since we have no advertising on our web site, our
+Google ranking is not even directly worth anything to us). If we
+don't want to link to you for free, then we probably won't want to
+link to you at all.
+
+If you have software based on PuTTY, or specifically designed to
+interoperate with PuTTY, or in some other way of genuine interest to
+PuTTY users, then we will probably be happy to add a link to you on
+our Links page. And if you're running a mirror of the PuTTY web
+site, we're \e{definitely} interested.
+
+\S{faq-sourceforge}{Question} Why don't you move PuTTY to
+SourceForge?
+
+Partly, because we don't want to move the web site location (see
+\k{faq-domain}).
+
+Also, security reasons. PuTTY is a security product, and as such it
+is particularly important to guard the code and the web site against
+unauthorised modifications which might introduce subtle security
+flaws. Therefore, we prefer that the Subversion repository, web site and
+FTP site remain where they are, under the direct control of system
+administrators we know and trust personally, rather than being run
+by a large organisation full of people we've never met and which is
+known to have had breakins in the past.
+
+No offence to SourceForge; I think they do a wonderful job. But
+they're not ideal for everyone, and in particular they're not ideal
+for us.
+
+\S{faq-mailinglist1}{Question} Why can't I subscribe to the
+putty-bugs mailing list?
+
+Because you're not a member of the PuTTY core development team. The
+putty-bugs mailing list is not a general newsgroup-like discussion
+forum; it's a contact address for the core developers, and an
+\e{internal} mailing list for us to discuss things among ourselves.
+If we opened it up for everybody to subscribe to, it would turn into
+something more like a newsgroup and we would be completely
+overwhelmed by the volume of traffic. It's hard enough to keep up
+with the list as it is.
+
+\S{faq-mailinglist2}{Question} If putty-bugs isn't a
+general-subscription mailing list, what is?
+
+There isn't one, that we know of.
+
+If someone else wants to set up a mailing list or other forum for
+PuTTY users to help each other with common problems, that would be
+fine with us, though the PuTTY team would almost certainly not have the
+time to read it. It's probably better to use one of the established
+newsgroups for this purpose (see \k{feedback-other-fora}).
+
+\S{faq-donations}{Question} How can I donate to PuTTY development?
+
+Please, \e{please} don't feel you have to. PuTTY is completely free
+software, and not shareware. We think it's very important that
+\e{everybody} who wants to use PuTTY should be able to, whether they
+have any money or not; so the last thing we would want is for a
+PuTTY user to feel guilty because they haven't paid us any money. If
+you want to keep your money, please do keep it. We wouldn't dream of
+asking for any.
+
+Having said all that, if you still really \e{want} to give us money,
+we won't argue :-) The easiest way for us to accept donations is if
+you send money to \cw{} using PayPal
+(\W{http://www.paypal.com/}\cw{www.paypal.com}). Alternatively, if
+you don't trust PayPal, you could donate through e-gold
+(\W{http://www.e-gold.com}\cw{www.e-gold.com}): deposit your
+donation in account number 174769, then send us e-mail to let us
+know you've done so (otherwise we might not notice for months!).
+
+Small donations (tens of dollars or tens of euros) will probably be
+spent on beer or curry, which helps motivate our volunteer team to
+continue doing this for the world. Larger donations will be spent on
+something that actually helps development, if we can find anything
+(perhaps new hardware, or a copy of Windows XP), but if we can't
+find anything then we'll just distribute the money among the
+developers. If you want to be sure your donation is going towards
+something worthwhile, ask us first. If you don't like these terms,
+feel perfectly free not to donate. We don't mind.
+
+\S{faq-permission}{Question} Can I have permission to put PuTTY on a
+cover disk / distribute it with other software / etc?
+
+Yes. For most things, you need not bother asking us explicitly for
+permission; our licence already grants you permission.
+
+See \k{feedback-permission} for more details.
+
+\S{faq-indemnity}{Question} Can you sign an agreement indemnifying
+us against security problems in PuTTY?
+
+No!
+
+A vendor of physical security products (e.g. locks) might plausibly
+be willing to accept financial liability for a product that failed
+to perform as advertised and resulted in damage (e.g. valuables
+being stolen). The reason they can afford to do this is because they
+sell a \e{lot} of units, and only a small proportion of them will
+fail; so they can meet their financial liability out of the income
+from all the rest of their sales, and still have enough left over to
+make a profit. Financial liability is intrinsically linked to
+selling your product for money.
+
+There are two reasons why PuTTY is not analogous to a physical lock
+in this context. One is that software products don't exhibit random
+variation: \e{if} PuTTY has a security hole (which does happen,
+although we do our utmost to prevent it and to respond quickly when
+it does), every copy of PuTTY will have the same hole, so it's
+likely to affect all the users at the same time. So even if our
+users were all paying us to use PuTTY, we wouldn't be able to
+\e{simultaneously} pay every affected user compensation in excess of
+the amount they had paid us in the first place. It just wouldn't
+work.
+
+The second, much more important, reason is that PuTTY users
+\e{don't} pay us. The PuTTY team does not have an income; it's a
+volunteer effort composed of people spending their spare time to try
+to write useful software. We aren't even a company or any kind of
+legally recognised organisation. We're just a bunch of people who
+happen to do some stuff in our spare time.
+
+Therefore, to ask us to assume financial liability is to ask us to
+assume a risk of having to pay it out of our own \e{personal}
+pockets: out of the same budget from which we buy food and clothes
+and pay our rent. That's more than we're willing to give. We're
+already giving a lot of our spare \e{time} to developing software
+for free; if we had to pay our own \e{money} to do it as well, we'd
+start to wonder why we were bothering.
+
+Free software fundamentally does not work on the basis of financial
+guarantees. Your guarantee of the software functioning correctly is
+simply that you have the source code and can check it before you use
+it. If you want to be sure there aren't any security holes, do a
+security audit of the PuTTY code, or hire a security engineer if you
+don't have the necessary skills yourself: instead of trying to
+ensure you can get compensation in the event of a disaster, try to
+ensure there isn't a disaster in the first place.
+
+If you \e{really} want financial security, see if you can find a
+security engineer who will take financial responsibility for the
+correctness of their review. (This might be less likely to suffer
+from the everything-failing-at-once problem mentioned above, because
+such an engineer would probably be reviewing a lot of \e{different}
+products which would tend to fail independently.) Failing that, see
+if you can persuade an insurance company to insure you against
+security incidents, and if the insurer demands it as a condition
+then get our code reviewed by a security engineer they're happy
+with.
+
+\S{faq-permission-form}{Question} Can you sign this form granting us
+permission to use/distribute PuTTY?
+
+If your form contains any clause along the lines of \q{the
+undersigned represents and warrants}, we're not going to sign it.
+This is particularly true if it asks us to warrant that PuTTY is
+secure; see \k{faq-indemnity} for more discussion of this. But it
+doesn't really matter what we're supposed to be warranting: even if
+it's something we already believe is true, such as that we don't
+infringe any third-party copyright, we will not sign a document
+accepting any legal or financial liability. This is simply because
+the PuTTY development project has no income out of which to satisfy
+that liability, or pay legal costs, should it become necessary. We
+cannot afford to be sued. We are assuring you that \e{we have done
+our best}; if that isn't good enough for you, tough.
+
+The existing PuTTY licence document already gives you permission to
+use or distribute PuTTY in pretty much any way which does not
+involve pretending you wrote it or suing us if it goes wrong. We
+think that really ought to be enough for anybody.
+
+See also \k{faq-permission-general} for another reason why we don't
+want to do this sort of thing.
+
+\S{faq-permission-future}{Question} Can you write us a formal notice
+of permission to use PuTTY?
+
+We could, in principle, but it isn't clear what use it would be. If
+you think there's a serious chance of one of the PuTTY copyright
+holders suing you (which we don't!), you would presumably want a
+signed notice from \e{all} of them; and we couldn't provide that
+even if we wanted to, because many of the copyright holders are
+people who contributed some code in the past and with whom we
+subsequently lost contact. Therefore the best we would be able to do
+\e{even in theory} would be to have the core development team sign
+the document, which wouldn't guarantee you that some other copyright
+holder might not sue.
+
+See also \k{faq-permission-general} for another reason why we don't
+want to do this sort of thing.
+
+\S{faq-permission-general}{Question} Can you sign \e{anything} for
+us?
+
+Not unless there's an incredibly good reason.
+
+We are generally unwilling to set a precedent that involves us
+having to enter into individual agreements with PuTTY users. We
+estimate that we have literally \e{millions} of users, and we
+absolutely would not have time to go round signing specific
+agreements with every one of them. So if you want us to sign
+something specific for you, you might usefully stop to consider
+whether there's anything special that distinguishes you from 999,999
+other users, and therefore any reason we should be willing to sign
+something for you without it setting such a precedent.
+
+If your company policy requires you to have an individual agreement
+with the supplier of any software you use, then your company policy
+is simply not well suited to using popular free software, and we
+urge you to consider this as a flaw in your policy.
+
+\S{faq-permission-assurance}{Question} If you won't sign anything,
+can you give us some sort of assurance that you won't make PuTTY
+closed-source in future?
+
+Yes and no.
+
+If what you want is an assurance that some \e{current version} of
+PuTTY which you've already downloaded will remain free, then you
+already have that assurance: it's called the PuTTY Licence. It
+grants you permission to use, distribute and copy the software to
+which it applies; once we've granted that permission (which we
+have), we can't just revoke it.
+
+On the other hand, if you want an assurance that \e{future} versions
+of PuTTY won't be closed-source, that's more difficult. We could in
+principle sign a document stating that we would never release a
+closed-source PuTTY, but that wouldn't assure you that we \e{would}
+keep releasing \e{open}-source PuTTYs: we would still have the
+option of ceasing to develop PuTTY at all, which would surely be
+even worse for you than making it closed-source! (And we almost
+certainly wouldn't \e{want} to sign a document guaranteeing that we
+would actually continue to do development work on PuTTY; we
+certainly wouldn't sign it for free. Documents like that are called
+contracts of employment, and are generally not signed except in
+return for a sizeable salary.)
+
+If we \e{were} to stop developing PuTTY, or to decide to make all
+future releases closed-source, then you would still be free to copy
+the last open release in accordance with the current licence, and in
+particular you could start your own fork of the project from that
+release. If this happened, I confidently predict that \e{somebody}
+would do that, and that some kind of a free PuTTY would continue to
+be developed. There's already precedent for that sort of thing
+happening in free software. We can't guarantee that somebody
+\e{other than you} would do it, of course; you might have to do it
+yourself. But we can assure you that there would be nothing
+\e{preventing} anyone from continuing free development if we
+stopped.
+
+(Finally, we can also confidently predict that if we made PuTTY
+closed-source and someone made an open-source fork, most people
+would switch to the latter. Therefore, it would be pretty stupid of
+us to try it.)
+
+\S{faq-export-cert}{Question} Can you provide us with export control
+information / FIPS certification for PuTTY?
+
+Some people have asked us for an Export Control Classification Number
+(ECCN) for PuTTY. We don't know whether we have one, and as a team of
+free software developers based in the UK we don't have the time,
+money, or effort to deal with US bureaucracy to investigate any
+further. We believe that PuTTY falls under 5D002 on the US Commerce
+Control List, but that shouldn't be taken as definitive. If you need
+to know more you should seek professional legal advice. The same
+applies to any other country's legal requirements and restrictions.
+
+Similarly, some people have asked us for FIPS certification of the
+PuTTY tools. Unless someone else is prepared to do the necessary work
+and pay any costs, we can't provide this.
+
+\H{faq-misc} Miscellaneous questions
+
+\S{faq-openssh}{Question} Is PuTTY a port of \i{OpenSSH}, or based on
+OpenSSH?
+
+No, it isn't. PuTTY is almost completely composed of code written
+from scratch for PuTTY. The only code we share with OpenSSH is the
+detector for SSH-1 CRC compensation attacks, written by CORE SDI S.A.
+
+\S{faq-sillyputty}{Question} Where can I buy silly putty?
+
+You're looking at the wrong web site; the only PuTTY we know about
+here is the name of a computer program.
+
+If you want the kind of putty you can buy as an executive toy, the
+PuTTY team can personally recommend Thinking Putty, which you can
+buy from Crazy Aaron's Putty World, at
+\W{http://www.puttyworld.com}\cw{www.puttyworld.com}.
+
+\S{faq-meaning}{Question} What does \q{PuTTY} mean?
+
+It's the name of a popular SSH and Telnet client. Any other meaning
+is in the eye of the beholder. It's been rumoured that \q{PuTTY}
+is the antonym of \q{\cw{getty}}, or that it's the stuff that makes your
+Windows useful, or that it's a kind of plutonium Teletype. We
+couldn't possibly comment on such allegations.
+
+\S{faq-pronounce}{Question} How do I pronounce \q{PuTTY}?
+
+Exactly like the English word \q{putty}, which we pronounce
+/\u02C8{'}p\u028C{V}ti/.
diff --git a/puttysrc/DOC/FEEDBACK.BUT b/puttysrc/DOC/FEEDBACK.BUT
new file mode 100644
index 0000000..5dfa1b0
--- /dev/null
+++ b/puttysrc/DOC/FEEDBACK.BUT
@@ -0,0 +1,414 @@
+\define{versionidfeedback} \versionid $Id: feedback.but 6895 2006-11-08 21:15:30Z jacob $
+
+\A{feedback} \ii{Feedback} and \i{bug reporting}
+
+This is a guide to providing feedback to the PuTTY development team.
+It is provided as both a web page on the PuTTY site, and an appendix
+in the PuTTY manual.
+
+\K{feedback-general} gives some general guidelines for sending any
+kind of e-mail to the development team. Following sections give more
+specific guidelines for particular types of e-mail, such as bug
+reports and feature requests.
+
+\H{feedback-general} General guidelines
+
+The PuTTY development team gets a \e{lot} of mail. If you can
+possibly solve your own problem by reading the manual, reading the
+FAQ, reading the web site, asking a fellow user, perhaps posting to a
+newsgroup (see \k{feedback-other-fora}), or some other means, then it
+would make our lives much easier.
+
+We get so much e-mail that we literally do not have time to answer
+it all. We regret this, but there's nothing we can do about it. So
+if you can \e{possibly} avoid sending mail to the PuTTY team, we
+recommend you do so. In particular, support requests
+(\k{feedback-support}) are probably better sent to newsgroups, or
+passed to a local expert if possible.
+
+The PuTTY contact email address is a private \i{mailing list} containing
+four or five core developers. Don't be put off by it being a mailing
+list: if you need to send confidential data as part of a bug report,
+you can trust the people on the list to respect that confidence.
+Also, the archives aren't publicly available, so you shouldn't be
+letting yourself in for any spam by sending us mail.
+
+Please use a meaningful subject line on your message. We get a lot of
+mail, and it's hard to find the message we're looking for if they all
+have subject lines like \q{PuTTY bug}.
+
+\S{feedback-largefiles} Sending large attachments
+
+Since the PuTTY contact address is a mailing list, e-mails larger
+than 40Kb will be held for inspection by the list administrator, and
+will not be allowed through unless they really appear to be worth
+their large size.
+
+If you are considering sending any kind of large data file to the
+PuTTY team, it's almost always a bad idea, or at the very least it
+would be better to ask us first whether we actually need the file.
+Alternatively, you could put the file on a web site and just send us
+the URL; that way, we don't have to download it unless we decide we
+actually need it, and only one of us needs to download it instead of
+it being automatically copied to all the developers.
+
+Some people like to send mail in MS Word format. Please \e{don't}
+send us bug reports, or any other mail, as a Word document. Word
+documents are roughly fifty times larger than writing the same
+report in plain text. In addition, most of the PuTTY team read their
+e-mail on Unix machines, so copying the file to a Windows box to run
+Word is very inconvenient. Not only that, but several of us don't
+even \e{have} a copy of Word!
+
+Some people like to send us screen shots when demonstrating a
+problem. Please don't do this without checking with us first - we
+almost never actually need the information in the screen shot.
+Sending a screen shot of an error box is almost certainly
+unnecessary when you could just tell us in plain text what the error
+was. (On some versions of Windows, pressing Ctrl-C when the error
+box is displayed will copy the text of the message to the clipboard.)
+Sending a full-screen shot is \e{occasionally} useful, but it's
+probably still wise to check whether we need it before sending it.
+
+If you \e{must} mail a screen shot, don't send it as a \cw{.BMP}
+file. \cw{BMP}s have no compression and they are \e{much} larger
+than other image formats such as PNG, TIFF and GIF. Convert the file
+to a properly compressed image format before sending it.
+
+Please don't mail us executables, at all. Our mail server blocks all
+incoming e-mail containing executables, as a defence against the
+vast numbers of e-mail viruses we receive every day. If you mail us
+an executable, it will just bounce.
+
+If you have made a tiny modification to the PuTTY code, please send
+us a \e{patch} to the source code if possible, rather than sending
+us a huge \cw{.ZIP} file containing the complete sources plus your
+modification. If you've only changed 10 lines, we'd prefer to
+receive a mail that's 30 lines long than one containing multiple
+megabytes of data we already have.
+
+\S{feedback-other-fora} Other places to ask for help
+
+There are two Usenet newsgroups that are particularly relevant to the
+PuTTY tools:
+
+\b \W{news:comp.security.ssh}\c{comp.security.ssh}, for questions
+specific to using the SSH protocol;
+
+\b \W{news:comp.terminals}\c{comp.terminals}, for issues relating to
+terminal emulation (for instance, keyboard problems).
+
+Please use the newsgroup most appropriate to your query, and remember
+that these are general newsgroups, not specifically about PuTTY.
+
+If you don't have direct access to Usenet, you can access these
+newsgroups through Google Groups
+(\W{http://groups.google.com/}\cw{groups.google.com}).
+
+\H{feedback-bugs} Reporting bugs
+
+If you think you have found a bug in PuTTY, your first steps should
+be:
+
+\b Check the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/}{Wishlist
+page} on the PuTTY website, and see if we already know about the
+problem. If we do, it is almost certainly not necessary to mail us
+about it, unless you think you have extra information that might be
+helpful to us in fixing it. (Of course, if we actually \e{need}
+specific extra information about a particular bug, the Wishlist page
+will say so.)
+
+\b Check the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html}{Change
+Log} on the PuTTY website, and see if we have already fixed the bug
+in the \i{development snapshots}.
+
+\b Check the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/faq.html}{FAQ}
+on the PuTTY website (also provided as \k{faq} in the manual), and
+see if it answers your question. The FAQ lists the most common
+things which people think are bugs, but which aren't bugs.
+
+\b Download the latest development snapshot and see if the problem
+still happens with that. This really is worth doing. As a general
+rule we aren't very interested in bugs that appear in the release
+version but not in the development version, because that usually
+means they are bugs we have \e{already fixed}. On the other hand, if
+you can find a bug in the development version that doesn't appear in
+the release, that's likely to be a new bug we've introduced since
+the release and we're definitely interested in it.
+
+If none of those options solved your problem, and you still need to
+report a bug to us, it is useful if you include some general
+information:
+
+\b Tell us what \i{version of PuTTY} you are running. To find this out,
+use the \q{About PuTTY} option from the System menu. Please \e{do
+not} just tell us \q{I'm running the latest version}; e-mail can be
+delayed and it may not be obvious which version was the latest at
+the time you sent the message.
+
+\b PuTTY is a multi-platform application; tell us what version of what
+OS you are running PuTTY on. (If you're running on Unix, or Windows
+for Alpha, tell us, or we'll assume you're running on Windows for
+Intel as this is overwhelmingly the case.)
+
+\b Tell us what protocol you are connecting with: SSH, Telnet,
+Rlogin or Raw mode.
+
+\b Tell us what kind of server you are connecting to; what OS, and
+if possible what SSH server (if you're using SSH). You can get some
+of this information from the PuTTY Event Log (see \k{using-eventlog}
+in the manual).
+
+\b Send us the contents of the PuTTY Event Log, unless you
+have a specific reason not to (for example, if it contains
+confidential information that you think we should be able to solve
+your problem without needing to know).
+
+\b Try to give us as much information as you can to help us
+see the problem for ourselves. If possible, give us a step-by-step
+sequence of \e{precise} instructions for reproducing the fault.
+
+\b Don't just tell us that PuTTY \q{does the wrong thing}; tell us
+exactly and precisely what it did, and also tell us exactly and
+precisely what you think it should have done instead. Some people
+tell us PuTTY does the wrong thing, and it turns out that it was
+doing the right thing and their expectations were wrong. Help to
+avoid this problem by telling us exactly what you think it should
+have done, and exactly what it did do.
+
+\b If you think you can, you're welcome to try to fix the problem
+yourself. A \i{patch} to the code which fixes a bug is an excellent
+addition to a bug report. However, a patch is never a \e{substitute}
+for a good bug report; if your patch is wrong or inappropriate, and
+you haven't supplied us with full information about the actual bug,
+then we won't be able to find a better solution.
+
+\b
+\W{http://www.chiark.greenend.org.uk/~sgtatham/bugs.html}\cw{http://www.chiark.greenend.org.uk/~sgtatham/bugs.html}
+is an article on how to report bugs effectively in general. If your
+bug report is \e{particularly} unclear, we may ask you to go away,
+read this article, and then report the bug again.
+
+It is reasonable to report bugs in PuTTY's documentation, if you
+think the documentation is unclear or unhelpful. But we do need to
+be given exact details of \e{what} you think the documentation has
+failed to tell you, or \e{how} you think it could be made clearer.
+If your problem is simply that you don't \e{understand} the
+documentation, we suggest posting to a newsgroup (see
+\k{feedback-other-fora}) and seeing if someone
+will explain what you need to know. \e{Then}, if you think the
+documentation could usefully have told you that, send us a bug
+report and explain how you think we should change it.
+
+\H{feedback-features} Requesting extra features
+
+If you want to request a new feature in PuTTY, the very first things
+you should do are:
+
+\b Check the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/}{Wishlist
+page} on the PuTTY website, and see if your feature is already on
+the list. If it is, it probably won't achieve very much to repeat
+the request. (But see \k{feedback-feature-priority} if you want to
+persuade us to give your particular feature higher priority.)
+
+\b Check the Wishlist and
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html}{Change
+Log} on the PuTTY website, and see if we have already added your
+feature in the development snapshots. If it isn't clear, download
+the latest development snapshot and see if the feature is present.
+If it is, then it will also be in the next release and there is no
+need to mail us at all.
+
+If you can't find your feature in either the development snapshots
+\e{or} the Wishlist, then you probably do need to submit a feature
+request. Since the PuTTY authors are very busy, it helps if you try
+to do some of the work for us:
+
+\b Do as much of the design as you can. Think about \q{corner
+cases}; think about how your feature interacts with other existing
+features. Think about the user interface; if you can't come up with
+a simple and intuitive interface to your feature, you shouldn't be
+surprised if we can't either. Always imagine whether it's possible
+for there to be more than one, or less than one, of something you'd
+assumed there would be one of. (For example, if you were to want
+PuTTY to put an icon in the System tray rather than the Taskbar, you
+should think about what happens if there's more than one PuTTY
+active; how would the user tell which was which?)
+
+\b If you can program, it may be worth offering to write the feature
+yourself and send us a patch. However, it is likely to be helpful
+if you confer with us first; there may be design issues you haven't
+thought of, or we may be about to make big changes to the code which
+your patch would clash with, or something. If you check with the
+maintainers first, there is a better chance of your code actually
+being usable. Also, read the design principles listed in \k{udp}: if
+you do not conform to them, we will probably not be able to accept
+your patch.
+
+\H{feedback-feature-priority} Requesting features that have already
+been requested
+
+If a feature is already listed on the Wishlist, then it usually
+means we would like to add it to PuTTY at some point. However, this
+may not be in the near future. If there's a feature on the Wishlist
+which you would like to see in the \e{near} future, there are
+several things you can do to try to increase its priority level:
+
+\b Mail us and vote for it. (Be sure to mention that you've seen it
+on the Wishlist, or we might think you haven't even \e{read} the
+Wishlist). This probably won't have very \e{much} effect; if a huge
+number of people vote for something then it may make a difference,
+but one or two extra votes for a particular feature are unlikely to
+change our priority list immediately. Offering a new and compelling
+justification might help. Also, don't expect a reply.
+
+\b Offer us money if we do the work sooner rather than later. This
+sometimes works, but not always. The PuTTY team all have full-time
+jobs and we're doing all of this work in our free time; we may
+sometimes be willing to give up some more of our free time in
+exchange for some money, but if you try to bribe us for a \e{big}
+feature it's entirely possible that we simply won't have the time to
+spare - whether you pay us or not. (Also, we don't accept bribes to
+add \e{bad} features to the Wishlist, because our desire to provide
+high-quality software to the users comes first.)
+
+\b Offer to help us write the code. This is probably the \e{only}
+way to get a feature implemented quickly, if it's a big one that we
+don't have time to do ourselves.
+
+\H{feedback-support} \ii{Support requests}
+
+If you're trying to make PuTTY do something for you and it isn't
+working, but you're not sure whether it's a bug or not, then
+\e{please} consider looking for help somewhere else. This is one of
+the most common types of mail the PuTTY team receives, and we simply
+don't have time to answer all the questions. Questions of this type
+include:
+
+\b If you want to do something with PuTTY but have no idea where to
+start, and reading the manual hasn't helped, try posting to a
+newsgroup (see \k{feedback-other-fora}) and see if someone can explain
+it to you.
+
+\b If you have tried to do something with PuTTY but it hasn't
+worked, and you aren't sure whether it's a bug in PuTTY or a bug in
+your SSH server or simply that you're not doing it right, then try
+posting to a newsgroup (see \k{feedback-other-fora}) and see
+if someone can solve your problem. Or try doing the same thing with
+a different SSH client and see if it works with that. Please do not
+report it as a PuTTY bug unless you are really sure it \e{is} a bug
+in PuTTY.
+
+\b If someone else installed PuTTY for you, or you're using PuTTY on
+someone else's computer, try asking them for help first. They're more
+likely to understand how they installed it and what they expected you
+to use it for than we are.
+
+\b If you have successfully made a connection to your server and now
+need to know what to type at the server's command prompt, or other
+details of how to use the server-end software, talk to your server's
+system administrator. This is not the PuTTY team's problem. PuTTY is
+only a communications tool, like a telephone; if you can't speak the
+same language as the person at the other end of the phone, it isn't
+the telephone company's job to teach it to you.
+
+If you absolutely cannot get a support question answered any other
+way, you can try mailing it to us, but we can't guarantee to have
+time to answer it.
+
+\H{feedback-webadmin} Web server administration
+
+If the PuTTY \i{web site} is down (Connection Timed Out), please don't
+bother mailing us to tell us about it. Most of us read our e-mail on
+the same machines that host the web site, so if those machines are
+down then we will notice \e{before} we read our e-mail. So there's
+no point telling us our servers are down.
+
+Of course, if the web site has some other error (Connection Refused,
+404 Not Found, 403 Forbidden, or something else) then we might
+\e{not} have noticed and it might still be worth telling us about it.
+
+If you want to report a problem with our web site, check that you're
+looking at our \e{real} web site and not a mirror. The real web site
+is at
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\c{http://www.chiark.greenend.org.uk/~sgtatham/putty/};
+if that's not where you're reading this, then don't report the
+problem to us until you've checked that it's really a problem with
+the main site. If it's only a problem with the mirror, you should
+try to contact the administrator of that mirror site first, and only
+contact us if that doesn't solve the problem (in case we need to
+remove the mirror from our list).
+
+\H{feedback-permission} Asking permission for things
+
+PuTTY is distributed under the MIT Licence (see \k{licence} for
+details). This means you can do almost \e{anything} you like with
+our software, our source code, and our documentation. The only
+things you aren't allowed to do are to remove our copyright notices
+or the licence text itself, or to hold us legally responsible if
+something goes wrong.
+
+So if you want permission to include PuTTY on a magazine cover disk,
+or as part of a collection of useful software on a CD or a web site,
+then \e{permission is already granted}. You don't have to mail us
+and ask. Just go ahead and do it. We don't mind.
+
+(If you want to distribute PuTTY alongside your own application for
+use with that application, or if you want to distribute PuTTY within
+your own organisation, then we recommend, but do not insist, that
+you offer your own first-line technical support, to answer questions
+about the interaction of PuTTY with your environment. If your users
+mail us directly, we won't be able to tell them anything useful about
+your specific setup.)
+
+If you want to use parts of the PuTTY source code in another
+program, then it might be worth mailing us to talk about technical
+details, but if all you want is to ask permission then you don't
+need to bother. You already have permission.
+
+If you just want to link to our web site, just go ahead. (It's not
+clear that we \e{could} stop you doing this, even if we wanted to!)
+
+\H{feedback-mirrors} Mirroring the PuTTY web site
+
+\#{This paragraph also in putty-website/mirrors.html}
+Mirrors of the PuTTY web site are welcome, especially in regions not
+well covered by existing mirrors. (However, if you're in a region that is
+already well served by mirrors, you should consider whether yet another one
+will be worth the effort.) Please don't bother asking us for permission before
+setting up a mirror. You already have permission.
+
+If you mail us \e{after} you have set up the mirror and checked that
+it works, and remember to let us know which country your mirror is in,
+then we'll add it to the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/mirrors.html}{Mirrors
+page} on the PuTTY website.
+
+If you have technical questions about the process of mirroring, then
+you might want to mail us before setting up the mirror (see also the
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/mirrors.html#guidelines}{guidelines on the Mirrors page});
+but if you just want to ask for permission, you don't need to. You
+already have permission.
+
+\H{feedback-compliments} Praise and compliments
+
+One of the most rewarding things about maintaining free software is
+getting e-mails that just say \q{thanks}. We are always happy to
+receive e-mails of this type.
+
+Regrettably we don't have time to answer them all in person. If you
+mail us a compliment and don't receive a reply, \e{please} don't
+think we've ignored you. We did receive it and we were happy about
+it; we just didn't have time to tell you so personally.
+
+To everyone who's ever sent us praise and compliments, in the past
+and the future: \e{you're welcome}!
+
+\H{feedback-address} E-mail address
+
+The actual address to mail is
+\cw{<\W{mailto:putty@projects.tartarus.org}{putty@projects.tartarus.org}>}.
diff --git a/puttysrc/DOC/GS.BUT b/puttysrc/DOC/GS.BUT
new file mode 100644
index 0000000..b6d8a82
--- /dev/null
+++ b/puttysrc/DOC/GS.BUT
@@ -0,0 +1,155 @@
+\define{versionidgs} \versionid $Id: gs.but 6815 2006-08-28 10:35:12Z simon $
+
+\C{gs} Getting started with PuTTY
+
+This chapter gives a quick guide to the simplest types of
+interactive login session using PuTTY.
+
+\H{gs-insecure} \ii{Starting a session}
+
+When you start PuTTY, you will see a \i{dialog box}. This dialog box
+allows you to control everything PuTTY can do. See \k{config} for
+details of all the things you can control.
+
+You don't usually need to change most of the configuration options.
+To start the simplest kind of session, all you need to do is to
+enter a few basic parameters.
+
+In the \q{Host Name} box, enter the Internet \i{host name} of the server
+you want to connect to. You should have been told this by the
+provider of your login account.
+
+Now select a login \i{protocol} to use, from the \q{Connection type}
+buttons. For a login session, you should select \i{Telnet},
+\i{Rlogin} or \i{SSH}. See \k{which-one} for a description of the
+differences between the three protocols, and advice on which one to
+use. The fourth protocol, \I{raw protocol}\e{Raw}, is not used for
+interactive login sessions; you would usually use this for debugging
+other Internet services (see \k{using-rawprot}). The fifth option,
+\e{Serial}, is used for connecting to a local serial line, and works
+somewhat differently: see \k{using-serial} for more information on
+this.
+
+When you change the selected protocol, the number in the \q{Port}
+box will change. This is normal: it happens because the various
+login services are usually provided on different network ports by
+the server machine. Most servers will use the standard port numbers,
+so you will not need to change the port setting. If your server
+provides login services on a non-standard port, your system
+administrator should have told you which one. (For example, many
+\i{MUDs} run Telnet service on a port other than 23.)
+
+Once you have filled in the \q{Host Name}, \q{Protocol}, and
+possibly \q{Port} settings, you are ready to connect. Press the
+\q{Open} button at the bottom of the dialog box, and PuTTY will
+begin trying to connect you to the server.
+
+\H{gs-hostkey} \ii{Verifying the host key} (SSH only)
+
+If you are not using the \i{SSH} protocol, you can skip this
+section.
+
+If you are using SSH to connect to a server for the first time, you
+will probably see a message looking something like this:
+
+\c The server's host key is not cached in the registry. You
+\c have no guarantee that the server is the computer you
+\c think it is.
+\c The server's rsa2 key fingerprint is:
+\c ssh-rsa 1024 7b:e5:6f:a7:f4:f9:81:62:5c:e3:1f:bf:8b:57:6c:5a
+\c If you trust this host, hit Yes to add the key to
+\c PuTTY's cache and carry on connecting.
+\c If you want to carry on connecting just once, without
+\c adding the key to the cache, hit No.
+\c If you do not trust this host, hit Cancel to abandon the
+\c connection.
+
+This is a feature of the SSH protocol. It is designed to protect you
+against a network attack known as \i\e{spoofing}: secretly
+redirecting your connection to a different computer, so that you
+send your password to the wrong machine. Using this technique, an
+attacker would be able to learn the password that guards your login
+account, and could then log in as if they were you and use the
+account for their own purposes.
+
+To prevent this attack, each server has a unique identifying code,
+called a \e{host key}. These keys are created in a way that prevents
+one server from forging another server's key. So if you connect to a
+server and it sends you a different host key from the one you were
+expecting, PuTTY can warn you that the server may have been switched
+and that a spoofing attack might be in progress.
+
+PuTTY records the host key for each server you connect to, in the
+Windows \i{Registry}. Every time you connect to a server, it checks
+that the host key presented by the server is the same host key as it
+was the last time you connected. If it is not, you will see a
+warning, and you will have the chance to abandon your connection
+before you type any private information (such as a password) into
+it.
+
+However, when you connect to a server you have not connected to
+before, PuTTY has no way of telling whether the host key is the
+right one or not. So it gives the warning shown above, and asks you
+whether you want to \I{trusting host keys}trust this host key or
+not.
+
+Whether or not to trust the host key is your choice. If you are
+connecting within a company network, you might feel that all the
+network users are on the same side and spoofing attacks are
+unlikely, so you might choose to trust the key without checking it.
+If you are connecting across a hostile network (such as the
+Internet), you should check with your system administrator, perhaps
+by telephone or in person. (Some modern servers have more than one
+host key. If the system administrator sends you more than one
+\I{host key fingerprint}fingerprint, you should make sure the one
+PuTTY shows you is on the list, but it doesn't matter which one it is.)
+
+\# FIXME: this is all very fine but of course in practice the world
+doesn't work that way. Ask the team if they have any good ideas for
+changes to this section!
+
+\H{gs-login} \ii{Logging in}
+
+After you have connected, and perhaps verified the server's host
+key, you will be asked to log in, probably using a \i{username} and
+a \i{password}. Your system administrator should have provided you
+with these. Enter the username and the password, and the server
+should grant you access and begin your session. If you have
+\I{mistyping a password}mistyped your password, most servers will
+give you several chances to get it right.
+
+If you are using SSH, be careful not to type your username wrongly,
+because you will not have a chance to correct it after you press
+Return; many SSH servers do not permit you to make two login attempts
+using \i{different usernames}. If you type your username wrongly, you
+must close PuTTY and start again.
+
+If your password is refused but you are sure you have typed it
+correctly, check that Caps Lock is not enabled. Many login servers,
+particularly Unix computers, treat upper case and lower case as
+different when checking your password; so if Caps Lock is on, your
+password will probably be refused.
+
+\H{gs-session} After logging in
+
+After you log in to the server, what happens next is up to the
+server! Most servers will print some sort of login message and then
+present a \i{prompt}, at which you can type
+\I{commands on the server}commands which the
+server will carry out. Some servers will offer you on-line help;
+others might not. If you are in doubt about what to do next, consult
+your system administrator.
+
+\H{gs-logout} \ii{Logging out}
+
+When you have finished your session, you should log out by typing
+the server's own logout command. This might vary between servers; if
+in doubt, try \c{logout} or \c{exit}, or consult a manual or your
+system administrator. When the server processes your logout command,
+the PuTTY window should close itself automatically.
+
+You \e{can} close a PuTTY session using the \i{Close button} in the
+window border, but this might confuse the server - a bit like
+hanging up a telephone unexpectedly in the middle of a conversation.
+We recommend you do not do this unless the server has stopped
+responding to you and you cannot close the window any other way.
diff --git a/puttysrc/DOC/INDEX.BUT b/puttysrc/DOC/INDEX.BUT
new file mode 100644
index 0000000..778dda3
--- /dev/null
+++ b/puttysrc/DOC/INDEX.BUT
@@ -0,0 +1,839 @@
+\define{versionidindex} \versionid $Id: index.but 6836 2006-08-29 21:46:56Z jacob $
+
+\IM{Unix version} Unix version of PuTTY tools
+\IM{Unix version} Linux version of PuTTY tools
+
+\IM{Unix} Unix
+\IM{Unix} Linux
+
+\IM{Command Prompt}{command prompt window}{MS-DOS Prompt}{console window} Command Prompt
+\IM{Command Prompt}{command prompt window}{MS-DOS Prompt}{console window} MS-DOS Prompt
+\IM{Command Prompt}{command prompt window}{MS-DOS Prompt}{console window} console window
+
+\IM{spoof}{spoofed}{spoofing} spoofing
+
+\IM{verifying the host key} verifying the host key
+\IM{verifying the host key} host key, verifying
+
+\IM{trusting host keys} trusting host keys
+\IM{trusting host keys} host keys, trusting
+
+\IM{host key fingerprint} fingerprint, of SSH host key
+\IM{host key fingerprint} host key fingerprint (SSH)
+\IM{host key fingerprint} SSH host key fingerprint
+
+\IM{starting a session} starting a session
+\IM{starting a session} session, starting
+
+\IM{commands on the server}{remote command} commands on the server
+\IM{commands on the server}{remote command} remote commands
+\IM{commands on the server}{remote command} server, commands on
+
+\IM{mistyping a password} mistyping a password
+\IM{mistyping a password} password, mistyping
+
+\IM{different usernames}{changes of username} different user names
+\IM{different usernames}{changes of username} changing user names
+\IM{different usernames}{changes of username} user names, different
+\IM{different usernames}{changes of username} login names, different
+\IM{different usernames}{changes of username} account names, different
+
+\IM{differences between SSH, Telnet and Rlogin} differences between
+SSH, Telnet and Rlogin
+\IM{differences between SSH, Telnet and Rlogin} protocols,
+differences between
+\IM{differences between SSH, Telnet and Rlogin} SSH, differences
+from Telnet and Rlogin
+\IM{differences between SSH, Telnet and Rlogin} Telnet, differences
+from SSH and Rlogin
+\IM{differences between SSH, Telnet and Rlogin} Rlogin, differences
+from SSH and Telnet
+\IM{differences between SSH, Telnet and Rlogin} selecting a protocol
+\IM{differences between SSH, Telnet and Rlogin} choosing a protocol
+
+\IM{MUD}{MUDs} MUDs
+
+\IM{talker}{talker systems} talker systems
+
+\IM{security hazard}{security risk} security hazard
+
+\IM{SSH-1}{SSH protocol version 1} SSH-1
+\IM{SSH-2}{SSH protocol version 2} SSH-2
+
+\IM{terminal window}{PuTTY window} terminal window
+\IM{terminal window}{PuTTY window} PuTTY terminal window
+\IM{terminal window}{PuTTY window} window, terminal
+
+\IM{copy and paste} copy and paste
+\IM{copy and paste} cut and paste
+\IM{copy and paste} paste, copy and
+
+\IM{three-button mouse} three-button mouse
+\IM{three-button mouse} mouse, three-button
+
+\IM{left mouse button}{left button} left mouse button
+\IM{middle mouse button}{middle button} middle mouse button
+\IM{right mouse button}{right button} right mouse button
+
+\IM{selecting words}{word-by-word selection} selecting whole words
+\IM{selecting words}{word-by-word selection} words, selecting
+
+\IM{selecting lines} selecting whole lines
+\IM{selecting lines} lines, selecting
+
+\IM{rectangular selection} rectangular selection
+\IM{rectangular selection} selection, rectangular
+
+\IM{adjusting a selection} adjusting a selection
+\IM{adjusting a selection} extending a selection
+\IM{adjusting a selection} selection, adjusting
+
+\IM{right mouse button, with Ctrl} right mouse button, with Ctrl
+\IM{right mouse button, with Ctrl} Ctrl, with right mouse button
+
+\IM{system menu} system menu
+\IM{system menu} menu, system
+\IM{system menu} window menu
+
+\IM{context menu} context menu
+\IM{context menu} menu, context
+\IM{context menu} right mouse button menu
+
+\IM{Event Log} Event Log
+\IM{Event Log} PuTTY Event Log
+\IM{Event Log} Log, Event
+
+\IM{Telnet special commands} Telnet special commands
+\IM{Telnet special commands} special commands, in Telnet
+
+\IM{SSH special commands} SSH special commands
+\IM{SSH special commands} special commands, in SSH
+
+\IM{Repeat key exchange, SSH special command} Repeat key exchange, SSH special command
+\IM{Repeat key exchange, SSH special command} key exchange, forcing repeat
+\IM{Repeat key exchange, SSH special command} SSH key exchange, forcing repeat
+
+\IM{accented characters} accented characters
+\IM{accented characters} characters, accented
+
+\IM{line-drawing characters} line-drawing characters
+\IM{line-drawing characters} box-drawing characters
+\IM{line-drawing characters} characters, line-drawing
+\IM{line-drawing characters} ANSI graphics
+
+\IM{port forwarding}{port forwardings} port forwarding in SSH
+\IM{port forwarding}{port forwardings} SSH port forwarding
+\IM{port forwarding}{port forwardings} forwarding ports in SSH
+\IM{port forwarding}{port forwardings} tunnelling using SSH
+\IM{port forwarding}{port forwardings} SSH tunnelling
+
+\IM{port forwarding, changing mid-session} port forwarding in SSH, changing mid-session
+\IM{port forwarding, changing mid-session} SSH port forwarding, changing mid-session
+\IM{port forwarding, changing mid-session} forwarding ports in SSH, changing mid-session
+\IM{port forwarding, changing mid-session} tunnelling using SSH, changing mid-session
+\IM{port forwarding, changing mid-session} SSH tunnelling, changing mid-session
+
+\IM{local port forwarding} local-to-remote port forwarding
+\IM{remote port forwarding} remote-to-local port forwarding
+
+\IM{dynamic port forwarding} dynamic port forwarding
+\IM{dynamic port forwarding} SOCKS port forwarding
+
+\IM{debugging Internet protocols} debugging Internet protocols
+\IM{debugging Internet protocols} Internet protocols, debugging
+\IM{debugging Internet protocols} protocols, debugging
+
+\IM{Internet protocol version} Internet Protocol version
+\IM{Internet protocol version} version, of Internet Protocol
+
+\IM{raw TCP connections} raw TCP connections
+\IM{raw TCP connections} TCP connections, raw
+
+\IM{command-line arguments} command-line arguments
+\IM{command-line arguments} arguments, command-line
+\IM{command-line arguments} options, command-line
+\IM{command-line arguments} switches, command-line
+
+\IM{Windows shortcut} Windows shortcut
+\IM{Windows shortcut} shortcut, Windows
+
+\IM{telnet URLs} Telnet URLs
+\IM{telnet URLs} URLs, Telnet
+
+\IM{saved sessions, loading from command line} saved sessions,
+loading from command line
+\IM{saved sessions, loading from command line} loading saved
+sessions from command line
+\IM{saved sessions, loading from command line} command line, loading
+saved sessions from
+
+\IM{putty @sessionname} \c{putty @sessionname}
+\IM{putty @sessionname} \c{@sessionname} command-line argument
+
+\IM{protocol selection} protocol selection
+\IM{protocol selection} selecting a protocol
+\IM{protocol selection} choosing a protocol
+
+\IM{login name}{username} login name
+\IM{login name}{username} user name
+\IM{login name}{username} account name
+
+\IM{reading commands from a file} reading commands from a file
+\IM{reading commands from a file} commands, reading from a file
+
+\IM{agent forwarding} agent forwarding
+\IM{agent forwarding} authentication agent forwarding
+\IM{agent forwarding} SSH agent forwarding
+\IM{agent forwarding} forwarding, SSH agent
+
+\IM{X11 forwarding}{forwarding of X11} X11 forwarding
+\IM{X11 forwarding}{forwarding of X11} SSH X11 forwarding
+\IM{X11 forwarding}{forwarding of X11} forwarding, of X11
+
+\IM{X11 authentication} X11 authentication
+\IM{X11 authentication} authentication, X11
+
+\IM{pseudo-terminal allocation} pseudo-terminal allocation
+\IM{pseudo-terminal allocation} pty allocation
+\IM{pseudo-terminal allocation} allocation, of pseudo-terminal
+
+\IM{ERASE special character} \cw{ERASE}, special character
+\IM{ERASE special character} \cw{VERASE}, special character
+\IM{QUIT special character} \cw{QUIT}, special character
+\IM{QUIT special character} \cw{VQUIT}, special character
+
+\IM{-telnet} \c{-telnet} command-line option
+\IM{-raw} \c{-raw} command-line option
+\IM{-rlogin} \c{-rlogin} command-line option
+\IM{-ssh} \c{-ssh} command-line option
+\IM{-cleanup} \c{-cleanup} command-line option
+\IM{-load} \c{-load} command-line option
+\IM{-v} \c{-v} command-line option
+\IM{-l} \c{-l} command-line option
+\IM{-L-upper} \c{-L} command-line option
+\IM{-R-upper} \c{-R} command-line option
+\IM{-D-upper} \c{-D} command-line option
+\IM{-m} \c{-m} command-line option
+\IM{-P-upper} \c{-P} command-line option
+\IM{-pw} \c{-pw} command-line option
+\IM{-A-upper} \c{-A} command-line option
+\IM{-a} \c{-a} command-line option
+\IM{-X-upper} \c{-X} command-line option
+\IM{-x} \c{-x} command-line option
+\IM{-T-upper} \c{-T} command-line option
+\IM{-t} \c{-t} command-line option
+\IM{-C-upper} \c{-C} command-line option
+\IM{-N-upper} \c{-N} command-line option
+\IM{-1} \c{-1} command-line option
+\IM{-2} \c{-2} command-line option
+\IM{-i} \c{-i} command-line option
+\IM{-pgpfp} \c{-pgpfp} command-line option
+
+\IM{removing registry entries} removing registry entries
+\IM{removing registry entries} registry entries, removing
+
+\IM{random seed file} random seed file
+\IM{random seed file} \c{putty.rnd} (random seed file)
+
+\IM{putty.rnd} \c{putty.rnd} (random seed file)
+
+\IM{suppressing remote shell} remote shell, suppressing
+\IM{suppressing remote shell} shell, remote, suppressing
+
+\IM{SSH protocol version} SSH protocol version
+\IM{SSH protocol version} protocol version, SSH
+\IM{SSH protocol version} version, of SSH protocol
+
+\IM{PPK} \cw{PPK} file
+\IM{PPK} private key file, PuTTY
+
+\IM{PGP key fingerprint} PGP key fingerprint
+\IM{PGP key fingerprint} fingerprint, of PGP key
+
+\IM{verifying new versions} verifying new versions of PuTTY
+\IM{verifying new versions} new version, verifying
+\IM{verifying new versions} upgraded version, verifying
+
+\IM{connection}{network connection} network connection
+\IM{connection}{network connection} connection, network
+
+\IM{host name}{hostname} host name
+\IM{host name}{hostname} DNS name
+\IM{host name}{hostname} server name
+
+\IM{IP address}{Internet address} IP address
+\IM{IP address}{Internet address} address, IP
+
+\IM{localhost} \c{localhost}
+
+\IM{loopback IP address}{loopback address} loopback IP address
+\IM{loopback IP address}{loopback address} IP address, loopback
+
+\IM{listen address} listen address
+\IM{listen address} bind address
+
+\IM{DNS} DNS
+\IM{DNS} Domain Name System
+
+\IM{name resolution} name resolution
+\IM{name resolution} DNS resolution
+\IM{name resolution} host name resolution
+\IM{name resolution} server name resolution
+
+\IM{loading and storing saved sessions} sessions, loading and storing
+\IM{loading and storing saved sessions} settings, loading and storing
+\IM{loading and storing saved sessions} saving settings
+\IM{loading and storing saved sessions} storing settings
+\IM{loading and storing saved sessions} loading settings
+
+\IM{Default Settings} Default Settings
+\IM{Default Settings} settings, default
+
+\IM{Registry} Registry (Windows)
+\IM{Registry} Windows Registry
+
+\IM{inactive window} inactive window
+\IM{inactive window} window, inactive
+\IM{inactive window} terminal window, inactive
+
+\IM{SSH packet log} SSH packet log
+\IM{SSH packet log} packet log, SSH
+
+\IM{auto wrap mode}{auto wrap} auto wrap mode
+\IM{auto wrap mode}{auto wrap} wrapping, automatic
+\IM{auto wrap mode}{auto wrap} line wrapping, automatic
+
+\IM{control sequence}{control codes} control sequences
+\IM{control sequence}{control codes} terminal control sequences
+\IM{control sequence}{control codes} escape sequences
+
+\IM{cursor coordinates} cursor coordinates
+\IM{cursor coordinates} coordinates, cursor
+
+\IM{CR} CR (Carriage Return)
+\IM{CR} Carriage Return
+
+\IM{LF} LF (Line Feed)
+\IM{LF} Line Feed
+
+\IM{clear screen} clear screen
+\IM{clear screen} erase screen
+\IM{clear screen} screen, clearing
+
+\IM{blinking text} blinking text
+\IM{blinking text} flashing text
+
+\IM{answerback} answerback string
+
+\IM{local echo} local echo
+\IM{local echo} echo, local
+
+\IM{remote echo} remote echo
+\IM{remote echo} echo, remote
+
+\IM{local line editing} local line editing
+\IM{local line editing} line editing, local
+
+\IM{remote-controlled printing} ANSI printing
+\IM{remote-controlled printing} remote-controlled printing
+\IM{remote-controlled printing} printing, remote-controlled
+
+\IM{Home and End keys} Home key
+\IM{Home and End keys} End key
+
+\IM{keypad} keypad, numeric
+\IM{keypad} numeric keypad
+
+\IM{Application Cursor Keys} Application Cursor Keys
+\IM{Application Cursor Keys} cursor keys, \q{Application} mode
+
+\IM{Application Keypad} Application Keypad
+\IM{Application Keypad} keypad, \q{Application} mode
+\IM{Application Keypad} numeric keypad, \q{Application} mode
+
+\IM{Num Lock}{NumLock} Num Lock
+
+\IM{NetHack keypad mode} NetHack keypad mode
+\IM{NetHack keypad mode} keypad, NetHack mode
+
+\IM{compose key} Compose key
+\IM{compose key} DEC Compose key
+
+\IM{terminal bell} terminal bell
+\IM{terminal bell} bell, terminal
+\IM{terminal bell} beep, terminal
+\IM{terminal bell} feep
+
+\IM{Windows Default Beep} Windows Default Beep sound
+\IM{Windows Default Beep} Default Beep sound, Windows
+
+\IM{terminal bell, disabling} terminal bell, disabling
+\IM{terminal bell, disabling} bell, disabling
+
+\IM{visual bell} visual bell
+\IM{visual bell} bell, visual
+
+\IM{PC speaker} PC speaker
+\IM{PC speaker} beep, with PC speaker
+
+\IM{sound file} sound file
+\IM{sound file} \cw{WAV} file
+
+\IM{bell overload} bell overload mode
+\IM{bell overload} terminal bell overload mode
+
+\IM{mouse reporting} mouse reporting
+\IM{mouse reporting} \c{xterm} mouse reporting
+
+\IM{links} \c{links} (web browser)
+
+\IM{mc} \c{mc}
+\IM{mc} Midnight Commander
+
+\IM{terminal resizing}{window resizing} terminal resizing
+\IM{terminal resizing}{window resizing} window resizing
+\IM{terminal resizing}{window resizing} resizing, terminal
+
+\IM{destructive backspace} destructive backspace
+\IM{destructive backspace} non-destructive backspace
+\IM{destructive backspace} backspace, destructive
+
+\IM{Arabic text shaping} Arabic text shaping
+\IM{Arabic text shaping} shaping, of Arabic text
+
+\IM{Unicode} Unicode
+\IM{Unicode} ISO-10646 (Unicode)
+
+\IM{ASCII} ASCII
+\IM{ASCII} US-ASCII
+
+\IM{bidirectional text} bidirectional text
+\IM{bidirectional text} right-to-left text
+
+\IM{display becomes corrupted} display corruption
+\IM{display becomes corrupted} corruption, of display
+
+\IM{rows} rows, in terminal window
+\IM{columns} columns, in terminal window
+
+\IM{window size} window size
+\IM{window size} size, of window
+
+\IM{font size} font size
+\IM{font size} size, of font
+
+\IM{full screen}{full-screen} full-screen mode
+
+\IM{cursor blinks} blinking cursor
+\IM{cursor blinks} flashing cursor
+\IM{cursor blinks} cursor, blinking
+
+\IM{font} font
+\IM{font} typeface
+
+\IM{minimise} minimise window
+\IM{minimise} window, minimising
+
+\IM{maximise} maximise window
+\IM{maximise} window, maximising
+
+\IM{closing window}{close window} closing window
+\IM{closing window}{close window} window, closing
+
+\IM{Dragon NaturallySpeaking} Dragon NaturallySpeaking
+\IM{Dragon NaturallySpeaking} NaturallySpeaking
+
+\IM{AltGr} \q{AltGr} key
+\IM{Alt} \q{Alt} key
+
+\IM{CJK} CJK
+\IM{CJK} Chinese
+\IM{CJK} Japanese
+\IM{CJK} Korean
+
+\IM{East Asian Ambiguous characters} East Asian Ambiguous characters
+\IM{East Asian Ambiguous characters} CJK ambiguous characters
+
+\IM{character width} character width
+\IM{character width} single-width character
+\IM{character width} double-width character
+
+\IM{Rich Text Format} Rich Text Format
+\IM{Rich Text Format} RTF
+
+\IM{bold}{bold text} bold text
+
+\IM{colour}{colours} colour
+
+\IM{8-bit colour} 8-bit colour
+\IM{8-bit colour} colour, 8-bit
+
+\IM{system colours} system colours
+\IM{system colours} colours, system
+
+\IM{ANSI colours} ANSI colours
+\IM{ANSI colours} colours, ANSI
+
+\IM{cursor colour} cursor colour
+\IM{cursor colour} colour, of cursor
+
+\IM{default background} background colour, default
+\IM{default background} colour, background, default
+
+\IM{default foreground} foreground colour, default
+\IM{default foreground} colour, foreground, default
+
+\IM{TERM} \cw{TERM} environment variable
+
+\IM{logical palettes} logical palettes
+\IM{logical palettes} palettes, logical
+
+\IM{breaks in connectivity} connectivity, breaks in
+\IM{breaks in connectivity} intermittent connectivity
+
+\IM{idle connections} idle connections
+\IM{idle connections} timeout, of connections
+\IM{idle connections} connections, idle
+
+\IM{interactive connections}{interactive session} interactive connections
+\IM{interactive connections}{interactive session} connections, interactive
+
+\IM{keepalives} keepalives, application
+
+\IM{Nagle's algorithm} Nagle's algorithm
+\IM{Nagle's algorithm} \cw{TCP_NODELAY}
+
+\IM{TCP keepalives} TCP keepalives
+\IM{TCP keepalives} keepalives, TCP
+\IM{TCP keepalives} \cw{SO_KEEPALIVE}
+
+\IM{half-open connections} half-open connections
+\IM{half-open connections} connections, half-open
+
+\IM{auto-login username} user name, for auto-login
+\IM{auto-login username} login name, for auto-login
+\IM{auto-login username} account name, for auto-login
+
+\IM{terminal emulation}{terminal-type} terminal emulation
+\IM{terminal emulation}{terminal-type} emulation, terminal
+
+\IM{terminal speed} terminal speed
+\IM{terminal speed} speed, terminal
+\IM{terminal speed} baud rate, of terminal
+
+\IM{environment variables} environment variables
+\IM{environment variables} variables, environment
+
+\IM{proxy} proxy server
+\IM{proxy} server, proxy
+
+\IM{HTTP proxy} HTTP proxy
+\IM{HTTP proxy} proxy, HTTP
+\IM{HTTP proxy} server, HTTP
+\IM{HTTP proxy} \cw{CONNECT} proxy (HTTP)
+
+\IM{SOCKS server} SOCKS proxy
+\IM{SOCKS server} server, SOCKS
+\IM{SOCKS server} proxy, SOCKS
+
+\IM{Telnet proxy} Telnet proxy
+\IM{Telnet proxy} TCP proxy
+\IM{Telnet proxy} ad-hoc proxy
+\IM{Telnet proxy} proxy, Telnet
+
+\IM{Local proxy} local proxy
+\IM{Local proxy} proxy command
+\IM{Local proxy} command, proxy
+
+\IM{proxy DNS} proxy DNS
+\IM{proxy DNS} DNS, with proxy
+\IM{proxy DNS} name resolution, with proxy
+\IM{proxy DNS} host name resolution, with proxy
+\IM{proxy DNS} server name resolution, with proxy
+
+\IM{proxy username} proxy user name
+\IM{proxy username} user name, for proxy
+\IM{proxy username} login name, for proxy
+\IM{proxy username} account name, for proxy
+
+\IM{proxy password} proxy password
+\IM{proxy password} password, for proxy
+
+\IM{proxy authentication} proxy authentication
+\IM{proxy authentication} authentication, to proxy
+
+\IM{HTTP basic} HTTP \q{basic} authentication
+\IM{HTTP basic} \q{basic} authentication (HTTP)
+
+\IM{plaintext password} plain text password
+\IM{plaintext password} password, plain text
+
+\IM{Telnet negotiation} Telnet option negotiation
+\IM{Telnet negotiation} option negotiation, Telnet
+\IM{Telnet negotiation} negotiation, of Telnet options
+
+\IM{firewall}{firewalls} firewalls
+
+\IM{NAT router}{NAT} NAT routers
+\IM{NAT router}{NAT} routers, NAT
+\IM{NAT router}{NAT} Network Address Translation
+\IM{NAT router}{NAT} IP masquerading
+
+\IM{Telnet New Line} Telnet New Line
+\IM{Telnet New Line} new line, in Telnet
+
+\IM{.rhosts} \c{.rhosts} file
+\IM{.rhosts} \q{rhosts} file
+
+\IM{passwordless login} passwordless login
+\IM{passwordless login} login, passwordless
+
+\IM{Windows user name} local user name, in Windows
+\IM{Windows user name} user name, local, in Windows
+\IM{Windows user name} login name, local, in Windows
+\IM{Windows user name} account name, local, in Windows
+
+\IM{local username in Rlogin} local user name, in Rlogin
+\IM{local username in Rlogin} user name, local, in Rlogin
+\IM{local username in Rlogin} login name, local, in Rlogin
+\IM{local username in Rlogin} account name, local, in Rlogin
+
+\IM{privileged port} privileged port
+\IM{privileged port} low-numbered port
+\IM{privileged port} port, privileged
+
+\IM{remote shell} shell, remote
+\IM{remote shell} remote shell
+
+\IM{encryption}{encrypted}{encrypt} encryption
+
+\IM{encryption algorithm} encryption algorithm
+\IM{encryption algorithm} cipher algorithm
+\IM{encryption algorithm} symmetric-key algorithm
+\IM{encryption algorithm} algorithm, encryption
+
+\IM{AES} AES
+\IM{AES} Advanced Encryption Standard
+\IM{AES} Rijndael
+
+\IM{Arcfour} Arcfour
+\IM{Arcfour} RC4
+
+\IM{triple-DES} triple-DES
+
+\IM{single-DES} single-DES
+\IM{single-DES} DES
+
+\IM{key exchange} key exchange
+\IM{key exchange} kex
+
+\IM{shared secret} shared secret
+\IM{shared secret} secret, shared
+
+\IM{key exchange algorithm} key exchange algorithm
+\IM{key exchange algorithm} algorithm, key exchange
+
+\IM{Diffie-Hellman key exchange} Diffie-Hellman key exchange
+\IM{Diffie-Hellman key exchange} key exchange, Diffie-Hellman
+
+\IM{group exchange} Diffie-Hellman group exchange
+\IM{group exchange} group exchange, Diffie-Hellman
+
+\IM{repeat key exchange} repeat key exchange
+\IM{repeat key exchange} key exchange, repeat
+
+\IM{challenge/response authentication} challenge/response authentication
+\IM{challenge/response authentication} authentication, challenge/response
+
+\IM{security token} security token
+\IM{security token} token, security
+
+\IM{one-time passwords} one-time passwords
+\IM{one-time passwords} password, one-time
+
+\IM{keyboard-interactive authentication} keyboard-interactive authentication
+\IM{keyboard-interactive authentication} authentication, keyboard-interactive
+
+\IM{password expiry} password expiry
+\IM{password expiry} expiry, of passwords
+
+\IM{public key authentication}{public-key authentication} public key authentication
+\IM{public key authentication}{public-key authentication} RSA authentication
+\IM{public key authentication}{public-key authentication} DSA authentication
+\IM{public key authentication}{public-key authentication} authentication, public key
+
+\IM{MIT-MAGIC-COOKIE-1} \cw{MIT-MAGIC-COOKIE-1}
+\IM{MIT-MAGIC-COOKIE-1} magic cookie
+\IM{MIT-MAGIC-COOKIE-1} cookie, magic
+
+\IM{SSH server bugs} SSH server bugs
+\IM{SSH server bugs} bugs, in SSH servers
+
+\IM{ignore message} SSH \q{ignore} messages
+\IM{ignore message} \q{ignore} messages, in SSH
+
+\IM{message authentication code} message authentication code
+\IM{message authentication code} MAC (message authentication code)
+
+\IM{signatures} signature
+\IM{signatures} digital signature
+
+\IM{storing configuration in a file} storing settings in a file
+\IM{storing configuration in a file} saving settings in a file
+\IM{storing configuration in a file} loading settings from a file
+
+\IM{transferring files} transferring files
+\IM{transferring files} files, transferring
+
+\IM{receiving files}{download a file} receiving files
+\IM{receiving files}{download a file} files, receiving
+\IM{receiving files}{download a file} downloading files
+
+\IM{sending files}{upload a file} sending files
+\IM{sending files}{upload a file} files, sending
+\IM{sending files}{upload a file} uploading files
+
+\IM{listing files} listing files
+\IM{listing files} files, listing
+
+\IM{wildcard}{wildcards} wildcards
+\IM{wildcard}{wildcards} glob (wildcard)
+
+\IM{PATH} \c{PATH} environment variable
+
+\IM{SFTP} SFTP
+\IM{SFTP} SSH file transfer protocol
+
+\IM{-unsafe} \c{-unsafe} PSCP command-line option
+\IM{-ls-PSCP} \c{-ls} PSCP command-line option
+\IM{-p-PSCP} \c{-p} PSCP command-line option
+\IM{-q-PSCP} \c{-q} PSCP command-line option
+\IM{-r-PSCP} \c{-r} PSCP command-line option
+\IM{-batch-PSCP} \c{-batch} PSCP command-line option
+\IM{-sftp} \c{-sftp} PSCP command-line option
+\IM{-scp} \c{-scp} PSCP command-line option
+
+\IM{return value} return value
+\IM{return value} exit value
+
+\IM{-b-PSFTP} \c{-b} PSFTP command-line option
+\IM{-bc-PSFTP} \c{-bc} PSFTP command-line option
+\IM{-be-PSFTP} \c{-be} PSFTP command-line option
+\IM{-batch-PSFTP} \c{-batch} PSFTP command-line option
+
+\IM{spaces in filenames} spaces in filenames
+\IM{spaces in filenames} filenames containing spaces
+
+\IM{working directory} working directory
+\IM{working directory} current working directory
+
+\IM{resuming file transfers} resuming file transfers
+\IM{resuming file transfers} files, resuming transfer of
+
+\IM{changing permissions on files} changing permissions on files
+\IM{changing permissions on files} permissions on files, changing
+\IM{changing permissions on files} files, changing permissions on
+\IM{changing permissions on files} modes of files, changing
+\IM{changing permissions on files} access to files, changing
+
+\IM{deleting files} deleting files
+\IM{deleting files} files, deleting
+\IM{deleting files} removing files
+
+\IM{create a directory} creating directories
+\IM{create a directory} directories, creating
+
+\IM{remove a directory} removing directories
+\IM{remove a directory} directories, removing
+\IM{remove a directory} deleting directories
+
+\IM{rename remote files} renaming files
+\IM{rename remote files} files, renaming and moving
+\IM{rename remote files} moving files
+
+\IM{local Windows command} local Windows command
+\IM{local Windows command} Windows command
+
+\IM{PLINK_PROTOCOL} \c{PLINK_PROTOCOL} environment variable
+
+\IM{-batch-plink} \c{-batch} Plink command-line option
+\IM{-s-plink} \c{-s} Plink command-line option
+
+\IM{subsystem} subsystem, SSH
+\IM{subsystem} SSH subsystem
+
+\IM{batch file}{batch files} batch files
+
+\IM{CVS_RSH} \c{CVS_RSH} environment variable
+
+\IM{DSA} DSA
+\IM{DSA} Digital Signature Standard
+
+\IM{public-key algorithm} public-key algorithm
+\IM{public-key algorithm} asymmetric key algorithm
+\IM{public-key algorithm} algorithm, public-key
+
+\IM{generating keys} generating key pairs
+\IM{generating keys} creating key pairs
+\IM{generating keys} key pairs, generating
+\IM{generating keys} public keys, generating
+\IM{generating keys} private keys, generating
+
+\IM{authorized_keys file}{authorized_keys} \cw{authorized_keys} file
+
+\IM{key fingerprint} fingerprint, of SSH authentication key
+\IM{key fingerprint} public key fingerprint (SSH)
+\IM{key fingerprint} SSH public key fingerprint
+
+\IM{SSH-2 public key format} SSH-2 public key file format
+\IM{SSH-2 public key format} public key file, SSH-2
+
+\IM{OpenSSH private key format} OpenSSH private key file format
+\IM{OpenSSH private key format} private key file, OpenSSH
+
+\IM{ssh.com private key format} \cw{ssh.com} private key file format
+\IM{ssh.com private key format} private key file, \cw{ssh.com}
+
+\IM{importing keys} importing private keys
+\IM{importing keys} loading private keys
+
+\IM{export private keys} exporting private keys
+\IM{export private keys} saving private keys
+
+\IM{.ssh} \c{.ssh} directory
+
+\IM{.ssh2} \c{.ssh2} directory
+
+\IM{authentication agent} authentication agent
+\IM{authentication agent} agent, authentication
+
+\IM{-c-pageant} \c{-c} Pageant command-line option
+
+\IM{FAQ} FAQ
+\IM{FAQ} Frequently Asked Questions
+
+\IM{supported features} supported features
+\IM{supported features} features, supported
+
+\IM{remember my password} storing passwords
+\IM{remember my password} password, storing
+
+\IM{login scripts}{startup scripts} login scripts
+\IM{login scripts}{startup scripts} startup scripts
+
+\IM{WS2_32.DLL} \cw{WS2_32.DLL}
+\IM{WS2_32.DLL} WinSock version 2
+
+\IM{Red Hat Linux} Red Hat Linux
+\IM{Red Hat Linux} Linux, Red Hat
+
+\IM{SMB} SMB
+\IM{SMB} Windows file sharing
+
+\IM{clean up} clean up after PuTTY
+\IM{clean up} uninstalling
+
+\IM{version of PuTTY} version, of PuTTY
+
+\IM{PGP signatures} PGP signatures, of PuTTY binaries
+\IM{PGP signatures} signatures, of PuTTY binaries
diff --git a/puttysrc/DOC/INTRO.BUT b/puttysrc/DOC/INTRO.BUT
new file mode 100644
index 0000000..8796662
--- /dev/null
+++ b/puttysrc/DOC/INTRO.BUT
@@ -0,0 +1,88 @@
+\define{versionidintro} \versionid $Id: intro.but 5593 2005-04-05 18:01:32Z jacob $
+
+\C{intro} Introduction to PuTTY
+
+PuTTY is a free SSH, Telnet and Rlogin client for 32-bit Windows
+systems.
+
+\H{you-what} What are SSH, Telnet and Rlogin?
+
+If you already know what SSH, Telnet and Rlogin are, you can safely
+skip on to the next section.
+
+SSH, Telnet and Rlogin are three ways of doing the same thing:
+logging in to a multi-user computer from another computer, over a
+network.
+
+Multi-user operating systems, such as Unix and VMS, usually present
+a \i{command-line interface} to the user, much like the \q{\i{Command
+Prompt}} or \q{\i{MS-DOS Prompt}} in Windows. The system prints a
+prompt, and you type commands which the system will obey.
+
+Using this type of interface, there is no need for you to be sitting
+at the same machine you are typing commands to. The commands, and
+responses, can be sent over a network, so you can sit at one
+computer and give commands to another one, or even to more than one.
+
+SSH, Telnet and Rlogin are \i\e{network protocols} that allow you to
+do this. On the computer you sit at, you run a \i\e{client}, which
+makes a network connection to the other computer (the \i\e{server}).
+The network connection carries your keystrokes and commands from the
+client to the server, and carries the server's responses back to
+you.
+
+These protocols can also be used for other types of keyboard-based
+interactive session. In particular, there are a lot of bulletin
+boards, \i{talker systems} and \i{MUDs} (Multi-User Dungeons) which support
+access using Telnet. There are even a few that support SSH.
+
+You might want to use SSH, Telnet or Rlogin if:
+
+\b you have an account on a Unix or VMS system which you want to be
+able to access from somewhere else
+
+\b your Internet Service Provider provides you with a login account
+on a \i{web server}. (This might also be known as a \i\e{shell account}.
+A \e{shell} is the program that runs on the server and interprets
+your commands for you.)
+
+\b you want to use a \i{bulletin board system}, talker or MUD which can
+be accessed using Telnet.
+
+You probably do \e{not} want to use SSH, Telnet or Rlogin if:
+
+\b you only use Windows. Windows computers have their own
+ways of networking between themselves, and unless you are doing
+something fairly unusual, you will not need to use any of these
+remote login protocols.
+
+\H{which-one} How do SSH, Telnet and Rlogin differ?
+
+This list summarises some of the \i{differences between SSH, Telnet
+and Rlogin}.
+
+\b SSH (which stands for \q{\i{secure shell}}) is a recently designed,
+high-security protocol. It uses strong cryptography to protect your
+connection against eavesdropping, hijacking and other attacks. Telnet
+and Rlogin are both older protocols offering minimal security.
+
+\b SSH and Rlogin both allow you to \I{passwordless login}log in to the
+server without having to type a password. (Rlogin's method of doing this is
+insecure, and can allow an attacker to access your account on the
+server. SSH's method is much more secure, and typically breaking the
+security requires the attacker to have gained access to your actual
+client machine.)
+
+\b SSH allows you to connect to the server and automatically send a
+command, so that the server will run that command and then
+disconnect. So you can use it in automated processing.
+
+The Internet is a hostile environment and security is everybody's
+responsibility. If you are connecting across the open Internet, then
+we recommend you use SSH. If the server you want to connect to
+doesn't support SSH, it might be worth trying to persuade the
+administrator to install it.
+
+If your client and server are both behind the same (good) firewall,
+it is more likely to be safe to use Telnet or Rlogin, but we still
+recommend you use SSH.
diff --git a/puttysrc/DOC/LICENCE.BUT b/puttysrc/DOC/LICENCE.BUT
new file mode 100644
index 0000000..7edb717
--- /dev/null
+++ b/puttysrc/DOC/LICENCE.BUT
@@ -0,0 +1,29 @@
+\define{versionidlicence} \versionid $Id: licence.but 7048 2007-01-01 21:19:14Z jacob $
+
+\A{licence} PuTTY \ii{Licence}
+
+PuTTY is \i{copyright} 1997-2007 Simon Tatham.
+
+Portions copyright Robert de Bath, Joris van Rantwijk, Delian
+Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
+Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn,
+and CORE SDI S.A.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation files
+(the \q{Software}), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED \q{AS IS}, WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/puttysrc/DOC/MAKEFILE b/puttysrc/DOC/MAKEFILE
new file mode 100644
index 0000000..1feefee
--- /dev/null
+++ b/puttysrc/DOC/MAKEFILE
@@ -0,0 +1,75 @@
+all: man index.html
+
+# Decide on the versionid policy.
+#
+# If the user has passed in $(VERSION) on the command line (`make
+# VERSION="Release 0.56"'), we use that as an explicit version
+# string. Otherwise, we use `svnversion' to examine the checked-out
+# documentation source, and if that returns a single revision
+# number then we invent a version string reflecting just that
+# number. Failing _that_, we resort to versionids.but which shows a
+# $Id for each individual file.
+#
+# So here, we define VERSION using svnversion if it isn't already
+# defined ...
+ifndef VERSION
+SVNVERSION=$(shell test -d .svn && svnversion .)
+BADCHARS=$(findstring :,$(SVNVERSION))$(findstring S,$(SVNVERSION))
+ifeq ($(BADCHARS),)
+ifneq ($(SVNVERSION),)
+ifneq ($(SVNVERSION),exported)
+VERSION=Built from revision $(patsubst M,,$(SVNVERSION))
+endif
+endif
+endif
+endif
+# ... and now, we condition our build behaviour on whether or not
+# VERSION _is_ defined.
+ifdef VERSION
+VERSIONIDS=vstr
+vstr.but: FORCE
+ echo \\versionid $(VERSION) > vstr.but
+FORCE:;
+else
+VERSIONIDS=vids
+endif
+
+CHAPTERS := $(SITE) blurb intro gs using config pscp psftp plink pubkey
+CHAPTERS += pageant errors faq feedback licence udp pgpkeys
+CHAPTERS += index $(VERSIONIDS)
+
+INPUTS = $(patsubst %,%.but,$(CHAPTERS))
+
+# This is temporary. Hack it locally or something.
+HALIBUT = halibut
+
+index.html: $(INPUTS)
+ $(HALIBUT) --text --html --winhelp $(INPUTS)
+
+# During formal builds it's useful to be able to build this one alone.
+putty.hlp: $(INPUTS)
+ $(HALIBUT) --winhelp $(INPUTS)
+
+putty.info: $(INPUTS)
+ $(HALIBUT) --info $(INPUTS)
+
+chm: putty.hhp
+putty.hhp: $(INPUTS) chm.but
+ $(HALIBUT) --html $(INPUTS) chm.but
+
+MKMAN = $(HALIBUT) --man=$@ mancfg.but $<
+MANPAGES = putty.1 puttygen.1 plink.1 pscp.1 psftp.1 puttytel.1 pterm.1
+man: $(MANPAGES)
+
+putty.1: man-putt.but mancfg.but; $(MKMAN)
+puttygen.1: man-pg.but mancfg.but; $(MKMAN)
+plink.1: man-pl.but mancfg.but; $(MKMAN)
+pscp.1: man-pscp.but mancfg.but; $(MKMAN)
+psftp.1: man-psft.but mancfg.but; $(MKMAN)
+puttytel.1: man-ptel.but mancfg.but; $(MKMAN)
+pterm.1: man-pter.but mancfg.but; $(MKMAN)
+
+mostlyclean:
+ rm -f *.html *.txt *.hlp *.cnt *.1 *.info vstr.but *.hh[pck]
+clean: mostlyclean
+ rm -f *.chm
diff --git a/puttysrc/DOC/MAN-PG.BUT b/puttysrc/DOC/MAN-PG.BUT
new file mode 100644
index 0000000..6bd6dc9
--- /dev/null
+++ b/puttysrc/DOC/MAN-PG.BUT
@@ -0,0 +1,207 @@
+\cfg{man-identity}{puttygen}{1}{2004-03-24}{PuTTY tool suite}{PuTTY tool suite}
+
+\H{puttygen-manpage} Man page for PuTTYgen
+
+\S{puttygen-manpage-name} NAME
+
+\cw{puttygen} - public-key generator for the PuTTY tools
+
+\S{puttygen-manpage-synopsis} SYNOPSIS
+
+\c puttygen ( keyfile | -t keytype [ -b bits ] )
+\e bbbbbbbb iiiiiii bb iiiiiii bb iiii
+\c [ -C new-comment ] [ -P ] [ -q ]
+\e bb iiiiiiiiiii bb bb
+\c [ -O output-type | -l | -L | -p ]
+\e bb iiiiiiiiiii bb bb bb
+\c [ -o output-file ]
+\e bb iiiiiiiiiii
+
+\S{puttygen-manpage-description} DESCRIPTION
+
+\c{puttygen} is a tool to generate and manipulate SSH public and
+private key pairs. It is part of the PuTTY suite, although it can
+also interoperate with the private key formats used by some other
+SSH clients.
+
+When you run \c{puttygen}, it does three things. Firstly, it either
+loads an existing key file (if you specified \e{keyfile}), or
+generates a new key (if you specified \e{keytype}). Then, it
+optionally makes modifications to the key (changing the comment
+and/or the passphrase); finally, it outputs the key, or some
+information about the key, to a file.
+
+All three of these phases are controlled by the options described in
+the following section.
+
+\S{puttygen-manpage-options} OPTIONS
+
+In the first phase, \c{puttygen} either loads or generates a key.
+The options to control this are:
+
+\dt \e{keyfile}
+
+\dd Specify a private key file to be loaded. This private key file can
+be in the (de facto standard) SSH-1 key format, or in PuTTY's SSH-2
+key format, or in either of the SSH-2 private key formats used by
+OpenSSH and ssh.com's implementation.
+
+\dt \cw{\-t} \e{keytype}
+
+\dd Specify a type of key to generate. The acceptable values here are
+\c{rsa} and \c{dsa} (to generate SSH-2 keys), and \c{rsa1} (to
+generate SSH-1 keys).
+
+\dt \cw{\-b} \e{bits}
+
+\dd Specify the size of the key to generate, in bits. Default is 1024.
+
+\dt \cw{\-q}
+
+\dd Suppress the progress display when generating a new key.
+
+In the second phase, \c{puttygen} optionally alters properties of
+the key it has loaded or generated. The options to control this are:
+
+\dt \cw{\-C} \e{new\-comment}
+
+\dd Specify a comment string to describe the key. This comment string
+will be used by PuTTY to identify the key to you (when asking you to
+enter the passphrase, for example, so that you know which passphrase
+to type).
+
+\dt \cw{\-P}
+
+\dd Indicate that you want to change the key's passphrase. This is
+automatic when you are generating a new key, but not when you are
+modifying an existing key.
+
+In the third phase, \c{puttygen} saves the key or information
+about it. The options to control this are:
+
+\dt \cw{\-O} \e{output\-type}
+
+\dd Specify the type of output you want \c{puttygen} to produce.
+Acceptable options are:
+
+\lcont{
+
+\dt \cw{private}
+
+\dd Save the private key in a format usable by PuTTY. This will either
+be the standard SSH-1 key format, or PuTTY's own SSH-2 key format.
+
+\dt \cw{public}
+
+\dd Save the public key only. For SSH-1 keys, the standard public key
+format will be used (\q{\cw{1024 37 5698745}...}). For SSH-2 keys, the
+public key will be output in the format specified by RFC 4716,
+which is a multi-line text file beginning with the line
+\q{\cw{---- BEGIN SSH2 PUBLIC KEY ----}}.
+
+\dt \cw{public-openssh}
+
+\dd Save the public key only, in a format usable by OpenSSH. For SSH-1
+keys, this output format behaves identically to \c{public}. For
+SSH-2 keys, the public key will be output in the OpenSSH format,
+which is a single line (\q{\cw{ssh-rsa AAAAB3NzaC1yc2}...}).
+
+\dt \cw{fingerprint}
+
+\dd Print the fingerprint of the public key. All fingerprinting
+algorithms are believed compatible with OpenSSH.
+
+\dt \cw{private-openssh}
+
+\dd Save an SSH-2 private key in OpenSSH's format. This option is not
+permitted for SSH-1 keys.
+
+\dt \cw{private-sshcom}
+
+\dd Save an SSH-2 private key in ssh.com's format. This option is not
+permitted for SSH-1 keys.
+
+If no output type is specified, the default is \c{private}.
+
+}
+
+\dt \cw{\-o} \e{output\-file}
+
+\dd Specify the file where \c{puttygen} should write its output. If
+this option is not specified, \c{puttygen} will assume you want to
+overwrite the original file if the input and output file types are
+the same (changing a comment or passphrase), and will assume you
+want to output to stdout if you are asking for a public key or
+fingerprint. Otherwise, the \c{\-o} option is required.
+
+\dt \cw{\-l}
+
+\dd Synonym for \q{\cw{-O fingerprint}}.
+
+\dt \cw{\-L}
+
+\dd Synonym for \q{\cw{-O public-openssh}}.
+
+\dt \cw{\-p}
+
+\dd Synonym for \q{\cw{-O public}}.
+
+The following options do not run PuTTYgen as normal, but print
+informational messages and then quit:
+
+\dt \cw{\-h}, \cw{\-\-help}
+
+\dd Display a message summarizing the available options.
+
+\dt \cw{\-V}, \cw{\-\-version}
+
+\dd Display the version of PuTTYgen.
+
+\dt \cw{\-\-pgpfp}
+
+\dd Display the fingerprints of the PuTTY PGP Master Keys, to aid
+in verifying new files released by the PuTTY team.
+
+\S{puttygen-manpage-examples} EXAMPLES
+
+To generate an SSH-2 RSA key pair and save it in PuTTY's own format
+(you will be prompted for the passphrase):
+
+\c puttygen -t rsa -C "my home key" -o mykey.ppk
+
+To generate a larger (2048-bit) key:
+
+\c puttygen -t rsa -b 2048 -C "my home key" -o mykey.ppk
+
+To change the passphrase on a key (you will be prompted for the old
+and new passphrases):
+
+\c puttygen -P mykey.ppk
+
+To change the comment on a key:
+
+\c puttygen -C "new comment" mykey.ppk
+
+To convert a key into OpenSSH's private key format:
+
+\c puttygen mykey.ppk -O private-openssh -o my-openssh-key
+
+To convert a key \e{from} another format (\c{puttygen} will
+automatically detect the input key type):
+
+\c puttygen my-ssh.com-key -o mykey.ppk
+
+To display the fingerprint of a key (some key types require a
+passphrase to extract even this much information):
+
+\c puttygen -l mykey.ppk
+
+To add the OpenSSH-format public half of a key to your authorised
+keys file:
+
+\c puttygen -L mykey.ppk >> $HOME/.ssh/authorized_keys
+
+\S{puttygen-manpage-bugs} BUGS
+
+There's currently no way to supply passphrases in batch mode, or
+even just to specify that you don't want a passphrase at all.
diff --git a/puttysrc/DOC/MAN-PL.BUT b/puttysrc/DOC/MAN-PL.BUT
new file mode 100644
index 0000000..bd255b1
--- /dev/null
+++ b/puttysrc/DOC/MAN-PL.BUT
@@ -0,0 +1,158 @@
+\cfg{man-identity}{plink}{1}{2004-03-24}{PuTTY tool suite}{PuTTY tool suite}
+
+\H{plink-manpage} Man page for Plink
+
+\S{plink-manpage-name} NAME
+
+\cw{plink} \- PuTTY link, command line network connection tool
+
+\S{plink-manpage-synopsis} SYNOPSIS
+
+\c plink [options] [user@]host [command]
+\e bbbbb iiiiiii iiiib iiii iiiiiii
+
+\S{plink-manpage-description} DESCRIPTION
+
+\cw{plink} is a network connection tool supporting several protocols.
+
+\S{plink-manpage-options} OPTIONS
+
+The command-line options supported by \cw{plink} are:
+
+\dt \cw{-V}
+
+\dd Show version information and exit.
+
+\dt \cw{-pgpfp}
+
+\dd Display the fingerprints of the PuTTY PGP Master Keys and exit,
+to aid in verifying new files released by the PuTTY team.
+
+\dt \cw{-v}
+
+\dd Show verbose messages.
+
+\dt \cw{-load} \e{session}
+
+\dd Load settings from saved session.
+
+\dt \cw{-ssh}
+
+\dd Force use of SSH protocol (default).
+
+\dt \cw{-telnet}
+
+\dd Force use of Telnet protocol.
+
+\dt \cw{-rlogin}
+
+\dd Force use of rlogin protocol.
+
+\dt \cw{-raw}
+
+\dd Force raw mode.
+
+\dt \cw{-P} \e{port}
+
+\dd Connect to port \e{port}.
+
+\dt \cw{-l} \e{user}
+
+\dd Set remote username to \e{user}.
+
+\dt \cw{-m} \e{path}
+
+\dd Read remote command(s) from local file \e{path}.
+
+\dt \cw{-batch}
+
+\dd Disable interactive prompts.
+
+\dt \cw{-pw} \e{password}
+
+\dd Set remote password to \e{password}. \e{CAUTION:} this will likely
+make the password visible to other users of the local machine (via
+commands such as \q{\c{w}}).
+
+\dt \cw{\-L} \cw{[}\e{srcaddr}\cw{:]}\e{srcport}\cw{:}\e{desthost}\cw{:}\e{destport}
+
+\dd Set up a local port forwarding: listen on \e{srcport} (or
+\e{srcaddr}:\e{srcport} if specified), and forward any connections
+over the SSH connection to the destination address
+\e{desthost}:\e{destport}. Only works in SSH.
+
+\dt \cw{\-R} \cw{[}\e{srcaddr}\cw{:]}\e{srcport}\cw{:}\e{desthost}\cw{:}\e{destport}
+
+\dd Set up a remote port forwarding: ask the SSH server to listen on
+\e{srcport} (or \e{srcaddr}:\e{srcport} if specified), and to
+forward any connections back over the SSH connection where the
+client will pass them on to the destination address
+\e{desthost}:\e{destport}. Only works in SSH.
+
+\dt \cw{\-D} [\e{srcaddr}:]\e{srcport}
+
+\dd Set up dynamic port forwarding. The client listens on
+\e{srcport} (or \e{srcaddr}:\e{srcport} if specified), and
+implements a SOCKS server. So you can point SOCKS-aware applications
+at this port and they will automatically use the SSH connection to
+tunnel all their connections. Only works in SSH.
+
+\dt \cw{-X}
+
+\dd Enable X11 forwarding.
+
+\dt \cw{-x}
+
+\dd Disable X11 forwarding (default).
+
+\dt \cw{-A}
+
+\dd Enable agent forwarding.
+
+\dt \cw{-a}
+
+\dd Disable agent forwarding (default).
+
+\dt \cw{-t}
+
+\dd Enable pty allocation (default if a command is NOT specified).
+
+\dt \cw{-T}
+
+\dd Disable pty allocation (default if a command is specified).
+
+\dt \cw{-1}
+
+\dd Force use of SSH protocol version 1.
+
+\dt \cw{-2}
+
+\dd Force use of SSH protocol version 2.
+
+\dt \cw{-C}
+
+\dd Enable SSH compression.
+
+\dt \cw{-i} \e{path}
+
+\dd Private key file for authentication.
+
+\dt \cw{-s}
+
+\dd Remote command is SSH subsystem (SSH-2 only).
+
+\dt \cw{-N}
+
+\dd Don't start a remote command or shell at all (SSH-2 only).
+
+\S{plink-manpage-more-information} MORE INFORMATION
+
+For more information on plink, it's probably best to go and look at
+the manual on the PuTTY web page:
+
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/}
+
+\S{plink-manpage-bugs} BUGS
+
+This man page isn't terribly complete. See the above web link for
+better documentation.
diff --git a/puttysrc/DOC/MAN-PSCP.BUT b/puttysrc/DOC/MAN-PSCP.BUT
new file mode 100644
index 0000000..c56db97
--- /dev/null
+++ b/puttysrc/DOC/MAN-PSCP.BUT
@@ -0,0 +1,116 @@
+\cfg{man-identity}{pscp}{1}{2004-03-24}{PuTTY tool suite}{PuTTY tool suite}
+
+\H{pscp-manpage} Man page for PSCP
+
+\S{pscp-manpage-name} NAME
+
+\cw{pscp} \- command-line SCP (secure copy) / SFTP client
+
+\S{pscp-manpage-synopsis} SYNOPSIS
+
+\c pscp [options] [user@]host:source target
+\e bbbb iiiiiii iiiib iiiibiiiiii iiiiii
+\c pscp [options] source [source...] [user@]host:target
+\e bbbb iiiiiii iiiiii iiiiii iiiib iiiibiiiiii
+\c pscp [options] -ls [user@]host:filespec
+\e bbbb iiiiiii bbb iiiib iiiibiiiiiiii
+
+\S{pscp-manpage-description} DESCRIPTION
+
+\cw{pscp} is a command-line client for the SSH-based SCP (secure
+copy) and SFTP (secure file transfer protocol) protocols.
+
+\S{pscp-manpage-options} OPTIONS
+
+The command-line options supported by \e{pscp} are:
+
+\dt \cw{-V}
+
+\dd Show version information and exit.
+
+\dt \cw{-pgpfp}
+
+\dd Display the fingerprints of the PuTTY PGP Master Keys and exit,
+to aid in verifying new files released by the PuTTY team.
+
+\dt \cw{-ls}
+
+\dd Remote directory listing.
+
+\dt \cw{-p}
+
+\dd Preserve file attributes.
+
+\dt \cw{-q}
+
+\dd Quiet, don't show statistics.
+
+\dt \cw{-r}
+
+\dd Copy directories recursively.
+
+\dt \cw{-unsafe}
+
+\dd Allow server-side wildcards (DANGEROUS).
+
+\dt \cw{-v}
+
+\dd Show verbose messages.
+
+\dt \cw{-load} \e{session}
+
+\dd Load settings from saved session.
+
+\dt \cw{-P} \e{port}
+
+\dd Connect to port \e{port}.
+
+\dt \cw{-l} \e{user}
+
+\dd Set remote username to \e{user}.
+
+\dt \cw{-batch}
+
+\dd Disable interactive prompts.
+
+\dt \cw{-pw} \e{password}
+
+\dd Set remote password to \e{password}. \e{CAUTION:} this will likely
+make the password visible to other users of the local machine (via
+commands such as \q{\c{w}}).
+
+\dt \cw{-1}
+
+\dd Force use of SSH protocol version 1.
+
+\dt \cw{-2}
+
+\dd Force use of SSH protocol version 2.
+
+\dt \cw{-C}
+
+\dd Enable SSH compression.
+
+\dt \cw{-i} \e{path}
+
+\dd Private key file for authentication.
+
+\dt \cw{-scp}
+
+\dd Force use of SCP protocol.
+
+\dt \cw{-sftp}
+
+\dd Force use of SFTP protocol.
+
+\S{pscp-manpage-more-information} MORE INFORMATION
+
+For more information on \cw{pscp} it's probably best to go and look at
+the manual on the PuTTY web page:
+
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/}
+
+\S{pscp-manpage-bugs} BUGS
+
+This man page isn't terribly complete. See the above web link for
+better documentation.
diff --git a/puttysrc/DOC/MAN-PSFT.BUT b/puttysrc/DOC/MAN-PSFT.BUT
new file mode 100644
index 0000000..adaf640
--- /dev/null
+++ b/puttysrc/DOC/MAN-PSFT.BUT
@@ -0,0 +1,101 @@
+\cfg{man-identity}{psftp}{1}{2004-03-24}{PuTTY tool suite}{PuTTY tool suite}
+
+\H{psftp-manpage} Man page for PSFTP
+
+\S{psftp-manpage-name} NAME
+
+\cw{psftp} \- interactive SFTP (secure file transfer protocol) client
+
+\S{psftp-manpage-synopsis} SYNOPSIS
+
+\c psftp [options] [user@]host
+\e bbbbb iiiiiii iiiib iiii
+
+\S{psftp-manpage-description} DESCRIPTION
+
+\cw{psftp} is an interactive text-based client for the SSH-based SFTP
+(secure file transfer) protocol.
+
+\S{psftp-manpage-options} OPTIONS
+
+The command-line options supported by \cw{psftp} are:
+
+\dt \cw{-V}
+
+\dd Show version information and exit.
+
+\dt \cw{-pgpfp}
+
+\dd Display the fingerprints of the PuTTY PGP Master Keys and exit,
+to aid in verifying new files released by the PuTTY team.
+
+\dt \cw{-b} \e{batchfile}
+
+\dd Use specified batchfile.
+
+\dt \cw{-bc}
+
+\dd Output batchfile commands.
+
+\dt \cw{-be}
+
+\dd Don't stop batchfile processing on errors.
+
+\dt \cw{-v}
+
+\dd Show verbose messages.
+
+\dt \cw{-load} \e{session}
+
+\dd Load settings from saved session.
+
+\dt \cw{-P} \e{port}
+
+\dd Connect to port \e{port}.
+
+\dt \cw{-l} \e{user}
+
+\dd Set remote username to \e{user}.
+
+\dt \cw{-batch}
+
+\dd Disable interactive prompts.
+
+\dt \cw{-pw} \e{password}
+
+\dd Set remote password to \e{password}. \e{CAUTION:} this will likely
+make the password visible to other users of the local machine (via
+commands such as \q{\c{w}}).
+
+\dt \cw{-1}
+
+\dd Force use of SSH protocol version 1.
+
+\dt \cw{-2}
+
+\dd Force use of SSH protocol version 2.
+
+\dt \cw{-C}
+
+\dd Enable SSH compression.
+
+\dt \cw{-i} \e{path}
+
+\dd Private key file for authentication.
+
+\S{psftp-manpage-commands} COMMANDS
+
+For a list of commands available inside \cw{psftp}, type \cw{help}
+at the \cw{psftp>} prompt.
+
+\S{psftp-manpage-more-information} MORE INFORMATION
+
+For more information on \cw{psftp} it's probably best to go and look at
+the manual on the PuTTY web page:
+
+\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/}
+
+\S{psftp-manpage-bugs} BUGS
+
+This man page isn't terribly complete. See the above web link for
+better documentation.
diff --git a/puttysrc/DOC/MAN-PTEL.BUT b/puttysrc/DOC/MAN-PTEL.BUT
new file mode 100644
index 0000000..1bdd334
--- /dev/null
+++ b/puttysrc/DOC/MAN-PTEL.BUT
@@ -0,0 +1,189 @@
+\cfg{man-identity}{puttytel}{1}{2004-03-24}{PuTTY tool suite}{PuTTY tool suite}
+
+\H{puttytel-manpage} Man page for PuTTYtel
+
+\S{puttytel-manpage-name} NAME
+
+\cw{puttytel} \- GUI Telnet and Rlogin client for X
+
+\S{puttytel-manpage-synopsis} SYNOPSIS
+
+\c puttytel [ options ] [ host ]
+\e bbbbbbbb iiiiiii iiii
+
+\S{puttytel-manpage-description} DESCRIPTION
+
+\cw{puttytel} is a graphical Telnet and Rlogin client for X. It
+is a direct port of the Windows Telnet and Rlogin client of the same
+name, and a cut-down cryptography-free version of PuTTY.
+
+\S{puttytel-manpage-options} OPTIONS
+
+The command-line options supported by \cw{puttytel} are:
+
+\dt \cw{\-\-display} \e{display\-name}
+
+\dd Specify the X display on which to open \cw{puttytel}. (Note this
+option has a double minus sign, even though none of the others do.
+This is because this option is supplied automatically by GTK.
+Sorry.)
+
+\dt \cw{\-fn} \e{font-name}
+
+\dd Specify the font to use for normal text displayed in the terminal.
+
+\dt \cw{\-fb} \e{font-name}
+
+\dd Specify the font to use for bold text displayed in the terminal. If
+the \cw{BoldAsColour} resource is set to 1 (the default), bold text
+will be displayed in different colours instead of a different font,
+so this option will be ignored. If \cw{BoldAsColour} is set to 0
+and you do not specify a bold font, \cw{puttytel} will overprint the
+normal font to make it look bolder.
+
+\dt \cw{\-fw} \e{font-name}
+
+\dd Specify the font to use for double-width characters (typically
+Chinese, Japanese and Korean text) displayed in the terminal.
+
+\dt \cw{\-fwb} \e{font-name}
+
+\dd Specify the font to use for bold double-width characters
+(typically Chinese, Japanese and Korean text). Like \cw{-fb}, this
+will be ignored unless the \cw{BoldAsColour} resource is set to 0.
+
+\dt \cw{\-geometry} \e{geometry}
+
+\dd Specify the size of the terminal, in rows and columns of text. See
+\e{X(7)} for more information on the syntax of geometry
+specifications.
+
+\dt \cw{\-sl} \e{lines}
+
+\dd Specify the number of lines of scrollback to save off the top of the
+terminal.
+
+\dt \cw{\-fg} \e{colour}
+
+\dd Specify the foreground colour to use for normal text.
+
+\dt \cw{\-bg} \e{colour}
+
+\dd Specify the background colour to use for normal text.
+
+\dt \cw{\-bfg} \e{colour}
+
+\dd Specify the foreground colour to use for bold text, if the
+\cw{BoldAsColour} resource is set to 1 (the default).
+
+\dt \cw{\-bbg} \e{colour}
+
+\dd Specify the foreground colour to use for bold reverse-video text, if
+the \cw{BoldAsColour} resource is set to 1 (the default). (This
+colour is best thought of as the bold version of the background
+colour; so it only appears when text is displayed \e{in} the
+background colour.)
+
+\dt \cw{\-cfg} \e{colour}
+
+\dd Specify the foreground colour to use for text covered by the cursor.
+
+\dt \cw{\-cbg} \e{colour}
+
+\dd Specify the background colour to use for text covered by the cursor.
+In other words, this is the main colour of the cursor.
+
+\dt \cw{\-title} \e{title}
+
+\dd Specify the initial title of the terminal window. (This can be
+changed under control of the server.)
+
+\dt \cw{\-sb\-} or \cw{+sb}
+
+\dd Tells \cw{puttytel} not to display a scroll bar.
+
+\dt \cw{\-sb}
+
+\dd Tells \cw{puttytel} to display a scroll bar: this is the opposite of
+\cw{\-sb\-}. This is the default option: you will probably only need
+to specify it explicitly if you have changed the default using the
+\cw{ScrollBar} resource.
+
+\dt \cw{\-log} \e{filename}
+
+\dd This option makes \cw{puttytel} log all the terminal output to a file
+as well as displaying it in the terminal.
+
+\dt \cw{\-cs} \e{charset}
+
+\dd This option specifies the character set in which \cw{puttytel}
+should assume the session is operating. This character set will be
+used to interpret all the data received from the session, and all
+input you type or paste into \cw{puttytel} will be converted into
+this character set before being sent to the session.
+
+\lcont{ Any character set name which is valid in a MIME header (and
+supported by \cw{puttytel}) should be valid here (examples are
+\q{\cw{ISO-8859-1}}, \q{\cw{windows-1252}} or \q{\cw{UTF-8}}). Also,
+any character encoding which is valid in an X logical font
+description should be valid (\q{\cw{ibm-cp437}}, for example).
+
+\cw{puttytel}'s default behaviour is to use the same character
+encoding as its primary font. If you supply a Unicode
+(\cw{iso10646-1}) font, it will default to the UTF-8 character set.
+
+Character set names are case-insensitive.
+}
+
+\dt \cw{\-nethack}
+
+\dd Tells \cw{puttytel} to enable NetHack keypad mode, in which the
+numeric keypad generates the NetHack \c{hjklyubn} direction keys.
+This enables you to play NetHack with the numeric keypad without
+having to use the NetHack \c{number_pad} option (which requires you
+to press \q{\cw{n}} before any repeat count). So you can move with
+the numeric keypad, and enter repeat counts with the normal number
+keys.
+
+\dt \cw{\-help}, \cw{\-\-help}
+
+\dd Display a message summarizing the available options.
+
+\dt \cw{\-pgpfp}
+
+\dd Display the fingerprints of the PuTTY PGP Master Keys, to aid
+in verifying new files released by the PuTTY team.
+
+\dt \cw{\-load} \e{session}
+
+\dd Load a saved session by name. This allows you to run a saved session
+straight from the command line without having to go through the
+configuration box first.
+
+\dt \cw{\-telnet}, \cw{\-rlogin}, \cw{\-raw}
+
+\dd Select the protocol \cw{puttytel} will use to make the connection.
+
+\dt \cw{\-l} \e{username}
+
+\dd Specify the username to use when logging in to the server.
+
+\dt \cw{\-P} \e{port}
+
+\dd Specify the port to connect to the server on.
+
+\S{puttytel-manpage-saved-sessions} SAVED SESSIONS
+
+Saved sessions are stored in a \cw{.putty/sessions} subdirectory in
+your home directory.
+
+\S{puttytel-manpage-more-information} MORE INFORMATION
+
+For more information on PuTTY and PuTTYtel, it's probably best to go
+and look at the manual on the web page:
+
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/}
+
+\S{puttytel-manpage-bugs} BUGS
+
+This man page isn't terribly complete.
diff --git a/puttysrc/DOC/MAN-PTER.BUT b/puttysrc/DOC/MAN-PTER.BUT
new file mode 100644
index 0000000..ef6653a
--- /dev/null
+++ b/puttysrc/DOC/MAN-PTER.BUT
@@ -0,0 +1,676 @@
+\cfg{man-identity}{pterm}{1}{2004-03-24}{PuTTY tool suite}{PuTTY tool suite}
+
+\H{pterm-manpage} Man page for pterm
+
+\S{pterm-manpage-name} NAME
+
+pterm \- yet another X terminal emulator
+
+\S{pterm-manpage-synopsis} SYNOPSIS
+
+\c pterm [ options ]
+\e bbbbb iiiiiii
+
+\S{pterm-manpage-description} DESCRIPTION
+
+\cw{pterm} is a terminal emulator for X. It is based on a port of
+the terminal emulation engine in the Windows SSH client PuTTY.
+
+\S{pterm-manpage-options} OPTIONS
+
+The command-line options supported by \cw{pterm} are:
+
+\dt \cw{\-e} \e{command} [ \e{arguments} ]
+
+\dd Specify a command to be executed in the new terminal. Everything on
+the command line after this option will be passed straight to the
+\cw{execvp} system call; so if you need the command to redirect its
+input or output, you will have to use \cw{sh}:
+
+\lcont{
+
+\c pterm -e sh -c 'mycommand < inputfile'
+
+}
+
+\dt \cw{\-\-display} \e{display\-name}
+
+\dd Specify the X display on which to open \cw{pterm}. (Note this
+option has a double minus sign, even though none of the others do.
+This is because this option is supplied automatically by GTK.
+Sorry.)
+
+\dt \cw{\-name} \e{font-name}
+
+\dd Specify the name under which \cw{pterm} looks up X resources.
+Normally it will look them up as (for example) \cw{pterm.Font}. If
+you specify \q{\cw{\-name xyz}}, it will look them up as
+\cw{xyz.Font} instead. This allows you to set up several different
+sets of defaults and choose between them.
+
+\dt \cw{\-fn} \e{font-name}
+
+\dd Specify the font to use for normal text displayed in the terminal.
+
+\dt \cw{\-fb} \e{font-name}
+
+\dd Specify the font to use for bold text displayed in the terminal. If
+the \cw{BoldAsColour} resource is set to 1 (the default), bold text
+will be displayed in different colours instead of a different font,
+so this option will be ignored. If \cw{BoldAsColour} is set to 0
+and you do not specify a bold font, \cw{pterm} will overprint the
+normal font to make it look bolder.
+
+\dt \cw{\-fw} \e{font-name}
+
+\dd Specify the font to use for double-width characters (typically
+Chinese, Japanese and Korean text) displayed in the terminal.
+
+\dt \cw{\-fwb} \e{font-name}
+
+\dd Specify the font to use for bold double-width characters
+(typically Chinese, Japanese and Korean text). Like \cw{-fb}, this
+will be ignored unless the \cw{BoldAsColour} resource is set to 0.
+
+\dt \cw{\-geometry} \e{geometry}
+
+\dd Specify the size of the terminal, in rows and columns of text. See
+\e{X(7)} for more information on the syntax of geometry
+specifications.
+
+\dt \cw{\-sl} \e{lines}
+
+\dd Specify the number of lines of scrollback to save off the top of the
+terminal.
+
+\dt \cw{\-fg} \e{colour}
+
+\dd Specify the foreground colour to use for normal text.
+
+\dt \cw{\-bg} \e{colour}
+
+\dd Specify the background colour to use for normal text.
+
+\dt \cw{\-bfg} \e{colour}
+
+\dd Specify the foreground colour to use for bold text, if the
+\cw{BoldAsColour} resource is set to 1 (the default).
+
+\dt \cw{\-bbg} \e{colour}
+
+\dd Specify the foreground colour to use for bold reverse-video text, if
+the \cw{BoldAsColour} resource is set to 1 (the default). (This
+colour is best thought of as the bold version of the background
+colour; so it only appears when text is displayed \e{in} the
+background colour.)
+
+\dt \cw{\-cfg} \e{colour}
+
+\dd Specify the foreground colour to use for text covered by the cursor.
+
+\dt \cw{\-cbg} \e{colour}
+
+\dd Specify the background colour to use for text covered by the cursor.
+In other words, this is the main colour of the cursor.
+
+\dt \cw{\-title} \e{title}
+
+\dd Specify the initial title of the terminal window. (This can be
+changed under control of the server.)
+
+\dt \cw{\-ut\-} or \cw{+ut}
+
+\dd Tells \cw{pterm} not to record your login in the \cw{utmp},
+\cw{wtmp} and \cw{lastlog} system log files; so you will not show
+up on \cw{finger} or \cw{who} listings, for example.
+
+\dt \cw{\-ut}
+
+\dd Tells \cw{pterm} to record your login in \cw{utmp}, \cw{wtmp} and
+\cw{lastlog}: this is the opposite of \cw{\-ut\-}. This is the
+default option: you will probably only need to specify it explicitly
+if you have changed the default using the \cw{StampUtmp} resource.
+
+\dt \cw{\-ls\-} or \cw{+ls}
+
+\dd Tells \cw{pterm} not to execute your shell as a login shell.
+
+\dt \cw{\-ls}
+
+\dd Tells \cw{pterm} to execute your shell as a login shell: this is
+the opposite of \cw{\-ls\-}. This is the default option: you will
+probably only need to specify it explicitly if you have changed the
+default using the \cw{LoginShell} resource.
+
+\dt \cw{\-sb\-} or \cw{+sb}
+
+\dd Tells \cw{pterm} not to display a scroll bar.
+
+\dt \cw{\-sb}
+
+\dd Tells \cw{pterm} to display a scroll bar: this is the opposite of
+\cw{\-sb\-}. This is the default option: you will probably only need
+to specify it explicitly if you have changed the default using the
+\cw{ScrollBar} resource.
+
+\dt \cw{\-log} \e{filename}
+
+\dd This option makes \cw{pterm} log all the terminal output to a file
+as well as displaying it in the terminal.
+
+\dt \cw{\-cs} \e{charset}
+
+\dd This option specifies the character set in which \cw{pterm} should
+assume the session is operating. This character set will be used to
+interpret all the data received from the session, and all input you
+type or paste into \cw{pterm} will be converted into this character
+set before being sent to the session.
+
+\lcont{ Any character set name which is valid in a MIME header (and
+supported by \cw{pterm}) should be valid here (examples are
+\q{\cw{ISO-8859-1}}, \q{\cw{windows-1252}} or \q{\cw{UTF-8}}). Also,
+any character encoding which is valid in an X logical font
+description should be valid (\q{\cw{ibm-cp437}}, for example).
+
+\cw{pterm}'s default behaviour is to use the same character encoding
+as its primary font. If you supply a Unicode (\cw{iso10646-1}) font,
+it will default to the UTF-8 character set.
+
+Character set names are case-insensitive.
+}
+
+\dt \cw{\-nethack}
+
+\dd Tells \cw{pterm} to enable NetHack keypad mode, in which the
+numeric keypad generates the NetHack \c{hjklyubn} direction keys.
+This enables you to play NetHack with the numeric keypad without
+having to use the NetHack \c{number_pad} option (which requires you
+to press \q{\cw{n}} before any repeat count). So you can move with
+the numeric keypad, and enter repeat counts with the normal number
+keys.
+
+\dt \cw{\-xrm} \e{resource-string}
+
+\dd This option specifies an X resource string. Useful for setting
+resources which do not have their own command-line options. For
+example:
+
+\lcont{
+
+\c pterm -xrm 'ScrollbarOnLeft: 1'
+
+}
+
+\dt \cw{\-help}, \cw{\-\-help}
+
+\dd Display a message summarizing the available options.
+
+\dt \cw{\-pgpfp}
+
+\dd Display the fingerprints of the PuTTY PGP Master Keys, to aid
+in verifying new files released by the PuTTY team.
+
+\S{pterm-manpage-x-resources} X RESOURCES
+
+\cw{pterm} can be more completely configured by means of X
+resources. All of these resources are of the form \cw{pterm.FOO} for
+some \cw{FOO}; you can make \cw{pterm} look them up under another
+name, such as \cw{xyz.FOO}, by specifying the command-line option
+\q{\cw{\-name xyz}}.
+
+\dt \cw{pterm.CloseOnExit}
+
+\dd This option should be set to 0, 1 or 2; the default is 2. It
+controls what \cw{pterm} does when the process running inside it
+terminates. When set to 2 (the default), \cw{pterm} will close its
+window as soon as the process inside it terminates. When set to 0,
+\cw{pterm} will print the process's exit status, and the window
+will remain present until a key is pressed (allowing you to inspect
+the scrollback, and copy and paste text out of it).
+
+\lcont{
+
+When this setting is set to 1, \cw{pterm} will close
+immediately if the process exits cleanly (with an exit status of
+zero), but the window will stay around if the process exits with a
+non-zero code or on a signal. This enables you to see what went
+wrong if the process suffers an error, but not to have to bother
+closing the window in normal circumstances.
+
+}
+
+\dt \cw{pterm.WarnOnClose}
+
+\dd This option should be set to either 0 or 1; the default is 1.
+When set to 1, \cw{pterm} will ask for confirmation before closing
+its window when you press the close button.
+
+\dt \cw{pterm.TerminalType}
+
+\dd This controls the value set in the \cw{TERM} environment
+variable inside the new terminal. The default is \q{\cw{xterm}}.
+
+\dt \cw{pterm.BackspaceIsDelete}
+
+\dd This option should be set to either 0 or 1; the default is 1.
+When set to 0, the ordinary Backspace key generates the Backspace
+character (\cw{^H}); when set to 1, it generates the Delete
+character (\cw{^?}). Whichever one you set, the terminal device
+inside \cw{pterm} will be set up to expect it.
+
+\dt \cw{pterm.RXVTHomeEnd}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+it is set to 1, the Home and End keys generate the control sequences
+they would generate in the \cw{rxvt} terminal emulator, instead of
+the more usual ones generated by other emulators.
+
+\dt \cw{pterm.LinuxFunctionKeys}
+
+\dd This option can be set to any number between 0 and 5 inclusive;
+the default is 0. The modes vary the control sequences sent by the
+function keys; for more complete documentation, it is probably
+simplest to try each option in \q{\cw{pterm \-e cat}}, and press the
+keys to see what they generate.
+
+\dt \cw{pterm.NoApplicationKeys}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, it stops the server from ever switching the numeric keypad
+into application mode (where the keys send function-key-like
+sequences instead of numbers or arrow keys). You probably only need
+this if some application is making a nuisance of itself.
+
+\dt \cw{pterm.NoApplicationCursors}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, it stops the server from ever switching the cursor keys
+into application mode (where the keys send slightly different
+sequences). You probably only need this if some application is
+making a nuisance of itself.
+
+\dt \cw{pterm.NoMouseReporting}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, it stops the server from ever enabling mouse reporting
+mode (where mouse clicks are sent to the application instead of
+controlling cut and paste).
+
+\dt \cw{pterm.NoRemoteResize}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, it stops the server from being able to remotely control
+the size of the \cw{pterm} window.
+
+\dt \cw{pterm.NoAltScreen}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, it stops the server from using the \q{alternate screen}
+terminal feature, which lets full-screen applications leave the
+screen exactly the way they found it.
+
+\dt \cw{pterm.NoRemoteWinTitle}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, it stops the server from remotely controlling the title of
+the \cw{pterm} window.
+
+\dt \cw{pterm.NoRemoteQTitle}
+
+\dd This option should be set to either 0 or 1; the default is 1. When
+set to 1, it stops the server from remotely requesting the title of
+the \cw{pterm} window.
+
+\lcont{
+This feature is a \e{POTENTIAL SECURITY HAZARD}. If a malicious
+application can write data to your terminal (for example, if you
+merely \cw{cat} a file owned by someone else on the server
+machine), it can change your window title (unless you have disabled
+this using the \cw{NoRemoteWinTitle} resource) and then use this
+service to have the new window title sent back to the server as if
+typed at the keyboard. This allows an attacker to fake keypresses
+and potentially cause your server-side applications to do things you
+didn't want. Therefore this feature is disabled by default, and we
+recommend you do not turn it on unless you \e{really} know what
+you are doing.
+}
+
+\dt \cw{pterm.NoDBackspace}
+
+\dd This option should be set to either 0 or 1; the default is 0.
+When set to 1, it disables the normal action of the Delete (\cw{^?})
+character when sent from the server to the terminal, which is to
+move the cursor left by one space and erase the character now under
+it.
+
+\dt \cw{pterm.ApplicationCursorKeys}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, the default initial state of the cursor keys are
+application mode (where the keys send function-key-like sequences
+instead of numbers or arrow keys). When set to 0, the default state
+is the normal one.
+
+\dt \cw{pterm.ApplicationKeypad}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, the default initial state of the numeric keypad is
+application mode (where the keys send function-key-like sequences
+instead of numbers or arrow keys). When set to 0, the default state
+is the normal one.
+
+\dt \cw{pterm.NetHackKeypad}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, the numeric keypad operates in NetHack mode. This is
+equivalent to the \cw{\-nethack} command-line option.
+
+\dt \cw{pterm.Answerback}
+
+\dd This option controls the string which the terminal sends in
+response to receiving the \cw{^E} character (\q{tell me about
+yourself}). By default this string is \q{\cw{PuTTY}}.
+
+\dt \cw{pterm.HideMousePtr}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+it is set to 1, the mouse pointer will disappear if it is over the
+\cw{pterm} window and you press a key. It will reappear as soon as
+you move it.
+
+\dt \cw{pterm.WindowBorder}
+
+\dd This option controls the number of pixels of space between the text
+in the \cw{pterm} window and the window frame. The default is 1.
+You can increase this value, but decreasing it to 0 is not
+recommended because it can cause the window manager's size hints to
+work incorrectly.
+
+\dt \cw{pterm.CurType}
+
+\dd This option should be set to either 0, 1 or 2; the default is 0.
+When set to 0, the text cursor displayed in the window is a
+rectangular block. When set to 1, the cursor is an underline; when
+set to 2, it is a vertical line.
+
+\dt \cw{pterm.BlinkCur}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+it is set to 1, the text cursor will blink when the window is active.
+
+\dt \cw{pterm.Beep}
+
+\dd This option should be set to either 0 or 2 (yes, 2); the default
+is 0. When it is set to 2, \cw{pterm} will respond to a bell
+character (\cw{^G}) by flashing the window instead of beeping.
+
+\dt \cw{pterm.BellOverload}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+it is set to 1, \cw{pterm} will watch out for large numbers of
+bells arriving in a short time and will temporarily disable the bell
+until they stop. The idea is that if you \cw{cat} a binary file,
+the frantic beeping will mostly be silenced by this feature and will
+not drive you crazy.
+
+\lcont{
+The bell overload mode is activated by receiving N bells in time T;
+after a further time S without any bells, overload mode will turn
+itself off again.
+
+Bell overload mode is always deactivated by any keypress in the
+terminal. This means it can respond to large unexpected streams of
+data, but does not interfere with ordinary command-line activities
+that generate beeps (such as filename completion).
+}
+
+\dt \cw{pterm.BellOverloadN}
+
+\dd This option counts the number of bell characters which will activate
+bell overload if they are received within a length of time T. The
+default is 5.
+
+\dt \cw{pterm.BellOverloadT}
+
+\dd This option specifies the time period in which receiving N or more
+bells will activate bell overload mode. It is measured in
+microseconds, so (for example) set it to 1000000 for one second. The
+default is 2000000 (two seconds).
+
+\dt \cw{pterm.BellOverloadS}
+
+\dd This option specifies the time period of silence required to turn
+off bell overload mode. It is measured in microseconds, so (for
+example) set it to 1000000 for one second. The default is 5000000
+(five seconds of silence).
+
+\dt \cw{pterm.ScrollbackLines}
+
+\dd This option specifies how many lines of scrollback to save above the
+visible terminal screen. The default is 200. This resource is
+equivalent to the \cw{\-sl} command-line option.
+
+\dt \cw{pterm.DECOriginMode}
+
+\dd This option should be set to either 0 or 1; the default is 0. It
+specifies the default state of DEC Origin Mode. (If you don't know
+what that means, you probably don't need to mess with it.)
+
+\dt \cw{pterm.AutoWrapMode}
+
+\dd This option should be set to either 0 or 1; the default is 1. It
+specifies the default state of auto wrap mode. When set to 1, very
+long lines will wrap over to the next line on the terminal; when set
+to 0, long lines will be squashed against the right-hand edge of the
+screen.
+
+\dt \cw{pterm.LFImpliesCR}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, the terminal will return the cursor to the left side of
+the screen when it receives a line feed character.
+
+\dt \cw{pterm.WinTitle}
+
+\dd This resource is the same as the \cw{\-T} command-line option:
+it controls the initial title of the window. The default is
+\q{\cw{pterm}}.
+
+\dt \cw{pterm.TermWidth}
+
+\dd This resource is the same as the width part of the \cw{\-geometry}
+command-line option: it controls the number of columns of text in
+the window. The default is 80.
+
+\dt \cw{pterm.TermHeight}
+
+\dd This resource is the same as the width part of the \cw{\-geometry}
+command-line option: it controls the number of columns of text in
+the window. The defaults is 24.
+
+\dt \cw{pterm.Font}
+
+\dd This resource is the same as the \cw{\-fn} command-line option: it
+controls the font used to display normal text. The default is
+\q{\cw{fixed}}.
+
+\dt \cw{pterm.BoldFont}
+
+\dd This resource is the same as the \cw{\-fb} command-line option: it
+controls the font used to display bold text when \cw{BoldAsColour}
+is turned off. The default is unset (the font will be bolded by
+printing it twice at a one-pixel offset).
+
+\dt \cw{pterm.WideFont}
+
+\dd This resource is the same as the \cw{\-fw} command-line option: it
+controls the font used to display double-width characters. The
+default is unset (double-width characters cannot be displayed).
+
+\dt \cw{pterm.WideBoldFont}
+
+\dd This resource is the same as the \cw{\-fwb} command-line option: it
+controls the font used to display double-width characters in bold,
+when \cw{BoldAsColour} is turned off. The default is unset
+(double-width characters are displayed in bold by printing them
+twice at a one-pixel offset).
+
+\dt \cw{pterm.ShadowBoldOffset}
+
+\dd This resource can be set to an integer; the default is \-1. It
+specifies the offset at which text is overprinted when using
+\q{shadow bold} mode. The default (1) means that the text will be
+printed in the normal place, and also one character to the right;
+this seems to work well for most X bitmap fonts, which have a blank
+line of pixels down the right-hand side. For some fonts, you may
+need to set this to \-1, so that the text is overprinted one pixel
+to the left; for really large fonts, you may want to set it higher
+than 1 (in one direction or the other).
+
+\dt \cw{pterm.BoldAsColour}
+
+\dd This option should be set to either 0 or 1; the default is 1. It
+specifies the default state of auto wrap mode. When set to 1, bold
+text is shown by displaying it in a brighter colour; when set to 0,
+bold text is shown by displaying it in a heavier font.
+
+\dt \cw{pterm.Colour0}, \cw{pterm.Colour1}, ..., \cw{pterm.Colour21}
+
+\dd These options control the various colours used to display text
+in the \cw{pterm} window. Each one should be specified as a triple
+of decimal numbers giving red, green and blue values: so that black
+is \q{\cw{0,0,0}}, white is \q{\cw{255,255,255}}, red is
+\q{\cw{255,0,0}} and so on.
+
+\lcont{
+
+Colours 0 and 1 specify the foreground colour and its bold
+equivalent (the \cw{\-fg} and \cw{\-bfg} command-line options).
+Colours 2 and 3 specify the background colour and its bold
+equivalent (the \cw{\-bg} and \cw{\-bbg} command-line options).
+Colours 4 and 5 specify the text and block colours used for the
+cursor (the \cw{\-cfg} and \cw{\-cbg} command-line options). Each
+even number from 6 to 20 inclusive specifies the colour to be used
+for one of the ANSI primary colour specifications (black, red,
+green, yellow, blue, magenta, cyan, white, in that order); the odd
+numbers from 7 to 21 inclusive specify the bold version of each
+colour, in the same order. The defaults are:
+
+\c pterm.Colour0: 187,187,187
+\c pterm.Colour1: 255,255,255
+\c pterm.Colour2: 0,0,0
+\c pterm.Colour3: 85,85,85
+\c pterm.Colour4: 0,0,0
+\c pterm.Colour5: 0,255,0
+\c pterm.Colour6: 0,0,0
+\c pterm.Colour7: 85,85,85
+\c pterm.Colour8: 187,0,0
+\c pterm.Colour9: 255,85,85
+\c pterm.Colour10: 0,187,0
+\c pterm.Colour11: 85,255,85
+\c pterm.Colour12: 187,187,0
+\c pterm.Colour13: 255,255,85
+\c pterm.Colour14: 0,0,187
+\c pterm.Colour15: 85,85,255
+\c pterm.Colour16: 187,0,187
+\c pterm.Colour17: 255,85,255
+\c pterm.Colour18: 0,187,187
+\c pterm.Colour19: 85,255,255
+\c pterm.Colour20: 187,187,187
+\c pterm.Colour21: 255,255,255
+
+}
+
+\dt \cw{pterm.RectSelect}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 0, dragging the mouse over several lines selects to the end
+of each line and from the beginning of the next; when set to 1,
+dragging the mouse over several lines selects a rectangular region.
+In each case, holding down Alt while dragging gives the other
+behaviour.
+
+\dt \cw{pterm.MouseOverride}
+
+\dd This option should be set to either 0 or 1; the default is 1. When
+set to 1, if the application requests mouse tracking (so that mouse
+clicks are sent to it instead of doing selection), holding down
+Shift will revert the mouse to normal selection. When set to 0,
+mouse tracking completely disables selection.
+
+\dt \cw{pterm.Printer}
+
+\dd This option is unset by default. If you set it, then
+server-controlled printing is enabled: the server can send control
+sequences to request data to be sent to a printer. That data will be
+piped into the command you specify here; so you might want to set it
+to \q{\cw{lpr}}, for example, or \q{\cw{lpr \-Pmyprinter}}.
+
+\dt \cw{pterm.ScrollBar}
+
+\dd This option should be set to either 0 or 1; the default is 1. When
+set to 0, the scrollbar is hidden (although Shift-PageUp and
+Shift-PageDown still work). This is the same as the \cw{\-sb}
+command-line option.
+
+\dt \cw{pterm.ScrollbarOnLeft}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, the scrollbar will be displayed on the left of the
+terminal instead of on the right.
+
+\dt \cw{pterm.ScrollOnKey}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, any keypress causes the position of the scrollback to be
+reset to the very bottom.
+
+\dt \cw{pterm.ScrollOnDisp}
+
+\dd This option should be set to either 0 or 1; the default is 1. When
+set to 1, any activity in the display causes the position of the
+scrollback to be reset to the very bottom.
+
+\dt \cw{pterm.LineCodePage}
+
+\dd This option specifies the character set to be used for the session.
+This is the same as the \cw{\-cs} command-line option.
+
+\dt \cw{pterm.NoRemoteCharset}
+
+\dd This option disables the terminal's ability to change its character
+set when it receives escape sequences telling it to. You might need
+to do this to interoperate with programs which incorrectly change
+the character set to something they think is sensible.
+
+\dt \cw{pterm.BCE}
+
+\dd This option should be set to either 0 or 1; the default is 1. When
+set to 1, the various control sequences that erase parts of the
+terminal display will erase in whatever the current background
+colour is; when set to 0, they will erase in black always.
+
+\dt \cw{pterm.BlinkText}
+
+\dd This option should be set to either 0 or 1; the default is 0. When
+set to 1, text specified as blinking by the server will actually
+blink on and off; when set to 0, \cw{pterm} will use the less
+distracting approach of making the text's background colour bold.
+
+\dt \cw{pterm.StampUtmp}
+
+\dd This option should be set to either 0 or 1; the default is 1. When
+set to 1, \cw{pterm} will log the login in the various system log
+files. This resource is equivalent to the \cw{\-ut} command-line
+option.
+
+\dt \cw{pterm.LoginShell}
+
+\dd This option should be set to either 0 or 1; the default is 1. When
+set to 1, \cw{pterm} will execute your shell as a login shell. This
+resource is equivalent to the \cw{\-ls} command-line option.
+
+\S{pterm-manpage-bugs} BUGS
+
+Most of the X resources have silly names. (Historical reasons from
+PuTTY, mostly.)
diff --git a/puttysrc/DOC/MAN-PUTT.BUT b/puttysrc/DOC/MAN-PUTT.BUT
new file mode 100644
index 0000000..ffb5bb0
--- /dev/null
+++ b/puttysrc/DOC/MAN-PUTT.BUT
@@ -0,0 +1,240 @@
+\cfg{man-identity}{putty}{1}{2004-03-24}{PuTTY tool suite}{PuTTY tool suite}
+
+\H{putty-manpage} Man page for PuTTY
+
+\S{putty-manpage-name} NAME
+
+\cw{putty} - GUI SSH, Telnet and Rlogin client for X
+
+\S{putty-manpage-synopsis} SYNOPSIS
+
+\c putty [ options ] [ host ]
+\e bbbbb iiiiiii iiii
+
+\S{putty-manpage-description} DESCRIPTION
+
+\cw{putty} is a graphical SSH, Telnet and Rlogin client for X. It is
+a direct port of the Windows SSH client of the same name.
+
+\S{putty-manpage-options} OPTIONS
+
+The command-line options supported by \cw{putty} are:
+
+\dt \cw{\-\-display} \e{display\-name}
+
+\dd Specify the X display on which to open \cw{putty}. (Note this
+option has a double minus sign, even though none of the others do.
+This is because this option is supplied automatically by GTK.
+Sorry.)
+
+\dt \cw{\-fn} \e{font-name}
+
+\dd Specify the font to use for normal text displayed in the terminal.
+
+\dt \cw{\-fb} \e{font-name}
+
+\dd Specify the font to use for bold text displayed in the terminal.
+If the \cw{BoldAsColour} resource is set to 1 (the default), bold
+text will be displayed in different colours instead of a different
+font, so this option will be ignored. If \cw{BoldAsColour} is set to
+0 and you do not specify a bold font, \cw{putty} will overprint the
+normal font to make it look bolder.
+
+\dt \cw{\-fw} \e{font-name}
+
+\dd Specify the font to use for double-width characters (typically
+Chinese, Japanese and Korean text) displayed in the terminal.
+
+\dt \cw{\-fwb} \e{font-name}
+
+\dd Specify the font to use for bold double-width characters
+(typically Chinese, Japanese and Korean text). Like \cw{-fb}, this
+will be ignored unless the \cw{BoldAsColour} resource is set to 0.
+
+\dt \cw{\-geometry} \e{geometry}
+
+\dd Specify the size of the terminal, in rows and columns of text.
+See \e{X(7)} for more information on the syntax of geometry
+specifications.
+
+\dt \cw{\-sl} \e{lines}
+
+\dd Specify the number of lines of scrollback to save off the top of the
+terminal.
+
+\dt \cw{\-fg} \e{colour}
+
+\dd Specify the foreground colour to use for normal text.
+
+\dt \cw{\-bg} \e{colour}
+
+\dd Specify the background colour to use for normal text.
+
+\dt \cw{\-bfg} \e{colour}
+
+\dd Specify the foreground colour to use for bold text, if the
+\cw{BoldAsColour} resource is set to 1 (the default).
+
+\dt \cw{\-bbg} \e{colour}
+
+\dd Specify the foreground colour to use for bold reverse-video
+text, if the \cw{BoldAsColour} resource is set to 1 (the default).
+(This colour is best thought of as the bold version of the
+background colour; so it only appears when text is displayed \e{in}
+the background colour.)
+
+\dt \cw{\-cfg} \e{colour}
+
+\dd Specify the foreground colour to use for text covered by the cursor.
+
+\dt \cw{\-cbg} \e{colour}
+
+\dd Specify the background colour to use for text covered by the cursor.
+In other words, this is the main colour of the cursor.
+
+\dt \cw{\-title} \e{title}
+
+\dd Specify the initial title of the terminal window. (This can be
+changed under control of the server.)
+
+\dt \cw{\-sb\-} or \cw{+sb}
+
+\dd Tells \cw{putty} not to display a scroll bar.
+
+\dt \cw{\-sb}
+
+\dd Tells \cw{putty} to display a scroll bar: this is the opposite of
+\cw{\-sb\-}. This is the default option: you will probably only need
+to specify it explicitly if you have changed the default using the
+\cw{ScrollBar} resource.
+
+\dt \cw{\-log} \e{filename}
+
+\dd This option makes \cw{putty} log all the terminal output to a file
+as well as displaying it in the terminal.
+
+
+\dt \cw{\-cs} \e{charset}
+
+\dd This option specifies the character set in which \cw{putty}
+should assume the session is operating. This character set will be
+used to interpret all the data received from the session, and all
+input you type or paste into \cw{putty} will be converted into
+this character set before being sent to the session.
+
+\lcont{ Any character set name which is valid in a MIME header (and
+supported by \cw{putty}) should be valid here (examples are
+\q{\cw{ISO-8859-1}}, \q{\cw{windows-1252}} or \q{\cw{UTF-8}}). Also,
+any character encoding which is valid in an X logical font
+description should be valid (\q{\cw{ibm-cp437}}, for example).
+
+\cw{putty}'s default behaviour is to use the same character
+encoding as its primary font. If you supply a Unicode
+(\cw{iso10646-1}) font, it will default to the UTF-8 character set.
+
+Character set names are case-insensitive.
+}
+
+\dt \cw{\-nethack}
+
+\dd Tells \cw{putty} to enable NetHack keypad mode, in which the
+numeric keypad generates the NetHack \c{hjklyubn} direction keys.
+This enables you to play NetHack with the numeric keypad without
+having to use the NetHack \c{number_pad} option (which requires you
+to press \q{\cw{n}} before any repeat count). So you can move with
+the numeric keypad, and enter repeat counts with the normal number
+keys.
+
+\dt \cw{\-help}, \cw{\-\-help}
+
+\dd Display a message summarizing the available options.
+
+\dt \cw{\-pgpfp}
+
+\dd Display the fingerprints of the PuTTY PGP Master Keys, to aid
+in verifying new files released by the PuTTY team.
+
+\dt \cw{\-load} \e{session}
+
+\dd Load a saved session by name. This allows you to run a saved session
+straight from the command line without having to go through the
+configuration box first.
+
+\dt \cw{\-ssh}, \cw{\-telnet}, \cw{\-rlogin}, \cw{\-raw}
+
+\dd Select the protocol \cw{putty} will use to make the connection.
+
+\dt \cw{\-l} \e{username}
+
+\dd Specify the username to use when logging in to the server.
+
+\dt \cw{\-L} \cw{[}\e{srcaddr}\cw{:]}\e{srcport}\cw{:}\e{desthost}\cw{:}\e{destport}
+
+\dd Set up a local port forwarding: listen on \e{srcport} (or
+\e{srcaddr}:\e{srcport} if specified), and forward any connections
+over the SSH connection to the destination address
+\e{desthost}:\e{destport}. Only works in SSH.
+
+\dt \cw{\-R} \cw{[}\e{srcaddr}\cw{:]}\e{srcport}\cw{:}\e{desthost}\cw{:}\e{destport}
+
+\dd Set up a remote port forwarding: ask the SSH server to listen on
+\e{srcport} (or \e{srcaddr}:\e{srcport} if specified), and to
+forward any connections back over the SSH connection where the
+client will pass them on to the destination address
+\e{desthost}:\e{destport}. Only works in SSH.
+
+\dt \cw{\-D} [\e{srcaddr}:]\e{srcport}
+
+\dd Set up dynamic port forwarding. The client listens on
+\e{srcport} (or \e{srcaddr}:\e{srcport} if specified), and
+implements a SOCKS server. So you can point SOCKS-aware applications
+at this port and they will automatically use the SSH connection to
+tunnel all their connections. Only works in SSH.
+
+\dt \cw{\-P} \e{port}
+
+\dd Specify the port to connect to the server on.
+
+\dt \cw{\-A}, \cw{\-a}
+
+\dd Enable (\cw{\-A}) or disable (\cw{\-a}) SSH agent forwarding.
+Currently this only works with OpenSSH and SSH-1.
+
+\dt \cw{\-X}, \cw{\-x}
+
+\dd Enable (\cw{\-X}) or disable (\cw{\-x}) X11 forwarding.
+
+\dt \cw{\-T}, \cw{\-t}
+
+\dd Enable (\cw{\-t}) or disable (\cw{\-T}) the allocation of a
+pseudo-terminal at the server end.
+
+\dt \cw{\-C}
+
+\dd Enable zlib-style compression on the connection.
+
+\dt \cw{\-1}, \cw{\-2}
+
+\dd Select SSH protocol version 1 or 2.
+
+\dt \cw{\-i} \e{keyfile}
+
+\dd Specify a private key file to use for authentication. For SSH-2
+keys, this key file must be in PuTTY's format, not OpenSSH's or
+anyone else's.
+
+\S{putty-manpage-saved-sessions} SAVED SESSIONS
+
+Saved sessions are stored in a \cw{.putty/sessions} subdirectory in
+your home directory.
+
+\S{putty-manpage-more-information} MORE INFORMATION
+
+For more information on PuTTY, it's probably best to go and look at
+the manual on the web page:
+
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/}\cw{http://www.chiark.greenend.org.uk/~sgtatham/putty/}
+
+\S{putty-manpage-bugs} BUGS
+
+This man page isn't terribly complete.
diff --git a/puttysrc/DOC/MANCFG.BUT b/puttysrc/DOC/MANCFG.BUT
new file mode 100644
index 0000000..37723bd
--- /dev/null
+++ b/puttysrc/DOC/MANCFG.BUT
@@ -0,0 +1,3 @@
+\cfg{man-mindepth}{2}
+
+\C{not-shown} Chapter title which is not shown
diff --git a/puttysrc/DOC/MANPAGES.BUT b/puttysrc/DOC/MANPAGES.BUT
new file mode 100644
index 0000000..5fe4a76
--- /dev/null
+++ b/puttysrc/DOC/MANPAGES.BUT
@@ -0,0 +1,3 @@
+\A{man-pages} Man pages for Unix PuTTY
+
+This appendix contains all the man pages for Unix PuTTY.
diff --git a/puttysrc/DOC/PAGEANT.BUT b/puttysrc/DOC/PAGEANT.BUT
new file mode 100644
index 0000000..04715ed
--- /dev/null
+++ b/puttysrc/DOC/PAGEANT.BUT
@@ -0,0 +1,273 @@
+\define{versionidpageant} \versionid $Id: pageant.but 6610 2006-03-14 11:21:59Z jacob $
+
+\C{pageant} Using \i{Pageant} for authentication
+
+\cfg{winhelp-topic}{pageant.general}
+
+Pageant is an SSH \i{authentication agent}. It holds your \i{private key}s
+in memory, already decoded, so that you can use them often
+\I{passwordless login}without needing to type a \i{passphrase}.
+
+\H{pageant-start} Getting started with Pageant
+
+Before you run Pageant, you need to have a private key in \c{*.\i{PPK}}
+format. See \k{pubkey} to find out how to generate and use one.
+
+When you run Pageant, it will put an icon of a computer wearing a
+hat into the \ii{System tray}. It will then sit and do nothing, until you
+load a private key into it.
+
+If you click the Pageant icon with the right mouse button, you will
+see a menu. Select \q{View Keys} from this menu. The Pageant main
+window will appear. (You can also bring this window up by
+double-clicking on the Pageant icon.)
+
+The Pageant window contains a list box. This shows the private keys
+Pageant is holding. When you start Pageant, it has no keys, so the
+list box will be empty. After you add one or more keys, they will
+show up in the list box.
+
+To add a key to Pageant, press the \q{Add Key} button. Pageant will
+bring up a file dialog, labelled \q{Select Private Key File}. Find
+your private key file in this dialog, and press \q{Open}.
+
+Pageant will now load the private key. If the key is protected by a
+passphrase, Pageant will ask you to type the passphrase. When the
+key has been loaded, it will appear in the list in the Pageant
+window.
+
+Now start PuTTY and open an SSH session to a site that accepts your
+key. PuTTY will notice that Pageant is running, retrieve the key
+automatically from Pageant, and use it to authenticate. You can now
+open as many PuTTY sessions as you like without having to type your
+passphrase again.
+
+(PuTTY can be configured not to try to use Pageant, but it will try
+by default. See \k{config-ssh-tryagent} and
+\k{using-cmdline-agentauth} for more information.)
+
+When you want to shut down Pageant, click the right button on the
+Pageant icon in the System tray, and select \q{Exit} from the menu.
+Closing the Pageant main window does \e{not} shut down Pageant.
+
+\H{pageant-mainwin} The Pageant main window
+
+The Pageant main window appears when you left-click on the Pageant
+system tray icon, or alternatively right-click and select \q{View
+Keys} from the menu. You can use it to keep track of what keys are
+currently loaded into Pageant, and to add new ones or remove the
+existing keys.
+
+\S{pageant-mainwin-keylist} The key list box
+
+\cfg{winhelp-topic}{pageant.keylist}
+
+The large list box in the Pageant main window lists the private keys
+that are currently loaded into Pageant. The list might look
+something like this:
+
+\c ssh1 1024 22:c3:68:3b:09:41:36:c3:39:83:91:ae:71:b2:0f:04 k1
+\c ssh-rsa 1023 74:63:08:82:95:75:e1:7c:33:31:bb:cb:00:c0:89:8b k2
+
+For each key, the list box will tell you:
+
+\b The type of the key. Currently, this can be \c{ssh1} (an RSA key
+for use with the SSH-1 protocol), \c{ssh-rsa} (an RSA key for use
+with the SSH-2 protocol), or \c{ssh-dss} (a DSA key for use with
+the SSH-2 protocol).
+
+\b The size (in bits) of the key.
+
+\b The \I{key fingerprint}fingerprint for the public key. This should be
+the same fingerprint given by PuTTYgen, and (hopefully) also the same
+fingerprint shown by remote utilities such as \i\c{ssh-keygen} when
+applied to your \c{authorized_keys} file.
+
+\b The comment attached to the key.
+
+\S{pageant-mainwin-addkey} The \q{Add Key} button
+
+\cfg{winhelp-topic}{pageant.addkey}
+
+To add a key to Pageant by reading it out of a local disk file,
+press the \q{Add Key} button in the Pageant main window, or
+alternatively right-click on the Pageant icon in the system tray and
+select \q{Add Key} from there.
+
+Pageant will bring up a file dialog, labelled \q{Select Private Key
+File}. Find your private key file in this dialog, and press
+\q{Open}. If you want to add more than one key at once, you can
+select multiple files using Shift-click (to select several adjacent
+files) or Ctrl-click (to select non-adjacent files).
+
+Pageant will now load the private key(s). If a key is protected by a
+passphrase, Pageant will ask you to type the passphrase.
+
+(This is not the only way to add a private key to Pageant. You can
+also add one from a remote system by using agent forwarding; see
+\k{pageant-forward} for details.)
+
+\S{pageant-mainwin-remkey} The \q{Remove Key} button
+
+\cfg{winhelp-topic}{pageant.remkey}
+
+If you need to remove a key from Pageant, select that key in the
+list box, and press the \q{Remove Key} button. Pageant will remove
+the key from its memory.
+
+You can apply this to keys you added using the \q{Add Key} button,
+or to keys you added remotely using agent forwarding (see
+\k{pageant-forward}); it makes no difference.
+
+\H{pageant-cmdline} The Pageant command line
+
+Pageant can be made to do things automatically when it starts up, by
+\I{command-line arguments}specifying instructions on its command line.
+If you're starting Pageant from the Windows GUI, you can arrange this
+by editing the properties of the \i{Windows shortcut} that it was
+started from.
+
+If Pageant is already running, invoking it again with the options
+below causes actions to be performed with the existing instance, not a
+new one.
+
+\S{pageant-cmdline-loadkey} Making Pageant automatically load keys
+on startup
+
+Pageant can automatically load one or more private keys when it
+starts up, if you provide them on the Pageant command line. Your
+command line might then look like:
+
+\c C:\PuTTY\pageant.exe d:\main.ppk d:\secondary.ppk
+
+If the keys are stored encrypted, Pageant will request the
+passphrases on startup.
+
+If Pageant is already running, this syntax loads keys into the
+existing Pageant.
+
+\S{pageant-cmdline-command} Making Pageant run another program
+
+You can arrange for Pageant to start another program once it has
+initialised itself and loaded any keys specified on its command
+line. This program (perhaps a PuTTY, or a WinCVS making use of
+Plink, or whatever) will then be able to use the keys Pageant has
+loaded.
+
+You do this by specifying the \I{-c-pageant}\c{-c} option followed
+by the command, like this:
+
+\c C:\PuTTY\pageant.exe d:\main.ppk -c C:\PuTTY\putty.exe
+
+\H{pageant-forward} Using \i{agent forwarding}
+
+Agent forwarding is a mechanism that allows applications on your SSH
+server machine to talk to the agent on your client machine.
+
+Note that at present, agent forwarding in SSH-2 is only available
+when your SSH server is \i{OpenSSH}. The \i\cw{ssh.com} server uses a
+different agent protocol, which PuTTY does not yet support.
+
+To enable agent forwarding, first start Pageant. Then set up a PuTTY
+SSH session in which \q{Allow agent forwarding} is enabled (see
+\k{config-ssh-agentfwd}). Open the session as normal. (Alternatively,
+you can use the \c{-A} command line option; see
+\k{using-cmdline-agent} for details.)
+
+If this has worked, your applications on the server should now have
+access to a Unix domain socket which the SSH server will forward
+back to PuTTY, and PuTTY will forward on to the agent. To check that
+this has actually happened, you can try this command on Unix server
+machines:
+
+\c unixbox:~$ echo $SSH_AUTH_SOCK
+\c /tmp/ssh-XXNP18Jz/agent.28794
+\c unixbox:~$
+
+If the result line comes up blank, agent forwarding has not been
+enabled at all.
+
+Now if you run \c{ssh} on the server and use it to connect through
+to another server that accepts one of the keys in Pageant, you
+should be able to log in without a password:
+
+\c unixbox:~$ ssh -v otherunixbox
+\c [...]
+\c debug: next auth method to try is publickey
+\c debug: userauth_pubkey_agent: trying agent key my-putty-key
+\c debug: ssh-userauth2 successful: method publickey
+\c [...]
+
+If you enable agent forwarding on \e{that} SSH connection as well
+(see the manual for your server-side SSH client to find out how to
+do this), your authentication keys will still be available on the
+next machine you connect to - two SSH connections away from where
+they're actually stored.
+
+In addition, if you have a private key on one of the SSH servers,
+you can send it all the way back to Pageant using the local
+\i\c{ssh-add} command:
+
+\c unixbox:~$ ssh-add ~/.ssh/id_rsa
+\c Need passphrase for /home/fred/.ssh/id_rsa
+\c Enter passphrase for /home/fred/.ssh/id_rsa:
+\c Identity added: /home/fred/.ssh/id_rsa (/home/simon/.ssh/id_rsa)
+\c unixbox:~$
+
+and then it's available to every machine that has agent forwarding
+available (not just the ones downstream of the place you added it).
+
+\H{pageant-security} Security considerations
+
+\I{security risk}Using Pageant for public-key authentication gives you the
+convenience of being able to open multiple SSH sessions without
+having to type a passphrase every time, but also gives you the
+security benefit of never storing a decrypted private key on disk.
+Many people feel this is a good compromise between security and
+convenience.
+
+It \e{is} a compromise, however. Holding your decrypted private keys
+in Pageant is better than storing them in easy-to-find disk files,
+but still less secure than not storing them anywhere at all. This is
+for two reasons:
+
+\b Windows unfortunately provides no way to protect pieces of memory
+from being written to the system \i{swap file}. So if Pageant is holding
+your private keys for a long period of time, it's possible that
+decrypted private key data may be written to the system swap file,
+and an attacker who gained access to your hard disk later on might
+be able to recover that data. (However, if you stored an unencrypted
+key in a disk file they would \e{certainly} be able to recover it.)
+
+\b Although, like most modern operating systems, Windows prevents
+programs from accidentally accessing one another's memory space, it
+does allow programs to access one another's memory space
+deliberately, for special purposes such as debugging. This means
+that if you allow a virus, trojan, or other malicious program on to
+your Windows system while Pageant is running, it could access the
+memory of the Pageant process, extract your decrypted authentication
+keys, and send them back to its master.
+
+Similarly, use of agent \e{forwarding} is a security improvement on
+other methods of one-touch authentication, but not perfect. Holding
+your keys in Pageant on your Windows box has a security advantage
+over holding them on the remote server machine itself (either in an
+agent or just unencrypted on disk), because if the server machine
+ever sees your unencrypted private key then the sysadmin or anyone
+who cracks the machine can steal the keys and pretend to be you for
+as long as they want.
+
+However, the sysadmin of the server machine can always pretend to be
+you \e{on that machine}. So if you forward your agent to a server
+machine, then the sysadmin of that machine can access the forwarded
+agent connection and request signatures from your private keys, and
+can therefore log in to other machines as you. They can only do this
+to a limited extent - when the agent forwarding disappears they lose
+the ability - but using Pageant doesn't actually \e{prevent} the
+sysadmin (or hackers) on the server from doing this.
+
+Therefore, if you don't trust the sysadmin of a server machine, you
+should \e{never} use agent forwarding to that machine. (Of course
+you also shouldn't store private keys on that machine, type
+passphrases into it, or log into other machines from it in any way
+at all; Pageant is hardly unique in this respect.)
diff --git a/puttysrc/DOC/PGPKEYS.BUT b/puttysrc/DOC/PGPKEYS.BUT
new file mode 100644
index 0000000..87f80db
--- /dev/null
+++ b/puttysrc/DOC/PGPKEYS.BUT
@@ -0,0 +1,141 @@
+\define{versionidpgpkeys} \versionid $Id: pgpkeys.but 5598 2005-04-05 19:36:25Z simon $
+
+\A{pgpkeys} PuTTY download keys and signatures
+
+\cfg{winhelp-topic}{pgpfingerprints}
+
+\I{verifying new versions}We create \i{PGP signatures} for all the PuTTY
+files distributed from our web site, so that users can be confident
+that the files have not been tampered with. Here we identify
+our public keys, and explain our signature policy so you can have an
+accurate idea of what each signature guarantees.
+This description is provided as both a web page on the PuTTY site, and
+an appendix in the PuTTY manual.
+
+As of release 0.58, all of the PuTTY executables contain fingerprint
+material (usually accessed via the \i\c{-pgpfp} command-line
+option), such that if you have an executable you trust, you can use
+it to establish a trust path, for instance to a newer version
+downloaded from the Internet.
+
+(Note that none of the keys, signatures, etc mentioned here have
+anything to do with keys used with SSH - they are purely for verifying
+the origin of files distributed by the PuTTY team.)
+
+\H{pgpkeys-pubkey} Public keys
+
+We supply two complete sets of keys. We supply a set of RSA keys,
+compatible with both \W{http://www.gnupg.org/}{GnuPG} and PGP2,
+and also a set of DSA keys compatible with GnuPG.
+
+In each format, we have three keys:
+
+\b A Development Snapshots key, used to sign the nightly builds.
+
+\b A Releases key, used to sign actual releases.
+
+\b A Master Key. The Master Key is used to sign the other two keys, and
+they sign it in return.
+
+Therefore, we have six public keys in total:
+
+\b RSA:
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-rsa.asc}{Master Key},
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-rsa.asc}{Release key},
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-rsa.asc}{Snapshot key}
+
+\lcont{
+Master Key: 1024-bit; \I{PGP key fingerprint}fingerprint:
+\cw{8F\_15\_97\_DA\_25\_30\_AB\_0D\_\_88\_D1\_92\_54\_11\_CF\_0C\_4C}
+}
+
+\b DSA:
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/master-dsa.asc}{Master Key},
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/release-dsa.asc}{Release key},
+\W{http://www.chiark.greenend.org.uk/~sgtatham/putty/keys/snapshot-dsa.asc}{Snapshot key}
+
+\lcont{
+Master Key: 1024-bit; fingerprint:
+\cw{313C\_3E76\_4B74\_C2C5\_F2AE\_\_83A8\_4F5E\_6DF5\_6A93\_B34E}
+}
+
+\H{pgpkeys-security} Security details
+
+The various keys have various different security levels. This
+section explains what those security levels are, and how far you can
+expect to trust each key.
+
+\S{pgpkeys-snapshot} The Development Snapshots keys
+
+These keys are stored \e{without passphrases}. This is
+necessary, because the snapshots are generated every night without
+human intervention, so nobody would be able to type a passphrase.
+
+The actual snapshots are built on a team member's home Windows box.
+The keys themselves are stored on an independently run Unix box
+(the same one that hosts our Subversion repository). After
+being built, the binaries are uploaded to this Unix box and then
+signed automatically.
+
+Therefore, a signature from one of the Development Snapshots keys
+\e{DOES} protect you against:
+
+\b People tampering with the PuTTY binaries between the PuTTY web site
+and you.
+
+But it \e{DOES NOT} protect you against:
+
+\b People tampering with the binaries before they are uploaded to the
+independent Unix box.
+
+\b The sysadmin of the independent Unix box using his root privilege to
+steal the private keys and abuse them, or tampering with the
+binaries before they are signed.
+
+\b Somebody getting root on the Unix box.
+
+Of course, we don't believe any of those things is very likely. We
+know our sysadmin personally and trust him (both to be competent and
+to be non-malicious), and we take all reasonable precautions to
+guard the build machine. But when you see a signature, you should
+always be certain of precisely what it guarantees and precisely what
+it does not.
+
+\S{pgpkeys-release} The Releases keys
+
+The Release keys have passphrases and we can be more careful about
+how we use them.
+
+The Release keys are kept safe on the developers' own local
+machines, and only used to sign releases that have been built by
+hand. A signature from a Release key protects you from almost any
+plausible attack.
+
+(Some of the developers' machines have cable modem connections and
+might in theory be crackable, but of course the private keys are
+still encrypted, so the crack would have to go unnoticed for long
+enough to steal a passphrase.)
+
+\S{pgpkeys-master} The Master Keys
+
+The Master Keys sign almost nothing. Their purpose is to bind the
+other keys together and certify that they are all owned by the same
+people and part of the same integrated setup. The only signatures
+produced by the Master Keys, \e{ever}, should be the signatures
+on the other keys.
+
+We intend to arrange for the Master Keys to sign each other, to
+certify that the DSA keys and RSA keys are part of the same setup.
+We have not yet got round to this at the time of writing.
+
+We have collected a few third-party signatures on the Master Keys,
+in order to increase the chances that you can find a suitable trust
+path to them. We intend to collect more. (Note that the keys on the
+keyservers appear to have also collected some signatures from people
+who haven't performed any verification of the Master Keys.)
+
+We have uploaded our various keys to public keyservers, so that
+even if you don't know any of the people who have signed our
+keys, you can still be reasonably confident that an attacker would
+find it hard to substitute fake keys on all the public keyservers at
+once.
diff --git a/puttysrc/DOC/PLINK.BUT b/puttysrc/DOC/PLINK.BUT
new file mode 100644
index 0000000..e3772fd
--- /dev/null
+++ b/puttysrc/DOC/PLINK.BUT
@@ -0,0 +1,294 @@
+\define{versionidplink} \versionid $Id: plink.but 7488 2007-04-29 11:28:54Z simon $
+
+\C{plink} Using the command-line connection tool \i{Plink}
+
+\i{Plink} (PuTTY Link) is a command-line connection tool similar to
+UNIX \c{ssh}. It is mostly used for \i{automated operations}, such as
+making CVS access a repository on a remote server.
+
+Plink is probably not what you want if you want to run an
+\i{interactive session} in a console window.
+
+\H{plink-starting} Starting Plink
+
+Plink is a command line application. This means that you cannot just
+double-click on its icon to run it and instead you have to bring up
+a \i{console window}. In Windows 95, 98, and ME, this is called an
+\q{MS-DOS Prompt}, and in Windows NT, 2000, and XP, it is called a
+\q{Command Prompt}. It should be available from the Programs section
+of your Start Menu.
+
+In order to use Plink, the file \c{plink.exe} will need either to be
+on your \i{\c{PATH}} or in your current directory. To add the
+directory containing Plink to your \c{PATH} environment variable,
+type into the console window:
+
+\c set PATH=C:\path\to\putty\directory;%PATH%
+
+This will only work for the lifetime of that particular console
+window. To set your \c{PATH} more permanently on Windows NT, 2000,
+and XP, use the Environment tab of the System Control Panel. On
+Windows 95, 98, and ME, you will need to edit your \i\c{AUTOEXEC.BAT}
+to include a \c{set} command like the one above.
+
+\H{plink-usage} Using Plink
+
+This section describes the basics of how to use Plink for
+interactive logins and for automated processes.
+
+Once you've got a console window to type into, you can just type
+\c{plink} on its own to bring up a usage message. This tells you the
+version of Plink you're using, and gives you a brief summary of how to
+use Plink:
+
+\c Z:\sysosd>plink
+\c PuTTY Link: command-line connection utility
+\c Release 0.60
+\c Usage: plink [options] [user@]host [command]
+\c ("host" can also be a PuTTY saved session name)
+\c Options:
+\c -V print version information and exit
+\c -pgpfp print PGP key fingerprints and exit
+\c -v show verbose messages
+\c -load sessname Load settings from saved session
+\c -ssh -telnet -rlogin -raw
+\c force use of a particular protocol
+\c -P port connect to specified port
+\c -l user connect with specified username
+\c -batch disable all interactive prompts
+\c The following options only apply to SSH connections:
+\c -pw passw login with specified password
+\c -D [listen-IP:]listen-port
+\c Dynamic SOCKS-based port forwarding
+\c -L [listen-IP:]listen-port:host:port
+\c Forward local port to remote address
+\c -R [listen-IP:]listen-port:host:port
+\c Forward remote port to local address
+\c -X -x enable / disable X11 forwarding
+\c -A -a enable / disable agent forwarding
+\c -t -T enable / disable pty allocation
+\c -1 -2 force use of particular protocol version
+\c -4 -6 force use of IPv4 or IPv6
+\c -C enable compression
+\c -i key private key file for authentication
+\c -noagent disable use of Pageant
+\c -agent enable use of Pageant
+\c -m file read remote command(s) from file
+\c -s remote command is an SSH subsystem (SSH-2 only)
+\c -N don't start a shell/command (SSH-2 only)
+\c -nc host:port
+\c open tunnel in place of session (SSH-2 only)
+
+Once this works, you are ready to use Plink.
+
+\S{plink-usage-interactive} Using Plink for interactive logins
+
+To make a simple interactive connection to a remote server, just
+type \c{plink} and then the host name:
+
+\c Z:\sysosd>plink login.example.com
+\c
+\c Debian GNU/Linux 2.2 flunky.example.com
+\c flunky login:
+
+You should then be able to log in as normal and run a session. The
+output sent by the server will be written straight to your command
+prompt window, which will most likely not interpret terminal \i{control
+codes} in the way the server expects it to. So if you run any
+full-screen applications, for example, you can expect to see strange
+characters appearing in your window. Interactive connections like
+this are not the main point of Plink.
+
+In order to connect with a different protocol, you can give the
+command line options \c{-ssh}, \c{-telnet}, \c{-rlogin} or \c{-raw}.
+To make an SSH connection, for example:
+
+\c Z:\sysosd>plink -ssh login.example.com
+\c login as:
+
+If you have already set up a PuTTY saved session, then instead of
+supplying a host name, you can give the saved session name. This
+allows you to use public-key authentication, specify a user name,
+and use most of the other features of PuTTY:
+
+\c Z:\sysosd>plink my-ssh-session
+\c Sent username "fred"
+\c Authenticating with public key "fred@winbox"
+\c Last login: Thu Dec 6 19:25:33 2001 from :0.0
+\c fred@flunky:~$
+
+(You can also use the \c{-load} command-line option to load a saved
+session; see \k{using-cmdline-load}. If you use \c{-load}, the saved
+session exists, and it specifies a hostname, you cannot also specify a
+\c{host} or \c{user@host} argument - it will be treated as part of the
+remote command.)
+
+\S{plink-usage-batch} Using Plink for automated connections
+
+More typically Plink is used with the SSH protocol, to enable you to
+talk directly to a program running on the server. To do this you
+have to ensure Plink is \e{using} the SSH protocol. You can do this
+in several ways:
+
+\b Use the \c{-ssh} option as described in
+\k{plink-usage-interactive}.
+
+\b Set up a PuTTY saved session that describes the server you are
+connecting to, and that also specifies the protocol as SSH.
+
+\b Set the Windows environment variable \i\c{PLINK_PROTOCOL} to the
+word \c{ssh}.
+
+Usually Plink is not invoked directly by a user, but run
+automatically by another process. Therefore you typically do not
+want Plink to prompt you for a user name or a password.
+
+Next, you are likely to need to avoid the various interactive
+prompts Plink can produce. You might be prompted to verify the host
+key of the server you're connecting to, to enter a user name, or to
+enter a password.
+
+To avoid being prompted for the server host key when using Plink for
+an automated connection, you should first make a \e{manual}
+connection (using either of PuTTY or Plink) to the same server,
+verify the host key (see \k{gs-hostkey} for more information), and
+select Yes to add the host key to the Registry. After that, Plink
+commands connecting to that server should not give a host key prompt
+unless the host key changes.
+
+To avoid being prompted for a user name, you can:
+
+\b Use the \c{-l} option to specify a user name on the command line.
+For example, \c{plink login.example.com -l fred}.
+
+\b Set up a PuTTY saved session that describes the server you are
+connecting to, and that also specifies the username to log in as
+(see \k{config-username}).
+
+To avoid being prompted for a password, you should almost certainly
+set up \i{public-key authentication}. (See \k{pubkey} for a general
+introduction to public-key authentication.) Again, you can do this
+in two ways:
+
+\b Set up a PuTTY saved session that describes the server you are
+connecting to, and that also specifies a private key file (see
+\k{config-ssh-privkey}). For this to work without prompting, your
+private key will need to have no passphrase.
+
+\b Store the private key in Pageant. See \k{pageant} for further
+information.
+
+Once you have done all this, you should be able to run a remote
+command on the SSH server machine and have it execute automatically
+with no prompting:
+
+\c Z:\sysosd>plink login.example.com -l fred echo hello, world
+\c hello, world
+\c
+\c Z:\sysosd>
+
+Or, if you have set up a saved session with all the connection
+details:
+
+\c Z:\sysosd>plink mysession echo hello, world
+\c hello, world
+\c
+\c Z:\sysosd>
+
+Then you can set up other programs to run this Plink command and
+talk to it as if it were a process on the server machine.
+
+\S{plink-options} Plink command line options
+
+Plink accepts all the general command line options supported by the
+PuTTY tools. See \k{using-general-opts} for a description of these
+options.
+
+Plink also supports some of its own options. The following sections
+describe Plink's specific command-line options.
+
+\S2{plink-option-batch} \I{-batch-plink}\c{-batch}: disable all
+interactive prompts
+
+If you use the \c{-batch} option, Plink will never give an
+interactive prompt while establishing the connection. If the
+server's host key is invalid, for example (see \k{gs-hostkey}), then
+the connection will simply be abandoned instead of asking you what
+to do next.
+
+This may help Plink's behaviour when it is used in automated
+scripts: using \c{-batch}, if something goes wrong at connection
+time, the batch job will fail rather than hang.
+
+\S2{plink-option-s} \I{-s-plink}\c{-s}: remote command is SSH subsystem
+
+If you specify the \c{-s} option, Plink passes the specified command
+as the name of an SSH \q{\i{subsystem}} rather than an ordinary command
+line.
+
+(This option is only meaningful with the SSH-2 protocol.)
+
+\H{plink-batch} Using Plink in \i{batch files} and \i{scripts}
+
+Once you have set up Plink to be able to log in to a remote server
+without any interactive prompting (see \k{plink-usage-batch}), you
+can use it for lots of scripting and batch purposes. For example, to
+start a backup on a remote machine, you might use a command like:
+
+\c plink root@myserver /etc/backups/do-backup.sh
+
+Or perhaps you want to fetch all system log lines relating to a
+particular web area:
+
+\c plink mysession grep /~fred/ /var/log/httpd/access.log > fredlog
+
+Any non-interactive command you could usefully run on the server
+command line, you can run in a batch file using Plink in this way.
+
+\H{plink-cvs} Using Plink with \i{CVS}
+
+To use Plink with CVS, you need to set the environment variable
+\i\c{CVS_RSH} to point to Plink:
+
+\c set CVS_RSH=\path\to\plink.exe
+
+You also need to arrange to be able to connect to a remote host
+without any interactive prompts, as described in
+\k{plink-usage-batch}.
+
+You should then be able to run CVS as follows:
+
+\c cvs -d :ext:user@sessionname:/path/to/repository co module
+
+If you specified a username in your saved session, you don't even
+need to specify the \q{user} part of this, and you can just say:
+
+\c cvs -d :ext:sessionname:/path/to/repository co module
+
+\H{plink-wincvs} Using Plink with \i{WinCVS}
+
+Plink can also be used with WinCVS. Firstly, arrange for Plink to be
+able to connect to a remote host non-interactively, as described in
+\k{plink-usage-batch}.
+
+Then, in WinCVS, bring up the \q{Preferences} dialogue box from the
+\e{Admin} menu, and switch to the \q{Ports} tab. Tick the box there
+labelled \q{Check for an alternate \cw{rsh} name} and in the text
+entry field to the right enter the full path to \c{plink.exe}.
+Select \q{OK} on the \q{Preferences} dialogue box.
+
+Next, select \q{Command Line} from the WinCVS \q{Admin} menu, and type
+a CVS command as in \k{plink-cvs}, for example:
+
+\c cvs -d :ext:user@hostname:/path/to/repository co module
+
+or (if you're using a saved session):
+
+\c cvs -d :ext:user@sessionname:/path/to/repository co module
+
+Select the folder you want to check out to with the \q{Change Folder}
+button, and click \q{OK} to check out your module. Once you've got
+modules checked out, WinCVS will happily invoke plink from the GUI for
+CVS operations.
+
+\# \H{plink-whatelse} Using Plink with... ?
diff --git a/puttysrc/DOC/PSCP.BUT b/puttysrc/DOC/PSCP.BUT
new file mode 100644
index 0000000..ba82ffe
--- /dev/null
+++ b/puttysrc/DOC/PSCP.BUT
@@ -0,0 +1,318 @@
+\define{versionidpscp} \versionid $Id: pscp.but 7488 2007-04-29 11:28:54Z simon $
+
+\#FIXME: Need examples
+
+\C{pscp} Using \i{PSCP} to transfer files securely
+
+\i{PSCP}, the PuTTY Secure Copy client, is a tool for \i{transferring files}
+securely between computers using an SSH connection.
+
+If you have an SSH-2 server, you might prefer PSFTP (see \k{psftp})
+for interactive use. PSFTP does not in general work with SSH-1
+servers, however.
+
+\H{pscp-starting} Starting PSCP
+
+PSCP is a command line application. This means that you cannot just
+double-click on its icon to run it and instead you have to bring up a
+\i{console window}. With Windows 95, 98, and ME, this is called an
+\q{MS-DOS Prompt} and with Windows NT, 2000, and XP, it is called a
+\q{Command Prompt}. It should be available from the Programs section
+of your \i{Start Menu}.
+
+To start PSCP it will need either to be on your \i{\c{PATH}} or in your
+current directory. To add the directory containing PSCP to your
+\c{PATH} environment variable, type into the console window:
+
+\c set PATH=C:\path\to\putty\directory;%PATH%
+
+This will only work for the lifetime of that particular console
+window. To set your \c{PATH} more permanently on Windows NT, 2000,
+and XP, use the Environment tab of the System Control Panel. On
+Windows 95, 98, and ME, you will need to edit your \i\c{AUTOEXEC.BAT}
+to include a \c{set} command like the one above.
+
+\H{pscp-usage} PSCP Usage
+
+Once you've got a console window to type into, you can just type
+\c{pscp} on its own to bring up a usage message. This tells you the
+version of PSCP you're using, and gives you a brief summary of how to
+use PSCP:
+
+\c Z:\owendadmin>pscp
+\c PuTTY Secure Copy client
+\c Release 0.60
+\c Usage: pscp [options] [user@]host:source target
+\c pscp [options] source [source...] [user@]host:target
+\c pscp [options] -ls [user@]host:filespec
+\c Options:
+\c -V print version information and exit
+\c -pgpfp print PGP key fingerprints and exit
+\c -p preserve file attributes
+\c -q quiet, don't show statistics
+\c -r copy directories recursively
+\c -v show verbose messages
+\c -load sessname Load settings from saved session
+\c -P port connect to specified port
+\c -l user connect with specified username
+\c -pw passw login with specified password
+\c -1 -2 force use of particular SSH protocol version
+\c -4 -6 force use of IPv4 or IPv6
+\c -C enable compression
+\c -i key private key file for authentication
+\c -noagent disable use of Pageant
+\c -agent enable use of Pageant
+\c -batch disable all interactive prompts
+\c -unsafe allow server-side wildcards (DANGEROUS)
+\c -sftp force use of SFTP protocol
+\c -scp force use of SCP protocol
+
+(PSCP's interface is much like the Unix \c{scp} command, if you're
+familiar with that.)
+
+\S{pscp-usage-basics} The basics
+
+To \I{receiving files}receive (a) file(s) from a remote server:
+
+\c pscp [options] [user@]host:source target
+
+So to copy the file \c{/etc/hosts} from the server \c{example.com} as
+user \c{fred} to the file \c{c:\\temp\\example-hosts.txt}, you would type:
+
+\c pscp fred@example.com:/etc/hosts c:\temp\example-hosts.txt
+
+To \I{sending files}send (a) file(s) to a remote server:
+
+\c pscp [options] source [source...] [user@]host:target
+
+So to copy the local file \c{c:\\documents\\foo.txt} to the server
+\c{example.com} as user \c{fred} to the file \c{/tmp/foo} you would
+type:
+
+\c pscp c:\documents\foo.txt fred@example.com:/tmp/foo
+
+You can use \i{wildcards} to transfer multiple files in either
+direction, like this:
+
+\c pscp c:\documents\*.doc fred@example.com:docfiles
+\c pscp fred@example.com:source/*.c c:\source
+
+However, in the second case (using a wildcard for multiple remote
+files) you may see a warning saying something like \q{warning:
+remote host tried to write to a file called \cq{terminal.c} when we
+requested a file called \cq{*.c}. If this is a wildcard, consider
+upgrading to SSH-2 or using the \cq{-unsafe} option. Renaming of
+this file has been disallowed}.
+
+This is due to a \I{security risk}fundamental insecurity in the old-style
+\i{SCP protocol}: the client sends the wildcard string (\c{*.c}) to the
+server, and the server sends back a sequence of file names that
+match the wildcard pattern. However, there is nothing to stop the
+server sending back a \e{different} pattern and writing over one of
+your other files: if you request \c{*.c}, the server might send back
+the file name \c{AUTOEXEC.BAT} and install a virus for you. Since
+the wildcard matching rules are decided by the server, the client
+cannot reliably verify that the filenames sent back match the
+pattern.
+
+PSCP will attempt to use the newer \i{SFTP} protocol (part of SSH-2)
+where possible, which does not suffer from this security flaw. If
+you are talking to an SSH-2 server which supports SFTP, you will
+never see this warning. (You can force use of the SFTP protocol,
+if available, with \c{-sftp} - see \k{pscp-usage-options-backend}.)
+
+If you really need to use a server-side wildcard with an SSH-1
+server, you can use the \i\c{-unsafe} command line option with PSCP:
+
+\c pscp -unsafe fred@example.com:source/*.c c:\source
+
+This will suppress the warning message and the file transfer will
+happen. However, you should be aware that by using this option you
+are giving the server the ability to write to \e{any} file in the
+target directory, so you should only use this option if you trust
+the server administrator not to be malicious (and not to let the
+server machine be cracked by malicious people). Alternatively, do
+any such download in a newly created empty directory. (Even in
+\q{unsafe} mode, PSCP will still protect you against the server
+trying to get out of that directory using pathnames including
+\cq{..}.)
+
+\S2{pscp-usage-basics-user} \c{user}
+
+The \i{login name} on the remote server. If this is omitted, and \c{host}
+is a PuTTY saved session, PSCP will use any username specified by that
+saved session. Otherwise, PSCP will attempt to use the local Windows
+username.
+
+\S2{pscp-usage-basics-host} \I{hostname}\c{host}
+
+The name of the remote server, or the name of an existing PuTTY saved
+session. In the latter case, the session's settings for hostname, port
+number, cipher type and username will be used.
+
+\S2{pscp-usage-basics-source} \c{source}
+
+One or more source files. \ii{Wildcards} are allowed. The syntax of
+wildcards depends on the system to which they apply, so if you are
+copying \e{from} a Windows system \e{to} a UNIX system, you should use
+Windows wildcard syntax (e.g. \c{*.*}), but if you are copying \e{from}
+a UNIX system \e{to} a Windows system, you would use the wildcard
+syntax allowed by your UNIX shell (e.g. \c{*}).
+
+If the source is a remote server and you do not specify a full
+pathname (in UNIX, a pathname beginning with a \c{/} (slash)
+character), what you specify as a source will be interpreted relative
+to your \i{home directory} on the remote server.
+
+\S2{pscp-usage-basics-target} \c{target}
+
+The filename or directory to put the file(s). When copying from a
+remote server to a local host, you may wish simply to place the
+file(s) in the current directory. To do this, you should specify a
+target of \c{.}. For example:
+
+\c pscp fred@example.com:/home/tom/.emacs .
+
+...would copy \c{/home/tom/.emacs} on the remote server to the current
+directory.
+
+As with the \c{source} parameter, if the target is on a remote server
+and is not a full path name, it is interpreted relative to your home
+directory on the remote server.
+
+\S{pscp-usage-options} Options
+
+PSCP accepts all the general command line options supported by the
+PuTTY tools, except the ones which make no sense in a file transfer
+utility. See \k{using-general-opts} for a description of these
+options. (The ones not supported by PSCP are clearly marked.)
+
+PSCP also supports some of its own options. The following sections
+describe PSCP's specific command-line options.
+
+\S2{pscp-usage-options-ls}\I{-ls-PSCP}\c{-ls} \I{listing files}list remote files
+
+If the \c{-ls} option is given, no files are transferred; instead,
+remote files are listed. Only a hostname specification and
+optional remote file specification need be given. For example:
+
+\c pscp -ls fred@example.com:dir1
+
+The SCP protocol does not contain within itself a means of listing
+files. If SCP is in use, this option therefore assumes that the
+server responds appropriately to the command \c{ls\_-la};
+this may not work with all servers.
+
+If SFTP is in use, this option should work with all servers.
+
+\S2{pscp-usage-options-p}\I{-p-PSCP}\c{-p} \i{preserve file attributes}
+
+By default, files copied with PSCP are \i{timestamp}ed with the date and
+time they were copied. The \c{-p} option preserves the original
+timestamp on copied files.
+
+\S2{pscp-usage-options-q}\I{-q-PSCP}\c{-q} quiet, don't show \i{statistics}
+
+By default, PSCP displays a meter displaying the progress of the
+current transfer:
+
+\c mibs.tar | 168 kB | 84.0 kB/s | ETA: 00:00:13 | 13%
+
+The fields in this display are (from left to right), filename, size
+(in kilobytes) of file transferred so far, estimate of how fast the
+file is being transferred (in kilobytes per second), estimated time
+that the transfer will be complete, and percentage of the file so far
+transferred. The \c{-q} option to PSCP suppresses the printing of
+these statistics.
+
+\S2{pscp-usage-options-r}\I{-r-PSCP}\c{-r} copies directories \i{recursive}ly
+
+By default, PSCP will only copy files. Any directories you specify to
+copy will be skipped, as will their contents. The \c{-r} option tells
+PSCP to descend into any directories you specify, and to copy them and
+their contents. This allows you to use PSCP to transfer whole
+directory structures between machines.
+
+\S2{pscp-usage-options-batch}\I{-batch-PSCP}\c{-batch} avoid interactive prompts
+
+If you use the \c{-batch} option, PSCP will never give an
+interactive prompt while establishing the connection. If the
+server's host key is invalid, for example (see \k{gs-hostkey}), then
+the connection will simply be abandoned instead of asking you what
+to do next.
+
+This may help PSCP's behaviour when it is used in automated
+scripts: using \c{-batch}, if something goes wrong at connection
+time, the batch job will fail rather than hang.
+
+\S2{pscp-usage-options-backend}\i\c{-sftp}, \i\c{-scp} force use of
+particular protocol
+
+As mentioned in \k{pscp-usage-basics}, there are two different file
+transfer protocols in use with SSH. Despite its name, PSCP (like many
+other ostensible \cw{scp} clients) can use either of these protocols.
+
+The older \i{SCP protocol} does not have a written specification and
+leaves a lot of detail to the server platform. \ii{Wildcards} are expanded
+on the server. The simple design means that any wildcard specification
+supported by the server platform (such as brace expansion) can be
+used, but also leads to interoperability issues such as with filename
+quoting (for instance, where filenames contain spaces), and also the
+security issue described in \k{pscp-usage-basics}.
+
+The newer \i{SFTP} protocol, which is usually associated with SSH-2
+servers, is specified in a more platform independent way, and leaves
+issues such as wildcard syntax up to the client. (PuTTY's SFTP
+wildcard syntax is described in \k{psftp-wildcards}.) This makes it
+more consistent across platforms, more suitable for scripting and
+automation, and avoids security issues with wildcard matching.
+
+Normally PSCP will attempt to use the SFTP protocol, and only fall
+back to the SCP protocol if SFTP is not available on the server.
+
+The \c{-scp} option forces PSCP to use the SCP protocol or quit.
+
+The \c{-sftp} option forces PSCP to use the SFTP protocol or quit.
+When this option is specified, PSCP looks harder for an SFTP server,
+which may allow use of SFTP with SSH-1 depending on server setup.
+
+\S{pscp-retval} \ii{Return value}
+
+PSCP returns an \i\cw{ERRORLEVEL} of zero (success) only if the files
+were correctly transferred. You can test for this in a \i{batch file},
+using code such as this:
+
+\c pscp file*.* user@hostname:
+\c if errorlevel 1 echo There was an error
+
+\S{pscp-pubkey} Using \i{public key authentication} with PSCP
+
+Like PuTTY, PSCP can authenticate using a public key instead of a
+password. There are three ways you can do this.
+
+Firstly, PSCP can use PuTTY saved sessions in place of hostnames
+(see \k{pscp-usage-basics-host}). So you would do this:
+
+\b Run PuTTY, and create a PuTTY saved session (see
+\k{config-saving}) which specifies your private key file (see
+\k{config-ssh-privkey}). You will probably also want to specify a
+username to log in as (see \k{config-username}).
+
+\b In PSCP, you can now use the name of the session instead of a
+hostname: type \c{pscp sessionname:file localfile}, where
+\c{sessionname} is replaced by the name of your saved session.
+
+Secondly, you can supply the name of a private key file on the command
+line, with the \c{-i} option. See \k{using-cmdline-identity} for more
+information.
+
+Thirdly, PSCP will attempt to authenticate using Pageant if Pageant
+is running (see \k{pageant}). So you would do this:
+
+\b Ensure Pageant is running, and has your private key stored in it.
+
+\b Specify a user and host name to PSCP as normal. PSCP will
+automatically detect Pageant and try to use the keys within it.
+
+For more general information on public-key authentication, see
+\k{pubkey}.
diff --git a/puttysrc/DOC/PSFTP.BUT b/puttysrc/DOC/PSFTP.BUT
new file mode 100644
index 0000000..a1d01ed
--- /dev/null
+++ b/puttysrc/DOC/PSFTP.BUT
@@ -0,0 +1,588 @@
+\define{versionidpsftp} \versionid $Id: psftp.but 6717 2006-05-26 12:45:21Z simon $
+
+\C{psftp} Using \i{PSFTP} to transfer files securely
+
+\i{PSFTP}, the PuTTY SFTP client, is a tool for \i{transferring files}
+securely between computers using an SSH connection.
+
+PSFTP differs from PSCP in the following ways:
+
+\b PSCP should work on virtually every SSH server. PSFTP uses the
+new \i{SFTP} protocol, which is a feature of SSH-2 only. (PSCP will also
+use this protocol if it can, but there is an SSH-1 equivalent it can
+fall back to if it cannot.)
+
+\b PSFTP allows you to run an interactive file transfer session,
+much like the Windows \i\c{ftp} program. You can list the contents of
+directories, browse around the file system, issue multiple \c{get}
+and \c{put} commands, and eventually log out. By contrast, PSCP is
+designed to do a single file transfer operation and immediately
+terminate.
+
+\H{psftp-starting} Starting PSFTP
+
+The usual way to start PSFTP is from a command prompt, much like
+PSCP. To do this, it will need either to be on your \i{\c{PATH}} or
+in your current directory. To add the directory containing PSFTP to
+your \c{PATH} environment variable, type into the console window:
+
+\c set PATH=C:\path\to\putty\directory;%PATH%
+
+Unlike PSCP, however, PSFTP has no complex command-line syntax; you
+just specify a host name and perhaps a user name:
+
+\c psftp server.example.com
+
+or perhaps
+
+\c psftp fred@server.example.com
+
+Alternatively, if you just type \c{psftp} on its own (or
+double-click the PSFTP icon in the Windows GUI), you will see the
+PSFTP prompt, and a message telling you PSFTP has not connected to
+any server:
+
+\c C:\>psftp
+\c psftp: no hostname specified; use "open host.name" to connect
+\c psftp>
+
+At this point you can type \c{open server.example.com} or \c{open
+fred@server.example.com} to start a session.
+
+PSFTP accepts all the general command line options supported by the
+PuTTY tools, except the ones which make no sense in a file transfer
+utility. See \k{using-general-opts} for a description of these
+options. (The ones not supported by PSFTP are clearly marked.)
+
+PSFTP also supports some of its own options. The following sections
+describe PSFTP's specific command-line options.
+
+\S{psftp-option-b} \I{-b-PSFTP}\c{-b}: specify a file containing batch commands
+
+In normal operation, PSFTP is an interactive program which displays
+a command line and accepts commands from the keyboard.
+
+If you need to do automated tasks with PSFTP, you would probably
+prefer to \I{batch scripts in PSFTP}specify a set of commands in
+advance and have them executed automatically. The \c{-b} option
+allows you to do this. You use it with a file name containing batch
+commands. For example, you might create a file called \c{myscript.scr}
+containing lines like this:
+
+\c cd /home/ftp/users/jeff
+\c del jam-old.tar.gz
+\c ren jam.tar.gz jam-old.tar.gz
+\c put jam.tar.gz
+\c chmod a+r jam.tar.gz
+
+and then you could run the script by typing
+
+\c psftp user@hostname -b myscript.scr
+
+When you run a batch script in this way, PSFTP will abort the script
+if any command fails to complete successfully. To change this
+behaviour, you can add the \c{-be} option (\k{psftp-option-be}).
+
+PSFTP will terminate after it finishes executing the batch script.
+
+\S{psftp-option-bc} \I{-bc-PSFTP}\c{-bc}: display batch commands as they are run
+
+The \c{-bc} option alters what PSFTP displays while processing a
+batch script specified with \c{-b}. With the \c{-bc} option, PSFTP
+will display prompts and commands just as if the commands had been
+typed at the keyboard. So instead of seeing this:
+
+\c C:\>psftp fred@hostname -b batchfile
+\c Sent username "fred"
+\c Remote working directory is /home/fred
+\c Listing directory /home/fred/lib
+\c drwxrwsr-x 4 fred fred 1024 Sep 6 10:42 .
+\c drwxr-sr-x 25 fred fred 2048 Dec 14 09:36 ..
+\c drwxrwsr-x 3 fred fred 1024 Apr 17 2000 jed
+\c lrwxrwxrwx 1 fred fred 24 Apr 17 2000 timber
+\c drwxrwsr-x 2 fred fred 1024 Mar 13 2000 trn
+
+you might see this:
+
+\c C:\>psftp fred@hostname -bc -b batchfile
+\c Sent username "fred"
+\c Remote working directory is /home/fred
+\c psftp> dir lib
+\c Listing directory /home/fred/lib
+\c drwxrwsr-x 4 fred fred 1024 Sep 6 10:42 .
+\c drwxr-sr-x 25 fred fred 2048 Dec 14 09:36 ..
+\c drwxrwsr-x 3 fred fred 1024 Apr 17 2000 jed
+\c lrwxrwxrwx 1 fred fred 24 Apr 17 2000 timber
+\c drwxrwsr-x 2 fred fred 1024 Mar 13 2000 trn
+\c psftp> quit
+
+\S{psftp-option-be} \I{-be-PSFTP}\c{-be}: continue batch processing on errors
+
+When running a batch file, this additional option causes PSFTP to
+continue processing even if a command fails to complete successfully.
+
+You might want this to happen if you wanted to delete a file and
+didn't care if it was already not present, for example.
+
+\S{psftp-usage-options-batch} \I{-batch-PSFTP}\c{-batch}: avoid
+interactive prompts
+
+If you use the \c{-batch} option, PSFTP will never give an
+interactive prompt while establishing the connection. If the
+server's host key is invalid, for example (see \k{gs-hostkey}), then
+the connection will simply be abandoned instead of asking you what
+to do next.
+
+This may help PSFTP's behaviour when it is used in automated
+scripts: using \c{-batch}, if something goes wrong at connection
+time, the batch job will fail rather than hang.
+
+\H{psftp-commands} Running PSFTP
+
+Once you have started your PSFTP session, you will see a \c{psftp>}
+prompt. You can now type commands to perform file-transfer
+functions. This section lists all the available commands.
+
+\S{psftp-quoting} \I{quoting, in PSFTP}General quoting rules for PSFTP commands
+
+Most PSFTP commands are considered by the PSFTP command interpreter
+as a sequence of words, separated by spaces. For example, the
+command \c{ren oldfilename newfilename} splits up into three words:
+\c{ren} (the command name), \c{oldfilename} (the name of the file to
+be renamed), and \c{newfilename} (the new name to give the file).
+
+Sometimes you will need to specify \I{spaces in filenames}file names
+that \e{contain} spaces. In order to do this, you can surround
+the file name with double quotes. This works equally well for
+local file names and remote file names:
+
+\c psftp> get "spacey file name.txt" "save it under this name.txt"
+
+The double quotes themselves will not appear as part of the file
+names; they are removed by PSFTP and their only effect is to stop
+the spaces inside them from acting as word separators.
+
+If you need to \e{use} a double quote (on some types of remote
+system, such as Unix, you are allowed to use double quotes in file
+names), you can do this by doubling it. This works both inside and
+outside double quotes. For example, this command
+
+\c psftp> ren ""this"" "a file with ""quotes"" in it"
+
+will take a file whose current name is \c{"this"} (with a double
+quote character at the beginning and the end) and rename it to a
+file whose name is \c{a file with "quotes" in it}.
+
+(The one exception to the PSFTP quoting rules is the \c{!} command,
+which passes its command line straight to Windows without splitting
+it up into words at all. See \k{psftp-cmd-pling}.)
+
+\S{psftp-wildcards} Wildcards in PSFTP
+
+Several commands in PSFTP support \q{\i{wildcards}} to select multiple
+files.
+
+For \e{local} file specifications (such as the first argument to
+\c{put}), wildcard rules for the local operating system are used. For
+instance, PSFTP running on Windows might require the use of \c{*.*}
+where PSFTP on Unix would need \c{*}.
+
+For \e{remote} file specifications (such as the first argument to
+\c{get}), PSFTP uses a standard wildcard syntax (similar to \i{POSIX}
+wildcards):
+
+\b \c{*} matches any sequence of characters (including a zero-length
+sequence).
+
+\b \c{?} matches exactly one character.
+
+\b \c{[abc]} matches exactly one character which can be \cw{a},
+\cw{b}, or \cw{c}.
+
+\lcont{
+
+\c{[a-z]} matches any character in the range \cw{a} to \cw{z}.
+
+\c{[^abc]} matches a single character that is \e{not} \cw{a}, \cw{b},
+or \cw{c}.
+
+Special cases: \c{[-a]} matches a literal hyphen (\cw{-}) or \cw{a};
+\c{[^-a]} matches all other characters. \c{[a^]} matches a literal
+caret (\cw{^}) or \cw{a}.
+
+}
+
+\b \c{\\} (backslash) before any of the above characters (or itself)
+removes that character's special meaning.
+
+A leading period (\cw{.}) on a filename is not treated specially,
+unlike in some Unix contexts; \c{get *} will fetch all files, whether
+or not they start with a leading period.
+
+\S{psftp-cmd-open} The \c{open} command: start a session
+
+If you started PSFTP by double-clicking in the GUI, or just by
+typing \c{psftp} at the command line, you will need to open a
+connection to an SFTP server before you can issue any other
+commands (except \c{help} and \c{quit}).
+
+To create a connection, type \c{open host.name}, or if you need to
+specify a user name as well you can type \c{open user@host.name}.
+
+Once you have issued this command, you will not be able to issue it
+again, \e{even} if the command fails (for example, if you mistype
+the host name or the connection times out). So if the connection is
+not opened successfully, PSFTP will terminate immediately.
+
+\S{psftp-cmd-quit} The \c{quit} command: end your session
+
+When you have finished your session, type the command \c{quit} to
+close the connection, terminate PSFTP and return to the command line
+(or just close the PSFTP console window if you started it from the
+GUI).
+
+You can also use the \c{bye} and \c{exit} commands, which have
+exactly the same effect.
+
+\S{psftp-cmd-close} The \c{close} command: close your connection
+
+If you just want to close the network connection but keep PSFTP
+running, you can use the \c{close} command. You can then use the
+\c{open} command to open a new connection.
+
+\S{psftp-cmd-help} The \c{help} command: get quick online help
+
+If you type \c{help}, PSFTP will give a short list of the available
+commands.
+
+If you type \c{help} with a command name - for example, \c{help get}
+- then PSFTP will give a short piece of help on that particular
+command.
+
+\S{psftp-cmd-cd} The \c{cd} and \c{pwd} commands: changing the
+remote \i{working directory}
+
+PSFTP maintains a notion of your \q{working directory} on the
+server. This is the default directory that other commands will
+operate on. For example, if you type \c{get filename.dat} then PSFTP
+will look for \c{filename.dat} in your remote working directory on
+the server.
+
+To change your remote working directory, use the \c{cd} command. If
+you don't provide an argument, \c{cd} will return you to your home
+directory on the server (more precisely, the remote directory you were
+in at the start of the connection).
+
+To display your current remote working directory, type \c{pwd}.
+
+\S{psftp-cmd-lcd} The \c{lcd} and \c{lpwd} commands: changing the
+local \i{working directory}
+
+As well as having a working directory on the remote server, PSFTP
+also has a working directory on your local machine (just like any
+other Windows process). This is the default local directory that
+other commands will operate on. For example, if you type \c{get
+filename.dat} then PSFTP will save the resulting file as
+\c{filename.dat} in your local working directory.
+
+To change your local working directory, use the \c{lcd} command. To
+display your current local working directory, type \c{lpwd}.
+
+\S{psftp-cmd-get} The \c{get} command: fetch a file from the server
+
+To \i{download a file} from the server and store it on your local PC,
+you use the \c{get} command.
+
+In its simplest form, you just use this with a file name:
+
+\c get myfile.dat
+
+If you want to store the file locally under a different name,
+specify the local file name after the remote one:
+
+\c get myfile.dat newname.dat
+
+This will fetch the file on the server called \c{myfile.dat}, but
+will save it to your local machine under the name \c{newname.dat}.
+
+To fetch an entire directory \i{recursive}ly, you can use the \c{-r}
+option:
+
+\c get -r mydir
+\c get -r mydir newname
+
+(If you want to fetch a file whose name starts with a hyphen, you
+may have to use the \c{--} special argument, which stops \c{get}
+from interpreting anything as a switch after it. For example,
+\cq{get -- -silly-name-}.)
+
+\S{psftp-cmd-put} The \c{put} command: send a file to the server
+
+To \i{upload a file} to the server from your local PC, you use the
+\c{put} command.
+
+In its simplest form, you just use this with a file name:
+
+\c put myfile.dat
+
+If you want to store the file remotely under a different name,
+specify the remote file name after the local one:
+
+\c put myfile.dat newname.dat
+
+This will send the local file called \c{myfile.dat}, but will store
+it on the server under the name \c{newname.dat}.
+
+To send an entire directory \i{recursive}ly, you can use the \c{-r}
+option:
+
+\c put -r mydir
+\c put -r mydir newname
+
+(If you want to send a file whose name starts with a hyphen, you may
+have to use the \c{--} special argument, which stops \c{put} from
+interpreting anything as a switch after it. For example, \cq{put --
+-silly-name-}.)
+
+\S{psftp-cmd-mgetput} The \c{mget} and \c{mput} commands: fetch or
+send multiple files
+
+\c{mget} works almost exactly like \c{get}, except that it allows
+you to specify more than one file to fetch at once. You can do this
+in two ways:
+
+\b by giving two or more explicit file names (\cq{mget file1.txt
+file2.txt})
+
+\b by using a wildcard (\cq{mget *.txt}).
+
+Every argument to \c{mget} is treated as the name of a file to fetch
+(unlike \c{get}, which will interpret at most one argument like
+that, and a second argument will be treated as an alternative name
+under which to store the retrieved file), or a \i{wildcard} expression
+matching more than one file.
+
+The \c{-r} and \c{--} options from \c{get} are also available with
+\c{mget}.
+
+\c{mput} is similar to \c{put}, with the same differences.
+
+\S{psftp-cmd-regetput} The \c{reget} and \c{reput} commands:
+\i{resuming file transfers}
+
+If a file transfer fails half way through, and you end up with half
+the file stored on your disk, you can resume the file transfer using
+the \c{reget} and \c{reput} commands. These work exactly like the
+\c{get} and \c{put} commands, but they check for the presence of the
+half-written destination file and start transferring from where the
+last attempt left off.
+
+The syntax of \c{reget} and \c{reput} is exactly the same as the
+syntax of \c{get} and \c{put}:
+
+\c reget myfile.dat
+\c reget myfile.dat newname.dat
+\c reget -r mydir
+
+These commands are intended mainly for resuming interrupted transfers.
+They assume that the remote file or directory structure has not
+changed in any way; if there have been changes, you may end up with
+corrupted files. In particular, the \c{-r} option will not pick up
+changes to files or directories already transferred in full.
+
+\S{psftp-cmd-dir} The \c{dir} command: \I{listing files}list remote files
+
+To list the files in your remote working directory, just type
+\c{dir}.
+
+You can also list the contents of a different directory by typing
+\c{dir} followed by the directory name:
+
+\c dir /home/fred
+\c dir sources
+
+And you can list a subset of the contents of a directory by
+providing a wildcard:
+
+\c dir /home/fred/*.txt
+\c dir sources/*.c
+
+The \c{ls} command works exactly the same way as \c{dir}.
+
+\S{psftp-cmd-chmod} The \c{chmod} command: change permissions on
+remote files
+
+\I{changing permissions on files}PSFTP
+allows you to modify the file permissions on files and
+directories on the server. You do this using the \c{chmod} command,
+which works very much like the Unix \c{chmod} command.
+
+The basic syntax is \c{chmod modes file}, where \c{modes} represents
+a modification to the file permissions, and \c{file} is the filename
+to modify. You can specify multiple files or wildcards. For example:
+
+\c chmod go-rwx,u+w privatefile
+\c chmod a+r public*
+\c chmod 640 groupfile1 groupfile2
+
+The \c{modes} parameter can be a set of octal digits in the Unix
+style. (If you don't know what this means, you probably don't want
+to be using it!) Alternatively, it can be a list of permission
+modifications, separated by commas. Each modification consists of:
+
+\b The people affected by the modification. This can be \c{u} (the
+owning user), \c{g} (members of the owning group), or \c{o}
+(everybody else - \q{others}), or some combination of those. It can
+also be \c{a} (\q{all}) to affect everybody at once.
+
+\b A \c{+} or \c{-} sign, indicating whether permissions are to be
+added or removed.
+
+\b The actual permissions being added or removed. These can be
+\I{read permission}\c{r} (permission to read the file),
+\I{write permission}\c{w} (permission to write to the file), and
+\I{execute permission}\c{x} (permission to execute the file, or in
+the case of a directory, permission to access files within the
+directory).
+
+So the above examples would do:
+
+\b The first example: \c{go-rwx} removes read, write and execute
+permissions for members of the owning group and everybody else (so
+the only permissions left are the ones for the file owner). \c{u+w}
+adds write permission for the file owner.
+
+\b The second example: \c{a+r} adds read permission for everybody to
+all files and directories starting with \q{public}.
+
+In addition to all this, there are a few extra special cases for
+\i{Unix} systems. On non-Unix systems these are unlikely to be useful:
+
+\b You can specify \c{u+s} and \c{u-s} to add or remove the Unix
+\i{set-user-ID bit}. This is typically only useful for special purposes;
+refer to your Unix documentation if you're not sure about it.
+
+\b You can specify \c{g+s} and \c{g-s} to add or remove the Unix
+\i{set-group-ID bit}. On a file, this works similarly to the set-user-ID
+bit (see your Unix documentation again); on a directory it ensures
+that files created in the directory are accessible by members of the
+group that owns the directory.
+
+\b You can specify \c{+t} and \c{-t} to add or remove the Unix
+\q{\i{sticky bit}}. When applied to a directory, this means that the
+owner of a file in that directory can delete the file (whereas
+normally only the owner of the \e{directory} would be allowed to).
+
+\S{psftp-cmd-del} The \c{del} command: delete remote files
+
+To \I{deleting files}delete a file on the server, type \c{del} and
+then the filename or filenames:
+
+\c del oldfile.dat
+\c del file1.txt file2.txt
+\c del *.o
+
+Files will be deleted without further prompting, even if multiple files
+are specified.
+
+\c{del} will only delete files. You cannot use it to delete
+directories; use \c{rmdir} for that.
+
+The \c{rm} command works exactly the same way as \c{del}.
+
+\S{psftp-cmd-mkdir} The \c{mkdir} command: create remote directories
+
+To \i{create a directory} on the server, type \c{mkdir} and then the
+directory name:
+
+\c mkdir newstuff
+
+You can specify multiple directories to create at once:
+
+\c mkdir dir1 dir2 dir3
+
+\S{psftp-cmd-rmdir} The \c{rmdir} command: remove remote directories
+
+To \i{remove a directory} on the server, type \c{rmdir} and then the
+directory name or names:
+
+\c rmdir oldstuff
+\c rmdir *.old ancient
+
+Directories will be deleted without further prompting, even if
+multiple directories are specified.
+
+Most SFTP servers will probably refuse to remove a directory if the
+directory has anything in it, so you will need to delete the
+contents first.
+
+\S{psftp-cmd-mv} The \c{mv} command: move and \i{rename remote files}
+
+To rename a single file on the server, type \c{mv}, then the current
+file name, and then the new file name:
+
+\c mv oldfile newname
+
+You can also move the file into a different directory and change the
+name:
+
+\c mv oldfile dir/newname
+
+To move one or more files into an existing subdirectory, specify the
+files (using wildcards if desired), and then the destination
+directory:
+
+\c mv file dir
+\c mv file1 dir1/file2 dir2
+\c mv *.c *.h ..
+
+The \c{rename} and \c{ren} commands work exactly the same way as
+\c{mv}.
+
+\S{psftp-cmd-pling} The \c{!} command: run a \i{local Windows command}
+
+You can run local Windows commands using the \c{!} command. This is
+the only PSFTP command that is not subject to the command quoting
+rules given in \k{psftp-quoting}. If any command line begins with
+the \c{!} character, then the rest of the line will be passed
+straight to Windows without further translation.
+
+For example, if you want to move an existing copy of a file out of
+the way before downloading an updated version, you might type:
+
+\c psftp> !ren myfile.dat myfile.bak
+\c psftp> get myfile.dat
+
+using the Windows \c{ren} command to rename files on your local PC.
+
+\H{psftp-pubkey} Using \i{public key authentication} with PSFTP
+
+Like PuTTY, PSFTP can authenticate using a public key instead of a
+password. There are three ways you can do this.
+
+Firstly, PSFTP can use PuTTY saved sessions in place of hostnames.
+So you might do this:
+
+\b Run PuTTY, and create a PuTTY saved session (see
+\k{config-saving}) which specifies your private key file (see
+\k{config-ssh-privkey}). You will probably also want to specify a
+username to log in as (see \k{config-username}).
+
+\b In PSFTP, you can now use the name of the session instead of a
+hostname: type \c{psftp sessionname}, where \c{sessionname} is
+replaced by the name of your saved session.
+
+Secondly, you can supply the name of a private key file on the command
+line, with the \c{-i} option. See \k{using-cmdline-identity} for more
+information.
+
+Thirdly, PSFTP will attempt to authenticate using Pageant if Pageant
+is running (see \k{pageant}). So you would do this:
+
+\b Ensure Pageant is running, and has your private key stored in it.
+
+\b Specify a user and host name to PSFTP as normal. PSFTP will
+automatically detect Pageant and try to use the keys within it.
+
+For more general information on public-key authentication, see
+\k{pubkey}.
diff --git a/puttysrc/DOC/PUBKEY.BUT b/puttysrc/DOC/PUBKEY.BUT
new file mode 100644
index 0000000..00a4508
--- /dev/null
+++ b/puttysrc/DOC/PUBKEY.BUT
@@ -0,0 +1,442 @@
+\define{versionidpubkey} \versionid $Id: pubkey.but 6905 2006-11-15 12:56:48Z jacob $
+
+\C{pubkey} Using public keys for SSH authentication
+
+\H{pubkey-intro} \ii{Public key authentication} - an introduction
+
+Public key authentication is an alternative means of identifying
+yourself to a login server, instead of typing a password. It is more
+secure and more flexible, but more difficult to set up.
+
+In conventional password authentication, you prove you are who you
+claim to be by proving that you know the correct password. The only
+way to prove you know the password is to tell the server what you
+think the password is. This means that if the server has been
+hacked, or \i\e{spoofed} (see \k{gs-hostkey}), an attacker can learn
+your password.
+
+Public key authentication solves this problem. You generate a \i\e{key
+pair}, consisting of a \i{public key} (which everybody is allowed to
+know) and a \i{private key} (which you keep secret and do not give to
+anybody). The private key is able to generate \i\e{signatures}.
+A signature created using your private key cannot be forged by
+anybody who does not have that key; but anybody who has your public
+key can verify that a particular signature is genuine.
+
+So you generate a key pair on your own computer, and you copy the
+public key to the server. Then, when the server asks you to prove
+who you are, PuTTY can generate a signature using your private key.
+The server can verify that signature (since it has your public key)
+and allow you to log in. Now if the server is hacked or spoofed, the
+attacker does not gain your private key or password; they only gain
+one signature. And signatures cannot be re-used, so they have gained
+nothing.
+
+There is a problem with this: if your private key is stored
+unprotected on your own computer, then anybody who gains access to
+\e{that} will be able to generate signatures as if they were you. So
+they will be able to log in to your server under your account. For
+this reason, your private key is usually \i\e{encrypted} when it is
+stored on your local machine, using a \i{passphrase} of your choice. In
+order to generate a signature, PuTTY must decrypt the key, so you
+have to type your passphrase.
+
+This can make public-key authentication less convenient than
+password authentication: every time you log in to the server,
+instead of typing a short password, you have to type a longer
+passphrase. One solution to this is to use an \i\e{authentication
+agent}, a separate program which holds decrypted private keys and
+generates signatures on request. PuTTY's authentication agent is
+called \i{Pageant}. When you begin a Windows session, you start Pageant
+and load your private key into it (typing your passphrase once). For
+the rest of your session, you can start PuTTY any number of times
+and Pageant will automatically generate signatures without you
+having to do anything. When you close your Windows session, Pageant
+shuts down, without ever having stored your decrypted private key on
+disk. Many people feel this is a good compromise between security
+and convenience. See \k{pageant} for further details.
+
+There is more than one \i{public-key algorithm} available. The most
+common is \i{RSA}, but others exist, notably \i{DSA} (otherwise known as
+DSS), the USA's federal Digital Signature Standard. The key types
+supported by PuTTY are described in \k{puttygen-keytype}.
+
+\H{pubkey-puttygen} Using \i{PuTTYgen}, the PuTTY key generator
+
+\cfg{winhelp-topic}{puttygen.general}
+
+PuTTYgen is a key generator. It \I{generating keys}generates pairs of
+public and private keys to be used with PuTTY, PSCP, and Plink, as well
+as the PuTTY authentication agent, Pageant (see \k{pageant}). PuTTYgen
+generates RSA and DSA keys.
+
+When you run PuTTYgen you will see a window where you have two
+choices: \q{Generate}, to generate a new public/private key pair, or
+\q{Load} to load in an existing private key.
+
+\S{puttygen-generating} Generating a new key
+
+This is a general outline of the procedure for generating a new key
+pair. The following sections describe the process in more detail.
+
+\b First, you need to select which type of key you want to generate,
+and also select the strength of the key. This is described in more
+detail in \k{puttygen-keytype} and
+\k{puttygen-strength}.
+
+\b Then press the \q{Generate} button, to actually generate the key.
+\K{puttygen-generate} describes this step.
+
+\b Once you have generated the key, select a comment field
+(\k{puttygen-comment}) and a passphrase (\k{puttygen-passphrase}).
+
+\b Now you're ready to save the private key to disk; press the
+\q{Save private key} button. (See \k{puttygen-savepriv}).
+
+Your key pair is now ready for use. You may also want to copy the
+public key to your server, either by copying it out of the \q{Public
+key for pasting into authorized_keys file} box (see
+\k{puttygen-pastekey}), or by using the \q{Save public key} button
+(\k{puttygen-savepub}). However, you don't need to do this
+immediately; if you want, you can load the private key back into
+PuTTYgen later (see \k{puttygen-load}) and the public key will be
+available for copying and pasting again.
+
+\K{pubkey-gettingready} describes the typical process of configuring
+PuTTY to attempt public-key authentication, and configuring your SSH
+server to accept it.
+
+\S{puttygen-keytype} Selecting the type of key
+
+\cfg{winhelp-topic}{puttygen.keytype}
+
+Before generating a key pair using PuTTYgen, you need to select
+which type of key you need. PuTTYgen currently supports three types
+of key:
+
+\b An \i{RSA} key for use with the SSH-1 protocol.
+
+\b An RSA key for use with the SSH-2 protocol.
+
+\b A \i{DSA} key for use with the SSH-2 protocol.
+
+The SSH-1 protocol only supports RSA keys; if you will be connecting
+using the SSH-1 protocol, you must select the first key type or your
+key will be completely useless.
+
+The SSH-2 protocol supports more than one key type. The two types
+supported by PuTTY are RSA and DSA.
+
+The PuTTY developers \e{strongly} recommend you use RSA.
+\I{security risk}\i{DSA} has an intrinsic weakness which makes it very
+easy to create a signature which contains enough information to give
+away the \e{private} key!
+This would allow an attacker to pretend to be you for any number of
+future sessions. PuTTY's implementation has taken very careful
+precautions to avoid this weakness, but we cannot be 100% certain we
+have managed it, and if you have the choice we strongly recommend
+using RSA keys instead.
+
+If you really need to connect to an SSH server which only supports
+DSA, then you probably have no choice but to use DSA. If you do use
+DSA, we recommend you do not use the same key to authenticate with
+more than one server.
+
+\S{puttygen-strength} Selecting the size (strength) of the key
+
+\cfg{winhelp-topic}{puttygen.bits}
+
+The \q{Number of bits} input box allows you to choose the strength
+of the key PuTTYgen will generate.
+
+Currently 1024 bits should be sufficient for most purposes.
+
+Note that an RSA key is generated by finding two primes of half the
+length requested, and then multiplying them together. For example,
+if you ask PuTTYgen for a 1024-bit RSA key, it will create two
+512-bit primes and multiply them. The result of this multiplication
+might be 1024 bits long, or it might be only 1023; so you may not
+get the exact length of key you asked for. This is perfectly normal,
+and you do not need to worry. The lengths should only ever differ by
+one, and there is no perceptible drop in security as a result.
+
+DSA keys are not created by multiplying primes together, so they
+should always be exactly the length you asked for.
+
+\S{puttygen-generate} The \q{Generate} button
+
+\cfg{winhelp-topic}{puttygen.generate}
+
+Once you have chosen the type of key you want, and the strength of
+the key, press the \q{Generate} button and PuTTYgen will begin the
+process of actually generating the key.
+
+First, a progress bar will appear and PuTTYgen will ask you to move
+the mouse around to generate randomness. Wave the mouse in circles
+over the blank area in the PuTTYgen window, and the progress bar
+will gradually fill up as PuTTYgen collects enough randomness. You
+don't need to wave the mouse in particularly imaginative patterns
+(although it can't hurt); PuTTYgen will collect enough randomness
+just from the fine detail of \e{exactly} how far the mouse has moved
+each time Windows samples its position.
+
+When the progress bar reaches the end, PuTTYgen will begin creating
+the key. The progress bar will reset to the start, and gradually
+move up again to track the progress of the key generation. It will
+not move evenly, and may occasionally slow down to a stop; this is
+unfortunately unavoidable, because key generation is a random
+process and it is impossible to reliably predict how long it will
+take.
+
+When the key generation is complete, a new set of controls will
+appear in the window to indicate this.
+
+\S{puttygen-fingerprint} The \q{\ii{Key fingerprint}} box
+
+\cfg{winhelp-topic}{puttygen.fingerprint}
+
+The \q{Key fingerprint} box shows you a fingerprint value for the
+generated key. This is derived cryptographically from the \e{public}
+key value, so it doesn't need to be kept secret.
+
+The fingerprint value is intended to be cryptographically secure, in
+the sense that it is computationally infeasible for someone to
+invent a second key with the same fingerprint, or to find a key with
+a particular fingerprint. So some utilities, such as the Pageant key
+list box (see \k{pageant-mainwin-keylist}) and the Unix \c{ssh-add}
+utility, will list key fingerprints rather than the whole public key.
+
+\S{puttygen-comment} Setting a comment for your key
+
+\cfg{winhelp-topic}{puttygen.comment}
+
+If you have more than one key and use them for different purposes,
+you don't need to memorise the key fingerprints in order to tell
+them apart. PuTTYgen allows you to enter a \e{comment} for your key,
+which will be displayed whenever PuTTY or Pageant asks you for the
+passphrase.
+
+The default comment format, if you don't specify one, contains the
+key type and the date of generation, such as \c{rsa-key-20011212}.
+Another commonly used approach is to use your name and the name of
+the computer the key will be used on, such as \c{simon@simons-pc}.
+
+To alter the key comment, just type your comment text into the
+\q{Key comment} box before saving the private key. If you want to
+change the comment later, you can load the private key back into
+PuTTYgen, change the comment, and save it again.
+
+\S{puttygen-passphrase} Setting a \i{passphrase} for your key
+
+\cfg{winhelp-topic}{puttygen.passphrase}
+
+The \q{Key passphrase} and \q{Confirm passphrase} boxes allow you to
+choose a passphrase for your key. The passphrase will be used to
+\i{encrypt} the key on disk, so you will not be able to use the key
+without first entering the passphrase.
+
+When you save the key, PuTTYgen will check that the \q{Key passphrase}
+and \q{Confirm passphrase} boxes both contain exactly the same
+passphrase, and will refuse to save the key otherwise.
+
+If you leave the passphrase fields blank, the key will be saved
+unencrypted. You should \e{not} do this without good reason; if you
+do, your private key file on disk will be all an attacker needs to
+gain access to any machine configured to accept that key. If you
+want to be able to \i{passwordless login}log in without having to
+type a passphrase every time, you should consider using Pageant
+(\k{pageant}) so that your decrypted key is only held in memory
+rather than on disk.
+
+Under special circumstances you may genuinely \e{need} to use a key
+with no passphrase; for example, if you need to run an automated
+batch script that needs to make an SSH connection, you can't be
+there to type the passphrase. In this case we recommend you generate
+a special key for each specific batch script (or whatever) that
+needs one, and on the server side you should arrange that each key
+is \e{restricted} so that it can only be used for that specific
+purpose. The documentation for your SSH server should explain how to
+do this (it will probably vary between servers).
+
+Choosing a good passphrase is difficult. Just as you shouldn't use a
+dictionary word as a password because it's easy for an attacker to
+run through a whole dictionary, you should not use a song lyric,
+quotation or other well-known sentence as a passphrase. \i{DiceWare}
+(\W{http://www.diceware.com/}\cw{www.diceware.com}) recommends using
+at least five words each generated randomly by rolling five dice,
+which gives over 2^64 possible passphrases and is probably not a bad
+scheme. If you want your passphrase to make grammatical sense, this
+cuts down the possibilities a lot and you should use a longer one as
+a result.
+
+\e{Do not forget your passphrase}. There is no way to recover it.
+
+\S{puttygen-savepriv} Saving your private key to a disk file
+
+\cfg{winhelp-topic}{puttygen.savepriv}
+
+Once you have generated a key, set a comment field and set a
+passphrase, you are ready to save your private key to disk.
+
+Press the \q{Save private key} button. PuTTYgen will put up a dialog
+box asking you where to save the file. Select a directory, type in a
+file name, and press \q{Save}.
+
+This file is in PuTTY's native format (\c{*.\i{PPK}}); it is the one you
+will need to tell PuTTY to use for authentication (see
+\k{config-ssh-privkey}) or tell Pageant to load (see
+\k{pageant-mainwin-addkey}).
+
+\S{puttygen-savepub} Saving your public key to a disk file
+
+\cfg{winhelp-topic}{puttygen.savepub}
+
+RFC 4716 specifies a \I{SSH-2 public key format}standard format for
+storing SSH-2 public keys on disk. Some SSH servers (such as
+\i\cw{ssh.com}'s) require a public key in this format in order to accept
+authentication with the corresponding private key. (Others, such as
+OpenSSH, use a different format; see \k{puttygen-pastekey}.)
+
+To save your public key in the SSH-2 standard format, press the
+\q{Save public key} button in PuTTYgen. PuTTYgen will put up a
+dialog box asking you where to save the file. Select a directory,
+type in a file name, and press \q{Save}.
+
+You will then probably want to copy the public key file to your SSH
+server machine. See \k{pubkey-gettingready} for general instructions
+on configuring public-key authentication once you have generated a
+key.
+
+If you use this option with an SSH-1 key, the file PuTTYgen saves
+will contain exactly the same text that appears in the \q{Public key
+for pasting} box. This is the only existing standard for SSH-1
+public keys.
+
+\S{puttygen-pastekey} \q{Public key for pasting into \i{authorized_keys
+file}}
+
+\cfg{winhelp-topic}{puttygen.pastekey}
+
+All SSH-1 servers require your public key to be given to it in a
+one-line format before it will accept authentication with your
+private key. The \i{OpenSSH} server also requires this for SSH-2.
+
+The \q{Public key for pasting into authorized_keys file} gives the
+public-key data in the correct one-line format. Typically you will
+want to select the entire contents of the box using the mouse, press
+Ctrl+C to copy it to the clipboard, and then paste the data into a
+PuTTY session which is already connected to the server.
+
+See \k{pubkey-gettingready} for general instructions on configuring
+public-key authentication once you have generated a key.
+
+\S{puttygen-load} Reloading a private key
+
+\cfg{winhelp-topic}{puttygen.load}
+
+PuTTYgen allows you to load an existing private key file into
+memory. If you do this, you can then change the passphrase and
+comment before saving it again; you can also make extra copies of
+the public key.
+
+To load an existing key, press the \q{Load} button. PuTTYgen will
+put up a dialog box where you can browse around the file system and
+find your key file. Once you select the file, PuTTYgen will ask you
+for a passphrase (if necessary) and will then display the key
+details in the same way as if it had just generated the key.
+
+If you use the Load command to load a foreign key format, it will
+work, but you will see a message box warning you that the key you
+have loaded is not a PuTTY native key. See \k{puttygen-conversions}
+for information about importing foreign key formats.
+
+\S{puttygen-conversions} Dealing with private keys in other formats
+
+\cfg{winhelp-topic}{puttygen.conversions}
+
+Most SSH-1 clients use a standard format for storing private keys on
+disk. PuTTY uses this format as well; so if you have generated an
+SSH-1 private key using OpenSSH or \cw{ssh.com}'s client, you can use
+it with PuTTY, and vice versa.
+
+However, SSH-2 private keys have no standard format. \I{OpenSSH private
+key format}OpenSSH and \I{ssh.com private key format}\cw{ssh.com} have
+different formats, and PuTTY's is different again.
+So a key generated with one client cannot immediately be used with
+another.
+
+Using the \I{importing keys}\q{Import} command from the \q{Conversions}
+menu, PuTTYgen can load SSH-2 private keys in OpenSSH's format and
+\cw{ssh.com}'s format. Once you have loaded one of these key types, you
+can then save it back out as a PuTTY-format key (\c{*.\i{PPK}}) so that
+you can use it with the PuTTY suite. The passphrase will be unchanged by this
+process (unless you deliberately change it). You may want to change
+the key comment before you save the key, since OpenSSH's SSH-2 key
+format contains no space for a comment and \cw{ssh.com}'s default
+comment format is long and verbose.
+
+PuTTYgen can also \i{export private keys} in OpenSSH format and in
+\cw{ssh.com} format. To do so, select one of the \q{Export} options
+from the \q{Conversions} menu. Exporting a key works exactly like
+saving it (see \k{puttygen-savepriv}) - you need to have typed your
+passphrase in beforehand, and you will be warned if you are about to
+save a key without a passphrase.
+
+Note that since only SSH-2 keys come in different formats, the export
+options are not available if you have generated an SSH-1 key.
+
+\H{pubkey-gettingready} Getting ready for public key authentication
+
+Connect to your SSH server using PuTTY with the SSH protocol. When the
+connection succeeds you will be prompted for your user name and
+password to login. Once logged in, you must configure the server to
+accept your public key for authentication:
+
+\b If your server is using the SSH-1 protocol, you should change
+into the \i\c{.ssh} directory and open the file \i\c{authorized_keys}
+with your favourite editor. (You may have to create this file if
+this is the first key you have put in it). Then switch to the
+PuTTYgen window, select all of the text in the \q{Public key for
+pasting into authorized_keys file} box (see \k{puttygen-pastekey}),
+and copy it to the clipboard (\c{Ctrl+C}). Then, switch back to the
+PuTTY window and insert the data into the open file, making sure it
+ends up all on one line. Save the file.
+
+\b If your server is \i{OpenSSH} and is using the SSH-2 protocol, you
+should follow the same instructions, except that in earlier versions
+of OpenSSH 2 the file might be called \c{authorized_keys2}. (In
+modern versions the same \c{authorized_keys} file is used for both
+SSH-1 and SSH-2 keys.)
+
+\b If your server is \i\cw{ssh.com}'s product and is using SSH-2, you
+need to save a \e{public} key file from PuTTYgen (see
+\k{puttygen-savepub}), and copy that into the \i\c{.ssh2} directory on
+the server. Then you should go into that \c{.ssh2} directory, and edit
+(or create) a file called \c{authorization}. In this file you should
+put a line like \c{Key mykey.pub}, with \c{mykey.pub} replaced by the
+name of your key file.
+
+\b For other SSH server software, you should refer to the manual for
+that server.
+
+You may also need to ensure that your home directory, your \c{.ssh}
+directory, and any other files involved (such as
+\c{authorized_keys}, \c{authorized_keys2} or \c{authorization}) are
+not group-writable or world-writable. You can typically do this by
+using a command such as
+
+\c chmod go-w $HOME $HOME/.ssh $HOME/.ssh/authorized_keys
+
+Your server should now be configured to accept authentication using
+your private key. Now you need to configure PuTTY to \e{attempt}
+authentication using your private key. You can do this in any of
+three ways:
+
+\b Select the private key in PuTTY's configuration. See
+\k{config-ssh-privkey} for details.
+
+\b Specify the key file on the command line with the \c{-i} option.
+See \k{using-cmdline-identity} for details.
+
+\b Load the private key into Pageant (see \k{pageant}). In this case
+PuTTY will automatically try to use it for authentication if it can.
diff --git a/puttysrc/DOC/SITE.BUT b/puttysrc/DOC/SITE.BUT
new file mode 100644
index 0000000..dc8c32e
--- /dev/null
+++ b/puttysrc/DOC/SITE.BUT
@@ -0,0 +1,4 @@
+\# Additional configuration for the version of the PuTTY docs
+\# actually published as HTML on the website.
+
+\cfg{xhtml-head-end}{}
diff --git a/puttysrc/DOC/UDP.BUT b/puttysrc/DOC/UDP.BUT
new file mode 100644
index 0000000..6635654
--- /dev/null
+++ b/puttysrc/DOC/UDP.BUT
@@ -0,0 +1,389 @@
+\# This file is so named for tradition's sake: it contains what we
+\# always used to refer to, before they were written down, as
+\# PuTTY's `unwritten design principles'. It has nothing to do with
+\# the User Datagram Protocol.
+
+\define{versionidudp} \versionid $Id: udp.but 5525 2005-03-19 02:29:57Z jacob $
+
+\A{udp} PuTTY hacking guide
+
+This appendix lists a selection of the design principles applying to
+the PuTTY source code. If you are planning to send code
+contributions, you should read this first.
+
+\H{udp-portability} Cross-OS portability
+
+Despite Windows being its main area of fame, PuTTY is no longer a
+Windows-only application suite. It has a working Unix port; a Mac
+port is in progress; more ports may or may not happen at a later
+date.
+
+Therefore, embedding Windows-specific code in core modules such as
+\cw{ssh.c} is not acceptable. We went to great lengths to \e{remove}
+all the Windows-specific stuff from our core modules, and to shift
+it out into Windows-specific modules. Adding large amounts of
+Windows-specific stuff in parts of the code that should be portable
+is almost guaranteed to make us reject a contribution.
+
+The PuTTY source base is divided into platform-specific modules and
+platform-generic modules. The Unix-specific modules are all in the
+\c{unix} subdirectory; the Mac-specific modules are in the \c{mac}
+subdirectory; the Windows-specific modules are in the \c{windows}
+subdirectory.
+
+All the modules in the main source directory - notably \e{all} of
+the code for the various back ends - are platform-generic. We want
+to keep them that way.
+
+This also means you should stick to what you are guaranteed by
+ANSI/ISO C (that is, the original C89/C90 standard, not C99). Try
+not to make assumptions about the precise size of basic types such
+as \c{int} and \c{long int}; don't use pointer casts to do
+endianness-dependent operations, and so on.
+
+(There are one or two aspects of ANSI C portability which we
+\e{don't} care about. In particular, we expect PuTTY to be compiled
+on 32-bit architectures \e{or bigger}; so it's safe to assume that
+\c{int} is at least 32 bits wide, not just the 16 you are guaranteed
+by ANSI C. Similarly, we assume that the execution character
+encoding is a superset of the printable characters of ASCII, though
+we don't assume the numeric values of control characters,
+particularly \cw{'\\n'} and \cw{'\\r'}.)
+
+\H{udp-multi-backend} Multiple backends treated equally
+
+PuTTY is not an SSH client with some other stuff tacked on the side.
+PuTTY is a generic, multiple-backend, remote VT-terminal client
+which happens to support one backend which is larger, more popular
+and more useful than the rest. Any extra feature which can possibly
+be general across all backends should be so: localising features
+unnecessarily into the SSH back end is a design error. (For example,
+we had several code submissions for proxy support which worked by
+hacking \cw{ssh.c}. Clearly this is completely wrong: the
+\cw{network.h} abstraction is the place to put it, so that it will
+apply to all back ends equally, and indeed we eventually put it
+there after another contributor sent a better patch.)
+
+The rest of PuTTY should try to avoid knowing anything about
+specific back ends if at all possible. To support a feature which is
+only available in one network protocol, for example, the back end
+interface should be extended in a general manner such that \e{any}
+back end which is able to provide that feature can do so. If it so
+happens that only one back end actually does, that's just the way it
+is, but it shouldn't be relied upon by any code.
+
+\H{udp-globals} Multiple sessions per process on some platforms
+
+Some ports of PuTTY - notably the in-progress Mac port - are
+constrained by the operating system to run as a single process
+potentially managing multiple sessions.
+
+Therefore, the platform-independent parts of PuTTY never use global
+variables to store per-session data. The global variables that do
+exist are tolerated because they are not specific to a particular
+login session: \c{flags} defines properties that are expected to
+apply equally to \e{all} the sessions run by a single PuTTY process,
+the random number state in \cw{sshrand.c} and the timer list in
+\cw{timing.c} serve all sessions equally, and so on. But most data
+is specific to a particular network session, and is therefore stored
+in dynamically allocated data structures, and pointers to these
+structures are passed around between functions.
+
+Platform-specific code can reverse this decision if it likes. The
+Windows code, for historical reasons, stores most of its data as
+global variables. That's OK, because \e{on Windows} we know there is
+only one session per PuTTY process, so it's safe to do that. But
+changes to the platform-independent code should avoid introducing
+global variables, unless they are genuinely cross-session.
+
+\H{udp-pure-c} C, not C++
+
+PuTTY is written entirely in C, not in C++.
+
+We have made \e{some} effort to make it easy to compile our code
+using a C++ compiler: notably, our \c{snew}, \c{snewn} and
+\c{sresize} macros explicitly cast the return values of \cw{malloc}
+and \cw{realloc} to the target type. (This has type checking
+advantages even in C: it means you never accidentally allocate the
+wrong size piece of memory for the pointer type you're assigning it
+to. C++ friendliness is really a side benefit.)
+
+We want PuTTY to continue being pure C, at least in the
+platform-independent parts and the currently existing ports. Patches
+which switch the Makefiles to compile it as C++ and start using
+classes will not be accepted. Also, in particular, we disapprove of
+\cw{//} comments, at least for the moment. (Perhaps once C99 becomes
+genuinely widespread we might be more lenient.)
+
+The one exception: a port to a new platform may use languages other
+than C if they are necessary to code on that platform. If your
+favourite PDA has a GUI with a C++ API, then there's no way you can
+do a port of PuTTY without using C++, so go ahead and use it. But
+keep the C++ restricted to that platform's subdirectory; if your
+changes force the Unix or Windows ports to be compiled as C++, they
+will be unacceptable to us.
+
+\H{udp-security} Security-conscious coding
+
+PuTTY is a network application and a security application. Assume
+your code will end up being fed deliberately malicious data by
+attackers, and try to code in a way that makes it unlikely to be a
+security risk.
+
+In particular, try not to use fixed-size buffers for variable-size
+data such as strings received from the network (or even the user).
+We provide functions such as \cw{dupcat} and \cw{dupprintf}, which
+dynamically allocate buffers of the right size for the string they
+construct. Use these wherever possible.
+
+\H{udp-multi-compiler} Independence of specific compiler
+
+Windows PuTTY can currently be compiled with any of four Windows
+compilers: MS Visual C, Borland's freely downloadable C compiler,
+the Cygwin / \cw{mingw32} GNU tools, and \cw{lcc-win32}.
+
+This is a really useful property of PuTTY, because it means people
+who want to contribute to the coding don't depend on having a
+specific compiler; so they don't have to fork out money for MSVC if
+they don't already have it, but on the other hand if they \e{do}
+have it they also don't have to spend effort installing \cw{gcc}
+alongside it. They can use whichever compiler they happen to have
+available, or install whichever is cheapest and easiest if they
+don't have one.
+
+Therefore, we don't want PuTTY to start depending on which compiler
+you're using. Using GNU extensions to the C language, for example,
+would ruin this useful property (not that anyone's ever tried it!);
+and more realistically, depending on an MS-specific library function
+supplied by the MSVC C library (\cw{_snprintf}, for example) is a
+mistake, because that function won't be available under the other
+compilers. Any function supplied in an official Windows DLL as part
+of the Windows API is fine, and anything defined in the C library
+standard is also fine, because those should be available
+irrespective of compilation environment. But things in between,
+available as non-standard library and language extensions in only
+one compiler, are disallowed.
+
+(\cw{_snprintf} in particular should be unnecessary, since we
+provide \cw{dupprintf}; see \k{udp-security}.)
+
+Compiler independence should apply on all platforms, of course, not
+just on Windows.
+
+\H{udp-small} Small code size
+
+PuTTY is tiny, compared to many other Windows applications. And it's
+easy to install: it depends on no DLLs, no other applications, no
+service packs or system upgrades. It's just one executable. You
+install that executable wherever you want to, and run it.
+
+We want to keep both these properties - the small size, and the ease
+of installation - if at all possible. So code contributions that
+depend critically on external DLLs, or that add a huge amount to the
+code size for a feature which is only useful to a small minority of
+users, are likely to be thrown out immediately.
+
+We do vaguely intend to introduce a DLL plugin interface for PuTTY,
+whereby seriously large extra features can be implemented in plugin
+modules. The important thing, though, is that those DLLs will be
+\e{optional}; if PuTTY can't find them on startup, it should run
+perfectly happily and just won't provide those particular features.
+A full installation of PuTTY might one day contain ten or twenty
+little DLL plugins, which would cut down a little on the ease of
+installation - but if you really needed ease of installation you
+\e{could} still just install the one PuTTY binary, or just the DLLs
+you really needed, and it would still work fine.
+
+Depending on \e{external} DLLs is something we'd like to avoid if at
+all possible (though for some purposes, such as complex SSH
+authentication mechanisms, it may be unavoidable). If it can't be
+avoided, the important thing is to follow the same principle of
+graceful degradation: if a DLL can't be found, then PuTTY should run
+happily and just not supply the feature that depended on it.
+
+\H{udp-single-threaded} Single-threaded code
+
+PuTTY and its supporting tools, or at least the vast majority of
+them, run in only one OS thread.
+
+This means that if you're devising some piece of internal mechanism,
+there's no need to use locks to make sure it doesn't get called by
+two threads at once. The only way code can be called re-entrantly is
+by recursion.
+
+That said, most of Windows PuTTY's network handling is triggered off
+Windows messages requested by \cw{WSAAsyncSelect()}, so if you call
+\cw{MessageBox()} deep within some network event handling code you
+should be aware that you might be re-entered if a network event
+comes in and is passed on to our window procedure by the
+\cw{MessageBox()} message loop.
+
+Also, the front ends (in particular Windows Plink) can use multiple
+threads if they like. However, Windows Plink keeps \e{very} tight
+control of its auxiliary threads, and uses them pretty much
+exclusively as a form of \cw{select()}. Pretty much all the code
+outside \cw{windows/winplink.c} is \e{only} ever called from the one
+primary thread; the others just loop round blocking on file handles
+and send messages to the main thread when some real work needs
+doing. This is not considered a portability hazard because that bit
+of \cw{windows/winplink.c} will need rewriting on other platforms in
+any case.
+
+One important consequence of this: PuTTY has only one thread in
+which to do everything. That \q{everything} may include managing
+more than one login session (\k{udp-globals}), managing multiple
+data channels within an SSH session, responding to GUI events even
+when nothing is happening on the network, and responding to network
+requests from the server (such as repeat key exchange) even when the
+program is dealing with complex user interaction such as the
+re-configuration dialog box. This means that \e{almost none} of the
+PuTTY code can safely block.
+
+\H{udp-keystrokes} Keystrokes sent to the server wherever possible
+
+In almost all cases, PuTTY sends keystrokes to the server. Even
+weird keystrokes that you think should be hot keys controlling
+PuTTY. Even Alt-F4 or Alt-Space, for example. If a keystroke has a
+well-defined escape sequence that it could usefully be sending to
+the server, then it should do so, or at the very least it should be
+configurably able to do so.
+
+To unconditionally turn a key combination into a hot key to control
+PuTTY is almost always a design error. If a hot key is really truly
+required, then try to find a key combination for it which \e{isn't}
+already used in existing PuTTYs (either it sends nothing to the
+server, or it sends the same thing as some other combination). Even
+then, be prepared for the possibility that one day that key
+combination might end up being needed to send something to the
+server - so make sure that there's an alternative way to invoke
+whatever PuTTY feature it controls.
+
+\H{udp-640x480} 640\u00D7{x}480 friendliness in configuration panels
+
+There's a reason we have lots of tiny configuration panels instead
+of a few huge ones, and that reason is that not everyone has a
+1600\u00D7{x}1200 desktop. 640\u00D7{x}480 is still a viable
+resolution for running Windows (and indeed it's still the default if
+you start up in safe mode), so it's still a resolution we care
+about.
+
+Accordingly, the PuTTY configuration box, and the PuTTYgen control
+window, are deliberately kept just small enough to fit comfortably
+on a 640\u00D7{x}480 display. If you're adding controls to either of
+these boxes and you find yourself wanting to increase the size of
+the whole box, \e{don't}. Split it into more panels instead.
+
+\H{udp-makefiles-auto} Automatically generated \cw{Makefile}s
+
+PuTTY is intended to compile on multiple platforms, and with
+multiple compilers. It would be horrifying to try to maintain a
+single \cw{Makefile} which handled all possible situations, and just
+as painful to try to directly maintain a set of matching
+\cw{Makefile}s for each different compilation environment.
+
+Therefore, we have moved the problem up by one level. In the PuTTY
+source archive is a file called \c{Recipe}, which lists which source
+files combine to produce which binaries; and there is also a script
+called \cw{mkfiles.pl}, which reads \c{Recipe} and writes out the
+real \cw{Makefile}s. (The script also reads all the source files and
+analyses their dependencies on header files, so we get an extra
+benefit from doing it this way, which is that we can supply correct
+dependency information even in environments where it's difficult to
+set up an automated \c{make depend} phase.)
+
+You should \e{never} edit any of the PuTTY \cw{Makefile}s directly.
+They are not stored in our source repository at all. They are
+automatically generated by \cw{mkfiles.pl} from the file \c{Recipe}.
+
+If you need to add a new object file to a particular binary, the
+right thing to do is to edit \c{Recipe} and re-run \cw{mkfiles.pl}.
+This will cause the new object file to be added in every tool that
+requires it, on every platform where it matters, in every
+\cw{Makefile} to which it is relevant, \e{and} to get all the
+dependency data right.
+
+If you send us a patch that modifies one of the \cw{Makefile}s, you
+just waste our time, because we will have to convert it into a
+change to \c{Recipe}. If you send us a patch that modifies \e{all}
+of the \cw{Makefile}s, you will have wasted a lot of \e{your} time
+as well!
+
+(There is a comment at the top of every \cw{Makefile} in the PuTTY
+source archive saying this, but many people don't seem to read it,
+so it's worth repeating here.)
+
+\H{udp-ssh-coroutines} Coroutines in \cw{ssh.c}
+
+Large parts of the code in \cw{ssh.c} are structured using a set of
+macros that implement (something close to) Donald Knuth's
+\q{coroutines} concept in C.
+
+Essentially, the purpose of these macros are to arrange that a
+function can call \cw{crReturn()} to return to its caller, and the
+next time it is called control will resume from just after that
+\cw{crReturn} statement.
+
+This means that any local (automatic) variables declared in such a
+function will be corrupted every time you call \cw{crReturn}. If you
+need a variable to persist for longer than that, you \e{must} make
+it a field in one of the persistent state structures: either the
+local state structures \c{s} or \c{st} in each function, or the
+backend-wide structure \c{ssh}.
+
+See
+\W{http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html}\c{http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html}
+for a more in-depth discussion of what these macros are for and how
+they work.
+
+\H{udp-compile-once} Single compilation of each source file
+
+The PuTTY build system for any given platform works on the following
+very simple model:
+
+\b Each source file is compiled precisely once, to produce a single
+object file.
+
+\b Each binary is created by linking together some combination of
+those object files.
+
+Therefore, if you need to introduce functionality to a particular
+module which is only available in some of the tool binaries (for
+example, a cryptographic proxy authentication mechanism which needs
+to be left out of PuTTYtel to maintain its usability in
+crypto-hostile jurisdictions), the \e{wrong} way to do it is by
+adding \cw{#ifdef}s in (say) \cw{proxy.c}. This would require
+separate compilation of \cw{proxy.c} for PuTTY and PuTTYtel, which
+means that the entire \cw{Makefile}-generation architecture (see
+\k{udp-makefiles-auto}) would have to be significantly redesigned.
+Unless you are prepared to do that redesign yourself, \e{and}
+guarantee that it will still port to any future platforms we might
+decide to run on, you should not attempt this!
+
+The \e{right} way to introduce a feature like this is to put the new
+code in a separate source file, and (if necessary) introduce a
+second new source file defining the same set of functions, but
+defining them as stubs which don't provide the feature. Then the
+module whose behaviour needs to vary (\cw{proxy.c} in this example)
+can call the functions defined in these two modules, and it will
+either provide the new feature or not provide it according to which
+of your new modules it is linked with.
+
+Of course, object files are never shared \e{between} platforms; so
+it is allowable to use \cw{#ifdef} to select between platforms. This
+happens in \cw{puttyps.h} (choosing which of the platform-specific
+include files to use), and also in \cw{misc.c} (the Windows-specific
+\q{Minefield} memory diagnostic system). It should be used
+sparingly, though, if at all.
+
+\H{udp-perfection} Do as we say, not as we do
+
+The current PuTTY code probably does not conform strictly to \e{all}
+of the principles listed above. There may be the occasional
+SSH-specific piece of code in what should be a backend-independent
+module, or the occasional dependence on a non-standard X library
+function under Unix.
+
+This should not be taken as a licence to go ahead and violate the
+rules. Where we violate them ourselves, we're not happy about it,
+and we would welcome patches that fix any existing problems. Please
+try to help us make our code better, not worse!
diff --git a/puttysrc/DOC/USING.BUT b/puttysrc/DOC/USING.BUT
new file mode 100644
index 0000000..4ee6e2c
--- /dev/null
+++ b/puttysrc/DOC/USING.BUT
@@ -0,0 +1,894 @@
+\define{versionidusing} \versionid $Id: using.but 7295 2007-02-18 14:02:39Z jacob $
+
+\C{using} Using PuTTY
+
+This chapter provides a general introduction to some more advanced
+features of PuTTY. For extreme detail and reference purposes,
+\k{config} is likely to contain more information.
+
+\H{using-session} During your session
+
+A lot of PuTTY's complexity and features are in the configuration
+panel. Once you have worked your way through that and started
+a session, things should be reasonably simple after that.
+Nevertheless, there are a few more useful features available.
+
+\S{using-selection} Copying and pasting text
+
+\I{copy and paste}Often in a PuTTY session you will find text on
+your terminal screen which you want to type in again. Like most
+other terminal emulators, PuTTY allows you to copy and paste the
+text rather than having to type it again. Also, copy and paste uses
+the \I{Windows clipboard}Windows \i{clipboard}, so that you can
+paste (for example) URLs into a web browser, or paste from a word
+processor or spreadsheet into your terminal session.
+
+PuTTY's copy and paste works entirely with the \i{mouse}. In order
+to copy text to the clipboard, you just click the \i{left mouse
+button} in the \i{terminal window}, and drag to \I{selecting text}select
+text. When you let go of the button, the text is \e{automatically}
+copied to the clipboard. You do not need to press Ctrl-C or
+Ctrl-Ins; in fact, if you do press Ctrl-C, PuTTY will send a Ctrl-C
+character down your session to the server where it will probably
+cause a process to be interrupted.
+
+Pasting is done using the right button (or the middle mouse button,
+if you have a \i{three-button mouse} and have set it up; see
+\k{config-mouse}). (Pressing \i{Shift-Ins}, or selecting \q{Paste}
+from the \I{right mouse button, with Ctrl}Ctrl+right-click
+\i{context menu}, have the same effect.) When
+you click the \i{right mouse button}, PuTTY will read whatever is in
+the Windows clipboard and paste it into your session, \e{exactly} as
+if it had been typed at the keyboard. (Therefore, be careful of
+pasting formatted text into an editor that does automatic indenting;
+you may find that the spaces pasted from the clipboard plus the
+spaces added by the editor add up to too many spaces and ruin the
+formatting. There is nothing PuTTY can do about this.)
+
+If you \i{double-click} the left mouse button, PuTTY will
+\I{selecting words}select a whole word. If you double-click, hold
+down the second click, and drag the mouse, PuTTY will select a
+sequence of whole words. (You can adjust precisely what PuTTY
+considers to be part of a word; see \k{config-charclasses}.)
+If you \e{triple}-click, or \i{triple-click} and drag, then
+PuTTY will \I{selecting lines}select a whole line or sequence of lines.
+
+If you want to select a \I{rectangular selection}rectangular region
+instead of selecting to the end of each line, you can do this by
+holding down Alt when you make your selection. (You can also
+configure rectangular selection to be the default, and then holding
+down Alt gives the normal behaviour instead. See
+\k{config-rectselect} for details.)
+
+If you have a \i{middle mouse button}, then you can use it to
+\I{adjusting a selection}adjust an existing selection if you
+selected something slightly wrong. (If you have configured the
+middle mouse button to paste, then the right mouse button does this
+instead.) Click the button on the screen, and you can pick up the
+nearest end of the selection and drag it to somewhere else.
+
+It's possible for the server to ask to \I{mouse reporting}handle mouse
+clicks in the PuTTY window itself. If this happens, the \i{mouse pointer}
+will turn into an arrow, and using the mouse to copy and paste will only
+work if you hold down Shift. See \k{config-features-mouse} and
+\k{config-mouseshift} for details of this feature and how to configure
+it.
+
+\S{using-scrollback} \I{scrollback}Scrolling the screen back
+
+PuTTY keeps track of text that has scrolled up off the top of the
+terminal. So if something appears on the screen that you want to
+read, but it scrolls too fast and it's gone by the time you try to
+look for it, you can use the \i{scrollbar} on the right side of the
+window to look back up the session \i{history} and find it again.
+
+As well as using the scrollbar, you can also page the scrollback up
+and down by pressing \i{Shift-PgUp} and \i{Shift-PgDn}. You can
+scroll a line at a time using \i{Ctrl-PgUp} and \i{Ctrl-PgDn}. These
+are still available if you configure the scrollbar to be invisible.
+
+By default the last 200 lines scrolled off the top are
+preserved for you to look at. You can increase (or decrease) this
+value using the configuration box; see \k{config-scrollback}.
+
+\S{using-sysmenu} The \ii{System menu}
+
+If you click the left mouse button on the icon in the top left
+corner of PuTTY's terminal window, or click the right mouse button
+on the title bar, you will see the standard Windows system menu
+containing items like Minimise, Move, Size and Close.
+
+PuTTY's system menu contains extra program features in addition to
+the Windows standard options. These extra menu commands are
+described below.
+
+(These options are also available in a \i{context menu} brought up
+by holding Ctrl and clicking with the right mouse button anywhere
+in the \i{PuTTY window}.)
+
+\S2{using-eventlog} The PuTTY \i{Event Log}
+
+If you choose \q{Event Log} from the system menu, a small window
+will pop up in which PuTTY logs significant events during the
+connection. Most of the events in the log will probably take place
+during session startup, but a few can occur at any point in the
+session, and one or two occur right at the end.
+
+You can use the mouse to select one or more lines of the Event Log,
+and hit the Copy button to copy them to the \i{clipboard}. If you
+are reporting a bug, it's often useful to paste the contents of the
+Event Log into your bug report.
+
+\S2{using-specials} \ii{Special commands}
+
+Depending on the protocol used for the current session, there may be
+a submenu of \q{special commands}. These are protocol-specific
+tokens, such as a \q{break} signal, that can be sent down a
+connection in addition to normal data. Their precise effect is usually
+up to the server. Currently only Telnet, SSH, and serial connections
+have special commands.
+
+The \q{break} signal can also be invoked from the keyboard with
+\i{Ctrl-Break}.
+
+The following \I{Telnet special commands}special commands are
+available in Telnet:
+
+\b \I{Are You There, Telnet special command}Are You There
+
+\b \I{Break, Telnet special command}Break
+
+\b \I{Synch, Telnet special command}Synch
+
+\b \I{Erase Character, Telnet special command}Erase Character
+
+\lcont{
+PuTTY can also be configured to send this when the Backspace key is
+pressed; see \k{config-telnetkey}.
+}
+
+\b \I{Erase Line, Telnet special command}Erase Line
+
+\b \I{Go Ahead, Telnet special command}Go Ahead
+
+\b \I{No Operation, Telnet special command}No Operation
+
+\lcont{
+Should have no effect.
+}
+
+\b \I{Abort Process, Telnet special command}Abort Process
+
+\b \I{Abort Output, Telnet special command}Abort Output
+
+\b \I{Interrupt Process, Telnet special command}Interrupt Process
+
+\lcont{
+PuTTY can also be configured to send this when Ctrl-C is typed; see
+\k{config-telnetkey}.
+}
+
+\b \I{Suspend Process, Telnet special command}Suspend Process
+
+\lcont{
+PuTTY can also be configured to send this when Ctrl-Z is typed; see
+\k{config-telnetkey}.
+}
+
+\b \I{End Of Record, Telnet special command}End Of Record
+
+\b \I{End Of File, Telnet special command}End Of File
+
+In an SSH connection, the following \I{SSH special commands}special
+commands are available:
+
+\b \I{IGNORE message, SSH special command}\I{No-op, in SSH}\ii{IGNORE message}
+
+\lcont{
+Should have no effect.
+}
+
+\b \I{Repeat key exchange, SSH special command}Repeat key exchange
+
+\lcont{
+Only available in SSH-2. Forces a \i{repeat key exchange} immediately (and
+resets associated timers and counters). For more information about
+repeat key exchanges, see \k{config-ssh-kex-rekey}.
+}
+
+\b \I{Break, SSH special command}Break
+
+\lcont{
+Only available in SSH-2, and only during a session. Optional
+extension; may not be supported by server. PuTTY requests the server's
+default break length.
+}
+
+\b \I{Signal, SSH special command}Signals (SIGINT, SIGTERM etc)
+
+\lcont{
+Only available in SSH-2, and only during a session. Sends various
+POSIX signals. Not honoured by all servers.
+}
+
+With a serial connection, the only available special command is
+\I{Break, serial special command}\q{Break}.
+
+\S2{using-newsession} Starting new sessions
+
+PuTTY's system menu provides some shortcut ways to start new
+sessions:
+
+\b Selecting \i{\q{New Session}} will start a completely new
+instance of PuTTY, and bring up the configuration box as normal.
+
+\b Selecting \i{\q{Duplicate Session}} will start a session in a
+new window with precisely the same options as your current one -
+connecting to the same host using the same protocol, with all the
+same terminal settings and everything.
+
+\b In an inactive window, selecting \i{\q{Restart Session}} will
+do the same as \q{Duplicate Session}, but in the current window.
+
+\b The \i{\q{Saved Sessions} submenu} gives you quick access to any
+sets of stored session details you have previously saved. See
+\k{config-saving} for details of how to create saved sessions.
+
+\S2{using-changesettings} \I{settings, changing}Changing your
+session settings
+
+If you select \i{\q{Change Settings}} from the system menu, PuTTY will
+display a cut-down version of its initial configuration box. This
+allows you to adjust most properties of your current session. You
+can change the terminal size, the font, the actions of various
+keypresses, the colours, and so on.
+
+Some of the options that are available in the main configuration box
+are not shown in the cut-down Change Settings box. These are usually
+options which don't make sense to change in the middle of a session
+(for example, you can't switch from SSH to Telnet in mid-session).
+
+You can save the current settings to a saved session for future use
+from this dialog box. See \k{config-saving} for more on saved
+sessions.
+
+\S2{using-copyall} \i{Copy All to Clipboard}
+
+This system menu option provides a convenient way to copy the whole
+contents of the terminal screen (up to the last nonempty line) and
+scrollback to the \i{clipboard} in one go.
+
+\S2{reset-terminal} \I{scrollback, clearing}Clearing and
+\I{terminal, resetting}resetting the terminal
+
+The \i{\q{Clear Scrollback}} option on the system menu tells PuTTY
+to discard all the lines of text that have been kept after they
+scrolled off the top of the screen. This might be useful, for
+example, if you displayed sensitive information and wanted to make
+sure nobody could look over your shoulder and see it. (Note that
+this only prevents a casual user from using the scrollbar to view
+the information; the text is not guaranteed not to still be in
+PuTTY's memory.)
+
+The \i{\q{Reset Terminal}} option causes a full reset of the
+\i{terminal emulation}. A VT-series terminal is a complex piece of
+software and can easily get into a state where all the text printed
+becomes unreadable. (This can happen, for example, if you
+accidentally output a binary file to your terminal.) If this
+happens, selecting Reset Terminal should sort it out.
+
+\S2{using-fullscreen} \ii{Full screen} mode
+
+If you find the title bar on a maximised window to be ugly or
+distracting, you can select Full Screen mode to maximise PuTTY
+\q{even more}. When you select this, PuTTY will expand to fill the
+whole screen and its borders, title bar and scrollbar will
+disappear. (You can configure the scrollbar not to disappear in
+full-screen mode if you want to keep it; see \k{config-scrollback}.)
+
+When you are in full-screen mode, you can still access the \i{system
+menu} if you click the left mouse button in the \e{extreme} top left
+corner of the screen.
+
+\H{using-logging} Creating a \i{log file} of your \I{session
+log}session
+
+For some purposes you may find you want to log everything that
+appears on your screen. You can do this using the \q{Logging}
+panel in the configuration box.
+
+To begin a session log, select \q{Change Settings} from the system
+menu and go to the Logging panel. Enter a log file name, and select
+a logging mode. (You can log all session output including the
+terminal \i{control sequence}s, or you can just log the printable text.
+It depends what you want the log for.) Click \q{Apply} and your log
+will be started. Later on, you can go back to the Logging panel and
+select \q{Logging turned off completely} to stop logging; then PuTTY
+will close the log file and you can safely read it.
+
+See \k{config-logging} for more details and options.
+
+\H{using-translation} Altering your \i{character set} configuration
+
+If you find that special characters (\i{accented characters}, for
+example, or \i{line-drawing characters}) are not being displayed
+correctly in your PuTTY session, it may be that PuTTY is interpreting
+the characters sent by the server according to the wrong \e{character
+set}. There are a lot of different character sets available, so it's
+entirely possible for this to happen.
+
+If you click \q{Change Settings} and look at the \q{Translation}
+panel, you should see a large number of character sets which you can
+select, and other related options. Now all you need is to find out
+which of them you want! (See \k{config-translation} for more
+information.)
+
+\H{using-x-forwarding} Using \i{X11 forwarding} in SSH
+
+The SSH protocol has the ability to securely forward X Window System
+applications over your encrypted SSH connection, so that you can run
+an application on the SSH server machine and have it put its windows
+up on your local machine without sending any X network traffic in
+the clear.
+
+In order to use this feature, you will need an X display server for
+your Windows machine, such as Cygwin/X, X-Win32, or Exceed. This will probably
+install itself as display number 0 on your local machine; if it
+doesn't, the manual for the \i{X server} should tell you what it
+does do.
+
+You should then tick the \q{Enable X11 forwarding} box in the
+Tunnels panel (see \k{config-ssh-x11}) before starting your SSH
+session. The \i{\q{X display location}} box is blank by default, which
+means that PuTTY will try to use a sensible default such as \c{:0},
+which is the usual display location where your X server will be
+installed. If that needs changing, then change it.
+
+Now you should be able to log in to the SSH server as normal. To
+check that X forwarding has been successfully negotiated during
+connection startup, you can check the PuTTY Event Log (see
+\k{using-eventlog}). It should say something like this:
+
+\c 2001-12-05 17:22:01 Requesting X11 forwarding
+\c 2001-12-05 17:22:02 X11 forwarding enabled
+
+If the remote system is Unix or Unix-like, you should also be able
+to see that the \i{\c{DISPLAY} environment variable} has been set to
+point at display 10 or above on the SSH server machine itself:
+
+\c fred@unixbox:~$ echo $DISPLAY
+\c unixbox:10.0
+
+If this works, you should then be able to run X applications in the
+remote session and have them display their windows on your PC.
+
+Note that if your PC X server requires \I{X11 authentication}authentication
+to connect, then PuTTY cannot currently support it. If this is a problem for
+you, you should mail the PuTTY authors \#{FIXME} and give details
+(see \k{feedback}).
+
+For more options relating to X11 forwarding, see \k{config-ssh-x11}.
+
+\H{using-port-forwarding} Using \i{port forwarding} in SSH
+
+The SSH protocol has the ability to forward arbitrary \i{network
+connection}s over your encrypted SSH connection, to avoid the network
+traffic being sent in clear. For example, you could use this to
+connect from your home computer to a \i{POP-3} server on a remote
+machine without your POP-3 password being visible to network
+sniffers.
+
+In order to use port forwarding to \I{local port forwarding}connect
+from your local machine to a port on a remote server, you need to:
+
+\b Choose a \i{port number} on your local machine where PuTTY should
+listen for incoming connections. There are likely to be plenty of
+unused port numbers above 3000. (You can also use a local loopback
+address here; see below for more details.)
+
+\b Now, before you start your SSH connection, go to the Tunnels
+panel (see \k{config-ssh-portfwd}). Make sure the \q{Local} radio
+button is set. Enter the local port number into the \q{Source port}
+box. Enter the destination host name and port number into the
+\q{Destination} box, separated by a colon (for example,
+\c{popserver.example.com:110} to connect to a POP-3 server).
+
+\b Now click the \q{Add} button. The details of your port forwarding
+should appear in the list box.
+
+Now start your session and log in. (Port forwarding will not be
+enabled until after you have logged in; otherwise it would be easy
+to perform completely anonymous network attacks, and gain access to
+anyone's virtual private network.) To check that PuTTY has set up
+the port forwarding correctly, you can look at the PuTTY Event Log
+(see \k{using-eventlog}). It should say something like this:
+
+\c 2001-12-05 17:22:10 Local port 3110 forwarding to
+\c popserver.example.com:110
+
+Now if you connect to the source port number on your local PC, you
+should find that it answers you exactly as if it were the service
+running on the destination machine. So in this example, you could
+then configure an e-mail client to use \c{localhost:3110} as a POP-3
+server instead of \c{popserver.example.com:110}. (Of course, the
+forwarding will stop happening when your PuTTY session closes down.)
+
+You can also forward ports in the other direction: arrange for a
+particular port number on the \e{server} machine to be \I{remote
+port forwarding}forwarded back to your PC as a connection to a
+service on your PC or near it.
+To do this, just select the \q{Remote} radio button instead of the
+\q{Local} one. The \q{Source port} box will now specify a port
+number on the \e{server} (note that most servers will not allow you
+to use \I{privileged port}port numbers under 1024 for this purpose).
+
+An alternative way to forward local connections to remote hosts is
+to use \I{dynamic port forwarding}dynamic SOCKS proxying. For
+this, you will need to select the \q{Dynamic} radio button instead
+of \q{Local}, and then you should not enter anything into the
+\q{Destination} box (it will be ignored). This will cause PuTTY to
+listen on the port you have specified, and provide a SOCKS proxy
+service to any programs which connect to that port. So, in
+particular, you can forward other PuTTY connections through it by
+setting up the Proxy control panel (see \k{config-proxy} for
+details).
+
+The source port for a forwarded connection usually does not accept
+connections from any machine except the \I{localhost}SSH client or
+server machine itself (for local and remote forwardings respectively).
+There are controls in the Tunnels panel to change this:
+
+\b The \q{Local ports accept connections from other hosts} option
+allows you to set up local-to-remote port forwardings (including
+dynamic port forwardings) in such a way that machines other than
+your client PC can connect to the forwarded port.
+
+\b The \q{Remote ports do the same} option does the same thing for
+remote-to-local port forwardings (so that machines other than the
+SSH server machine can connect to the forwarded port.) Note that
+this feature is only available in the SSH-2 protocol, and not all
+SSH-2 servers honour it (in \i{OpenSSH}, for example, it's usually
+disabled by default).
+
+You can also specify an \i{IP address} to \I{listen address}listen
+on. Typically a Windows machine can be asked to listen on any single
+IP address in the \cw{127.*.*.*} range, and all of these are
+\i{loopback address}es available only to the local machine. So if
+you forward (for example) \c{127.0.0.5:79} to a remote machine's
+\i\cw{finger} port, then you should be able to run commands such as
+\c{finger fred@127.0.0.5}.
+This can be useful if the program connecting to the forwarded port
+doesn't allow you to change the port number it uses. This feature is
+available for local-to-remote forwarded ports; SSH-1 is unable to
+support it for remote-to-local ports, while SSH-2 can support it in
+theory but servers will not necessarily cooperate.
+
+(Note that if you're using Windows XP Service Pack 2, you may need
+to obtain a fix from Microsoft in order to use addresses like
+\cw{127.0.0.5} - see \k{faq-alternate-localhost}.)
+
+\H{using-rawprot} Making \i{raw TCP connections}
+
+A lot of \I{debugging Internet protocols}Internet protocols are
+composed of commands and responses in plain text. For example,
+\i{SMTP} (the protocol used to transfer e-mail), \i{NNTP} (the
+protocol used to transfer Usenet news), and \i{HTTP} (the protocol
+used to serve Web pages) all consist of commands in readable plain
+text.
+
+Sometimes it can be useful to connect directly to one of these
+services and speak the protocol \q{by hand}, by typing protocol
+commands and watching the responses. On Unix machines, you can do
+this using the system's \c{telnet} command to connect to the right
+port number. For example, \c{telnet mailserver.example.com 25} might
+enable you to talk directly to the SMTP service running on a mail
+server.
+
+Although the Unix \c{telnet} program provides this functionality,
+the protocol being used is not really Telnet. Really there is no
+actual protocol at all; the bytes sent down the connection are
+exactly the ones you type, and the bytes shown on the screen are
+exactly the ones sent by the server. Unix \c{telnet} will attempt to
+detect or guess whether the service it is talking to is a real
+Telnet service or not; PuTTY prefers to be told for certain.
+
+In order to make a debugging connection to a service of this type,
+you simply select the fourth protocol name, \I{\q{Raw}
+protocol}\q{Raw}, from the \q{Protocol} buttons in the \q{Session}
+configuration panel. (See \k{config-hostname}.) You can then enter a
+host name and a port number, and make the connection.
+
+\H{using-serial} Connecting to a local serial line
+
+PuTTY can connect directly to a local serial line as an alternative
+to making a network connection. In this mode, text typed into the
+PuTTY window will be sent straight out of your computer's serial
+port, and data received through that port will be displayed in the
+PuTTY window. You might use this mode, for example, if your serial
+port is connected to another computer which has a serial connection.
+
+To make a connection of this type, simply select \q{Serial} from the
+\q{Connection type} radio buttons on the \q{Session} configuration
+panel (see \k{config-hostname}). The \q{Host Name} and \q{Port}
+boxes will transform into \q{Serial line} and \q{Speed}, allowing
+you to specify which serial line to use (if your computer has more
+than one) and what speed (baud rate) to use when transferring data.
+For further configuration options (data bits, stop bits, parity,
+flow control), you can use the \q{Serial} configuration panel (see
+\k{config-serial}).
+
+After you start up PuTTY in serial mode, you might find that you
+have to make the first move, by sending some data out of the serial
+line in order to notify the device at the other end that someone is
+there for it to talk to. This probably depends on the device. If you
+start up a PuTTY serial session and nothing appears in the window,
+try pressing Return a few times and see if that helps.
+
+A serial line provides no well defined means for one end of the
+connection to notify the other that the connection is finished.
+Therefore, PuTTY in serial mode will remain connected until you
+close the window using the close button.
+
+\H{using-cmdline} The PuTTY command line
+
+PuTTY can be made to do various things without user intervention by
+supplying \i{command-line arguments} (e.g., from a \i{command prompt
+window}, or a \i{Windows shortcut}).
+
+\S{using-cmdline-session} Starting a session from the command line
+
+\I\c{-ssh}\I\c{-telnet}\I\c{-rlogin}\I\c{-raw}These options allow
+you to bypass the configuration window and launch straight into a
+session.
+
+To start a connection to a server called \c{host}:
+
+\c putty.exe [-ssh | -telnet | -rlogin | -raw] [user@]host
+
+If this syntax is used, settings are taken from the \i{Default Settings}
+(see \k{config-saving}); \c{user} overrides these settings if
+supplied. Also, you can specify a protocol, which will override the
+default protocol (see \k{using-cmdline-protocol}).
+
+For telnet sessions, the following alternative syntax is supported
+(this makes PuTTY suitable for use as a URL handler for \i{telnet
+URLs} in web browsers):
+
+\c putty.exe telnet://host[:port]/
+
+In order to start an existing saved session called \c{sessionname},
+use the \c{-load} option (described in \k{using-cmdline-load}).
+
+\c putty.exe -load "session name"
+
+\S{using-cleanup} \i\c{-cleanup}
+
+\cfg{winhelp-topic}{options.cleanup}
+
+If invoked with the \c{-cleanup} option, rather than running as
+normal, PuTTY will remove its \I{removing registry entries}registry
+entries and \i{random seed file} from the local machine (after
+confirming with the user).
+
+Note that on \i{multi-user systems}, \c{-cleanup} only removes
+registry entries and files associated with the currently logged-in
+user.
+
+\S{using-general-opts} Standard command-line options
+
+PuTTY and its associated tools support a range of command-line
+options, most of which are consistent across all the tools. This
+section lists the available options in all tools. Options which are
+specific to a particular tool are covered in the chapter about that
+tool.
+
+\S2{using-cmdline-load} \i\c{-load}: load a saved session
+
+\I{saved sessions, loading from command line}The \c{-load} option
+causes PuTTY to load configuration details out of a saved session.
+If these details include a host name, then this option is all you
+need to make PuTTY start a session.
+
+You need double quotes around the session name if it contains spaces.
+
+If you want to create a \i{Windows shortcut} to start a PuTTY saved
+session, this is the option you should use: your shortcut should
+call something like
+
+\c d:\path\to\putty.exe -load "my session"
+
+(Note that PuTTY itself supports an alternative form of this option,
+for backwards compatibility. If you execute \i\c{putty @sessionname}
+it will have the same effect as \c{putty -load "sessionname"}. With
+the \c{@} form, no double quotes are required, and the \c{@} sign
+must be the very first thing on the command line. This form of the
+option is deprecated.)
+
+\S2{using-cmdline-protocol} Selecting a protocol: \c{-ssh},
+\c{-telnet}, \c{-rlogin}, \c{-raw}
+
+To choose which protocol you want to connect with, you can use one
+of these options:
+
+\b \i\c{-ssh} selects the SSH protocol.
+
+\b \i\c{-telnet} selects the Telnet protocol.
+
+\b \i\c{-rlogin} selects the Rlogin protocol.
+
+\b \i\c{-raw} selects the raw protocol.
+
+These options are not available in the file transfer tools PSCP and
+PSFTP (which only work with the SSH protocol).
+
+These options are equivalent to the \i{protocol selection} buttons
+in the Session panel of the PuTTY configuration box (see
+\k{config-hostname}).
+
+\S2{using-cmdline-v} \i\c{-v}: increase verbosity
+
+\I{verbose mode}Most of the PuTTY tools can be made to tell you more
+about what they are doing by supplying the \c{-v} option. If you are
+having trouble when making a connection, or you're simply curious,
+you can turn this switch on and hope to find out more about what is
+happening.
+
+\S2{using-cmdline-l} \i\c{-l}: specify a \i{login name}
+
+You can specify the user name to log in as on the remote server
+using the \c{-l} option. For example, \c{plink login.example.com -l
+fred}.
+
+These options are equivalent to the username selection box in the
+Connection panel of the PuTTY configuration box (see
+\k{config-username}).
+
+\S2{using-cmdline-portfwd} \I{-L-upper}\c{-L}, \I{-R-upper}\c{-R}
+and \I{-D-upper}\c{-D}: set up \i{port forwardings}
+
+As well as setting up port forwardings in the PuTTY configuration
+(see \k{config-ssh-portfwd}), you can also set up forwardings on the
+command line. The command-line options work just like the ones in
+Unix \c{ssh} programs.
+
+To \I{local port forwarding}forward a local port (say 5110) to a
+remote destination (say \cw{popserver.example.com} port 110), you
+can write something like one of these:
+
+\c putty -L 5110:popserver.example.com:110 -load mysession
+\c plink mysession -L 5110:popserver.example.com:110
+
+To forward a \I{remote port forwarding}remote port to a local
+destination, just use the \c{-R} option instead of \c{-L}:
+
+\c putty -R 5023:mytelnetserver.myhouse.org:23 -load mysession
+\c plink mysession -R 5023:mytelnetserver.myhouse.org:23
+
+To \I{listen address}specify an IP address for the listening end of the
+tunnel, prepend it to the argument:
+
+\c plink -L 127.0.0.5:23:localhost:23 myhost
+
+To set up \I{dynamic port forwarding}SOCKS-based dynamic port
+forwarding on a local port, use the \c{-D} option. For this one you
+only have to pass the port number:
+
+\c putty -D 4096 -load mysession
+
+For general information on port forwarding, see
+\k{using-port-forwarding}.
+
+These options are not available in the file transfer tools PSCP and
+PSFTP.
+
+\S2{using-cmdline-m} \i\c{-m}: \I{reading commands from a file}read
+a remote command or script from a file
+
+The \i\c{-m} option performs a similar function to the \q{\ii{Remote
+command}} box in the SSH panel of the PuTTY configuration box (see
+\k{config-command}). However, the \c{-m} option expects to be given
+a local file name, and it will read a command from that file.
+
+With some servers (particularly Unix systems), you can even put
+multiple lines in this file and execute more than one command in
+sequence, or a whole shell script; but this is arguably an abuse, and
+cannot be expected to work on all servers. In particular, it is known
+\e{not} to work with certain \q{embedded} servers, such as \i{Cisco}
+routers.
+
+This option is not available in the file transfer tools PSCP and
+PSFTP.
+
+\S2{using-cmdline-p} \I{-P-upper}\c{-P}: specify a \i{port number}
+
+The \c{-P} option is used to specify the port number to connect to. If
+you have a Telnet server running on port 9696 of a machine instead of
+port 23, for example:
+
+\c putty -telnet -P 9696 host.name
+\c plink -telnet -P 9696 host.name
+
+(Note that this option is more useful in Plink than in PuTTY,
+because in PuTTY you can write \c{putty -telnet host.name 9696} in
+any case.)
+
+This option is equivalent to the port number control in the Session
+panel of the PuTTY configuration box (see \k{config-hostname}).
+
+\S2{using-cmdline-pw} \i\c{-pw}: specify a \i{password}
+
+A simple way to automate a remote login is to supply your password
+on the command line. This is \e{not recommended} for reasons of
+security. If you possibly can, we recommend you set up public-key
+authentication instead. See \k{pubkey} for details.
+
+Note that the \c{-pw} option only works when you are using the SSH
+protocol. Due to fundamental limitations of Telnet and Rlogin, these
+protocols do not support automated password authentication.
+
+\S2{using-cmdline-agentauth} \i\c{-agent} and \i\c{-noagent}:
+control use of Pageant for authentication
+
+The \c{-agent} option turns on SSH authentication using Pageant, and
+\c{-noagent} turns it off. These options are only meaningful if you
+are using SSH.
+
+See \k{pageant} for general information on \i{Pageant}.
+
+These options are equivalent to the agent authentication checkbox in
+the Auth panel of the PuTTY configuration box (see
+\k{config-ssh-tryagent}).
+
+\S2{using-cmdline-agent} \I{-A-upper}\c{-A} and \i\c{-a}: control \i{agent
+forwarding}
+
+The \c{-A} option turns on SSH agent forwarding, and \c{-a} turns it
+off. These options are only meaningful if you are using SSH.
+
+See \k{pageant} for general information on \i{Pageant}, and
+\k{pageant-forward} for information on agent forwarding. Note that
+there is a security risk involved with enabling this option; see
+\k{pageant-security} for details.
+
+These options are equivalent to the agent forwarding checkbox in the
+Auth panel of the PuTTY configuration box (see \k{config-ssh-agentfwd}).
+
+These options are not available in the file transfer tools PSCP and
+PSFTP.
+
+\S2{using-cmdline-x11} \I{-X-upper}\c{-X} and \i\c{-x}: control \i{X11
+forwarding}
+
+The \c{-X} option turns on X11 forwarding in SSH, and \c{-x} turns
+it off. These options are only meaningful if you are using SSH.
+
+For information on X11 forwarding, see \k{using-x-forwarding}.
+
+These options are equivalent to the X11 forwarding checkbox in the
+Tunnels panel of the PuTTY configuration box (see
+\k{config-ssh-x11}).
+
+These options are not available in the file transfer tools PSCP and
+PSFTP.
+
+\S2{using-cmdline-pty} \i\c{-t} and \I{-T-upper}\c{-T}: control
+\i{pseudo-terminal allocation}
+
+The \c{-t} option ensures PuTTY attempts to allocate a
+pseudo-terminal at the server, and \c{-T} stops it from allocating
+one. These options are only meaningful if you are using SSH.
+
+These options are equivalent to the \q{Don't allocate a
+pseudo-terminal} checkbox in the SSH panel of the PuTTY
+configuration box (see \k{config-ssh-pty}).
+
+These options are not available in the file transfer tools PSCP and
+PSFTP.
+
+\S2{using-cmdline-noshell} \I{-N-upper}\c{-N}: suppress starting a
+\I{suppressing remote shell}shell or command
+
+The \c{-N} option prevents PuTTY from attempting to start a shell or
+command on the remote server. You might want to use this option if
+you are only using the SSH connection for port forwarding, and your
+user account on the server does not have the ability to run a shell.
+
+This feature is only available in SSH protocol version 2 (since the
+version 1 protocol assumes you will always want to run a shell).
+
+This option is equivalent to the \q{Don't start a shell or command
+at all} checkbox in the SSH panel of the PuTTY configuration box
+(see \k{config-ssh-noshell}).
+
+This option is not available in the file transfer tools PSCP and
+PSFTP.
+
+\S2{using-cmdline-ncmode} \I{-nc}\c{-nc}: make a \i{remote network
+connection} in place of a remote shell or command
+
+The \c{-nc} option prevents Plink (or PuTTY) from attempting to
+start a shell or command on the remote server. Instead, it will
+instruct the remote server to open a network connection to a host
+name and port number specified by you, and treat that network
+connection as if it were the main session.
+
+You specify a host and port as an argument to the \c{-nc} option,
+with a colon separating the host name from the port number, like
+this:
+
+\c plink host1.example.com -nc host2.example.com:1234
+
+You might want to use this feature if you needed to make an SSH
+connection to a target host which you can only reach by going
+through a proxy host, and rather than using port forwarding you
+prefer to use the local proxy feature (see \k{config-proxy-type} for
+more about local proxies). In this situation you might select
+\q{Local} proxy type, set your local proxy command to be \cq{plink
+%proxyhost -nc %host:%port}, enter the target host name on the
+Session panel, and enter the directly reachable proxy host name on
+the Proxy panel.
+
+This feature is only available in SSH protocol version 2 (since the
+version 1 protocol assumes you will always want to run a shell). It
+is not available in the file transfer tools PSCP and PSFTP. It is
+available in PuTTY itself, although it is unlikely to be very useful
+in any tool other than Plink. Also, \c{-nc} uses the same server
+functionality as port forwarding, so it will not work if your server
+administrator has disabled port forwarding.
+
+(The option is named \c{-nc} after the Unix program
+\W{http://www.vulnwatch.org/netcat/}\c{nc}, short for \q{netcat}.
+The command \cq{plink host1 -nc host2:port} is very similar in
+functionality to \cq{plink host1 nc host2 port}, which invokes
+\c{nc} on the server and tells it to connect to the specified
+destination. However, Plink's built-in \c{-nc} option does not
+depend on the \c{nc} program being installed on the server.)
+
+\S2{using-cmdline-compress} \I{-C-upper}\c{-C}: enable \i{compression}
+
+The \c{-C} option enables compression of the data sent across the
+network. This option is only meaningful if you are using SSH.
+
+This option is equivalent to the \q{Enable compression} checkbox in
+the SSH panel of the PuTTY configuration box (see
+\k{config-ssh-comp}).
+
+\S2{using-cmdline-sshprot} \i\c{-1} and \i\c{-2}: specify an \i{SSH
+protocol version}
+
+The \c{-1} and \c{-2} options force PuTTY to use version \I{SSH-1}1
+or version \I{SSH-2}2 of the SSH protocol. These options are only
+meaningful if you are using SSH.
+
+These options are equivalent to selecting your preferred SSH
+protocol version as \q{1 only} or \q{2 only} in the SSH panel of the
+PuTTY configuration box (see \k{config-ssh-prot}).
+
+\S2{using-cmdline-ipversion} \i\c{-4} and \i\c{-6}: specify an
+\i{Internet protocol version}
+
+The \c{-4} and \c{-6} options force PuTTY to use the older Internet
+protocol \i{IPv4} or the newer \i{IPv6}.
+
+These options are equivalent to selecting your preferred Internet
+protocol version as \q{IPv4} or \q{IPv6} in the Connection panel of
+the PuTTY configuration box (see \k{config-address-family}).
+
+\S2{using-cmdline-identity} \i\c{-i}: specify an SSH \i{private key}
+
+The \c{-i} option allows you to specify the name of a private key
+file in \c{*.\i{PPK}} format which PuTTY will use to authenticate with the
+server. This option is only meaningful if you are using SSH.
+
+For general information on \i{public-key authentication}, see
+\k{pubkey}.
+
+This option is equivalent to the \q{Private key file for
+authentication} box in the Auth panel of the PuTTY configuration box
+(see \k{config-ssh-privkey}).
+
+\S2{using-cmdline-pgpfp} \i\c{-pgpfp}: display \i{PGP key fingerprint}s
+
+This option causes the PuTTY tools not to run as normal, but instead
+to display the fingerprints of the PuTTY PGP Master Keys, in order to
+aid with \i{verifying new versions}. See \k{pgpkeys} for more information.
diff --git a/puttysrc/DOC/VIDS.BUT b/puttysrc/DOC/VIDS.BUT
new file mode 100644
index 0000000..7f35118
--- /dev/null
+++ b/puttysrc/DOC/VIDS.BUT
@@ -0,0 +1,36 @@
+\# Invoke the versionid macros defined in all the other manual
+\# chapter files.
+
+\versionidblurb
+
+\versionidintro
+
+\versionidgs
+
+\versionidusing
+
+\versionidconfig
+
+\versionidpscp
+
+\versionidpsftp
+
+\versionidplink
+
+\versionidpubkey
+
+\versionidpageant
+
+\versioniderrors
+
+\versionidfaq
+
+\versionidfeedback
+
+\versionidlicence
+
+\versionidudp
+
+\versionidpgpkeys
+
+\versionidindex
diff --git a/puttysrc/ICONS/CICON.PL b/puttysrc/ICONS/CICON.PL
new file mode 100644
index 0000000..7bce7d3
--- /dev/null
+++ b/puttysrc/ICONS/CICON.PL
@@ -0,0 +1,28 @@
+#!/usr/bin/perl
+
+# Given a list of input PNGs, create a C source file containing a
+# const array of XPMs, named by a given C identifier.
+
+$id = shift @ARGV;
+$k = 0;
+@xpms = ();
+foreach $f (@ARGV) {
+ # XPM format is generated directly by ImageMagick, so that's easy
+ # enough. We just have to adjust the declaration line so that it
+ # has the right name, linkage and storage class.
+ @lines = ();
+ open XPM, "convert $f xpm:- |";
+ push @lines, $_ while ;
+ close XPM;
+ die "XPM from $f in unexpected format\n" unless $lines[1] =~ /^static.*\{$/;
+ $lines[1] = "static const char *const ${id}_$k"."[] = {\n";
+ $k++;
+ push @xpms, @lines, "\n";
+}
+
+# Now output.
+foreach $line (@xpms) { print $line; }
+print "const char *const *const ${id}[] = {\n";
+for ($i = 0; $i < $k; $i++) { print " ${id}_$i,\n"; }
+print "};\n";
+print "const int n_${id} = $k;\n";
diff --git a/puttysrc/ICONS/ICON.PL b/puttysrc/ICONS/ICON.PL
new file mode 100644
index 0000000..aefd3fa
--- /dev/null
+++ b/puttysrc/ICONS/ICON.PL
@@ -0,0 +1,270 @@
+#!/usr/bin/perl
+
+# Take a collection of input image files and convert them into a
+# multi-resolution Windows .ICO icon file.
+#
+# The input images can be treated as having four different colour
+# depths:
+#
+# - 24-bit true colour
+# - 8-bit with custom palette
+# - 4-bit using the Windows 16-colour palette (see comment below
+# for details)
+# - 1-bit using black and white only.
+#
+# The images can be supplied in any input format acceptable to
+# ImageMagick, but their actual colour usage must already be
+# appropriate for the specified mode; this script will not do any
+# substantive conversion. So if an image intended to be used in 4-
+# or 1-bit mode contains any colour not in the appropriate fixed
+# palette, that's a fatal error; if an image to be used in 8-bit
+# mode contains more than 256 distinct colours, that's also a fatal
+# error.
+#
+# Command-line syntax is:
+#
+# icon.pl -depth imagefile [imagefile...] [-depth imagefile [imagefile...]]
+#
+# where `-depth' is one of `-24', `-8', `-4' or `-1', and tells the
+# script how to treat all the image files given after that option
+# until the next depth option. For example, you might execute
+#
+# icon.pl -24 48x48x24.png 32x32x24.png -8 32x32x8.png -1 monochrome.png
+#
+# to build an icon file containing two differently sized 24-bit
+# images, one 8-bit image and one black and white image.
+#
+# Windows .ICO files support a 1-bit alpha channel on all these
+# image types. That is, any pixel can be either opaque or fully
+# transparent, but not partially transparent. The alpha channel is
+# separate from the main image data, meaning that `transparent' is
+# not required to take up a palette entry. (So an 8-bit image can
+# have 256 distinct _opaque_ colours, plus transparent pixels as
+# well.) If the input images have alpha channels, they will be used
+# to determine which pixels of the icon are transparent, by simple
+# quantisation half way up (e.g. in a PNG image with an 8-bit alpha
+# channel, alpha values of 00-7F will be mapped to transparent
+# pixels, and 80-FF will become opaque).
+
+# The Windows 16-colour palette consists of:
+# - the eight corners of the colour cube (000000, 0000FF, 00FF00,
+# 00FFFF, FF0000, FF00FF, FFFF00, FFFFFF)
+# - dim versions of the seven non-black corners, at 128/255 of the
+# brightness (000080, 008000, 008080, 800000, 800080, 808000,
+# 808080)
+# - light grey at 192/255 of full brightness (C0C0C0).
+%win16pal = (
+ "\x00\x00\x00\x00" => 0,
+ "\x00\x00\x80\x00" => 1,
+ "\x00\x80\x00\x00" => 2,
+ "\x00\x80\x80\x00" => 3,
+ "\x80\x00\x00\x00" => 4,
+ "\x80\x00\x80\x00" => 5,
+ "\x80\x80\x00\x00" => 6,
+ "\xC0\xC0\xC0\x00" => 7,
+ "\x80\x80\x80\x00" => 8,
+ "\x00\x00\xFF\x00" => 9,
+ "\x00\xFF\x00\x00" => 10,
+ "\x00\xFF\xFF\x00" => 11,
+ "\xFF\x00\x00\x00" => 12,
+ "\xFF\x00\xFF\x00" => 13,
+ "\xFF\xFF\x00\x00" => 14,
+ "\xFF\xFF\xFF\x00" => 15,
+);
+@win16pal = sort { $win16pal{$a} <=> $win16pal{$b} } keys %win16pal;
+
+# The black and white palette consists of black (000000) and white
+# (FFFFFF), obviously.
+%win2pal = (
+ "\x00\x00\x00\x00" => 0,
+ "\xFF\xFF\xFF\x00" => 1,
+);
+@win2pal = sort { $win16pal{$a} <=> $win2pal{$b} } keys %win2pal;
+
+@hdr = ();
+@dat = ();
+
+$depth = undef;
+foreach $_ (@ARGV) {
+ if (/^-(24|8|4|1)$/) {
+ $depth = $1;
+ } elsif (defined $depth) {
+ &readicon($_, $depth);
+ } else {
+ $usage = 1;
+ }
+}
+if ($usage || length @hdr == 0) {
+ print "usage: icon.pl ( -24 | -8 | -4 | -1 ) image [image...]\n";
+ print " [ ( -24 | -8 | -4 | -1 ) image [image...] ...]\n";
+ exit 0;
+}
+
+# Now write out the output icon file.
+print pack "vvv", 0, 1, scalar @hdr; # file-level header
+$filepos = 6 + 16 * scalar @hdr;
+for ($i = 0; $i < scalar @hdr; $i++) {
+ print $hdr[$i];
+ print pack "V", $filepos;
+ $filepos += length($dat[$i]);
+}
+for ($i = 0; $i < scalar @hdr; $i++) {
+ print $dat[$i];
+}
+
+sub readicon {
+ my $filename = shift @_;
+ my $depth = shift @_;
+ my $pix;
+ my $i;
+ my %pal;
+
+ # Determine the icon's width and height.
+ my $w = `identify -format %w $filename`;
+ my $h = `identify -format %h $filename`;
+
+ # Read the file in as RGBA data. We flip vertically at this
+ # point, to avoid having to do it ourselves (.BMP and hence
+ # .ICO are bottom-up).
+ my $data = [];
+ open IDATA, "convert -flip -depth 8 $filename rgba:- |";
+ push @$data, $rgb while (read IDATA,$rgb,4,0) == 4;
+ close IDATA;
+ # Check we have the right amount of data.
+ $xl = $w * $h;
+ $al = scalar @$data;
+ die "wrong amount of image data ($al, expected $xl) from $filename\n"
+ unless $al == $xl;
+
+ # Build the alpha channel now, so we can exclude transparent
+ # pixels from the palette analysis. We replace transparent
+ # pixels with undef in the data array.
+ #
+ # We quantise the alpha channel half way up, so that alpha of
+ # 0x80 or more is taken to be fully opaque and 0x7F or less is
+ # fully transparent. Nasty, but the best we can do without
+ # dithering (and don't even suggest we do that!).
+ my $x;
+ my $y;
+ my $alpha = "";
+
+ for ($y = 0; $y < $h; $y++) {
+ my $currbyte = 0, $currbits = 0;
+ for ($x = 0; $x < (($w+31)|31)-31; $x++) {
+ $pix = ($x < $w ? $data->[$y*$w+$x] : "\x00\x00\x00\xFF");
+ my @rgba = unpack "CCCC", $pix;
+ $currbyte <<= 1;
+ $currbits++;
+ if ($rgba[3] < 0x80) {
+ if ($x < $w) {
+ $data->[$y*$w+$x] = undef;
+ }
+ $currbyte |= 1; # MS has the alpha channel inverted :-)
+ } else {
+ # Might as well flip RGBA into BGR0 while we're here.
+ if ($x < $w) {
+ $data->[$y*$w+$x] = pack "CCCC",
+ $rgba[2], $rgba[1], $rgba[0], 0;
+ }
+ }
+ if ($currbits >= 8) {
+ $alpha .= pack "C", $currbyte;
+ $currbits -= 8;
+ }
+ }
+ }
+
+ # For an 8-bit image, check we have at most 256 distinct
+ # colours, and build the palette.
+ %pal = ();
+ if ($depth == 8) {
+ my $palindex = 0;
+ foreach $pix (@$data) {
+ next unless defined $pix;
+ $pal{$pix} = $palindex++ unless defined $pal{$pix};
+ }
+ die "too many colours in 8-bit image $filename\n" unless $palindex <= 256;
+ } elsif ($depth == 4) {
+ %pal = %win16pal;
+ } elsif ($depth == 1) {
+ %pal = %win2pal;
+ }
+
+ my $raster = "";
+ if ($depth < 24) {
+ # For a non-24-bit image, flatten the image into one palette
+ # index per pixel.
+ $pad = 32 / $depth; # number of pixels to pad scanline to 4-byte align
+ $pmask = $pad-1;
+ for ($y = 0; $y < $h; $y++) {
+ my $currbyte = 0, $currbits = 0;
+ for ($x = 0; $x < (($w+$pmask)|$pmask)-$pmask; $x++) {
+ $currbyte <<= $depth;
+ $currbits += $depth;
+ if ($x < $w && defined ($pix = $data->[$y*$w+$x])) {
+ if (!defined $pal{$pix}) {
+ $pixhex = sprintf "%02x%02x%02x", unpack "CCC", $pix;
+ die "illegal colour value $pixhex at pixel ($x,$y) in $filename\n";
+ }
+ $currbyte |= $pal{$pix};
+ }
+ if ($currbits >= 8) {
+ $raster .= pack "C", $currbyte;
+ $currbits -= 8;
+ }
+ }
+ }
+ } else {
+ # For a 24-bit image, reverse the order of the R,G,B values
+ # and stick a padding zero on the end.
+ #
+ # (In this loop we don't need to bother padding the
+ # scanline out to a multiple of four bytes, because every
+ # pixel takes four whole bytes anyway.)
+ for ($i = 0; $i < scalar @$data; $i++) {
+ if (defined $data->[$i]) {
+ $raster .= $data->[$i];
+ } else {
+ $raster .= "\x00\x00\x00\x00";
+ }
+ }
+ $depth = 32; # and adjust this
+ }
+
+ # Prepare the icon data. First the header...
+ my $data = pack "VVVvvVVVVVV",
+ 40, # size of bitmap info header
+ $w, # icon width
+ $h*2, # icon height (x2 to indicate the subsequent alpha channel)
+ 1, # 1 plane (common to all MS image formats)
+ $depth, # bits per pixel
+ 0, # no compression
+ length $raster, # image size
+ 0, 0, 0, 0; # resolution, colours used, colours important (ignored)
+ # ... then the palette ...
+ if ($depth <= 8) {
+ my $ncols = (1 << $depth);
+ my $palette = "\x00\x00\x00\x00" x $ncols;
+ foreach $i (keys %pal) {
+ substr($palette, $pal{$i}*4, 4) = $i;
+ }
+ $data .= $palette;
+ }
+ # ... the raster data we already had ready ...
+ $data .= $raster;
+ # ... and the alpha channel we already had as well.
+ $data .= $alpha;
+
+ # Prepare the header which will represent this image in the
+ # icon file.
+ my $header = pack "CCCCvvV",
+ $w, $h, # width and height (this time the real height)
+ 1 << $depth, # number of colours, if less than 256
+ 0, # reserved
+ 1, # planes
+ $depth, # bits per pixel
+ length $data; # size of real icon data
+
+ push @hdr, $header;
+ push @dat, $data;
+}
diff --git a/puttysrc/ICONS/MAKEFILE b/puttysrc/ICONS/MAKEFILE
new file mode 100644
index 0000000..620fab4
--- /dev/null
+++ b/puttysrc/ICONS/MAKEFILE
@@ -0,0 +1,92 @@
+# Makefile for the PuTTY icon suite.
+
+ICONS = putty puttycfg puttygen pscp pageant pterm ptermcfg puttyins
+SIZES = 16 32 48
+
+MODE = # override to -it on command line for opaque testing
+
+PNGS = $(foreach I,$(ICONS),$(foreach S,$(SIZES),$(I)-$(S).png))
+MONOPNGS = $(foreach I,$(ICONS),$(foreach S,$(SIZES),$(I)-$(S)-mono.png))
+TRUEPNGS = $(foreach I,$(ICONS),$(foreach S,$(SIZES),$(I)-$(S)-true.png))
+
+ICOS = putty.ico puttygen.ico pscp.ico pageant.ico pageants.ico puttycfg.ico \
+ puttyins.ico
+CICONS = xpmputty.c xpmpucfg.c xpmpterm.c xpmptcfg.c
+
+base: icos cicons
+
+all: pngs monopngs base # truepngs currently disabled by default
+
+pngs: $(PNGS)
+monopngs: $(MONOPNGS)
+truepngs: $(TRUEPNGS)
+
+icos: $(ICOS)
+cicons: $(CICONS)
+
+install: icos cicons
+ cp $(ICOS) ../windows
+ cp $(CICONS) ../unix
+
+$(PNGS): %.png: mkicon.py
+ ./mkicon.py $(MODE) $(join $(subst -, ,$(basename $@)),_icon) $@
+
+$(MONOPNGS): %.png: mkicon.py
+ ./mkicon.py -2 $(MODE) $(join $(subst -, ,$(subst -mono,,$(basename $@))),_icon) $@
+
+$(TRUEPNGS): %.png: mkicon.py
+ ./mkicon.py -T $(MODE) $(join $(subst -, ,$(subst -true,,$(basename $@))),_icon) $@
+
+putty.ico: putty-16.png putty-32.png putty-48.png \
+ putty-16-mono.png putty-32-mono.png putty-48-mono.png
+ ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@
+
+puttycfg.ico: puttycfg-16.png puttycfg-32.png puttycfg-48.png \
+ puttycfg-16-mono.png puttycfg-32-mono.png puttycfg-48-mono.png
+ ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@
+
+puttygen.ico: puttygen-16.png puttygen-32.png puttygen-48.png \
+ puttygen-16-mono.png puttygen-32-mono.png puttygen-48-mono.png
+ ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@
+
+pageant.ico: pageant-16.png pageant-32.png pageant-48.png \
+ pageant-16-mono.png pageant-32-mono.png pageant-48-mono.png
+ ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@
+
+pageants.ico: pageant-16.png pageant-16-mono.png
+ ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@
+
+pscp.ico: pscp-16.png pscp-32.png pscp-48.png \
+ pscp-16-mono.png pscp-32-mono.png pscp-48-mono.png
+ ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@
+
+# Because the installer icon makes heavy use of brown when drawing
+# the cardboard box, it's worth having 8-bit versions of it in
+# addition to the 4- and 1-bit ones.
+puttyins.ico: puttyins-16.png puttyins-32.png puttyins-48.png \
+ puttyins-16-mono.png puttyins-32-mono.png \
+ puttyins-48-mono.png \
+ puttyins-16-true.png puttyins-32-true.png \
+ puttyins-48-true.png
+ ./icon.pl -8 $(filter %-true.png, $^) \
+ -4 $(filter-out %-true.png, $(filter-out %-mono.png, $^)) \
+ -1 $(filter %-mono.png, $^) > $@
+
+# Icon for the website. (This isn't linked into "make all".)
+website.ico: putty-16.png
+ ./icon.pl -4 $^ >$@
+
+xpmputty.c: putty-16.png putty-32.png putty-48.png
+ ./cicon.pl main_icon $^ > $@
+
+xpmpucfg.c: puttycfg-16.png puttycfg-32.png puttycfg-48.png
+ ./cicon.pl cfg_icon $^ > $@
+
+xpmpterm.c: pterm-16.png pterm-32.png pterm-48.png
+ ./cicon.pl main_icon $^ > $@
+
+xpmptcfg.c: ptermcfg-16.png ptermcfg-32.png ptermcfg-48.png
+ ./cicon.pl cfg_icon $^ > $@
+
+clean:
+ rm -f *.png *.ico *.c
diff --git a/puttysrc/ICONS/MKICON.PY b/puttysrc/ICONS/MKICON.PY
new file mode 100644
index 0000000..88b05a9
--- /dev/null
+++ b/puttysrc/ICONS/MKICON.PY
@@ -0,0 +1,1093 @@
+#!/usr/bin/env python
+
+import math
+
+# Python code which draws the PuTTY icon components at a range of
+# sizes.
+
+# TODO
+# ----
+#
+# - use of alpha blending
+# + try for variable-transparency borders
+#
+# - can we integrate the Mac icons into all this? Do we want to?
+
+def pixel(x, y, colour, canvas):
+ canvas[(int(x),int(y))] = colour
+
+def overlay(src, x, y, dst):
+ x = int(x)
+ y = int(y)
+ for (sx, sy), colour in src.items():
+ dst[sx+x, sy+y] = blend(colour, dst.get((sx+x, sy+y), cT))
+
+def finalise(canvas):
+ for k in canvas.keys():
+ canvas[k] = finalisepix(canvas[k])
+
+def bbox(canvas):
+ minx, miny, maxx, maxy = None, None, None, None
+ for (x, y) in canvas.keys():
+ if minx == None:
+ minx, miny, maxx, maxy = x, y, x+1, y+1
+ else:
+ minx = min(minx, x)
+ miny = min(miny, y)
+ maxx = max(maxx, x+1)
+ maxy = max(maxy, y+1)
+ return (minx, miny, maxx, maxy)
+
+def topy(canvas):
+ miny = {}
+ for (x, y) in canvas.keys():
+ miny[x] = min(miny.get(x, y), y)
+ return miny
+
+def render(canvas, minx, miny, maxx, maxy):
+ w = maxx - minx
+ h = maxy - miny
+ ret = []
+ for y in range(h):
+ ret.append([outpix(cT)] * w)
+ for (x, y), colour in canvas.items():
+ if x >= minx and x < maxx and y >= miny and y < maxy:
+ ret[y-miny][x-minx] = outpix(colour)
+ return ret
+
+# Code to actually draw pieces of icon. These don't generally worry
+# about positioning within a canvas; they just draw at a standard
+# location, return some useful coordinates, and leave composition
+# to other pieces of code.
+
+sqrthash = {}
+def memoisedsqrt(x):
+ if not sqrthash.has_key(x):
+ sqrthash[x] = math.sqrt(x)
+ return sqrthash[x]
+
+BR, TR, BL, TL = range(4) # enumeration of quadrants for border()
+
+def border(canvas, thickness, squarecorners, out={}):
+ # I haven't yet worked out exactly how to do borders in a
+ # properly alpha-blended fashion.
+ #
+ # When you have two shades of dark available (half-dark H and
+ # full-dark F), the right sequence of circular border sections
+ # around a pixel x starts off with these two layouts:
+ #
+ # H F
+ # HxH FxF
+ # H F
+ #
+ # Where it goes after that I'm not entirely sure, but I'm
+ # absolutely sure those are the right places to start. However,
+ # every automated algorithm I've tried has always started off
+ # with the two layouts
+ #
+ # H HHH
+ # HxH HxH
+ # H HHH
+ #
+ # which looks much worse. This is true whether you do
+ # pixel-centre sampling (define an inner circle and an outer
+ # circle with radii differing by 1, set any pixel whose centre
+ # is inside the inner circle to F, any pixel whose centre is
+ # outside the outer one to nothing, interpolate between the two
+ # and round sensibly), _or_ whether you plot a notional circle
+ # of a given radius and measure the actual _proportion_ of each
+ # pixel square taken up by it.
+ #
+ # It's not clear what I should be doing to prevent this. One
+ # option is to attempt error-diffusion: Ian Jackson proved on
+ # paper that if you round each pixel's ideal value to the
+ # nearest of the available output values, then measure the
+ # error at each pixel, propagate that error outwards into the
+ # original values of the surrounding pixels, and re-round
+ # everything, you do get the correct second stage. However, I
+ # haven't tried it at a proper range of radii.
+ #
+ # Another option is that the automated mechanisms described
+ # above would be entirely adequate if it weren't for the fact
+ # that the human visual centres are adapted to detect
+ # horizontal and vertical lines in particular, so the only
+ # place you have to behave a bit differently is at the ends of
+ # the top and bottom row of pixels in the circle, and the top
+ # and bottom of the extreme columns.
+ #
+ # For the moment, what I have below is a very simple mechanism
+ # which always uses only one alpha level for any given border
+ # thickness, and which seems to work well enough for Windows
+ # 16-colour icons. Everything else will have to wait.
+
+ thickness = memoisedsqrt(thickness)
+
+ if thickness < 0.9:
+ darkness = 0.5
+ else:
+ darkness = 1
+ if thickness < 1: thickness = 1
+ thickness = round(thickness - 0.5) + 0.3
+
+ out["borderthickness"] = thickness
+
+ dmax = int(round(thickness))
+ if dmax < thickness: dmax = dmax + 1
+
+ cquadrant = [[0] * (dmax+1) for x in range(dmax+1)]
+ squadrant = [[0] * (dmax+1) for x in range(dmax+1)]
+
+ for x in range(dmax+1):
+ for y in range(dmax+1):
+ if max(x, y) < thickness:
+ squadrant[x][y] = darkness
+ if memoisedsqrt(x*x+y*y) < thickness:
+ cquadrant[x][y] = darkness
+
+ bvalues = {}
+ for (x, y), colour in canvas.items():
+ for dx in range(-dmax, dmax+1):
+ for dy in range(-dmax, dmax+1):
+ quadrant = 2 * (dx < 0) + (dy < 0)
+ if (x, y, quadrant) in squarecorners:
+ bval = squadrant[abs(dx)][abs(dy)]
+ else:
+ bval = cquadrant[abs(dx)][abs(dy)]
+ if bvalues.get((x+dx,y+dy),0) < bval:
+ bvalues[(x+dx,y+dy)] = bval
+
+ for (x, y), value in bvalues.items():
+ if not canvas.has_key((x,y)):
+ canvas[(x,y)] = dark(value)
+
+def sysbox(size, out={}):
+ canvas = {}
+
+ # The system box of the computer.
+
+ height = int(round(3.6*size))
+ width = int(round(16.51*size))
+ depth = int(round(2*size))
+ highlight = int(round(1*size))
+ bothighlight = int(round(1*size))
+
+ out["sysboxheight"] = height
+
+ floppystart = int(round(19*size)) # measured in half-pixels
+ floppyend = int(round(29*size)) # measured in half-pixels
+ floppybottom = height - bothighlight
+ floppyrheight = 0.7 * size
+ floppyheight = int(round(floppyrheight))
+ if floppyheight < 1:
+ floppyheight = 1
+ floppytop = floppybottom - floppyheight
+
+ # The front panel is rectangular.
+ for x in range(width):
+ for y in range(height):
+ grey = 3
+ if x < highlight or y < highlight:
+ grey = grey + 1
+ if x >= width-highlight or y >= height-bothighlight:
+ grey = grey - 1
+ if y < highlight and x >= width-highlight:
+ v = (highlight-1-y) - (x-(width-highlight))
+ if v < 0:
+ grey = grey - 1
+ elif v > 0:
+ grey = grey + 1
+ if y >= floppytop and y < floppybottom and \
+ 2*x+2 > floppystart and 2*x < floppyend:
+ if 2*x >= floppystart and 2*x+2 <= floppyend and \
+ floppyrheight >= 0.7:
+ grey = 0
+ else:
+ grey = 2
+ pixel(x, y, greypix(grey/4.0), canvas)
+
+ # The side panel is a parallelogram.
+ for x in range(depth):
+ for y in range(height):
+ pixel(x+width, y-(x+1), greypix(0.5), canvas)
+
+ # The top panel is another parallelogram.
+ for x in range(width-1):
+ for y in range(depth):
+ grey = 3
+ if x >= width-1 - highlight:
+ grey = grey + 1
+ pixel(x+(y+1), -(y+1), greypix(grey/4.0), canvas)
+
+ # And draw a border.
+ border(canvas, size, [], out)
+
+ return canvas
+
+def monitor(size):
+ canvas = {}
+
+ # The computer's monitor.
+
+ height = int(round(9.55*size))
+ width = int(round(11.49*size))
+ surround = int(round(1*size))
+ botsurround = int(round(2*size))
+ sheight = height - surround - botsurround
+ swidth = width - 2*surround
+ depth = int(round(2*size))
+ highlight = int(round(math.sqrt(size)))
+ shadow = int(round(0.55*size))
+
+ # The front panel is rectangular.
+ for x in range(width):
+ for y in range(height):
+ if x >= surround and y >= surround and \
+ x < surround+swidth and y < surround+sheight:
+ # Screen.
+ sx = (float(x-surround) - swidth/3) / swidth
+ sy = (float(y-surround) - sheight/3) / sheight
+ shighlight = 1.0 - (sx*sx+sy*sy)*0.27
+ pix = bluepix(shighlight)
+ if x < surround+shadow or y < surround+shadow:
+ pix = blend(cD, pix) # sharp-edged shadow on top and left
+ else:
+ # Complicated double bevel on the screen surround.
+
+ # First, the outer bevel. We compute the distance
+ # from this pixel to each edge of the front
+ # rectangle.
+ list = [
+ (x, +1),
+ (y, +1),
+ (width-1-x, -1),
+ (height-1-y, -1)
+ ]
+ # Now sort the list to find the distance to the
+ # _nearest_ edge, or the two joint nearest.
+ list.sort()
+ # If there's one nearest edge, that determines our
+ # bevel colour. If there are two joint nearest, our
+ # bevel colour is their shared one if they agree,
+ # and neutral otherwise.
+ outerbevel = 0
+ if list[0][0] < list[1][0] or list[0][1] == list[1][1]:
+ if list[0][0] < highlight:
+ outerbevel = list[0][1]
+
+ # Now, the inner bevel. We compute the distance
+ # from this pixel to each edge of the screen
+ # itself.
+ list = [
+ (surround-1-x, -1),
+ (surround-1-y, -1),
+ (x-(surround+swidth), +1),
+ (y-(surround+sheight), +1)
+ ]
+ # Now we sort to find the _maximum_ distance, which
+ # conveniently ignores any less than zero.
+ list.sort()
+ # And now the strategy is pretty much the same as
+ # above, only we're working from the opposite end
+ # of the list.
+ innerbevel = 0
+ if list[-1][0] > list[-2][0] or list[-1][1] == list[-2][1]:
+ if list[-1][0] >= 0 and list[-1][0] < highlight:
+ innerbevel = list[-1][1]
+
+ # Now we know the adjustment we want to make to the
+ # pixel's overall grey shade due to the outer
+ # bevel, and due to the inner one. We break a tie
+ # in favour of a light outer bevel, but otherwise
+ # add.
+ grey = 3
+ if outerbevel > 0 or outerbevel == innerbevel:
+ innerbevel = 0
+ grey = grey + outerbevel + innerbevel
+
+ pix = greypix(grey / 4.0)
+
+ pixel(x, y, pix, canvas)
+
+ # The side panel is a parallelogram.
+ for x in range(depth):
+ for y in range(height):
+ pixel(x+width, y-x, greypix(0.5), canvas)
+
+ # The top panel is another parallelogram.
+ for x in range(width):
+ for y in range(depth-1):
+ pixel(x+(y+1), -(y+1), greypix(0.75), canvas)
+
+ # And draw a border.
+ border(canvas, size, [(0,int(height-1),BL)])
+
+ return canvas
+
+def computer(size):
+ # Monitor plus sysbox.
+ out = {}
+ m = monitor(size)
+ s = sysbox(size, out)
+ x = int(round((2+size/(size+1))*size))
+ y = int(out["sysboxheight"] + out["borderthickness"])
+ mb = bbox(m)
+ sb = bbox(s)
+ xoff = sb[0] - mb[0] + x
+ yoff = sb[3] - mb[3] - y
+ overlay(m, xoff, yoff, s)
+ return s
+
+def lightning(size):
+ canvas = {}
+
+ # The lightning bolt motif.
+
+ # We always want this to be an even number of pixels in height,
+ # and an odd number in width.
+ width = round(7*size) * 2 - 1
+ height = round(8*size) * 2
+
+ # The outer edge of each side of the bolt goes to this point.
+ outery = round(8.4*size)
+ outerx = round(11*size)
+
+ # And the inner edge goes to this point.
+ innery = height - 1 - outery
+ innerx = round(7*size)
+
+ for y in range(int(height)):
+ list = []
+ if y <= outery:
+ list.append(width-1-int(outerx * float(y) / outery + 0.3))
+ if y <= innery:
+ list.append(width-1-int(innerx * float(y) / innery + 0.3))
+ y0 = height-1-y
+ if y0 <= outery:
+ list.append(int(outerx * float(y0) / outery + 0.3))
+ if y0 <= innery:
+ list.append(int(innerx * float(y0) / innery + 0.3))
+ list.sort()
+ for x in range(int(list[0]), int(list[-1]+1)):
+ pixel(x, y, cY, canvas)
+
+ # And draw a border.
+ border(canvas, size, [(int(width-1),0,TR), (0,int(height-1),BL)])
+
+ return canvas
+
+def document(size):
+ canvas = {}
+
+ # The document used in the PSCP/PSFTP icon.
+
+ width = round(13*size)
+ height = round(16*size)
+
+ lineht = round(1*size)
+ if lineht < 1: lineht = 1
+ linespc = round(0.7*size)
+ if linespc < 1: linespc = 1
+ nlines = int((height-linespc)/(lineht+linespc))
+ height = nlines*(lineht+linespc)+linespc # round this so it fits better
+
+ # Start by drawing a big white rectangle.
+ for y in range(int(height)):
+ for x in range(int(width)):
+ pixel(x, y, cW, canvas)
+
+ # Now draw lines of text.
+ for line in range(nlines):
+ # Decide where this line of text begins.
+ if line == 0:
+ start = round(4*size)
+ elif line < 5*nlines/7:
+ start = round((line - (nlines/7)) * size)
+ else:
+ start = round(1*size)
+ if start < round(1*size):
+ start = round(1*size)
+ # Decide where it ends.
+ endpoints = [10, 8, 11, 6, 5, 7, 5]
+ ey = line * 6.0 / (nlines-1)
+ eyf = math.floor(ey)
+ eyc = math.ceil(ey)
+ exf = endpoints[int(eyf)]
+ exc = endpoints[int(eyc)]
+ if eyf == eyc:
+ end = exf
+ else:
+ end = exf * (eyc-ey) + exc * (ey-eyf)
+ end = round(end * size)
+
+ liney = height - (lineht+linespc) * (line+1)
+ for x in range(int(start), int(end)):
+ for y in range(int(lineht)):
+ pixel(x, y+liney, cK, canvas)
+
+ # And draw a border.
+ border(canvas, size, \
+ [(0,0,TL),(int(width-1),0,TR),(0,int(height-1),BL), \
+ (int(width-1),int(height-1),BR)])
+
+ return canvas
+
+def hat(size):
+ canvas = {}
+
+ # The secret-agent hat in the Pageant icon.
+
+ topa = [6]*9+[5,3,1,0,0,1,2,2,1,1,1,9,9,10,10,11,11,12,12]
+ topa = [round(x*size) for x in topa]
+ botl = round(topa[0]+2.4*math.sqrt(size))
+ botr = round(topa[-1]+2.4*math.sqrt(size))
+ width = round(len(topa)*size)
+
+ # Line equations for the top and bottom of the hat brim, in the
+ # form y=mx+c. c, of course, needs scaling by size, but m is
+ # independent of size.
+ brimm = 1.0 / 3.75
+ brimtopc = round(4*size/3)
+ brimbotc = round(10*size/3)
+
+ for x in range(int(width)):
+ xs = float(x) * (len(topa)-1) / (width-1)
+ xf = math.floor(xs)
+ xc = math.ceil(xs)
+ topf = topa[int(xf)]
+ topc = topa[int(xc)]
+ if xf == xc:
+ top = topf
+ else:
+ top = topf * (xc-xs) + topc * (xs-xf)
+ top = math.floor(top)
+ bot = round(botl + (botr-botl) * x/(width-1))
+
+ for y in range(int(top), int(bot)):
+ pixel(x, y, cK, canvas)
+
+ # Now draw the brim.
+ for x in range(int(width)):
+ brimtop = brimtopc + brimm * x
+ brimbot = brimbotc + brimm * x
+ for y in range(int(math.floor(brimtop)), int(math.ceil(brimbot))):
+ tophere = max(min(brimtop - y, 1), 0)
+ bothere = max(min(brimbot - y, 1), 0)
+ grey = bothere - tophere
+ # Only draw brim pixels over pixels which are (a) part
+ # of the main hat, and (b) not right on its edge.
+ if canvas.has_key((x,y)) and \
+ canvas.has_key((x,y-1)) and \
+ canvas.has_key((x,y+1)) and \
+ canvas.has_key((x-1,y)) and \
+ canvas.has_key((x+1,y)):
+ pixel(x, y, greypix(grey), canvas)
+
+ return canvas
+
+def key(size):
+ canvas = {}
+
+ # The key in the PuTTYgen icon.
+
+ keyheadw = round(9.5*size)
+ keyheadh = round(12*size)
+ keyholed = round(4*size)
+ keyholeoff = round(2*size)
+ # Ensure keyheadh and keyshafth have the same parity.
+ keyshafth = round((2*size - (int(keyheadh)&1)) / 2) * 2 + (int(keyheadh)&1)
+ keyshaftw = round(18.5*size)
+ keyhead = [round(x*size) for x in [12,11,8,10,9,8,11,12]]
+
+ squarepix = []
+
+ # Ellipse for the key head, minus an off-centre circular hole.
+ for y in range(int(keyheadh)):
+ dy = (y-(keyheadh-1)/2.0) / (keyheadh/2.0)
+ dyh = (y-(keyheadh-1)/2.0) / (keyholed/2.0)
+ for x in range(int(keyheadw)):
+ dx = (x-(keyheadw-1)/2.0) / (keyheadw/2.0)
+ dxh = (x-(keyheadw-1)/2.0-keyholeoff) / (keyholed/2.0)
+ if dy*dy+dx*dx <= 1 and dyh*dyh+dxh*dxh > 1:
+ pixel(x + keyshaftw, y, cy, canvas)
+
+ # Rectangle for the key shaft, extended at the bottom for the
+ # key head detail.
+ for x in range(int(keyshaftw)):
+ top = round((keyheadh - keyshafth) / 2)
+ bot = round((keyheadh + keyshafth) / 2)
+ xs = float(x) * (len(keyhead)-1) / round((len(keyhead)-1)*size)
+ xf = math.floor(xs)
+ xc = math.ceil(xs)
+ in_head = 0
+ if xc < len(keyhead):
+ in_head = 1
+ yf = keyhead[int(xf)]
+ yc = keyhead[int(xc)]
+ if xf == xc:
+ bot = yf
+ else:
+ bot = yf * (xc-xs) + yc * (xs-xf)
+ for y in range(int(top),int(bot)):
+ pixel(x, y, cy, canvas)
+ if in_head:
+ last = (x, y)
+ if x == 0:
+ squarepix.append((x, int(top), TL))
+ if x == 0:
+ squarepix.append(last + (BL,))
+ if last != None and not in_head:
+ squarepix.append(last + (BR,))
+ last = None
+
+ # And draw a border.
+ border(canvas, size, squarepix)
+
+ return canvas
+
+def linedist(x1,y1, x2,y2, x,y):
+ # Compute the distance from the point x,y to the line segment
+ # joining x1,y1 to x2,y2. Returns the distance vector, measured
+ # with x,y at the origin.
+
+ vectors = []
+
+ # Special case: if x1,y1 and x2,y2 are the same point, we
+ # don't attempt to extrapolate it into a line at all.
+ if x1 != x2 or y1 != y2:
+ # First, find the nearest point to x,y on the infinite
+ # projection of the line segment. So we construct a vector
+ # n perpendicular to that segment...
+ nx = y2-y1
+ ny = x1-x2
+ # ... compute the dot product of (x1,y1)-(x,y) with that
+ # vector...
+ nd = (x1-x)*nx + (y1-y)*ny
+ # ... multiply by the vector we first thought of...
+ ndx = nd * nx
+ ndy = nd * ny
+ # ... and divide twice by the length of n.
+ ndx = ndx / (nx*nx+ny*ny)
+ ndy = ndy / (nx*nx+ny*ny)
+ # That gives us a displacement vector from x,y to the
+ # nearest point. See if it's within the range of the line
+ # segment.
+ cx = x + ndx
+ cy = y + ndy
+ if cx >= min(x1,x2) and cx <= max(x1,x2) and \
+ cy >= min(y1,y2) and cy <= max(y1,y2):
+ vectors.append((ndx,ndy))
+
+ # Now we have up to three candidate result vectors: (ndx,ndy)
+ # as computed just above, and the two vectors to the ends of
+ # the line segment, (x1-x,y1-y) and (x2-x,y2-y). Pick the
+ # shortest.
+ vectors = vectors + [(x1-x,y1-y), (x2-x,y2-y)]
+ bestlen, best = None, None
+ for v in vectors:
+ vlen = v[0]*v[0]+v[1]*v[1]
+ if bestlen == None or bestlen > vlen:
+ bestlen = vlen
+ best = v
+ return best
+
+def spanner(size):
+ canvas = {}
+
+ # The spanner in the config box icon.
+
+ headcentre = 0.5 + round(4*size)
+ headradius = headcentre + 0.1
+ headhighlight = round(1.5*size)
+ holecentre = 0.5 + round(3*size)
+ holeradius = round(2*size)
+ holehighlight = round(1.5*size)
+ shaftend = 0.5 + round(25*size)
+ shaftwidth = round(2*size)
+ shafthighlight = round(1.5*size)
+ cmax = shaftend + shaftwidth
+
+ # Define three line segments, such that the shortest distance
+ # vectors from any point to each of these segments determines
+ # everything we need to know about where it is on the spanner
+ # shape.
+ segments = [
+ ((0,0), (holecentre, holecentre)),
+ ((headcentre, headcentre), (headcentre, headcentre)),
+ ((headcentre+headradius/math.sqrt(2), headcentre+headradius/math.sqrt(2)),
+ (cmax, cmax))
+ ]
+
+ for y in range(int(cmax)):
+ for x in range(int(cmax)):
+ vectors = [linedist(a,b,c,d,x,y) for ((a,b),(c,d)) in segments]
+ dists = [memoisedsqrt(vx*vx+vy*vy) for (vx,vy) in vectors]
+
+ # If the distance to the hole line is less than
+ # holeradius, we're not part of the spanner.
+ if dists[0] < holeradius:
+ continue
+ # If the distance to the head `line' is less than
+ # headradius, we are part of the spanner; likewise if
+ # the distance to the shaft line is less than
+ # shaftwidth _and_ the resulting shaft point isn't
+ # beyond the shaft end.
+ if dists[1] > headradius and \
+ (dists[2] > shaftwidth or x+vectors[2][0] >= shaftend):
+ continue
+
+ # We're part of the spanner. Now compute the highlight
+ # on this pixel. We do this by computing a `slope
+ # vector', which points from this pixel in the
+ # direction of its nearest edge. We store an array of
+ # slope vectors, in polar coordinates.
+ angles = [math.atan2(vy,vx) for (vx,vy) in vectors]
+ slopes = []
+ if dists[0] < holeradius + holehighlight:
+ slopes.append(((dists[0]-holeradius)/holehighlight,angles[0]))
+ if dists[1]/headradius < dists[2]/shaftwidth:
+ if dists[1] > headradius - headhighlight and dists[1] < headradius:
+ slopes.append(((headradius-dists[1])/headhighlight,math.pi+angles[1]))
+ else:
+ if dists[2] > shaftwidth - shafthighlight and dists[2] < shaftwidth:
+ slopes.append(((shaftwidth-dists[2])/shafthighlight,math.pi+angles[2]))
+ # Now we find the smallest distance in that array, if
+ # any, and that gives us a notional position on a
+ # sphere which we can use to compute the final
+ # highlight level.
+ bestdist = None
+ bestangle = 0
+ for dist, angle in slopes:
+ if bestdist == None or bestdist > dist:
+ bestdist = dist
+ bestangle = angle
+ if bestdist == None:
+ bestdist = 1.0
+ sx = (1.0-bestdist) * math.cos(bestangle)
+ sy = (1.0-bestdist) * math.sin(bestangle)
+ sz = math.sqrt(1.0 - sx*sx - sy*sy)
+ shade = sx-sy+sz / math.sqrt(3) # can range from -1 to +1
+ shade = 1.0 - (1-shade)/3
+
+ pixel(x, y, yellowpix(shade), canvas)
+
+ # And draw a border.
+ border(canvas, size, [])
+
+ return canvas
+
+def box(size, back):
+ canvas = {}
+
+ # The back side of the cardboard box in the installer icon.
+
+ boxwidth = round(15 * size)
+ boxheight = round(12 * size)
+ boxdepth = round(4 * size)
+ boxfrontflapheight = round(5 * size)
+ boxrightflapheight = round(3 * size)
+
+ # Three shades of basically acceptable brown, all achieved by
+ # halftoning between two of the Windows-16 colours. I'm quite
+ # pleased that was feasible at all!
+ dark = halftone(cr, cK)
+ med = halftone(cr, cy)
+ light = halftone(cr, cY)
+ # We define our halftoning parity in such a way that the black
+ # pixels along the RHS of the visible part of the box back
+ # match up with the one-pixel black outline around the
+ # right-hand side of the box. In other words, we want the pixel
+ # at (-1, boxwidth-1) to be black, and hence the one at (0,
+ # boxwidth) too.
+ parityadjust = int(boxwidth) % 2
+
+ # The entire back of the box.
+ if back:
+ for x in range(int(boxwidth + boxdepth)):
+ ytop = max(-x-1, -boxdepth-1)
+ ybot = min(boxheight, boxheight+boxwidth-1-x)
+ for y in range(int(ytop), int(ybot)):
+ pixel(x, y, dark[(x+y+parityadjust) % 2], canvas)
+
+ # Even when drawing the back of the box, we still draw the
+ # whole shape, because that means we get the right overall size
+ # (the flaps make the box front larger than the box back) and
+ # it'll all be overwritten anyway.
+
+ # The front face of the box.
+ for x in range(int(boxwidth)):
+ for y in range(int(boxheight)):
+ pixel(x, y, med[(x+y+parityadjust) % 2], canvas)
+ # The right face of the box.
+ for x in range(int(boxwidth), int(boxwidth+boxdepth)):
+ ybot = boxheight + boxwidth-x
+ ytop = ybot - boxheight
+ for y in range(int(ytop), int(ybot)):
+ pixel(x, y, dark[(x+y+parityadjust) % 2], canvas)
+ # The front flap of the box.
+ for y in range(int(boxfrontflapheight)):
+ xadj = int(round(-0.5*y))
+ for x in range(int(xadj), int(xadj+boxwidth)):
+ pixel(x, y, light[(x+y+parityadjust) % 2], canvas)
+ # The right flap of the box.
+ for x in range(int(boxwidth), int(boxwidth + boxdepth + boxrightflapheight + 1)):
+ ytop = max(boxwidth - 1 - x, x - boxwidth - 2*boxdepth - 1)
+ ybot = min(x - boxwidth - 1, boxwidth + 2*boxrightflapheight - 1 - x)
+ for y in range(int(ytop), int(ybot+1)):
+ pixel(x, y, med[(x+y+parityadjust) % 2], canvas)
+
+ # And draw a border.
+ border(canvas, size, [(0, int(boxheight)-1, BL)])
+
+ return canvas
+
+def boxback(size):
+ return box(size, 1)
+def boxfront(size):
+ return box(size, 0)
+
+# Functions to draw entire icons by composing the above components.
+
+def xybolt(c1, c2, size, boltoffx=0, boltoffy=0, aux={}):
+ # Two unspecified objects and a lightning bolt.
+
+ canvas = {}
+ w = h = round(32 * size)
+
+ bolt = lightning(size)
+
+ # Position c2 against the top right of the icon.
+ bb = bbox(c2)
+ assert bb[2]-bb[0] <= w and bb[3]-bb[1] <= h
+ overlay(c2, w-bb[2], 0-bb[1], canvas)
+ aux["c2pos"] = (w-bb[2], 0-bb[1])
+ # Position c1 against the bottom left of the icon.
+ bb = bbox(c1)
+ assert bb[2]-bb[0] <= w and bb[3]-bb[1] <= h
+ overlay(c1, 0-bb[0], h-bb[3], canvas)
+ aux["c1pos"] = (0-bb[0], h-bb[3])
+ # Place the lightning bolt artistically off-centre. (The
+ # rationale for this positioning is that it's centred on the
+ # midpoint between the centres of the two monitors in the PuTTY
+ # icon proper, but it's not really feasible to _base_ the
+ # calculation here on that.)
+ bb = bbox(bolt)
+ assert bb[2]-bb[0] <= w and bb[3]-bb[1] <= h
+ overlay(bolt, (w-bb[0]-bb[2])/2 + round(boltoffx*size), \
+ (h-bb[1]-bb[3])/2 + round((boltoffy-2)*size), canvas)
+
+ return canvas
+
+def putty_icon(size):
+ return xybolt(computer(size), computer(size), size)
+
+def puttycfg_icon(size):
+ w = h = round(32 * size)
+ s = spanner(size)
+ canvas = putty_icon(size)
+ # Centre the spanner.
+ bb = bbox(s)
+ overlay(s, (w-bb[0]-bb[2])/2, (h-bb[1]-bb[3])/2, canvas)
+ return canvas
+
+def puttygen_icon(size):
+ return xybolt(computer(size), key(size), size, boltoffx=2)
+
+def pscp_icon(size):
+ return xybolt(document(size), computer(size), size)
+
+def puttyins_icon(size):
+ aret = {}
+ # The box back goes behind the lightning bolt.
+ canvas = xybolt(boxback(size), computer(size), size, boltoffx=-2, boltoffy=+1, aux=aret)
+ # But the box front goes over the top, so that the lightning
+ # bolt appears to come _out_ of the box. Here it's useful to
+ # know the exact coordinates where xybolt placed the box back,
+ # so we can overlay the box front exactly on top of it.
+ c1x, c1y = aret["c1pos"]
+ overlay(boxfront(size), c1x, c1y, canvas)
+ return canvas
+
+def pterm_icon(size):
+ # Just a really big computer.
+
+ canvas = {}
+ w = h = round(32 * size)
+
+ c = computer(size * 1.4)
+
+ # Centre c in the return canvas.
+ bb = bbox(c)
+ assert bb[2]-bb[0] <= w and bb[3]-bb[1] <= h
+ overlay(c, (w-bb[0]-bb[2])/2, (h-bb[1]-bb[3])/2, canvas)
+
+ return canvas
+
+def ptermcfg_icon(size):
+ w = h = round(32 * size)
+ s = spanner(size)
+ canvas = pterm_icon(size)
+ # Centre the spanner.
+ bb = bbox(s)
+ overlay(s, (w-bb[0]-bb[2])/2, (h-bb[1]-bb[3])/2, canvas)
+ return canvas
+
+def pageant_icon(size):
+ # A biggish computer, in a hat.
+
+ canvas = {}
+ w = h = round(32 * size)
+
+ c = computer(size * 1.2)
+ ht = hat(size)
+
+ cbb = bbox(c)
+ hbb = bbox(ht)
+
+ # Determine the relative y-coordinates of the computer and hat.
+ # We just centre the one on the other.
+ xrel = (cbb[0]+cbb[2]-hbb[0]-hbb[2])/2
+
+ # Determine the relative y-coordinates of the computer and hat.
+ # We do this by sitting the hat as low down on the computer as
+ # possible without any computer showing over the top. To do
+ # this we first have to find the minimum x coordinate at each
+ # y-coordinate of both components.
+ cty = topy(c)
+ hty = topy(ht)
+ yrelmin = None
+ for cx in cty.keys():
+ hx = cx - xrel
+ assert hty.has_key(hx)
+ yrel = cty[cx] - hty[hx]
+ if yrelmin == None:
+ yrelmin = yrel
+ else:
+ yrelmin = min(yrelmin, yrel)
+
+ # Overlay the hat on the computer.
+ overlay(ht, xrel, yrelmin, c)
+
+ # And centre the result in the main icon canvas.
+ bb = bbox(c)
+ assert bb[2]-bb[0] <= w and bb[3]-bb[1] <= h
+ overlay(c, (w-bb[0]-bb[2])/2, (h-bb[1]-bb[3])/2, canvas)
+
+ return canvas
+
+# Test and output functions.
+
+import os
+import sys
+
+def testrun(func, fname):
+ canvases = []
+ for size in [0.5, 0.6, 1.0, 1.2, 1.5, 4.0]:
+ canvases.append(func(size))
+ wid = 0
+ ht = 0
+ for canvas in canvases:
+ minx, miny, maxx, maxy = bbox(canvas)
+ wid = max(wid, maxx-minx+4)
+ ht = ht + maxy-miny+4
+ block = []
+ for canvas in canvases:
+ minx, miny, maxx, maxy = bbox(canvas)
+ block.extend(render(canvas, minx-2, miny-2, minx-2+wid, maxy+2))
+ p = os.popen("convert -depth 8 -size %dx%d rgb:- %s" % (wid,ht,fname), "w")
+ assert len(block) == ht
+ for line in block:
+ assert len(line) == wid
+ for r, g, b, a in line:
+ # Composite on to orange.
+ r = int(round((r * a + 255 * (255-a)) / 255.0))
+ g = int(round((g * a + 128 * (255-a)) / 255.0))
+ b = int(round((b * a + 0 * (255-a)) / 255.0))
+ p.write("%c%c%c" % (r,g,b))
+ p.close()
+
+def drawicon(func, width, fname, orangebackground = 0):
+ canvas = func(width / 32.0)
+ finalise(canvas)
+ minx, miny, maxx, maxy = bbox(canvas)
+ assert minx >= 0 and miny >= 0 and maxx <= width and maxy <= width
+
+ block = render(canvas, 0, 0, width, width)
+ p = os.popen("convert -depth 8 -size %dx%d rgba:- %s" % (width,width,fname), "w")
+ assert len(block) == width
+ for line in block:
+ assert len(line) == width
+ for r, g, b, a in line:
+ if orangebackground:
+ # Composite on to orange.
+ r = int(round((r * a + 255 * (255-a)) / 255.0))
+ g = int(round((g * a + 128 * (255-a)) / 255.0))
+ b = int(round((b * a + 0 * (255-a)) / 255.0))
+ a = 255
+ p.write("%c%c%c%c" % (r,g,b,a))
+ p.close()
+
+args = sys.argv[1:]
+
+orangebackground = test = 0
+colours = 1 # 0=mono, 1=16col, 2=truecol
+doingargs = 1
+
+realargs = []
+for arg in args:
+ if doingargs and arg[0] == "-":
+ if arg == "-t":
+ test = 1
+ elif arg == "-it":
+ orangebackground = 1
+ elif arg == "-2":
+ colours = 0
+ elif arg == "-T":
+ colours = 2
+ elif arg == "--":
+ doingargs = 0
+ else:
+ sys.stderr.write("unrecognised option '%s'\n" % arg)
+ sys.exit(1)
+ else:
+ realargs.append(arg)
+
+if colours == 0:
+ # Monochrome.
+ cK=cr=cg=cb=cm=cc=cP=cw=cR=cG=cB=cM=cC=cD = 0
+ cY=cy=cW = 1
+ cT = -1
+ def greypix(value):
+ return [cK,cW][int(round(value))]
+ def yellowpix(value):
+ return [cK,cW][int(round(value))]
+ def bluepix(value):
+ return cK
+ def dark(value):
+ return [cT,cK][int(round(value))]
+ def blend(col1, col2):
+ if col1 == cT:
+ return col2
+ else:
+ return col1
+ pixvals = [
+ (0x00, 0x00, 0x00, 0xFF), # cK
+ (0xFF, 0xFF, 0xFF, 0xFF), # cW
+ (0x00, 0x00, 0x00, 0x00), # cT
+ ]
+ def outpix(colour):
+ return pixvals[colour]
+ def finalisepix(colour):
+ return colour
+ def halftone(col1, col2):
+ return (col1, col2)
+elif colours == 1:
+ # Windows 16-colour palette.
+ cK,cr,cg,cy,cb,cm,cc,cP,cw,cR,cG,cY,cB,cM,cC,cW = range(16)
+ cT = -1
+ cD = -2 # special translucent half-darkening value used internally
+ def greypix(value):
+ return [cK,cw,cw,cP,cW][int(round(4*value))]
+ def yellowpix(value):
+ return [cK,cy,cY][int(round(2*value))]
+ def bluepix(value):
+ return [cK,cb,cB][int(round(2*value))]
+ def dark(value):
+ return [cT,cD,cK][int(round(2*value))]
+ def blend(col1, col2):
+ if col1 == cT:
+ return col2
+ elif col1 == cD:
+ return [cK,cK,cK,cK,cK,cK,cK,cw,cK,cr,cg,cy,cb,cm,cc,cw,cD,cD][col2]
+ else:
+ return col1
+ pixvals = [
+ (0x00, 0x00, 0x00, 0xFF), # cK
+ (0x80, 0x00, 0x00, 0xFF), # cr
+ (0x00, 0x80, 0x00, 0xFF), # cg
+ (0x80, 0x80, 0x00, 0xFF), # cy
+ (0x00, 0x00, 0x80, 0xFF), # cb
+ (0x80, 0x00, 0x80, 0xFF), # cm
+ (0x00, 0x80, 0x80, 0xFF), # cc
+ (0xC0, 0xC0, 0xC0, 0xFF), # cP
+ (0x80, 0x80, 0x80, 0xFF), # cw
+ (0xFF, 0x00, 0x00, 0xFF), # cR
+ (0x00, 0xFF, 0x00, 0xFF), # cG
+ (0xFF, 0xFF, 0x00, 0xFF), # cY
+ (0x00, 0x00, 0xFF, 0xFF), # cB
+ (0xFF, 0x00, 0xFF, 0xFF), # cM
+ (0x00, 0xFF, 0xFF, 0xFF), # cC
+ (0xFF, 0xFF, 0xFF, 0xFF), # cW
+ (0x00, 0x00, 0x00, 0x80), # cD
+ (0x00, 0x00, 0x00, 0x00), # cT
+ ]
+ def outpix(colour):
+ return pixvals[colour]
+ def finalisepix(colour):
+ # cD is used internally, but can't be output. Convert to cK.
+ if colour == cD:
+ return cK
+ return colour
+ def halftone(col1, col2):
+ return (col1, col2)
+else:
+ # True colour.
+ cK = (0x00, 0x00, 0x00, 0xFF)
+ cr = (0x80, 0x00, 0x00, 0xFF)
+ cg = (0x00, 0x80, 0x00, 0xFF)
+ cy = (0x80, 0x80, 0x00, 0xFF)
+ cb = (0x00, 0x00, 0x80, 0xFF)
+ cm = (0x80, 0x00, 0x80, 0xFF)
+ cc = (0x00, 0x80, 0x80, 0xFF)
+ cP = (0xC0, 0xC0, 0xC0, 0xFF)
+ cw = (0x80, 0x80, 0x80, 0xFF)
+ cR = (0xFF, 0x00, 0x00, 0xFF)
+ cG = (0x00, 0xFF, 0x00, 0xFF)
+ cY = (0xFF, 0xFF, 0x00, 0xFF)
+ cB = (0x00, 0x00, 0xFF, 0xFF)
+ cM = (0xFF, 0x00, 0xFF, 0xFF)
+ cC = (0x00, 0xFF, 0xFF, 0xFF)
+ cW = (0xFF, 0xFF, 0xFF, 0xFF)
+ cD = (0x00, 0x00, 0x00, 0x80)
+ cT = (0x00, 0x00, 0x00, 0x00)
+ def greypix(value):
+ value = max(min(value, 1), 0)
+ return (int(round(0xFF*value)),) * 3 + (0xFF,)
+ def yellowpix(value):
+ value = max(min(value, 1), 0)
+ return (int(round(0xFF*value)),) * 2 + (0, 0xFF)
+ def bluepix(value):
+ value = max(min(value, 1), 0)
+ return (0, 0, int(round(0xFF*value)), 0xFF)
+ def dark(value):
+ value = max(min(value, 1), 0)
+ return (0, 0, 0, int(round(0xFF*value)))
+ def blend(col1, col2):
+ r1,g1,b1,a1 = col1
+ r2,g2,b2,a2 = col2
+ r = int(round((r1*a1 + r2*(0xFF-a1)) / 255.0))
+ g = int(round((g1*a1 + g2*(0xFF-a1)) / 255.0))
+ b = int(round((b1*a1 + b2*(0xFF-a1)) / 255.0))
+ a = int(round((255*a1 + a2*(0xFF-a1)) / 255.0))
+ return r, g, b, a
+ def outpix(colour):
+ return colour
+ if colours == 2:
+ # True colour with no alpha blending: we still have to
+ # finalise half-dark pixels to black.
+ def finalisepix(colour):
+ if colour[3] > 0:
+ return colour[:3] + (0xFF,)
+ return colour
+ else:
+ def finalisepix(colour):
+ return colour
+ def halftone(col1, col2):
+ r1,g1,b1,a1 = col1
+ r2,g2,b2,a2 = col2
+ colret = (int(r1+r2)/2, int(g1+g2)/2, int(b1+b2)/2, int(a1+a2)/2)
+ return (colret, colret)
+
+if test:
+ testrun(eval(realargs[0]), realargs[1])
+else:
+ drawicon(eval(realargs[0]), int(realargs[1]), realargs[2], orangebackground)
diff --git a/puttysrc/IMPORT.C b/puttysrc/IMPORT.C
new file mode 100644
index 0000000..098c793
--- /dev/null
+++ b/puttysrc/IMPORT.C
@@ -0,0 +1,1689 @@
+/*
+ * Code for PuTTY to import and export private key files in other
+ * SSH clients' formats.
+ */
+
+#include
+#include
+#include
+#include
+
+#include "putty.h"
+#include "ssh.h"
+#include "misc.h"
+
+int openssh_encrypted(const Filename *filename);
+struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase,
+ const char **errmsg_p);
+int openssh_write(const Filename *filename, struct ssh2_userkey *key,
+ char *passphrase);
+
+int sshcom_encrypted(const Filename *filename, char **comment);
+struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase,
+ const char **errmsg_p);
+int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
+ char *passphrase);
+
+/*
+ * Given a key type, determine whether we know how to import it.
+ */
+int import_possible(int type)
+{
+ if (type == SSH_KEYTYPE_OPENSSH)
+ return 1;
+ if (type == SSH_KEYTYPE_SSHCOM)
+ return 1;
+ return 0;
+}
+
+/*
+ * Given a key type, determine what native key type
+ * (SSH_KEYTYPE_SSH1 or SSH_KEYTYPE_SSH2) it will come out as once
+ * we've imported it.
+ */
+int import_target_type(int type)
+{
+ /*
+ * There are no known foreign SSH-1 key formats.
+ */
+ return SSH_KEYTYPE_SSH2;
+}
+
+/*
+ * Determine whether a foreign key is encrypted.
+ */
+int import_encrypted(const Filename *filename, int type, char **comment)
+{
+ if (type == SSH_KEYTYPE_OPENSSH) {
+ /* OpenSSH doesn't do key comments */
+ *comment = dupstr(filename_to_str(filename));
+ return openssh_encrypted(filename);
+ }
+ if (type == SSH_KEYTYPE_SSHCOM) {
+ return sshcom_encrypted(filename, comment);
+ }
+ return 0;
+}
+
+/*
+ * Import an SSH-1 key.
+ */
+int import_ssh1(const Filename *filename, int type,
+ struct RSAKey *key, char *passphrase, const char **errmsg_p)
+{
+ return 0;
+}
+
+/*
+ * Import an SSH-2 key.
+ */
+struct ssh2_userkey *import_ssh2(const Filename *filename, int type,
+ char *passphrase, const char **errmsg_p)
+{
+ if (type == SSH_KEYTYPE_OPENSSH)
+ return openssh_read(filename, passphrase, errmsg_p);
+ if (type == SSH_KEYTYPE_SSHCOM)
+ return sshcom_read(filename, passphrase, errmsg_p);
+ return NULL;
+}
+
+/*
+ * Export an SSH-1 key.
+ */
+int export_ssh1(const Filename *filename, int type, struct RSAKey *key,
+ char *passphrase)
+{
+ return 0;
+}
+
+/*
+ * Export an SSH-2 key.
+ */
+int export_ssh2(const Filename *filename, int type,
+ struct ssh2_userkey *key, char *passphrase)
+{
+ if (type == SSH_KEYTYPE_OPENSSH)
+ return openssh_write(filename, key, passphrase);
+ if (type == SSH_KEYTYPE_SSHCOM)
+ return sshcom_write(filename, key, passphrase);
+ return 0;
+}
+
+/*
+ * Strip trailing CRs and LFs at the end of a line of text.
+ */
+void strip_crlf(char *str)
+{
+ char *p = str + strlen(str);
+
+ while (p > str && (p[-1] == '\r' || p[-1] == '\n'))
+ *--p = '\0';
+}
+
+/* ----------------------------------------------------------------------
+ * Helper routines. (The base64 ones are defined in sshpubk.c.)
+ */
+
+#define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \
+ ((c) >= 'a' && (c) <= 'z') || \
+ ((c) >= '0' && (c) <= '9') || \
+ (c) == '+' || (c) == '/' || (c) == '=' \
+ )
+
+/*
+ * Read an ASN.1/BER identifier and length pair.
+ *
+ * Flags are a combination of the #defines listed below.
+ *
+ * Returns -1 if unsuccessful; otherwise returns the number of
+ * bytes used out of the source data.
+ */
+
+/* ASN.1 tag classes. */
+#define ASN1_CLASS_UNIVERSAL (0 << 6)
+#define ASN1_CLASS_APPLICATION (1 << 6)
+#define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6)
+#define ASN1_CLASS_PRIVATE (3 << 6)
+#define ASN1_CLASS_MASK (3 << 6)
+
+/* Primitive versus constructed bit. */
+#define ASN1_CONSTRUCTED (1 << 5)
+
+static int ber_read_id_len(void *source, int sourcelen,
+ int *id, int *length, int *flags)
+{
+ unsigned char *p = (unsigned char *) source;
+
+ if (sourcelen == 0)
+ return -1;
+
+ *flags = (*p & 0xE0);
+ if ((*p & 0x1F) == 0x1F) {
+ *id = 0;
+ while (*p & 0x80) {
+ p++, sourcelen--;
+ if (sourcelen == 0)
+ return -1;
+ *id = (*id << 7) | (*p & 0x7F);
+ }
+ p++, sourcelen--;
+ } else {
+ *id = *p & 0x1F;
+ p++, sourcelen--;
+ }
+
+ if (sourcelen == 0)
+ return -1;
+
+ if (*p & 0x80) {
+ int n = *p & 0x7F;
+ p++, sourcelen--;
+ if (sourcelen < n)
+ return -1;
+ *length = 0;
+ while (n--)
+ *length = (*length << 8) | (*p++);
+ sourcelen -= n;
+ } else {
+ *length = *p;
+ p++, sourcelen--;
+ }
+
+ return p - (unsigned char *) source;
+}
+
+/*
+ * Write an ASN.1/BER identifier and length pair. Returns the
+ * number of bytes consumed. Assumes dest contains enough space.
+ * Will avoid writing anything if dest is NULL, but still return
+ * amount of space required.
+ */
+static int ber_write_id_len(void *dest, int id, int length, int flags)
+{
+ unsigned char *d = (unsigned char *)dest;
+ int len = 0;
+
+ if (id <= 30) {
+ /*
+ * Identifier is one byte.
+ */
+ len++;
+ if (d) *d++ = id | flags;
+ } else {
+ int n;
+ /*
+ * Identifier is multiple bytes: the first byte is 11111
+ * plus the flags, and subsequent bytes encode the value of
+ * the identifier, 7 bits at a time, with the top bit of
+ * each byte 1 except the last one which is 0.
+ */
+ len++;
+ if (d) *d++ = 0x1F | flags;
+ for (n = 1; (id >> (7*n)) > 0; n++)
+ continue; /* count the bytes */
+ while (n--) {
+ len++;
+ if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F);
+ }
+ }
+
+ if (length < 128) {
+ /*
+ * Length is one byte.
+ */
+ len++;
+ if (d) *d++ = length;
+ } else {
+ int n;
+ /*
+ * Length is multiple bytes. The first is 0x80 plus the
+ * number of subsequent bytes, and the subsequent bytes
+ * encode the actual length.
+ */
+ for (n = 1; (length >> (8*n)) > 0; n++)
+ continue; /* count the bytes */
+ len++;
+ if (d) *d++ = 0x80 | n;
+ while (n--) {
+ len++;
+ if (d) *d++ = (length >> (8*n)) & 0xFF;
+ }
+ }
+
+ return len;
+}
+
+static int put_string(void *target, void *data, int len)
+{
+ unsigned char *d = (unsigned char *)target;
+
+ PUT_32BIT(d, len);
+ memcpy(d+4, data, len);
+ return len+4;
+}
+
+static int put_mp(void *target, void *data, int len)
+{
+ unsigned char *d = (unsigned char *)target;
+ unsigned char *i = (unsigned char *)data;
+
+ if (*i & 0x80) {
+ PUT_32BIT(d, len+1);
+ d[4] = 0;
+ memcpy(d+5, data, len);
+ return len+5;
+ } else {
+ PUT_32BIT(d, len);
+ memcpy(d+4, data, len);
+ return len+4;
+ }
+}
+
+/* Simple structure to point to an mp-int within a blob. */
+struct mpint_pos { void *start; int bytes; };
+
+static int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret)
+{
+ int bytes;
+ unsigned char *d = (unsigned char *) data;
+
+ if (len < 4)
+ goto error;
+ bytes = GET_32BIT(d);
+ if (len < 4+bytes)
+ goto error;
+
+ ret->start = d + 4;
+ ret->bytes = bytes;
+ return bytes+4;
+
+ error:
+ ret->start = NULL;
+ ret->bytes = -1;
+ return len; /* ensure further calls fail as well */
+}
+
+/* ----------------------------------------------------------------------
+ * Code to read and write OpenSSH private keys.
+ */
+
+enum { OSSH_DSA, OSSH_RSA };
+struct openssh_key {
+ int type;
+ int encrypted;
+ char iv[32];
+ unsigned char *keyblob;
+ int keyblob_len, keyblob_size;
+};
+
+static struct openssh_key *load_openssh_key(const Filename *filename,
+ const char **errmsg_p)
+{
+ struct openssh_key *ret;
+ FILE *fp;
+ char *line = NULL;
+ char *errmsg, *p;
+ int headers_done;
+ char base64_bit[4];
+ int base64_chars = 0;
+
+ ret = snew(struct openssh_key);
+ ret->keyblob = NULL;
+ ret->keyblob_len = ret->keyblob_size = 0;
+ ret->encrypted = 0;
+ memset(ret->iv, 0, sizeof(ret->iv));
+
+ fp = f_open(*filename, "r", FALSE);
+ if (!fp) {
+ errmsg = "unable to open key file";
+ goto error;
+ }
+
+ if (!(line = fgetline(fp))) {
+ errmsg = "unexpected end of file";
+ goto error;
+ }
+ strip_crlf(line);
+ if (0 != strncmp(line, "-----BEGIN ", 11) ||
+ 0 != strcmp(line+strlen(line)-16, "PRIVATE KEY-----")) {
+ errmsg = "file does not begin with OpenSSH key header";
+ goto error;
+ }
+ if (!strcmp(line, "-----BEGIN RSA PRIVATE KEY-----"))
+ ret->type = OSSH_RSA;
+ else if (!strcmp(line, "-----BEGIN DSA PRIVATE KEY-----"))
+ ret->type = OSSH_DSA;
+ else {
+ errmsg = "unrecognised key type";
+ goto error;
+ }
+ memset(line, 0, strlen(line));
+ sfree(line);
+ line = NULL;
+
+ headers_done = 0;
+ while (1) {
+ if (!(line = fgetline(fp))) {
+ errmsg = "unexpected end of file";
+ goto error;
+ }
+ strip_crlf(line);
+ if (0 == strncmp(line, "-----END ", 9) &&
+ 0 == strcmp(line+strlen(line)-16, "PRIVATE KEY-----"))
+ break; /* done */
+ if ((p = strchr(line, ':')) != NULL) {
+ if (headers_done) {
+ errmsg = "header found in body of key data";
+ goto error;
+ }
+ *p++ = '\0';
+ while (*p && isspace((unsigned char)*p)) p++;
+ if (!strcmp(line, "Proc-Type")) {
+ if (p[0] != '4' || p[1] != ',') {
+ errmsg = "Proc-Type is not 4 (only 4 is supported)";
+ goto error;
+ }
+ p += 2;
+ if (!strcmp(p, "ENCRYPTED"))
+ ret->encrypted = 1;
+ } else if (!strcmp(line, "DEK-Info")) {
+ int i, j;
+
+ if (strncmp(p, "DES-EDE3-CBC,", 13)) {
+ errmsg = "ciphers other than DES-EDE3-CBC not supported";
+ goto error;
+ }
+ p += 13;
+ for (i = 0; i < 8; i++) {
+ if (1 != sscanf(p, "%2x", &j))
+ break;
+ ret->iv[i] = j;
+ p += 2;
+ }
+ if (i < 8) {
+ errmsg = "expected 16-digit iv in DEK-Info";
+ goto error;
+ }
+ }
+ } else {
+ headers_done = 1;
+
+ p = line;
+ while (isbase64(*p)) {
+ base64_bit[base64_chars++] = *p;
+ if (base64_chars == 4) {
+ unsigned char out[3];
+ int len;
+
+ base64_chars = 0;
+
+ len = base64_decode_atom(base64_bit, out);
+
+ if (len <= 0) {
+ errmsg = "invalid base64 encoding";
+ goto error;
+ }
+
+ if (ret->keyblob_len + len > ret->keyblob_size) {
+ ret->keyblob_size = ret->keyblob_len + len + 256;
+ ret->keyblob = sresize(ret->keyblob, ret->keyblob_size,
+ unsigned char);
+ }
+
+ memcpy(ret->keyblob + ret->keyblob_len, out, len);
+ ret->keyblob_len += len;
+
+ memset(out, 0, sizeof(out));
+ }
+
+ p++;
+ }
+ }
+ memset(line, 0, strlen(line));
+ sfree(line);
+ line = NULL;
+ }
+
+ if (ret->keyblob_len == 0 || !ret->keyblob) {
+ errmsg = "key body not present";
+ goto error;
+ }
+
+ if (ret->encrypted && ret->keyblob_len % 8 != 0) {
+ errmsg = "encrypted key blob is not a multiple of cipher block size";
+ goto error;
+ }
+
+ memset(base64_bit, 0, sizeof(base64_bit));
+ if (errmsg_p) *errmsg_p = NULL;
+ return ret;
+
+ error:
+ if (line) {
+ memset(line, 0, strlen(line));
+ sfree(line);
+ line = NULL;
+ }
+ memset(base64_bit, 0, sizeof(base64_bit));
+ if (ret) {
+ if (ret->keyblob) {
+ memset(ret->keyblob, 0, ret->keyblob_size);
+ sfree(ret->keyblob);
+ }
+ memset(ret, 0, sizeof(*ret));
+ sfree(ret);
+ }
+ if (errmsg_p) *errmsg_p = errmsg;
+ return NULL;
+}
+
+int openssh_encrypted(const Filename *filename)
+{
+ struct openssh_key *key = load_openssh_key(filename, NULL);
+ int ret;
+
+ if (!key)
+ return 0;
+ ret = key->encrypted;
+ memset(key->keyblob, 0, key->keyblob_size);
+ sfree(key->keyblob);
+ memset(key, 0, sizeof(*key));
+ sfree(key);
+ return ret;
+}
+
+struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase,
+ const char **errmsg_p)
+{
+ struct openssh_key *key = load_openssh_key(filename, errmsg_p);
+ struct ssh2_userkey *retkey;
+ unsigned char *p;
+ int ret, id, len, flags;
+ int i, num_integers;
+ struct ssh2_userkey *retval = NULL;
+ char *errmsg;
+ unsigned char *blob;
+ int blobsize = 0, blobptr, privptr;
+ char *modptr = NULL;
+ int modlen = 0;
+
+ blob = NULL;
+
+ if (!key)
+ return NULL;
+
+ if (key->encrypted) {
+ /*
+ * Derive encryption key from passphrase and iv/salt:
+ *
+ * - let block A equal MD5(passphrase || iv)
+ * - let block B equal MD5(A || passphrase || iv)
+ * - block C would be MD5(B || passphrase || iv) and so on
+ * - encryption key is the first N bytes of A || B
+ */
+ struct MD5Context md5c;
+ unsigned char keybuf[32];
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
+ MD5Update(&md5c, (unsigned char *)key->iv, 8);
+ MD5Final(keybuf, &md5c);
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, keybuf, 16);
+ MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
+ MD5Update(&md5c, (unsigned char *)key->iv, 8);
+ MD5Final(keybuf+16, &md5c);
+
+ /*
+ * Now decrypt the key blob.
+ */
+ des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv,
+ key->keyblob, key->keyblob_len);
+
+ memset(&md5c, 0, sizeof(md5c));
+ memset(keybuf, 0, sizeof(keybuf));
+ }
+
+ /*
+ * Now we have a decrypted key blob, which contains an ASN.1
+ * encoded private key. We must now untangle the ASN.1.
+ *
+ * We expect the whole key blob to be formatted as a SEQUENCE
+ * (0x30 followed by a length code indicating that the rest of
+ * the blob is part of the sequence). Within that SEQUENCE we
+ * expect to see a bunch of INTEGERs. What those integers mean
+ * depends on the key type:
+ *
+ * - For RSA, we expect the integers to be 0, n, e, d, p, q,
+ * dmp1, dmq1, iqmp in that order. (The last three are d mod
+ * (p-1), d mod (q-1), inverse of q mod p respectively.)
+ *
+ * - For DSA, we expect them to be 0, p, q, g, y, x in that
+ * order.
+ */
+
+ p = key->keyblob;
+
+ /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */
+ ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags);
+ p += ret;
+ if (ret < 0 || id != 16) {
+ errmsg = "ASN.1 decoding failure";
+ retval = SSH2_WRONG_PASSPHRASE;
+ goto error;
+ }
+
+ /* Expect a load of INTEGERs. */
+ if (key->type == OSSH_RSA)
+ num_integers = 9;
+ else if (key->type == OSSH_DSA)
+ num_integers = 6;
+ else
+ num_integers = 0; /* placate compiler warnings */
+
+ /*
+ * Space to create key blob in.
+ */
+ blobsize = 256+key->keyblob_len;
+ blob = snewn(blobsize, unsigned char);
+ PUT_32BIT(blob, 7);
+ if (key->type == OSSH_DSA)
+ memcpy(blob+4, "ssh-dss", 7);
+ else if (key->type == OSSH_RSA)
+ memcpy(blob+4, "ssh-rsa", 7);
+ blobptr = 4+7;
+ privptr = -1;
+
+ for (i = 0; i < num_integers; i++) {
+ ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
+ &id, &len, &flags);
+ p += ret;
+ if (ret < 0 || id != 2 ||
+ key->keyblob+key->keyblob_len-p < len) {
+ errmsg = "ASN.1 decoding failure";
+ retval = SSH2_WRONG_PASSPHRASE;
+ goto error;
+ }
+
+ if (i == 0) {
+ /*
+ * The first integer should be zero always (I think
+ * this is some sort of version indication).
+ */
+ if (len != 1 || p[0] != 0) {
+ errmsg = "version number mismatch";
+ goto error;
+ }
+ } else if (key->type == OSSH_RSA) {
+ /*
+ * Integers 1 and 2 go into the public blob but in the
+ * opposite order; integers 3, 4, 5 and 8 go into the
+ * private blob. The other two (6 and 7) are ignored.
+ */
+ if (i == 1) {
+ /* Save the details for after we deal with number 2. */
+ modptr = (char *)p;
+ modlen = len;
+ } else if (i != 6 && i != 7) {
+ PUT_32BIT(blob+blobptr, len);
+ memcpy(blob+blobptr+4, p, len);
+ blobptr += 4+len;
+ if (i == 2) {
+ PUT_32BIT(blob+blobptr, modlen);
+ memcpy(blob+blobptr+4, modptr, modlen);
+ blobptr += 4+modlen;
+ privptr = blobptr;
+ }
+ }
+ } else if (key->type == OSSH_DSA) {
+ /*
+ * Integers 1-4 go into the public blob; integer 5 goes
+ * into the private blob.
+ */
+ PUT_32BIT(blob+blobptr, len);
+ memcpy(blob+blobptr+4, p, len);
+ blobptr += 4+len;
+ if (i == 4)
+ privptr = blobptr;
+ }
+
+ /* Skip past the number. */
+ p += len;
+ }
+
+ /*
+ * Now put together the actual key. Simplest way to do this is
+ * to assemble our own key blobs and feed them to the createkey
+ * functions; this is a bit faffy but it does mean we get all
+ * the sanity checks for free.
+ */
+ assert(privptr > 0); /* should have bombed by now if not */
+ retkey = snew(struct ssh2_userkey);
+ retkey->alg = (key->type == OSSH_RSA ? &ssh_rsa : &ssh_dss);
+ retkey->data = retkey->alg->createkey(blob, privptr,
+ blob+privptr, blobptr-privptr);
+ if (!retkey->data) {
+ sfree(retkey);
+ errmsg = "unable to create key data structure";
+ goto error;
+ }
+
+ retkey->comment = dupstr("imported-openssh-key");
+ errmsg = NULL; /* no error */
+ retval = retkey;
+
+ error:
+ if (blob) {
+ memset(blob, 0, blobsize);
+ sfree(blob);
+ }
+ memset(key->keyblob, 0, key->keyblob_size);
+ sfree(key->keyblob);
+ memset(key, 0, sizeof(*key));
+ sfree(key);
+ if (errmsg_p) *errmsg_p = errmsg;
+ return retval;
+}
+
+int openssh_write(const Filename *filename, struct ssh2_userkey *key,
+ char *passphrase)
+{
+ unsigned char *pubblob, *privblob, *spareblob;
+ int publen, privlen, sparelen = 0;
+ unsigned char *outblob;
+ int outlen;
+ struct mpint_pos numbers[9];
+ int nnumbers, pos, len, seqlen, i;
+ char *header, *footer;
+ char zero[1];
+ unsigned char iv[8];
+ int ret = 0;
+ FILE *fp;
+
+ /*
+ * Fetch the key blobs.
+ */
+ pubblob = key->alg->public_blob(key->data, &publen);
+ privblob = key->alg->private_blob(key->data, &privlen);
+ spareblob = outblob = NULL;
+
+ /*
+ * Find the sequence of integers to be encoded into the OpenSSH
+ * key blob, and also decide on the header line.
+ */
+ if (key->alg == &ssh_rsa) {
+ int pos;
+ struct mpint_pos n, e, d, p, q, iqmp, dmp1, dmq1;
+ Bignum bd, bp, bq, bdmp1, bdmq1;
+
+ pos = 4 + GET_32BIT(pubblob);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
+ pos = 0;
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
+
+ assert(e.start && iqmp.start); /* can't go wrong */
+
+ /* We also need d mod (p-1) and d mod (q-1). */
+ bd = bignum_from_bytes(d.start, d.bytes);
+ bp = bignum_from_bytes(p.start, p.bytes);
+ bq = bignum_from_bytes(q.start, q.bytes);
+ decbn(bp);
+ decbn(bq);
+ bdmp1 = bigmod(bd, bp);
+ bdmq1 = bigmod(bd, bq);
+ freebn(bd);
+ freebn(bp);
+ freebn(bq);
+
+ dmp1.bytes = (bignum_bitcount(bdmp1)+8)/8;
+ dmq1.bytes = (bignum_bitcount(bdmq1)+8)/8;
+ sparelen = dmp1.bytes + dmq1.bytes;
+ spareblob = snewn(sparelen, unsigned char);
+ dmp1.start = spareblob;
+ dmq1.start = spareblob + dmp1.bytes;
+ for (i = 0; i < dmp1.bytes; i++)
+ spareblob[i] = bignum_byte(bdmp1, dmp1.bytes-1 - i);
+ for (i = 0; i < dmq1.bytes; i++)
+ spareblob[i+dmp1.bytes] = bignum_byte(bdmq1, dmq1.bytes-1 - i);
+ freebn(bdmp1);
+ freebn(bdmq1);
+
+ numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
+ numbers[1] = n;
+ numbers[2] = e;
+ numbers[3] = d;
+ numbers[4] = p;
+ numbers[5] = q;
+ numbers[6] = dmp1;
+ numbers[7] = dmq1;
+ numbers[8] = iqmp;
+
+ nnumbers = 9;
+ header = "-----BEGIN RSA PRIVATE KEY-----\n";
+ footer = "-----END RSA PRIVATE KEY-----\n";
+ } else if (key->alg == &ssh_dss) {
+ int pos;
+ struct mpint_pos p, q, g, y, x;
+
+ pos = 4 + GET_32BIT(pubblob);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
+ pos = 0;
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
+
+ assert(y.start && x.start); /* can't go wrong */
+
+ numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
+ numbers[1] = p;
+ numbers[2] = q;
+ numbers[3] = g;
+ numbers[4] = y;
+ numbers[5] = x;
+
+ nnumbers = 6;
+ header = "-----BEGIN DSA PRIVATE KEY-----\n";
+ footer = "-----END DSA PRIVATE KEY-----\n";
+ } else {
+ assert(0); /* zoinks! */
+ exit(1); /* XXX: GCC doesn't understand assert() on some systems. */
+ }
+
+ /*
+ * Now count up the total size of the ASN.1 encoded integers,
+ * so as to determine the length of the containing SEQUENCE.
+ */
+ len = 0;
+ for (i = 0; i < nnumbers; i++) {
+ len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
+ len += numbers[i].bytes;
+ }
+ seqlen = len;
+ /* Now add on the SEQUENCE header. */
+ len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
+ /* Round up to the cipher block size, ensuring we have at least one
+ * byte of padding (see below). */
+ outlen = len;
+ if (passphrase)
+ outlen = (outlen+8) &~ 7;
+
+ /*
+ * Now we know how big outblob needs to be. Allocate it.
+ */
+ outblob = snewn(outlen, unsigned char);
+
+ /*
+ * And write the data into it.
+ */
+ pos = 0;
+ pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
+ for (i = 0; i < nnumbers; i++) {
+ pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
+ memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
+ pos += numbers[i].bytes;
+ }
+
+ /*
+ * Padding on OpenSSH keys is deterministic. The number of
+ * padding bytes is always more than zero, and always at most
+ * the cipher block length. The value of each padding byte is
+ * equal to the number of padding bytes. So a plaintext that's
+ * an exact multiple of the block size will be padded with 08
+ * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a
+ * plaintext one byte less than a multiple of the block size
+ * will be padded with just 01.
+ *
+ * This enables the OpenSSL key decryption function to strip
+ * off the padding algorithmically and return the unpadded
+ * plaintext to the next layer: it looks at the final byte, and
+ * then expects to find that many bytes at the end of the data
+ * with the same value. Those are all removed and the rest is
+ * returned.
+ */
+ assert(pos == len);
+ while (pos < outlen) {
+ outblob[pos++] = outlen - len;
+ }
+
+ /*
+ * Encrypt the key.
+ */
+ if (passphrase) {
+ /*
+ * Invent an iv. Then derive encryption key from passphrase
+ * and iv/salt:
+ *
+ * - let block A equal MD5(passphrase || iv)
+ * - let block B equal MD5(A || passphrase || iv)
+ * - block C would be MD5(B || passphrase || iv) and so on
+ * - encryption key is the first N bytes of A || B
+ */
+ struct MD5Context md5c;
+ unsigned char keybuf[32];
+
+ for (i = 0; i < 8; i++) iv[i] = random_byte();
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
+ MD5Update(&md5c, iv, 8);
+ MD5Final(keybuf, &md5c);
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, keybuf, 16);
+ MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
+ MD5Update(&md5c, iv, 8);
+ MD5Final(keybuf+16, &md5c);
+
+ /*
+ * Now encrypt the key blob.
+ */
+ des3_encrypt_pubkey_ossh(keybuf, iv, outblob, outlen);
+
+ memset(&md5c, 0, sizeof(md5c));
+ memset(keybuf, 0, sizeof(keybuf));
+ }
+
+ /*
+ * And save it. We'll use Unix line endings just in case it's
+ * subsequently transferred in binary mode.
+ */
+ fp = f_open(*filename, "wb", TRUE); /* ensure Unix line endings */
+ if (!fp)
+ goto error;
+ fputs(header, fp);
+ if (passphrase) {
+ fprintf(fp, "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,");
+ for (i = 0; i < 8; i++)
+ fprintf(fp, "%02X", iv[i]);
+ fprintf(fp, "\n\n");
+ }
+ base64_encode(fp, outblob, outlen, 64);
+ fputs(footer, fp);
+ fclose(fp);
+ ret = 1;
+
+ error:
+ if (outblob) {
+ memset(outblob, 0, outlen);
+ sfree(outblob);
+ }
+ if (spareblob) {
+ memset(spareblob, 0, sparelen);
+ sfree(spareblob);
+ }
+ if (privblob) {
+ memset(privblob, 0, privlen);
+ sfree(privblob);
+ }
+ if (pubblob) {
+ memset(pubblob, 0, publen);
+ sfree(pubblob);
+ }
+ return ret;
+}
+
+/* ----------------------------------------------------------------------
+ * Code to read ssh.com private keys.
+ */
+
+/*
+ * The format of the base64 blob is largely SSH-2-packet-formatted,
+ * except that mpints are a bit different: they're more like the
+ * old SSH-1 mpint. You have a 32-bit bit count N, followed by
+ * (N+7)/8 bytes of data.
+ *
+ * So. The blob contains:
+ *
+ * - uint32 0x3f6ff9eb (magic number)
+ * - uint32 size (total blob size)
+ * - string key-type (see below)
+ * - string cipher-type (tells you if key is encrypted)
+ * - string encrypted-blob
+ *
+ * (The first size field includes the size field itself and the
+ * magic number before it. All other size fields are ordinary SSH-2
+ * strings, so the size field indicates how much data is to
+ * _follow_.)
+ *
+ * The encrypted blob, once decrypted, contains a single string
+ * which in turn contains the payload. (This allows padding to be
+ * added after that string while still making it clear where the
+ * real payload ends. Also it probably makes for a reasonable
+ * decryption check.)
+ *
+ * The payload blob, for an RSA key, contains:
+ * - mpint e
+ * - mpint d
+ * - mpint n (yes, the public and private stuff is intermixed)
+ * - mpint u (presumably inverse of p mod q)
+ * - mpint p (p is the smaller prime)
+ * - mpint q (q is the larger)
+ *
+ * For a DSA key, the payload blob contains:
+ * - uint32 0
+ * - mpint p
+ * - mpint g
+ * - mpint q
+ * - mpint y
+ * - mpint x
+ *
+ * Alternatively, if the parameters are `predefined', that
+ * (0,p,g,q) sequence can be replaced by a uint32 1 and a string
+ * containing some predefined parameter specification. *shudder*,
+ * but I doubt we'll encounter this in real life.
+ *
+ * The key type strings are ghastly. The RSA key I looked at had a
+ * type string of
+ *
+ * `if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}'
+ *
+ * and the DSA key wasn't much better:
+ *
+ * `dl-modp{sign{dsa-nist-sha1},dh{plain}}'
+ *
+ * It isn't clear that these will always be the same. I think it
+ * might be wise just to look at the `if-modn{sign{rsa' and
+ * `dl-modp{sign{dsa' prefixes.
+ *
+ * Finally, the encryption. The cipher-type string appears to be
+ * either `none' or `3des-cbc'. Looks as if this is SSH-2-style
+ * 3des-cbc (i.e. outer cbc rather than inner). The key is created
+ * from the passphrase by means of yet another hashing faff:
+ *
+ * - first 16 bytes are MD5(passphrase)
+ * - next 16 bytes are MD5(passphrase || first 16 bytes)
+ * - if there were more, they'd be MD5(passphrase || first 32),
+ * and so on.
+ */
+
+#define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb
+
+struct sshcom_key {
+ char comment[256]; /* allowing any length is overkill */
+ unsigned char *keyblob;
+ int keyblob_len, keyblob_size;
+};
+
+static struct sshcom_key *load_sshcom_key(const Filename *filename,
+ const char **errmsg_p)
+{
+ struct sshcom_key *ret;
+ FILE *fp;
+ char *line = NULL;
+ int hdrstart, len;
+ char *errmsg, *p;
+ int headers_done;
+ char base64_bit[4];
+ int base64_chars = 0;
+
+ ret = snew(struct sshcom_key);
+ ret->comment[0] = '\0';
+ ret->keyblob = NULL;
+ ret->keyblob_len = ret->keyblob_size = 0;
+
+ fp = f_open(*filename, "r", FALSE);
+ if (!fp) {
+ errmsg = "unable to open key file";
+ goto error;
+ }
+ if (!(line = fgetline(fp))) {
+ errmsg = "unexpected end of file";
+ goto error;
+ }
+ strip_crlf(line);
+ if (0 != strcmp(line, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----")) {
+ errmsg = "file does not begin with ssh.com key header";
+ goto error;
+ }
+ memset(line, 0, strlen(line));
+ sfree(line);
+ line = NULL;
+
+ headers_done = 0;
+ while (1) {
+ if (!(line = fgetline(fp))) {
+ errmsg = "unexpected end of file";
+ goto error;
+ }
+ strip_crlf(line);
+ if (!strcmp(line, "---- END SSH2 ENCRYPTED PRIVATE KEY ----"))
+ break; /* done */
+ if ((p = strchr(line, ':')) != NULL) {
+ if (headers_done) {
+ errmsg = "header found in body of key data";
+ goto error;
+ }
+ *p++ = '\0';
+ while (*p && isspace((unsigned char)*p)) p++;
+ hdrstart = p - line;
+
+ /*
+ * Header lines can end in a trailing backslash for
+ * continuation.
+ */
+ len = hdrstart + strlen(line+hdrstart);
+ assert(!line[len]);
+ while (line[len-1] == '\\') {
+ char *line2;
+ int line2len;
+
+ line2 = fgetline(fp);
+ if (!line2) {
+ errmsg = "unexpected end of file";
+ goto error;
+ }
+ strip_crlf(line2);
+
+ line2len = strlen(line2);
+ line = sresize(line, len + line2len + 1, char);
+ strcpy(line + len - 1, line2);
+ len += line2len - 1;
+ assert(!line[len]);
+
+ memset(line2, 0, strlen(line2));
+ sfree(line2);
+ line2 = NULL;
+ }
+ p = line + hdrstart;
+ strip_crlf(p);
+ if (!strcmp(line, "Comment")) {
+ /* Strip quotes in comment if present. */
+ if (p[0] == '"' && p[strlen(p)-1] == '"') {
+ p++;
+ p[strlen(p)-1] = '\0';
+ }
+ strncpy(ret->comment, p, sizeof(ret->comment));
+ ret->comment[sizeof(ret->comment)-1] = '\0';
+ }
+ } else {
+ headers_done = 1;
+
+ p = line;
+ while (isbase64(*p)) {
+ base64_bit[base64_chars++] = *p;
+ if (base64_chars == 4) {
+ unsigned char out[3];
+
+ base64_chars = 0;
+
+ len = base64_decode_atom(base64_bit, out);
+
+ if (len <= 0) {
+ errmsg = "invalid base64 encoding";
+ goto error;
+ }
+
+ if (ret->keyblob_len + len > ret->keyblob_size) {
+ ret->keyblob_size = ret->keyblob_len + len + 256;
+ ret->keyblob = sresize(ret->keyblob, ret->keyblob_size,
+ unsigned char);
+ }
+
+ memcpy(ret->keyblob + ret->keyblob_len, out, len);
+ ret->keyblob_len += len;
+ }
+
+ p++;
+ }
+ }
+ memset(line, 0, strlen(line));
+ sfree(line);
+ line = NULL;
+ }
+
+ if (ret->keyblob_len == 0 || !ret->keyblob) {
+ errmsg = "key body not present";
+ goto error;
+ }
+
+ if (errmsg_p) *errmsg_p = NULL;
+ return ret;
+
+ error:
+ if (line) {
+ memset(line, 0, strlen(line));
+ sfree(line);
+ line = NULL;
+ }
+ if (ret) {
+ if (ret->keyblob) {
+ memset(ret->keyblob, 0, ret->keyblob_size);
+ sfree(ret->keyblob);
+ }
+ memset(ret, 0, sizeof(*ret));
+ sfree(ret);
+ }
+ if (errmsg_p) *errmsg_p = errmsg;
+ return NULL;
+}
+
+int sshcom_encrypted(const Filename *filename, char **comment)
+{
+ struct sshcom_key *key = load_sshcom_key(filename, NULL);
+ int pos, len, answer;
+
+ *comment = NULL;
+ if (!key)
+ return 0;
+
+ /*
+ * Check magic number.
+ */
+ if (GET_32BIT(key->keyblob) != 0x3f6ff9eb)
+ return 0; /* key is invalid */
+
+ /*
+ * Find the cipher-type string.
+ */
+ answer = 0;
+ pos = 8;
+ if (key->keyblob_len < pos+4)
+ goto done; /* key is far too short */
+ pos += 4 + GET_32BIT(key->keyblob + pos); /* skip key type */
+ if (key->keyblob_len < pos+4)
+ goto done; /* key is far too short */
+ len = GET_32BIT(key->keyblob + pos); /* find cipher-type length */
+ if (key->keyblob_len < pos+4+len)
+ goto done; /* cipher type string is incomplete */
+ if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4))
+ answer = 1;
+
+ done:
+ *comment = dupstr(key->comment);
+ memset(key->keyblob, 0, key->keyblob_size);
+ sfree(key->keyblob);
+ memset(key, 0, sizeof(*key));
+ sfree(key);
+ return answer;
+}
+
+static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret)
+{
+ int bits;
+ int bytes;
+ unsigned char *d = (unsigned char *) data;
+
+ if (len < 4)
+ goto error;
+ bits = GET_32BIT(d);
+
+ bytes = (bits + 7) / 8;
+ if (len < 4+bytes)
+ goto error;
+
+ ret->start = d + 4;
+ ret->bytes = bytes;
+ return bytes+4;
+
+ error:
+ ret->start = NULL;
+ ret->bytes = -1;
+ return len; /* ensure further calls fail as well */
+}
+
+static int sshcom_put_mpint(void *target, void *data, int len)
+{
+ unsigned char *d = (unsigned char *)target;
+ unsigned char *i = (unsigned char *)data;
+ int bits = len * 8 - 1;
+
+ while (bits > 0) {
+ if (*i & (1 << (bits & 7)))
+ break;
+ if (!(bits-- & 7))
+ i++, len--;
+ }
+
+ PUT_32BIT(d, bits+1);
+ memcpy(d+4, i, len);
+ return len+4;
+}
+
+struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase,
+ const char **errmsg_p)
+{
+ struct sshcom_key *key = load_sshcom_key(filename, errmsg_p);
+ char *errmsg;
+ int pos, len;
+ const char prefix_rsa[] = "if-modn{sign{rsa";
+ const char prefix_dsa[] = "dl-modp{sign{dsa";
+ enum { RSA, DSA } type;
+ int encrypted;
+ char *ciphertext;
+ int cipherlen;
+ struct ssh2_userkey *ret = NULL, *retkey;
+ const struct ssh_signkey *alg;
+ unsigned char *blob = NULL;
+ int blobsize = 0, publen, privlen;
+
+ if (!key)
+ return NULL;
+
+ /*
+ * Check magic number.
+ */
+ if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) {
+ errmsg = "key does not begin with magic number";
+ goto error;
+ }
+
+ /*
+ * Determine the key type.
+ */
+ pos = 8;
+ if (key->keyblob_len < pos+4 ||
+ (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
+ errmsg = "key blob does not contain a key type string";
+ goto error;
+ }
+ if (len > sizeof(prefix_rsa) - 1 &&
+ !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) {
+ type = RSA;
+ } else if (len > sizeof(prefix_dsa) - 1 &&
+ !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) {
+ type = DSA;
+ } else {
+ errmsg = "key is of unknown type";
+ goto error;
+ }
+ pos += 4+len;
+
+ /*
+ * Determine the cipher type.
+ */
+ if (key->keyblob_len < pos+4 ||
+ (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
+ errmsg = "key blob does not contain a cipher type string";
+ goto error;
+ }
+ if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4))
+ encrypted = 0;
+ else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8))
+ encrypted = 1;
+ else {
+ errmsg = "key encryption is of unknown type";
+ goto error;
+ }
+ pos += 4+len;
+
+ /*
+ * Get hold of the encrypted part of the key.
+ */
+ if (key->keyblob_len < pos+4 ||
+ (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
+ errmsg = "key blob does not contain actual key data";
+ goto error;
+ }
+ ciphertext = (char *)key->keyblob + pos + 4;
+ cipherlen = len;
+ if (cipherlen == 0) {
+ errmsg = "length of key data is zero";
+ goto error;
+ }
+
+ /*
+ * Decrypt it if necessary.
+ */
+ if (encrypted) {
+ /*
+ * Derive encryption key from passphrase and iv/salt:
+ *
+ * - let block A equal MD5(passphrase)
+ * - let block B equal MD5(passphrase || A)
+ * - block C would be MD5(passphrase || A || B) and so on
+ * - encryption key is the first N bytes of A || B
+ */
+ struct MD5Context md5c;
+ unsigned char keybuf[32], iv[8];
+
+ if (cipherlen % 8 != 0) {
+ errmsg = "encrypted part of key is not a multiple of cipher block"
+ " size";
+ goto error;
+ }
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
+ MD5Final(keybuf, &md5c);
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
+ MD5Update(&md5c, keybuf, 16);
+ MD5Final(keybuf+16, &md5c);
+
+ /*
+ * Now decrypt the key blob.
+ */
+ memset(iv, 0, sizeof(iv));
+ des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
+ cipherlen);
+
+ memset(&md5c, 0, sizeof(md5c));
+ memset(keybuf, 0, sizeof(keybuf));
+
+ /*
+ * Hereafter we return WRONG_PASSPHRASE for any parsing
+ * error. (But only if we've just tried to decrypt it!
+ * Returning WRONG_PASSPHRASE for an unencrypted key is
+ * automatic doom.)
+ */
+ if (encrypted)
+ ret = SSH2_WRONG_PASSPHRASE;
+ }
+
+ /*
+ * Strip away the containing string to get to the real meat.
+ */
+ len = GET_32BIT(ciphertext);
+ if (len < 0 || len > cipherlen-4) {
+ errmsg = "containing string was ill-formed";
+ goto error;
+ }
+ ciphertext += 4;
+ cipherlen = len;
+
+ /*
+ * Now we break down into RSA versus DSA. In either case we'll
+ * construct public and private blobs in our own format, and
+ * end up feeding them to alg->createkey().
+ */
+ blobsize = cipherlen + 256;
+ blob = snewn(blobsize, unsigned char);
+ privlen = 0;
+ if (type == RSA) {
+ struct mpint_pos n, e, d, u, p, q;
+ int pos = 0;
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e);
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d);
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n);
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u);
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
+ if (!q.start) {
+ errmsg = "key data did not contain six integers";
+ goto error;
+ }
+
+ alg = &ssh_rsa;
+ pos = 0;
+ pos += put_string(blob+pos, "ssh-rsa", 7);
+ pos += put_mp(blob+pos, e.start, e.bytes);
+ pos += put_mp(blob+pos, n.start, n.bytes);
+ publen = pos;
+ pos += put_string(blob+pos, d.start, d.bytes);
+ pos += put_mp(blob+pos, q.start, q.bytes);
+ pos += put_mp(blob+pos, p.start, p.bytes);
+ pos += put_mp(blob+pos, u.start, u.bytes);
+ privlen = pos - publen;
+ } else if (type == DSA) {
+ struct mpint_pos p, q, g, x, y;
+ int pos = 4;
+ if (GET_32BIT(ciphertext) != 0) {
+ errmsg = "predefined DSA parameters not supported";
+ goto error;
+ }
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g);
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y);
+ pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x);
+ if (!x.start) {
+ errmsg = "key data did not contain five integers";
+ goto error;
+ }
+
+ alg = &ssh_dss;
+ pos = 0;
+ pos += put_string(blob+pos, "ssh-dss", 7);
+ pos += put_mp(blob+pos, p.start, p.bytes);
+ pos += put_mp(blob+pos, q.start, q.bytes);
+ pos += put_mp(blob+pos, g.start, g.bytes);
+ pos += put_mp(blob+pos, y.start, y.bytes);
+ publen = pos;
+ pos += put_mp(blob+pos, x.start, x.bytes);
+ privlen = pos - publen;
+ } else
+ return NULL;
+
+ assert(privlen > 0); /* should have bombed by now if not */
+
+ retkey = snew(struct ssh2_userkey);
+ retkey->alg = alg;
+ retkey->data = alg->createkey(blob, publen, blob+publen, privlen);
+ if (!retkey->data) {
+ sfree(retkey);
+ errmsg = "unable to create key data structure";
+ goto error;
+ }
+ retkey->comment = dupstr(key->comment);
+
+ errmsg = NULL; /* no error */
+ ret = retkey;
+
+ error:
+ if (blob) {
+ memset(blob, 0, blobsize);
+ sfree(blob);
+ }
+ memset(key->keyblob, 0, key->keyblob_size);
+ sfree(key->keyblob);
+ memset(key, 0, sizeof(*key));
+ sfree(key);
+ if (errmsg_p) *errmsg_p = errmsg;
+ return ret;
+}
+
+int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
+ char *passphrase)
+{
+ unsigned char *pubblob, *privblob;
+ int publen, privlen;
+ unsigned char *outblob;
+ int outlen;
+ struct mpint_pos numbers[6];
+ int nnumbers, initial_zero, pos, lenpos, i;
+ char *type;
+ char *ciphertext;
+ int cipherlen;
+ int ret = 0;
+ FILE *fp;
+
+ /*
+ * Fetch the key blobs.
+ */
+ pubblob = key->alg->public_blob(key->data, &publen);
+ privblob = key->alg->private_blob(key->data, &privlen);
+ outblob = NULL;
+
+ /*
+ * Find the sequence of integers to be encoded into the OpenSSH
+ * key blob, and also decide on the header line.
+ */
+ if (key->alg == &ssh_rsa) {
+ int pos;
+ struct mpint_pos n, e, d, p, q, iqmp;
+
+ pos = 4 + GET_32BIT(pubblob);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
+ pos = 0;
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
+
+ assert(e.start && iqmp.start); /* can't go wrong */
+
+ numbers[0] = e;
+ numbers[1] = d;
+ numbers[2] = n;
+ numbers[3] = iqmp;
+ numbers[4] = q;
+ numbers[5] = p;
+
+ nnumbers = 6;
+ initial_zero = 0;
+ type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
+ } else if (key->alg == &ssh_dss) {
+ int pos;
+ struct mpint_pos p, q, g, y, x;
+
+ pos = 4 + GET_32BIT(pubblob);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
+ pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
+ pos = 0;
+ pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
+
+ assert(y.start && x.start); /* can't go wrong */
+
+ numbers[0] = p;
+ numbers[1] = g;
+ numbers[2] = q;
+ numbers[3] = y;
+ numbers[4] = x;
+
+ nnumbers = 5;
+ initial_zero = 1;
+ type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
+ } else {
+ assert(0); /* zoinks! */
+ exit(1); /* XXX: GCC doesn't understand assert() on some systems. */
+ }
+
+ /*
+ * Total size of key blob will be somewhere under 512 plus
+ * combined length of integers. We'll calculate the more
+ * precise size as we construct the blob.
+ */
+ outlen = 512;
+ for (i = 0; i < nnumbers; i++)
+ outlen += 4 + numbers[i].bytes;
+ outblob = snewn(outlen, unsigned char);
+
+ /*
+ * Create the unencrypted key blob.
+ */
+ pos = 0;
+ PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4;
+ pos += 4; /* length field, fill in later */
+ pos += put_string(outblob+pos, type, strlen(type));
+ {
+ char *ciphertype = passphrase ? "3des-cbc" : "none";
+ pos += put_string(outblob+pos, ciphertype, strlen(ciphertype));
+ }
+ lenpos = pos; /* remember this position */
+ pos += 4; /* encrypted-blob size */
+ pos += 4; /* encrypted-payload size */
+ if (initial_zero) {
+ PUT_32BIT(outblob+pos, 0);
+ pos += 4;
+ }
+ for (i = 0; i < nnumbers; i++)
+ pos += sshcom_put_mpint(outblob+pos,
+ numbers[i].start, numbers[i].bytes);
+ /* Now wrap up the encrypted payload. */
+ PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8));
+ /* Pad encrypted blob to a multiple of cipher block size. */
+ if (passphrase) {
+ int padding = -(pos - (lenpos+4)) & 7;
+ while (padding--)
+ outblob[pos++] = random_byte();
+ }
+ ciphertext = (char *)outblob+lenpos+4;
+ cipherlen = pos - (lenpos+4);
+ assert(!passphrase || cipherlen % 8 == 0);
+ /* Wrap up the encrypted blob string. */
+ PUT_32BIT(outblob+lenpos, cipherlen);
+ /* And finally fill in the total length field. */
+ PUT_32BIT(outblob+4, pos);
+
+ assert(pos < outlen);
+
+ /*
+ * Encrypt the key.
+ */
+ if (passphrase) {
+ /*
+ * Derive encryption key from passphrase and iv/salt:
+ *
+ * - let block A equal MD5(passphrase)
+ * - let block B equal MD5(passphrase || A)
+ * - block C would be MD5(passphrase || A || B) and so on
+ * - encryption key is the first N bytes of A || B
+ */
+ struct MD5Context md5c;
+ unsigned char keybuf[32], iv[8];
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
+ MD5Final(keybuf, &md5c);
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
+ MD5Update(&md5c, keybuf, 16);
+ MD5Final(keybuf+16, &md5c);
+
+ /*
+ * Now decrypt the key blob.
+ */
+ memset(iv, 0, sizeof(iv));
+ des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
+ cipherlen);
+
+ memset(&md5c, 0, sizeof(md5c));
+ memset(keybuf, 0, sizeof(keybuf));
+ }
+
+ /*
+ * And save it. We'll use Unix line endings just in case it's
+ * subsequently transferred in binary mode.
+ */
+ fp = f_open(*filename, "wb", TRUE); /* ensure Unix line endings */
+ if (!fp)
+ goto error;
+ fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
+ fprintf(fp, "Comment: \"");
+ /*
+ * Comment header is broken with backslash-newline if it goes
+ * over 70 chars. Although it's surrounded by quotes, it
+ * _doesn't_ escape backslashes or quotes within the string.
+ * Don't ask me, I didn't design it.
+ */
+ {
+ int slen = 60; /* starts at 60 due to "Comment: " */
+ char *c = key->comment;
+ while ((int)strlen(c) > slen) {
+ fprintf(fp, "%.*s\\\n", slen, c);
+ c += slen;
+ slen = 70; /* allow 70 chars on subsequent lines */
+ }
+ fprintf(fp, "%s\"\n", c);
+ }
+ base64_encode(fp, outblob, pos, 70);
+ fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
+ fclose(fp);
+ ret = 1;
+
+ error:
+ if (outblob) {
+ memset(outblob, 0, outlen);
+ sfree(outblob);
+ }
+ if (privblob) {
+ memset(privblob, 0, privlen);
+ sfree(privblob);
+ }
+ if (pubblob) {
+ memset(pubblob, 0, publen);
+ sfree(pubblob);
+ }
+ return ret;
+}
diff --git a/puttysrc/INT64.C b/puttysrc/INT64.C
new file mode 100644
index 0000000..9285f4a
--- /dev/null
+++ b/puttysrc/INT64.C
@@ -0,0 +1,130 @@
+/*
+ * Handling of the int64 and uint64 types. Done in 32-bit integers,
+ * for (pre-C99) portability. Hopefully once C99 becomes widespread
+ * we can kiss this lot goodbye...
+ */
+
+#include
+#include
+
+#include "int64.h"
+
+uint64 uint64_div10(uint64 x, int *remainder)
+{
+ uint64 y;
+ int rem, r2;
+ y.hi = x.hi / 10;
+ y.lo = x.lo / 10;
+ rem = x.lo % 10;
+ /*
+ * Now we have to add in the remainder left over from x.hi.
+ */
+ r2 = x.hi % 10;
+ y.lo += r2 * 2 * (0x80000000 / 10);
+ rem += r2 * 2 * (0x80000000 % 10);
+ y.lo += rem / 10;
+ rem %= 10;
+
+ if (remainder)
+ *remainder = rem;
+ return y;
+}
+
+void uint64_decimal(uint64 x, char *buffer)
+{
+ char buf[20];
+ int start = 20;
+ int d;
+
+ do {
+ x = uint64_div10(x, &d);
+ assert(start > 0);
+ buf[--start] = d + '0';
+ } while (x.hi || x.lo);
+
+ memcpy(buffer, buf + start, sizeof(buf) - start);
+ buffer[sizeof(buf) - start] = '\0';
+}
+
+uint64 uint64_make(unsigned long hi, unsigned long lo)
+{
+ uint64 y;
+ y.hi = hi;
+ y.lo = lo;
+ return y;
+}
+
+uint64 uint64_add(uint64 x, uint64 y)
+{
+ x.lo += y.lo;
+ x.hi += y.hi + (x.lo < y.lo ? 1 : 0);
+ return x;
+}
+
+uint64 uint64_add32(uint64 x, unsigned long y)
+{
+ uint64 yy;
+ yy.hi = 0;
+ yy.lo = y;
+ return uint64_add(x, yy);
+}
+
+int uint64_compare(uint64 x, uint64 y)
+{
+ if (x.hi != y.hi)
+ return x.hi < y.hi ? -1 : +1;
+ if (x.lo != y.lo)
+ return x.lo < y.lo ? -1 : +1;
+ return 0;
+}
+
+uint64 uint64_subtract(uint64 x, uint64 y)
+{
+ x.lo -= y.lo;
+ x.hi -= y.hi + (x.lo > ~y.lo ? 1 : 0);
+ return x;
+}
+
+double uint64_to_double(uint64 x)
+{
+ return (4294967296.0 * x.hi) + (double)x.lo;
+}
+
+uint64 uint64_shift_right(uint64 x, int shift)
+{
+ if (shift < 32) {
+ x.lo >>= shift;
+ x.lo |= (x.hi << (32-shift));
+ x.hi >>= shift;
+ } else {
+ x.lo = x.hi >> (shift-32);
+ x.hi = 0;
+ }
+ return x;
+}
+
+uint64 uint64_shift_left(uint64 x, int shift)
+{
+ if (shift < 32) {
+ x.hi <<= shift;
+ x.hi |= (x.lo >> (32-shift));
+ x.lo <<= shift;
+ } else {
+ x.hi = x.lo << (shift-32);
+ x.lo = 0;
+ }
+ return x;
+}
+
+uint64 uint64_from_decimal(char *str)
+{
+ uint64 ret;
+ ret.hi = ret.lo = 0;
+ while (*str >= '0' && *str <= '9') {
+ ret = uint64_add(uint64_shift_left(ret, 3),
+ uint64_shift_left(ret, 1));
+ ret = uint64_add32(ret, *str - '0');
+ str++;
+ }
+ return ret;
+}
diff --git a/puttysrc/INT64.H b/puttysrc/INT64.H
new file mode 100644
index 0000000..63df3a9
--- /dev/null
+++ b/puttysrc/INT64.H
@@ -0,0 +1,24 @@
+/*
+ * Header for int64.c.
+ */
+
+#ifndef PUTTY_INT64_H
+#define PUTTY_INT64_H
+
+typedef struct {
+ unsigned long hi, lo;
+} uint64;
+
+uint64 uint64_div10(uint64 x, int *remainder);
+void uint64_decimal(uint64 x, char *buffer);
+uint64 uint64_make(unsigned long hi, unsigned long lo);
+uint64 uint64_add(uint64 x, uint64 y);
+uint64 uint64_add32(uint64 x, unsigned long y);
+int uint64_compare(uint64 x, uint64 y);
+uint64 uint64_subtract(uint64 x, uint64 y);
+double uint64_to_double(uint64 x);
+uint64 uint64_shift_right(uint64 x, int shift);
+uint64 uint64_shift_left(uint64 x, int shift);
+uint64 uint64_from_decimal(char *str);
+
+#endif
diff --git a/puttysrc/LDISC.C b/puttysrc/LDISC.C
new file mode 100644
index 0000000..20fa3c5
--- /dev/null
+++ b/puttysrc/LDISC.C
@@ -0,0 +1,336 @@
+/*
+ * ldisc.c: PuTTY line discipline. Sits between the input coming
+ * from keypresses in the window, and the output channel leading to
+ * the back end. Implements echo and/or local line editing,
+ * depending on what's currently configured.
+ */
+
+#include
+#include
+
+#include "putty.h"
+#include "terminal.h"
+#include "ldisc.h"
+
+#define ECHOING (ldisc->cfg->localecho == FORCE_ON || \
+ (ldisc->cfg->localecho == AUTO && \
+ (ldisc->back->ldisc(ldisc->backhandle, LD_ECHO) || \
+ term_ldisc(ldisc->term, LD_ECHO))))
+#define EDITING (ldisc->cfg->localedit == FORCE_ON || \
+ (ldisc->cfg->localedit == AUTO && \
+ (ldisc->back->ldisc(ldisc->backhandle, LD_EDIT) || \
+ term_ldisc(ldisc->term, LD_EDIT))))
+
+static void c_write(Ldisc ldisc, char *buf, int len)
+{
+ from_backend(ldisc->frontend, 0, buf, len);
+}
+
+static int plen(Ldisc ldisc, unsigned char c)
+{
+ if ((c >= 32 && c <= 126) || (c >= 160 && !in_utf(ldisc->term)))
+ return 1;
+ else if (c < 128)
+ return 2; /* ^x for some x */
+ else if (in_utf(ldisc->term) && c >= 0xC0)
+ return 1; /* UTF-8 introducer character
+ * (FIXME: combining / wide chars) */
+ else if (in_utf(ldisc->term) && c >= 0x80 && c < 0xC0)
+ return 0; /* UTF-8 followup character */
+ else
+ return 4; /* hex representation */
+}
+
+static void pwrite(Ldisc ldisc, unsigned char c)
+{
+ if ((c >= 32 && c <= 126) ||
+ (!in_utf(ldisc->term) && c >= 0xA0) ||
+ (in_utf(ldisc->term) && c >= 0x80)) {
+ c_write(ldisc, (char *)&c, 1);
+ } else if (c < 128) {
+ char cc[2];
+ cc[1] = (c == 127 ? '?' : c + 0x40);
+ cc[0] = '^';
+ c_write(ldisc, cc, 2);
+ } else {
+ char cc[5];
+ sprintf(cc, "<%02X>", c);
+ c_write(ldisc, cc, 4);
+ }
+}
+
+static int char_start(Ldisc ldisc, unsigned char c)
+{
+ if (in_utf(ldisc->term))
+ return (c < 0x80 || c >= 0xC0);
+ else
+ return 1;
+}
+
+static void bsb(Ldisc ldisc, int n)
+{
+ while (n--)
+ c_write(ldisc, "\010 \010", 3);
+}
+
+#define CTRL(x) (x^'@')
+#define KCTRL(x) ((x^'@') | 0x100)
+
+void *ldisc_create(Config *mycfg, Terminal *term,
+ Backend *back, void *backhandle,
+ void *frontend)
+{
+ Ldisc ldisc = snew(struct ldisc_tag);
+
+ ldisc->buf = NULL;
+ ldisc->buflen = 0;
+ ldisc->bufsiz = 0;
+ ldisc->quotenext = 0;
+
+ ldisc->cfg = mycfg;
+ ldisc->back = back;
+ ldisc->backhandle = backhandle;
+ ldisc->term = term;
+ ldisc->frontend = frontend;
+
+ /* Link ourselves into the backend and the terminal */
+ if (term)
+ term->ldisc = ldisc;
+ if (back)
+ back->provide_ldisc(backhandle, ldisc);
+
+ return ldisc;
+}
+
+void ldisc_free(void *handle)
+{
+ Ldisc ldisc = (Ldisc) handle;
+
+ if (ldisc->term)
+ ldisc->term->ldisc = NULL;
+ if (ldisc->back)
+ ldisc->back->provide_ldisc(ldisc->backhandle, NULL);
+ if (ldisc->buf)
+ sfree(ldisc->buf);
+ sfree(ldisc);
+}
+
+void ldisc_send(void *handle, char *buf, int len, int interactive)
+{
+ Ldisc ldisc = (Ldisc) handle;
+ int keyflag = 0;
+ /*
+ * Called with len=0 when the options change. We must inform
+ * the front end in case it needs to know.
+ */
+ if (len == 0) {
+ ldisc_update(ldisc->frontend, ECHOING, EDITING);
+ return;
+ }
+ /*
+ * Notify the front end that something was pressed, in case
+ * it's depending on finding out (e.g. keypress termination for
+ * Close On Exit).
+ */
+ frontend_keypress(ldisc->frontend);
+
+ /*
+ * Less than zero means null terminated special string.
+ */
+ if (len < 0) {
+ len = strlen(buf);
+ keyflag = KCTRL('@');
+ }
+ /*
+ * Either perform local editing, or just send characters.
+ */
+ if (EDITING) {
+ while (len--) {
+ int c;
+ c = *buf++ + keyflag;
+ if (!interactive && c == '\r')
+ c += KCTRL('@');
+ switch (ldisc->quotenext ? ' ' : c) {
+ /*
+ * ^h/^?: delete, and output BSBs, to return to
+ * last character boundary (in UTF-8 mode this may
+ * be more than one byte)
+ * ^w: delete, and output BSBs, to return to last
+ * space/nonspace boundary
+ * ^u: delete, and output BSBs, to return to BOL
+ * ^c: Do a ^u then send a telnet IP
+ * ^z: Do a ^u then send a telnet SUSP
+ * ^\: Do a ^u then send a telnet ABORT
+ * ^r: echo "^R\n" and redraw line
+ * ^v: quote next char
+ * ^d: if at BOL, end of file and close connection,
+ * else send line and reset to BOL
+ * ^m: send line-plus-\r\n and reset to BOL
+ */
+ case KCTRL('H'):
+ case KCTRL('?'): /* backspace/delete */
+ if (ldisc->buflen > 0) {
+ do {
+ if (ECHOING)
+ bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
+ ldisc->buflen--;
+ } while (!char_start(ldisc, ldisc->buf[ldisc->buflen]));
+ }
+ break;
+ case CTRL('W'): /* delete word */
+ while (ldisc->buflen > 0) {
+ if (ECHOING)
+ bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
+ ldisc->buflen--;
+ if (ldisc->buflen > 0 &&
+ isspace((unsigned char)ldisc->buf[ldisc->buflen-1]) &&
+ !isspace((unsigned char)ldisc->buf[ldisc->buflen]))
+ break;
+ }
+ break;
+ case CTRL('U'): /* delete line */
+ case CTRL('C'): /* Send IP */
+ case CTRL('\\'): /* Quit */
+ case CTRL('Z'): /* Suspend */
+ while (ldisc->buflen > 0) {
+ if (ECHOING)
+ bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
+ ldisc->buflen--;
+ }
+ ldisc->back->special(ldisc->backhandle, TS_EL);
+ /*
+ * We don't send IP, SUSP or ABORT if the user has
+ * configured telnet specials off! This breaks
+ * talkers otherwise.
+ */
+ if (!ldisc->cfg->telnet_keyboard)
+ goto default_case;
+ if (c == CTRL('C'))
+ ldisc->back->special(ldisc->backhandle, TS_IP);
+ if (c == CTRL('Z'))
+ ldisc->back->special(ldisc->backhandle, TS_SUSP);
+ if (c == CTRL('\\'))
+ ldisc->back->special(ldisc->backhandle, TS_ABORT);
+ break;
+ case CTRL('R'): /* redraw line */
+ if (ECHOING) {
+ int i;
+ c_write(ldisc, "^R\r\n", 4);
+ for (i = 0; i < ldisc->buflen; i++)
+ pwrite(ldisc, ldisc->buf[i]);
+ }
+ break;
+ case CTRL('V'): /* quote next char */
+ ldisc->quotenext = TRUE;
+ break;
+ case CTRL('D'): /* logout or send */
+ if (ldisc->buflen == 0) {
+ ldisc->back->special(ldisc->backhandle, TS_EOF);
+ } else {
+ ldisc->back->send(ldisc->backhandle, ldisc->buf, ldisc->buflen);
+ ldisc->buflen = 0;
+ }
+ break;
+ /*
+ * This particularly hideous bit of code from RDB
+ * allows ordinary ^M^J to do the same thing as
+ * magic-^M when in Raw protocol. The line `case
+ * KCTRL('M'):' is _inside_ the if block. Thus:
+ *
+ * - receiving regular ^M goes straight to the
+ * default clause and inserts as a literal ^M.
+ * - receiving regular ^J _not_ directly after a
+ * literal ^M (or not in Raw protocol) fails the
+ * if condition, leaps to the bottom of the if,
+ * and falls through into the default clause
+ * again.
+ * - receiving regular ^J just after a literal ^M
+ * in Raw protocol passes the if condition,
+ * deletes the literal ^M, and falls through
+ * into the magic-^M code
+ * - receiving a magic-^M empties the line buffer,
+ * signals end-of-line in one of the various
+ * entertaining ways, and _doesn't_ fall out of
+ * the bottom of the if and through to the
+ * default clause because of the break.
+ */
+ case CTRL('J'):
+ if (ldisc->cfg->protocol == PROT_RAW &&
+ ldisc->buflen > 0 && ldisc->buf[ldisc->buflen - 1] == '\r') {
+ if (ECHOING)
+ bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
+ ldisc->buflen--;
+ /* FALLTHROUGH */
+ case KCTRL('M'): /* send with newline */
+ if (ldisc->buflen > 0)
+ ldisc->back->send(ldisc->backhandle, ldisc->buf, ldisc->buflen);
+ if (ldisc->cfg->protocol == PROT_RAW)
+ ldisc->back->send(ldisc->backhandle, "\r\n", 2);
+ else if (ldisc->cfg->protocol == PROT_TELNET && ldisc->cfg->telnet_newline)
+ ldisc->back->special(ldisc->backhandle, TS_EOL);
+ else
+ ldisc->back->send(ldisc->backhandle, "\r", 1);
+ if (ECHOING)
+ c_write(ldisc, "\r\n", 2);
+ ldisc->buflen = 0;
+ break;
+ }
+ /* FALLTHROUGH */
+ default: /* get to this label from ^V handler */
+ default_case:
+ if (ldisc->buflen >= ldisc->bufsiz) {
+ ldisc->bufsiz = ldisc->buflen + 256;
+ ldisc->buf = sresize(ldisc->buf, ldisc->bufsiz, char);
+ }
+ ldisc->buf[ldisc->buflen++] = c;
+ if (ECHOING)
+ pwrite(ldisc, (unsigned char) c);
+ ldisc->quotenext = FALSE;
+ break;
+ }
+ }
+ } else {
+ if (ldisc->buflen != 0) {
+ ldisc->back->send(ldisc->backhandle, ldisc->buf, ldisc->buflen);
+ while (ldisc->buflen > 0) {
+ bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
+ ldisc->buflen--;
+ }
+ }
+ if (len > 0) {
+ if (ECHOING)
+ c_write(ldisc, buf, len);
+ if (keyflag && ldisc->cfg->protocol == PROT_TELNET && len == 1) {
+ switch (buf[0]) {
+ case CTRL('M'):
+ if (ldisc->cfg->protocol == PROT_TELNET && ldisc->cfg->telnet_newline)
+ ldisc->back->special(ldisc->backhandle, TS_EOL);
+ else
+ ldisc->back->send(ldisc->backhandle, "\r", 1);
+ break;
+ case CTRL('?'):
+ case CTRL('H'):
+ if (ldisc->cfg->telnet_keyboard) {
+ ldisc->back->special(ldisc->backhandle, TS_EC);
+ break;
+ }
+ case CTRL('C'):
+ if (ldisc->cfg->telnet_keyboard) {
+ ldisc->back->special(ldisc->backhandle, TS_IP);
+ break;
+ }
+ case CTRL('Z'):
+ if (ldisc->cfg->telnet_keyboard) {
+ ldisc->back->special(ldisc->backhandle, TS_SUSP);
+ break;
+ }
+
+ default:
+ ldisc->back->send(ldisc->backhandle, buf, len);
+ break;
+ }
+ } else
+ ldisc->back->send(ldisc->backhandle, buf, len);
+ }
+ }
+}
diff --git a/puttysrc/LDISC.H b/puttysrc/LDISC.H
new file mode 100644
index 0000000..ef84f6d
--- /dev/null
+++ b/puttysrc/LDISC.H
@@ -0,0 +1,22 @@
+/*
+ * ldisc.h: defines the Ldisc data structure used by ldisc.c and
+ * ldiscucs.c. (Unfortunately it was necessary to split the ldisc
+ * module in two, to avoid unnecessarily linking in the Unicode
+ * stuff in tools that don't require it.)
+ */
+
+#ifndef PUTTY_LDISC_H
+#define PUTTY_LDISC_H
+
+typedef struct ldisc_tag {
+ Terminal *term;
+ Backend *back;
+ Config *cfg;
+ void *backhandle;
+ void *frontend;
+
+ char *buf;
+ int buflen, bufsiz, quotenext;
+} *Ldisc;
+
+#endif /* PUTTY_LDISC_H */
diff --git a/puttysrc/LDISCUCS.C b/puttysrc/LDISCUCS.C
new file mode 100644
index 0000000..a12fd74
--- /dev/null
+++ b/puttysrc/LDISCUCS.C
@@ -0,0 +1,80 @@
+/*
+ * ldisc.c: PuTTY line discipline. Sits between the input coming
+ * from keypresses in the window, and the output channel leading to
+ * the back end. Implements echo and/or local line editing,
+ * depending on what's currently configured.
+ */
+
+#include
+#include
+
+#include "putty.h"
+#include "terminal.h"
+#include "ldisc.h"
+
+void lpage_send(void *handle,
+ int codepage, char *buf, int len, int interactive)
+{
+ Ldisc ldisc = (Ldisc)handle;
+ wchar_t *widebuffer = 0;
+ int widesize = 0;
+ int wclen;
+
+ if (codepage < 0) {
+ ldisc_send(ldisc, buf, len, interactive);
+ return;
+ }
+
+ widesize = len * 2;
+ widebuffer = snewn(widesize, wchar_t);
+
+ wclen = mb_to_wc(codepage, 0, buf, len, widebuffer, widesize);
+ luni_send(ldisc, widebuffer, wclen, interactive);
+
+ sfree(widebuffer);
+}
+
+void luni_send(void *handle, wchar_t * widebuf, int len, int interactive)
+{
+ Ldisc ldisc = (Ldisc)handle;
+ int ratio = (in_utf(ldisc->term))?3:1;
+ char *linebuffer;
+ int linesize;
+ int i;
+ char *p;
+
+ linesize = len * ratio * 2;
+ linebuffer = snewn(linesize, char);
+
+ if (in_utf(ldisc->term)) {
+ /* UTF is a simple algorithm */
+ for (p = linebuffer, i = 0; i < len; i++) {
+ wchar_t ch = widebuf[i];
+ /* We only deal with 16-bit wide chars */
+ if ((ch&0xF800) == 0xD800) ch = '.';
+
+ if (ch < 0x80) {
+ *p++ = (char) (ch);
+ } else if (ch < 0x800) {
+ *p++ = (0xC0 | (ch >> 6));
+ *p++ = (0x80 | (ch & 0x3F));
+ } else {
+ *p++ = (0xE0 | (ch >> 12));
+ *p++ = (0x80 | ((ch >> 6) & 0x3F));
+ *p++ = (0x80 | (ch & 0x3F));
+ }
+ }
+ } else {
+ int rv;
+ rv = wc_to_mb(ldisc->term->ucsdata->line_codepage, 0, widebuf, len,
+ linebuffer, linesize, NULL, NULL, ldisc->term->ucsdata);
+ if (rv >= 0)
+ p = linebuffer + rv;
+ else
+ p = linebuffer;
+ }
+ if (p > linebuffer)
+ ldisc_send(ldisc, linebuffer, p - linebuffer, interactive);
+
+ sfree(linebuffer);
+}
diff --git a/puttysrc/LICENCE b/puttysrc/LICENCE
new file mode 100644
index 0000000..956ff6b
--- /dev/null
+++ b/puttysrc/LICENCE
@@ -0,0 +1,25 @@
+PuTTY is copyright 1997-2007 Simon Tatham.
+
+Portions copyright Robert de Bath, Joris van Rantwijk, Delian
+Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
+Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
+Kuhn, and CORE SDI S.A.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation files
+(the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/puttysrc/LOGGING.C b/puttysrc/LOGGING.C
new file mode 100644
index 0000000..3a43663
--- /dev/null
+++ b/puttysrc/LOGGING.C
@@ -0,0 +1,415 @@
+/*
+ * Session logging.
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include "putty.h"
+
+/* log session to file stuff ... */
+struct LogContext {
+ FILE *lgfp;
+ enum { L_CLOSED, L_OPENING, L_OPEN, L_ERROR } state;
+ bufchain queue;
+ Filename currlogfilename;
+ void *frontend;
+ Config cfg;
+};
+
+static void xlatlognam(Filename *d, Filename s, char *hostname, struct tm *tm);
+
+/*
+ * Internal wrapper function which must be called for _all_ output
+ * to the log file. It takes care of opening the log file if it
+ * isn't open, buffering data if it's in the process of being
+ * opened asynchronously, etc.
+ */
+static void logwrite(struct LogContext *ctx, void *data, int len)
+{
+ /*
+ * In state L_CLOSED, we call logfopen, which will set the state
+ * to one of L_OPENING, L_OPEN or L_ERROR. Hence we process all of
+ * those three _after_ processing L_CLOSED.
+ */
+ if (ctx->state == L_CLOSED)
+ logfopen(ctx);
+
+ if (ctx->state == L_OPENING) {
+ bufchain_add(&ctx->queue, data, len);
+ } else if (ctx->state == L_OPEN) {
+ assert(ctx->lgfp);
+ fwrite(data, 1, len, ctx->lgfp);
+ } /* else L_ERROR, so ignore the write */
+}
+
+/*
+ * Convenience wrapper on logwrite() which printf-formats the
+ * string.
+ */
+static void logprintf(struct LogContext *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ char *data;
+
+ va_start(ap, fmt);
+ data = dupvprintf(fmt, ap);
+ va_end(ap);
+
+ logwrite(ctx, data, strlen(data));
+ sfree(data);
+}
+
+/*
+ * Flush any open log file.
+ */
+void logflush(void *handle) {
+ struct LogContext *ctx = (struct LogContext *)handle;
+ if (ctx->cfg.logtype > 0)
+ if (ctx->state == L_OPEN)
+ fflush(ctx->lgfp);
+}
+
+static void logfopen_callback(void *handle, int mode)
+{
+ struct LogContext *ctx = (struct LogContext *)handle;
+ char buf[256], *event;
+ struct tm tm;
+ const char *fmode;
+
+ if (mode == 0) {
+ ctx->state = L_ERROR; /* disable logging */
+ } else {
+ fmode = (mode == 1 ? "ab" : "wb");
+ ctx->lgfp = f_open(ctx->currlogfilename, fmode, TRUE);
+ if (ctx->lgfp)
+ ctx->state = L_OPEN;
+ else
+ ctx->state = L_ERROR;
+ }
+
+ if (ctx->state == L_OPEN) {
+ /* Write header line into log file. */
+ tm = ltime();
+ strftime(buf, 24, "%Y.%m.%d %H:%M:%S", &tm);
+ logprintf(ctx, "=~=~=~=~=~=~=~=~=~=~=~= PuTTY log %s"
+ " =~=~=~=~=~=~=~=~=~=~=~=\r\n", buf);
+ }
+
+ event = dupprintf("%s session log (%s mode) to file: %s",
+ (mode == 0 ? "Disabled writing" :
+ mode == 1 ? "Appending" : "Writing new"),
+ (ctx->cfg.logtype == LGTYP_ASCII ? "ASCII" :
+ ctx->cfg.logtype == LGTYP_DEBUG ? "raw" :
+ ctx->cfg.logtype == LGTYP_PACKETS ? "SSH packets" :
+ ctx->cfg.logtype == LGTYP_SSHRAW ? "SSH raw data" :
+ "unknown"),
+ filename_to_str(&ctx->currlogfilename));
+ logevent(ctx->frontend, event);
+ sfree(event);
+
+ /*
+ * Having either succeeded or failed in opening the log file,
+ * we should write any queued data out.
+ */
+ assert(ctx->state != L_OPENING); /* make _sure_ it won't be requeued */
+ while (bufchain_size(&ctx->queue)) {
+ void *data;
+ int len;
+ bufchain_prefix(&ctx->queue, &data, &len);
+ logwrite(ctx, data, len);
+ bufchain_consume(&ctx->queue, len);
+ }
+}
+
+/*
+ * Open the log file. Takes care of detecting an already-existing
+ * file and asking the user whether they want to append, overwrite
+ * or cancel logging.
+ */
+void logfopen(void *handle)
+{
+ struct LogContext *ctx = (struct LogContext *)handle;
+ struct tm tm;
+ int mode;
+
+ /* Prevent repeat calls */
+ if (ctx->state != L_CLOSED)
+ return;
+
+ if (!ctx->cfg.logtype)
+ return;
+
+ tm = ltime();
+
+ /* substitute special codes in file name */
+ xlatlognam(&ctx->currlogfilename, ctx->cfg.logfilename,ctx->cfg.host, &tm);
+
+ ctx->lgfp = f_open(ctx->currlogfilename, "r", FALSE); /* file already present? */
+ if (ctx->lgfp) {
+ fclose(ctx->lgfp);
+ if (ctx->cfg.logxfovr != LGXF_ASK) {
+ mode = ((ctx->cfg.logxfovr == LGXF_OVR) ? 2 : 1);
+ } else
+ mode = askappend(ctx->frontend, ctx->currlogfilename,
+ logfopen_callback, ctx);
+ } else
+ mode = 2; /* create == overwrite */
+
+ if (mode < 0)
+ ctx->state = L_OPENING;
+ else
+ logfopen_callback(ctx, mode); /* open the file */
+}
+
+void logfclose(void *handle)
+{
+ struct LogContext *ctx = (struct LogContext *)handle;
+ if (ctx->lgfp) {
+ fclose(ctx->lgfp);
+ ctx->lgfp = NULL;
+ }
+ ctx->state = L_CLOSED;
+}
+
+/*
+ * Log session traffic.
+ */
+void logtraffic(void *handle, unsigned char c, int logmode)
+{
+ struct LogContext *ctx = (struct LogContext *)handle;
+ if (ctx->cfg.logtype > 0) {
+ if (ctx->cfg.logtype == logmode)
+ logwrite(ctx, &c, 1);
+ }
+}
+
+/*
+ * Log an Event Log entry. Used in SSH packet logging mode; this is
+ * also as convenient a place as any to put the output of Event Log
+ * entries to stderr when a command-line tool is in verbose mode.
+ * (In particular, this is a better place to put it than in the
+ * front ends, because it only has to be done once for all
+ * platforms. Platforms which don't have a meaningful stderr can
+ * just avoid defining FLAG_STDERR.
+ */
+void log_eventlog(void *handle, const char *event)
+{
+ struct LogContext *ctx = (struct LogContext *)handle;
+ if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) {
+ fprintf(stderr, "%s\n", event);
+ fflush(stderr);
+ }
+ /* If we don't have a context yet (eg winnet.c init) then skip entirely */
+ if (!ctx)
+ return;
+ if (ctx->cfg.logtype != LGTYP_PACKETS &&
+ ctx->cfg.logtype != LGTYP_SSHRAW)
+ return;
+ logprintf(ctx, "Event Log: %s\r\n", event);
+ logflush(ctx);
+}
+
+/*
+ * Log an SSH packet.
+ * If n_blanks != 0, blank or omit some parts.
+ * Set of blanking areas must be in increasing order.
+ */
+void log_packet(void *handle, int direction, int type,
+ char *texttype, void *data, int len,
+ int n_blanks, const struct logblank_t *blanks)
+{
+ struct LogContext *ctx = (struct LogContext *)handle;
+ char dumpdata[80], smalldata[5];
+ int p = 0, b = 0, omitted = 0;
+ int output_pos = 0; /* NZ if pending output in dumpdata */
+
+ if (!(ctx->cfg.logtype == LGTYP_SSHRAW ||
+ (ctx->cfg.logtype == LGTYP_PACKETS && texttype)))
+ return;
+
+ /* Packet header. */
+ if (texttype)
+ logprintf(ctx, "%s packet type %d / 0x%02x (%s)\r\n",
+ direction == PKT_INCOMING ? "Incoming" : "Outgoing",
+ type, type, texttype);
+ else
+ logprintf(ctx, "%s raw data\r\n",
+ direction == PKT_INCOMING ? "Incoming" : "Outgoing");
+
+ /*
+ * Output a hex/ASCII dump of the packet body, blanking/omitting
+ * parts as specified.
+ */
+ while (p < len) {
+ int blktype;
+
+ /* Move to a current entry in the blanking array. */
+ while ((b < n_blanks) &&
+ (p >= blanks[b].offset + blanks[b].len))
+ b++;
+ /* Work out what type of blanking to apply to
+ * this byte. */
+ blktype = PKTLOG_EMIT; /* default */
+ if ((b < n_blanks) &&
+ (p >= blanks[b].offset) &&
+ (p < blanks[b].offset + blanks[b].len))
+ blktype = blanks[b].type;
+
+ /* If we're about to stop omitting, it's time to say how
+ * much we omitted. */
+ if ((blktype != PKTLOG_OMIT) && omitted) {
+ logprintf(ctx, " (%d byte%s omitted)\r\n",
+ omitted, (omitted==1?"":"s"));
+ omitted = 0;
+ }
+
+ /* (Re-)initialise dumpdata as necessary
+ * (start of row, or if we've just stopped omitting) */
+ if (!output_pos && !omitted)
+ sprintf(dumpdata, " %08x%*s\r\n", p-(p%16), 1+3*16+2+16, "");
+
+ /* Deal with the current byte. */
+ if (blktype == PKTLOG_OMIT) {
+ omitted++;
+ } else {
+ int c;
+ if (blktype == PKTLOG_BLANK) {
+ c = 'X';
+ sprintf(smalldata, "XX");
+ } else { /* PKTLOG_EMIT */
+ c = ((unsigned char *)data)[p];
+ sprintf(smalldata, "%02x", c);
+ }
+ dumpdata[10+2+3*(p%16)] = smalldata[0];
+ dumpdata[10+2+3*(p%16)+1] = smalldata[1];
+ dumpdata[10+1+3*16+2+(p%16)] = (isprint(c) ? c : '.');
+ output_pos = (p%16) + 1;
+ }
+
+ p++;
+
+ /* Flush row if necessary */
+ if (((p % 16) == 0) || (p == len) || omitted) {
+ if (output_pos) {
+ strcpy(dumpdata + 10+1+3*16+2+output_pos, "\r\n");
+ logwrite(ctx, dumpdata, strlen(dumpdata));
+ output_pos = 0;
+ }
+ }
+
+ }
+
+ /* Tidy up */
+ if (omitted)
+ logprintf(ctx, " (%d byte%s omitted)\r\n",
+ omitted, (omitted==1?"":"s"));
+ logflush(ctx);
+}
+
+void *log_init(void *frontend, Config *cfg)
+{
+ struct LogContext *ctx = snew(struct LogContext);
+ ctx->lgfp = NULL;
+ ctx->state = L_CLOSED;
+ ctx->frontend = frontend;
+ ctx->cfg = *cfg; /* STRUCTURE COPY */
+ bufchain_init(&ctx->queue);
+ return ctx;
+}
+
+void log_free(void *handle)
+{
+ struct LogContext *ctx = (struct LogContext *)handle;
+
+ logfclose(ctx);
+ bufchain_clear(&ctx->queue);
+ sfree(ctx);
+}
+
+void log_reconfig(void *handle, Config *cfg)
+{
+ struct LogContext *ctx = (struct LogContext *)handle;
+ int reset_logging;
+
+ if (!filename_equal(ctx->cfg.logfilename, cfg->logfilename) ||
+ ctx->cfg.logtype != cfg->logtype)
+ reset_logging = TRUE;
+ else
+ reset_logging = FALSE;
+
+ if (reset_logging)
+ logfclose(ctx);
+
+ ctx->cfg = *cfg; /* STRUCTURE COPY */
+
+ if (reset_logging)
+ logfopen(ctx);
+}
+
+/*
+ * translate format codes into time/date strings
+ * and insert them into log file name
+ *
+ * "&Y":YYYY "&m":MM "&d":DD "&T":hhmmss "&h": "&&":&
+ */
+static void xlatlognam(Filename *dest, Filename src,
+ char *hostname, struct tm *tm) {
+ char buf[10], *bufp;
+ int size;
+ char buffer[FILENAME_MAX];
+ int len = sizeof(buffer)-1;
+ char *d;
+ const char *s;
+
+ d = buffer;
+ s = filename_to_str(&src);
+
+ while (*s) {
+ /* Let (bufp, len) be the string to append. */
+ bufp = buf; /* don't usually override this */
+ if (*s == '&') {
+ char c;
+ s++;
+ size = 0;
+ if (*s) switch (c = *s++, tolower(c)) {
+ case 'y':
+ size = strftime(buf, sizeof(buf), "%Y", tm);
+ break;
+ case 'm':
+ size = strftime(buf, sizeof(buf), "%m", tm);
+ break;
+ case 'd':
+ size = strftime(buf, sizeof(buf), "%d", tm);
+ break;
+ case 't':
+ size = strftime(buf, sizeof(buf), "%H%M%S", tm);
+ break;
+ case 'h':
+ bufp = hostname;
+ size = strlen(bufp);
+ break;
+ default:
+ buf[0] = '&';
+ size = 1;
+ if (c != '&')
+ buf[size++] = c;
+ }
+ } else {
+ buf[0] = *s++;
+ size = 1;
+ }
+ if (size > len)
+ size = len;
+ memcpy(d, bufp, size);
+ d += size;
+ len -= size;
+ }
+ *d = '\0';
+
+ *dest = filename_from_str(buffer);
+}
diff --git a/puttysrc/MAC/MAC.C b/puttysrc/MAC/MAC.C
new file mode 100644
index 0000000..70c71f8
--- /dev/null
+++ b/puttysrc/MAC/MAC.C
@@ -0,0 +1,880 @@
+/* $Id: mac.c 5424 2005-03-01 21:38:06Z owen $ */
+/*
+ * Copyright (c) 1999, 2003 Ben Harris
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/*
+ * mac.c -- miscellaneous Mac-specific routines
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include /* putty.h needs size_t */
+#include /* for vsprintf */
+
+#define PUTTY_DO_GLOBALS
+
+#include "macresid.h"
+#include "putty.h"
+#include "ssh.h"
+#include "terminal.h"
+#include "mac.h"
+
+Session *sesslist;
+
+static int cold = 1;
+static int borednow = FALSE;
+struct mac_gestalts mac_gestalts;
+UInt32 sleeptime;
+static long timing_next_time;
+
+static void mac_startup(void);
+static void mac_eventloop(void);
+#pragma noreturn (mac_eventloop)
+static void mac_event(EventRecord *);
+static void mac_contentclick(WindowPtr, EventRecord *);
+static void mac_growwindow(WindowPtr, EventRecord *);
+static void mac_activatewindow(WindowPtr, EventRecord *);
+static void mac_suspendresume(EventRecord *);
+static void mac_activateabout(WindowPtr, EventRecord *);
+static void mac_updatewindow(WindowPtr);
+static void mac_updatelicence(WindowPtr);
+static void mac_keypress(EventRecord *);
+static int mac_windowtype(WindowPtr);
+static void mac_menucommand(long);
+static void mac_openlicence(void);
+static void mac_adjustcursor(RgnHandle);
+static void mac_adjustmenus(void);
+static void mac_closewindow(WindowPtr);
+static void mac_zoomwindow(WindowPtr, short);
+#pragma noreturn (cleanup_exit)
+
+struct mac_windows {
+ WindowPtr about;
+ WindowPtr licence;
+};
+
+struct mac_windows windows;
+
+int main (int argc, char **argv) {
+
+ mac_startup();
+ mac_eventloop();
+}
+
+#pragma noreturn (main)
+
+static void mac_startup(void) {
+ Handle menuBar;
+ TECInfoHandle ti;
+
+#if !TARGET_API_MAC_CARBON
+ /* Init Memory Manager */
+ MaxApplZone();
+ /* Init QuickDraw */
+ InitGraf(&qd.thePort);
+ /* Init Font Manager */
+ InitFonts();
+ /* Init Window Manager */
+ InitWindows();
+ /* Init Menu Manager */
+ InitMenus();
+ /* Init TextEdit */
+ TEInit();
+ /* Init Dialog Manager */
+ InitDialogs(NULL);
+#endif
+ cold = 0;
+
+ /* Get base system version (only used if there's no better selector) */
+ if (Gestalt(gestaltSystemVersion, &mac_gestalts.sysvers) != noErr ||
+ (mac_gestalts.sysvers &= 0xffff) < 0x700)
+ fatalbox("PuTTY requires System 7 or newer");
+ /* Find out if we've got Color Quickdraw */
+ if (Gestalt(gestaltQuickdrawVersion, &mac_gestalts.qdvers) != noErr)
+ mac_gestalts.qdvers = gestaltOriginalQD;
+ /* ... and the Appearance Manager? */
+ if (Gestalt(gestaltAppearanceVersion, &mac_gestalts.apprvers) != noErr)
+ if (Gestalt(gestaltAppearanceAttr, NULL) == noErr)
+ mac_gestalts.apprvers = 0x0100;
+ else
+ mac_gestalts.apprvers = 0;
+#if TARGET_RT_MAC_CFM
+ /* Paranoia: Did we manage to pull in AppearanceLib? */
+ if (&RegisterAppearanceClient == kUnresolvedCFragSymbolAddress)
+ mac_gestalts.apprvers = 0;
+#endif
+#if TARGET_CPU_68K
+ mac_gestalts.cntlattr = 0;
+ mac_gestalts.windattr = 0;
+#else
+ /* Mac OS 8.5 Control Manager (proportional scrollbars)? */
+ if (Gestalt(gestaltControlMgrAttr, &mac_gestalts.cntlattr) != noErr ||
+ &SetControlViewSize == kUnresolvedCFragSymbolAddress)
+ mac_gestalts.cntlattr = 0;
+ /* Mac OS 8.5 Window Manager? */
+ if (Gestalt(gestaltWindowMgrAttr, &mac_gestalts.windattr) != noErr ||
+ &SetWindowContentColor == kUnresolvedCFragSymbolAddress)
+ mac_gestalts.windattr = 0;
+ /* Mac OS 8.5 Menu Manager? */
+ if (Gestalt(gestaltMenuMgrAttr, &mac_gestalts.menuattr) != noErr)
+ mac_gestalts.menuattr = 0;
+#endif
+ /* Text Encoding Conversion Manager? */
+ if (
+#if TARGET_RT_MAC_CFM
+ &TECGetInfo == kUnresolvedCFragSymbolAddress ||
+#else
+ InitializeUnicodeConverter(NULL) != noErr ||
+#endif
+ TECGetInfo(&ti) != noErr)
+ mac_gestalts.encvvers = 0;
+ else {
+ mac_gestalts.encvvers = (*ti)->tecVersion;
+ mac_gestalts.uncvattr = (*ti)->tecUnicodeConverterFeatures;
+ DisposeHandle((Handle)ti);
+ }
+ /* Navigation Services? */
+ if (NavServicesAvailable())
+ mac_gestalts.navsvers = NavLibraryVersion();
+ else
+ mac_gestalts.navsvers = 0;
+
+ sk_init();
+
+ /* We've been tested with the Appearance Manager */
+ if (mac_gestalts.apprvers != 0)
+ RegisterAppearanceClient();
+
+ menuBar = GetNewMBar(128);
+ if (menuBar == NULL)
+ fatalbox("Unable to create menu bar.");
+ SetMenuBar(menuBar);
+ AppendResMenu(GetMenuHandle(mApple), 'DRVR');
+ if (mac_gestalts.menuattr & gestaltMenuMgrAquaLayoutMask) {
+ DeleteMenuItem(GetMenuHandle(mFile), iQuit);
+ /* Also delete the separator above the Quit item. */
+ DeleteMenuItem(GetMenuHandle(mFile), iQuit - 1);
+ }
+ mac_adjustmenus();
+ DrawMenuBar();
+ InitCursor();
+ windows.about = NULL;
+ windows.licence = NULL;
+
+ 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;
+ }
+ }
+ flags = FLAG_INTERACTIVE;
+
+#if !TARGET_API_MAC_CARBON
+ {
+ short vol;
+ long dirid;
+
+ /* Set the default directory for loading and saving settings. */
+ /* XXX Should we create it? */
+ if (get_session_dir(FALSE, &vol, &dirid) == noErr) {
+ LMSetSFSaveDisk(-vol);
+ LMSetCurDirStore(dirid);
+ }
+ }
+#endif
+
+ /* Install Apple Event handlers. */
+ AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
+ NewAEEventHandlerUPP(&mac_aevt_oapp), 0, FALSE);
+ AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
+ NewAEEventHandlerUPP(&mac_aevt_odoc), 0, FALSE);
+ AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
+ NewAEEventHandlerUPP(&mac_aevt_pdoc), 0, FALSE);
+ AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerUPP(&mac_aevt_quit), 0, FALSE);
+}
+
+void timer_change_notify(long next)
+{
+ timing_next_time = next;
+}
+
+static void mac_eventloop(void) {
+ Boolean gotevent;
+ EventRecord event;
+ RgnHandle cursrgn;
+ long next;
+ long ticksleft;
+
+ cursrgn = NewRgn();
+ sleeptime = 0;
+ for (;;) {
+ ticksleft=timing_next_time-GETTICKCOUNT();
+ if (sleeptime > ticksleft && ticksleft >=0)
+ sleeptime=ticksleft;
+ gotevent = WaitNextEvent(everyEvent, &event, sleeptime, cursrgn);
+ if (timing_next_time <= GETTICKCOUNT()) {
+ if (run_timers(timing_next_time, &next)) {
+ timer_change_notify(next);
+ }
+ }
+
+ /*
+ * XXX For now, limit sleep time to 1/10 s to work around
+ * wake-before-sleep race in MacTCP code.
+ */
+ sleeptime = 6;
+ mac_adjustcursor(cursrgn);
+ if (gotevent) {
+ /* Ensure we get a null event when the real ones run out. */
+ sleeptime = 0;
+ mac_event(&event);
+ if (borednow)
+ cleanup_exit(0);
+ }
+ if (!gotevent)
+ sk_poll();
+ if (mac_gestalts.apprvers >= 0x100 && mac_frontwindow() != NULL)
+ IdleControls(mac_frontwindow());
+ }
+ DisposeRgn(cursrgn);
+}
+
+static void mac_event(EventRecord *event) {
+ short part;
+ WindowPtr window;
+
+ switch (event->what) {
+ case mouseDown:
+ part = FindWindow(event->where, &window);
+ switch (part) {
+ case inMenuBar:
+ mac_adjustmenus();
+ mac_menucommand(MenuSelect(event->where));
+ break;
+#if !TARGET_API_MAC_CARBON
+ case inSysWindow:
+ SystemClick(event, window);
+ break;
+#endif
+ case inContent:
+ if (window != FrontWindow())
+ /* XXX: check for movable modal dboxes? */
+ SelectWindow(window);
+ else
+ mac_contentclick(window, event);
+ break;
+ case inGoAway:
+ if (TrackGoAway(window, event->where))
+ mac_closewindow(window);
+ break;
+ case inDrag:
+ /* XXX: moveable modal check? */
+#if TARGET_API_MAC_CARBON
+ {
+ BitMap screenBits;
+
+ GetQDGlobalsScreenBits(&screenBits);
+ DragWindow(window, event->where, &screenBits.bounds);
+ }
+#else
+ DragWindow(window, event->where, &qd.screenBits.bounds);
+#endif
+ break;
+ case inGrow:
+ mac_growwindow(window, event);
+ break;
+ case inZoomIn:
+ case inZoomOut:
+ if (TrackBox(window, event->where, part))
+ mac_zoomwindow(window, part);
+ break;
+ }
+ break;
+ case keyDown:
+ case autoKey:
+ mac_keypress(event);
+ break;
+ case activateEvt:
+ mac_activatewindow((WindowPtr)event->message, event);
+ break;
+ case updateEvt:
+ mac_updatewindow((WindowPtr)event->message);
+ break;
+#if !TARGET_API_MAC_CARBON
+ case diskEvt:
+ if (HiWord(event->message) != noErr) {
+ Point pt;
+
+ SetPt(&pt, 120, 120);
+ DIBadMount(pt, event->message);
+ }
+ break;
+#endif
+ case osEvt:
+ switch ((event->message & osEvtMessageMask) >> 24) {
+ case suspendResumeMessage:
+ mac_suspendresume(event);
+ break;
+ }
+ break;
+ case kHighLevelEvent:
+ AEProcessAppleEvent(event); /* errors? */
+ break;
+ }
+}
+
+static void mac_contentclick(WindowPtr window, EventRecord *event)
+{
+
+ if (mac_wininfo(window)->click != NULL)
+ (*mac_wininfo(window)->click)(window, event);
+}
+
+static void mac_growwindow(WindowPtr window, EventRecord *event)
+{
+
+ if (mac_wininfo(window)->grow != NULL)
+ (*mac_wininfo(window)->grow)(window, event);
+}
+
+static void mac_activatewindow(WindowPtr window, EventRecord *event)
+{
+
+ mac_adjustmenus();
+ if (mac_wininfo(window)->activate != NULL)
+ (*mac_wininfo(window)->activate)(window, event);
+}
+
+static void mac_updatewindow(WindowPtr window)
+{
+
+ if (mac_wininfo(window)->update != NULL)
+ (*mac_wininfo(window)->update)(window);
+}
+
+/*
+ * Work out what kind of window we're dealing with.
+ */
+static int mac_windowtype(WindowPtr window)
+{
+
+#if !TARGET_API_MAC_CARBON
+ if (GetWindowKind(window) < 0)
+ return wDA;
+#endif
+ return ((WinInfo *)GetWRefCon(window))->wtype;
+}
+
+/*
+ * Handle a key press
+ */
+static void mac_keypress(EventRecord *event) {
+ WindowPtr window;
+
+ window = mac_frontwindow();
+ /*
+ * Check for a command-key combination, but ignore it if it counts
+ * as a meta-key combination and we're in a terminal window.
+ */
+ if (event->what == keyDown && (event->modifiers & cmdKey) /*&&
+ !((event->modifiers & cfg.meta_modifiers) == cfg.meta_modifiers &&
+ mac_windowtype(window) == wTerminal)*/) {
+ mac_adjustmenus();
+ mac_menucommand(MenuKey(event->message & charCodeMask));
+ } else {
+ if (window != NULL && mac_wininfo(window)->key != NULL)
+ (*mac_wininfo(window)->key)(window, event);
+ }
+}
+
+static void mac_menucommand(long result) {
+ short menu, item;
+ WindowPtr window;
+#if !TARGET_API_MAC_CARBON
+ Str255 da;
+#endif
+
+ menu = HiWord(result);
+ item = LoWord(result);
+ window = mac_frontwindow();
+ /* Things which do the same whatever window we're in. */
+ switch (menu) {
+ case mApple:
+ switch (item) {
+ case iAbout:
+ mac_openabout();
+ goto done;
+#if !TARGET_API_MAC_CARBON
+ default:
+ GetMenuItemText(GetMenuHandle(mApple), item, da);
+ OpenDeskAcc(da);
+ goto done;
+#endif
+ }
+ break;
+ case mFile:
+ switch (item) {
+ case iNew:
+ mac_newsession();
+ goto done;
+ case iOpen:
+ mac_opensession();
+ goto done;
+ case iChange:
+ mac_reconfig();
+ goto done;
+ case iClose:
+ mac_closewindow(window);
+ goto done;
+ case iSave:
+ mac_savesession();
+ goto done;
+ case iSaveAs:
+ mac_savesessionas();
+ goto done;
+ case iDuplicate:
+ mac_dupsession();
+ goto done;
+ case iQuit:
+ cleanup_exit(0);
+ goto done;
+ }
+ break;
+ }
+ /* If we get here, handling is up to window-specific code. */
+ if (window != NULL && mac_wininfo(window)->menu != NULL)
+ (*mac_wininfo(window)->menu)(window, menu, item);
+
+ done:
+ HiliteMenu(0);
+}
+
+static void mac_closewindow(WindowPtr window) {
+
+ switch (mac_windowtype(window)) {
+#if !TARGET_API_MAC_CARBON
+ case wDA:
+ CloseDeskAcc(GetWindowKind(window));
+ break;
+#endif
+ default:
+ if (mac_wininfo(window)->close != NULL)
+ (*mac_wininfo(window)->close)(window);
+ break;
+ }
+}
+
+static void mac_suspendresume(EventRecord *event)
+{
+ WindowPtr front;
+ EventRecord fakeevent;
+
+ /*
+ * We're called either before we're suspended or after we're
+ * resumed, so we're the front application at this point.
+ */
+ front = FrontWindow();
+ if (front != NULL) {
+ fakeevent.what = activateEvt;
+ fakeevent.message = (UInt32)front;
+ fakeevent.when = event->when;
+ fakeevent.where = event->where;
+ fakeevent.modifiers =
+ (event->message & resumeFlag) ? activeFlag : 0;
+ mac_activatewindow(front, &fakeevent);
+ }
+}
+
+static void mac_zoomwindow(WindowPtr window, short part) {
+
+ /* FIXME: do something */
+}
+
+/*
+ * Make the menus look right before the user gets to see them.
+ */
+#if TARGET_API_MAC_CARBON
+#define EnableItem EnableMenuItem
+#define DisableItem DisableMenuItem
+#endif
+static void mac_adjustmenus(void) {
+ WindowPtr window;
+ MenuHandle menu;
+
+ window = mac_frontwindow();
+ menu = GetMenuHandle(mApple);
+ EnableItem(menu, 0);
+ EnableItem(menu, iAbout);
+
+ menu = GetMenuHandle(mFile);
+ EnableItem(menu, 0);
+ EnableItem(menu, iNew);
+ if (window != NULL)
+ EnableItem(menu, iClose);
+ else
+ DisableItem(menu, iClose);
+ EnableItem(menu, iQuit);
+
+ if (window != NULL && mac_wininfo(window)->adjustmenus != NULL)
+ (*mac_wininfo(window)->adjustmenus)(window);
+ else {
+ DisableItem(menu, iChange);
+ DisableItem(menu, iSave);
+ DisableItem(menu, iSaveAs);
+ DisableItem(menu, iDuplicate);
+ menu = GetMenuHandle(mEdit);
+ DisableItem(menu, 0);
+ menu = GetMenuHandle(mWindow);
+ DisableItem(menu, 0); /* Until we get more than 1 item on it. */
+ }
+ DrawMenuBar();
+}
+
+/*
+ * Make sure the right cursor's being displayed.
+ */
+static void mac_adjustcursor(RgnHandle cursrgn) {
+ Point mouse;
+ WindowPtr window, front;
+ short part;
+#if TARGET_API_MAC_CARBON
+ Cursor arrow;
+ RgnHandle visrgn;
+#endif
+
+ GetMouse(&mouse);
+ LocalToGlobal(&mouse);
+ part = FindWindow(mouse, &window);
+ front = FrontWindow();
+ if (part != inContent || window == NULL || window != front) {
+ /* Cursor isn't in the front window, so switch to arrow */
+#if TARGET_API_MAC_CARBON
+ GetQDGlobalsArrow(&arrow);
+ SetCursor(&arrow);
+#else
+ SetCursor(&qd.arrow);
+#endif
+ SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
+ if (front != NULL) {
+#if TARGET_API_MAC_CARBON
+ visrgn = NewRgn();
+ GetPortVisibleRegion(GetWindowPort(front), visrgn);
+ DiffRgn(cursrgn, visrgn, cursrgn);
+ DisposeRgn(visrgn);
+#else
+ DiffRgn(cursrgn, front->visRgn, cursrgn);
+#endif
+ }
+ } else {
+ if (mac_wininfo(window)->adjustcursor != NULL)
+ (*mac_wininfo(window)->adjustcursor)(window, mouse, cursrgn);
+ else {
+#if TARGET_API_MAC_CARBON
+ GetQDGlobalsArrow(&arrow);
+ SetCursor(&arrow);
+ GetPortVisibleRegion(GetWindowPort(window), cursrgn);
+#else
+ SetCursor(&qd.arrow);
+ CopyRgn(window->visRgn, cursrgn);
+#endif
+ }
+ }
+}
+
+pascal OSErr mac_aevt_quit(const AppleEvent *req, AppleEvent *reply,
+ long refcon)
+{
+ DescType type;
+ Size size;
+
+ if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
+ &type, NULL, 0, &size) == noErr)
+ return errAEParamMissed;
+
+ borednow = 1;
+ return noErr;
+}
+
+void cleanup_exit(int status)
+{
+
+#if !TARGET_RT_MAC_CFM
+ if (mac_gestalts.encvvers != 0)
+ TerminateUnicodeConverter();
+#endif
+ sk_cleanup();
+ exit(status);
+}
+
+/* This should only kill the current session, not the whole application. */
+void connection_fatal(void *frontend, char *fmt, ...) {
+ va_list ap;
+ Str255 stuff;
+ Session *s = frontend;
+
+ va_start(ap, fmt);
+ /* We'd like stuff to be a Pascal string */
+ stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
+ va_end(ap);
+ ParamText(stuff, NULL, NULL, NULL);
+ StopAlert(128, NULL);
+
+ s->session_closed = TRUE;
+
+ if (s->cfg.close_on_exit == FORCE_ON)
+ mac_closewindow(s->window);
+}
+
+/* Null SSH agent client -- never finds an agent. */
+
+int agent_exists(void)
+{
+
+ return FALSE;
+}
+
+int agent_query(void *in, int inlen, void **out, int *outlen,
+ void (*callback)(void *, void *, int), void *callback_ctx)
+{
+
+ *out = NULL;
+ *outlen = 0;
+ return 1;
+}
+
+/* Temporary null routines for testing. */
+
+int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
+ char *keystr, char *fingerprint,
+ void (*callback)(void *ctx, int result), void *ctx)
+{
+ Str255 pappname;
+ Str255 pfingerprint;
+ Str255 pkeytype;
+ Session *s = frontend;
+ int ret, alertret;
+
+ c2pstrcpy(pappname, appname);
+ c2pstrcpy(pkeytype, keytype);
+ c2pstrcpy(pfingerprint, fingerprint);
+
+ /*
+ * The alert shouldn't be modal, it should be movable modal, or
+ * a sheet in Aqua. Also, PuTTY might be in the background, in
+ * which case we should use the Notification Manager to wake up
+ * the user. In any case, we shouldn't hold up processing of
+ * other connections' data just because this one's waiting for
+ * the user.
+ */
+
+ /* Verify the key against the cache */
+
+ ret = verify_host_key(host, port, keytype, keystr);
+
+ if (ret == 0) { /* success - key matched OK */
+ return 1;
+ } else if (ret == 2) { /* key was different */
+ ParamText(pappname, pkeytype, pfingerprint, NULL);
+ alertret=CautionAlert(wWrong, NULL);
+ if (alertret == 8) {
+ /* Cancel */
+ return 0;
+ } else if (alertret == 9) {
+ /* Connect Just Once */
+ return 1;
+ } else {
+ /* Update Key */
+ store_host_key(host, port, keytype, keystr);
+ return 1;
+ }
+ } else /* ret == 1 */ { /* key was absent */
+ ParamText(pkeytype, pfingerprint, pappname, NULL);
+ alertret=CautionAlert(wAbsent, NULL);
+ if (alertret == 7) {
+ /* Cancel */
+ return 0;
+ } else if (alertret == 8) {
+ /* Connect Just Once */
+ return 1;
+ } else {
+ /* Update Key */
+ store_host_key(host, port, keytype, keystr);
+ return 1;
+ }
+ }
+}
+
+int askalg(void *frontend, const char *algtype, const char *algname,
+ void (*callback)(void *ctx, int result), void *ctx)
+{
+ return 0;
+}
+
+void old_keyfile_warning(void)
+{
+
+}
+
+FontSpec platform_default_fontspec(char const *name)
+{
+ FontSpec ret;
+ long smfs;
+
+ if (!strcmp(name, "Font")) {
+ smfs = GetScriptVariable(smSystemScript, smScriptMonoFondSize);
+ if (smfs == 0)
+ smfs = GetScriptVariable(smRoman, smScriptMonoFondSize);
+ if (smfs != 0) {
+ GetFontName(HiWord(smfs), ret.name);
+ if (ret.name[0] == 0)
+ memcpy(ret.name, "\pMonaco", 7);
+ ret.size = LoWord(smfs);
+ } else {
+ memcpy(ret.name, "\pMonaco", 7);
+ ret.size = 9;
+ }
+ ret.face = 0;
+ } else {
+ ret.name[0] = 0;
+ }
+
+ return ret;
+}
+
+Filename platform_default_filename(const char *name)
+{
+ Filename ret;
+ if (!strcmp(name, "LogFileName"))
+ FSMakeFSSpec(0, 0, "\pputty.log", &ret.fss);
+ else
+ memset(&ret, 0, sizeof(ret));
+ return ret;
+}
+
+char *platform_default_s(char const *name)
+{
+ return NULL;
+}
+
+int platform_default_i(char const *name, int def)
+{
+
+ /* Non-raw cut and paste of line-drawing chars works badly on the
+ * current Unix stub implementation of the Unicode functions.
+ * So I'm going to temporarily set the default to raw mode so
+ * that the failure mode isn't quite so drastically horrid.
+ * When Unicode comes in, this can all be put right. */
+ if (!strcmp(name, "RawCNP"))
+ return 1;
+ return def;
+}
+
+void platform_get_x11_auth(char *display, int *proto,
+ unsigned char *data, int *datalen)
+{
+ /* SGT: I have no idea whether Mac X servers need anything here. */
+}
+
+void update_specials_menu(void *frontend)
+{
+ Session *s = frontend;
+ WindowPtr front;
+
+ front = mac_frontwindow();
+ if (front != NULL && mac_windowsession(front) == s)
+ mac_adjustmenus();
+}
+
+void notify_remote_exit(void *frontend)
+{
+ Session *s = frontend;
+ int exitcode;
+
+ if (!s->session_closed &&
+ (exitcode = s->back->exitcode(s->backhandle)) >=0) {
+ s->session_closed = TRUE;
+ if (s->cfg.close_on_exit == FORCE_ON ||
+ (s->cfg.close_on_exit == AUTO && exitcode == 0)) {
+ mac_closewindow(s->window);
+ return;
+ }
+
+ /* The session's dead */
+
+ if (s->ldisc) {
+ ldisc_free(s->ldisc);
+ s->ldisc = NULL;
+ }
+
+ if (s->back) {
+ s->back->free(s->backhandle);
+ s->backhandle = NULL;
+ s->back = NULL;
+ update_specials_menu(s);
+ }
+
+ {
+ char title[100];
+ sprintf(title, "%.70s (inactive)", appname);
+ set_title(s, title);
+ }
+ }
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MAC.H b/puttysrc/MAC/MAC.H
new file mode 100644
index 0000000..5addf59
--- /dev/null
+++ b/puttysrc/MAC/MAC.H
@@ -0,0 +1,238 @@
+/*
+ * mac.h -- macintosh-specific declarations
+ */
+
+#ifndef PUTTY_MAC_H
+#define PUTTY_MAC_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "charset.h"
+#include "tree234.h"
+
+#define PUTTY_CREATOR FOUR_CHAR_CODE('pTTY')
+#define INTERNAL_CREATOR FOUR_CHAR_CODE('pTTI')
+#define SESS_TYPE FOUR_CHAR_CODE('Sess')
+#define SEED_TYPE FOUR_CHAR_CODE('Seed')
+#define HKYS_TYPE FOUR_CHAR_CODE('Hkys')
+
+struct mac_gestalts {
+ long sysvers;
+ long qdvers;
+ long apprvers;
+ long cntlattr;
+ long windattr;
+ long menuattr;
+ long encvvers; /* TEC version (from TECGetInfo()) */
+ long uncvattr; /* Unicode Converter attributes (frem TECGetInfo()) */
+ long navsvers; /* Navigation Services version */
+};
+
+extern struct mac_gestalts mac_gestalts;
+extern UInt32 sleeptime;
+
+#if TARGET_RT_MAC_CFM
+/* All systems that can use CFM have Color QuickDraw */
+#define HAVE_COLOR_QD() 1
+#else
+#define HAVE_COLOR_QD() (mac_gestalts.qdvers > gestaltOriginalQD)
+#endif
+
+/* Every window used by PuTTY has a refCon field pointing to one of these. */
+typedef struct {
+ struct Session *s; /* Only used in PuTTY */
+ struct KeyState *ks; /* Only used in PuTTYgen */
+ struct macctrls *mcs;
+
+ void (*activate) (WindowPtr, EventRecord *);
+ void (*adjustcursor)(WindowPtr, Point, RgnHandle);
+ void (*adjustmenus) (WindowPtr);
+ void (*update) (WindowPtr);
+ void (*click) (WindowPtr, EventRecord *);
+ void (*grow) (WindowPtr, EventRecord *);
+ void (*key) (WindowPtr, EventRecord *);
+ void (*menu) (WindowPtr, short, short);
+ void (*close) (WindowPtr);
+
+ int wtype;
+} WinInfo;
+
+#define mac_wininfo(w) ((WinInfo *)GetWRefCon(w))
+#define mac_windowsession(w) (((WinInfo *)GetWRefCon(w))->s)
+#define mac_winctrls(w) (((WinInfo *)GetWRefCon(w))->mcs)
+
+union macctrl;
+
+struct macctrls {
+ WindowPtr window;
+ void (*end)(WindowPtr, int);
+ tree234 *byctrl;
+ void *data; /* private data for config box */
+ unsigned int npanels;
+ unsigned int curpanel;
+ union macctrl **panels; /* lists of controls by panel */
+ union macctrl *focus; /* Input focus for System 7 */
+ union macctrl *defbutton; /* Default button */
+ union macctrl *canbutton; /* Cancel button */
+ Boolean gotcolour;
+ RGBColor thecolour;
+};
+
+typedef struct Session {
+ struct Session *next;
+ struct Session **prev;
+ /* Config that created this session */
+ Config cfg;
+ /* Temporary config for passing to Change Settings */
+ Config temp_cfg;
+ /* Terminal emulator internal state */
+ Terminal *term;
+ /* Display state */
+ int font_width, font_height;
+ /* Line discipline */
+ void *ldisc;
+ /* Backend */
+ Backend *back;
+ void *backhandle;
+ char *realhost;
+ /* Logging */
+ void *logctx;
+ /* Unicode stuff */
+ struct unicode_data ucsdata;
+ /* Session closed flag */
+ int session_closed;
+
+ /* Mac-specific elements */
+ short fontnum;
+ int font_ascent;
+ int font_leading;
+ int font_boldadjust;
+ Point font_stdnumer;
+ Point font_stddenom;
+ Point font_widenumer;
+ Point font_widedenom;
+ Point font_bignumer;
+ Point font_bigdenom;
+ WindowPtr window;
+ WindowPtr eventlog_window;
+ ListHandle eventlog;
+ PaletteHandle palette;
+ ControlHandle scrollbar;
+ WCTabHandle wctab;
+ int raw_mouse;
+ UnicodeToTextInfo uni_to_font; /* Only one of uni_to_font and */
+ charset_t font_charset; /* font_charset is used at a time. */
+ int hasfile;
+ FSSpec savefile;
+
+ /* Config dialogue bits */
+ WindowPtr settings_window;
+ struct controlbox *ctrlbox;
+ struct macctrls settings_ctrls;
+} Session;
+
+extern Session *sesslist;
+
+/* PuTTYgen per-window state */
+typedef struct KeyState {
+ DialogPtr box;
+ int collecting_entropy;
+ int entropy_got, entropy_required, entropy_size;
+ unsigned *entropy;
+ ControlHandle progress;
+} KeyState;
+
+#define mac_windowkey(w) (((WinInfo *)GetWRefCon(w))->ks)
+
+/* from macmisc.c */
+extern WindowPtr mac_frontwindow(void);
+/* from macdlg.c */
+extern void mac_newsession(void);
+extern void mac_reconfig(void);
+extern void mac_dupsession(void);
+extern void mac_savesession(void);
+extern void mac_savesessionas(void);
+/* from maceventlog.c */
+extern void mac_freeeventlog(Session *);
+extern void mac_showeventlog(Session *);
+/* from macterm.c */
+extern void mac_opensession(void);
+extern void mac_startsession(Session *);
+/* from macstore.c */
+extern OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID);
+extern OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID);
+extern void *open_settings_r_fsp(FSSpec *);
+extern void *open_settings_w_fsp(FSSpec *);
+extern int verify_host_key(const char *, int, const char *, const char*);
+extern void store_host_key(const char *, int, const char *, const char*);
+/* from macucs.c */
+extern void init_ucs(Session *);
+/* from macnet.c */
+extern void sk_poll(void);
+/* from mtcpnet.c */
+extern OSErr mactcp_init(void);
+extern void mactcp_cleanup(void);
+extern void mactcp_poll(void);
+extern SockAddr mactcp_namelookup(char const *, char **);
+extern SockAddr mactcp_nonamelookup(char const *);
+extern void mactcp_getaddr(SockAddr, char *, int);
+extern int mactcp_hostname_is_local(char *);
+extern int mactcp_address_is_local(SockAddr);
+extern int mactcp_addrtype(SockAddr);
+extern void mactcp_addrcopy(SockAddr, char *);
+extern void mactcp_addr_free(SockAddr);
+extern Socket mactcp_register(void *, Plug);
+extern Socket mactcp_new(SockAddr addr, int, int, int, int, int, Plug);
+extern Socket mactcp_newlistener(char *, int, Plug, int, int);
+extern char *mactcp_addr_error(SockAddr);
+/* from otnet.c */
+extern OSErr ot_init(void);
+extern void ot_cleanup(void);
+extern void ot_poll(void);
+extern SockAddr ot_namelookup(char const *, char **);
+extern SockAddr ot_nonamelookup(char const *);
+extern void ot_getaddr(SockAddr, char *, int);
+extern int ot_hostname_is_local(char *);
+extern int ot_address_is_local(SockAddr);
+extern int ot_addrtype(SockAddr);
+extern void ot_addrcopy(SockAddr, char *);
+extern void ot_addr_free(SockAddr);
+extern Socket ot_register(void *, Plug);
+extern Socket ot_new(SockAddr addr, int, int, int, int, int, Plug);
+extern Socket ot_newlistener(char *, int, Plug, int, int);
+extern char *ot_addr_error(SockAddr);
+/* from macabout.c */
+extern void mac_openabout(void);
+/* from macctrls.c */
+extern void macctrl_layoutbox(struct controlbox *, WindowPtr,
+ struct macctrls *);
+extern void macctrl_activate(WindowPtr, EventRecord *);
+extern void macctrl_click(WindowPtr, EventRecord *);
+extern void macctrl_key(WindowPtr, EventRecord *);
+extern void macctrl_update(WindowPtr);
+extern void macctrl_adjustmenus(WindowPtr);
+extern void macctrl_close(WindowPtr);
+
+
+/* from macpgkey.c */
+extern void mac_newkey(void);
+/* Apple Event Handlers (in various files) */
+extern pascal OSErr mac_aevt_oapp(const AppleEvent *, AppleEvent *, long);
+extern pascal OSErr mac_aevt_odoc(const AppleEvent *, AppleEvent *, long);
+extern pascal OSErr mac_aevt_pdoc(const AppleEvent *, AppleEvent *, long);
+extern pascal OSErr mac_aevt_quit(const AppleEvent *, AppleEvent *, long);
+
+#endif
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MACABOUT.C b/puttysrc/MAC/MACABOUT.C
new file mode 100644
index 0000000..d699a85
--- /dev/null
+++ b/puttysrc/MAC/MACABOUT.C
@@ -0,0 +1,189 @@
+/* $Id: macabout.c 4787 2004-11-16 15:27:00Z simon $ */
+/*
+ * Copyright (c) 1999, 2002, 2003 Ben Harris
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "putty.h"
+#include "mac.h"
+#include "macresid.h"
+
+static struct mac_windows {
+ WindowPtr about;
+ WindowPtr licence;
+} windows;
+
+static void mac_openlicence(void);
+
+static void mac_clickabout(WindowPtr window, EventRecord *event)
+{
+ short item;
+ DialogRef dialog;
+
+ dialog = GetDialogFromWindow(window);
+ if (DialogSelect(event, &dialog, &item))
+ switch (item) {
+ case wiAboutLicence:
+ mac_openlicence();
+ break;
+ }
+}
+
+static void mac_activateabout(WindowPtr window, EventRecord *event)
+{
+ DialogRef dialog;
+ DialogItemType itemtype;
+ Handle itemhandle;
+ short item;
+ Rect itemrect;
+ int active;
+
+ dialog = GetDialogFromWindow(window);
+ active = (event->modifiers & activeFlag) != 0;
+ GetDialogItem(dialog, wiAboutLicence, &itemtype, &itemhandle, &itemrect);
+ HiliteControl((ControlHandle)itemhandle, active ? 0 : 255);
+ DialogSelect(event, &dialog, &item);
+}
+
+static void mac_updateabout(WindowPtr window)
+{
+#if TARGET_API_MAC_CARBON
+ RgnHandle rgn;
+#endif
+
+ BeginUpdate(window);
+#if TARGET_API_MAC_CARBON
+ rgn = NewRgn();
+ GetPortVisibleRegion(GetWindowPort(window), rgn);
+ UpdateDialog(GetDialogFromWindow(window), rgn);
+ DisposeRgn(rgn);
+#else
+ UpdateDialog(window, window->visRgn);
+#endif
+ EndUpdate(window);
+}
+
+static void mac_closeabout(WindowPtr window)
+{
+
+ windows.about = NULL;
+ DisposeDialog(GetDialogFromWindow(window));
+}
+
+static void mac_updatelicence(WindowPtr window)
+{
+ Handle h;
+ int len;
+ long fondsize;
+ Rect textrect;
+
+ SetPort((GrafPtr)GetWindowPort(window));
+ BeginUpdate(window);
+ fondsize = GetScriptVariable(smRoman, smScriptSmallFondSize);
+ TextFont(HiWord(fondsize));
+ TextSize(LoWord(fondsize));
+ h = Get1Resource('TEXT', wLicence);
+ len = GetResourceSizeOnDisk(h);
+#if TARGET_API_MAC_CARBON
+ GetPortBounds(GetWindowPort(window), &textrect);
+#else
+ textrect = window->portRect;
+#endif
+ if (h != NULL) {
+ HLock(h);
+ TETextBox(*h, len, &textrect, teFlushDefault);
+ HUnlock(h);
+ }
+ EndUpdate(window);
+}
+
+static void mac_closelicence(WindowPtr window)
+{
+
+ windows.licence = NULL;
+ DisposeWindow(window);
+}
+
+void mac_openabout(void)
+{
+ DialogItemType itemtype;
+ Handle item;
+ VersRecHndl vers;
+ Rect box;
+ StringPtr longvers;
+ WinInfo *wi;
+
+ if (windows.about)
+ SelectWindow(windows.about);
+ else {
+ windows.about =
+ GetDialogWindow(GetNewDialog(wAbout, NULL, (WindowPtr)-1));
+ wi = snew(WinInfo);
+ memset(wi, 0, sizeof(*wi));
+ wi->wtype = wAbout;
+ wi->update = &mac_updateabout;
+ wi->click = &mac_clickabout;
+ wi->activate = &mac_activateabout;
+ wi->close = &mac_closeabout;
+ SetWRefCon(windows.about, (long)wi);
+ vers = (VersRecHndl)Get1Resource('vers', 1);
+ if (vers != NULL && *vers != NULL) {
+ longvers = (*vers)->shortVersion + (*vers)->shortVersion[0] + 1;
+ GetDialogItem(GetDialogFromWindow(windows.about), wiAboutVersion,
+ &itemtype, &item, &box);
+ assert(itemtype & kStaticTextDialogItem);
+ SetDialogItemText(item, longvers);
+ }
+ ShowWindow(windows.about);
+ }
+}
+
+static void mac_openlicence(void)
+{
+ WinInfo *wi;
+
+ if (windows.licence)
+ SelectWindow(windows.licence);
+ else {
+ windows.licence = GetNewWindow(wLicence, NULL, (WindowPtr)-1);
+ wi = snew(WinInfo);
+ memset(wi, 0, sizeof(*wi));
+ wi->wtype = wLicence;
+ wi->update = &mac_updatelicence;
+ wi->close = &mac_closelicence;
+ SetWRefCon(windows.licence, (long)wi);
+ ShowWindow(windows.licence);
+ }
+}
+
diff --git a/puttysrc/MAC/MACCTRLS.C b/puttysrc/MAC/MACCTRLS.C
new file mode 100644
index 0000000..af5b48c
--- /dev/null
+++ b/puttysrc/MAC/MACCTRLS.C
@@ -0,0 +1,2345 @@
+/* $Id: macctrls.c 6815 2006-08-28 10:35:12Z simon $ */
+/*
+ * Copyright (c) 2003 Ben Harris
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "putty.h"
+#include "mac.h"
+#include "macresid.h"
+#include "dialog.h"
+#include "tree234.h"
+
+/* Range of menu IDs for popup menus */
+#define MENU_MIN 1024
+#define MENU_MAX 2048
+
+
+union macctrl {
+ struct macctrl_generic {
+ enum {
+ MACCTRL_TEXT,
+ MACCTRL_EDITBOX,
+ MACCTRL_RADIO,
+ MACCTRL_CHECKBOX,
+ MACCTRL_BUTTON,
+ MACCTRL_LISTBOX,
+ MACCTRL_POPUP,
+ MACCTRL_GROUPBOX
+ } type;
+ /* Template from which this was generated */
+ union control *ctrl;
+ /* Next control in this panel */
+ union macctrl *next;
+ void *privdata;
+ int freeprivdata;
+ } generic;
+ struct {
+ struct macctrl_generic generic;
+ ControlRef tbctrl;
+ } text;
+ struct {
+ struct macctrl_generic generic;
+ ControlRef tbctrl;
+ ControlRef tblabel;
+ ControlRef tbbutton;
+ MenuRef menu;
+ int menuid;
+ unsigned int nids;
+ int *ids;
+ } editbox;
+ struct {
+ struct macctrl_generic generic;
+ ControlRef *tbctrls;
+ ControlRef tblabel;
+ } radio;
+ struct {
+ struct macctrl_generic generic;
+ ControlRef tbctrl;
+ } checkbox;
+ struct {
+ struct macctrl_generic generic;
+ ControlRef tbctrl;
+ ControlRef tbring;
+ } button;
+ struct {
+ struct macctrl_generic generic;
+ ControlRef tbctrl;
+ ControlRef tbup;
+ ControlRef tbdown;
+ ListHandle list;
+ unsigned int nids;
+ int *ids;
+ } listbox;
+ struct {
+ struct macctrl_generic generic;
+ ControlRef tbctrl;
+ MenuRef menu;
+ int menuid;
+ unsigned int nids;
+ int *ids;
+ } popup;
+ struct {
+ struct macctrl_generic generic;
+ ControlRef tbctrl;
+ } groupbox;
+};
+
+struct mac_layoutstate {
+ Point pos;
+ Point boxpos;
+ char *boxname;
+ unsigned int width;
+ unsigned int panelnum;
+};
+
+#define ctrlevent(mcs, mc, event) do { \
+ if ((mc)->generic.ctrl->generic.handler != NULL) \
+ (*(mc)->generic.ctrl->generic.handler)((mc)->generic.ctrl, (mcs),\
+ (mcs)->data, (event)); \
+} while (0)
+
+#define findbyctrl(mcs, ctrl) \
+ find234((mcs)->byctrl, (ctrl), macctrl_cmp_byctrl_find)
+
+static void macctrl_layoutset(struct mac_layoutstate *, struct controlset *,
+ WindowPtr, struct macctrls *);
+static void macctrl_hideshowpanel(struct macctrls *, unsigned int, int);
+static void macctrl_switchtopanel(struct macctrls *, unsigned int);
+static void macctrl_setfocus(struct macctrls *, union macctrl *);
+static void macctrl_text(struct macctrls *, WindowPtr,
+ struct mac_layoutstate *, union control *);
+static void macctrl_editbox(struct macctrls *, WindowPtr,
+ struct mac_layoutstate *, union control *);
+static void macctrl_radio(struct macctrls *, WindowPtr,
+ struct mac_layoutstate *, union control *);
+static void macctrl_checkbox(struct macctrls *, WindowPtr,
+ struct mac_layoutstate *, union control *);
+static void macctrl_button(struct macctrls *, WindowPtr,
+ struct mac_layoutstate *, union control *);
+static void macctrl_listbox(struct macctrls *, WindowPtr,
+ struct mac_layoutstate *, union control *);
+static void macctrl_popup(struct macctrls *, WindowPtr,
+ struct mac_layoutstate *, union control *);
+static void macctrl_groupbox(struct macctrls *, WindowPtr,
+ struct mac_layoutstate *, union control *);
+static void draglist_up(union macctrl *, struct macctrls *);
+static void draglist_down(union macctrl *, struct macctrls *);
+
+#if !TARGET_API_MAC_CARBON
+static pascal SInt32 macctrl_sys7_editbox_cdef(SInt16, ControlRef,
+ ControlDefProcMessage, SInt32);
+static pascal SInt32 macctrl_sys7_default_cdef(SInt16, ControlRef,
+ ControlDefProcMessage, SInt32);
+static pascal SInt32 macctrl_sys7_listbox_cdef(SInt16, ControlRef,
+ ControlDefProcMessage, SInt32);
+static pascal SInt32 macctrl_sys7_groupbox_cdef(SInt16, ControlRef,
+ ControlDefProcMessage, SInt32);
+#endif
+
+#if !TARGET_API_MAC_CARBON
+/*
+ * This trick enables us to keep all the CDEF code in the main
+ * application, which makes life easier. For details, see
+ * .
+ */
+
+#pragma options align=mac68k
+typedef struct {
+ short jmpabs; /* 4EF9 */
+ ControlDefUPP theUPP;
+} **PatchCDEF;
+#pragma options align=reset
+#endif
+
+static void macctrl_init()
+{
+#if !TARGET_API_MAC_CARBON
+ static int inited = 0;
+ PatchCDEF cdef;
+
+ if (inited) return;
+ cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_EditBox);
+ (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_editbox_cdef);
+ cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_Default);
+ (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_default_cdef);
+ cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_ListBox);
+ (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_listbox_cdef);
+ cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_GroupBox);
+ (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_groupbox_cdef);
+ inited = 1;
+#endif
+}
+
+
+static int macctrl_cmp_byctrl(void *av, void *bv)
+{
+ union macctrl *a = (union macctrl *)av;
+ union macctrl *b = (union macctrl *)bv;
+
+ if (a->generic.ctrl < b->generic.ctrl)
+ return -1;
+ else if (a->generic.ctrl > b->generic.ctrl)
+ return +1;
+ else
+ return 0;
+}
+
+static int macctrl_cmp_byctrl_find(void *av, void *bv)
+{
+ union control *a = (union control *)av;
+ union macctrl *b = (union macctrl *)bv;
+
+ if (a < b->generic.ctrl)
+ return -1;
+ else if (a > b->generic.ctrl)
+ return +1;
+ else
+ return 0;
+}
+
+static union control panellist;
+
+static void panellist_handler(union control *ctrl, void *dlg, void *data,
+ int event)
+{
+ struct macctrls *mcs = dlg;
+
+ /* XXX what if there's no selection? */
+ if (event == EVENT_SELCHANGE)
+ macctrl_switchtopanel(mcs, dlg_listbox_index(ctrl, dlg) + 1);
+}
+
+void macctrl_layoutbox(struct controlbox *cb, WindowPtr window,
+ struct macctrls *mcs)
+{
+ int i;
+ struct mac_layoutstate curstate;
+ ControlRef root;
+ Rect rect;
+
+ macctrl_init();
+ if (mac_gestalts.apprvers >= 0x100)
+ CreateRootControl(window, &root);
+#if TARGET_API_MAC_CARBON
+ GetPortBounds(GetWindowPort(window), &rect);
+#else
+ rect = window->portRect;
+#endif
+ mcs->window = window;
+ mcs->byctrl = newtree234(macctrl_cmp_byctrl);
+ mcs->focus = NULL;
+ mcs->defbutton = NULL;
+ mcs->canbutton = NULL;
+ mcs->curpanel = 1;
+ /* Count the number of panels */
+ mcs->npanels = 1;
+ for (i = 1; i < cb->nctrlsets; i++)
+ if (strcmp(cb->ctrlsets[i]->pathname, cb->ctrlsets[i-1]->pathname))
+ mcs->npanels++;
+ mcs->panels = snewn(mcs->npanels, union macctrl *);
+ memset(mcs->panels, 0, sizeof(*mcs->panels) * mcs->npanels);
+ curstate.panelnum = 0;
+
+ curstate.pos.h = rect.left + 13;
+ curstate.pos.v = rect.top + 13;
+ curstate.width = 160;
+ panellist.listbox.type = CTRL_LISTBOX;
+ panellist.listbox.handler = &panellist_handler;
+ panellist.listbox.height = 20;
+ panellist.listbox.percentwidth = 100;
+ macctrl_listbox(mcs, window, &curstate, &panellist);
+ /* XXX Start with panel 1 active */
+
+ curstate.pos.h = rect.left + 13 + 160 + 13;
+ curstate.pos.v = rect.bottom - 33;
+ curstate.width = rect.right - (rect.left + 13 + 160) - (13 * 2);
+ for (i = 0; i < cb->nctrlsets; i++) {
+ if (i > 0 && strcmp(cb->ctrlsets[i]->pathname,
+ cb->ctrlsets[i-1]->pathname)) {
+ curstate.pos.v = rect.top + 13;
+ curstate.panelnum++;
+ assert(curstate.panelnum < mcs->npanels);
+ dlg_listbox_add(&panellist, mcs, cb->ctrlsets[i]->pathname);
+ }
+ macctrl_layoutset(&curstate, cb->ctrlsets[i], window, mcs);
+ }
+ macctrl_switchtopanel(mcs, 1);
+ macctrl_hideshowpanel(mcs, 0, TRUE);
+ /* 14 = proxies, 19 = portfwd, 20 = SSH bugs */
+}
+
+
+
+#define MAXCOLS 16
+
+static void macctrl_layoutset(struct mac_layoutstate *curstate,
+ struct controlset *s,
+ WindowPtr window, struct macctrls *mcs)
+{
+ unsigned int i, j, ncols, colstart, colspan;
+ struct mac_layoutstate cols[MAXCOLS], pos;
+
+ /* Start a containing box, if we have a boxname. */
+ if (s->boxname && *s->boxname) {
+ curstate->boxpos = curstate->pos;
+ if (s->boxtitle) {
+ curstate->boxname = s->boxtitle;
+ curstate->pos.v += 10; /* XXX determine font height */
+ } else {
+ curstate->boxname = NULL;
+ }
+ curstate->pos.v += 6;
+ curstate->pos.h += 12;
+ curstate->width -= 24;
+ }
+
+ /* Draw a title, if we have one. */
+ if (!s->boxname && s->boxtitle) {
+ union control *ctrl = snew(union control);
+ ctrl->generic.handler = NULL;
+ ctrl->text.label = dupstr(s->boxtitle);
+ macctrl_text(mcs, window, curstate, ctrl);
+ /* FIXME: should be highlighted, centred or boxed */
+ }
+
+ cols[0] = *curstate;
+ ncols = 1;
+
+ for (i = 0; i < s->ncontrols; i++) {
+ union control *ctrl = s->ctrls[i];
+
+ colstart = COLUMN_START(ctrl->generic.column);
+ colspan = COLUMN_SPAN(ctrl->generic.column);
+ if (ctrl->generic.type == CTRL_COLUMNS) {
+ if (ctrl->columns.ncols != 1) {
+ ncols = ctrl->columns.ncols;
+ assert(ncols <= MAXCOLS);
+ for (j = 0; j < ncols; j++) {
+ cols[j] = cols[0];
+ if (j > 0)
+ cols[j].pos.h = cols[j-1].pos.h + cols[j-1].width + 6;
+ if (j == ncols - 1)
+ cols[j].width = curstate->width -
+ (cols[j].pos.h - curstate->pos.h);
+ else
+ cols[j].width = (curstate->width + 6) *
+ ctrl->columns.percentages[j] / 100 - 6;
+ }
+ } else {
+ for (j = 0; j < ncols; j++)
+ if (cols[j].pos.v > cols[0].pos.v)
+ cols[0].pos.v = cols[j].pos.v;
+ cols[0].width = curstate->width;
+ ncols = 1;
+ }
+ } else {
+ pos = cols[colstart];
+ pos.width = cols[colstart + colspan - 1].width +
+ (cols[colstart + colspan - 1].pos.h - cols[colstart].pos.h);
+
+ for (j = colstart; j < colstart + colspan; j++)
+ if (pos.pos.v < cols[j].pos.v)
+ pos.pos.v = cols[j].pos.v;
+
+ switch (ctrl->generic.type) {
+ case CTRL_TEXT:
+ macctrl_text(mcs, window, &pos, ctrl);
+ break;
+ case CTRL_EDITBOX:
+ macctrl_editbox(mcs, window, &pos, ctrl);
+ break;
+ case CTRL_RADIO:
+ macctrl_radio(mcs, window, &pos, ctrl);
+ break;
+ case CTRL_CHECKBOX:
+ macctrl_checkbox(mcs, window, &pos, ctrl);
+ break;
+ case CTRL_BUTTON:
+ macctrl_button(mcs, window, &pos, ctrl);
+ break;
+ case CTRL_LISTBOX:
+ if (ctrl->listbox.height == 0)
+ macctrl_popup(mcs, window, &pos, ctrl);
+ else
+ macctrl_listbox(mcs, window, &pos, ctrl);
+ break;
+ }
+ for (j = colstart; j < colstart + colspan; j++)
+ cols[j].pos.v = pos.pos.v;
+ }
+ }
+ for (j = 0; j < ncols; j++)
+ if (cols[j].pos.v > curstate->pos.v)
+ curstate->pos.v = cols[j].pos.v;
+
+ if (s->boxname && *s->boxname) {
+ union control *ctrl = snew(union control);
+ /* We're coming out of a box, so set the width back */
+ curstate->pos.h -= 12;
+ curstate->width += 24;
+ /* And draw the box to the original width */
+ macctrl_groupbox(mcs, window, curstate, ctrl);
+ }
+}
+
+static void macctrl_hideshowpanel(struct macctrls *mcs, unsigned int panel,
+ int showit)
+{
+ union macctrl *mc;
+ int j;
+
+#define hideshow(c) do { \
+ if (showit) ShowControl(c); else HideControl(c); \
+} while (0)
+
+ for (mc = mcs->panels[panel]; mc != NULL; mc = mc->generic.next) {
+#if !TARGET_API_MAC_CARBON
+ if (mcs->focus == mc)
+ macctrl_setfocus(mcs, NULL);
+#endif
+ switch (mc->generic.type) {
+ case MACCTRL_TEXT:
+ hideshow(mc->text.tbctrl);
+ break;
+ case MACCTRL_EDITBOX:
+ hideshow(mc->editbox.tbctrl);
+ if (mc->editbox.tblabel != NULL)
+ hideshow(mc->editbox.tblabel);
+ if (mc->editbox.tbbutton != NULL)
+ hideshow(mc->editbox.tbbutton);
+ break;
+ case MACCTRL_RADIO:
+ for (j = 0; j < mc->generic.ctrl->radio.nbuttons; j++)
+ hideshow(mc->radio.tbctrls[j]);
+ if (mc->radio.tblabel != NULL)
+ hideshow(mc->radio.tblabel);
+ break;
+ case MACCTRL_CHECKBOX:
+ hideshow(mc->checkbox.tbctrl);
+ break;
+ case MACCTRL_BUTTON:
+ hideshow(mc->button.tbctrl);
+ if (mc->button.tbring != NULL)
+ hideshow(mc->button.tbring);
+ break;
+ case MACCTRL_LISTBOX:
+ hideshow(mc->listbox.tbctrl);
+ if (mc->listbox.tbup != NULL)
+ hideshow(mc->listbox.tbup);
+ if (mc->listbox.tbdown != NULL)
+ hideshow(mc->listbox.tbdown);
+ /*
+ * At least under Mac OS 8.1, hiding a list box
+ * doesn't hide its scroll bars.
+ */
+#if TARGET_API_MAC_CARBON
+ hideshow(GetListVerticalScrollBar(mc->listbox.list));
+#else
+ hideshow((*mc->listbox.list)->vScroll);
+#endif
+ break;
+ case MACCTRL_POPUP:
+ hideshow(mc->popup.tbctrl);
+ break;
+ case MACCTRL_GROUPBOX:
+ hideshow(mc->groupbox.tbctrl);
+ break;
+ }
+ }
+}
+
+static void macctrl_switchtopanel(struct macctrls *mcs, unsigned int which)
+{
+
+ macctrl_hideshowpanel(mcs, mcs->curpanel, FALSE);
+ macctrl_hideshowpanel(mcs, which, TRUE);
+ mcs->curpanel = which;
+}
+
+#if !TARGET_API_MAC_CARBON
+/*
+ * System 7 focus manipulation
+ */
+static void macctrl_defocus(union macctrl *mc)
+{
+
+ assert(mac_gestalts.apprvers < 0x100);
+ switch (mc->generic.type) {
+ case MACCTRL_EDITBOX:
+ TEDeactivate((TEHandle)(*mc->editbox.tbctrl)->contrlData);
+ break;
+ }
+}
+
+static void macctrl_enfocus(union macctrl *mc)
+{
+
+ assert(mac_gestalts.apprvers < 0x100);
+ switch (mc->generic.type) {
+ case MACCTRL_EDITBOX:
+ TEActivate((TEHandle)(*mc->editbox.tbctrl)->contrlData);
+ break;
+ }
+}
+
+static void macctrl_setfocus(struct macctrls *mcs, union macctrl *mc)
+{
+
+ if (mcs->focus == mc)
+ return;
+ if (mcs->focus != NULL)
+ macctrl_defocus(mcs->focus);
+ mcs->focus = mc;
+ if (mc != NULL)
+ macctrl_enfocus(mc);
+}
+#endif
+
+static void macctrl_text(struct macctrls *mcs, WindowPtr window,
+ struct mac_layoutstate *curstate,
+ union control *ctrl)
+{
+ union macctrl *mc = snew(union macctrl);
+ Rect bounds;
+ SInt16 height;
+
+ assert(ctrl->text.label != NULL);
+ mc->generic.type = MACCTRL_TEXT;
+ mc->generic.ctrl = ctrl;
+ mc->generic.privdata = NULL;
+ bounds.left = curstate->pos.h;
+ bounds.right = bounds.left + curstate->width;
+ bounds.top = curstate->pos.v;
+ bounds.bottom = bounds.top + 16;
+ if (mac_gestalts.apprvers >= 0x100) {
+ Size olen;
+
+ mc->text.tbctrl = NewControl(window, &bounds, NULL, FALSE, 0, 0, 0,
+ kControlStaticTextProc, (long)mc);
+ SetControlData(mc->text.tbctrl, kControlEntireControl,
+ kControlStaticTextTextTag,
+ strlen(ctrl->text.label), ctrl->text.label);
+ GetControlData(mc->text.tbctrl, kControlEntireControl,
+ kControlStaticTextTextHeightTag,
+ sizeof(height), &height, &olen);
+ }
+#if !TARGET_API_MAC_CARBON
+ else {
+ TEHandle te;
+
+ mc->text.tbctrl = NewControl(window, &bounds, NULL, FALSE, 0, 0, 0,
+ SYS7_TEXT_PROC, (long)mc);
+ te = (TEHandle)(*mc->text.tbctrl)->contrlData;
+ TESetText(ctrl->text.label, strlen(ctrl->text.label), te);
+ height = TEGetHeight(1, (*te)->nLines, te);
+ }
+#endif
+ SizeControl(mc->text.tbctrl, curstate->width, height);
+ curstate->pos.v += height + 6;
+ add234(mcs->byctrl, mc);
+ mc->generic.next = mcs->panels[curstate->panelnum];
+ mcs->panels[curstate->panelnum] = mc;
+}
+
+static void macctrl_editbox(struct macctrls *mcs, WindowPtr window,
+ struct mac_layoutstate *curstate,
+ union control *ctrl)
+{
+ union macctrl *mc = snew(union macctrl);
+ Rect lbounds, bounds, butbounds;
+ static int nextmenuid = MENU_MIN;
+ int menuid;
+ MenuRef menu;
+
+ mc->generic.type = MACCTRL_EDITBOX;
+ mc->generic.ctrl = ctrl;
+ mc->generic.privdata = NULL;
+ lbounds.left = curstate->pos.h;
+ lbounds.top = curstate->pos.v;
+ if (ctrl->editbox.percentwidth == 100) {
+ if (ctrl->editbox.label != NULL) {
+ lbounds.right = lbounds.left + curstate->width;
+ lbounds.bottom = lbounds.top + 16;
+ curstate->pos.v += 18;
+ }
+ bounds.left = curstate->pos.h;
+ bounds.right = bounds.left + curstate->width;
+ } else {
+ lbounds.right = lbounds.left +
+ curstate->width * (100 - ctrl->editbox.percentwidth) / 100;
+ lbounds.bottom = lbounds.top + 22;
+ bounds.left = lbounds.right;
+ bounds.right = lbounds.left + curstate->width;
+ }
+ bounds.top = curstate->pos.v;
+ bounds.bottom = bounds.top + 22;
+
+ if (ctrl->editbox.has_list) {
+ butbounds = bounds;
+ butbounds.left = butbounds.right - 20;
+ bounds.right -= 26; /* enough for 6 px gap and a button */
+ }
+
+ if (mac_gestalts.apprvers >= 0x100) {
+ if (ctrl->editbox.label == NULL)
+ mc->editbox.tblabel = NULL;
+ else {
+ mc->editbox.tblabel = NewControl(window, &lbounds, NULL, FALSE,
+ 0, 0, 0, kControlStaticTextProc,
+ (long)mc);
+ SetControlData(mc->editbox.tblabel, kControlEntireControl,
+ kControlStaticTextTextTag,
+ strlen(ctrl->editbox.label), ctrl->editbox.label);
+ }
+ InsetRect(&bounds, 3, 3);
+ mc->editbox.tbctrl = NewControl(window, &bounds, NULL, FALSE, 0, 0, 0,
+ ctrl->editbox.password ?
+ kControlEditTextPasswordProc :
+ kControlEditTextProc, (long)mc);
+ }
+#if !TARGET_API_MAC_CARBON
+ else {
+ if (ctrl->editbox.label == NULL)
+ mc->editbox.tblabel = NULL;
+ else {
+ mc->editbox.tblabel = NewControl(window, &lbounds, NULL, FALSE,
+ 0, 0, 0, SYS7_TEXT_PROC,
+ (long)mc);
+ TESetText(ctrl->editbox.label, strlen(ctrl->editbox.label),
+ (TEHandle)(*mc->editbox.tblabel)->contrlData);
+ }
+ mc->editbox.tbctrl = NewControl(window, &bounds, NULL, FALSE, 0, 0, 0,
+ SYS7_EDITBOX_PROC, (long)mc);
+ }
+#endif
+
+ if (ctrl->editbox.has_list) {
+ while (GetMenuHandle(nextmenuid) != NULL)
+ if (++nextmenuid >= MENU_MAX) nextmenuid = MENU_MIN;
+ menuid = nextmenuid++;
+ menu = NewMenu(menuid, "\pdummy");
+ if (menu == NULL) goto nomenu;
+ mc->editbox.menu = menu;
+ mc->editbox.menuid = menuid;
+ InsertMenu(menu, kInsertHierarchicalMenu);
+ mc->editbox.nids = 0;
+ mc->editbox.ids = NULL;
+
+ mc->editbox.tbbutton = NewControl(window, &butbounds, NULL, FALSE,
+ popupTitleLeftJust, menuid, 0,
+ popupMenuProc + popupFixedWidth,
+ (long)mc);
+ }
+
+ nomenu:
+
+ curstate->pos.v += 28;
+ add234(mcs->byctrl, mc);
+ mc->generic.next = mcs->panels[curstate->panelnum];
+ mcs->panels[curstate->panelnum] = mc;
+ ctrlevent(mcs, mc, EVENT_REFRESH);
+}
+
+#if !TARGET_API_MAC_CARBON
+static pascal SInt32 macctrl_sys7_editbox_cdef(SInt16 variant,
+ ControlRef control,
+ ControlDefProcMessage msg,
+ SInt32 param)
+{
+ RgnHandle rgn;
+ Rect rect;
+ TEHandle te;
+ long ssfs;
+ Point mouse;
+
+ switch (msg) {
+ case initCntl:
+ rect = (*control)->contrlRect;
+ if (variant == SYS7_EDITBOX_VARIANT)
+ InsetRect(&rect, 3, 3); /* 2 if it's 20 pixels high */
+ te = TENew(&rect, &rect);
+ ssfs = GetScriptVariable(smSystemScript, smScriptSysFondSize);
+ (*te)->txSize = LoWord(ssfs);
+ (*te)->txFont = HiWord(ssfs);
+ (*control)->contrlData = (Handle)te;
+ return noErr;
+ case dispCntl:
+ TEDispose((TEHandle)(*control)->contrlData);
+ return 0;
+ case drawCntl:
+ if ((*control)->contrlVis) {
+ rect = (*control)->contrlRect;
+ if (variant == SYS7_EDITBOX_VARIANT) {
+ PenNormal();
+ FrameRect(&rect);
+ InsetRect(&rect, 3, 3);
+ }
+ EraseRect(&rect);
+ (*(TEHandle)(*control)->contrlData)->viewRect = rect;
+ TEUpdate(&rect, (TEHandle)(*control)->contrlData);
+ }
+ return 0;
+ case testCntl:
+ if (variant == SYS7_TEXT_VARIANT)
+ return kControlNoPart;
+ mouse.h = LoWord(param);
+ mouse.v = HiWord(param);
+ rect = (*control)->contrlRect;
+ InsetRect(&rect, 3, 3);
+ return PtInRect(mouse, &rect) ? kControlEditTextPart : kControlNoPart;
+ case calcCRgns:
+ if (param & (1 << 31)) {
+ param &= ~(1 << 31);
+ goto calcthumbrgn;
+ }
+ /* FALLTHROUGH */
+ case calcCntlRgn:
+ rgn = (RgnHandle)param;
+ RectRgn(rgn, &(*control)->contrlRect);
+ return 0;
+ case calcThumbRgn:
+ calcthumbrgn:
+ rgn = (RgnHandle)param;
+ SetEmptyRgn(rgn);
+ return 0;
+ }
+
+ return 0;
+}
+#endif
+
+static void macctrl_radio(struct macctrls *mcs, WindowPtr window,
+ struct mac_layoutstate *curstate,
+ union control *ctrl)
+{
+ union macctrl *mc = snew(union macctrl);
+ Rect bounds;
+ Str255 title;
+ unsigned int i, colwidth;
+
+ mc->generic.type = MACCTRL_RADIO;
+ mc->generic.ctrl = ctrl;
+ mc->generic.privdata = NULL;
+ mc->radio.tbctrls = snewn(ctrl->radio.nbuttons, ControlRef);
+ colwidth = (curstate->width + 13) / ctrl->radio.ncolumns;
+ bounds.top = curstate->pos.v;
+ bounds.bottom = bounds.top + 16;
+ bounds.left = curstate->pos.h;
+ bounds.right = bounds.left + curstate->width;
+ if (ctrl->radio.label == NULL)
+ mc->radio.tblabel = NULL;
+ else {
+ if (mac_gestalts.apprvers >= 0x100) {
+ mc->radio.tblabel = NewControl(window, &bounds, NULL, FALSE,
+ 0, 0, 0, kControlStaticTextProc,
+ (long)mc);
+ SetControlData(mc->radio.tblabel, kControlEntireControl,
+ kControlStaticTextTextTag,
+ strlen(ctrl->radio.label), ctrl->radio.label);
+ }
+#if !TARGET_API_MAC_CARBON
+ else {
+ mc->radio.tblabel = NewControl(window, &bounds, NULL, FALSE,
+ 0, 0, 0, SYS7_TEXT_PROC, (long)mc);
+ TESetText(ctrl->radio.label, strlen(ctrl->radio.label),
+ (TEHandle)(*mc->radio.tblabel)->contrlData);
+ }
+#endif
+ curstate->pos.v += 18;
+ }
+ for (i = 0; i < ctrl->radio.nbuttons; i++) {
+ bounds.top = curstate->pos.v - 2;
+ bounds.bottom = bounds.top + 18;
+ bounds.left = curstate->pos.h + colwidth * (i % ctrl->radio.ncolumns);
+ if (i == ctrl->radio.nbuttons - 1 ||
+ i % ctrl->radio.ncolumns == ctrl->radio.ncolumns - 1) {
+ bounds.right = curstate->pos.h + curstate->width;
+ curstate->pos.v += 18;
+ } else
+ bounds.right = bounds.left + colwidth - 13;
+ c2pstrcpy(title, ctrl->radio.buttons[i]);
+ mc->radio.tbctrls[i] = NewControl(window, &bounds, title, FALSE,
+ 0, 0, 1, radioButProc, (long)mc);
+ }
+ curstate->pos.v += 4;
+ add234(mcs->byctrl, mc);
+ mc->generic.next = mcs->panels[curstate->panelnum];
+ mcs->panels[curstate->panelnum] = mc;
+ ctrlevent(mcs, mc, EVENT_REFRESH);
+}
+
+static void macctrl_checkbox(struct macctrls *mcs, WindowPtr window,
+ struct mac_layoutstate *curstate,
+ union control *ctrl)
+{
+ union macctrl *mc = snew(union macctrl);
+ Rect bounds;
+ Str255 title;
+
+ assert(ctrl->checkbox.label != NULL);
+ mc->generic.type = MACCTRL_CHECKBOX;
+ mc->generic.ctrl = ctrl;
+ mc->generic.privdata = NULL;
+ bounds.left = curstate->pos.h;
+ bounds.right = bounds.left + curstate->width;
+ bounds.top = curstate->pos.v;
+ bounds.bottom = bounds.top + 16;
+ c2pstrcpy(title, ctrl->checkbox.label);
+ mc->checkbox.tbctrl = NewControl(window, &bounds, title, FALSE, 0, 0, 1,
+ checkBoxProc, (long)mc);
+ add234(mcs->byctrl, mc);
+ curstate->pos.v += 22;
+ mc->generic.next = mcs->panels[curstate->panelnum];
+ mcs->panels[curstate->panelnum] = mc;
+ ctrlevent(mcs, mc, EVENT_REFRESH);
+}
+
+static void macctrl_button(struct macctrls *mcs, WindowPtr window,
+ struct mac_layoutstate *curstate,
+ union control *ctrl)
+{
+ union macctrl *mc = snew(union macctrl);
+ Rect bounds;
+ Str255 title;
+
+ assert(ctrl->button.label != NULL);
+ mc->generic.type = MACCTRL_BUTTON;
+ mc->generic.ctrl = ctrl;
+ mc->generic.privdata = NULL;
+ bounds.left = curstate->pos.h;
+ bounds.right = bounds.left + curstate->width;
+ bounds.top = curstate->pos.v;
+ bounds.bottom = bounds.top + 20;
+ c2pstrcpy(title, ctrl->button.label);
+ mc->button.tbctrl = NewControl(window, &bounds, title, FALSE, 0, 0, 1,
+ pushButProc, (long)mc);
+ mc->button.tbring = NULL;
+ if (mac_gestalts.apprvers >= 0x100) {
+ Boolean isdefault = ctrl->button.isdefault;
+
+ SetControlData(mc->button.tbctrl, kControlEntireControl,
+ kControlPushButtonDefaultTag,
+ sizeof(isdefault), &isdefault);
+ } else if (ctrl->button.isdefault) {
+ InsetRect(&bounds, -4, -4);
+ mc->button.tbring = NewControl(window, &bounds, title, FALSE, 0, 0, 1,
+ SYS7_DEFAULT_PROC, (long)mc);
+ }
+ if (mac_gestalts.apprvers >= 0x110) {
+ Boolean iscancel = ctrl->button.iscancel;
+
+ SetControlData(mc->button.tbctrl, kControlEntireControl,
+ kControlPushButtonCancelTag,
+ sizeof(iscancel), &iscancel);
+ }
+ if (ctrl->button.isdefault)
+ mcs->defbutton = mc;
+ if (ctrl->button.iscancel)
+ mcs->canbutton = mc;
+ add234(mcs->byctrl, mc);
+ mc->generic.next = mcs->panels[curstate->panelnum];
+ mcs->panels[curstate->panelnum] = mc;
+ curstate->pos.v += 26;
+}
+
+#if !TARGET_API_MAC_CARBON
+static pascal SInt32 macctrl_sys7_default_cdef(SInt16 variant,
+ ControlRef control,
+ ControlDefProcMessage msg,
+ SInt32 param)
+{
+ RgnHandle rgn;
+ Rect rect;
+ int oval;
+ PenState savestate;
+
+ switch (msg) {
+ case drawCntl:
+ if ((*control)->contrlVis) {
+ rect = (*control)->contrlRect;
+ GetPenState(&savestate);
+ PenNormal();
+ PenSize(3, 3);
+ if ((*control)->contrlHilite == kControlInactivePart)
+ PenPat(&qd.gray);
+ oval = (rect.bottom - rect.top) / 2 + 2;
+ FrameRoundRect(&rect, oval, oval);
+ SetPenState(&savestate);
+ }
+ return 0;
+ case calcCRgns:
+ if (param & (1 << 31)) {
+ param &= ~(1 << 31);
+ goto calcthumbrgn;
+ }
+ /* FALLTHROUGH */
+ case calcCntlRgn:
+ rgn = (RgnHandle)param;
+ RectRgn(rgn, &(*control)->contrlRect);
+ return 0;
+ case calcThumbRgn:
+ calcthumbrgn:
+ rgn = (RgnHandle)param;
+ SetEmptyRgn(rgn);
+ return 0;
+ }
+
+ return 0;
+}
+#endif
+
+static void macctrl_listbox(struct macctrls *mcs, WindowPtr window,
+ struct mac_layoutstate *curstate,
+ union control *ctrl)
+{
+ union macctrl *mc = snew(union macctrl);
+ Rect bounds, upbounds, downbounds;
+ Size olen;
+
+ /* XXX Use label */
+ assert(ctrl->listbox.percentwidth == 100);
+ mc->generic.type = MACCTRL_LISTBOX;
+ mc->generic.ctrl = ctrl;
+ mc->generic.privdata = NULL;
+ /* The list starts off empty */
+ mc->listbox.nids = 0;
+ mc->listbox.ids = NULL;
+ bounds.left = curstate->pos.h;
+ bounds.right = bounds.left + curstate->width;
+ bounds.top = curstate->pos.v;
+ bounds.bottom = bounds.top + 16 * ctrl->listbox.height + 2;
+
+ if (ctrl->listbox.draglist) {
+ upbounds = downbounds = bounds;
+ upbounds.left = upbounds.right - 58;
+ upbounds.bottom = upbounds.top + 20;
+ downbounds.left = downbounds.right - 58;
+ downbounds.top = upbounds.bottom + 6;
+ downbounds.bottom = downbounds.top + 20;
+ bounds.right -= 64; /* enough for 6 px gap and a button */
+ }
+
+ if (mac_gestalts.apprvers >= 0x100) {
+ InsetRect(&bounds, 3, 3);
+ mc->listbox.tbctrl = NewControl(window, &bounds, NULL, FALSE,
+ ldes_Default, 0, 0,
+ kControlListBoxProc, (long)mc);
+ if (GetControlData(mc->listbox.tbctrl, kControlEntireControl,
+ kControlListBoxListHandleTag,
+ sizeof(mc->listbox.list), &mc->listbox.list,
+ &olen) != noErr) {
+ DisposeControl(mc->listbox.tbctrl);
+ sfree(mc);
+ return;
+ }
+ }
+#if !TARGET_API_MAC_CARBON
+ else {
+ InsetRect(&bounds, -3, -3);
+ mc->listbox.tbctrl = NewControl(window, &bounds, NULL, FALSE,
+ 0, 0, 0,
+ SYS7_LISTBOX_PROC, (long)mc);
+ mc->listbox.list = (ListHandle)(*mc->listbox.tbctrl)->contrlData;
+ (*mc->listbox.list)->refCon = (long)mc;
+ }
+#endif
+ if (!ctrl->listbox.multisel) {
+#if TARGET_API_MAC_CARBON
+ SetListSelectionFlags(mc->listbox.list, lOnlyOne);
+#else
+ (*mc->listbox.list)->selFlags = lOnlyOne;
+#endif
+ }
+
+ if (ctrl->listbox.draglist) {
+ mc->listbox.tbup = NewControl(window, &upbounds, "\pUp", FALSE, 0, 0, 1,
+ pushButProc, (long)mc);
+ mc->listbox.tbdown = NewControl(window, &downbounds, "\pDown", FALSE, 0, 0, 1,
+ pushButProc, (long)mc);
+ }
+
+ add234(mcs->byctrl, mc);
+ curstate->pos.v += 6 + 16 * ctrl->listbox.height + 2;
+ mc->generic.next = mcs->panels[curstate->panelnum];
+ mcs->panels[curstate->panelnum] = mc;
+ ctrlevent(mcs, mc, EVENT_REFRESH);
+#if TARGET_API_MAC_CARBON
+ HideControl(GetListVerticalScrollBar(mc->listbox.list));
+#else
+ HideControl((*mc->listbox.list)->vScroll);
+#endif
+}
+
+#if !TARGET_API_MAC_CARBON
+static pascal SInt32 macctrl_sys7_listbox_cdef(SInt16 variant,
+ ControlRef control,
+ ControlDefProcMessage msg,
+ SInt32 param)
+{
+ RgnHandle rgn;
+ Rect rect;
+ ListHandle list;
+ long ssfs;
+ Point mouse;
+ ListBounds bounds;
+ Point csize;
+ short savefont;
+ short savesize;
+ GrafPtr curport;
+
+ switch (msg) {
+ case initCntl:
+ rect = (*control)->contrlRect;
+ InsetRect(&rect, 4, 4);
+ rect.right -= 15; /* scroll bar */
+ bounds.top = bounds.bottom = bounds.left = 0;
+ bounds.right = 1;
+ csize.h = csize.v = 0;
+ GetPort(&curport);
+ savefont = curport->txFont;
+ savesize = curport->txSize;
+ ssfs = GetScriptVariable(smSystemScript, smScriptSysFondSize);
+ TextFont(HiWord(ssfs));
+ TextSize(LoWord(ssfs));
+ list = LNew(&rect, &bounds, csize, 0, (*control)->contrlOwner,
+ TRUE, FALSE, FALSE, TRUE);
+ SetControlReference((*list)->vScroll, (long)list);
+ (*control)->contrlData = (Handle)list;
+ TextFont(savefont);
+ TextSize(savesize);
+ return noErr;
+ case dispCntl:
+ /*
+ * If the dialogue box is being destroyed, the scroll bar
+ * might have gone already. In our situation, this is the
+ * only time we destroy a control, so NULL out the scroll bar
+ * handle to prevent LDispose trying to free it.
+ */
+ list = (ListHandle)(*control)->contrlData;
+ (*list)->vScroll = NULL;
+ LDispose(list);
+ return 0;
+ case drawCntl:
+ if ((*control)->contrlVis) {
+ rect = (*control)->contrlRect;
+ /* XXX input focus highlighting? */
+ InsetRect(&rect, 3, 3);
+ PenNormal();
+ FrameRect(&rect);
+ list = (ListHandle)(*control)->contrlData;
+ LActivate((*control)->contrlHilite != kControlInactivePart, list);
+ GetPort(&curport);
+ LUpdate(curport->visRgn, list);
+ }
+ return 0;
+ case testCntl:
+ mouse.h = LoWord(param);
+ mouse.v = HiWord(param);
+ rect = (*control)->contrlRect;
+ InsetRect(&rect, 4, 4);
+ /*
+ * We deliberately exclude the scrollbar so that LClick() can see it.
+ */
+ rect.right -= 15;
+ return PtInRect(mouse, &rect) ? kControlListBoxPart : kControlNoPart;
+ case calcCRgns:
+ if (param & (1 << 31)) {
+ param &= ~(1 << 31);
+ goto calcthumbrgn;
+ }
+ /* FALLTHROUGH */
+ case calcCntlRgn:
+ rgn = (RgnHandle)param;
+ RectRgn(rgn, &(*control)->contrlRect);
+ return 0;
+ case calcThumbRgn:
+ calcthumbrgn:
+ rgn = (RgnHandle)param;
+ SetEmptyRgn(rgn);
+ return 0;
+ }
+
+ return 0;
+}
+#endif
+
+#if !TARGET_API_MAC_CARBON
+static pascal SInt32 macctrl_sys7_groupbox_cdef(SInt16 variant,
+ ControlRef control,
+ ControlDefProcMessage msg,
+ SInt32 param)
+{
+ RgnHandle rgn;
+ Rect rect;
+ PenState savestate;
+
+ switch (msg) {
+ case drawCntl:
+ if ((*control)->contrlVis) {
+ rect = (*control)->contrlRect;
+ GetPenState(&savestate);
+ PenNormal();
+ PenSize(3, 3);
+ PenPat(&qd.gray);
+ FrameRect(&rect);
+ SetPenState(&savestate);
+ }
+ return 0;
+ case calcCRgns:
+ if (param & (1 << 31)) {
+ param &= ~(1 << 31);
+ goto calcthumbrgn;
+ }
+ /* FALLTHROUGH */
+ case calcCntlRgn:
+ rgn = (RgnHandle)param;
+ RectRgn(rgn, &(*control)->contrlRect);
+ return 0;
+ case calcThumbRgn:
+ calcthumbrgn:
+ rgn = (RgnHandle)param;
+ SetEmptyRgn(rgn);
+ return 0;
+ }
+ return 0;
+}
+#endif
+
+static void macctrl_popup(struct macctrls *mcs, WindowPtr window,
+ struct mac_layoutstate *curstate,
+ union control *ctrl)
+{
+ union macctrl *mc = snew(union macctrl);
+ Rect bounds;
+ Str255 title;
+ unsigned int labelwidth;
+ static int nextmenuid = MENU_MIN;
+ int menuid;
+ MenuRef menu;
+
+ /*
+ * explains how to
+ * create a popup menu with dynamic content.
+ */
+ assert(ctrl->listbox.height == 0);
+ assert(!ctrl->listbox.draglist);
+ assert(!ctrl->listbox.multisel);
+
+ mc->generic.type = MACCTRL_POPUP;
+ mc->generic.ctrl = ctrl;
+ mc->generic.privdata = NULL;
+ c2pstrcpy(title, ctrl->button.label == NULL ? "" : ctrl->button.label);
+
+ /* Find a spare menu ID and create the menu */
+ while (GetMenuHandle(nextmenuid) != NULL)
+ if (++nextmenuid >= MENU_MAX) nextmenuid = MENU_MIN;
+ menuid = nextmenuid++;
+ menu = NewMenu(menuid, "\pdummy");
+ if (menu == NULL) return;
+ mc->popup.menu = menu;
+ mc->popup.menuid = menuid;
+ InsertMenu(menu, kInsertHierarchicalMenu);
+
+ /* The menu starts off empty */
+ mc->popup.nids = 0;
+ mc->popup.ids = NULL;
+
+ bounds.left = curstate->pos.h;
+ bounds.right = bounds.left + curstate->width;
+ bounds.top = curstate->pos.v;
+ bounds.bottom = bounds.top + 20;
+ /* XXX handle percentwidth == 100 */
+ labelwidth = curstate->width * (100 - ctrl->listbox.percentwidth) / 100;
+ mc->popup.tbctrl = NewControl(window, &bounds, title, FALSE,
+ popupTitleLeftJust, menuid, labelwidth,
+ popupMenuProc + popupFixedWidth, (long)mc);
+ add234(mcs->byctrl, mc);
+ curstate->pos.v += 26;
+ mc->generic.next = mcs->panels[curstate->panelnum];
+ mcs->panels[curstate->panelnum] = mc;
+ ctrlevent(mcs, mc, EVENT_REFRESH);
+}
+
+static void macctrl_groupbox(struct macctrls *mcs, WindowPtr window,
+ struct mac_layoutstate *curstate,
+ union control *ctrl)
+{
+ union macctrl *mc = snew (union macctrl);
+ Str255 ptitle;
+ Rect r;
+
+ r.top = curstate->boxpos.v;
+ r.left = curstate->boxpos.h;
+ r.bottom = curstate->pos.v;
+ r.right = curstate->boxpos.h + curstate->width;
+
+ mc->generic.type = MACCTRL_GROUPBOX;
+ mc->generic.privdata = NULL;
+ mc->generic.ctrl = ctrl;
+ mc->generic.ctrl->generic.handler = NULL;
+
+ if (curstate->boxname)
+ c2pstrcpy(ptitle, curstate->boxname);
+ else
+ c2pstrcpy(ptitle, "");
+ if (mac_gestalts.apprvers >= 0x100) { /* Appearance Manager */
+ mc->groupbox.tbctrl = NewControl(window, &r, ptitle, FALSE, 0, 0, 1,
+ kControlGroupBoxTextTitleProc, (long)mc);
+ } else {
+ mc->groupbox.tbctrl = NewControl(window, &r, ptitle, FALSE, 0, 0, 1,
+ SYS7_GROUPBOX_PROC, (long)mc);
+ }
+ add234(mcs->byctrl, mc);
+ mc->generic.next = mcs->panels[curstate->panelnum];
+ mcs->panels[curstate->panelnum] = mc;
+}
+
+void macctrl_activate(WindowPtr window, EventRecord *event)
+{
+ struct macctrls *mcs = mac_winctrls(window);
+ Boolean active = (event->modifiers & activeFlag) != 0;
+ GrafPtr saveport;
+ int i, j;
+ ControlPartCode state;
+ union macctrl *mc;
+
+ GetPort(&saveport);
+ SetPort((GrafPtr)GetWindowPort(window));
+ if (mac_gestalts.apprvers >= 0x100)
+ SetThemeWindowBackground(window, active ?
+ kThemeBrushModelessDialogBackgroundActive :
+ kThemeBrushModelessDialogBackgroundInactive,
+ TRUE);
+ state = active ? kControlNoPart : kControlInactivePart;
+ for (i = 0; i <= mcs->curpanel; i += mcs->curpanel)
+ for (mc = mcs->panels[i]; mc != NULL; mc = mc->generic.next) {
+ switch (mc->generic.type) {
+ case MACCTRL_TEXT:
+ HiliteControl(mc->text.tbctrl, state);
+ break;
+ case MACCTRL_EDITBOX:
+ HiliteControl(mc->editbox.tbctrl, state);
+ if (mc->editbox.tblabel != NULL)
+ HiliteControl(mc->editbox.tblabel, state);
+ if (mc->editbox.tbbutton != NULL)
+ HiliteControl(mc->editbox.tbbutton, state);
+ break;
+ case MACCTRL_RADIO:
+ for (j = 0; j < mc->generic.ctrl->radio.nbuttons; j++)
+ HiliteControl(mc->radio.tbctrls[j], state);
+ if (mc->radio.tblabel != NULL)
+ HiliteControl(mc->radio.tblabel, state);
+ break;
+ case MACCTRL_CHECKBOX:
+ HiliteControl(mc->checkbox.tbctrl, state);
+ break;
+ case MACCTRL_BUTTON:
+ HiliteControl(mc->button.tbctrl, state);
+ if (mc->button.tbring != NULL)
+ HiliteControl(mc->button.tbring, state);
+ break;
+ case MACCTRL_LISTBOX:
+ HiliteControl(mc->listbox.tbctrl, state);
+ if (mc->listbox.tbup != NULL)
+ HiliteControl(mc->listbox.tbup, state);
+ if (mc->listbox.tbdown != NULL)
+ HiliteControl(mc->listbox.tbdown, state);
+ break;
+ case MACCTRL_POPUP:
+ HiliteControl(mc->popup.tbctrl, state);
+ break;
+ case MACCTRL_GROUPBOX:
+ HiliteControl(mc->popup.tbctrl, state);
+ }
+#if !TARGET_API_MAC_CARBON
+ if (mcs->focus == mc) {
+ if (active)
+ macctrl_enfocus(mc);
+ else
+ macctrl_defocus(mc);
+ }
+#endif
+ }
+ SetPort(saveport);
+}
+
+void macctrl_click(WindowPtr window, EventRecord *event)
+{
+ Point mouse;
+ ControlHandle control, oldfocus;
+ int part, trackresult;
+ GrafPtr saveport;
+ union macctrl *mc;
+ struct macctrls *mcs = mac_winctrls(window);
+ int i;
+ UInt32 features;
+
+ GetPort(&saveport);
+ SetPort((GrafPtr)GetWindowPort(window));
+ mouse = event->where;
+ GlobalToLocal(&mouse);
+ part = FindControl(mouse, window, &control);
+ if (control != NULL) {
+#if !TARGET_API_MAC_CARBON
+ /*
+ * Special magic for scroll bars in list boxes, whose refcon
+ * is the list.
+ */
+ if (part == kControlUpButtonPart || part == kControlDownButtonPart ||
+ part == kControlPageUpPart || part == kControlPageDownPart ||
+ part == kControlIndicatorPart)
+ mc = (union macctrl *)
+ (*(ListHandle)GetControlReference(control))->refCon;
+ else
+#endif
+ mc = (union macctrl *)GetControlReference(control);
+ if (mac_gestalts.apprvers >= 0x100) {
+ if (GetControlFeatures(control, &features) == noErr &&
+ (features & kControlSupportsFocus) &&
+ (features & kControlGetsFocusOnClick) &&
+ GetKeyboardFocus(window, &oldfocus) == noErr &&
+ control != oldfocus)
+ SetKeyboardFocus(window, control, part);
+ trackresult = HandleControlClick(control, mouse, event->modifiers,
+ (ControlActionUPP)-1);
+ } else {
+#if !TARGET_API_MAC_CARBON
+ if (mc->generic.type == MACCTRL_EDITBOX &&
+ control == mc->editbox.tbctrl) {
+ TEHandle te = (TEHandle)(*control)->contrlData;
+
+ macctrl_setfocus(mcs, mc);
+ TEClick(mouse, !!(event->modifiers & shiftKey), te);
+ goto done;
+ }
+ if (mc->generic.type == MACCTRL_EDITBOX &&
+ control == mc->editbox.tbbutton) {
+ dlg_editbox_set(mc->generic.ctrl, mcs,
+ cp_enumerate(dlg_listbox_index(mc->generic.ctrl, mcs)));
+ ctrlevent(mcs, mc, EVENT_VALCHANGE);
+ }
+ if (mc->generic.type == MACCTRL_LISTBOX &&
+ (control == mc->listbox.tbctrl ||
+ control == (*mc->listbox.list)->vScroll)) {
+
+ macctrl_setfocus(mcs, mc);
+ if (LClick(mouse, event->modifiers, mc->listbox.list))
+ /* double-click */
+ ctrlevent(mcs, mc, EVENT_ACTION);
+ else
+ ctrlevent(mcs, mc, EVENT_SELCHANGE);
+ goto done;
+ }
+ if (mc->generic.type == MACCTRL_LISTBOX &&
+ control == mc->listbox.tbup)
+ draglist_up(mc, mcs);
+ if (mc->generic.type == MACCTRL_LISTBOX &&
+ control == mc->listbox.tbdown)
+ draglist_down(mc, mcs);
+#endif
+ trackresult = TrackControl(control, mouse, (ControlActionUPP)-1);
+ }
+ switch (mc->generic.type) {
+ case MACCTRL_RADIO:
+ if (trackresult != 0) {
+ for (i = 0; i < mc->generic.ctrl->radio.nbuttons; i++)
+ if (mc->radio.tbctrls[i] == control)
+ SetControlValue(mc->radio.tbctrls[i],
+ kControlRadioButtonCheckedValue);
+ else
+ SetControlValue(mc->radio.tbctrls[i],
+ kControlRadioButtonUncheckedValue);
+ ctrlevent(mcs, mc, EVENT_VALCHANGE);
+ }
+ break;
+ case MACCTRL_CHECKBOX:
+ if (trackresult != 0) {
+ SetControlValue(control, !GetControlValue(control));
+ ctrlevent(mcs, mc, EVENT_VALCHANGE);
+ }
+ break;
+ case MACCTRL_BUTTON:
+ if (trackresult != 0)
+ ctrlevent(mcs, mc, EVENT_ACTION);
+ break;
+ case MACCTRL_EDITBOX:
+ if (control == mc->editbox.tbbutton) {
+ dlg_editbox_set(mc->generic.ctrl, mcs,
+ cp_enumerate(dlg_listbox_index(mc->generic.ctrl, mcs)));
+ ctrlevent(mcs, mc, EVENT_VALCHANGE);
+ }
+ break;
+ case MACCTRL_LISTBOX:
+ if (control == mc->listbox.tbup)
+ draglist_up(mc, mcs);
+ if (control == mc->listbox.tbdown)
+ draglist_down(mc, mcs);
+
+ /* FIXME spot double-click */
+ ctrlevent(mcs, mc, EVENT_SELCHANGE);
+ break;
+ case MACCTRL_POPUP:
+ ctrlevent(mcs, mc, EVENT_SELCHANGE);
+ break;
+ }
+ }
+ done:
+ SetPort(saveport);
+}
+
+void macctrl_key(WindowPtr window, EventRecord *event)
+{
+ ControlRef control;
+ struct macctrls *mcs = mac_winctrls(window);
+ union macctrl *mc;
+ unsigned long dummy;
+
+ switch (event->message & charCodeMask) {
+ case kEnterCharCode:
+ case kReturnCharCode:
+ if (mcs->defbutton != NULL) {
+ assert(mcs->defbutton->generic.type == MACCTRL_BUTTON);
+ HiliteControl(mcs->defbutton->button.tbctrl, kControlButtonPart);
+ /*
+ * I'd like to delay unhilighting the button until after
+ * the event has been processed, but by them the entire
+ * dialgue box might have been destroyed.
+ */
+ Delay(6, &dummy);
+ HiliteControl(mcs->defbutton->button.tbctrl, kControlNoPart);
+ ctrlevent(mcs, mcs->defbutton, EVENT_ACTION);
+ }
+ return;
+ case kEscapeCharCode:
+ if (mcs->canbutton != NULL) {
+ assert(mcs->canbutton->generic.type == MACCTRL_BUTTON);
+ HiliteControl(mcs->canbutton->button.tbctrl, kControlButtonPart);
+ Delay(6, &dummy);
+ HiliteControl(mcs->defbutton->button.tbctrl, kControlNoPart);
+ ctrlevent(mcs, mcs->canbutton, EVENT_ACTION);
+ }
+ return;
+ }
+ if (mac_gestalts.apprvers >= 0x100) {
+ if (GetKeyboardFocus(window, &control) == noErr && control != NULL) {
+ HandleControlKey(control, (event->message & keyCodeMask) >> 8,
+ event->message & charCodeMask, event->modifiers);
+ mc = (union macctrl *)GetControlReference(control);
+ switch (mc->generic.type) {
+ case MACCTRL_LISTBOX:
+ ctrlevent(mcs, mc, EVENT_SELCHANGE);
+ break;
+ default:
+ ctrlevent(mcs, mc, EVENT_VALCHANGE);
+ break;
+ }
+ }
+ }
+#if !TARGET_API_MAC_CARBON
+ else {
+ TEHandle te;
+
+ if (mcs->focus != NULL) {
+ mc = mcs->focus;
+ switch (mc->generic.type) {
+ case MACCTRL_EDITBOX:
+ te = (TEHandle)(*mc->editbox.tbctrl)->contrlData;
+ TEKey(event->message & charCodeMask, te);
+ ctrlevent(mcs, mc, EVENT_VALCHANGE);
+ break;
+ }
+ }
+ }
+#endif
+}
+
+void macctrl_update(WindowPtr window)
+{
+#if TARGET_API_MAC_CARBON
+ RgnHandle visrgn;
+#endif
+ Rect rect;
+ GrafPtr saveport;
+
+ BeginUpdate(window);
+ GetPort(&saveport);
+ SetPort((GrafPtr)GetWindowPort(window));
+ if (mac_gestalts.apprvers >= 0x101) {
+#if TARGET_API_MAC_CARBON
+ GetPortBounds(GetWindowPort(window), &rect);
+#else
+ rect = window->portRect;
+#endif
+ InsetRect(&rect, -1, -1);
+ DrawThemeModelessDialogFrame(&rect, mac_frontwindow() == window ?
+ kThemeStateActive : kThemeStateInactive);
+ }
+#if TARGET_API_MAC_CARBON
+ visrgn = NewRgn();
+ GetPortVisibleRegion(GetWindowPort(window), visrgn);
+ UpdateControls(window, visrgn);
+ DisposeRgn(visrgn);
+#else
+ UpdateControls(window, window->visRgn);
+#endif
+ SetPort(saveport);
+ EndUpdate(window);
+}
+
+#if TARGET_API_MAC_CARBON
+#define EnableItem EnableMenuItem
+#define DisableItem DisableMenuItem
+#endif
+void macctrl_adjustmenus(WindowPtr window)
+{
+ MenuHandle menu;
+
+ menu = GetMenuHandle(mFile);
+ DisableItem(menu, iSave); /* XXX enable if modified */
+ EnableItem(menu, iSaveAs);
+ EnableItem(menu, iDuplicate);
+
+ menu = GetMenuHandle(mEdit);
+ DisableItem(menu, 0);
+}
+
+void macctrl_close(WindowPtr window)
+{
+ struct macctrls *mcs = mac_winctrls(window);
+ union macctrl *mc;
+
+ /*
+ * Mostly, we don't bother disposing of the Toolbox controls,
+ * since that will happen automatically when the window is
+ * disposed of. Popup menus are an exception, because we have to
+ * dispose of the menu ourselves, and doing that while the control
+ * still holds a reference to it seems rude.
+ */
+ while ((mc = index234(mcs->byctrl, 0)) != NULL) {
+ if (mc->generic.privdata != NULL && mc->generic.freeprivdata)
+ sfree(mc->generic.privdata);
+ switch (mc->generic.type) {
+ case MACCTRL_POPUP:
+ DisposeControl(mc->popup.tbctrl);
+ DeleteMenu(mc->popup.menuid);
+ DisposeMenu(mc->popup.menu);
+ break;
+ }
+ del234(mcs->byctrl, mc);
+ sfree(mc);
+ }
+
+ freetree234(mcs->byctrl);
+ mcs->byctrl = NULL;
+ sfree(mcs->panels);
+ mcs->panels = NULL;
+}
+
+void dlg_update_start(union control *ctrl, void *dlg)
+{
+
+ /* No-op for now */
+}
+
+void dlg_update_done(union control *ctrl, void *dlg)
+{
+
+ /* No-op for now */
+}
+
+void dlg_set_focus(union control *ctrl, void *dlg)
+{
+
+ if (mac_gestalts.apprvers >= 0x100) {
+ /* Use SetKeyboardFocus() */
+ } else {
+ /* Do our own mucking around */
+ }
+}
+
+union control *dlg_last_focused(union control *ctrl, void *dlg)
+{
+
+ return NULL;
+}
+
+void dlg_beep(void *dlg)
+{
+
+ SysBeep(30);
+}
+
+void dlg_error_msg(void *dlg, char *msg)
+{
+ Str255 pmsg;
+
+ c2pstrcpy(pmsg, msg);
+ ParamText(pmsg, NULL, NULL, NULL);
+ StopAlert(128, NULL);
+}
+
+void dlg_end(void *dlg, int value)
+{
+ struct macctrls *mcs = dlg;
+
+ if (mcs->end != NULL)
+ (*mcs->end)(mcs->window, value);
+};
+
+void dlg_refresh(union control *ctrl, void *dlg)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc;
+ int i;
+
+ if (ctrl == NULL) {
+ /* NULL means refresh every control */
+ for (i = 0 ; i < mcs->npanels; i++) {
+ for (mc = mcs->panels[i]; mc != NULL; mc = mc->generic.next) {
+ ctrlevent(mcs, mc, EVENT_REFRESH);
+ }
+ }
+ return;
+ }
+ /* Just refresh a specific control */
+ mc = findbyctrl(mcs, ctrl);
+ assert(mc != NULL);
+ ctrlevent(mcs, mc, EVENT_REFRESH);
+};
+
+void *dlg_get_privdata(union control *ctrl, void *dlg)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ assert(mc != NULL);
+ return mc->generic.privdata;
+}
+
+void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ assert(mc != NULL);
+ mc->generic.privdata = ptr;
+ mc->generic.freeprivdata = FALSE;
+}
+
+void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ assert(mc != NULL);
+ mc->generic.privdata = smalloc(size);
+ mc->generic.freeprivdata = TRUE;
+ return mc->generic.privdata;
+}
+
+
+/*
+ * Radio Button control
+ */
+
+void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ int i;
+
+ if (mc == NULL) return;
+ for (i = 0; i < ctrl->radio.nbuttons; i++) {
+ if (i == whichbutton)
+ SetControlValue(mc->radio.tbctrls[i],
+ kControlRadioButtonCheckedValue);
+ else
+ SetControlValue(mc->radio.tbctrls[i],
+ kControlRadioButtonUncheckedValue);
+ }
+
+};
+
+int dlg_radiobutton_get(union control *ctrl, void *dlg)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ int i;
+
+ assert(mc != NULL);
+ for (i = 0; i < ctrl->radio.nbuttons; i++) {
+ if (GetControlValue(mc->radio.tbctrls[i]) ==
+ kControlRadioButtonCheckedValue)
+ return i;
+ }
+ return -1;
+};
+
+
+/*
+ * Check Box control
+ */
+
+void dlg_checkbox_set(union control *ctrl, void *dlg, int checked)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ if (mc == NULL) return;
+ SetControlValue(mc->checkbox.tbctrl,
+ checked ? kControlCheckBoxCheckedValue :
+ kControlCheckBoxUncheckedValue);
+}
+
+int dlg_checkbox_get(union control *ctrl, void *dlg)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ assert(mc != NULL);
+ return GetControlValue(mc->checkbox.tbctrl);
+}
+
+
+/*
+ * Edit Box control
+ */
+
+void dlg_editbox_set(union control *ctrl, void *dlg, char const *text)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ GrafPtr saveport;
+
+ if (mc == NULL) return;
+ assert(mc->generic.type == MACCTRL_EDITBOX);
+ GetPort(&saveport);
+ SetPort((GrafPtr)(GetWindowPort(mcs->window)));
+ if (mac_gestalts.apprvers >= 0x100)
+ SetControlData(mc->editbox.tbctrl, kControlEntireControl,
+ ctrl->editbox.password ?
+ kControlEditTextPasswordTag :
+ kControlEditTextTextTag,
+ strlen(text), text);
+#if !TARGET_API_MAC_CARBON
+ else
+ TESetText(text, strlen(text),
+ (TEHandle)(*mc->editbox.tbctrl)->contrlData);
+#endif
+ DrawOneControl(mc->editbox.tbctrl);
+ SetPort(saveport);
+}
+
+void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ Size olen;
+
+ assert(mc != NULL);
+ assert(mc->generic.type == MACCTRL_EDITBOX);
+ if (mac_gestalts.apprvers >= 0x100) {
+ if (GetControlData(mc->editbox.tbctrl, kControlEntireControl,
+ ctrl->editbox.password ?
+ kControlEditTextPasswordTag :
+ kControlEditTextTextTag,
+ length - 1, buffer, &olen) != noErr)
+ olen = 0;
+ if (olen > length - 1)
+ olen = length - 1;
+ }
+#if !TARGET_API_MAC_CARBON
+ else {
+ TEHandle te = (TEHandle)(*mc->editbox.tbctrl)->contrlData;
+
+ olen = (*te)->teLength;
+ if (olen > length - 1)
+ olen = length - 1;
+ memcpy(buffer, *(*te)->hText, olen);
+ }
+#endif
+ buffer[olen] = '\0';
+}
+
+
+/*
+ * List Box control
+ */
+
+static void dlg_macpopup_clear(union control *ctrl, void *dlg)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ MenuRef menu = mc->popup.menu;
+ unsigned int i, n;
+
+ if (mc == NULL) return;
+ n = CountMenuItems(menu);
+ for (i = 0; i < n; i++)
+ DeleteMenuItem(menu, n - i);
+ mc->popup.nids = 0;
+ sfree(mc->popup.ids);
+ mc->popup.ids = NULL;
+ SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
+}
+
+static void dlg_macedit_clear(union control *ctrl, void *dlg)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ MenuRef menu = mc->editbox.menu;
+ unsigned int i, n;
+
+ if (mc == NULL) return;
+ n = CountMenuItems(menu);
+ for (i = 0; i < n; i++)
+ DeleteMenuItem(menu, n - i);
+ mc->editbox.nids = 0;
+ sfree(mc->editbox.ids);
+ mc->editbox.ids = NULL;
+ SetControlMaximum(mc->editbox.tbbutton, CountMenuItems(menu));
+}
+
+static void dlg_maclist_clear(union control *ctrl, void *dlg)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ if (mc == NULL) return;
+ LDelRow(0, 0, mc->listbox.list);
+ mc->listbox.nids = 0;
+ sfree(mc->listbox.ids);
+ mc->listbox.ids = NULL;
+ DrawOneControl(mc->listbox.tbctrl);
+}
+
+void dlg_listbox_clear(union control *ctrl, void *dlg)
+{
+
+ switch (ctrl->generic.type) {
+ case CTRL_LISTBOX:
+ if (ctrl->listbox.height == 0)
+ dlg_macpopup_clear(ctrl, dlg);
+ else
+ dlg_maclist_clear(ctrl, dlg);
+ break;
+ case CTRL_EDITBOX:
+ dlg_macedit_clear(ctrl, dlg);
+ }
+}
+
+static void dlg_macpopup_del(union control *ctrl, void *dlg, int index)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ MenuRef menu = mc->popup.menu;
+
+ if (mc == NULL) return;
+ DeleteMenuItem(menu, index + 1);
+ if (mc->popup.ids != NULL)
+ memcpy(mc->popup.ids + index, mc->popup.ids + index + 1,
+ (mc->popup.nids - index - 1) * sizeof(*mc->popup.ids));
+ SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
+}
+
+static void dlg_macedit_del(union control *ctrl, void *dlg, int index)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ MenuRef menu = mc->editbox.menu;
+
+ if (mc == NULL) return;
+ DeleteMenuItem(menu, index + 1);
+ if (mc->editbox.ids != NULL)
+ memcpy(mc->editbox.ids + index, mc->editbox.ids + index + 1,
+ (mc->editbox.nids - index - 1) * sizeof(*mc->editbox.ids));
+ SetControlMaximum(mc->editbox.tbbutton, CountMenuItems(menu));
+}
+
+static void dlg_maclist_del(union control *ctrl, void *dlg, int index)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ if (mc == NULL) return;
+ LDelRow(1, index, mc->listbox.list);
+ if (mc->listbox.ids != NULL)
+ memcpy(mc->listbox.ids + index, mc->listbox.ids + index + 1,
+ (mc->listbox.nids - index - 1) * sizeof(*mc->listbox.ids));
+ DrawOneControl(mc->listbox.tbctrl);
+}
+
+void dlg_listbox_del(union control *ctrl, void *dlg, int index)
+{
+
+ switch (ctrl->generic.type) {
+ case CTRL_LISTBOX:
+ if (ctrl->listbox.height == 0)
+ dlg_macpopup_del(ctrl, dlg, index);
+ else
+ dlg_maclist_del(ctrl, dlg, index);
+ break;
+ case CTRL_EDITBOX:
+ dlg_macedit_del(ctrl, dlg, index);
+ }
+}
+
+static void dlg_macpopup_add(union control *ctrl, void *dlg, char const *text)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ MenuRef menu = mc->popup.menu;
+ Str255 itemstring;
+
+ if (mc == NULL) return;
+ assert(text[0] != '\0');
+ c2pstrcpy(itemstring, text);
+ AppendMenu(menu, "\pdummy");
+ SetMenuItemText(menu, CountMenuItems(menu), itemstring);
+ SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
+}
+
+static void dlg_macedit_add(union control *ctrl, void *dlg, char const *text)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ MenuRef menu = mc->editbox.menu;
+ Str255 itemstring;
+
+ if (mc == NULL) return;
+ assert(text[0] != '\0');
+ c2pstrcpy(itemstring, text);
+ AppendMenu(menu, "\pdummy");
+ SetMenuItemText(menu, CountMenuItems(menu), itemstring);
+ SetControlMaximum(mc->editbox.tbbutton, CountMenuItems(menu));
+}
+
+static void dlg_maclist_add(union control *ctrl, void *dlg, char const *text)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ ListBounds bounds;
+ Cell cell = { 0, 0 };
+
+ if (mc == NULL) return;
+#if TARGET_API_MAC_CARBON
+ GetListDataBounds(mc->listbox.list, &bounds);
+#else
+ bounds = (*mc->listbox.list)->dataBounds;
+#endif
+ cell.v = bounds.bottom;
+ LAddRow(1, cell.v, mc->listbox.list);
+ LSetCell(text, strlen(text), cell, mc->listbox.list);
+ DrawOneControl(mc->listbox.tbctrl);
+}
+
+void dlg_listbox_add(union control *ctrl, void *dlg, char const *text)
+{
+
+ switch (ctrl->generic.type) {
+ case CTRL_LISTBOX:
+ if (ctrl->listbox.height == 0)
+ dlg_macpopup_add(ctrl, dlg, text);
+ else
+ dlg_maclist_add(ctrl, dlg, text);
+ break;
+ case CTRL_EDITBOX:
+ dlg_macedit_add(ctrl, dlg, text);
+ break;
+ }
+}
+
+static void dlg_macpopup_addwithid(union control *ctrl, void *dlg,
+ char const *text, int id)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ MenuRef menu = mc->popup.menu;
+ unsigned int index;
+
+ if (mc == NULL) return;
+ dlg_macpopup_add(ctrl, dlg, text);
+ index = CountMenuItems(menu) - 1;
+ if (mc->popup.nids <= index) {
+ mc->popup.nids = index + 1;
+ mc->popup.ids = sresize(mc->popup.ids, mc->popup.nids, int);
+ }
+ mc->popup.ids[index] = id;
+}
+
+static void dlg_macedit_addwithid(union control *ctrl, void *dlg,
+ char const *text, int id)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ MenuRef menu = mc->editbox.menu;
+ unsigned int index;
+
+ if (mc == NULL) return;
+ dlg_macedit_add(ctrl, dlg, text);
+ index = CountMenuItems(menu) - 1;
+ if (mc->editbox.nids <= index) {
+ mc->editbox.nids = index + 1;
+ mc->editbox.ids = sresize(mc->editbox.ids, mc->editbox.nids, int);
+ }
+ mc->editbox.ids[index] = id;
+}
+
+static void dlg_maclist_addwithid(union control *ctrl, void *dlg,
+ char const *text, int id)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ ListBounds bounds;
+ int index;
+
+ if (mc == NULL) return;
+ dlg_maclist_add(ctrl, dlg, text);
+#if TARGET_API_MAC_CARBON
+ GetListDataBounds(mc->listbox.list, &bounds);
+#else
+ bounds = (*mc->listbox.list)->dataBounds;
+#endif
+ index = bounds.bottom;
+ if (mc->listbox.nids <= index) {
+ mc->listbox.nids = index + 1;
+ mc->listbox.ids = sresize(mc->listbox.ids, mc->listbox.nids, int);
+ }
+ mc->listbox.ids[index] = id;
+}
+
+void dlg_listbox_addwithid(union control *ctrl, void *dlg,
+ char const *text, int id)
+{
+
+ switch (ctrl->generic.type) {
+ case CTRL_LISTBOX:
+ if (ctrl->listbox.height == 0)
+ dlg_macpopup_addwithid(ctrl, dlg, text, id);
+ else
+ dlg_maclist_addwithid(ctrl, dlg, text, id);
+ break;
+ case CTRL_EDITBOX:
+ dlg_macedit_addwithid(ctrl, dlg, text, id);
+ break;
+ }
+}
+
+int dlg_listbox_getid(union control *ctrl, void *dlg, int index)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ assert(mc != NULL);
+ switch (ctrl->generic.type) {
+ case CTRL_LISTBOX:
+ if (ctrl->listbox.height == 0) {
+ assert(mc->popup.ids != NULL && mc->popup.nids > index);
+ return mc->popup.ids[index];
+ } else {
+ assert(mc->listbox.ids != NULL && mc->listbox.nids > index);
+ return mc->listbox.ids[index];
+ }
+ case CTRL_EDITBOX:
+ assert(mc->editbox.ids != NULL && mc->editbox.nids > index);
+ return mc->editbox.ids[index];
+ }
+ return -1;
+}
+
+int dlg_listbox_index(union control *ctrl, void *dlg)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ Cell cell = { 0, 0 };
+
+ assert(mc != NULL);
+ switch (ctrl->generic.type) {
+ case CTRL_LISTBOX:
+ if (ctrl->listbox.height == 0)
+ return GetControlValue(mc->popup.tbctrl) - 1;
+ else {
+ if (LGetSelect(TRUE, &cell, mc->listbox.list))
+ return cell.v;
+ else
+ return -1;
+ }
+ case CTRL_EDITBOX:
+ return GetControlValue(mc->editbox.tbbutton) - 1;
+ }
+ return -1;
+}
+
+int dlg_listbox_issel(union control *ctrl, void *dlg, int index)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ Cell cell = { 0, 0 };
+
+ assert(mc != NULL);
+ switch (ctrl->generic.type) {
+ case CTRL_LISTBOX:
+ if (ctrl->listbox.height == 0)
+ return GetControlValue(mc->popup.tbctrl) - 1 == index;
+ else {
+ cell.v = index;
+ return LGetSelect(FALSE, &cell, mc->listbox.list);
+ }
+ case CTRL_EDITBOX:
+ return GetControlValue(mc->editbox.tbbutton) - 1 == index;
+ }
+ return FALSE;
+}
+
+void dlg_listbox_select(union control *ctrl, void *dlg, int index)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ if (mc == NULL) return;
+ switch (ctrl->generic.type) {
+ case CTRL_LISTBOX:
+ if (ctrl->listbox.height == 0)
+ SetControlValue(mc->popup.tbctrl, index + 1);
+ break;
+ case CTRL_EDITBOX:
+ SetControlValue(mc->editbox.tbbutton, index + 1);
+ }
+}
+
+static void draglist_move(union macctrl *mc, struct macctrls *mcs,
+ int direction)
+{
+ ListBounds bounds;
+ Cell cell = {0, 0};
+ char current[255];
+ char new[255];
+ short curlength = 255;
+ short newlength = 255;
+ int curid, newid;
+
+ int index = dlg_listbox_index(mc->generic.ctrl, mcs);
+
+#if TARGET_API_MAC_CARBON
+ GetListDataBounds(mc->listbox.list, &bounds);
+#else
+ bounds = (*mc->listbox.list)->dataBounds;
+#endif
+
+ if ((index < 0) ||
+ (index == 0 && direction < 0) ||
+ (index == bounds.bottom-1 && direction > 0)) {
+ SysBeep(30);
+ return;
+ }
+
+ /* Swap the contents of the selected and target list cells */
+
+ cell.v = index;
+ LGetCell(current, &curlength, cell, mc->listbox.list);
+ current[curlength] = '\0';
+ cell.v += direction;
+ LGetCell(new, &newlength, cell, mc->listbox.list);
+ new[newlength] = '\0';
+
+ cell.v = index;
+ LSetCell(new, newlength, cell, mc->listbox.list);
+ cell.v += direction;
+ LSetCell(current, curlength, cell, mc->listbox.list);
+
+ /* Move the selection to the target list cell */
+
+ cell.v = index;
+ LSetSelect(FALSE, cell, mc->listbox.list);
+ cell.v += direction;
+ LSetSelect(TRUE, cell, mc->listbox.list);
+ DrawOneControl(mc->listbox.tbctrl);
+
+ /* Swap the ids of the list cells */
+
+ curid = mc->listbox.ids[index];
+ newid = mc->listbox.ids[index + direction];
+ mc->listbox.ids[index] = newid;
+ mc->listbox.ids[index + direction] = curid;
+
+ ctrlevent(mcs, mc, EVENT_VALCHANGE);
+}
+
+static void draglist_up(union macctrl *mc, struct macctrls *mcs)
+{
+ draglist_move(mc, mcs, -1);
+}
+
+static void draglist_down(union macctrl *mc, struct macctrls *mcs)
+{
+ draglist_move(mc, mcs, +1);
+}
+
+/*
+ * Text control
+ */
+
+void dlg_text_set(union control *ctrl, void *dlg, char const *text)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+
+ if (mc == NULL) return;
+ if (mac_gestalts.apprvers >= 0x100)
+ SetControlData(mc->text.tbctrl, kControlEntireControl,
+ kControlStaticTextTextTag, strlen(text), text);
+#if !TARGET_API_MAC_CARBON
+ else
+ TESetText(text, strlen(text),
+ (TEHandle)(*mc->text.tbctrl)->contrlData);
+#endif
+}
+
+
+/*
+ * File Selector control
+ */
+
+void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn)
+{
+
+}
+
+void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn)
+{
+
+}
+
+
+/*
+ * Font Selector control
+ */
+
+void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fn)
+{
+
+}
+
+void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fn)
+{
+
+}
+
+
+/*
+ * Printer enumeration
+ */
+
+printer_enum *printer_start_enum(int *nprinters)
+{
+
+ *nprinters = 0;
+ return NULL;
+}
+
+char *printer_get_name(printer_enum *pe, int thing)
+{
+
+ return "";
+}
+
+void printer_finish_enum(printer_enum *pe)
+{
+
+}
+
+
+/*
+ * Colour selection stuff
+ */
+
+void dlg_coloursel_start(union control *ctrl, void *dlg,
+ int r, int g, int b)
+{
+ struct macctrls *mcs = dlg;
+ union macctrl *mc = findbyctrl(mcs, ctrl);
+ Point where = {-1, -1}; /* Screen with greatest colour depth */
+ RGBColor incolour;
+
+ if (HAVE_COLOR_QD()) {
+ incolour.red = r * 0x0101;
+ incolour.green = g * 0x0101;
+ incolour.blue = b * 0x0101;
+ mcs->gotcolour = GetColor(where, "\pModify Colour:", &incolour,
+ &mcs->thecolour);
+ ctrlevent(mcs, mc, EVENT_CALLBACK);
+ } else
+ dlg_beep(dlg);
+}
+
+int dlg_coloursel_results(union control *ctrl, void *dlg,
+ int *r, int *g, int *b)
+{
+ struct macctrls *mcs = dlg;
+
+ if (mcs->gotcolour) {
+ *r = mcs->thecolour.red >> 8;
+ *g = mcs->thecolour.green >> 8;
+ *b = mcs->thecolour.blue >> 8;
+ return 1;
+ } else
+ return 0;
+}
+
+void dlg_label_change(union control *ctrl, void *dlg, char const *text)
+{
+ /*
+ * This function is currently only used by the config box to
+ * switch the labels on the host and port boxes between serial
+ * and network modes. Since the Mac port does not have a serial
+ * back end, this function can safely do nothing.
+ */
+}
+
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MACDLG.C b/puttysrc/MAC/MACDLG.C
new file mode 100644
index 0000000..3ff6ac6
--- /dev/null
+++ b/puttysrc/MAC/MACDLG.C
@@ -0,0 +1,408 @@
+/* $Id: macdlg.c 7266 2007-02-10 17:12:06Z simon $ */
+/*
+ * Copyright (c) 2002 Ben Harris
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * macdlg.c - settings dialogue box for Mac OS.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "putty.h"
+#include "dialog.h"
+#include "mac.h"
+#include "macresid.h"
+#include "storage.h"
+
+static void mac_config(int);
+static void mac_closedlg(WindowPtr);
+static void mac_enddlg_config(WindowPtr, int);
+static void mac_enddlg_reconfig(WindowPtr, int);
+
+void mac_newsession(void)
+{
+ mac_config(FALSE);
+}
+
+void mac_reconfig(void)
+{
+ mac_config(TRUE);
+}
+
+static void mac_config(int midsession)
+{
+ Session *s;
+ WinInfo *wi;
+ Str255 mactitle;
+ char *str;
+
+ if (midsession) {
+ s = mac_windowsession(FrontWindow());
+ } else {
+ s = snew(Session);
+ memset(s, 0, sizeof(*s));
+ do_defaults(NULL, &s->cfg);
+ s->hasfile = FALSE;
+ s->session_closed = FALSE;
+ }
+
+ /* Copy the configuration somewhere else in case this is a *
+ * reconfiguration and the user cancels the operation */
+
+ s->temp_cfg = s->cfg;
+
+ if (HAVE_COLOR_QD())
+ s->settings_window = GetNewCWindow(wSettings, NULL, (WindowPtr)-1);
+ else
+ s->settings_window = GetNewWindow(wSettings, NULL, (WindowPtr)-1);
+
+ s->ctrlbox = ctrl_new_box();
+ setup_config_box(s->ctrlbox, midsession, 0, 0);
+
+ s->settings_ctrls.data = &s->temp_cfg;
+ if (midsession)
+ s->settings_ctrls.end = &mac_enddlg_reconfig;
+ else
+ s->settings_ctrls.end = &mac_enddlg_config;
+
+ macctrl_layoutbox(s->ctrlbox, s->settings_window, &s->settings_ctrls);
+
+ wi = snew(WinInfo);
+ memset(wi, 0, sizeof(*wi));
+ wi->s = s;
+ wi->mcs = &s->settings_ctrls;
+ wi->wtype = wSettings;
+ wi->update = &macctrl_update;
+ wi->click = &macctrl_click;
+ wi->key = &macctrl_key;
+ wi->activate = &macctrl_activate;
+ wi->adjustmenus = &macctrl_adjustmenus;
+ wi->close = &mac_closedlg;
+ SetWRefCon(s->settings_window, (long)wi);
+ if (midsession)
+ str = dupprintf("%s Reconfiguration", appname);
+ else
+ str = dupprintf("%s Configuration", appname);
+ c2pstrcpy(mactitle, str);
+ sfree(str);
+ SetWTitle(s->settings_window, mactitle);
+ ShowWindow(s->settings_window);
+}
+
+static void mac_closedlg(WindowPtr window)
+{
+ Session *s = mac_windowsession(window);
+
+ macctrl_close(window);
+ DisposeWindow(window);
+ if (s->window == NULL)
+ sfree(s);
+}
+
+static void mac_enddlg_config(WindowPtr window, int value)
+{
+ Session *s = mac_windowsession(window);
+
+ if (value == 0)
+ mac_closedlg(window);
+ else {
+ s->cfg = s->temp_cfg;
+ mac_startsession(s);
+ mac_closedlg(window);
+ }
+}
+
+static void mac_enddlg_reconfig(WindowPtr window, int value)
+{
+ Session *s = mac_windowsession(window);
+
+ if (value == 0)
+ mac_closedlg(window);
+ else {
+ Config prev_cfg = s->cfg;
+ s->cfg = s->temp_cfg;
+ mac_closedlg(window);
+
+ /* Pass new config data to the logging module */
+ log_reconfig(s->logctx, &s->cfg);
+
+ /*
+ * Flush the line discipline's edit buffer in the
+ * case where local editing has just been disabled.
+ */
+ if (s->ldisc)
+ ldisc_send(s->ldisc, NULL, 0, 0);
+
+ /* Change the palette */
+ palette_reset(s);
+
+ /* Reinitialise line codepage */
+ init_ucs(s);
+
+ /* Pass new config data to the terminal */
+ term_reconfig(s->term, &s->cfg);
+
+ /* Pass new config data to the back end */
+ if (s->back)
+ s->back->reconfig(s->backhandle, &s->cfg);
+
+ /* Screen size changed ? */
+ if (s->cfg.height != prev_cfg.height ||
+ s->cfg.width != prev_cfg.width ||
+ s->cfg.savelines != prev_cfg.savelines) {
+ request_resize(s, s->cfg.width, s->cfg.height);
+ }
+
+ /* Set the window title */
+ if (s->cfg.wintitle[0])
+ set_title(s, s->cfg.wintitle);
+
+ /* Scroll bar */
+ if (s->cfg.scrollbar != prev_cfg.scrollbar)
+ request_resize(s, s->cfg.width, s->cfg.height);
+
+ /* TODO: zoom, font */
+ }
+}
+
+void mac_dupsession(void)
+{
+ Session *s1 = mac_windowsession(FrontWindow());
+ Session *s2;
+
+ s2 = snew(Session);
+ memset(s2, 0, sizeof(*s2));
+ s2->cfg = s1->cfg;
+ s2->hasfile = s1->hasfile;
+ s2->savefile = s1->savefile;
+
+ mac_startsession(s2);
+}
+
+static OSErr mac_opensessionfrom(FSSpec *fss)
+{
+ FInfo fi;
+ Session *s;
+ void *sesshandle;
+ OSErr err;
+
+ s = snew(Session);
+ memset(s, 0, sizeof(*s));
+
+ err = FSpGetFInfo(fss, &fi);
+ if (err != noErr) return err;
+ if (fi.fdFlags & kIsStationery)
+ s->hasfile = FALSE;
+ else {
+ s->hasfile = TRUE;
+ s->savefile = *fss;
+ }
+
+ sesshandle = open_settings_r_fsp(fss);
+ if (sesshandle == NULL) {
+ /* XXX need a way to pass up an error number */
+ err = -9999;
+ goto fail;
+ }
+ load_open_settings(sesshandle, &s->cfg);
+ close_settings_r(sesshandle);
+
+ mac_startsession(s);
+ return noErr;
+
+ fail:
+ sfree(s);
+ return err;
+}
+
+static OSErr mac_openlist(AEDesc docs)
+{
+ OSErr err;
+ long ndocs, i;
+ FSSpec fss;
+ AEKeyword keywd;
+ DescType type;
+ Size size;
+
+ err = AECountItems(&docs, &ndocs);
+ if (err != noErr) return err;
+
+ for (i = 0; i < ndocs; i++) {
+ err = AEGetNthPtr(&docs, i + 1, typeFSS,
+ &keywd, &type, &fss, sizeof(fss), &size);
+ if (err != noErr) return err;;
+ err = mac_opensessionfrom(&fss);
+ if (err != noErr) return err;
+ }
+ return noErr;
+}
+
+void mac_opensession(void)
+{
+
+ if (mac_gestalts.navsvers > 0) {
+ NavReplyRecord navr;
+ NavDialogOptions navopts;
+ NavTypeListHandle navtypes;
+ AEDesc defaultloc = { 'null', NULL };
+ AEDesc *navdefault = NULL;
+ short vol;
+ long dirid;
+ FSSpec fss;
+
+ if (NavGetDefaultDialogOptions(&navopts) != noErr) return;
+ /* XXX should we create sessions dir? */
+ if (get_session_dir(FALSE, &vol, &dirid) == noErr &&
+ FSMakeFSSpec(vol, dirid, NULL, &fss) == noErr &&
+ AECreateDesc(typeFSS, &fss, sizeof(fss), &defaultloc) == noErr)
+ navdefault = &defaultloc;
+ /* Can't meaningfully preview a saved session yet */
+ navopts.dialogOptionFlags &= ~kNavAllowPreviews;
+ navtypes = (NavTypeListHandle)GetResource('open', open_pTTY);
+ if (NavGetFile(navdefault, &navr, &navopts, NULL, NULL, NULL, navtypes,
+ NULL) == noErr && navr.validRecord)
+ mac_openlist(navr.selection);
+ NavDisposeReply(&navr);
+ if (navtypes != NULL)
+ ReleaseResource((Handle)navtypes);
+ }
+#if !TARGET_API_MAC_CARBON /* XXX Navigation Services */
+ else {
+ StandardFileReply sfr;
+ static const OSType sftypes[] = { 'Sess', 0, 0, 0 };
+
+ StandardGetFile(NULL, 1, sftypes, &sfr);
+ if (!sfr.sfGood) return;
+
+ mac_opensessionfrom(&sfr.sfFile);
+ /* XXX handle error */
+ }
+#endif
+}
+
+void mac_savesession(void)
+{
+ Session *s = mac_windowsession(FrontWindow());
+ void *sesshandle;
+
+ assert(s->hasfile);
+ sesshandle = open_settings_w_fsp(&s->savefile);
+ if (sesshandle == NULL) return; /* XXX report error */
+ save_open_settings(sesshandle, &s->cfg);
+ close_settings_w(sesshandle);
+}
+
+void mac_savesessionas(void)
+{
+#if !TARGET_API_MAC_CARBON /* XXX Navigation Services */
+ Session *s = mac_windowsession(FrontWindow());
+ StandardFileReply sfr;
+ void *sesshandle;
+
+ StandardPutFile("\pSave session as:",
+ s->hasfile ? s->savefile.name : "\puntitled", &sfr);
+ if (!sfr.sfGood) return;
+
+ if (!sfr.sfReplacing) {
+ FSpCreateResFile(&sfr.sfFile, PUTTY_CREATOR, SESS_TYPE, sfr.sfScript);
+ if (ResError() != noErr) return; /* XXX report error */
+ }
+ sesshandle = open_settings_w_fsp(&sfr.sfFile);
+ if (sesshandle == NULL) return; /* XXX report error */
+ save_open_settings(sesshandle, &s->cfg);
+ close_settings_w(sesshandle);
+ s->hasfile = TRUE;
+ s->savefile = sfr.sfFile;
+#endif
+}
+
+pascal OSErr mac_aevt_oapp(const AppleEvent *req, AppleEvent *reply,
+ long refcon)
+{
+ DescType type;
+ Size size;
+
+ if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
+ &type, NULL, 0, &size) == noErr)
+ return errAEParamMissed;
+
+ /* XXX we should do something here. */
+ return noErr;
+}
+
+pascal OSErr mac_aevt_odoc(const AppleEvent *req, AppleEvent *reply,
+ long refcon)
+{
+ DescType type;
+ Size size;
+ AEDescList docs = { typeNull, NULL };
+ OSErr err;
+
+ err = AEGetParamDesc(req, keyDirectObject, typeAEList, &docs);
+ if (err != noErr) goto out;
+
+ if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
+ &type, NULL, 0, &size) == noErr) {
+ err = errAEParamMissed;
+ goto out;
+ }
+
+ err = mac_openlist(docs);
+
+ out:
+ AEDisposeDesc(&docs);
+ return err;
+}
+
+pascal OSErr mac_aevt_pdoc(const AppleEvent *req, AppleEvent *reply,
+ long refcon)
+{
+ DescType type;
+ Size size;
+
+ if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
+ &type, NULL, 0, &size) == noErr)
+ return errAEParamMissed;
+
+ /* We can't meaningfully do anything here. */
+ return errAEEventNotHandled;
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MACEVLOG.C b/puttysrc/MAC/MACEVLOG.C
new file mode 100644
index 0000000..44588b9
--- /dev/null
+++ b/puttysrc/MAC/MACEVLOG.C
@@ -0,0 +1,277 @@
+/* $Id: macevlog.c 5250 2005-02-05 00:29:20Z owen $ */
+/*
+ * Copyright (c) 2003 Ben Harris
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "putty.h"
+#include "mac.h"
+#include "macresid.h"
+#include "terminal.h"
+
+static void mac_draweventloggrowicon(Session *s);
+static void mac_adjusteventlogscrollbar(Session *s);
+static void mac_clickeventlog(WindowPtr, EventRecord *);
+static void mac_activateeventlog(WindowPtr, EventRecord *);
+static void mac_groweventlog(WindowPtr, EventRecord *);
+static void mac_updateeventlog(WindowPtr);
+static void mac_closeeventlog(WindowPtr);
+
+static void mac_createeventlog(Session *s)
+{
+ Rect view;
+ ListBounds bounds = { 0, 0, 0, 1 }; /* 1 column, 0 rows */
+ Point csize = { 0, 0 };
+ GrafPtr saveport;
+ long fondsize;
+ WinInfo *wi;
+
+ s->eventlog_window = GetNewWindow(wEventLog, NULL, (WindowPtr)-1);
+ wi = snew(WinInfo);
+ memset(wi, 0, sizeof(*wi));
+ wi->s = s;
+ wi->wtype = wEventLog;
+ wi->click = &mac_clickeventlog;
+ wi->activate = &mac_activateeventlog;
+ wi->grow = &mac_groweventlog;
+ wi->update = &mac_updateeventlog;
+ wi->close = &mac_closeeventlog;
+ SetWRefCon(s->eventlog_window, (long)wi);
+ GetPort(&saveport);
+ SetPort((GrafPtr)GetWindowPort(s->eventlog_window));
+ fondsize = GetScriptVariable(smRoman, smScriptSmallFondSize);
+ TextFont(HiWord(fondsize));
+ TextSize(LoWord(fondsize));
+ SetPort(saveport);
+#if TARGET_API_MAC_CARBON
+ GetPortBounds(GetWindowPort(s->eventlog_window), &view);
+#else
+ view = s->eventlog_window->portRect;
+#endif
+ view.right -= 15; /* Scrollbar */
+ s->eventlog = LNew(&view, &bounds, csize, 0, s->eventlog_window,
+ TRUE, TRUE, FALSE, TRUE);
+ mac_adjusteventlogscrollbar(s);
+#if TARGET_API_MAC_CARBON
+ SetListSelectionFlags(s->eventlog, lExtendDrag | lNoDisjoint | lNoExtend);
+#else
+ (*s->eventlog)->selFlags = lExtendDrag | lNoDisjoint | lNoExtend;
+#endif
+}
+
+void mac_freeeventlog(Session *s)
+{
+
+ if (s->eventlog != NULL)
+ LDispose(s->eventlog);
+ if (s->eventlog_window != NULL) {
+ sfree((WinInfo *)GetWRefCon(s->eventlog_window));
+ DisposeWindow(s->eventlog_window);
+ }
+}
+
+void logevent(void *frontend, const char *str)
+{
+ Session *s = frontend;
+ ListBounds bounds, visible;
+ Cell cell = { 0, 0 };
+ char timebuf[40];
+ struct tm tm;
+ char *string;
+
+ tm=ltime();
+ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S\t", &tm);
+
+ string=snewn(strlen(timebuf) + strlen(str) +1, char);
+ strcpy(string, timebuf);
+ strcat(string, str);
+
+ if (s->eventlog == NULL)
+ mac_createeventlog(s);
+ if (s->eventlog == NULL)
+ return;
+
+#if TARGET_API_MAC_CARBON
+ GetListDataBounds(s->eventlog, &bounds);
+ GetListVisibleCells(s->eventlog, &visible);
+#else
+ bounds = (*s->eventlog)->dataBounds;
+ visible = (*s->eventlog)->visible;
+#endif
+
+ cell.v = bounds.bottom;
+ LAddRow(1, cell.v, s->eventlog);
+ LSetCell(string, strlen(string), cell, s->eventlog);
+ /* ">=" and "2" because there can be a blank cell below the last one. */
+ if (visible.bottom >= bounds.bottom)
+ LScroll(0, 2, s->eventlog);
+ sfree(string);
+}
+
+static void mac_draweventloggrowicon(Session *s)
+{
+ Rect clip;
+ RgnHandle savergn;
+
+ SetPort((GrafPtr)GetWindowPort(s->eventlog_window));
+ /*
+ * Stop DrawGrowIcon giving us space for a horizontal scrollbar
+ * See Tech Note TB575 for details.
+ */
+#if TARGET_API_MAC_CARBON
+ GetPortBounds(GetWindowPort(s->eventlog_window), &clip);
+#else
+ clip = s->eventlog_window->portRect;
+#endif
+ clip.left = clip.right - 15;
+ savergn = NewRgn();
+ GetClip(savergn);
+ ClipRect(&clip);
+ DrawGrowIcon(s->eventlog_window);
+ SetClip(savergn);
+ DisposeRgn(savergn);
+}
+
+/*
+ * For some reason, LNew doesn't seem to respect the hasGrow
+ * parameter, so we hammer the scrollbar into shape ourselves.
+ */
+static void mac_adjusteventlogscrollbar(Session *s)
+{
+#if TARGET_API_MAC_CARBON
+ Rect winrect;
+
+ GetPortBounds(GetWindowPort(s->eventlog_window), &winrect);
+ SizeControl(GetListVerticalScrollBar(s->eventlog),
+ 16, winrect.bottom - 13);
+#else
+ SizeControl((*s->eventlog)->vScroll,
+ 16, s->eventlog_window->portRect.bottom - 13);
+#endif
+}
+
+void mac_clickeventlog(WindowPtr window, EventRecord *event)
+{
+ Session *s = mac_windowsession(window);
+ Point mouse;
+ GrafPtr saveport;
+
+ GetPort(&saveport);
+ SetPort((GrafPtr)GetWindowPort(window));
+ mouse = event->where;
+ GlobalToLocal(&mouse);
+ LClick(mouse, event->modifiers, s->eventlog);
+ SetPort(saveport);
+}
+
+static void mac_groweventlog(WindowPtr window, EventRecord *event)
+{
+ Session *s = mac_windowsession(window);
+ Rect limits;
+ long grow_result;
+#if TARGET_API_MAC_CARBON
+ Rect rect;
+ Point cellsize;
+#else
+ GrafPtr saveport;
+#endif
+
+ SetRect(&limits, 15, 0, SHRT_MAX, SHRT_MAX);
+ grow_result = GrowWindow(window, event->where, &limits);
+ if (grow_result == 0) return;
+ SizeWindow(window, LoWord(grow_result), HiWord(grow_result), TRUE);
+ LSize(LoWord(grow_result) - 15, HiWord(grow_result), s->eventlog);
+ mac_adjusteventlogscrollbar(s);
+ /* We would use SetListCellSize in Carbon, but it's missing. */
+ (*s->eventlog)->cellSize.h = LoWord(grow_result) - 15;
+#if TARGET_API_MAC_CARBON
+ cellsize.h = LoWord(grow_result) - 15;
+ GetListViewBounds(s->eventlog, &rect);
+ InvalWindowRect(window, &rect);
+#else
+ GetPort(&saveport);
+ SetPort(window);
+ InvalRect(&(*s->eventlog)->rView);
+ SetPort(saveport);
+#endif
+}
+
+static void mac_activateeventlog(WindowPtr window, EventRecord *event)
+{
+ Session *s = mac_windowsession(window);
+ int active = (event->modifiers & activeFlag) != 0;
+
+ LActivate(active, s->eventlog);
+ mac_draweventloggrowicon(s);
+}
+
+static void mac_updateeventlog(WindowPtr window)
+{
+ Session *s = mac_windowsession(window);
+#if TARGET_API_MAC_CARBON
+ RgnHandle visrgn;
+#endif
+
+ SetPort((GrafPtr)GetWindowPort(window));
+ BeginUpdate(window);
+#if TARGET_API_MAC_CARBON
+ visrgn = NewRgn();
+ GetPortVisibleRegion(GetWindowPort(window), visrgn);
+ LUpdate(visrgn, s->eventlog);
+ DisposeRgn(visrgn);
+#else
+ LUpdate(window->visRgn, s->eventlog);
+#endif
+ mac_draweventloggrowicon(s);
+ EndUpdate(window);
+}
+
+static void mac_closeeventlog(WindowPtr window)
+{
+
+ HideWindow(window);
+}
+
+void mac_showeventlog(Session *s)
+{
+
+ SelectWindow(s->eventlog_window);
+ ShowWindow(s->eventlog_window);
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MACMISC.C b/puttysrc/MAC/MACMISC.C
new file mode 100644
index 0000000..13f7bd5
--- /dev/null
+++ b/puttysrc/MAC/MACMISC.C
@@ -0,0 +1,207 @@
+/* $Id: macmisc.c 7084 2007-01-09 18:14:30Z simon $ */
+/*
+ * Copyright (c) 1999, 2003 Ben Harris
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "putty.h"
+#include "mac.h"
+#include "ssh.h"
+
+#if TARGET_API_MAC_CARBON
+/*
+ * This is used by (I think) CarbonStdCLib, but only exists in
+ * CarbonLib 1.1 and later. Muppets. Happily, it's documented to be
+ * a synonym for NULL.
+ */
+#include
+const CFAllocatorRef kCFAllocatorDefault = NULL;
+#else
+QDGlobals qd;
+#endif
+
+/*
+ * Like FrontWindow(), but return NULL if we aren't the front process
+ * (i.e. the front window isn't one of ours).
+ */
+WindowPtr mac_frontwindow(void)
+{
+ ProcessSerialNumber frontpsn;
+ ProcessSerialNumber curpsn = { 0, kCurrentProcess };
+ Boolean result;
+
+ GetFrontProcess(&frontpsn);
+ if (SameProcess(&frontpsn, &curpsn, &result) == noErr && result)
+ return FrontWindow();
+ return NULL;
+}
+
+void fatalbox(char *fmt, ...) {
+ va_list ap;
+ Str255 stuff;
+
+ va_start(ap, fmt);
+ /* We'd like stuff to be a Pascal string */
+ stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
+ va_end(ap);
+ ParamText(stuff, NULL, NULL, NULL);
+ StopAlert(128, NULL);
+ cleanup_exit(1);
+}
+
+void modalfatalbox(char *fmt, ...) {
+ va_list ap;
+ Str255 stuff;
+
+ va_start(ap, fmt);
+ /* We'd like stuff to be a Pascal string */
+ stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
+ va_end(ap);
+ ParamText(stuff, NULL, NULL, NULL);
+ StopAlert(128, NULL);
+ cleanup_exit(1);
+}
+
+Filename filename_from_str(const char *str)
+{
+ Filename ret;
+ Str255 tmp;
+
+ /* XXX This fails for filenames over 255 characters long. */
+ c2pstrcpy(tmp, str);
+ FSMakeFSSpec(0, 0, tmp, &ret.fss);
+ return ret;
+}
+
+/*
+ * Convert a filename to a string for display purposes.
+ * See pp 2-44--2-46 of IM:Files
+ *
+ * XXX static storage considered harmful
+ */
+const char *filename_to_str(const Filename *fn)
+{
+ CInfoPBRec pb;
+ Str255 dirname;
+ OSErr err;
+ static char *path = NULL;
+ char *newpath;
+
+ if (path != NULL) sfree(path);
+ path = snewn(fn->fss.name[0], char);
+ p2cstrcpy(path, fn->fss.name);
+ pb.dirInfo.ioNamePtr = dirname;
+ pb.dirInfo.ioVRefNum = fn->fss.vRefNum;
+ pb.dirInfo.ioDrParID = fn->fss.parID;
+ pb.dirInfo.ioFDirIndex = -1;
+ do {
+ pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+ err = PBGetCatInfoSync(&pb);
+
+ /* XXX Assume not A/UX */
+ newpath = snewn(strlen(path) + dirname[0] + 2, char);
+ p2cstrcpy(newpath, dirname);
+ strcat(newpath, ":");
+ strcat(newpath, path);
+ sfree(path);
+ path = newpath;
+ } while (pb.dirInfo.ioDrDirID != fsRtDirID);
+ return path;
+}
+
+int filename_equal(Filename f1, Filename f2)
+{
+
+ return f1.fss.vRefNum == f2.fss.vRefNum &&
+ f1.fss.parID == f2.fss.parID &&
+ f1.fss.name[0] == f2.fss.name[0] &&
+ memcmp(f1.fss.name + 1, f2.fss.name + 1, f1.fss.name[0]) == 0;
+}
+
+int filename_is_null(Filename fn)
+{
+
+ return fn.fss.vRefNum == 0 && fn.fss.parID == 0 && fn.fss.name[0] == 0;
+}
+
+FILE *f_open(Filename fn, char const *mode, int is_private)
+{
+ short savevol;
+ long savedir;
+ char tmp[256];
+ FILE *ret;
+
+ HGetVol(NULL, &savevol, &savedir);
+ if (HSetVol(NULL, fn.fss.vRefNum, fn.fss.parID) == noErr) {
+ p2cstrcpy(tmp, fn.fss.name);
+ ret = fopen(tmp, mode);
+ } else
+ ret = NULL;
+ HSetVol(NULL, savevol, savedir);
+ return ret;
+}
+
+struct tm ltime(void)
+{
+ struct tm tm;
+ DateTimeRec d;
+ GetTime(&d);
+
+ tm.tm_sec=d.second;
+ tm.tm_min=d.minute;
+ tm.tm_hour=d.hour;
+ tm.tm_mday=d.day;
+ tm.tm_mon=d.month-1;
+ tm.tm_year=d.year-1900;
+ tm.tm_wday=d.dayOfWeek;
+ tm.tm_yday=1; /* GetTime doesn't tell us */
+ tm.tm_isdst=0; /* Have to do DST ourselves */
+
+ /* XXX find out DST adjustment and add it */
+
+ return tm;
+}
+
+const char platform_x11_best_transport[] = "localhost";
+
+char *platform_get_x_display(void) {
+ return NULL;
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MACNET.C b/puttysrc/MAC/MACNET.C
new file mode 100644
index 0000000..693dc7a
--- /dev/null
+++ b/puttysrc/MAC/MACNET.C
@@ -0,0 +1,188 @@
+#include "putty.h"
+#include "network.h"
+#include "mac.h"
+#include "ssh.h"
+
+struct macnet_stack {
+ SockAddr (*namelookup)(char const *, char **);
+ SockAddr (*nonamelookup)(char const *);
+ void (*getaddr)(SockAddr, char *, int);
+ int (*hostname_is_local)(char *);
+ int (*address_is_local)(SockAddr);
+ int (*addrtype)(SockAddr);
+ void (*addrcopy)(SockAddr, char *);
+ void (*addr_free)(SockAddr);
+ Socket (*skregister)(void *, Plug); /* "register" is a reserved word */
+ Socket (*new)(SockAddr, int, int, int, int, int, Plug);
+ Socket (*newlistener)(char *, int, Plug, int, int);
+ char *(*addr_error)(SockAddr);
+ void (*poll)(void);
+ void (*cleanup)(void);
+};
+
+static struct macnet_stack *stack;
+
+static struct macnet_stack ot = {
+ ot_namelookup, ot_nonamelookup, ot_getaddr, ot_hostname_is_local,
+ ot_address_is_local, ot_addrtype, ot_addrcopy, ot_addr_free,
+ ot_register, ot_new, ot_newlistener, ot_addr_error, ot_poll, ot_cleanup
+};
+
+#if !TARGET_API_MAC_CARBON
+static struct macnet_stack mactcp = {
+ mactcp_namelookup, mactcp_nonamelookup, mactcp_getaddr,
+ mactcp_hostname_is_local, mactcp_address_is_local, mactcp_addrtype,
+ mactcp_addrcopy, mactcp_addr_free, mactcp_register, mactcp_new,
+ mactcp_newlistener, mactcp_addr_error, mactcp_poll, mactcp_cleanup
+};
+#endif
+
+void sk_init(void)
+{
+
+#ifndef NO_OT
+ if (ot_init() == noErr)
+ stack = &ot;
+ else
+#endif
+#if !TARGET_API_MAC_CARBON
+ if (mactcp_init() == noErr)
+ stack = &mactcp;
+ else
+#endif
+ stack = NULL;
+}
+
+/*
+ * Network functions exported to the world. These choose whether to call
+ * MacTCP or OpenTransport and behave accordingly.
+ */
+SockAddr sk_namelookup(char const *host, char **canonicalname, int address_family)
+{
+
+ if (stack != NULL)
+ return stack->namelookup(host, canonicalname);
+ return NULL;
+}
+
+SockAddr sk_nonamelookup(char const *host)
+{
+
+ if (stack != NULL)
+ return stack->nonamelookup(host);
+ return NULL;
+}
+
+void sk_getaddr(SockAddr addr, char *buf, int buflen)
+{
+
+ if (stack != NULL)
+ stack->getaddr(addr, buf, buflen);
+ else
+ *buf = '\0';
+}
+
+int sk_hostname_is_local(char *name)
+{
+
+ if (stack != NULL)
+ return stack->hostname_is_local(name);
+ return 0;
+}
+
+int sk_address_is_local(SockAddr addr)
+{
+
+ if (stack != NULL)
+ return stack->address_is_local(addr);
+ return 0;
+}
+
+int sk_addrtype(SockAddr addr)
+{
+
+ if (stack != NULL)
+ return stack->addrtype(addr);
+ return 0;
+}
+
+void sk_addrcopy(SockAddr addr, char *buf)
+{
+
+ if (stack != NULL)
+ stack->addrcopy(addr, buf);
+}
+
+void sk_addr_free(SockAddr addr)
+{
+
+ if (stack != NULL)
+ stack->addr_free(addr);
+}
+
+Socket sk_register(void *sock, Plug plug)
+{
+
+ if (stack != NULL)
+ return stack->skregister(sock, plug);
+ return NULL;
+}
+
+Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
+ int nodelay, int keepalive, Plug plug)
+{
+
+ if (stack != NULL)
+ return stack->new(addr, port, privport, oobinline, nodelay, keepalive,
+ plug);
+ return NULL;
+}
+
+Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int address_family)
+{
+
+ if (stack != NULL)
+ return stack->newlistener(srcaddr, port, plug, local_host_only, address_family);
+ return NULL;
+}
+
+const char *sk_addr_error(SockAddr addr)
+{
+
+ if (stack != NULL)
+ return stack->addr_error(addr);
+ return "No TCP/IP stack installed";
+}
+
+void sk_poll(void)
+{
+
+ if (stack != NULL)
+ stack->poll();
+}
+
+void sk_cleanup(void)
+{
+
+ if (stack != NULL)
+ stack->cleanup();
+}
+
+/* We should use Internet Config here. */
+int net_service_lookup(char *service)
+{
+
+ return 0;
+}
+
+SockAddr platform_get_x11_unix_address(int displaynum, char **canonicalname)
+{
+ return NULL;
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
+
diff --git a/puttysrc/MAC/MACNOISE.C b/puttysrc/MAC/MACNOISE.C
new file mode 100644
index 0000000..f997862
--- /dev/null
+++ b/puttysrc/MAC/MACNOISE.C
@@ -0,0 +1,97 @@
+/*
+ * Noise generation for PuTTY's cryptographic random number
+ * generator.
+ */
+
+#include
+#include
+#include
+
+#include "putty.h"
+#include "ssh.h"
+#include "storage.h"
+
+/*
+ * This function is called once, at PuTTY startup, and will do some
+ * seriously silly things like listing directories and getting disk
+ * free space and a process snapshot.
+ */
+
+static void noise_get_processes(void (*func) (void *, int))
+{
+ ProcessSerialNumber psn = {0, kNoProcess};
+ ProcessInfoRec info;
+
+ for (;;) {
+ GetNextProcess(&psn);
+ if (psn.highLongOfPSN == 0 && psn.lowLongOfPSN == kNoProcess) return;
+ info.processInfoLength = sizeof(info);
+ info.processName = NULL;
+ info.processAppSpec = NULL;
+ GetProcessInformation(&psn, &info);
+ func(&info, sizeof(info));
+ }
+}
+
+void noise_get_heavy(void (*func) (void *, int))
+{
+
+ noise_get_light(func);
+ noise_get_processes(func);
+ read_random_seed(func);
+ /* Update the seed immediately, in case another instance uses it. */
+ random_save_seed();
+}
+
+void random_save_seed(void)
+{
+ int len;
+ void *data;
+
+ if (random_active) {
+ random_get_savedata(&data, &len);
+ write_random_seed(data, len);
+ sfree(data);
+ }
+}
+
+/*
+ * This function is called every time the random pool needs
+ * stirring, and will acquire the system time.
+ */
+void noise_get_light(void (*func) (void *, int))
+{
+ UnsignedWide utc;
+
+ Microseconds(&utc);
+ func(&utc, sizeof(utc));
+}
+
+/*
+ * This function is called on a timer, and grabs as much changeable
+ * system data as it can quickly get its hands on.
+ */
+void noise_regular(void)
+{
+ /* XXX */
+}
+
+/*
+ * This function is called on every keypress or mouse move, and
+ * will add the current time to the noise pool. It gets the scan
+ * code or mouse position passed in, and adds that too.
+ */
+void noise_ultralight(unsigned long data)
+{
+ UnsignedWide utc;
+
+ Microseconds(&utc);
+ random_add_noise(&utc, sizeof(utc));
+ random_add_noise(&data, sizeof(data));
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MACPGEN.C b/puttysrc/MAC/MACPGEN.C
new file mode 100644
index 0000000..7cfae5d
--- /dev/null
+++ b/puttysrc/MAC/MACPGEN.C
@@ -0,0 +1,593 @@
+/* $Id: macpgen.c 4787 2004-11-16 15:27:00Z simon $ */
+/*
+ * Copyright (c) 1999, 2003 Ben Harris
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * macpgen.c - PuTTYgen for Mac OS
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include /* putty.h needs size_t */
+#include /* for vsprintf */
+
+#define PUTTY_DO_GLOBALS
+
+#include "macpgrid.h"
+#include "putty.h"
+#include "ssh.h"
+#include "mac.h"
+
+static void mac_startup(void);
+static void mac_eventloop(void);
+#pragma noreturn (mac_eventloop)
+static void mac_event(EventRecord *);
+static void mac_contentclick(WindowPtr, EventRecord *);
+static void mac_growwindow(WindowPtr, EventRecord *);
+static void mac_activatewindow(WindowPtr, EventRecord *);
+static void mac_suspendresume(EventRecord *);
+static void mac_updatewindow(WindowPtr);
+static void mac_keypress(EventRecord *);
+static int mac_windowtype(WindowPtr);
+static void mac_menucommand(long);
+static void mac_adjustcursor(RgnHandle);
+static void mac_adjustmenus(void);
+static void mac_closewindow(WindowPtr);
+static void mac_zoomwindow(WindowPtr, short);
+#pragma noreturn (cleanup_exit)
+
+struct mac_windows {
+ WindowPtr about;
+ WindowPtr licence;
+};
+
+struct mac_windows windows;
+int borednow;
+struct mac_gestalts mac_gestalts;
+
+int main (int argc, char **argv) {
+
+ mac_startup();
+ mac_eventloop();
+}
+
+#pragma noreturn (main)
+
+static void mac_startup(void) {
+ Handle menuBar;
+ TECInfoHandle ti;
+
+#if !TARGET_API_MAC_CARBON
+ /* Init Memory Manager */
+ MaxApplZone();
+ /* Init QuickDraw */
+ InitGraf(&qd.thePort);
+ /* Init Font Manager */
+ InitFonts();
+ /* Init Window Manager */
+ InitWindows();
+ /* Init Menu Manager */
+ InitMenus();
+ /* Init TextEdit */
+ TEInit();
+ /* Init Dialog Manager */
+ InitDialogs(NULL);
+#endif
+
+ /* Get base system version (only used if there's no better selector) */
+ if (Gestalt(gestaltSystemVersion, &mac_gestalts.sysvers) != noErr ||
+ (mac_gestalts.sysvers &= 0xffff) < 0x700)
+ fatalbox("PuTTYgen requires System 7 or newer");
+ /* Find out if we've got Color Quickdraw */
+ if (Gestalt(gestaltQuickdrawVersion, &mac_gestalts.qdvers) != noErr)
+ mac_gestalts.qdvers = gestaltOriginalQD;
+ /* ... and the Appearance Manager? */
+ if (Gestalt(gestaltAppearanceVersion, &mac_gestalts.apprvers) != noErr)
+ if (Gestalt(gestaltAppearanceAttr, NULL) == noErr)
+ mac_gestalts.apprvers = 0x0100;
+ else
+ mac_gestalts.apprvers = 0;
+#if TARGET_RT_MAC_CFM
+ /* Paranoia: Did we manage to pull in AppearanceLib? */
+ if (&RegisterAppearanceClient == kUnresolvedCFragSymbolAddress)
+ mac_gestalts.apprvers = 0;
+#endif
+#if TARGET_CPU_68K
+ mac_gestalts.cntlattr = 0;
+ mac_gestalts.windattr = 0;
+#else
+ /* Mac OS 8.5 Control Manager (proportional scrollbars)? */
+ if (Gestalt(gestaltControlMgrAttr, &mac_gestalts.cntlattr) != noErr ||
+ &SetControlViewSize == kUnresolvedCFragSymbolAddress)
+ mac_gestalts.cntlattr = 0;
+ /* Mac OS 8.5 Window Manager? */
+ if (Gestalt(gestaltWindowMgrAttr, &mac_gestalts.windattr) != noErr ||
+ &SetWindowContentColor == kUnresolvedCFragSymbolAddress)
+ mac_gestalts.windattr = 0;
+#endif
+ /* Text Encoding Conversion Manager? */
+ if (
+#if TARGET_RT_MAC_CFM
+ &TECGetInfo == kUnresolvedCFragSymbolAddress ||
+#else
+ InitializeUnicodeConverter(NULL) != noErr ||
+#endif
+ TECGetInfo(&ti) != noErr)
+ mac_gestalts.encvvers = 0;
+ else {
+ mac_gestalts.encvvers = (*ti)->tecVersion;
+ mac_gestalts.uncvattr = (*ti)->tecUnicodeConverterFeatures;
+ DisposeHandle((Handle)ti);
+ }
+ /* Navigation Services? */
+ if (NavServicesAvailable())
+ mac_gestalts.navsvers = NavLibraryVersion();
+ else
+ mac_gestalts.navsvers = 0;
+
+ /* We've been tested with the Appearance Manager */
+ if (mac_gestalts.apprvers != 0)
+ RegisterAppearanceClient();
+
+ menuBar = GetNewMBar(128);
+ if (menuBar == NULL)
+ fatalbox("Unable to create menu bar.");
+ SetMenuBar(menuBar);
+ AppendResMenu(GetMenuHandle(mApple), 'DRVR');
+ mac_adjustmenus();
+ DrawMenuBar();
+ InitCursor();
+ windows.about = NULL;
+ windows.licence = NULL;
+
+ flags = FLAG_INTERACTIVE;
+
+ /* Install Apple Event handlers. */
+#if 0
+ AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
+ NewAEEventHandlerUPP(&mac_aevt_oapp), 0, FALSE);
+ AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
+ NewAEEventHandlerUPP(&mac_aevt_odoc), 0, FALSE);
+ AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
+ NewAEEventHandlerUPP(&mac_aevt_pdoc), 0, FALSE);
+#endif
+ AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerUPP(&mac_aevt_quit), 0, FALSE);
+}
+
+static void mac_eventloop(void) {
+ Boolean gotevent;
+ EventRecord event;
+ RgnHandle cursrgn;
+ Point mousenow, mousethen;
+ KeyState *ks;
+ WindowPtr front;
+
+ cursrgn = NewRgn();
+ GetMouse(&mousethen);
+ for (;;) {
+ mac_adjustcursor(cursrgn);
+ gotevent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursrgn);
+ mac_adjustcursor(cursrgn);
+ front = mac_frontwindow();
+ if (front != NULL) {
+ ks = mac_windowkey(front);
+ if (ks->collecting_entropy) {
+ GetMouse(&mousenow);
+ if (mousenow.h != mousethen.h || mousenow.v != mousethen.v) {
+ ks->entropy[ks->entropy_got++] = *(unsigned *)&mousenow;
+ ks->entropy[ks->entropy_got++] = TickCount();
+ if (ks->entropy_got >= ks->entropy_required)
+ ks->collecting_entropy = 0;
+ SetControlValue(ks->progress, ks->entropy_got);
+ mousethen = mousenow;
+ }
+ SetEmptyRgn(cursrgn);
+ }
+ }
+
+ if (gotevent)
+ mac_event(&event);
+ if (borednow)
+ cleanup_exit(0);
+ }
+ DisposeRgn(cursrgn);
+}
+
+static void mac_event(EventRecord *event) {
+ short part;
+ WindowPtr window;
+
+ switch (event->what) {
+ case mouseDown:
+ part = FindWindow(event->where, &window);
+ switch (part) {
+ case inMenuBar:
+ mac_adjustmenus();
+ mac_menucommand(MenuSelect(event->where));
+ break;
+#if !TARGET_API_MAC_CARBON
+ case inSysWindow:
+ SystemClick(event, window);
+ break;
+#endif
+ case inContent:
+ if (window != FrontWindow())
+ /* XXX: check for movable modal dboxes? */
+ SelectWindow(window);
+ else
+ mac_contentclick(window, event);
+ break;
+ case inGoAway:
+ if (TrackGoAway(window, event->where))
+ mac_closewindow(window);
+ break;
+ case inDrag:
+ /* XXX: moveable modal check? */
+#if TARGET_API_MAC_CARBON
+ {
+ BitMap screenBits;
+
+ GetQDGlobalsScreenBits(&screenBits);
+ DragWindow(window, event->where, &screenBits.bounds);
+ }
+#else
+ DragWindow(window, event->where, &qd.screenBits.bounds);
+#endif
+ break;
+ case inGrow:
+ mac_growwindow(window, event);
+ break;
+ case inZoomIn:
+ case inZoomOut:
+ if (TrackBox(window, event->where, part))
+ mac_zoomwindow(window, part);
+ break;
+ }
+ break;
+ case keyDown:
+ case autoKey:
+ mac_keypress(event);
+ break;
+ case activateEvt:
+ mac_activatewindow((WindowPtr)event->message, event);
+ break;
+ case updateEvt:
+ mac_updatewindow((WindowPtr)event->message);
+ break;
+#if !TARGET_API_MAC_CARBON
+ case diskEvt:
+ if (HiWord(event->message) != noErr) {
+ Point pt;
+
+ SetPt(&pt, 120, 120);
+ DIBadMount(pt, event->message);
+ }
+ break;
+#endif
+ case osEvt:
+ switch ((event->message & osEvtMessageMask) >> 24) {
+ case suspendResumeMessage:
+ mac_suspendresume(event);
+ break;
+ }
+ break;
+ case kHighLevelEvent:
+ AEProcessAppleEvent(event); /* errors? */
+ break;
+ }
+}
+
+static void mac_contentclick(WindowPtr window, EventRecord *event)
+{
+
+ if (mac_wininfo(window)->click != NULL)
+ (*mac_wininfo(window)->click)(window, event);
+}
+
+static void mac_growwindow(WindowPtr window, EventRecord *event)
+{
+
+ if (mac_wininfo(window)->grow != NULL)
+ (*mac_wininfo(window)->grow)(window, event);
+}
+
+static void mac_activatewindow(WindowPtr window, EventRecord *event)
+{
+
+ mac_adjustmenus();
+ if (mac_wininfo(window)->activate != NULL)
+ (*mac_wininfo(window)->activate)(window, event);
+}
+
+static void mac_updatewindow(WindowPtr window)
+{
+
+ if (mac_wininfo(window)->update != NULL)
+ (*mac_wininfo(window)->update)(window);
+}
+
+/*
+ * Work out what kind of window we're dealing with.
+ */
+static int mac_windowtype(WindowPtr window)
+{
+
+#if !TARGET_API_MAC_CARBON
+ if (GetWindowKind(window) < 0)
+ return wDA;
+#endif
+ return ((WinInfo *)GetWRefCon(window))->wtype;
+}
+
+/*
+ * Handle a key press
+ */
+static void mac_keypress(EventRecord *event)
+{
+ WindowPtr window;
+
+ window = FrontWindow();
+ if (event->what == keyDown && (event->modifiers & cmdKey)) {
+ mac_adjustmenus();
+ mac_menucommand(MenuKey(event->message & charCodeMask));
+ } else {
+ if (mac_wininfo(window)->key != NULL)
+ (*mac_wininfo(window)->key)(window, event);
+ }
+}
+
+static void mac_menucommand(long result)
+{
+ short menu, item;
+ WindowPtr window;
+#if !TARGET_API_MAC_CARBON
+ Str255 da;
+#endif
+
+ menu = HiWord(result);
+ item = LoWord(result);
+ window = FrontWindow();
+ /* Things which do the same whatever window we're in. */
+ switch (menu) {
+ case mApple:
+ switch (item) {
+ case iAbout:
+ mac_openabout();
+ goto done;
+#if !TARGET_API_MAC_CARBON
+ default:
+ GetMenuItemText(GetMenuHandle(mApple), item, da);
+ OpenDeskAcc(da);
+ goto done;
+#endif
+ }
+ break;
+ case mFile:
+ switch (item) {
+ case iNew:
+ mac_newkey();
+ goto done;
+ case iClose:
+ mac_closewindow(window);
+ goto done;
+ case iQuit:
+ cleanup_exit(0);
+ goto done;
+ }
+ break;
+ }
+ /* If we get here, handling is up to window-specific code. */
+ if (mac_wininfo(window)->menu != NULL)
+ (*mac_wininfo(window)->menu)(window, menu, item);
+
+ done:
+ HiliteMenu(0);
+}
+
+static void mac_closewindow(WindowPtr window)
+{
+
+ switch (mac_windowtype(window)) {
+#if !TARGET_API_MAC_CARBON
+ case wDA:
+ CloseDeskAcc(GetWindowKind(window));
+ break;
+#endif
+ default:
+ if (mac_wininfo(window)->close != NULL)
+ (*mac_wininfo(window)->close)(window);
+ }
+}
+
+static void mac_suspendresume(EventRecord *event)
+{
+ WindowPtr front;
+ EventRecord fakeevent;
+
+ /*
+ * We're called either before we're suspended or after we're
+ * resumed, so we're the front application at this point.
+ */
+ front = FrontWindow();
+ if (front != NULL) {
+ fakeevent.what = activateEvt;
+ fakeevent.message = (UInt32)front;
+ fakeevent.when = event->when;
+ fakeevent.where = event->where;
+ fakeevent.modifiers =
+ (event->message & resumeFlag) ? activeFlag : 0;
+ mac_activatewindow(front, &fakeevent);
+ }
+}
+
+static void mac_zoomwindow(WindowPtr window, short part) {
+
+ /* FIXME: do something */
+}
+
+/*
+ * Make the menus look right before the user gets to see them.
+ */
+#if TARGET_API_MAC_CARBON
+#define EnableItem EnableMenuItem
+#define DisableItem DisableMenuItem
+#endif
+static void mac_adjustmenus(void) {
+ WindowPtr window;
+ MenuHandle menu;
+
+ window = FrontWindow();
+ menu = GetMenuHandle(mApple);
+ EnableItem(menu, 0);
+ EnableItem(menu, iAbout);
+
+ menu = GetMenuHandle(mFile);
+ EnableItem(menu, 0);
+ EnableItem(menu, iNew);
+ if (window != NULL)
+ EnableItem(menu, iClose);
+ else
+ DisableItem(menu, iClose);
+ EnableItem(menu, iQuit);
+
+ if (mac_wininfo(window)->adjustmenus != NULL)
+ (*mac_wininfo(window)->adjustmenus)(window);
+ else {
+ DisableItem(menu, iSave);
+ DisableItem(menu, iSaveAs);
+ menu = GetMenuHandle(mEdit);
+ DisableItem(menu, 0);
+ menu = GetMenuHandle(mWindow);
+ DisableItem(menu, 0); /* Until we get more than 1 item on it. */
+ }
+ DrawMenuBar();
+}
+
+/*
+ * Make sure the right cursor's being displayed.
+ */
+static void mac_adjustcursor(RgnHandle cursrgn)
+{
+ Point mouse;
+ WindowPtr window, front;
+ short part;
+#if TARGET_API_MAC_CARBON
+ Cursor arrow;
+ RgnHandle visrgn;
+#endif
+
+ GetMouse(&mouse);
+ LocalToGlobal(&mouse);
+ part = FindWindow(mouse, &window);
+ front = FrontWindow();
+ if (part != inContent || window == NULL || window != front) {
+ /* Cursor isn't in the front window, so switch to arrow */
+#if TARGET_API_MAC_CARBON
+ GetQDGlobalsArrow(&arrow);
+ SetCursor(&arrow);
+#else
+ SetCursor(&qd.arrow);
+#endif
+ SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
+ if (front != NULL) {
+#if TARGET_API_MAC_CARBON
+ visrgn = NewRgn();
+ GetPortVisibleRegion(GetWindowPort(front), visrgn);
+ DiffRgn(cursrgn, visrgn, cursrgn);
+ DisposeRgn(visrgn);
+#else
+ DiffRgn(cursrgn, front->visRgn, cursrgn);
+#endif
+ }
+ } else {
+ if (mac_wininfo(window)->adjustcursor != NULL)
+ (*mac_wininfo(window)->adjustcursor)(window, mouse, cursrgn);
+ else {
+#if TARGET_API_MAC_CARBON
+ GetQDGlobalsArrow(&arrow);
+ SetCursor(&arrow);
+ GetPortVisibleRegion(GetWindowPort(window), cursrgn);
+#else
+ SetCursor(&qd.arrow);
+ CopyRgn(window->visRgn, cursrgn);
+#endif
+ }
+ }
+}
+
+pascal OSErr mac_aevt_quit(const AppleEvent *req, AppleEvent *reply,
+ long refcon)
+{
+ DescType type;
+ Size size;
+
+ if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
+ &type, NULL, 0, &size) == noErr)
+ return errAEParamMissed;
+
+ borednow = 1;
+ return noErr;
+}
+
+void cleanup_exit(int status)
+{
+
+#if !TARGET_RT_MAC_CFM
+ if (mac_gestalts.encvvers != 0)
+ TerminateUnicodeConverter();
+#endif
+ exit(status);
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MACPGEN.R b/puttysrc/MAC/MACPGEN.R
new file mode 100644
index 0000000..6cb4f8f
--- /dev/null
+++ b/puttysrc/MAC/MACPGEN.R
@@ -0,0 +1,509 @@
+/* $Id: macpgen.r 7048 2007-01-01 21:19:14Z jacob $ */
+/*
+ * Copyright (c) 1999, 2002, 2003 Ben Harris
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* PuTTYgen resources */
+
+/*
+ * The space after the # for system includes is to stop mkfiles.pl
+ * trying to chase them (Rez doesn't support the angle-bracket
+ * syntax).
+ */
+
+# include "Types.r"
+# include "Dialogs.r"
+# include "Palettes.r"
+# include "Script.r"
+
+
+/* Get resource IDs we share with C code */
+#include "macpgrid.h"
+
+#include "version.r"
+
+/*
+ * Finder-related resources
+ */
+
+/* 'pGen' is now registered with Apple as PuTTYgen's signature */
+
+type 'pGen' as 'STR ';
+
+resource 'pGen' (0, purgeable) {
+ "PuTTYgen experimental Mac port"
+};
+
+resource 'SIZE' (-1) {
+ reserved,
+ acceptSuspendResumeEvents,
+ reserved,
+ canBackground,
+ doesActivateOnFGSwitch,
+ backgroundAndForeground,
+ dontGetFrontClicks,
+ ignoreAppDiedEvents,
+ is32BitCompatible,
+ isHighLevelEventAware,
+ localandRemoteHLEvents,
+ isStationeryAware,
+ dontUseTextEditServices,
+ reserved,
+ reserved,
+ reserved,
+ 1024 * 1024, /* Minimum size */
+ 1024 * 1024, /* Preferred size */
+};
+
+#define FREF_APPL 128
+#define FREF_Seed 132
+
+resource 'FREF' (FREF_APPL, purgeable) {
+ /* The application itself */
+ 'APPL', FREF_APPL, ""
+};
+
+resource 'FREF' (FREF_Seed, purgeable) {
+ /* Random seed */
+ 'Seed', FREF_Seed, ""
+};
+
+/* "Internal" file types, which can't be opened */
+resource 'BNDL' (129, purgeable) {
+ 'pTTI', 0,
+ {
+ 'ICN#', {
+ FREF_Seed, FREF_Seed,
+ },
+ 'FREF', {
+ FREF_Seed, FREF_Seed,
+ };
+ };
+};
+
+resource 'kind' (129) {
+ 'pTTI',
+ verBritain,
+ {
+ 'Seed', "PuTTY random number seed",
+ }
+};
+
+#if TARGET_API_MAC_CARBON
+/*
+ * Mac OS X Info.plist.
+ * See Tech Note TN2013 for details.
+ * We don't bother with things that Mac OS X seems to be able to get from
+ * other resources.
+ */
+type 'plst' as 'TEXT';
+
+resource 'plst' (0) {
+ "\n"
+ "\n"
+ "\n"
+ " \n"
+ " CFBundleInfoDictionaryVersion6.0\n"
+ " CFBundleIdentifier\n"
+ " org.tartarus.projects.putty.puttygen\n"
+ " CFBundleNamePuTTYgen\n"
+ " CFBundlePackageTypeAPPL\n"
+ " CFBundleSignaturepGen\n"
+ " \n"
+ "\n"
+};
+
+/* Mac OS X doesn't use this, but Mac OS 9 does. */
+type 'carb' as 'TEXT';
+resource 'carb' (0) { "" };
+#endif
+
+/* Icons, courtesy of DeRez */
+
+/* Random seed icon */
+
+resource 'ICN#' (FREF_Seed, purgeable) {
+ { /* array: 2 elements */
+ /* [1] */
+ $"1FFFFC00 18F36600 161EF500 1CC92C80"
+ $"1CF2EC40 10662C20 108E07F0 151F0490"
+ $"1E00C4F0 1803BBD0 1FC5BE10 108B5A90"
+ $"1B3C4F50 1267AC90 14B60470 1BB791B0"
+ $"17F4D2B0 1DC1F830 1B029450 1B753DD0"
+ $"145A8170 11390DD0 1E15A8B0 1CC4CD90"
+ $"154ECED0 15C9CF30 172CDB50 12617970"
+ $"15E45C90 1D4B9890 15CE4430 1FFFFFF0",
+ /* [2] */
+ $"1FFFFC00 1FFFFE00 1FFFFF00 1FFFFF80"
+ $"1FFFFFC0 1FFFFFE0 1FFFFFF0 1FFFFFF0"
+ $"1FFFFFF0 1FFFFFF0 1FFFFFF0 1FFFFFF0"
+ $"1FFFFFF0 1FFFFFF0 1FFFFFF0 1FFFFFF0"
+ $"1FFFFFF0 1FFFFFF0 1FFFFFF0 1FFFFFF0"
+ $"1FFFFFF0 1FFFFFF0 1FFFFFF0 1FFFFFF0"
+ $"1FFFFFF0 1FFFFFF0 1FFFFFF0 1FFFFFF0"
+ $"1FFFFFF0 1FFFFFF0 1FFFFFF0 1FFFFFF0"
+ }
+};
+resource 'icl4' (FREF_Seed) {
+ $"000FFFFFFFFFFFFFFFFFFF0000000000"
+ $"000FFC0CFFFF0CFF1FFC0FF000000000"
+ $"000F0FF0C0CFFFF1FFFFCFCF00000000"
+ $"000FFF0CFF0CF11F0CFCFFCCF0000000"
+ $"000FFFC0FFFF11F0FFF0FFCCCF000000"
+ $"000F0C0C0FF11FFC0CFCFFCCCCF00000"
+ $"000FC0C0F111FFF0C0C0CFFFFFFF0000"
+ $"000F0F0F111FFFFF0C0C0F0CFC0F0000"
+ $"000FFFF111111111FFC0CFC0FFFF0000"
+ $"000FF111111111FFFCFFF0FFFF0F0000"
+ $"000FFFFFFF111FCFF0FFFFF0C0CF0000"
+ $"000F0C0CF111FCFF0F0FFCFCFC0F0000"
+ $"000FF0FF11FFFFC0CFC0FFFFCFCF0000"
+ $"000F0CF11FFC0FFFFCFCFF0CFC0F0000"
+ $"000FCF11F0FFCFF0C0C0CFC0CFFF0000"
+ $"000FF1FFFCFF0FFFFC0F0C0FFCFF0000"
+ $"000F1FFFFFFFCFC0FFCFC0F0F0FF0000"
+ $"000FFF0FFF0C0C0FFFFFFC0C0CFF0000"
+ $"000FF0FFC0C0C0F0F0CF0FC0CFCF0000"
+ $"000FFCFF0FFF0F0F0CFFFF0FFF0F0000"
+ $"000FCFC0CF0FF0F0F0C0C0CFCFFF0000"
+ $"000F0C0F0CFFFC0F0C0CFF0FFF0F0000"
+ $"000FFFF0C0CFCFCFF0F0F0C0F0FF0000"
+ $"000FFF0CFF0C0F0CFF0CFF0FFC0F0000"
+ $"000FCFCF0FC0FFF0FFC0FFF0FFCF0000"
+ $"000F0F0FFF0CFC0FFF0CFFFF0CFF0000"
+ $"000FCFFFC0F0FFC0FFCFF0FFCFCF0000"
+ $"000F0CFC0FFC0C0F0FFFFC0F0FFF0000"
+ $"000FCFCFFFF0CFC0CFCFFFC0F0CF0000"
+ $"000FFF0F0F0CF0FFFC0FFC0CFC0F0000"
+ $"000FCFCFFFC0FFF0CFC0CFC0C0FF0000"
+ $"000FFFFFFFFFFFFFFFFFFFFFFFFF"
+};
+resource 'icl8' (FREF_Seed) {
+ $"000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000"
+ $"000000FFFFF5F5F5FFFFFFFFF5F5FFFF05FFFFF5F5FFFF000000000000000000"
+ $"000000FFF5FFFFF5F5F5F5FFFFFFFF05FFFFFFFFF5FF2BFF0000000000000000"
+ $"000000FFFFFFF5F5FFFFF5F5FF0505FF0000FFF5FFFF2B2BFF00000000000000"
+ $"000000FFFFFFF5F5FFFFFFFF0505FFF5FFFFFFF5FFFF2B2B2BFF000000000000"
+ $"000000FFF5F5F5F5F5FFFF0505FFFFF5F5F5FFF5FFFF2B2B2B2BFF0000000000"
+ $"000000FFF5F5F5F5FF050505FFFFFFF5F5F5F5F5F5FFFFFFFFFFFFFF00000000"
+ $"000000FFF5FFF5FF050505FFFFFFFFFFF5F5F5F5F5FFF5F5FFF5F5FF00000000"
+ $"000000FFFFFFFF050505050505050505FFFFF5F5F5FFF5F5FFFFFFFF00000000"
+ $"000000FFFF050505050505050505FFFFFFF5FFFFFFF5FFFFFFFFF5FF00000000"
+ $"000000FFFFFFFFFFFFFF050505FFF5FFFFF5FFFFFFFFFFF5F5F5F5FF00000000"
+ $"000000FFF5F5F5F5FF050505FFF5FFFFF5FFF5FFFFF5FFF5FFF5F5FF00000000"
+ $"000000FFFFF5FFFF0505FFFFFFFFF5F5F5FFF5F5FFFFFFFFF5FFF5FF00000000"
+ $"000000FFF5F5FF0505FFFFF5F5FFFFFFFFF5FFF5FFFFF5F5FFF5F5FF00000000"
+ $"000000FFF5FF0505FFF5FFFFF5FFFFF5F5F5F5F5F5FFF5F5F5FFFFFF00000000"
+ $"000000FFFF05FFFFFFF5FFFFF5FFFFFFFFF5F5FFF5F5F5FFFFF5FFFF00000000"
+ $"000000FF05FFFFFFFFFFFFFFF5FFF5F5FFFFF5FFF5F5FFF5FFF5FFFF00000000"
+ $"000000FFFFFFF5FFFFFFF5F5F5F5F5FFFFFFFFFFFFF5F5F5F5F5FFFF00000000"
+ $"000000FFFFF5FFFFF5F5F5F5F5F5FF00FFF5F5FFF5FFF5F5F5FFF5FF00000000"
+ $"000000FFFFF5FFFFF5FFFFFFF5FF00FFF5F5FFFFFFFFF5FFFFFFF5FF00000000"
+ $"000000FFF5FFF5F5F5FFF5FFFF00FF00FFF5F5F5F5F5F5FFF5FFFFFF00000000"
+ $"000000FFF5F5F5FFF5F5FFFFFF0000FFF5F5F5F5FFFFF5FFFFFF00FF00000000"
+ $"000000FFFFFFFFF5F5F5F5FFF5FF00FFFFF5FFF5FFF5F5F5FF00FFFF00000000"
+ $"000000FFFFFFF5F5FFFFF5F5F5FF0000FFFFF5F5FFFFF5FFFF0000FF00000000"
+ $"000000FFF5FFF5FFF5FFF5F5FFFFFF00FFFFF5F5FFFFFFF5FFFF00FF00000000"
+ $"000000FFF5FFF5FFFFFFF5F5FFF5F5FFFFFFF5F5FFFFFFFFF5F5FFFF00000000"
+ $"000000FFF5FFFFFFF5F5FFF5FFFFF5F5FFFFF5FFFFF5FFFFF5FFF5FF00000000"
+ $"000000FFF5F5FFF5F5FFFFF5F5F5F5FFF5FFFFFFFFF5F5FFF5FFFFFF00000000"
+ $"000000FFF5FFF5FFFFFFFFF5F5FFF5F5F5FFF5FFFFFFF5F5FFF5F5FF00000000"
+ $"000000FFFFFFF5FFF5FFF5F5FFF5FFFFFFF5F5FFFFF5F5F5FFF5F5FF00000000"
+ $"000000FFF5FFF5FFFFFFF5F5FFFFFFF5F5FFF5F5F5FFF5F5F5F5FFFF00000000"
+ $"000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+};
+resource 'ics#' (FREF_Seed) {
+ { /* array: 2 elements */
+ /* [1] */
+ $"7FE0 56B0 59A8 637C 51DC 6794 59AC 76EC"
+ $"7224 7C6C 743C 71AC 505C 459C 4424 7FFC",
+ /* [2] */
+ $"7FE0 7FF0 7FF8 7FFC 7FFC 7FFC 7FFC 7FFC"
+ $"7FFC 7FFC 7FFC 7FFC 7FFC 7FFC 7FFC 7FFC"
+ }
+};
+resource 'ics4' (FREF_Seed) {
+ $"0FFFFFFFFFF00000"
+ $"0F0F0FF1FCFF0000"
+ $"0FCFF11FF0FCF000"
+ $"0FF111FF0FFFFF00"
+ $"0FCF111FFFCFFF00"
+ $"0FF11FFFFC0F0F00"
+ $"0F1FF0CFF0F0FF00"
+ $"0FFF0FFCFFFCFF00"
+ $"0FFFC0F0C0F0CF00"
+ $"0FFFFF0C0FFCFF00"
+ $"0FFFCFC0C0FFFF00"
+ $"0FFF0C0FFCFCFF00"
+ $"0FCFC0C0CFCFFF00"
+ $"0F0C0F0FFC0FFF00"
+ $"0FC0CFC0C0F0CF00"
+ $"0FFFFFFFFFFFFF"
+};
+resource 'ics8' (FREF_Seed) {
+ $"00FFFFFFFFFFFFFFFFFFFF0000000000"
+ $"00FFF5FFF5FFFF05FFF5FFFF00000000"
+ $"00FFF5FFFF0505FFFFF5FF2BFF000000"
+ $"00FFFF050505FFFFF5FFFFFFFFFF0000"
+ $"00FFF5FF050505FFFFFFF5FFFFFF0000"
+ $"00FFFF0505FFFFFFFFF5F5FFF5FF0000"
+ $"00FF05FFFFF5F5FFFFF5FFF5FFFF0000"
+ $"00FFFFFFF5FFFFF5FFFFFFF5FFFF0000"
+ $"00FFFFFFF5F5FFF5F5F5FFF5F5FF0000"
+ $"00FFFFFFFFFFF5F5F5FFFFF5FFFF0000"
+ $"00FFFFFFF5FFF5F5F5F5FFFFFFFF0000"
+ $"00FFFFFFF5F5F5FFFFF5FFF5FFFF0000"
+ $"00FFF5FFF5F5F5F5F5FFF5FFFFFF0000"
+ $"00FFF5F5F5FFF5FFFFF5F5FFFFFF0000"
+ $"00FFF5F5F5FFF5F5F5F5FFF5F5FF0000"
+ $"00FFFFFFFFFFFFFFFFFFFFFFFFFF"
+};
+
+/*
+ * Application-missing message string, for random seed and host key database
+ * files.
+ */
+resource 'STR ' (-16397, purgeable) {
+ "This file is used internally by PuTTY. It cannot be opened."
+};
+
+/* Missing-application name string, for private keys. */
+/* XXX Private keys should eventually be owned by Pageant */
+resource 'STR ' (-16396, purgeable) {
+ "PuTTYgen"
+};
+
+/*
+ * Internal resources
+ */
+
+/* Menu bar */
+
+resource 'MBAR' (MBAR_Main, preload) {
+ { mApple, mFile, mEdit, mWindow }
+};
+
+resource 'MENU' (mApple, preload) {
+ mApple,
+ textMenuProc,
+ 0b11111111111111111111111111111101,
+ enabled,
+ apple,
+ {
+ "About PuTTYgen\0xc9", noicon, nokey, nomark, plain,
+ "-", noicon, nokey, nomark, plain,
+ }
+};
+
+resource 'MENU' (mFile, preload) {
+ mFile,
+ textMenuProc,
+ 0b11111111111111111111111101111011,
+ enabled,
+ "File",
+ {
+ "New", noicon, "N", nomark, plain,
+ "Open\0xc9", noicon, "O", nomark, plain,
+ "-", noicon, nokey, nomark, plain,
+ "Close", noicon, "W", nomark, plain,
+ "Save", noicon, "S", nomark, plain,
+ "Save As\0xc9", noicon, nokey, nomark, plain,
+ "-", noicon, nokey, nomark, plain,
+ "Quit", noicon, "Q", nomark, plain,
+ }
+};
+
+resource 'MENU' (mEdit, preload) {
+ mEdit,
+ textMenuProc,
+ 0b11111111111111111111111111111101,
+ enabled,
+ "Edit",
+ {
+ "Undo", noicon, "Z", nomark, plain,
+ "-", noicon, nokey, nomark, plain,
+ "Cut", noicon, "X", nomark, plain,
+ "Copy", noicon, "C", nomark, plain,
+ "Paste", noicon, "V", nomark, plain,
+ "Clear", noicon, nokey, nomark, plain,
+ "Select All", noicon, "A", nomark, plain,
+ }
+};
+
+resource 'MENU' (mWindow, preload) {
+ mWindow,
+ textMenuProc,
+ 0b11111111111111111111111111111111,
+ enabled,
+ "Window",
+ {
+ }
+};
+
+/* Fatal error box. Stolen from the Finder. */
+
+resource 'ALRT' (wFatal, "fatalbox", purgeable) {
+ {54, 67, 152, 435},
+ wFatal,
+ beepStages,
+ alertPositionMainScreen
+};
+
+resource 'DITL' (wFatal, "fatalbox", purgeable) {
+ { /* array DITLarray: 3 elements */
+ /* [1] */
+ {68, 299, 88, 358},
+ Button {
+ enabled,
+ "OK"
+ },
+ /* [2] */
+ {68, 227, 88, 286},
+ StaticText {
+ disabled,
+ ""
+ },
+ /* [3] */
+ {7, 74, 55, 358},
+ StaticText {
+ disabled,
+ "^0"
+ }
+ }
+};
+
+/* "About" box */
+
+resource 'DLOG' (wAbout, "about", purgeable) {
+ { 0, 0, 120, 240 },
+ noGrowDocProc,
+ invisible,
+ goAway,
+ wAbout, /* RefCon -- identifies the window to PuTTY */
+ wAbout, /* DITL ID */
+ "About PuTTYgen",
+ alertPositionMainScreen
+};
+
+resource 'dlgx' (wAbout, "about", purgeable) {
+ versionZero {
+ kDialogFlagsUseThemeBackground | kDialogFlagsUseThemeControls
+ }
+};
+
+resource 'DITL' (wAbout, "about", purgeable) {
+ {
+ { 87, 13, 107, 227 },
+ Button { enabled, "View Licence" },
+ { 13, 13, 29, 227 },
+ StaticText { disabled, "PuTTYgen"},
+ { 42, 13, 74, 227 },
+ StaticText { disabled, "Some version or other\n"
+ "Copyright 1997-2007 Simon Tatham"},
+ }
+};
+
+/* Licence box */
+
+resource 'WIND' (wLicence, "licence", purgeable) {
+ { 0, 0, 250, 400 },
+ noGrowDocProc,
+ visible,
+ goAway,
+ wLicence,
+ "PuTTYgen Licence",
+ alertPositionParentWindowScreen
+};
+
+type 'TEXT' {
+ string;
+};
+
+resource 'TEXT' (wLicence, "licence", purgeable) {
+ "Copyright 1997-2007 Simon Tatham.\n"
+ "\n"
+ "Portions copyright Robert de Bath, Joris van Rantwijk, Delian "
+ "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, "
+ "Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus "
+ "Kuhn, and CORE SDI S.A.\n"
+ "\n"
+ "Permission is hereby granted, free of charge, to any person "
+ "obtaining a copy of this software and associated documentation "
+ "files (the \"Software\"), to deal in the Software without "
+ "restriction, including without limitation the rights to use, "
+ "copy, modify, merge, publish, distribute, sublicense, and/or "
+ "sell copies of the Software, and to permit persons to whom the "
+ "Software is furnished to do so, subject to the following "
+ "conditions:\n\n"
+
+ "The above copyright notice and this permission notice shall be "
+ "included in all copies or substantial portions of the Software.\n\n"
+
+ "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
+ "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
+ "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND "
+ "NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR "
+ "ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF "
+ "CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN "
+ "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE "
+ "SOFTWARE."
+};
+
+/* Key box */
+
+resource 'DLOG' (wKey, "key", purgeable) {
+ { 0, 0, 120, 240 },
+ noGrowDocProc,
+ invisible,
+ goAway,
+ wKey, /* RefCon -- identifies the window to PuTTY */
+ wKey, /* DITL ID */
+ "untitled",
+ staggerParentWindowScreen
+};
+
+resource 'dlgx' (wKey, "key", purgeable) {
+ versionZero {
+ kDialogFlagsUseThemeBackground | kDialogFlagsUseThemeControls
+ }
+};
+
+#define cProgress 129
+
+resource 'DITL' (wKey, "key", purgeable) {
+ {
+ { 13, 13, 33, 227 },
+ Button { enabled, "Generate" },
+ { 46, 13, 12, 227 },
+ Control { enabled, cProgress },
+ }
+};
+
+resource 'CNTL' (cProgress) {
+ { 46, 13, 12, 227 },
+ 0, visible, 0, 0,
+ kControlProgressBarProc, 0, ""
+};
diff --git a/puttysrc/MAC/MACPGKEY.C b/puttysrc/MAC/MACPGKEY.C
new file mode 100644
index 0000000..053b318
--- /dev/null
+++ b/puttysrc/MAC/MACPGKEY.C
@@ -0,0 +1,196 @@
+/* $Id: macpgkey.c 4787 2004-11-16 15:27:00Z simon $ */
+/*
+ * Copyright (c) 2003 Ben Harris
+ * Copyright (c) 1997-2003 Simon Tatham
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* Stuff to handle the key window in PuTTYgen */
+
+#include
+#include
+#include
+#include
+
+#include "putty.h"
+#include "mac.h"
+#include "macpgrid.h"
+#include "ssh.h"
+
+/* ----------------------------------------------------------------------
+ * Progress report code. This is really horrible :-)
+ */
+#define PROGRESSRANGE 65535
+#define MAXPHASE 5
+struct progress {
+ int nphases;
+ struct {
+ int exponential;
+ unsigned startpoint, total;
+ unsigned param, current, n; /* if exponential */
+ unsigned mult; /* if linear */
+ } phases[MAXPHASE];
+ unsigned total, divisor, range;
+ ControlHandle progbar;
+};
+
+static void progress_update(void *param, int action, int phase, int iprogress)
+{
+ struct progress *p = (struct progress *) param;
+ unsigned progress = iprogress;
+ int position;
+
+ if (action < PROGFN_READY && p->nphases < phase)
+ p->nphases = phase;
+ switch (action) {
+ case PROGFN_INITIALISE:
+ p->nphases = 0;
+ break;
+ case PROGFN_LIN_PHASE:
+ p->phases[phase-1].exponential = 0;
+ p->phases[phase-1].mult = p->phases[phase].total / progress;
+ break;
+ case PROGFN_EXP_PHASE:
+ p->phases[phase-1].exponential = 1;
+ p->phases[phase-1].param = 0x10000 + progress;
+ p->phases[phase-1].current = p->phases[phase-1].total;
+ p->phases[phase-1].n = 0;
+ break;
+ case PROGFN_PHASE_EXTENT:
+ p->phases[phase-1].total = progress;
+ break;
+ case PROGFN_READY:
+ {
+ unsigned total = 0;
+ int i;
+ for (i = 0; i < p->nphases; i++) {
+ p->phases[i].startpoint = total;
+ total += p->phases[i].total;
+ }
+ p->total = total;
+ p->divisor = ((p->total + PROGRESSRANGE - 1) / PROGRESSRANGE);
+ p->range = p->total / p->divisor;
+ SetControlMaximum(p->progbar, p->range);
+ }
+ break;
+ case PROGFN_PROGRESS:
+ if (p->phases[phase-1].exponential) {
+ while (p->phases[phase-1].n < progress) {
+ p->phases[phase-1].n++;
+ p->phases[phase-1].current *= p->phases[phase-1].param;
+ p->phases[phase-1].current /= 0x10000;
+ }
+ position = (p->phases[phase-1].startpoint +
+ p->phases[phase-1].total - p->phases[phase-1].current);
+ } else {
+ position = (p->phases[phase-1].startpoint +
+ progress * p->phases[phase-1].mult);
+ }
+ SetControlValue(p->progbar, position / p->divisor);
+ break;
+ }
+}
+
+static void mac_clickkey(WindowPtr window, EventRecord *event)
+{
+ short item;
+ DialogRef dialog;
+ KeyState *ks = mac_windowkey(window);
+
+ dialog = GetDialogFromWindow(window);
+ if (DialogSelect(event, &dialog, &item))
+ switch (item) {
+ case wiKeyGenerate:
+ SetControlMaximum(ks->progress, 1024);
+ ks->entropy = snewn(1024, unsigned int);
+ ks->entropy_required = 1024;
+ ks->entropy_got = 0;
+ ks->collecting_entropy = TRUE;
+ /* Do something */
+ break;
+ }
+}
+
+static void mac_activatekey(WindowPtr window, EventRecord *event)
+{
+ DialogRef dialog;
+ DialogItemType itemtype;
+ Handle itemhandle;
+ short item;
+ Rect itemrect;
+ int active;
+
+ dialog = GetDialogFromWindow(window);
+ active = (event->modifiers & activeFlag) != 0;
+ GetDialogItem(dialog, wiKeyGenerate, &itemtype, &itemhandle, &itemrect);
+ HiliteControl((ControlHandle)itemhandle, active ? 0 : 255);
+ DialogSelect(event, &dialog, &item);
+}
+
+static void mac_updatekey(WindowPtr window)
+{
+#if TARGET_API_MAC_CARBON
+ RgnHandle rgn;
+#endif
+
+ BeginUpdate(window);
+#if TARGET_API_MAC_CARBON
+ rgn = NewRgn();
+ GetPortVisibleRegion(GetWindowPort(window), rgn);
+ UpdateDialog(GetDialogFromWindow(window), rgn);
+ DisposeRgn(rgn);
+#else
+ UpdateDialog(window, window->visRgn);
+#endif
+ EndUpdate(window);
+}
+
+void mac_newkey(void)
+{
+ KeyState *ks;
+ WinInfo *wi;
+ Handle h;
+ short type;
+ Rect rect;
+
+ ks = snew(KeyState);
+ ks->box = GetNewDialog(wKey, NULL, (WindowPtr)-1);
+ GetDialogItem(ks->box, wiKeyProgress, &type, &h, &rect);
+ ks->progress = (ControlHandle)h;
+ wi = snew(WinInfo);
+ memset(wi, 0, sizeof(*wi));
+ wi->ks = ks;
+ wi->wtype = wKey;
+ wi->update = &mac_updatekey;
+ wi->click = &mac_clickkey;
+ wi->activate = &mac_activatekey;
+ SetWRefCon(GetDialogWindow(ks->box), (long)wi);
+ ShowWindow(GetDialogWindow(ks->box));
+}
+
+/*
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MACPGRID.H b/puttysrc/MAC/MACPGRID.H
new file mode 100644
index 0000000..01fcaed
--- /dev/null
+++ b/puttysrc/MAC/MACPGRID.H
@@ -0,0 +1,48 @@
+/* $Id: macpgrid.h 4787 2004-11-16 15:27:00Z simon $ */
+
+/*
+ * macpgrid.h -- Mac resource IDs for PuTTYgen
+ *
+ * This file is shared by C and Rez source files
+ */
+
+/* Menu bar IDs */
+#define MBAR_Main 128
+
+/* Menu IDs */
+#define mApple 128
+#define mFile 129
+#define mEdit 130
+#define mWindow 131
+
+/* Menu Items */
+/* Apple menu */
+#define iAbout 1
+/* File menu */
+#define iNew 1
+#define iOpen 2
+#define iClose 4
+#define iSave 5
+#define iSaveAs 6
+#define iQuit 8
+/* Edit menu */
+#define iUndo 1
+#define iCut 3
+#define iCopy 4
+#define iPaste 5
+#define iClear 6
+#define iSelectAll 7
+/* Window menu */
+
+/* Window types (and resource IDs) */
+#define wNone 0 /* Dummy value for no window */
+#define wDA 1 /* Dummy value for desk accessory */
+#define wFatal 128
+#define wAbout 129
+#define wiAboutLicence 1
+#define wiAboutVersion 3
+#define wLicence 131
+#define wKey 134
+#define wiKeyGenerate 1
+#define wiKeyProgress 2
+
diff --git a/puttysrc/MAC/MACRESID.H b/puttysrc/MAC/MACRESID.H
new file mode 100644
index 0000000..cca9429
--- /dev/null
+++ b/puttysrc/MAC/MACRESID.H
@@ -0,0 +1,79 @@
+/* $Id: macresid.h 5310 2005-02-15 22:41:00Z owen $ */
+
+/*
+ * macresid.h -- Mac resource IDs
+ *
+ * This file is shared by C and Rez source files
+ */
+
+/* TMPL for saved sessions */
+#define TMPL_Int 128
+
+/* Menu bar IDs */
+#define MBAR_Main 128
+
+/* Open IDs */
+#define open_pTTY 128
+
+/* Menu IDs */
+#define mApple 128
+#define mFile 129
+#define mEdit 130
+#define mWindow 131
+
+/* Menu Items */
+/* Apple menu */
+#define iAbout 1
+/* File menu */
+#define iNew 1
+#define iOpen 2
+#define iChange 4
+#define iClose 6
+#define iSave 7
+#define iSaveAs 8
+#define iDuplicate 9
+#define iQuit 11
+/* Edit menu */
+#define iUndo 1
+#define iCut 3
+#define iCopy 4
+#define iPaste 5
+#define iClear 6
+#define iSelectAll 7
+/* Window menu */
+#define iShowEventLog 1
+
+/* Window types (and resource IDs) */
+#define wNone 0 /* Dummy value for no window */
+#define wDA 1 /* Dummy value for desk accessory */
+#define wFatal 128
+#define wAbout 129
+#define wiAboutLicence 1
+#define wiAboutVersion 3
+#define wTerminal 130
+#define wLicence 131
+#define wSettings 132
+#define wiSettingsOpen 1
+#define wEventLog 133
+#define wQuestion 134
+#define wAbsent 135
+#define wWrong 136
+
+/* Controls */
+#define cVScroll 128
+
+/* ldes for list box controls */
+#define ldes_Default 128
+
+/* xDEFs */
+#define CDEF_EditBox 129
+#define SYS7_EDITBOX_VARIANT 0
+#define SYS7_TEXT_VARIANT 1
+#define SYS7_EDITBOX_PROC ((CDEF_EditBox << 4) + SYS7_EDITBOX_VARIANT)
+#define SYS7_TEXT_PROC ((CDEF_EditBox << 4) + SYS7_TEXT_VARIANT)
+#define CDEF_Default 130
+#define SYS7_DEFAULT_PROC (CDEF_Default << 4)
+#define CDEF_ListBox 131
+#define SYS7_LISTBOX_PROC (CDEF_ListBox << 4)
+#define CDEF_GroupBox 132
+#define SYS7_GROUPBOX_PROC (CDEF_GroupBox << 4)
diff --git a/puttysrc/MAC/MACSTORE.C b/puttysrc/MAC/MACSTORE.C
new file mode 100644
index 0000000..bfd1c83
--- /dev/null
+++ b/puttysrc/MAC/MACSTORE.C
@@ -0,0 +1,739 @@
+/* $Id: macstore.c 5385 2005-02-22 23:40:47Z owen $ */
+
+/*
+ * macstore.c: Macintosh-specific impementation of the interface
+ * defined in storage.h
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "putty.h"
+#include "storage.h"
+#include "mac.h"
+#include "macresid.h"
+
+
+OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit);
+
+/*
+ * We store each session as a file in the "PuTTY" sub-directory of the
+ * preferences folder. Each (key,value) pair is stored as a resource.
+ */
+
+OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID)
+{
+ OSErr error = noErr;
+ short prefVRefNum;
+ FSSpec puttydir;
+ long prefDirID, puttyDirID;
+
+ error = FindFolder(kOnSystemDisk, kPreferencesFolderType, makeit,
+ &prefVRefNum, &prefDirID);
+ if (error != noErr) goto out;
+
+ error = FSMakeFSSpec(prefVRefNum, prefDirID, "\pPuTTY", &puttydir);
+ if (error != noErr && error != fnfErr) goto out;
+ error = FSpGetDirID(&puttydir, &puttyDirID, makeit);
+ if (error != noErr) goto out;
+
+ *pVRefNum = prefVRefNum;
+ *pDirID = puttyDirID;
+
+ out:
+ return error;
+}
+
+OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID) {
+ OSErr error = noErr;
+ short puttyVRefNum;
+ FSSpec sessdir;
+ long puttyDirID, sessDirID;
+
+ error = get_putty_dir(makeit, &puttyVRefNum, &puttyDirID);
+ if (error != noErr) goto out;
+ error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSaved Sessions",
+ &sessdir);
+ if (error != noErr && error != fnfErr) goto out;
+ error = FSpGetDirID(&sessdir, &sessDirID, makeit);
+ if (error != noErr) goto out;
+
+ *pVRefNum = puttyVRefNum;
+ *pDirID = sessDirID;
+
+ out:
+ return error;
+}
+
+OSErr FSpGetDirID(FSSpec *f, long *idp, Boolean makeit) {
+ CInfoPBRec pb;
+ OSErr error = noErr;
+
+ pb.dirInfo.ioNamePtr = f->name;
+ pb.dirInfo.ioVRefNum = f->vRefNum;
+ pb.dirInfo.ioDrDirID = f->parID;
+ pb.dirInfo.ioFDirIndex = 0;
+ error = PBGetCatInfoSync(&pb);
+ if (error == fnfErr && makeit)
+ return FSpDirCreate(f, smSystemScript, idp);
+ if (error != noErr) goto out;
+ if ((pb.dirInfo.ioFlAttrib & ioDirMask) == 0) {
+ error = dirNFErr;
+ goto out;
+ }
+ *idp = pb.dirInfo.ioDrDirID;
+
+ out:
+ return error;
+}
+
+/* Copy a resource into the current resource file */
+static OSErr copy_resource(ResType restype, short resid)
+{
+ Handle h;
+ Str255 resname;
+
+ h = GetResource(restype, resid);
+ if (h != NULL) {
+ GetResInfo(h, &resid, &restype, resname);
+ DetachResource(h);
+ AddResource(h, restype, resid, resname);
+ if (ResError() == noErr)
+ WriteResource(h);
+ }
+ return ResError();
+}
+
+struct write_settings {
+ int fd;
+ FSSpec tmpfile;
+ FSSpec dstfile;
+};
+
+void *open_settings_w(char const *sessionname, char **errmsg) {
+ short sessVRefNum;
+ long sessDirID;
+ OSErr error;
+ Str255 psessionname;
+ FSSpec dstfile;
+
+ *errmsg = NULL;
+
+ error = get_session_dir(kCreateFolder, &sessVRefNum, &sessDirID);
+ if (error != noErr) return NULL;
+
+ if (!sessionname || !*sessionname)
+ sessionname = "Default Settings";
+ c2pstrcpy(psessionname, sessionname);
+ error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &dstfile);
+ if (error == fnfErr) {
+ FSpCreateResFile(&dstfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
+ if ((error = ResError()) != noErr) return NULL;
+ } else if (error != noErr) return NULL;
+
+ return open_settings_w_fsp(&dstfile);
+}
+
+/*
+ * NB: Destination file must exist.
+ */
+void *open_settings_w_fsp(FSSpec *dstfile)
+{
+ short tmpVRefNum;
+ long tmpDirID;
+ struct write_settings *ws;
+ OSErr error;
+ Str255 tmpname;
+
+ ws = snew(struct write_settings);
+ ws->dstfile = *dstfile;
+
+ /* Create a temporary file to save to first. */
+ error = FindFolder(ws->dstfile.vRefNum, kTemporaryFolderType,
+ kCreateFolder, &tmpVRefNum, &tmpDirID);
+ if (error != noErr) goto out;
+ c2pstrcpy(tmpname, tmpnam(NULL));
+ error = FSMakeFSSpec(tmpVRefNum, tmpDirID, tmpname, &ws->tmpfile);
+ if (error != noErr && error != fnfErr) goto out;
+ if (error == noErr) {
+ error = FSpDelete(&ws->tmpfile);
+ if (error != noErr) goto out;
+ }
+ FSpCreateResFile(&ws->tmpfile, PUTTY_CREATOR, SESS_TYPE, smSystemScript);
+ if ((error = ResError()) != noErr) goto out;
+
+ ws->fd = FSpOpenResFile(&ws->tmpfile, fsWrPerm);
+ if (ws->fd == -1) {error = ResError(); goto out;}
+
+ /* Set up standard resources. Doesn't matter if these fail. */
+ copy_resource('STR ', -16396);
+ copy_resource('TMPL', TMPL_Int);
+
+ return ws;
+
+ out:
+ safefree(ws);
+ fatalbox("Failed to open session for write (%d)", error);
+}
+
+void write_setting_s(void *handle, char const *key, char const *value) {
+ int fd = *(int *)handle;
+ Handle h;
+ int id;
+ OSErr error;
+ Str255 pkey;
+
+ UseResFile(fd);
+ if (ResError() != noErr)
+ fatalbox("Failed to open saved session (%d)", ResError());
+
+ error = PtrToHand(value, &h, strlen(value));
+ if (error != noErr)
+ fatalbox("Failed to allocate memory");
+ /* Put the data in a resource. */
+ id = Unique1ID(FOUR_CHAR_CODE('TEXT'));
+ if (ResError() != noErr)
+ fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
+ c2pstrcpy(pkey, key);
+ AddResource(h, FOUR_CHAR_CODE('TEXT'), id, pkey);
+ if (ResError() != noErr)
+ fatalbox("Failed to add resource %s (%d)", key, ResError());
+}
+
+void write_setting_i(void *handle, char const *key, int value) {
+ int fd = *(int *)handle;
+ Handle h;
+ int id;
+ OSErr error;
+ Str255 pkey;
+
+ UseResFile(fd);
+ if (ResError() != noErr)
+ fatalbox("Failed to open saved session (%d)", ResError());
+
+ /* XXX assume all systems have the same "int" format */
+ error = PtrToHand(&value, &h, sizeof(int));
+ if (error != noErr)
+ fatalbox("Failed to allocate memory (%d)", error);
+
+ /* Put the data in a resource. */
+ id = Unique1ID(FOUR_CHAR_CODE('Int '));
+ if (ResError() != noErr)
+ fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
+ c2pstrcpy(pkey, key);
+ AddResource(h, FOUR_CHAR_CODE('Int '), id, pkey);
+ if (ResError() != noErr)
+ fatalbox("Failed to add resource %s (%d)", key, ResError());
+}
+
+void close_settings_w(void *handle) {
+ struct write_settings *ws = handle;
+ OSErr error;
+
+ CloseResFile(ws->fd);
+ if ((error = ResError()) != noErr)
+ goto out;
+ error = FSpExchangeFiles(&ws->tmpfile, &ws->dstfile);
+ if (error != noErr) goto out;
+ error = FSpDelete(&ws->tmpfile);
+ if (error != noErr) goto out;
+ return;
+
+ out:
+ fatalbox("Close of saved session failed (%d)", error);
+ safefree(handle);
+}
+
+void *open_settings_r(char const *sessionname)
+{
+ short sessVRefNum;
+ long sessDirID;
+ FSSpec sessfile;
+ OSErr error;
+ Str255 psessionname;
+
+ error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
+
+ if (!sessionname || !*sessionname)
+ sessionname = "Default Settings";
+ c2pstrcpy(psessionname, sessionname);
+ error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
+ if (error != noErr) goto out;
+ return open_settings_r_fsp(&sessfile);
+
+ out:
+ return NULL;
+}
+
+void *open_settings_r_fsp(FSSpec *sessfile)
+{
+ OSErr error;
+ int fd;
+ int *handle;
+
+ fd = FSpOpenResFile(sessfile, fsRdPerm);
+ if (fd == 0) {error = ResError(); goto out;}
+
+ handle = snew(int);
+ *handle = fd;
+ return handle;
+
+ out:
+ return NULL;
+}
+
+char *read_setting_s(void *handle, char const *key, char *buffer, int buflen) {
+ int fd;
+ Handle h;
+ size_t len;
+ Str255 pkey;
+
+ if (handle == NULL) goto out;
+ fd = *(int *)handle;
+ UseResFile(fd);
+ if (ResError() != noErr) goto out;
+ c2pstrcpy(pkey, key);
+ h = Get1NamedResource(FOUR_CHAR_CODE('TEXT'), pkey);
+ if (h == NULL) goto out;
+
+ len = GetHandleSize(h);
+ if (len + 1 > buflen) goto out;
+ memcpy(buffer, *h, len);
+ buffer[len] = '\0';
+
+ ReleaseResource(h);
+ if (ResError() != noErr) goto out;
+ return buffer;
+
+ out:
+ return NULL;
+}
+
+int read_setting_i(void *handle, char const *key, int defvalue) {
+ int fd;
+ Handle h;
+ int value;
+ Str255 pkey;
+
+ if (handle == NULL) goto out;
+ fd = *(int *)handle;
+ UseResFile(fd);
+ if (ResError() != noErr) goto out;
+ c2pstrcpy(pkey, key);
+ h = Get1NamedResource(FOUR_CHAR_CODE('Int '), pkey);
+ if (h == NULL) goto out;
+ value = *(int *)*h;
+ ReleaseResource(h);
+ if (ResError() != noErr) goto out;
+ return value;
+
+ out:
+ return defvalue;
+}
+
+int read_setting_fontspec(void *handle, const char *name, FontSpec *result)
+{
+ char *settingname;
+ FontSpec ret;
+ char tmp[256];
+
+ if (!read_setting_s(handle, name, tmp, sizeof(tmp)))
+ return 0;
+ c2pstrcpy(ret.name, tmp);
+ settingname = dupcat(name, "Face", NULL);
+ ret.face = read_setting_i(handle, settingname, 0);
+ sfree(settingname);
+ settingname = dupcat(name, "Height", NULL);
+ ret.size = read_setting_i(handle, settingname, 0);
+ sfree(settingname);
+ if (ret.size == 0) return 0;
+ *result = ret;
+ return 1;
+}
+
+void write_setting_fontspec(void *handle, const char *name, FontSpec font)
+{
+ char *settingname;
+ char tmp[256];
+
+ p2cstrcpy(tmp, font.name);
+ write_setting_s(handle, name, tmp);
+ settingname = dupcat(name, "Face", NULL);
+ write_setting_i(handle, settingname, font.face);
+ sfree(settingname);
+ settingname = dupcat(name, "Size", NULL);
+ write_setting_i(handle, settingname, font.size);
+ sfree(settingname);
+}
+
+int read_setting_filename(void *handle, const char *key, Filename *result)
+{
+ int fd;
+ AliasHandle h;
+ Boolean changed;
+ OSErr err;
+ Str255 pkey;
+
+ if (handle == NULL) goto out;
+ fd = *(int *)handle;
+ UseResFile(fd);
+ if (ResError() != noErr) goto out;
+ c2pstrcpy(pkey, key);
+ h = (AliasHandle)Get1NamedResource(rAliasType, pkey);
+ if (h == NULL) goto out;
+ if ((*h)->userType == 'pTTY' && (*h)->aliasSize == sizeof(**h))
+ memset(result, 0, sizeof(*result));
+ else {
+ err = ResolveAlias(NULL, h, &result->fss, &changed);
+ if (err != noErr && err != fnfErr) goto out;
+ if ((*h)->userType == 'pTTY') {
+ long dirid;
+ StrFileName fname;
+
+ /* Tail of record is pascal string contaning leafname */
+ if (FSpGetDirID(&result->fss, &dirid, FALSE) != noErr) goto out;
+ memcpy(fname, (char *)*h + (*h)->aliasSize,
+ GetHandleSize((Handle)h) - (*h)->aliasSize);
+ err = FSMakeFSSpec(result->fss.vRefNum, dirid, fname,
+ &result->fss);
+ if (err != noErr && err != fnfErr) goto out;
+ }
+ }
+ ReleaseResource((Handle)h);
+ if (ResError() != noErr) goto out;
+ return 1;
+
+ out:
+ return 0;
+}
+
+void write_setting_filename(void *handle, const char *key, Filename fn)
+{
+ int fd = *(int *)handle;
+ AliasHandle h;
+ int id;
+ OSErr error;
+ Str255 pkey;
+
+ UseResFile(fd);
+ if (ResError() != noErr)
+ fatalbox("Failed to open saved session (%d)", ResError());
+
+ if (filename_is_null(fn)) {
+ /* Generate a special "null" alias */
+ h = (AliasHandle)NewHandle(sizeof(**h));
+ if (h == NULL)
+ fatalbox("Failed to create fake alias");
+ (*h)->userType = 'pTTY';
+ (*h)->aliasSize = sizeof(**h);
+ } else {
+ error = NewAlias(NULL, &fn.fss, &h);
+ if (error == fnfErr) {
+ /*
+ * NewAlias can't create an alias for a nonexistent file.
+ * Create an alias for the directory, and record the
+ * filename as well.
+ */
+ FSSpec tmpfss;
+
+ FSMakeFSSpec(fn.fss.vRefNum, fn.fss.parID, NULL, &tmpfss);
+ error = NewAlias(NULL, &tmpfss, &h);
+ if (error != noErr)
+ fatalbox("Failed to create alias");
+ (*h)->userType = 'pTTY';
+ SetHandleSize((Handle)h, (*h)->aliasSize + fn.fss.name[0] + 1);
+ if (MemError() != noErr)
+ fatalbox("Failed to create alias");
+ memcpy((char *)*h + (*h)->aliasSize, fn.fss.name,
+ fn.fss.name[0] + 1);
+ }
+ if (error != noErr)
+ fatalbox("Failed to create alias");
+ }
+ /* Put the data in a resource. */
+ id = Unique1ID(rAliasType);
+ if (ResError() != noErr)
+ fatalbox("Failed to get ID for resource %s (%d)", key, ResError());
+ c2pstrcpy(pkey, key);
+ AddResource((Handle)h, rAliasType, id, pkey);
+ if (ResError() != noErr)
+ fatalbox("Failed to add resource %s (%d)", key, ResError());
+}
+
+void close_settings_r(void *handle) {
+ int fd;
+
+ if (handle == NULL) return;
+ fd = *(int *)handle;
+ CloseResFile(fd);
+ if (ResError() != noErr)
+ fatalbox("Close of saved session failed (%d)", ResError());
+ sfree(handle);
+}
+
+void del_settings(char const *sessionname) {
+ OSErr error;
+ FSSpec sessfile;
+ short sessVRefNum;
+ long sessDirID;
+ Str255 psessionname;
+
+ error = get_session_dir(kDontCreateFolder, &sessVRefNum, &sessDirID);
+
+ c2pstrcpy(psessionname, sessionname);
+ error = FSMakeFSSpec(sessVRefNum, sessDirID, psessionname, &sessfile);
+ if (error != noErr) goto out;
+
+ error = FSpDelete(&sessfile);
+ return;
+ out:
+ fatalbox("Delete session failed (%d)", error);
+}
+
+struct enum_settings_state {
+ short vRefNum;
+ long dirID;
+ int index;
+};
+
+void *enum_settings_start(void) {
+ OSErr error;
+ struct enum_settings_state *state;
+
+ state = snew(struct enum_settings_state);
+ error = get_session_dir(kDontCreateFolder, &state->vRefNum, &state->dirID);
+ if (error != noErr) {
+ sfree(state);
+ return NULL;
+ }
+ state->index = 1;
+ return state;
+}
+
+char *enum_settings_next(void *handle, char *buffer, int buflen) {
+ struct enum_settings_state *e = handle;
+ CInfoPBRec pb;
+ OSErr error = noErr;
+ Str255 name;
+
+ if (e == NULL) return NULL;
+ do {
+ pb.hFileInfo.ioNamePtr = name;
+ pb.hFileInfo.ioVRefNum = e->vRefNum;
+ pb.hFileInfo.ioDirID = e->dirID;
+ pb.hFileInfo.ioFDirIndex = e->index++;
+ error = PBGetCatInfoSync(&pb);
+ if (error != noErr) return NULL;
+ } while (!((pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 &&
+ pb.hFileInfo.ioFlFndrInfo.fdCreator == PUTTY_CREATOR &&
+ pb.hFileInfo.ioFlFndrInfo.fdType == SESS_TYPE &&
+ name[0] < buflen));
+
+ p2cstrcpy(buffer, name);
+ return buffer;
+}
+
+void enum_settings_finish(void *handle) {
+
+ safefree(handle);
+}
+
+#define SEED_SIZE 512
+
+void read_random_seed(noise_consumer_t consumer)
+{
+ short puttyVRefNum;
+ long puttyDirID;
+ OSErr error;
+ char buf[SEED_SIZE];
+ short refnum;
+ long count = SEED_SIZE;
+
+ if (get_putty_dir(kDontCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
+ return;
+ if (HOpenDF(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed", fsRdPerm,
+ &refnum) != noErr)
+ return;
+ error = FSRead(refnum, &count, buf);
+ if (error != noErr && error != eofErr)
+ return;
+ (*consumer)(buf, count);
+ FSClose(refnum);
+}
+
+/*
+ * We don't bother with the usual FSpExchangeFiles dance here because
+ * it doesn't really matter if the old random seed gets lost.
+ */
+void write_random_seed(void *data, int len)
+{
+ short puttyVRefNum;
+ long puttyDirID;
+ OSErr error;
+ FSSpec dstfile;
+ short refnum;
+ long count = len;
+
+ if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
+ return;
+
+ error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pPuTTY Random Seed",
+ &dstfile);
+ if (error == fnfErr) {
+ /* Set up standard resources */
+ FSpCreateResFile(&dstfile, INTERNAL_CREATOR, SEED_TYPE, smRoman);
+ refnum = FSpOpenResFile(&dstfile, fsWrPerm);
+ if (ResError() == noErr) {
+ copy_resource('STR ', -16397);
+ CloseResFile(refnum);
+ }
+ } else if (error != noErr) return;
+
+ if (FSpOpenDF(&dstfile, fsWrPerm, &refnum) != noErr) return;
+ FSWrite(refnum, &count, data);
+ FSClose(refnum);
+
+ return;
+}
+
+/*
+ * This host key cache uses a file in the PuTTY Preferences folder and
+ * stores keys as individual TEXT resources in the resource fork of
+ * that file. This has two problems. Firstly, a resource fork can
+ * contain no more than 2727 resources. Secondly, the Resource
+ * Manager uses a linear search to find a particular resource, which
+ * could make having lots of host keys quite slow.
+ */
+
+int verify_host_key(const char *hostname, int port,
+ const char *keytype, const char *key)
+{
+ short puttyVRefNum;
+ long puttyDirID;
+ OSErr error;
+ FSSpec keyfile;
+ short refnum;
+ char *resname;
+ Str255 presname;
+ char *resvalue;
+ Handle reshandle;
+ int len, compare;
+
+ if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
+ return 1;
+
+ error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSSH Host Keys",
+ &keyfile);
+ if (error == fnfErr) {
+ /* Keys file doesn't exist yet, so we can't match the key */
+ return 1;
+ }
+
+ refnum = FSpOpenResFile(&keyfile, fsRdPerm);
+
+ if (refnum == -1) {
+ /* We couldn't open the resource fork, so we can't match the key */
+ return 1;
+ }
+
+ UseResFile(refnum);
+
+ resname = dupprintf("%s@%d:%s", keytype, port, hostname);
+ c2pstrcpy(presname, resname);
+ reshandle = Get1NamedResource(FOUR_CHAR_CODE('TEXT'), presname);
+ if (ResError() != noErr) {
+ /* Couldn't open the specific resource */
+ return 1;
+ }
+
+ len = GetHandleSize(reshandle);
+ resvalue = snewn(len+1, char);
+ memcpy(resvalue, *reshandle, len);
+ resvalue[len]='\0';
+ ReleaseResource(reshandle);
+ CloseResFile(refnum);
+
+ compare = strncmp(resvalue, key, strlen(resvalue));
+ sfree(resname);
+ sfree(resvalue);
+
+ if (compare) {
+ /* Key different */
+ return 2;
+ } else {
+ /* Key matched */
+ return 0;
+ }
+}
+
+void store_host_key(const char *hostname, int port,
+ const char *keytype, const char *key)
+{
+ short puttyVRefNum;
+ long puttyDirID;
+ OSErr error;
+ FSSpec keyfile;
+ short keyrefnum;
+ char *resname;
+ Str255 presname;
+ Handle resvalue;
+ Handle reshandle;
+ int id;
+
+ /* Open the host key file */
+
+ if (get_putty_dir(~kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr)
+ goto out;
+
+ error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSSH Host Keys",
+ &keyfile);
+ if (error == fnfErr) {
+ /* It doesn't exist, so create it */
+ FSpCreateResFile(&keyfile, INTERNAL_CREATOR, HKYS_TYPE, smRoman);
+ keyrefnum = FSpOpenResFile(&keyfile, fsWrPerm);
+ if (ResError() == noErr) {
+ copy_resource('STR', -16397); /* XXX: wtf is this? */
+ CloseResFile(keyrefnum);
+ }
+ } else if (error != noErr) goto out;
+
+ keyrefnum = FSpOpenResFile(&keyfile, fsWrPerm);
+ if (keyrefnum == -1) goto out;
+
+ UseResFile(keyrefnum);
+ resname = dupprintf("%s@%d:%s", keytype, port, hostname);
+ c2pstrcpy(presname, resname);
+
+ reshandle = Get1NamedResource(FOUR_CHAR_CODE('TEXT'), presname);
+ if (reshandle != NULL) {
+ /* The resource exists, we're replacing a host key */
+ RemoveResource(reshandle);
+ }
+ error = PtrToHand(key, &resvalue, strlen(key));
+ if (error != noErr) goto out;
+
+ id = Unique1ID(FOUR_CHAR_CODE('TEXT'));
+ if (ResError() != noErr) goto out;
+ AddResource(resvalue, FOUR_CHAR_CODE('TEXT'), id, presname);
+ if (ResError() != noErr) goto out;
+
+ CloseResFile(keyrefnum);
+ return;
+
+ out:
+ fatalbox("Writing host key failed (%d)", error);
+ sfree(resname);
+}
+
+/*
+ * Emacs magic:
+ * Local Variables:
+ * c-file-style: "simon"
+ * End:
+ */
diff --git a/puttysrc/MAC/MACSTUFF.H b/puttysrc/MAC/MACSTUFF.H
new file mode 100644
index 0000000..a86cdbb
--- /dev/null
+++ b/puttysrc/MAC/MACSTUFF.H
@@ -0,0 +1,69 @@
+/*
+ * macstuff.h -- Mac-specific definitions visible to the rest of PuTTY.
+ */
+
+typedef void *Context; /* FIXME */
+
+#include
+#include
+
+#include
+#include "charset.h"
+
+struct Filename {
+ FSSpec fss;
+};
+
+extern FILE * f_open(struct Filename, char const *, int);
+
+/* Suspiciously similar to an ICFontRecord */
+struct FontSpec {
+ short size;
+ Style face;
+ char pad;
+ Str255 name;
+};
+
+/*
+ * On the Mac, Unicode text copied to the clipboard has U+2028 line separators.
+ * Non-Unicode text will have these converted to CR along with the rest of the
+ * content.
+ */
+#define SEL_NL { 0x2028 }
+
+#include
+#include /* Timing related goo */
+
+#define GETTICKCOUNT TickCount
+#define CURSORBLINK GetCaretTime()
+#define TICKSPERSEC 60
+
+#define DEFAULT_CODEPAGE 0 /* FIXME: no idea how to do this */
+
+#define WCHAR wchar_t
+#define BYTE UInt8
+#define DWORD UInt32
+
+#define OPTIMISE_SCROLL
+
+/*
+ * sk_getxdmdata() does not exist under the Mac (SGT: I have no
+ * idea whatsoever how to write it, and furthermore I'm unconvinced
+ * it's necessary), so it's a macro which always returns NULL.
+ */
+#define sk_getxdmdata(socket, lenp) (NULL)
+
+/* To make it compile */
+
+#include
+extern int vsnprintf(char *, size_t, char const *, va_list);
+
+extern int stricmp(char const *, char const *);
+extern int strnicmp(char const *, char const *, size_t);
+
+#define HELPCTX(foo) I(0)
+
+#define FILTER_KEY_FILES "pAgt.PPK"
+
+#define CP_UTF8 CS_UTF8 /* from libcharset */
+
diff --git a/puttysrc/MAC/MACTERM.C b/puttysrc/MAC/MACTERM.C
new file mode 100644
index 0000000..28e94b2
--- /dev/null
+++ b/puttysrc/MAC/MACTERM.C
@@ -0,0 +1,1913 @@
+/* $Id: macterm.c 6555 2006-02-13 22:18:17Z owen $ */
+/*
+ * Copyright (c) 1999 Simon Tatham
+ * Copyright (c) 1999, 2002 Ben Harris
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * macterm.c -- Macintosh terminal front-end
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include