ANSI remote printer support. Raw mode only.
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 9 Mar 2002 17:59:15 +0000 (17:59 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 9 Mar 2002 17:59:15 +0000 (17:59 +0000)
git-svn-id: svn://svn.tartarus.org/sgt/putty@1581 cda61777-01e9-0310-a592-d414129be87e

Makefile
doc/config.but
putty.h
settings.c
terminal.c
windlg.c

index ed0c831..3c27e21 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -94,6 +94,7 @@ RES=res
 ##-- objects putty puttytel
 GOBJS1 = window.$(OBJ) windlg.$(OBJ) winctrls.$(OBJ) terminal.$(OBJ)
 GOBJS2 = sizetip.$(OBJ) wcwidth.$(OBJ) unicode.$(OBJ) logging.$(OBJ)
 ##-- objects putty puttytel
 GOBJS1 = window.$(OBJ) windlg.$(OBJ) winctrls.$(OBJ) terminal.$(OBJ)
 GOBJS2 = sizetip.$(OBJ) wcwidth.$(OBJ) unicode.$(OBJ) logging.$(OBJ)
+GOBJS3 = printing.$(OBJ)
 ##-- objects putty puttytel plink
 LOBJS1 = telnet.$(OBJ) raw.$(OBJ) rlogin.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ)
 ##-- objects putty plink
 ##-- objects putty puttytel plink
 LOBJS1 = telnet.$(OBJ) raw.$(OBJ) rlogin.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ)
 ##-- objects putty plink
index 5387a8a..04dd0d0 100644 (file)
@@ -1,4 +1,4 @@
-\versionid $Id: config.but,v 1.28 2002/03/09 11:47:39 simon Exp $
+\versionid $Id: config.but,v 1.29 2002/03/09 17:59:15 simon Exp $
 
 \C{config} Configuring PuTTY
 
 
 \C{config} Configuring PuTTY
 
@@ -380,6 +380,38 @@ 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.
 
 local line editing to be turned on, or force it to be turned off,
 instead of relying on the automatic detection.
 
+\S{config-printing} 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
 \H{config-keyboard} The Keyboard panel
 
 The Keyboard configuration panel allows you to control the behaviour
diff --git a/putty.h b/putty.h
index e37c1a1..79f0b8d 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -336,6 +336,7 @@ typedef struct {
     int sunken_edge;
     int window_border;
     char answerback[256];
     int sunken_edge;
     int window_border;
     char answerback[256];
+    char printer[128];
     /* Colour options */
     int try_palette;
     int bold_colour;
     /* Colour options */
     int try_palette;
     int bold_colour;
@@ -609,4 +610,16 @@ extern int console_batch_mode;
 extern char *console_password;
 int console_get_line(const char *prompt, char *str, int maxlen, int is_pw);
 
 extern char *console_password;
 int console_get_line(const char *prompt, char *str, int maxlen, int is_pw);
 
+/*
+ * Exports from printing.c.
+ */
+typedef struct printer_enum_tag printer_enum;
+typedef struct printer_job_tag printer_job;
+printer_enum *printer_start_enum(int *nprinters);
+char *printer_get_name(printer_enum *, int);
+void printer_finish_enum(printer_enum *);
+printer_job *printer_start_job(char *printer);
+void printer_job_data(printer_job *, void *, int);
+void printer_finish_job(printer_job *);
+
 #endif
 #endif
index 3d54fe1..55955ac 100644 (file)
@@ -261,6 +261,7 @@ void save_settings(char *section, int do_host, Config * cfg)
        write_setting_s(sesskey, buf, buf2);
     }
     write_setting_s(sesskey, "LineCodePage", cfg->line_codepage);
        write_setting_s(sesskey, buf, buf2);
     }
     write_setting_s(sesskey, "LineCodePage", cfg->line_codepage);
+    write_setting_s(sesskey, "Printer", cfg->printer);
     write_setting_i(sesskey, "CapsLockCyr", cfg->xlat_capslockcyr);
     write_setting_i(sesskey, "ScrollBar", cfg->scrollbar);
     write_setting_i(sesskey, "ScrollBarFullScreen", cfg->scrollbar_in_fullscreen);
     write_setting_i(sesskey, "CapsLockCyr", cfg->xlat_capslockcyr);
     write_setting_i(sesskey, "ScrollBar", cfg->scrollbar);
     write_setting_i(sesskey, "ScrollBarFullScreen", cfg->scrollbar_in_fullscreen);
