diff --git a/ChangeLog b/ChangeLog index b602d6c5ae..469ecb2eb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2000-10-29 Michael Natterer + + * plug-ins/print/escputil.c + * plug-ins/print/.cvsignore + * plug-ins/print/Makefile.am: new tool which installs under + /bin and does stuff like cleaning and adjusting your + printer's head. + + * plug-ins/print/README + * plug-ins/print/RELNOTES: these files already say 4.0.1 now but I + didn't tag the sourceforge tree of bumped the version number in + Makefile.am (it's just about getting in the new executable as early + as possible). + 2000-10-29 Sven Neumann * plug-ins/common/screenshot.c: tuned the dialog layout and cleaned diff --git a/plug-ins/print/.cvsignore b/plug-ins/print/.cvsignore index 318a9682f0..39e273b681 100644 --- a/plug-ins/print/.cvsignore +++ b/plug-ins/print/.cvsignore @@ -4,3 +4,4 @@ Makefile _libs .libs print +escputil diff --git a/plug-ins/print/Makefile.am b/plug-ins/print/Makefile.am index 64ba79e4d8..4631820e1b 100644 --- a/plug-ins/print/Makefile.am +++ b/plug-ins/print/Makefile.am @@ -6,6 +6,8 @@ EXTRA_DIST = print-printers.c libexec_PROGRAMS = print +bin_PROGRAMS = escputil + print_SOURCES = \ print-canon.c \ print-dither.c \ @@ -24,6 +26,8 @@ print_SOURCES = \ gimp_main_window.c \ print_gimp.h +escputil_SOURCES = escputil.c + INCLUDES = \ -I$(top_srcdir) \ $(GTK_CFLAGS) \ @@ -44,6 +48,8 @@ LDADD = \ $(GTK_LIBS) \ $(INTLLIBS) +escputil_LDADD = + .PHONY: files files: diff --git a/plug-ins/print/README b/plug-ins/print/README index def6bc602a..bc42948958 100644 --- a/plug-ins/print/README +++ b/plug-ins/print/README @@ -1,7 +1,7 @@ -This is Gimp-Print version 4.0.0, the first stable release in the 4.0 -line. Gimp-print is the print facility for the Gimp, and in addition -a suite of drivers that may be used with common UNIX spooling systems -using GhostScript or CUPS. These drivers provide printing quality for +This is Gimp-Print version 4.0.1, a stable release in the 4.0 line. +Gimp-print is the print facility for the Gimp, and in addition a suite +of drivers that may be used with common UNIX spooling systems using +GhostScript or CUPS. These drivers provide printing quality for UNIX/Linux on a par with proprietary vendor-supplied drivers in many cases, and can be used for many of the most demanding printing tasks. diff --git a/plug-ins/print/RELNOTES b/plug-ins/print/RELNOTES index 464a14fe85..eaea1e55de 100644 --- a/plug-ins/print/RELNOTES +++ b/plug-ins/print/RELNOTES @@ -1,5 +1,4 @@ -This is gimp-print version 4.0.0, the first stable release in the 4.0 -line. +This is gimp-print version 4.0.1, a stable release in the 4.0 line. This software includes the Print plug-in for the Gimp (1.0, 1.1, and 1.2), and GhostScript and CUPS drivers. The support for printers in @@ -8,7 +7,18 @@ the Print plugin -- they use the identical code base. Please read Ghost/README and CUPS/README.txt for more information on this. -Gimp-Print 4.0.0 is a major release of the Gimp Print plugin and +Gimp-Print 4.0.1 contains the following fixes over Gimp-Print 4.0.0: + +1) The copy of escputil.c in the Ghost subdirectory was older than the + copy at top level. + +2) escputil in either location would fail to compile without the GNU + version of getopt() due to a syntax error. + +3) The INSTALL file referred to an old version of gimp-print. + + +Gimp-Print 4.0 is a major release of the Gimp Print plugin and associated stp GhostScript driver and CUPS driver. Among the new features over the 2.0 (distributed with the Gimp 1.0) and 3.0 (distributed with some versions of the Gimp 1.1) releases are: diff --git a/plug-ins/print/escputil.c b/plug-ins/print/escputil.c new file mode 100644 index 0000000000..88304b0997 --- /dev/null +++ b/plug-ins/print/escputil.c @@ -0,0 +1,891 @@ +/* + * "$Id$" + * + * Printer maintenance utility for Epson Stylus 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. + */ + +#include +#include +#include +#include +#include +#include +#ifdef __GNU_LIBRARY__ +#include +#endif + +char *banner = "\ +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' }, + { "usb", 0, NULL, (int) 'u' }, + { "help", 0, NULL, (int) 'h' }, + { "identify", 0, NULL, (int) 'd' }, + { "model", 1, NULL, (int) 'm' }, + { "quiet", 0, NULL, (int) 'q' }, + { NULL, 0, NULL, 0 } +}; + +char *help_msg = "\ +Usage: escputil [-P printer | -r device] [-m model] [-u]\n\ + [-c | -n | -a | -i] [-q]\n\ + -P|--printer-name Specify the name of the printer 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\ + -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 run a\n\ + head cleaning pass.\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\ + -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\ + -u|--usb The printer is connected via USB.\n\ + -h|--help Print this help message.\n\ + -q|--quiet Suppress the banner.\n\ + -m|--model Specify the precise printer model for head alignment.\n"; +#else +char *help_msg = "\ +Usage: escputil [-P printer | -r device] [-u] [-c | -n | -a | -i] [-q]\n\ + -P Specify the name of the printer 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\ + -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 run a\n\ + head cleaning pass.\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\ + -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\ + -u The printer is connected via USB.\n\ + -h Print this help message.\n\ + -q Suppress the banner.\n\ + -m Specify the precise printer model for head alignment.\n"; +#endif + +typedef struct +{ + char *short_name; + char *long_name; + int passes; + int choices; +} printer_t; + +printer_t printer_list[] = +{ + { "color", "Stylus Color", 1, 7 }, + { "pro", "Stylus Color Pro", 1, 7 }, + { "pro-xl", "Stylus Color Pro XL", 1, 7 }, + { "400", "Stylus Color 400", 1, 7 }, + { "440", "Stylus Color 440", 1, 15 }, + { "460", "Stylus Color 460", 1, 15 }, + { "480", "Stylus Color 480", 1, 15 }, + { "500", "Stylus Color 500", 1, 7 }, + { "600", "Stylus Color 600", 1, 7 }, + { "640", "Stylus Color 640", 1, 15 }, + { "660", "Stylus Color 660", 1, 15 }, + { "670", "Stylus Color 670", 3, 15 }, + { "740", "Stylus Color 740", 3, 15 }, + { "760", "Stylus Color 760", 3, 15 }, + { "800", "Stylus Color 800", 1, 7 }, + { "850", "Stylus Color 850", 1, 7 }, + { "860", "Stylus Color 860", 3, 15 }, + { "880", "Stylus Color 880", 3, 15 }, + { "900", "Stylus Color 900", 3, 15 }, + { "980", "Stylus Color 980", 3, 15 }, + { "1160", "Stylus Color 1160", 3, 15 }, + { "1500", "Stylus Color 1500", 1, 7 }, + { "1520", "Stylus Color 1520", 1, 7 }, + { "3000", "Stylus Color 3000", 1, 7 }, + { "photo", "Stylus Photo", 1, 7 }, + { "700", "Stylus Photo 700", 1, 7 }, + { "ex", "Stylus Photo EX", 1, 7 }, + { "720", "Stylus Photo 720", 3, 15 }, + { "750", "Stylus Photo 750", 3, 15 }, + { "870", "Stylus Photo 870", 3, 15 }, + { "1200", "Stylus Photo 1200", 3, 15 }, + { "1270", "Stylus Photo 1270", 3, 15 }, + { "2000", "Stylus Photo 2000P", 2, 15 }, + { NULL, NULL, 0, 0 } +}; + +void initialize_print_cmd(void); +void do_head_clean(void); +void do_nozzle_check(void); +void do_align(void); +void do_ink_level(void); +void do_identify(void); + +char *printer = NULL; +char *raw_device = NULL; +char *printer_model = NULL; +char printer_cmd[1025]; +int bufpos = 0; +int isUSB = 0; + +void +do_help(int code) +{ + printer_t *printer = &printer_list[0]; + printf("%s", help_msg); + printf("Available models are:\n"); + while (printer->short_name) + { + printf("%10s %s\n", printer->short_name, printer->long_name); + printer++; + } + exit(code); +} + +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:icnaduqm:", optlist, &option_index); +#else + c = getopt(argc, argv, "P:r:icnaduqm:"); +#endif + if (c == -1) + break; + switch (c) + { + case 'q': + quiet = 1; + break; + case 'c': + case 'i': + case 'n': + case 'a': + case 'd': + if (operation) + do_help(1); + operation = c; + break; + case 'P': + if (printer || raw_device) + { + printf("You may only specify one printer or raw device.\n"); + do_help(1); + } + printer = malloc(strlen(optarg) + 1); + strcpy(printer, optarg); + break; + case 'r': + if (printer || raw_device) + { + printf("You may only specify one printer or raw device.\n"); + do_help(1); + } + raw_device = malloc(strlen(optarg) + 1); + strcpy(raw_device, optarg); + break; + case 'm': + if (printer_model) + { + printf("You may only specify one printer model.\n"); + do_help(1); + } + printer_model = malloc(strlen(optarg) + 1); + strcpy(printer_model, optarg); + break; + case 'u': + isUSB = 1; + break; + case 'h': + do_help(0); + break; + default: + printf("%s\n", banner); + fprintf(stderr, "Unknown option %c\n", c); + do_help(1); + } + } + if (!quiet) + printf("%s\n", banner); + if (operation == 0) + do_help(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 'd': + do_identify(); + 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; +} + +void +initialize_print_cmd(void) +{ + bufpos = 0; + if (isUSB) + { + static char hdr[] = "\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@"; + memcpy(printer_cmd, hdr, sizeof(hdr) - 1); /* Do NOT include the null! */ + bufpos = sizeof(hdr) - 1; + } +} + +void +do_remote_cmd(char *cmd, int nargs, int a0, int a1, int a2, int a3) +{ + static char remote_hdr[] = "\033@\033(R\010\000\000REMOTE1"; + static char remote_trailer[] = "\033\000\000\000\033\000"; + 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) + printer_cmd[bufpos + 2] = a0; + if (nargs > 1) + printer_cmd[bufpos + 3] = a1; + if (nargs > 2) + printer_cmd[bufpos + 4] = a2; + if (nargs > 3) + printer_cmd[bufpos + 5] = a3; + bufpos += 2 + nargs; + memcpy(printer_cmd + bufpos, remote_trailer, sizeof(remote_trailer) - 1); + bufpos += sizeof(remote_trailer) - 1; +} + +void +add_newlines(int count) +{ + int i; + for (i = 0; i < count; i++) + { + printer_cmd[bufpos++] = '\r'; + printer_cmd[bufpos++] = '\n'; + } +} + +void +add_resets(int count) +{ + int i; + for (i = 0; i < count; i++) + { + printer_cmd[bufpos++] = '\033'; + printer_cmd[bufpos++] = '\000'; + } +} + +char *colors[] = { + "Black", "Cyan", "Magenta", "Yellow", "Light Cyan", "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); + } + do_remote_cmd("IQ", 1, 1, 0, 0, 0); + add_resets(2); + if (write(fd, printer_cmd, bufpos) < bufpos) + { + fprintf(stderr, "Cannot write to %s: %s\n", raw_device, strerror(errno)); + exit(1); + } + sleep(1); + memset(buf, 0, 1024); + status = read(fd, buf, 1023); + if (status < 0) + { + fprintf(stderr, "Cannot read from %s: %s\n", raw_device,strerror(errno)); + exit(1); + } + ind = strchr(buf, 'I'); + 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; + } + (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); + } + 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); + } + sleep(1); + memset(buf, 0, 1024); + status = read(fd, buf, 1023); + 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_head_clean(void) +{ + do_remote_cmd("CH", 2, 0, 0, 0, 0); + printf("Cleaning heads...\n"); + exit(do_print_cmd()); +} + +void +do_nozzle_check(void) +{ + do_remote_cmd("VI", 2, 0, 0, 0, 0); + do_remote_cmd("NC", 2, 0, 0, 0, 0); + printf("Running nozzle check, please ensure paper is in the printer.\n"); + exit(do_print_cmd()); +} + +char new_align_help[] = "\ +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"; + +char old_align_help[] = "\ +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"; + +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); +} + +void +align_error(void) +{ + printf("Unable to send command to the printer, exiting.\n"); + exit(1); +} + +/* + * This is the thorny one. + */ +void +do_align(void) +{ + char inbuf[64]; + long answer; + char *endptr; + int passes = 0; + int choices = 0; + int curpass; + int notfound = 1; + printer_t *printer = &printer_list[0]; + char *printer_name = NULL; + if (!printer_model) + { + char buf[1024]; + int fd; + int status; + char *pos = NULL; + char *spos = NULL; + if (!raw_device) + { + printf("Printer alignment must be done with a raw device or else\n"); + printf("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) + { + fprintf(stderr, "\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)) + { + fprintf(stderr, "\nCannot write to %s: %s\n", raw_device, + strerror(errno)); + exit(1); + } + sleep(1); + memset(buf, 0, 1024); + status = read(fd, buf, 1023); + if (status < 0) + { + fprintf(stderr, "\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) + { + fprintf(stderr, "\nCannot detect printer type. 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 && notfound) + { + if (!strcmp(printer_model, printer->short_name) || + !strcmp(printer_model, printer->long_name)) + { + passes = printer->passes; + choices = printer->choices; + printer_name = printer->long_name; + notfound = 0; + } + else + printer++; + } + if (notfound) + { + printf("Printer model %s is not known.\n", printer_model); + do_help(1); + } + + start: + do_align_help(passes, choices); + printf("This procedure assumes that your printer is an Epson %s.\n", + printer_name); + printf("If this is not your printer model, please type control-C now and\n"); + printf("choose your actual printer model.\n"); + printf("\n"); + printf("Please place a sheet of paper in your printer to begin the head\n"); + printf("alignment procedure.\n"); + memset(inbuf, 0, 64); + fflush(stdin); + fgets(inbuf, 63, stdin); + putc('\n', stdout); + fflush(stdout); + initialize_print_cmd(); + for (curpass = 1; curpass <= passes; curpass ++) + { + top: + add_newlines(7 * (curpass - 1)); + do_remote_cmd("DT", 3, 0, curpass - 1, 0, 0); + if (do_print_cmd()) + align_error(); + reread: + printf("Please inspect the print, and choose the best pair of lines\n"); + if (curpass == passes) + printf("in pattern #%d, and then insert a fresh page in the input tray.\n", + curpass); + else + printf("in pattern #%d, and then reinsert the page in the input tray.\n", + curpass); + printf("Type a pair number, '?' for help, or 'r' to retry this pattern. ==> "); + fflush(stdout); + memset(inbuf, 0, 64); + fflush(stdin); + fgets(inbuf, 63, stdin); + putc('\n', stdout); + switch (inbuf[0]) + { + case 'r': + case 'R': + printf("Please insert a fresh sheet of paper, and then type the enter key.\n"); + initialize_print_cmd(); + fflush(stdin); + fgets(inbuf, 15, stdin); + putc('\n', stdout); + fflush(stdout); + 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 (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", curpass); + printf("Please insert a fresh sheet of paper.\n"); + } + 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, 0); + if (do_print_cmd()) + align_error(); + read_final: + printf("Please inspect the final output very carefully to ensure that your\n"); + printf("printer is in proper alignment. You may now (s)ave the results in\n"); + printf("the printer, (q)uit without saving the results, or (r)epeat the entire\n"); + printf("process from the beginning. You will then be asked to confirm your choice\n"); + printf("What do you want to do (s, q, r)? "); + fflush(stdout); + memset(inbuf, 0, 64); + fflush(stdin); + fgets(inbuf, 15, stdin); + putc('\n', stdout); + switch (inbuf[0]) + { + case 'q': + case 'Q': + printf("Please confirm by typing 'q' again that you wish to quit without saving: "); + fflush(stdout); + memset(inbuf, 0, 64); + fflush(stdin); + putc('\n', stdout); + fgets(inbuf, 15, stdin); + if (inbuf[0] == 'q' || inbuf[0] == 'Q') + { + printf("OK, your printer is aligned, but the alignment has not been saved.\n"); + printf("If you wish to save the alignment, you must repeat this process.\n"); + exit(0); + } + break; + case 'r': + case 'R': + printf("Please confirm by typing 'r' again that you wish to repeat the\n"); + printf("alignment process: "); + fflush(stdout); + memset(inbuf, 0, 64); + fflush(stdin); + putc('\n', stdout); + fgets(inbuf, 15, stdin); + if (inbuf[0] == 'r' || inbuf[0] == 'R') + { + printf("Repeating the alignment process.\n"); + goto start; + } + break; + case 's': + case 'S': + printf("Please confirm by typing 's' again that you wish to save the settings\n"); + printf("to your printer. This will permanently alter the configuration of\n"); + printf("your printer. WARNING: this procedure has not been approved by\n"); + printf("Seiko Epson, and it may damage your printer. Proceed? "); + + fflush(stdout); + memset(inbuf, 0, 64); + fflush(stdin); + putc('\n', stdout); + fgets(inbuf, 15, stdin); + if (inbuf[0] == 's' || inbuf[0] == 'S') + { + printf("Please insert your alignment test page in the printer once more\n"); + printf("for the final save of your alignment settings. When the printer\n"); + printf("feeds the page through, your settings have been saved.\n"); + fflush(stdout); + initialize_print_cmd(); + add_newlines(2); + do_remote_cmd("SV", 0, 0, 0, 0, 0); + add_newlines(2); + if (do_print_cmd()) + align_error(); + exit(0); + } + break; + default: + printf("Unrecognized command.\n"); + goto read_final; + } + printf("Final command was not confirmed.\n"); + goto read_final; +}