summaryrefslogtreecommitdiff
path: root/src/escputil
diff options
context:
space:
mode:
authorRoger Leigh <rleigh@debian.org>2008-10-26 16:10:50 +0000
committerRoger Leigh <rleigh@debian.org>2008-10-26 16:10:50 +0000
commiteb5718390731a9746c556317e641320b671f2091 (patch)
tree762876b4adf298c1281142328e2ae87007330904 /src/escputil
Imported Upstream version 4.2.0
Diffstat (limited to 'src/escputil')
-rw-r--r--src/escputil/.cvsignore5
-rw-r--r--src/escputil/Makefile.am48
-rw-r--r--src/escputil/escputil.c1277
3 files changed, 1330 insertions, 0 deletions
diff --git a/src/escputil/.cvsignore b/src/escputil/.cvsignore
new file mode 100644
index 0000000..5da45ee
--- /dev/null
+++ b/src/escputil/.cvsignore
@@ -0,0 +1,5 @@
+.deps
+.libs
+Makefile
+Makefile.in
+escputil
diff --git a/src/escputil/Makefile.am b/src/escputil/Makefile.am
new file mode 100644
index 0000000..d730545
--- /dev/null
+++ b/src/escputil/Makefile.am
@@ -0,0 +1,48 @@
+## $id: makefile.am,v 1.9 2001/06/03 18:35:03 rleigh Exp $
+## Copyright (C) 2000 Roger Leigh
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+## Process this file with automake to produce Makefile.in.
+
+AUTOMAKE_OPTIONS = 1.4 gnu
+
+@SET_MAKE@
+
+MAINT_CHARSET = latin1
+
+
+## Variables
+
+AM_CFLAGS = $(GNUCFLAGS)
+INCLUDES = @INCLUDES@
+LIBS = @LIBS@ ../../lib/libprintut.la $(INTLLIBS) ../../lib/libprintut.la
+
+
+## Programs
+
+ESCPUTIL_BIN = escputil
+
+bin_PROGRAMS = @ESCPUTIL_BIN@
+
+EXTRA_PROGRAMS = escputil
+
+escputil_LDADD = $(LIBREADLINE_DEPS)
+
+
+## Clean
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/escputil/escputil.c b/src/escputil/escputil.c
new file mode 100644
index 0000000..954ff3c
--- /dev/null
+++ b/src/escputil/escputil.c
@@ -0,0 +1,1277 @@
+/*
+ * "$Id: escputil.c,v 1.39 2001/10/27 17:16:38 rlk Exp $"
+ *
+ * Printer maintenance utility for EPSON Stylus (R) printers
+ *
+ * Copyright 2000 Robert Krawitz (rlk@alum.mit.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "../../lib/libprintut.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#if defined(HAVE_VARARGS_H) && !defined(HAVE_STDARG_H)
+#include <varargs.h>
+#else
+#include <stdarg.h>
+#endif
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#endif
+#ifdef __GNU_LIBRARY__
+#include <getopt.h>
+#endif
+#ifdef HAVE_READLINE_READLINE_H
+#include <readline/readline.h>
+#endif
+#ifdef HAVE_READLINE_HISTORY_H
+#include <readline/history.h>
+#endif
+#include <gimp-print/gimp-print-intl-internal.h>
+
+void do_align(void);
+void do_align_color(void);
+char *do_get_input (const char *prompt);
+void do_head_clean(void);
+void do_help(int code);
+void do_identify(void);
+void do_ink_level(void);
+void do_nozzle_check(void);
+void do_status(void);
+int do_print_cmd(void);
+
+
+const char *banner = N_("\
+Escputil version " VERSION ", Copyright (C) 2000-2001 Robert Krawitz\n\
+Escputil comes with ABSOLUTELY NO WARRANTY; for details type 'escputil -l'\n\
+This is free software, and you are welcome to redistribute it\n\
+under certain conditions; type 'escputil -l' for details.\n");
+
+const char *license = N_("\
+Copyright 2000 Robert Krawitz (rlk@alum.mit.edu)\n\
+\n\
+This program is free software; you can redistribute it and/or modify it\n\
+under the terms of the GNU General Public License as published by the Free\n\
+Software Foundation; either version 2 of the License, or (at your option)\n\
+any later version.\n\
+\n\
+This program is distributed in the hope that it will be useful, but\n\
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n\
+for more details.\n\
+\n\
+You should have received a copy of the GNU General Public License\n\
+along with this program; if not, write to the Free Software\n\
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n");
+
+
+#ifdef __GNU_LIBRARY__
+
+struct option optlist[] =
+{
+ { "printer-name", 1, NULL, (int) 'P' },
+ { "raw-device", 1, NULL, (int) 'r' },
+ { "ink-level", 0, NULL, (int) 'i' },
+ { "clean-head", 0, NULL, (int) 'c' },
+ { "nozzle-check", 0, NULL, (int) 'n' },
+ { "align-head", 0, NULL, (int) 'a' },
+ { "align-color", 0, NULL, (int) 'o' },
+ { "status", 0, NULL, (int) 's' },
+ { "new", 0, NULL, (int) 'u' },
+ { "help", 0, NULL, (int) 'h' },
+ { "identify", 0, NULL, (int) 'd' },
+ { "model", 1, NULL, (int) 'm' },
+ { "quiet", 0, NULL, (int) 'q' },
+ { "license", 0, NULL, (int) 'l' },
+ { "list-models", 0, NULL, (int) 'M' },
+ { NULL, 0, NULL, 0 }
+};
+
+const char *help_msg = N_("\
+Usage: escputil [-c | -n | -a | -i | -o | -s | -d | -l | -M]\n\
+ [-P printer | -r device] [-u] [-q] [-m model]\n\
+Perform maintenance on EPSON Stylus (R) printers.\n\
+Examples: escputil --clean-head --printer stpex-on-third-floor\n\
+ escputil --ink-level --new --raw-device /dev/lp0\n\
+\n\
+ Commands:\n\
+ -c|--clean-head Clean the print head.\n\
+ -n|--nozzle-check Print a nozzle test pattern.\n\
+ Dirty or clogged nozzles will show as gaps in the\n\
+ pattern. If you see any gaps, you should clean\n\
+ the print head.\n\
+ -a|--align-head Align the print head. CAUTION: Misuse of this\n\
+ utility may result in poor print quality and/or\n\
+ damage to the printer.\n\
+ -o|--align-color Align the color print head (Stylus Color 480 and 580\n\
+ only). CAUTION: Misuse of this utility may result in\n\
+ poor print quality and/or damage to the printer.\n\
+ -s|--status Retrieve printer status.\n\
+ -i|--ink-level Obtain the ink level from the printer. This requires\n\
+ read/write access to the raw printer device.\n\
+ -d|--identify Query the printer for make and model information.\n\
+ This requires read/write access to the raw printer\n\
+ device.\n\
+ -l|--license Display the license/warranty terms of this program.\n\
+ -M|--list-models List the available printer models.\n\
+ -h|--help Print this help message.\n\
+ Options:\n\
+ -P|--printer-name Specify the name of the printer queue to operate on.\n\
+ Default is the default system printer.\n\
+ -r|--raw-device Specify the name of the device to write to directly\n\
+ rather than going through a printer queue.\n\
+ -u|--new The printer is a new printer (Stylus Color 740 or\n\
+ newer).\n\
+ -q|--quiet Suppress the banner.\n\
+ -m|--model Specify the precise printer model for head alignment.\n");
+#else
+const char *help_msg = N_("\
+Usage: escputil [OPTIONS] [COMMAND]\n\
+Usage: escputil [-c | -n | -a | -i | -o | -s | -d | -l | -M]\n\
+ [-P printer | -r device] [-u] [-q] [-m model]\n\
+Perform maintenance on EPSON Stylus (R) printers.\n\
+Examples: escputil -c -P stpex-on-third-floor\n\
+ escputil -i -u -r /dev/lp0\n\
+\n\
+ Commands:\n\
+ -c Clean the print head.\n\
+ -n Print a nozzle test pattern.\n\
+ Dirty or clogged nozzles will show as gaps in the\n\
+ pattern. If you see any gaps, you should clean\n\
+ the print head.\n\
+ -a Align the print head. CAUTION: Misuse of this\n\
+ utility may result in poor print quality and/or\n\
+ damage to the printer.\n\
+ -o Align the color print head (Stylus Color 480 and 580\n\
+ only). CAUTION: Misuse of this utility may result in\n\
+ poor print quality and/or damage to the printer.\n\
+ -s Retrieve printer status.\n\
+ -i Obtain the ink level from the printer. This requires\n\
+ read/write access to the raw printer device.\n\
+ -d Query the printer for make and model information. This\n\
+ requires read/write access to the raw printer device.\n\
+ -l Display the license/warranty terms of this program.\n\
+ -M List the available printer models.\n\
+ -h Print this help message.\n\
+ Options:\n\
+ -P Specify the name of the printer queue to operate on.\n\
+ Default is the default system printer.\n\
+ -r Specify the name of the device to write to directly\n\
+ rather than going through a printer queue.\n\
+ -u The printer is a new printer (Stylus Color 740 or newer).\n\
+ -q Suppress the banner.\n\
+ -m Specify the precise printer model for head alignment.\n");
+#endif
+
+typedef struct
+{
+ const char *short_name;
+ const char *long_name;
+ int passes;
+ int choices;
+ int ink_change;
+ int color_passes;
+ int color_choices;
+} stp_printer_t;
+
+stp_printer_t printer_list[] =
+{
+ { "C20sx", N_("Stylus C20sx"), 3, 15, 0, 2, 9 },
+ { "C20ux", N_("Stylus C20ux"), 3, 15, 0, 2, 9 },
+ { "C40sx", N_("Stylus C40sx"), 3, 15, 0, 2, 9 },
+ { "C40ux", N_("Stylus C40ux"), 3, 15, 0, 2, 9 },
+ { "C60", N_("Stylus C60"), 3, 15, 0, 0, 0 },
+ { "C70", N_("Stylus C70"), 3, 15, 0, 2, 9 },
+ { "C80", N_("Stylus C80"), 3, 15, 0, 2, 9 },
+ { "color", N_("Stylus Color"), 1, 7, 0, 0, 0 },
+ { "pro", N_("Stylus Color Pro"), 1, 7, 0, 0, 0 },
+ { "pro-xl", N_("Stylus Color Pro XL"),1, 7, 0, 0, 0 },
+ { "400", N_("Stylus Color 400"), 1, 7, 0, 0, 0 },
+ { "440", N_("Stylus Color 440"), 1, 15, 0, 0, 0 },
+ { "460", N_("Stylus Color 460"), 1, 15, 0, 0, 0 },
+ { "480", N_("Stylus Color 480"), 3, 15, 1, 2, 9 },
+ { "500", N_("Stylus Color 500"), 1, 7, 0, 0, 0 },
+ { "580", N_("Stylus Color 580"), 3, 15, 1, 2, 9 },
+ { "600", N_("Stylus Color 600"), 1, 7, 0, 0, 0 },
+ { "640", N_("Stylus Color 640"), 1, 15, 0, 0, 0 },
+ { "660", N_("Stylus Color 660"), 1, 15, 0, 0, 0 },
+ { "670", N_("Stylus Color 670"), 3, 15, 0, 0, 0 },
+ { "680", N_("Stylus Color 680"), 3, 15, 0, 0, 0 },
+ { "740", N_("Stylus Color 740"), 3, 15, 0, 0, 0 },
+ { "760", N_("Stylus Color 760"), 3, 15, 0, 0, 0 },
+ { "777", N_("Stylus Color 777"), 3, 15, 0, 0, 0 },
+ { "800", N_("Stylus Color 800"), 1, 7, 0, 0, 0 },
+ { "850", N_("Stylus Color 850"), 1, 7, 0, 0, 0 },
+ { "860", N_("Stylus Color 860"), 3, 15, 0, 0, 0 },
+ { "880", N_("Stylus Color 880"), 3, 15, 0, 0, 0 },
+ { "83", N_("Stylus Color 83"), 3, 15, 0, 0, 0 },
+ { "900", N_("Stylus Color 900"), 3, 15, 0, 0, 0 },
+ { "980", N_("Stylus Color 980"), 3, 15, 0, 0, 0 },
+ { "1160", N_("Stylus Color 1160"),3, 15, 0, 0, 0 },
+ { "1500", N_("Stylus Color 1500"),1, 7, 0, 0, 0 },
+ { "1520", N_("Stylus Color 1520"),1, 7, 0, 0, 0 },
+ { "3000", N_("Stylus Color 3000"),1, 7, 0, 0, 0 },
+ { "photo", N_("Stylus Photo"), 1, 7, 0, 0, 0 },
+ { "700", N_("Stylus Photo 700"), 1, 7, 0, 0, 0 },
+ { "ex", N_("Stylus Photo EX"), 1, 7, 0, 0, 0 },
+ { "720", N_("Stylus Photo 720"), 3, 15, 0, 0, 0 },
+ { "750", N_("Stylus Photo 750"), 3, 15, 0, 0, 0 },
+ { "780", N_("Stylus Photo 780"), 3, 15, 0, 0, 0 },
+ { "785", N_("Stylus Photo 785"), 3, 15, 0, 0, 0 },
+ { "790", N_("Stylus Photo 790"), 3, 15, 0, 0, 0 },
+ { "810", N_("Stylus Photo 810"), 3, 15, 0, 0, 0 },
+ { "820", N_("Stylus Photo 820"), 3, 15, 0, 0, 0 },
+ { "870", N_("Stylus Photo 870"), 3, 15, 0, 0, 0 },
+ { "875", N_("Stylus Photo 875"), 3, 15, 0, 0, 0 },
+ { "890", N_("Stylus Photo 890"), 3, 15, 0, 0, 0 },
+ { "895", N_("Stylus Photo 895"), 3, 15, 0, 0, 0 },
+ { "1200", N_("Stylus Photo 1200"),3, 15, 0, 0, 0 },
+ { "1270", N_("Stylus Photo 1270"),3, 15, 0, 0, 0 },
+ { "1280", N_("Stylus Photo 1280"),3, 15, 0, 0, 0 },
+ { "1290", N_("Stylus Photo 1290"),3, 15, 0, 0, 0 },
+ { "2000", N_("Stylus Photo 2000P"),2, 15, 0, 0, 0 },
+ { "5000", N_("Stylus Pro 5000"), 1, 7, 0, 0, 0 },
+ { "5500", N_("Stylus Pro 5500"), 1, 7, 0, 0, 0 },
+ { "7000", N_("Stylus Pro 7000"), 1, 7, 0, 0, 0 },
+ { "7500", N_("Stylus Pro 7500"), 1, 7, 0, 0, 0 },
+ { "9000", N_("Stylus Pro 9000"), 1, 7, 0, 0, 0 },
+ { "9500", N_("Stylus Pro 9500"), 1, 7, 0, 0, 0 },
+ { "10000", N_("Stylus Pro 10000"), 3, 15, 0, 0, 0 },
+ { "scan2000", N_("Stylus Scan 2000"), 3, 15, 0, 0, 0 },
+ { "scan2500", N_("Stylus Scan 2500"), 3, 15, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0, 0 },
+};
+
+char *printer = NULL;
+char *raw_device = NULL;
+char *printer_model = NULL;
+char printer_cmd[1025];
+int bufpos = 0;
+int isnew = 0;
+
+static void
+print_models(void)
+{
+ stp_printer_t *printer = &printer_list[0];
+ while (printer->short_name)
+ {
+ printf("%10s %s\n", printer->short_name, _(printer->long_name));
+ printer++;
+ }
+}
+
+void
+do_help(int code)
+{
+ printf("%s", _(help_msg));
+ exit(code);
+}
+
+static void
+exit_packet_mode(void)
+{
+ static char hdr[] = "\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@";
+ memcpy(printer_cmd + bufpos, hdr, sizeof(hdr) - 1); /* DON'T include null! */
+ bufpos += sizeof(hdr) - 1;
+}
+
+static void
+initialize_print_cmd(void)
+{
+ bufpos = 0;
+ if (isnew)
+ exit_packet_mode();
+}
+
+int
+main(int argc, char **argv)
+{
+ int quiet = 0;
+ int operation = 0;
+ int c;
+ while (1)
+ {
+#ifdef __GNU_LIBRARY__
+ int option_index = 0;
+ c = getopt_long(argc, argv, "P:r:icnaosduqm:hlM", optlist, &option_index);
+#else
+ c = getopt(argc, argv, "P:r:icnaosduqm:hlM");
+#endif
+ if (c == -1)
+ break;
+ switch (c)
+ {
+ case 'q':
+ quiet = 1;
+ break;
+ case 'c':
+ case 'i':
+ case 'n':
+ case 'a':
+ case 'd':
+ case 's':
+ case 'o':
+ if (operation)
+ do_help(1);
+ operation = c;
+ break;
+ case 'P':
+ if (printer || raw_device)
+ {
+ printf(_("You may only specify one printer or raw device."));
+ do_help(1);
+ }
+ printer = xmalloc(strlen(optarg) + 1);
+ strcpy(printer, optarg);
+ break;
+ case 'r':
+ if (printer || raw_device)
+ {
+ printf(_("You may only specify one printer or raw device."));
+ do_help(1);
+ }
+ raw_device = xmalloc(strlen(optarg) + 1);
+ strcpy(raw_device, optarg);
+ break;
+ case 'm':
+ if (printer_model)
+ {
+ printf(_("You may only specify one printer model."));
+ do_help(1);
+ }
+ printer_model = xmalloc(strlen(optarg) + 1);
+ strcpy(printer_model, optarg);
+ break;
+ case 'u':
+ isnew = 1;
+ break;
+ case 'h':
+ do_help(0);
+ break;
+ case 'l':
+ printf("%s\n", _(license));
+ exit(0);
+ case 'M':
+ print_models();
+ exit(0);
+ default:
+ printf("%s\n", _(banner));
+ fprintf(stderr, _("Unknown option %c\n"), c);
+ do_help(1);
+ }
+ }
+ if (!quiet)
+ printf("%s\n", banner);
+ if (operation == 0)
+ {
+ fprintf(stderr, "Usage: %s [OPTIONS] command\n", argv[0]);
+#ifdef __GNU_LIBRARY__
+ fprintf(stderr, "Type `%s --help' for more information.\n", argv[0]);
+#else
+ fprintf(stderr, "Type `%s -h' for more information.\n", argv[0]);
+#endif
+ exit(1);
+ }
+ initialize_print_cmd();
+ switch(operation)
+ {
+ case 'c':
+ do_head_clean();
+ break;
+ case 'n':
+ do_nozzle_check();
+ break;
+ case 'i':
+ do_ink_level();
+ break;
+ case 'a':
+ do_align();
+ break;
+ case 'o':
+ do_align_color();
+ break;
+ case 'd':
+ do_identify();
+ break;
+ case 's':
+ do_status();
+ break;
+ default:
+ do_help(1);
+ }
+ exit(0);
+}
+
+int
+do_print_cmd(void)
+{
+ FILE *pfile;
+ int bytes = 0;
+ int retries = 0;
+ char command[1024];
+ memcpy(printer_cmd + bufpos, "\f\033\000\033\000", 5);
+ bufpos += 5;
+ if (raw_device)
+ {
+ pfile = fopen(raw_device, "wb");
+ if (!pfile)
+ {
+ fprintf(stderr, _("Cannot open device %s: %s\n"), raw_device,
+ strerror(errno));
+ return 1;
+ }
+ }
+ else
+ {
+ if (!access("/bin/lpr", X_OK) ||
+ !access("/usr/bin/lpr", X_OK) ||
+ !access("/usr/bsd/lpr", X_OK))
+ {
+ if (printer == NULL)
+ strcpy(command, "lpr -l");
+ else
+ sprintf(command, "lpr -P%s -l", printer);
+ }
+ else if (printer == NULL)
+ strcpy(command, "lp -s -oraw");
+ else
+ sprintf(command, "lp -s -oraw -d%s", printer);
+
+ if ((pfile = popen(command, "w")) == NULL)
+ {
+ fprintf(stderr, _("Cannot print to printer %s with %s\n"), printer,
+ command);
+ return 1;
+ }
+ }
+ while (bytes < bufpos)
+ {
+ int status = fwrite(printer_cmd + bytes, 1, bufpos - bytes, pfile);
+ if (status == 0)
+ {
+ retries++;
+ if (retries > 2)
+ {
+ fprintf(stderr, _("Unable to send command to printer\n"));
+ if (raw_device)
+ fclose(pfile);
+ else
+ pclose(pfile);
+ return 1;
+ }
+ }
+ else if (status == -1)
+ {
+ fprintf(stderr, _("Unable to send command to printer\n"));
+ if (raw_device)
+ fclose(pfile);
+ else
+ pclose(pfile);
+ return 1;
+ }
+ else
+ {
+ bytes += status;
+ retries = 0;
+ }
+ }
+ if (raw_device)
+ fclose(pfile);
+ else
+ pclose(pfile);
+ return 0;
+}
+
+static int
+read_from_printer(int fd, char *buf, int bufsize)
+{
+#ifdef HAVE_POLL
+ struct pollfd ufds;
+#endif
+ int status;
+ int retry = 5;
+ memset(buf, 0, bufsize);
+ do
+ {
+#ifdef HAVE_POLL
+ ufds.fd = fd;
+ ufds.events = POLLIN;
+ ufds.revents = 0;
+ (void) poll(&ufds, 1, 1000);
+#endif
+ status = read(fd, buf, bufsize - 1);
+ if (status <= 0)
+ sleep(1);
+ }
+ while ((status == 0) && (--retry != 0));
+ return status;
+}
+
+static void
+do_remote_cmd(const char *cmd, int nargs, ...)
+{
+ static char remote_hdr[] = "\033@\033(R\010\000\000REMOTE1";
+ static char remote_trailer[] = "\033\000\000\000\033\000";
+ int i;
+ va_list args;
+ va_start(args, nargs);
+
+ memcpy(printer_cmd + bufpos, remote_hdr, sizeof(remote_hdr) - 1);
+ bufpos += sizeof(remote_hdr) - 1;
+ memcpy(printer_cmd + bufpos, cmd, 2);
+ bufpos += 2;
+ printer_cmd[bufpos] = nargs % 256;
+ printer_cmd[bufpos + 1] = (nargs >> 8) % 256;
+ if (nargs > 0)
+ for (i = 0; i < nargs; i++)
+ printer_cmd[bufpos + 2 + i] = va_arg(args, int);
+ bufpos += 2 + nargs;
+ memcpy(printer_cmd + bufpos, remote_trailer, sizeof(remote_trailer) - 1);
+ bufpos += sizeof(remote_trailer) - 1;
+}
+
+static void
+add_newlines(int count)
+{
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ printer_cmd[bufpos++] = '\r';
+ printer_cmd[bufpos++] = '\n';
+ }
+}
+
+static void
+add_resets(int count)
+{
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ printer_cmd[bufpos++] = '\033';
+ printer_cmd[bufpos++] = '\000';
+ }
+}
+
+const char *colors[] =
+{
+ N_("Black"),
+ N_("Cyan"),
+ N_("Magenta"),
+ N_("Yellow"),
+ N_("Light Cyan"),
+ N_("Light Magenta"),
+ 0
+};
+
+void
+do_ink_level(void)
+{
+ int fd;
+ int status;
+ char buf[1024];
+ char *ind;
+ int i;
+ if (!raw_device)
+ {
+ fprintf(stderr,_("Obtaining ink levels requires using a raw device.\n"));
+ exit(1);
+ }
+ fd = open(raw_device, O_RDWR, 0666);
+ if (fd == -1)
+ {
+ fprintf(stderr, _("Cannot open %s read/write: %s\n"), raw_device,
+ strerror(errno));
+ exit(1);
+ }
+ initialize_print_cmd();
+ do_remote_cmd("ST", 2, 0, 1);
+ add_resets(2);
+ if (write(fd, printer_cmd, bufpos) < bufpos)
+ {
+ fprintf(stderr, _("Cannot write to %s: %s\n"), raw_device,
+ strerror(errno));
+ exit(1);
+ }
+ status = read_from_printer(fd, buf, 1024);
+ if (status < 0)
+ {
+ fprintf(stderr, _("Cannot read from %s: %s\n"),
+ raw_device,strerror(errno));
+ exit(1);
+ }
+ ind = buf;
+ do
+ ind = strchr(ind, 'I');
+ while (ind && ind[1] != 'Q' && (ind[1] != '\0' && ind[2] != ':'));
+ if (!ind || ind[1] != 'Q' || ind[2] != ':')
+ {
+ fprintf(stderr, _("Cannot parse output from printer\n"));
+ exit(1);
+ }
+ ind += 3;
+ printf("%20s %s\n", _("Ink color"), _("Percent remaining"));
+ for (i = 0; i < 6; i++)
+ {
+ int val, j;
+ if (!ind[0] || ind[0] == ';')
+ exit(0);
+ for (j = 0; j < 2; j++)
+ {
+ if (ind[j] >= '0' && ind[j] <= '9')
+ ind[j] -= '0';
+ else if (ind[j] >= 'A' && ind[j] <= 'F')
+ ind[j] = ind[j] - 'A' + 10;
+ else if (ind[j] >= 'a' && ind[j] <= 'f')
+ ind[j] = ind[j] - 'a' + 10;
+ else
+ exit(1);
+ }
+ val = (ind[0] << 4) + ind[1];
+ printf("%20s %3d\n", _(colors[i]), val);
+ ind += 2;
+ }
+ initialize_print_cmd();
+ do_remote_cmd("ST", 2, 0, 0);
+ add_resets(2);
+ (void) write(fd, printer_cmd, bufpos);
+ (void) read(fd, buf, 1024);
+ (void) close(fd);
+ exit(0);
+}
+
+void
+do_identify(void)
+{
+ int fd;
+ int status;
+ char buf[1024];
+ if (!raw_device)
+ {
+ fprintf(stderr,
+ _("Printer identification requires using a raw device.\n"));
+ exit(1);
+ }
+ fd = open(raw_device, O_RDWR, 0666);
+ if (fd == -1)
+ {
+ fprintf(stderr, _("Cannot open %s read/write: %s\n"), raw_device,
+ strerror(errno));
+ exit(1);
+ }
+ initialize_print_cmd();
+ add_resets(2);
+ (void) write(fd, printer_cmd, bufpos);
+ bufpos = 0;
+ sprintf(printer_cmd, "\033\001@EJL ID\r\n");
+ if (write(fd, printer_cmd, strlen(printer_cmd)) < strlen(printer_cmd))
+ {
+ fprintf(stderr, _("Cannot write to %s: %s\n"),
+ raw_device, strerror(errno));
+ exit(1);
+ }
+ status = read_from_printer(fd, buf, 1024);
+ if (status < 0)
+ {
+ fprintf(stderr, _("Cannot read from %s: %s\n"),
+ raw_device, strerror(errno));
+ exit(1);
+ }
+ printf("%s\n", buf);
+ (void) close(fd);
+ exit(0);
+}
+
+void
+do_status(void)
+{
+ int fd;
+ int status;
+ char buf[1024];
+ char *where;
+ memset(buf, 0, 1024);
+ if (!raw_device)
+ {
+ fprintf(stderr, _("Printer status requires using a raw device.\n"));
+ exit(1);
+ }
+ fd = open(raw_device, O_RDWR, 0666);
+ if (fd == -1)
+ {
+ fprintf(stderr, _("Cannot open %s read/write: %s\n"), raw_device,
+ strerror(errno));
+ exit(1);
+ }
+ bufpos = 0;
+ initialize_print_cmd();
+ do_remote_cmd("ST", 2, 0, 1);
+ if (write(fd, printer_cmd, bufpos) < bufpos)
+ {
+ fprintf(stderr, _("Cannot write to %s: %s\n"),
+ raw_device, strerror(errno));
+ exit(1);
+ }
+ status = read_from_printer(fd, buf, 1024);
+ if (status < 0)
+ {
+ fprintf(stderr, _("Cannot read from %s: %s\n"),
+ raw_device, strerror(errno));
+ exit(1);
+ }
+ initialize_print_cmd();
+ do_remote_cmd("ST", 2, 0, 0);
+ add_resets(2);
+ (void) write(fd, printer_cmd, bufpos);
+ (void) read(fd, buf, 1024);
+ while ((where = strchr(buf, ';')) != NULL)
+ *where = '\n';
+ printf("%s\n", buf);
+ (void) close(fd);
+ exit(0);
+}
+
+
+void
+do_head_clean(void)
+{
+ do_remote_cmd("CH", 2, 0, 0);
+ printf(_("Cleaning heads...\n"));
+ exit(do_print_cmd());
+}
+
+void
+do_nozzle_check(void)
+{
+ do_remote_cmd("VI", 2, 0, 0);
+ do_remote_cmd("NC", 2, 0, 0);
+ printf(_("Running nozzle check, please ensure paper is in the printer.\n"));
+ exit(do_print_cmd());
+}
+
+const char *new_align_help = N_("\
+Please read these instructions very carefully before proceeding.\n\
+\n\
+This utility lets you align the print head of your Epson Stylus inkjet\n\
+printer. Misuse of this utility may cause your print quality to degrade\n\
+and possibly damage your printer. This utility has not been reviewed by\n\
+Seiko Epson for correctness, and is offered with no warranty at all. The\n\
+entire risk of using this utility lies with you.\n\
+\n\
+This utility prints %d test patterns. Each pattern looks very similar.\n\
+The patterns consist of a series of pairs of vertical lines that overlap.\n\
+Below each pair of lines is a number between %d and %d.\n\
+\n\
+When you inspect the pairs of lines, you should find the pair of lines that\n\
+is best in alignment, that is, that best forms a single vertical line.\n\
+Inspect the pairs very carefully to find the best match. Using a loupe\n\
+or magnifying glass is recommended for the most critical inspection.\n\
+It is also suggested that you use a good quality paper for the test,\n\
+so that the lines are well-formed and do not spread through the paper.\n\
+After picking the number matching the best pair, place the paper back in\n\
+the paper input tray before typing it in.\n\
+\n\
+Each pattern is similar, but later patterns use finer dots for more\n\
+critical alignment. You must run all of the passes to correctly align your\n\
+printer. After running all the alignment passes, the alignment\n\
+patterns will be printed once more. You should find that the middle-most\n\
+pair (#%d out of the %d) is the best for all patterns.\n\
+\n\
+After the passes are printed once more, you will be offered the\n\
+choices of (s)aving the result in the printer, (r)epeating the process,\n\
+or (q)uitting without saving. Quitting will not restore the previous\n\
+settings, but powering the printer off and back on will. If you quit,\n\
+you must repeat the entire process if you wish to later save the results.\n\
+It is essential that you not turn your printer off during this procedure.\n\n");
+
+const char *old_align_help = N_("\
+Please read these instructions very carefully before proceeding.\n\
+\n\
+This utility lets you align the print head of your Epson Stylus inkjet\n\
+printer. Misuse of this utility may cause your print quality to degrade\n\
+and possibly damage your printer. This utility has not been reviewed by\n\
+Seiko Epson for correctness, and is offered with no warranty at all. The\n\
+entire risk of using this utility lies with you.\n\
+\n\
+This utility prints a test pattern that consist of a series of pairs of\n\
+vertical lines that overlap. Below each pair of lines is a number between\n\
+%d and %d.\n\
+\n\
+When you inspect the pairs of lines, you should find the pair of lines that\n\
+is best in alignment, that is, that best forms a single vertical align.\n\
+Inspect the pairs very carefully to find the best match. Using a loupe\n\
+or magnifying glass is recommended for the most critical inspection.\n\
+It is also suggested that you use a good quality paper for the test,\n\
+so that the lines are well-formed and do not spread through the paper.\n\
+After picking the number matching the best pair, place the paper back in\n\
+the paper input tray before typing it in.\n\
+\n\
+After running the alignment pattern, it will be printed once more. You\n\
+should find that the middle-most pair (#%d out of the %d) is the best.\n\
+You will then be offered the choices of (s)aving the result in the printer,\n\
+(r)epeating the process, or (q)uitting without saving. Quitting will not\n\
+restore the previous settings, but powering the printer off and back on will.\n\
+If you quit, you must repeat the entire process if you wish to later save\n\
+the results. It is essential that you not turn off your printer during\n\
+this procedure.\n\n");
+
+static void
+do_align_help(int passes, int choices)
+{
+ if (passes > 1)
+ printf(_(new_align_help), passes, 1, choices, (choices + 1) / 2, choices);
+ else
+ printf(_(old_align_help), 1, choices, (choices + 1) / 2, choices);
+ fflush(stdout);
+}
+
+static void
+printer_error(void)
+{
+ printf(_("Unable to send command to the printer, exiting.\n"));
+ exit(1);
+}
+
+static stp_printer_t *
+get_printer(void)
+{
+ stp_printer_t *printer = &printer_list[0];
+ if (!printer_model)
+ {
+ char buf[1024];
+ int fd;
+ int status;
+ char *pos = NULL;
+ char *spos = NULL;
+ if (!raw_device)
+ {
+ fprintf(stderr,
+ _("Printer alignment must be done with a raw device or else\n"
+ "the -m option must be used to specify a printer.\n"));
+ do_help(1);
+ }
+ printf(_("Attempting to detect printer model..."));
+ fflush(stdout);
+ fd = open(raw_device, O_RDWR, 0666);
+ if (fd == -1)
+ {
+ printf(_("\nCannot open %s read/write: %s\n"), raw_device,
+ strerror(errno));
+ exit(1);
+ }
+ bufpos = 0;
+ sprintf(printer_cmd, "\033\001@EJL ID\r\n");
+ if (write(fd, printer_cmd, strlen(printer_cmd)) < strlen(printer_cmd))
+ {
+ printf(_("\nCannot write to %s: %s\n"), raw_device, strerror(errno));
+ exit(1);
+ }
+ status = read_from_printer(fd, buf, 1024);
+ if (status < 0)
+ {
+ printf(_("\nCannot read from %s: %s\n"), raw_device,strerror(errno));
+ exit(1);
+ }
+ (void) close(fd);
+ pos = strchr(buf, (int) ';');
+ if (pos)
+ pos = strchr(pos + 1, (int) ';');
+ if (pos)
+ pos = strchr(pos, (int) ':');
+ if (pos)
+ spos = strchr(pos, (int) ';');
+ if (!pos)
+ {
+ printf(_("\nCannot detect printer type.\n"
+ "Please use -m to specify your printer model.\n"));
+ do_help(1);
+ }
+ if (spos)
+ *spos = '\000';
+ printer_model = pos + 1;
+ printf("%s\n\n", printer_model);
+ }
+ while (printer->short_name)
+ {
+ if (!strcasecmp(printer_model, printer->short_name) ||
+ !strcasecmp(printer_model, printer->long_name))
+ return printer;
+ else
+ printer++;
+ }
+ printf(_("Printer model %s is not known.\n"), printer_model);
+ do_help(1);
+ return 0;
+}
+
+static int
+do_final_alignment(void)
+{
+ while (1)
+ {
+ char *inbuf;
+ printf(_("Please inspect the final output very carefully to ensure that your\n"
+ "printer is in proper alignment. You may now:\n"
+ " (s)ave the results in the printer,\n"
+ " (q)uit without saving the results, or\n"
+ " (r)epeat the entire process from the beginning.\n"
+ "You will then be asked to confirm your choice.\n"
+ "What do you want to do (s, q, r)?\n"));
+ fflush(stdout);
+ inbuf = do_get_input(_("> "));
+ switch (inbuf[0])
+ {
+ case 'q':
+ case 'Q':
+ printf(_("Please confirm by typing 'q' again that you wish to quit without saving:\n"));
+ fflush(stdout);
+ inbuf = do_get_input (_("> "));
+ if (inbuf[0] == 'q' || inbuf[0] == 'Q')
+ {
+ printf(_("OK, your printer is aligned, but the alignment has not been saved.\n"
+ "If you wish to save the alignment, you must repeat this process.\n"));
+ return 1;
+ }
+ break;
+ case 'r':
+ case 'R':
+ printf(_("Please confirm by typing 'r' again that you wish to repeat the\n"
+ "alignment process:\n"));
+ fflush(stdout);
+ inbuf = do_get_input(_("> "));
+ if (inbuf[0] == 'r' || inbuf[0] == 'R')
+ {
+ printf(_("Repeating the alignment process.\n"));
+ return 0;
+ }
+ break;
+ case 's':
+ case 'S':
+ printf(_("This will permanently alter the configuration of your printer.\n"
+ "WARNING: this procedure has not been approved by Seiko Epson, and\n"
+ "it may damage your printer. Proceed?\n"
+ "Please confirm by typing 's' again that you wish to save the settings\n"
+ "to your printer:\n"));
+
+ fflush(stdout);
+ inbuf = do_get_input(_("> "));
+ if (inbuf[0] == 's' || inbuf[0] == 'S')
+ {
+ printf(_("Please insert your alignment test page in the printer once more\n"
+ "for the final save of your alignment settings. When the printer\n"
+ "feeds the page through, your settings have been saved.\n"));
+ fflush(stdout);
+ initialize_print_cmd();
+ add_newlines(2);
+ do_remote_cmd("SV", 0);
+ add_newlines(2);
+ if (do_print_cmd())
+ printer_error();
+ return 1;
+ }
+ break;
+ default:
+ printf(_("Unrecognized command.\n"));
+ continue;
+ }
+ printf(_("Final command was not confirmed.\n"));
+ }
+}
+
+const char *printer_msg =
+N_("This procedure assumes that your printer is an Epson %s.\n"
+ "If this is not your printer model, please type control-C now and\n"
+ "choose your actual printer model.\n\n"
+ "Please place a sheet of paper in your printer to begin the head\n"
+ "alignment procedure.\n");
+
+/*
+ * This is the thorny one.
+ */
+void
+do_align(void)
+{
+ char *inbuf;
+ long answer;
+ char *endptr;
+ int curpass;
+ const stp_printer_t *printer = get_printer();
+ int passes = printer->passes;
+ int choices = printer->choices;
+ const char *printer_name = printer->long_name;
+
+ do
+ {
+ do_align_help(passes, choices);
+ printf(_(printer_msg), _(printer_name));
+ inbuf = do_get_input(_("Press enter to continue > "));
+ initialize_print_cmd();
+ for (curpass = 1; curpass <= passes; curpass ++)
+ {
+ top:
+ add_newlines(7 * (curpass - 1));
+ do_remote_cmd("DT", 3, 0, curpass - 1, 0);
+ if (do_print_cmd())
+ printer_error();
+ reread:
+ if (curpass == passes)
+ printf(_("Please inspect the print, and choose the best pair of lines\n"
+ "in pattern #%d, and then insert a fresh page in the input tray.\n"
+ "Type a pair number, '?' for help, or 'r' to retry this pattern.\n"),
+ curpass);
+ else
+ printf(_("Please inspect the print, and choose the best pair of lines\n"
+ "in pattern #%d, and then reinsert the page in the input tray.\n"
+ "Type a pair number, '?' for help, or 'r' to retry this pattern.\n"),
+ curpass);
+ fflush(stdout);
+ inbuf = do_get_input(_("> "));
+ switch (inbuf[0])
+ {
+ case 'r':
+ case 'R':
+ printf(_("Please insert a fresh sheet of paper.\n"));
+ fflush(stdout);
+ initialize_print_cmd();
+ (void) do_get_input(_("Press enter to continue > "));
+ /* Ick. Surely there's a cleaner way? */
+ goto top;
+ case 'h':
+ case '?':
+ do_align_help(passes, choices);
+ fflush(stdout);
+ case '\n':
+ case '\000':
+ goto reread;
+ default:
+ break;
+ }
+ answer = strtol(inbuf, &endptr, 10);
+ if (errno == ERANGE)
+ {
+ printf(_("Number out of range!\n"));
+ goto reread;
+ }
+ if (endptr == inbuf)
+ {
+ printf(_("I cannot understand what you typed!\n"));
+ fflush(stdout);
+ goto reread;
+ }
+ if (answer < 1 || answer > choices)
+ {
+ printf(_("The best pair of lines should be numbered between 1 and %d.\n"),
+ choices);
+ fflush(stdout);
+ goto reread;
+ }
+ if (curpass == passes)
+ {
+ printf(_("Aligning phase %d, and performing final test.\n"
+ "Please insert a fresh sheet of paper.\n"), curpass);
+ (void) do_get_input(_("Press enter to continue > "));
+ }
+ else
+ printf(_("Aligning phase %d, and starting phase %d.\n"), curpass,
+ curpass + 1);
+ fflush(stdout);
+ initialize_print_cmd();
+ do_remote_cmd("DA", 4, 0, curpass - 1, 0, answer);
+ }
+ for (curpass = 0; curpass < passes; curpass++)
+ do_remote_cmd("DT", 3, 0, curpass, 0);
+ if (do_print_cmd())
+ printer_error();
+ } while (!do_final_alignment());
+ exit(0);
+}
+
+const char *color_align_help = N_("\
+Please read these instructions very carefully before proceeding.\n\
+\n\
+This utility lets you align the color print head of your Epson Stylus inkjet\n\
+printer. Misuse of this utility may cause your print quality to degrade\n\
+and possibly damage your printer. This utility has not been reviewed by\n\
+Seiko Epson for correctness, and is offered with no warranty at all. The\n\
+entire risk of using this utility lies with you.\n\
+\n\
+This utility prints %d overprinting test patterns on one piece of paper.\n\
+That is, it prints one pattern and ejects the page. You must then reinsert\n\
+the same page, and it will print another pattern. Each pattern consists of\n\
+a set of choices numbered between %d and %d.\n\
+\n\
+When you inspect the patterns, you should find one patch to have the\n\
+smoothest texture (least ``grain''). You should inspect the patches very\n\
+carefully to choose the best one. We suggest using Photo Quality Inkjet\n\
+Paper or a similar high quality paper for this test. If you do not find\n\
+a smooth pattern, you should repeat the test.\n\
+\n\
+After you inspect the choices and select a patch, you will be offered the\n\
+choices of (s)aving the result in the printer, (r)epeating the process,\n\
+or (q)uitting without saving. Quitting will not restore the previous\n\
+settings, but powering the printer off and back on will. If you quit,\n\
+you must repeat the entire process if you wish to later save the results.\n\
+It is essential that you not turn your printer off during this procedure.\n\
+\n\
+WARNING: THIS FUNCTION IS NOT YET TESTED! It may not work, and it may\n\
+damage your printer!\n");
+
+static void
+do_align_color_help(int passes, int choices)
+{
+ printf(color_align_help, 1, choices);
+ fflush(stdout);
+}
+
+void
+do_align_color(void)
+{
+ char *inbuf;
+ long answer;
+ char *endptr;
+ int curpass;
+ const stp_printer_t *printer = get_printer();
+ int passes = printer->color_passes;
+ int choices = printer->color_choices;
+ const char *printer_name = printer->long_name;
+ if (passes == 0)
+ {
+ printf(_("Printer %s does not require color head alignment.\n"),
+ printer_model);
+ exit(0);
+ }
+
+ do
+ {
+ do_align_color_help(passes, choices);
+ printf(_(printer_msg), _(printer_name));
+ inbuf = do_get_input(_("Press enter to continue > "));
+ for (curpass = 1; curpass <= passes; curpass ++)
+ {
+ initialize_print_cmd();
+ do_remote_cmd("DU", 6, 0, curpass, 0, 9, 0, curpass - 1);
+ if (do_print_cmd())
+ printer_error();
+ if (curpass < passes)
+ {
+ printf(_("Please re-insert the same alignment sheet in the printer when it is\n"
+ "finished printing.\n"));
+ (void) do_get_input(_("Press enter to continue > "));
+ }
+ }
+ reread:
+ printf(_("Inspect the alignment sheet, and determine which pattern is the smoothest.\n"
+ "This pattern will appear to have the least ``grain''.\n"
+ "If you cannot find a smooth pattern, please select the number for the\n"
+ "best pattern, and repeat the procedure.\n"
+ "Type a pattern number, or '?' for help.\n"));
+ fflush(stdout);
+ inbuf = do_get_input(_("> "));
+ if (!inbuf)
+ exit(1);
+ switch (inbuf[0])
+ {
+ case 'h':
+ case '?':
+ do_align_color_help(passes, choices);
+ fflush(stdout);
+ /* FALLTHROUGH */
+ case '\n':
+ case '\000':
+ goto reread;
+ default:
+ break;
+ }
+ answer = strtol(inbuf, &endptr, 10);
+ if (errno == ERANGE)
+ {
+ printf(_("Number out of range!\n"));
+ goto reread;
+ }
+ if (endptr == inbuf)
+ {
+ printf(_("I cannot understand what you typed!\n"));
+ fflush(stdout);
+ goto reread;
+ }
+ if (answer < 1 || answer > choices)
+ {
+ printf(_("The best pattern should be numbered between 1 and %d.\n"),
+ choices);
+ fflush(stdout);
+ goto reread;
+ }
+ initialize_print_cmd();
+ do_remote_cmd("DA", 6, 0, 0, 0, answer, 9, 0);
+ if (do_print_cmd())
+ printer_error();
+ } while (!do_final_alignment());
+ exit (0);
+}
+
+char *
+do_get_input (const char *prompt)
+{
+ static char *input = NULL;
+#if (HAVE_LIBREADLINE == 0 || !defined HAVE_READLINE_READLINE_H)
+ char *fgets_status;
+#endif
+ /* free only if previously allocated */
+ if (input)
+ {
+ free (input);
+ input = NULL;
+ }
+#if (HAVE_LIBREADLINE > 0 && defined HAVE_READLINE_READLINE_H)
+ /* get input with libreadline, if present */
+ input = readline ((char *) prompt);
+ /* if input, add to history list */
+#ifdef HAVE_READLINE_HISTORY_H
+ if (input && *input)
+ {
+ add_history (input);
+ }
+#endif
+#else
+ /* no libreadline; use fgets instead */
+ input = xmalloc (sizeof (char) * BUFSIZ);
+ memset(input, 0, BUFSIZ);
+ printf ("%s", prompt);
+ fgets_status = fgets (input, BUFSIZ, stdin);
+ if (fgets_status == NULL)
+ {
+ fprintf (stderr, _("Error in input\n"));
+ return (NULL);
+ }
+ else if (strlen (input) == 1 && input[0] == '\n')
+ {
+ /* user just hit enter: empty input buffer */
+ /* remove line feed */
+ input[0] = '\0';
+ }
+ else
+ {
+ /* remove line feed */
+ input[strlen (input) - 1] = '\0';
+ }
+#endif
+ return (input);
+}