@@ -503,6 +504,7 @@ void load_settings(char *section, int do_host, Config * cfg)
      */
     gpps(sesskey, "LineCodePage", "", cfg->line_codepage,
         sizeof(cfg->line_codepage));
      */
     gpps(sesskey, "LineCodePage", "", cfg->line_codepage,
         sizeof(cfg->line_codepage));
+    gpps(sesskey, "Printer", "", cfg->printer, sizeof(cfg->printer));
     gppi (sesskey, "CapsLockCyr", 0, &cfg->xlat_capslockcyr);
     gppi(sesskey, "ScrollBar", 1, &cfg->scrollbar);
     gppi(sesskey, "ScrollBarFullScreen", 0, &cfg->scrollbar_in_fullscreen);
     gppi (sesskey, "CapsLockCyr", 0, &cfg->xlat_capslockcyr);
     gppi(sesskey, "ScrollBar", 1, &cfg->scrollbar);
     gppi(sesskey, "ScrollBarFullScreen", 0, &cfg->scrollbar_in_fullscreen);
index af175d5..a224afd 100644 (file)
@@ -115,6 +115,10 @@ static int vt52_bold;                     /* Force bold on non-bold colours */
 static int utf_state;                 /* Is there a pending UTF-8 character */
 static int utf_char;                  /* and what is it so far. */
 static int utf_size;                  /* The size of the UTF character. */
 static int utf_state;                 /* Is there a pending UTF-8 character */
 static int utf_char;                  /* and what is it so far. */
 static int utf_size;                  /* The size of the UTF character. */
+static int printing, only_printing;    /* Are we doing ANSI printing? */
+static int print_state;                       /* state of print-end-sequence scan */
+static bufchain printer_buf;          /* buffered data for printer */
+static printer_job *print_job;
 
 static int xterm_mouse;                       /* send mouse messages to app */
 
 
 static int xterm_mouse;                       /* send mouse messages to app */
 
@@ -206,6 +210,7 @@ static void erase_lots(int, int, int);
 static void swap_screen(int);
 static void update_sbar(void);
 static void deselect(void);
 static void swap_screen(int);
 static void update_sbar(void);
 static void deselect(void);
+static void term_print_finish(void);
 
 /*
  * Resize a line to make it `cols' columns wide.
 
 /*
  * Resize a line to make it `cols' columns wide.
@@ -302,6 +307,7 @@ static void power_on(void)
     blink_is_real = cfg.blinktext;
     erase_char = ERASE_CHAR;
     alt_which = 0;
     blink_is_real = cfg.blinktext;
     erase_char = ERASE_CHAR;
     alt_which = 0;
+    term_print_finish();
     {
        int i;
        for (i = 0; i < 256; i++)
     {
        int i;
        for (i = 0; i < 256; i++)
@@ -352,8 +358,9 @@ void term_pwron(void)
 
 /*
  * When the user reconfigures us, we need to check the forbidden-
 
 /*
  * When the user reconfigures us, we need to check the forbidden-
- * alternate-screen config option, and also disable raw mouse mode
- * if the user has disabled mouse reporting.
+ * alternate-screen config option, disable raw mouse mode if the
+ * user has disabled mouse reporting, and abandon a print job if
+ * the user has disabled printing.
  */
 void term_reconfig(void)
 {
  */
 void term_reconfig(void)
 {
@@ -368,6 +375,9 @@ void term_reconfig(void)
        sco_acs = alt_sco_acs = 0;
        utf = 0;
     }
        sco_acs = alt_sco_acs = 0;
        utf = 0;
     }
+    if (!*cfg.printer) {
+       term_print_finish();
+    }
 }
 
 /*
 }
 
 /*
@@ -1008,6 +1018,50 @@ static void do_osc(void)
 }
 
 /*
 }
 
 /*
+ * ANSI printing routines.
+ */
+static void term_print_setup(void)
+{
+    bufchain_clear(&printer_buf);
+    print_job = printer_start_job(cfg.printer);
+}
+static void term_print_flush(void)
+{
+    void *data;
+    int len;
+    int size;
+    while ((size = bufchain_size(&printer_buf)) > 5) {
+       bufchain_prefix(&printer_buf, &data, &len);
+       if (len > size-5)
+           len = size-5;
+       printer_job_data(print_job, data, len);
+       bufchain_consume(&printer_buf, len);
+    }
+}
+static void term_print_finish(void)
+{
+    void *data;
+    int len, size;
+    char c;
+
+    term_print_flush();
+    while ((size = bufchain_size(&printer_buf)) > 0) {
+       bufchain_prefix(&printer_buf, &data, &len);
+       c = *(char *)data;
+       if (c == '\033' || c == '\233') {
+           bufchain_consume(&printer_buf, size);
+           break;
+       } else {
+           printer_job_data(print_job, &c, 1);
+           bufchain_consume(&printer_buf, 1);
+       }
+    }
+    printer_finish_job(print_job);
+    print_job = NULL;
+    printing = only_printing = FALSE;
+}
+
+/*
  * Remove everything currently in `inbuf' and stick it up on the
  * in-memory display. There's a big state machine in here to
  * process escape sequences...
  * Remove everything currently in `inbuf' and stick it up on the
  * in-memory display. There's a big state machine in here to
  * process escape sequences...
@@ -1051,6 +1105,40 @@ void term_out(void)
         * of i18n.
         */
 
         * of i18n.
         */
 
+       /*
+        * If we're printing, add the character to the printer
+        * buffer.
+        */
+       if (printing) {
+           char cc = c;
+           bufchain_add(&printer_buf, &c, 1);
+
+           /*
+            * If we're in print-only mode, we use a much simpler
+            * state machine designed only to recognise the ESC[4i
+            * termination sequence.
+            */
+           if (only_printing) {
+               if (c == '\033')
+                   print_state = 1;
+               else if (c == (unsigned char)'\233')
+                   print_state = 2;
+               else if (c == '[' && print_state == 1)
+                   print_state = 2;
+               else if (c == '4' && print_state == 2)
+                   print_state = 3;
+               else if (c == 'i' && print_state == 3)
+                   print_state = 4;
+               else
+                   print_state = 0;
+               if (print_state == 4) {
+                   printing = only_printing = FALSE;
+                   term_print_finish();
+               }
+               continue;
+           }
+       }
+
        /* First see about all those translations. */
        if (termstate == TOPLEVEL) {
            if (in_utf)
        /* First see about all those translations. */
        if (termstate == TOPLEVEL) {
            if (in_utf)
@@ -1815,6 +1903,24 @@ void term_out(void)
                                toggle_mode(esc_args[i], esc_query, TRUE);
                        }
                        break;
                                toggle_mode(esc_args[i], esc_query, TRUE);
                        }
                        break;
+                     case 'i':
+                     case ANSI_QUE('i'):
+                       compatibility(VT100);
+                       {
+                           int i;
+                           if (esc_nargs != 1) break;
+                           if (esc_args[0] == 5 && *cfg.printer) {
+                               printing = TRUE;
+                               only_printing = !esc_query;
+                               print_state = 0;
+                               term_print_setup();
+                           } else if (esc_args[0] == 4 && printing) {
+                               printing = FALSE;
+                               only_printing = FALSE;
+                               term_print_finish();
+                           }
+                       }
+                       break;                  
                      case 'l':       /* toggle modes to low */
                      case ANSI_QUE('l'):
                        compatibility(VT100);
                      case 'l':       /* toggle modes to low */
                      case ANSI_QUE('l'):
                        compatibility(VT100);
@@ -2657,6 +2763,8 @@ void term_out(void)
            check_selection(curs, cursplus);
        }
     }
            check_selection(curs, cursplus);
        }
     }
+
+    term_print_flush();
 }
 
 #if 0
 }
 
 #if 0
index 2912040..316115e 100644 (file)
--- a/windlg.c
+++ b/windlg.c
@@ -27,6 +27,8 @@ static int requested_help;
 
 static struct prefslist cipherlist;
 
 
 static struct prefslist cipherlist;
 
+#define PRINTER_DISABLED_STRING "None (printing disabled)"
+
 void force_normal(HWND hwnd)
 {
     static int recurse = 0;
 void force_normal(HWND hwnd)
 {
     static int recurse = 0;
@@ -307,6 +309,7 @@ enum { IDCX_ABOUT =
     IDC_TITLE_TERMINAL,
     IDC_BOX_TERMINAL1,
     IDC_BOX_TERMINAL2,
     IDC_TITLE_TERMINAL,
     IDC_BOX_TERMINAL1,
     IDC_BOX_TERMINAL2,
+    IDC_BOX_TERMINAL3,
     IDC_WRAPMODE,
     IDC_DECOM,
     IDC_LFHASCR,
     IDC_WRAPMODE,
     IDC_DECOM,
     IDC_LFHASCR,
@@ -322,6 +325,8 @@ enum { IDCX_ABOUT =
     IDC_EDITBACKEND,
     IDC_EDITYES,
     IDC_EDITNO,
     IDC_EDITBACKEND,
     IDC_EDITYES,
     IDC_EDITNO,
+    IDC_PRINTERSTATIC,
+    IDC_PRINTER,
     terminalpanelend,
 
     featurespanelstart,
     terminalpanelend,
 
     featurespanelstart,
@@ -724,6 +729,9 @@ char *help_context_cmd(int id)
       case IDC_EDITYES:
       case IDC_EDITNO:
         return "JI(`',`terminal.localedit')";
       case IDC_EDITYES:
       case IDC_EDITNO:
         return "JI(`',`terminal.localedit')";
+      case IDC_PRINTERSTATIC:
+      case IDC_PRINTER:
+       return "JI(`',`terminal.printing')";
 
       case IDC_BELLSTATIC:
       case IDC_BELL_DISABLED:
 
       case IDC_BELLSTATIC:
       case IDC_BELL_DISABLED:
@@ -1203,7 +1211,25 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess)
        }
        SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage);
     }
        }
        SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage);
     }
-    
+
+    {
+       int i, nprinters;
+       printer_enum *pe;
+       pe = printer_start_enum(&nprinters);
+       strcpy(cfg.line_codepage, cp_name(decode_codepage(cfg.line_codepage)));
+       SendDlgItemMessage(hwnd, IDC_PRINTER, CB_RESETCONTENT, 0, 0);
+       SendDlgItemMessage(hwnd, IDC_PRINTER, CB_ADDSTRING,
+                          0, (LPARAM) PRINTER_DISABLED_STRING);
+       for (i = 0; i < nprinters; i++) {
+           char *printer_name = printer_get_name(pe, i);
+           SendDlgItemMessage(hwnd, IDC_PRINTER, CB_ADDSTRING,
+                              0, (LPARAM) printer_name);
+       }
+       printer_finish_enum(pe);
+       SetDlgItemText(hwnd, IDC_PRINTER,
+                      *cfg.printer ? cfg.printer : PRINTER_DISABLED_STRING);
+    }
+
     CheckRadioButton(hwnd, IDC_VTXWINDOWS, IDC_VTUNICODE,
                     cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
                     cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
     CheckRadioButton(hwnd, IDC_VTXWINDOWS, IDC_VTUNICODE,
                     cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
                     cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
@@ -1330,7 +1356,7 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
     }
 
     if (panel == terminalpanelstart) {
     }
 
     if (panel == terminalpanelstart) {
-       /* The Terminal panel. Accelerators used: [acgoh] wdren lts */
+       /* The Terminal panel. Accelerators used: [acgoh] wdren lts */
        struct ctlpos cp;
        ctlposinit(&cp, hwnd, 80, 3, 13);
        bartitle(&cp, "Options controlling the terminal emulation",
        struct ctlpos cp;
        ctlposinit(&cp, hwnd, 80, 3, 13);
        bartitle(&cp, "Options controlling the terminal emulation",
@@ -1354,6 +1380,11 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
                  "Auto", IDC_EDITBACKEND,
                  "Force on", IDC_EDITYES, "Force off", IDC_EDITNO, NULL);
        endbox(&cp);
                  "Auto", IDC_EDITBACKEND,
                  "Force on", IDC_EDITYES, "Force off", IDC_EDITNO, NULL);
        endbox(&cp);
+
+       beginbox(&cp, "Remote-controlled printing", IDC_BOX_TERMINAL3);
+       combobox(&cp, "&Printer to send ANSI printer output to:",
+                IDC_PRINTERSTATIC, IDC_PRINTER);
+       endbox(&cp);
     }
 
     if (panel == featurespanelstart) {
     }
 
     if (panel == featurespanelstart) {
@@ -3109,6 +3140,19 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
                    SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage);
                }
                break;
                    SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage);
                }
                break;
+             case IDC_PRINTER:
+               if (HIWORD(wParam) == CBN_SELCHANGE) {
+                   int index = SendDlgItemMessage(hwnd, IDC_PRINTER,
+                                                  CB_GETCURSEL, 0, 0);
+                   SendDlgItemMessage(hwnd, IDC_PRINTER, CB_GETLBTEXT,
+                                      index, (LPARAM)cfg.printer);
+               } else if (HIWORD(wParam) == CBN_EDITCHANGE) {
+                   GetDlgItemText(hwnd, IDC_PRINTER, cfg.printer,
+                                  sizeof(cfg.printer) - 1);
+               }
+               if (!strcmp(cfg.printer, PRINTER_DISABLED_STRING))
+                   *cfg.printer = '\0';
+               break;
              case IDC_CAPSLOCKCYR:
                if (HIWORD(wParam) == BN_CLICKED ||
                    HIWORD(wParam) == BN_DOUBLECLICKED) {
              case IDC_CAPSLOCKCYR:
                if (HIWORD(wParam) == BN_CLICKED ||
                    HIWORD(wParam) == BN_DOUBLECLICKED) {