1/* 2 * "$Id: plist.c,v 1.18 2008/07/04 14:29:28 rlk Exp $" 3 * 4 * Print plug-in for the GIMP. 5 * 6 * Copyright 1997-2000 Michael Sweet (mike@easysw.com) and 7 * Robert Krawitz (rlk@alum.mit.edu) 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the Free 11 * Software Foundation; either version 2 of the License, or (at your option) 12 * any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 * for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27 28#include <gutenprint/gutenprint-intl-internal.h> 29#include <gutenprint/gutenprint.h> 30#include <gutenprintui2/gutenprintui.h> 31#include "gutenprintui-internal.h" 32 33#include <unistd.h> 34#include <ctype.h> 35#include <stdio.h> 36#include <string.h> 37#include <errno.h> 38#include <locale.h> 39 40#include <sys/types.h> 41#include <signal.h> 42#include <sys/wait.h> 43 44typedef enum 45{ 46 PRINTERS_NONE, 47 PRINTERS_LPC, 48 PRINTERS_LPSTAT 49} printer_system_t; 50 51static int compare_printers (stpui_plist_t *p1, stpui_plist_t *p2); 52 53int stpui_plist_current = 0, /* Current system printer */ 54 stpui_plist_count = 0; /* Number of system printers */ 55stpui_plist_t *stpui_plist; /* System printers */ 56int stpui_show_all_paper_sizes = 0; 57static char *printrc_name = NULL; 58static char *image_type; 59static gint image_raw_channels = 0; 60static gint image_channel_depth = 8; 61static stp_string_list_t *default_parameters = NULL; 62stp_string_list_t *stpui_system_print_queues; 63static const char *copy_count_name = "STPUICopyCount"; 64 65#define SAFE_FREE(x) \ 66do \ 67{ \ 68 if ((x)) \ 69 g_free((char *)(x)); \ 70 ((x)) = NULL; \ 71} while (0) 72 73typedef struct 74{ 75 const char *printing_system_name; 76 const char *printing_system_text; 77 const char *print_command; 78 const char *queue_select; 79 const char *raw_flag; 80 const char *key_file; 81 const char *scan_command; 82 const char *copy_count_command; 83} print_system_t; 84 85/* 86 * Generic printing system, based on SysV lp 87 * 88 * CAUTION: Do not use lpstat -t or lpstat -p. 89 * See bug 742187 (huge delays with lpstat -d -p) for an explanation. 90 */ 91static const print_system_t default_printing_system = 92 { "SysV", N_("System V lp"), "lp -s", "-d", "-oraw", "/usr/bin/lp", 93 "/usr/bin/lpstat -v | awk '/^device for /i {sub(\":\", \"\", $3); print $3}'", 94 "-n" }; 95 96static print_system_t known_printing_systems[] = 97{ 98 { "CUPS", N_("CUPS"), "lp -s", "-d", "-oraw", "/usr/sbin/cupsd", 99 "/usr/bin/lpstat -v | awk '/^device for /i {sub(\":\", \"\", $3); print $3}'", 100 "-n" }, 101 { "SysV", N_("System V lp"), "lp -s", "-d", "-oraw", "/usr/bin/lp", 102 "/usr/bin/lpstat -v | awk '/^device for /i {sub(\":\", \"\", $3); print $3}'", 103 "-n" }, 104 { "lpd", N_("Berkeley lpd (/etc/lpc)"), "lpr", "-P", "-l", "/etc/lpc", 105 "/etc/lpc status | awk '/^...*:/ {sub(\":.*\", \"\"); print}'", 106 "-#" }, 107 { "lpd", N_("Berkeley lpd (/usr/bsd/lpc)"), "lpr", "-P", "-l", "/usr/bsd/lpc", 108 "/usr/bsd/lpc status | awk '/^...*:/ {sub(\":.*\", \"\"); print}'", 109 "-#" }, 110 { "lpd", N_("Berkeley lpd (/usr/etc/lpc"), "lpr", "-P", "-l", "/usr/etc/lpc", 111 "/usr/etc/lpc status | awk '/^...*:/ {sub(\":.*\", \"\"); print}'", 112 "-#" }, 113 { "lpd", N_("Berkeley lpd (/usr/libexec/lpc)"), "lpr", "-P", "-l", "/usr/libexec/lpc", 114 "/usr/libexec/lpc status | awk '/^...*:/ {sub(\":.*\", \"\"); print}'", 115 "-#" }, 116 { "lpd", N_("Berkeley lpd (/usr/sbin/lpc)"), "lpr", "-P", "-l", "/usr/sbin/lpc", 117 "/usr/sbin/lpc status | awk '/^...*:/ {sub(\":.*\", \"\"); print}'", 118 "-#" }, 119}; 120 121static unsigned print_system_count = sizeof(known_printing_systems) / sizeof(print_system_t); 122 123static const print_system_t *global_printing_system = NULL; 124 125static void 126initialize_default_parameters(void) 127{ 128 default_parameters = stp_string_list_create(); 129 stp_string_list_add_string(default_parameters, "PrintingSystem", "Autodetect"); 130 stp_string_list_add_string(default_parameters, "PrintCommand", ""); 131 stp_string_list_add_string(default_parameters, "QueueSelect", ""); 132 stp_string_list_add_string(default_parameters, "RawOutputFlag", ""); 133 stp_string_list_add_string(default_parameters, "ScanOnStartup", "False"); 134 stp_string_list_add_string(default_parameters, "ScanPrintersCommand", ""); 135} 136 137void 138stpui_set_global_parameter(const char *param, const char *value) 139{ 140 stp_string_list_remove_string(default_parameters, param); 141 stp_string_list_add_string(default_parameters, param, value); 142} 143 144const char * 145stpui_get_global_parameter(const char *param) 146{ 147 stp_param_string_t *ps = stp_string_list_find(default_parameters, param); 148 if (ps) 149 return ps->text; 150 else 151 return NULL; 152} 153 154static const print_system_t * 155identify_print_system(void) 156{ 157 int i; 158 if (!global_printing_system) 159 { 160 for (i = 0; i < print_system_count; i++) 161 { 162 if (!access(known_printing_systems[i].key_file, R_OK)) 163 { 164 global_printing_system = &(known_printing_systems[i]); 165 break; 166 } 167 } 168 if (!global_printing_system) 169 global_printing_system = &default_printing_system; 170 } 171 return global_printing_system; 172} 173 174char * 175stpui_build_standard_print_command(const stpui_plist_t *plist, 176 const stp_printer_t *printer) 177{ 178 const char *queue_name = stpui_plist_get_queue_name(plist); 179 const char *extra_options = stpui_plist_get_extra_printer_options(plist); 180 const char *family = stp_printer_get_family(printer); 181 int copy_count = stpui_plist_get_copy_count(plist); 182 int raw = 0; 183 char *print_cmd; 184 char *count_string = NULL; 185 char *quoted_queue_name = NULL; 186 if (!queue_name) 187 queue_name = ""; 188 identify_print_system(); 189 if (strcmp(family, "ps") == 0) 190 raw = 0; 191 else 192 raw = 1; 193 194 if (copy_count > 1) 195 stp_asprintf(&count_string, "%s %d ", 196 global_printing_system->copy_count_command, copy_count); 197 198 if (queue_name[0]) 199 quoted_queue_name = g_shell_quote(queue_name); 200 201 stp_asprintf(&print_cmd, "%s %s %s %s %s%s%s", 202 global_printing_system->print_command, 203 queue_name[0] ? global_printing_system->queue_select : "", 204 queue_name[0] ? quoted_queue_name : "", 205 count_string ? count_string : "", 206 raw ? global_printing_system->raw_flag : "", 207 extra_options ? " " : "", 208 extra_options ? extra_options : ""); 209 SAFE_FREE(count_string); 210 SAFE_FREE(quoted_queue_name); 211 return print_cmd; 212} 213 214static void 215append_external_options(char **command, const stp_vars_t *v) 216{ 217 stp_string_list_t *external_options; 218 if (! command || ! *command) 219 return; 220 external_options = stp_get_external_options(v); 221 if (external_options) 222 { 223 int count = stp_string_list_count(external_options); 224 int i; 225 for (i = 0; i < count; i++) 226 { 227 stp_param_string_t *param = stp_string_list_param(external_options, i); 228 char *quoted_name=g_shell_quote(param->name); 229 char *quoted_value=g_shell_quote(param->text); 230 stp_catprintf(command, " -o%s=%s", quoted_name, quoted_value); 231 SAFE_FREE(quoted_name); 232 SAFE_FREE(quoted_value); 233 } 234 stp_string_list_destroy(external_options); 235 } 236} 237 238 239void 240stpui_set_printrc_file(const char *name) 241{ 242 if (name && name == printrc_name) 243 return; 244 SAFE_FREE(printrc_name); 245 if (name) 246 printrc_name = g_strdup(name); 247 else 248 printrc_name = g_build_filename(g_get_home_dir(), ".gutenprintrc", NULL); 249} 250 251const char * 252stpui_get_printrc_file(void) 253{ 254 if (!printrc_name) 255 stpui_set_printrc_file(NULL); 256 return printrc_name; 257} 258 259#define PLIST_ACCESSORS(name) \ 260void \ 261stpui_plist_set_##name(stpui_plist_t *p, const char *val) \ 262{ \ 263 if (p->name == val) \ 264 return; \ 265 SAFE_FREE(p->name); \ 266 p->name = g_strdup(val); \ 267} \ 268 \ 269void \ 270stpui_plist_set_##name##_n(stpui_plist_t *p, const char *val, int n) \ 271{ \ 272 if (p->name == val) \ 273 return; \ 274 SAFE_FREE(p->name); \ 275 p->name = g_strndup(val, n); \ 276} \ 277 \ 278const char * \ 279stpui_plist_get_##name(const stpui_plist_t *p) \ 280{ \ 281 return p->name; \ 282} 283 284PLIST_ACCESSORS(output_filename) 285PLIST_ACCESSORS(name) 286PLIST_ACCESSORS(queue_name) 287PLIST_ACCESSORS(extra_printer_options) 288PLIST_ACCESSORS(custom_command) 289PLIST_ACCESSORS(current_standard_command) 290 291void 292stpui_plist_set_command_type(stpui_plist_t *p, command_t val) 293{ 294 switch (val) 295 { 296 case COMMAND_TYPE_DEFAULT: 297 case COMMAND_TYPE_CUSTOM: 298 case COMMAND_TYPE_FILE: 299 p->command_type = val; 300 break; 301 default: 302 p->command_type = COMMAND_TYPE_DEFAULT; 303 } 304} 305 306command_t 307stpui_plist_get_command_type(const stpui_plist_t *p) 308{ 309 return p->command_type; 310} 311 312void 313stpui_plist_set_copy_count(stpui_plist_t *p, gint copy_count) 314{ 315 if (copy_count > 0) 316 stp_set_int_parameter(p->v, copy_count_name, copy_count); 317} 318 319gint 320stpui_plist_get_copy_count(const stpui_plist_t *p) 321{ 322 if (stp_check_int_parameter(p->v, copy_count_name, STP_PARAMETER_ACTIVE)) 323 return stp_get_int_parameter(p->v, copy_count_name); 324 else 325 return 1; 326} 327 328void 329stpui_set_image_type(const char *itype) 330{ 331 image_type = g_strdup(itype); 332} 333 334void 335stpui_set_image_raw_channels(gint channels) 336{ 337 image_raw_channels = channels; 338} 339 340void 341stpui_set_image_channel_depth(gint depth) 342{ 343 image_channel_depth = depth; 344} 345 346static void 347writefunc(void *file, const char *buf, size_t bytes) 348{ 349 FILE *prn = (FILE *)file; 350 fwrite(buf, 1, bytes, prn); 351} 352 353static void 354stpui_errfunc(void *file, const char *buf, size_t bytes) 355{ 356 g_message("%s",buf); 357} 358 359void 360stpui_printer_initialize(stpui_plist_t *printer) 361{ 362 char tmp[32]; 363 stpui_plist_set_name(printer, ""); 364 stpui_plist_set_output_filename(printer, ""); 365 stpui_plist_set_queue_name(printer, ""); 366 stpui_plist_set_extra_printer_options(printer, ""); 367 stpui_plist_set_custom_command(printer, ""); 368 stpui_plist_set_current_standard_command(printer, ""); 369 printer->command_type = COMMAND_TYPE_DEFAULT; 370 printer->scaling = 100.0; 371 printer->orientation = ORIENT_AUTO; 372 printer->auto_size_roll_feed_paper = 0; 373 printer->unit = 0; 374 printer->v = stp_vars_create(); 375 stp_set_errfunc(printer->v, writefunc); 376 stp_set_errdata(printer->v, stderr); 377 stpui_plist_set_copy_count(printer, 1); 378 stp_set_string_parameter(printer->v, "InputImageType", image_type); 379 if (image_raw_channels) 380 { 381 (void) sprintf(tmp, "%d", image_raw_channels); 382 stp_set_string_parameter(printer->v, "RawChannels", tmp); 383 } 384 if (image_channel_depth) 385 { 386 (void) sprintf(tmp, "%d", image_channel_depth); 387 stp_set_string_parameter(printer->v, "ChannelBitDepth", tmp); 388 } 389 printer->invalid_mask = INVALID_TOP | INVALID_LEFT; 390} 391 392static void 393stpui_plist_destroy(stpui_plist_t *printer) 394{ 395 SAFE_FREE(printer->name); 396 SAFE_FREE(printer->queue_name); 397 SAFE_FREE(printer->extra_printer_options); 398 SAFE_FREE(printer->custom_command); 399 SAFE_FREE(printer->current_standard_command); 400 SAFE_FREE(printer->output_filename); 401 stp_vars_destroy(printer->v); 402} 403 404void 405stpui_plist_copy(stpui_plist_t *vd, const stpui_plist_t *vs) 406{ 407 if (vs == vd) 408 return; 409 stp_vars_copy(vd->v, vs->v); 410 vd->scaling = vs->scaling; 411 vd->orientation = vs->orientation; 412 vd->auto_size_roll_feed_paper = vs->auto_size_roll_feed_paper; 413 vd->unit = vs->unit; 414 vd->invalid_mask = vs->invalid_mask; 415 vd->command_type = vs->command_type; 416 stpui_plist_set_name(vd, stpui_plist_get_name(vs)); 417 stpui_plist_set_queue_name(vd, stpui_plist_get_queue_name(vs)); 418 stpui_plist_set_extra_printer_options(vd, stpui_plist_get_extra_printer_options(vs)); 419 stpui_plist_set_custom_command(vd, stpui_plist_get_custom_command(vs)); 420 stpui_plist_set_current_standard_command(vd, stpui_plist_get_current_standard_command(vs)); 421 stpui_plist_set_output_filename(vd, stpui_plist_get_output_filename(vs)); 422 stpui_plist_set_copy_count(vd, stpui_plist_get_copy_count(vs)); 423} 424 425static stpui_plist_t * 426allocate_stpui_plist_copy(const stpui_plist_t *vs) 427{ 428 stpui_plist_t *rep = g_malloc(sizeof(stpui_plist_t)); 429 memset(rep, 0, sizeof(stpui_plist_t)); 430 rep->v = stp_vars_create(); 431 stpui_plist_copy(rep, vs); 432 return rep; 433} 434 435static void 436check_plist(int count) 437{ 438 static int current_plist_size = 0; 439 int i; 440 if (count <= current_plist_size) 441 return; 442 else if (current_plist_size == 0) 443 { 444 current_plist_size = count; 445 stpui_plist = g_malloc(current_plist_size * sizeof(stpui_plist_t)); 446 for (i = 0; i < current_plist_size; i++) 447 { 448 memset(&(stpui_plist[i]), 0, sizeof(stpui_plist_t)); 449 stpui_printer_initialize(&(stpui_plist[i])); 450 } 451 } 452 else 453 { 454 int old_plist_size = current_plist_size; 455 current_plist_size *= 2; 456 if (current_plist_size < count) 457 current_plist_size = count; 458 stpui_plist = g_realloc(stpui_plist, current_plist_size * sizeof(stpui_plist_t)); 459 for (i = old_plist_size; i < current_plist_size; i++) 460 { 461 memset(&(stpui_plist[i]), 0, sizeof(stpui_plist_t)); 462 stpui_printer_initialize(&(stpui_plist[i])); 463 } 464 } 465} 466 467#define GET_MANDATORY_INTERNAL_STRING_PARAM(param) \ 468do { \ 469 if ((commaptr = strchr(lineptr, ',')) == NULL) \ 470 continue; \ 471 stpui_plist_set_##param##_n(&key, lineptr, commaptr - line); \ 472 lineptr = commaptr + 1; \ 473} while (0) 474 475#define GET_MANDATORY_STRING_PARAM(param) \ 476do { \ 477 if ((commaptr = strchr(lineptr, ',')) == NULL) \ 478 continue; \ 479 stp_set_##param##_n(key.v, lineptr, commaptr - line); \ 480 lineptr = commaptr + 1; \ 481} while (0) 482 483static int 484get_mandatory_string_param(stp_vars_t *v, const char *param, char **lineptr) 485{ 486 char *commaptr = strchr(*lineptr, ','); 487 if (commaptr == NULL) 488 return 0; 489 stp_set_string_parameter_n(v, param, *lineptr, commaptr - *lineptr); 490 *lineptr = commaptr + 1; 491 return 1; 492} 493 494static int 495get_mandatory_file_param(stp_vars_t *v, const char *param, char **lineptr) 496{ 497 char *commaptr = strchr(*lineptr, ','); 498 if (commaptr == NULL) 499 return 0; 500 stp_set_file_parameter_n(v, param, *lineptr, commaptr - *lineptr); 501 *lineptr = commaptr + 1; 502 return 1; 503} 504 505#define GET_MANDATORY_INT_PARAM(param) \ 506do { \ 507 if ((commaptr = strchr(lineptr, ',')) == NULL) \ 508 continue; \ 509 stp_set_##param(key.v, atoi(lineptr)); \ 510 lineptr = commaptr + 1; \ 511} while (0) 512 513#define GET_MANDATORY_INTERNAL_INT_PARAM(param) \ 514do { \ 515 if ((commaptr = strchr(lineptr, ',')) == NULL) \ 516 continue; \ 517 key.param = atoi(lineptr); \ 518 lineptr = commaptr + 1; \ 519} while (0) 520 521static void 522get_optional_string_param(stp_vars_t *v, const char *param, 523 char **lineptr, int *keepgoing) 524{ 525 if (*keepgoing) 526 { 527 char *commaptr = strchr(*lineptr, ','); 528 if (commaptr == NULL) 529 { 530 stp_set_string_parameter(v, param, *lineptr); 531 *keepgoing = 0; 532 } 533 else 534 { 535 stp_set_string_parameter_n(v, param, *lineptr, commaptr - *lineptr); 536 *lineptr = commaptr + 1; 537 } 538 } 539} 540 541#define GET_OPTIONAL_INT_PARAM(param) \ 542do { \ 543 if ((keepgoing == 0) || ((commaptr = strchr(lineptr, ',')) == NULL)) \ 544 { \ 545 keepgoing = 0; \ 546 } \ 547 else \ 548 { \ 549 stp_set_##param(key.v, atoi(lineptr)); \ 550 lineptr = commaptr + 1; \ 551 } \ 552} while (0) 553 554#define GET_OPTIONAL_INTERNAL_INT_PARAM(param) \ 555do { \ 556 if ((keepgoing == 0) || ((commaptr = strchr(lineptr, ',')) == NULL)) \ 557 { \ 558 keepgoing = 0; \ 559 } \ 560 else \ 561 { \ 562 key.param = atoi(lineptr); \ 563 lineptr = commaptr + 1; \ 564 } \ 565} while (0) 566 567#define IGNORE_OPTIONAL_PARAM(param) \ 568do { \ 569 if ((keepgoing == 0) || ((commaptr = strchr(lineptr, ',')) == NULL)) \ 570 { \ 571 keepgoing = 0; \ 572 } \ 573 else \ 574 { \ 575 lineptr = commaptr + 1; \ 576 } \ 577} while (0) 578 579static void 580get_optional_float_param(stp_vars_t *v, const char *param, 581 char **lineptr, int *keepgoing) 582{ 583 if (*keepgoing) 584 { 585 char *commaptr = strchr(*lineptr, ','); 586 if (commaptr == NULL) 587 { 588 stp_set_float_parameter(v, param, atof(*lineptr)); 589 *keepgoing = 0; 590 } 591 else 592 { 593 stp_set_float_parameter(v, param, atof(*lineptr)); 594 *lineptr = commaptr + 1; 595 } 596 } 597} 598 599#define GET_OPTIONAL_INTERNAL_FLOAT_PARAM(param) \ 600do { \ 601 if ((keepgoing == 0) || ((commaptr = strchr(lineptr, ',')) == NULL)) \ 602 { \ 603 keepgoing = 0; \ 604 } \ 605 else \ 606 { \ 607 key.param = atof(lineptr); \ 608 } \ 609} while (0) 610 611static void * 612psearch(const void *key, void *base, size_t nmemb, size_t size, 613 int (*compar)(const void *, const void *)) 614{ 615 int i; 616 char *cbase = (char *) base; 617 for (i = 0; i < nmemb; i++) 618 { 619 if ((*compar)(key, (const void *) cbase) == 0) 620 return (void *) cbase; 621 cbase += size; 622 } 623 return NULL; 624} 625 626stpui_plist_t * 627stpui_plist_create(const char *name, const char *driver) 628{ 629 stpui_plist_t key; 630 stpui_plist_t *answer = NULL; 631 memset(&key, 0, sizeof(key)); 632 stpui_printer_initialize(&key); 633 key.invalid_mask = 0; 634 stpui_plist_set_name(&key, name); 635 stp_set_driver(key.v, driver); 636 if (stpui_plist_add(&key, 0)) 637 answer = psearch(&key, stpui_plist, stpui_plist_count, 638 sizeof(stpui_plist_t), 639 (int (*)(const void *, const void *)) compare_printers); 640 SAFE_FREE(key.name); 641 SAFE_FREE(key.queue_name); 642 SAFE_FREE(key.extra_printer_options); 643 SAFE_FREE(key.custom_command); 644 SAFE_FREE(key.current_standard_command); 645 SAFE_FREE(key.output_filename); 646 stp_vars_destroy(key.v); 647 return answer; 648} 649 650int 651stpui_plist_add(const stpui_plist_t *key, int add_only) 652{ 653 /* 654 * The format of the list is the File printer followed by a qsort'ed list 655 * of system printers. So, if we want to update the file printer, it is 656 * always first in the list, else call psearch. 657 */ 658 stpui_plist_t *p; 659 if (!stp_get_printer(key->v)) 660 stp_set_driver(key->v, "ps2"); 661 if (stp_get_printer(key->v)) 662 { 663 p = psearch(key, stpui_plist, stpui_plist_count, 664 sizeof(stpui_plist_t), 665 (int (*)(const void *, const void *)) compare_printers); 666 if (p == NULL) 667 { 668#ifdef DEBUG 669 fprintf(stderr, "Adding new printer from printrc file: %s\n", 670 key->name); 671#endif 672 check_plist(stpui_plist_count + 1); 673 p = stpui_plist + stpui_plist_count; 674 stpui_plist_count++; 675 stpui_plist_copy(p, key); 676 if (strlen(stpui_plist_get_queue_name(p)) == 0 && 677 stp_string_list_is_present(stpui_system_print_queues, 678 stpui_plist_get_name(p))) 679 stpui_plist_set_queue_name(p, stpui_plist_get_name(p)); 680 } 681 else 682 { 683 if (add_only) 684 return 0; 685#ifdef DEBUG 686 fprintf(stderr, "Updating printer %s.\n", key->name); 687#endif 688 stpui_plist_copy(p, key); 689 } 690 return 1; 691 } 692 else 693 { 694 fprintf(stderr, "No printer found!\n"); 695 return 0; 696 } 697} 698 699static void 700stpui_printrc_load_v0(FILE *fp) 701{ 702 char line[1024]; /* Line in printrc file */ 703 char *lineptr; /* Pointer in line */ 704 char *commaptr; /* Pointer to next comma */ 705 stpui_plist_t key; /* Search key */ 706 int keepgoing = 1; 707 (void) memset(line, 0, 1024); 708 (void) memset(&key, 0, sizeof(stpui_plist_t)); 709 stpui_printer_initialize(&key); 710 key.name = g_strdup(_("File")); 711 while (fgets(line, sizeof(line), fp) != NULL) 712 { 713 /* 714 * Read old format printrc lines... 715 */ 716 717 stpui_printer_initialize(&key); 718 key.invalid_mask = 0; 719 lineptr = line; 720 721 /* 722 * Read the command-delimited printer definition data. Note that 723 * we can't use sscanf because %[^,] fails if the string is empty... 724 */ 725 726 GET_MANDATORY_INTERNAL_STRING_PARAM(name); 727 GET_MANDATORY_INTERNAL_STRING_PARAM(custom_command); 728 GET_MANDATORY_STRING_PARAM(driver); 729 730 if (! stp_get_printer(key.v)) 731 continue; 732 733 if (!get_mandatory_file_param(key.v, "PPDFile", &lineptr)) 734 continue; 735 if ((commaptr = strchr(lineptr, ',')) != NULL) 736 { 737 switch (atoi(lineptr)) 738 { 739 case 1: 740 stp_set_string_parameter(key.v, "PrintingMode", "Color"); 741 break; 742 case 0: 743 default: 744 stp_set_string_parameter(key.v, "PrintingMode", "BW"); 745 break; 746 } 747 } 748 else 749 continue; 750 751 if (!get_mandatory_string_param(key.v, "Resolution", &lineptr)) 752 continue; 753 if (!get_mandatory_string_param(key.v, "PageSize", &lineptr)) 754 continue; 755 if (!get_mandatory_string_param(key.v, "MediaType", &lineptr)) 756 continue; 757 758 get_optional_string_param(key.v, "InputSlot", &lineptr, &keepgoing); 759 get_optional_float_param(key.v, "Brightness", &lineptr, &keepgoing); 760 761 GET_OPTIONAL_INTERNAL_FLOAT_PARAM(scaling); 762 GET_OPTIONAL_INTERNAL_INT_PARAM(orientation); 763 GET_OPTIONAL_INT_PARAM(left); 764 GET_OPTIONAL_INT_PARAM(top); 765 get_optional_float_param(key.v, "Gamma", &lineptr, &keepgoing); 766 get_optional_float_param(key.v, "Contrast", &lineptr, &keepgoing); 767 get_optional_float_param(key.v, "Cyan", &lineptr, &keepgoing); 768 get_optional_float_param(key.v, "Magenta", &lineptr, &keepgoing); 769 get_optional_float_param(key.v, "Yellow", &lineptr, &keepgoing); 770 IGNORE_OPTIONAL_PARAM(linear); 771 IGNORE_OPTIONAL_PARAM(image_type); 772 get_optional_float_param(key.v, "Saturation", &lineptr, &keepgoing); 773 get_optional_float_param(key.v, "Density", &lineptr, &keepgoing); 774 get_optional_string_param(key.v, "InkType", &lineptr, &keepgoing); 775 get_optional_string_param(key.v,"DitherAlgorithm",&lineptr,&keepgoing); 776 GET_OPTIONAL_INTERNAL_INT_PARAM(unit); 777 stpui_plist_add(&key, 0); 778 g_free(key.name); 779 stp_vars_destroy(key.v); 780 } 781 stpui_plist_current = 0; 782} 783 784static void 785stpui_printrc_load_v1(FILE *fp) 786{ 787 char line[1024]; /* Line in printrc file */ 788 stpui_plist_t key; /* Search key */ 789 char * current_printer = 0; /* printer to select */ 790 (void) memset(line, 0, 1024); 791 (void) memset(&key, 0, sizeof(stpui_plist_t)); 792 stpui_printer_initialize(&key); 793 key.name = g_strdup(_("File")); 794 while (fgets(line, sizeof(line), fp) != NULL) 795 { 796 /* 797 * Read new format printrc lines... 798 */ 799 800 char *keyword, *end, *value; 801 802 keyword = line; 803 for (keyword = line; g_ascii_isspace(*keyword); keyword++) 804 { 805 /* skip initial spaces... */ 806 } 807 if (!g_ascii_isalpha(*keyword)) 808 continue; 809 for (end = keyword; g_ascii_isalnum(*end) || *end == '-'; end++) 810 { 811 /* find end of keyword... */ 812 } 813 value = end; 814 while (g_ascii_isspace(*value)) 815 { 816 /* skip over white space... */ 817 value++; 818 } 819 if (*value != ':') 820 continue; 821 value++; 822 *end = '\0'; 823 while (g_ascii_isspace(*value)) 824 { 825 /* skip over white space... */ 826 value++; 827 } 828 for (end = value; *end && *end != '\n'; end++) 829 { 830 /* find end of line... */ 831 } 832 *end = '\0'; 833#ifdef DEBUG 834 fprintf(stderr, "Keyword = `%s', value = `%s'\n", keyword, value); 835#endif 836 if (strcasecmp("current-printer", keyword) == 0) 837 { 838 SAFE_FREE(current_printer); 839 current_printer = g_strdup(value); 840 } 841 else if (strcasecmp("printer", keyword) == 0) 842 { 843 /* Switch to printer named VALUE */ 844 stpui_plist_add(&key, 0); 845#ifdef DEBUG 846 fprintf(stderr, 847 "output_to is now %s\n", stpui_plist_get_output_to(&key)); 848#endif 849 850 stp_vars_destroy(key.v); 851 stpui_printer_initialize(&key); 852 key.invalid_mask = 0; 853 stpui_plist_set_name(&key, value); 854 } 855 else if (strcasecmp("destination", keyword) == 0) 856 stpui_plist_set_custom_command(&key, value); 857 else if (strcasecmp("driver", keyword) == 0) 858 stp_set_driver(key.v, value); 859 else if (strcasecmp("ppd-file", keyword) == 0) 860 stp_set_file_parameter(key.v, "PPDFile", value); 861 else if (strcasecmp("output-type", keyword) == 0) 862 { 863 switch (atoi(value)) 864 { 865 case 1: 866 stp_set_string_parameter(key.v, "PrintingMode", "Color"); 867 break; 868 case 0: 869 default: 870 stp_set_string_parameter(key.v, "PrintingMode", "BW"); 871 break; 872 } 873 } 874 else if (strcasecmp("media-size", keyword) == 0) 875 stp_set_string_parameter(key.v, "PageSize", value); 876 else if (strcasecmp("media-type", keyword) == 0) 877 stp_set_string_parameter(key.v, "MediaType", value); 878 else if (strcasecmp("media-source", keyword) == 0) 879 stp_set_float_parameter(key.v, "Brightness", atof(value)); 880 else if (strcasecmp("scaling", keyword) == 0) 881 key.scaling = atof(value); 882 else if (strcasecmp("orientation", keyword) == 0) 883 key.orientation = atoi(value); 884 else if (strcasecmp("left", keyword) == 0) 885 stp_set_left(key.v, atoi(value)); 886 else if (strcasecmp("top", keyword) == 0) 887 stp_set_top(key.v, atoi(value)); 888 else if (strcasecmp("linear", keyword) == 0) 889 /* Ignore linear */ 890 ; 891 else if (strcasecmp("image-type", keyword) == 0) 892 /* Ignore image type */ 893 ; 894 else if (strcasecmp("unit", keyword) == 0) 895 key.unit = atoi(value); 896 else if (strcasecmp("custom-page-width", keyword) == 0) 897 stp_set_page_width(key.v, atoi(value)); 898 else if (strcasecmp("custom-page-height", keyword) == 0) 899 stp_set_page_height(key.v, atoi(value)); 900 /* Special case Ink-Type and Dither-Algorithm */ 901 else if (strcasecmp("ink-type", keyword) == 0) 902 stp_set_string_parameter(key.v, "InkType", value); 903 else if (strcasecmp("dither-algorithm", keyword) == 0) 904 stp_set_string_parameter(key.v, "DitherAlgorithm", value); 905 else 906 { 907 stp_parameter_t desc; 908 stp_curve_t *curve; 909 stp_describe_parameter(key.v, keyword, &desc); 910 switch (desc.p_type) 911 { 912 case STP_PARAMETER_TYPE_STRING_LIST: 913 stp_set_string_parameter(key.v, keyword, value); 914 break; 915 case STP_PARAMETER_TYPE_FILE: 916 stp_set_file_parameter(key.v, keyword, value); 917 break; 918 case STP_PARAMETER_TYPE_DOUBLE: 919 stp_set_float_parameter(key.v, keyword, atof(value)); 920 break; 921 case STP_PARAMETER_TYPE_INT: 922 stp_set_int_parameter(key.v, keyword, atoi(value)); 923 break; 924 case STP_PARAMETER_TYPE_BOOLEAN: 925 stp_set_boolean_parameter(key.v, keyword, atoi(value)); 926 break; 927 case STP_PARAMETER_TYPE_CURVE: 928 curve = stp_curve_create_from_string(value); 929 if (curve) 930 { 931 stp_set_curve_parameter(key.v, keyword, curve); 932 stp_curve_destroy(curve); 933 } 934 break; 935 default: 936 if (strlen(value)) 937 { 938 char buf[1024]; 939 snprintf(buf, sizeof(buf), 940 "Unrecognized keyword `%s' in printrc; value `%s' (%d)\n", 941 keyword, value, desc.p_type); 942 } 943 } 944 stp_parameter_description_destroy(&desc); 945 } 946 } 947 if (strlen(key.name) > 0) 948 { 949 stpui_plist_add(&key, 0); 950 stp_vars_destroy(key.v); 951 g_free(key.name); 952 } 953 if (current_printer) 954 { 955 int i; 956 for (i = 0; i < stpui_plist_count; i ++) 957 if (strcmp(current_printer, stpui_plist[i].name) == 0) 958 stpui_plist_current = i; 959 } 960} 961 962char *stpui_printrc_current_printer = NULL; 963extern FILE *yyin; 964extern int yyparse(void); 965 966static void 967stpui_printrc_load_v2(FILE *fp) 968{ 969 int retval; 970 char *locale; 971 yyin = fp; 972 973 stpui_printrc_current_printer = NULL; 974#ifdef HAVE_LOCALE_H 975 locale = g_strdup(setlocale(LC_NUMERIC, NULL)); 976 setlocale(LC_NUMERIC, "C"); 977#endif 978 retval = yyparse(); 979#ifdef HAVE_LOCALE_H 980 setlocale(LC_NUMERIC, locale); 981 SAFE_FREE(locale); 982#endif 983 if (stpui_printrc_current_printer) 984 { 985 int i; 986 for (i = 0; i < stpui_plist_count; i ++) 987 { 988 if (strcmp(stpui_printrc_current_printer, stpui_plist[i].name) == 0) 989 stpui_plist_current = i; 990 if (!stp_check_boolean_parameter(stpui_plist[i].v, 991 "PageSizeExtended", 992 STP_PARAMETER_ACTIVE)) 993 stp_set_boolean_parameter(stpui_plist[i].v, "PageSizeExtended", 0); 994 } 995 SAFE_FREE(stpui_printrc_current_printer); 996 } 997} 998 999/* 1000 * 'stpui_printrc_load()' - Load the printer resource configuration file. 1001 */ 1002void 1003stpui_printrc_load(void) 1004{ 1005 FILE *fp; /* Printrc file */ 1006 char line[1024]; /* Line in printrc file */ 1007 int format = 0; /* rc file format version */ 1008 const char *filename = stpui_get_printrc_file(); 1009 1010 initialize_default_parameters(); 1011 check_plist(1); 1012 1013 /* 1014 * Get the printer list... 1015 */ 1016 1017 stpui_get_system_printers(); 1018 1019 if ((fp = fopen(filename, "r")) != NULL) 1020 { 1021 (void) memset(line, 0, 1024); 1022 if (fgets(line, sizeof(line), fp) != NULL) 1023 { 1024#ifdef HAVE_LOCALE_H 1025 char *locale = g_strdup(setlocale(LC_NUMERIC, NULL)); 1026 setlocale(LC_NUMERIC, "C"); 1027#endif 1028 if (strncmp("#PRINTRCv", line, 9) == 0) 1029 { 1030 /* Force locale to "C", so that numbers scan correctly */ 1031#ifdef DEBUG 1032 fprintf(stderr, "Found printrc version tag: `%s'\n", line); 1033 fprintf(stderr, "Version number: `%s'\n", &(line[9])); 1034#endif 1035 (void) sscanf(&(line[9]), "%d", &format); 1036 } 1037#ifdef HAVE_LOCALE_H 1038 setlocale(LC_NUMERIC, locale); 1039 SAFE_FREE(locale); 1040#endif 1041 } 1042 rewind(fp); 1043 switch (format) 1044 { 1045 case 0: 1046 stpui_printrc_load_v0(fp); 1047 break; 1048 case 1: 1049 stpui_printrc_load_v1(fp); 1050 break; 1051 case 2: 1052 case 3: 1053 case 4: 1054 stpui_printrc_load_v2(fp); 1055 break; 1056 } 1057 (void) fclose(fp); 1058 } 1059 if (stpui_plist_count == 0) 1060 stpui_plist_create(_("Printer"), "ps2"); 1061} 1062 1063/* 1064 * 'stpui_printrc_save()' - Save the current printer resource configuration. 1065 */ 1066void 1067stpui_printrc_save(void) 1068{ 1069 FILE *fp; /* Printrc file */ 1070 int i; /* Looping var */ 1071 size_t global_settings_count = stp_string_list_count(default_parameters); 1072 stpui_plist_t *p; /* Current printer */ 1073 const char *filename = stpui_get_printrc_file(); 1074 1075 1076 if ((fp = fopen(filename, "w")) != NULL) 1077 { 1078 /* 1079 * Write the contents of the printer list... 1080 */ 1081 1082 /* Force locale to "C", so that numbers print correctly */ 1083#ifdef HAVE_LOCALE_H 1084 char *locale = g_strdup(setlocale(LC_NUMERIC, NULL)); 1085 setlocale(LC_NUMERIC, "C"); 1086#endif 1087#ifdef DEBUG 1088 fprintf(stderr, "Number of printers: %d\n", stpui_plist_count); 1089#endif 1090 1091 fputs("#PRINTRCv4 written by Gutenprint " PLUG_IN_VERSION "\n\n", fp); 1092 1093 fprintf(fp, "Global-Settings:\n"); 1094 fprintf(fp, " Current-Printer: \"%s\"\n", 1095 stpui_plist[stpui_plist_current].name); 1096 fprintf(fp, " Show-All-Paper-Sizes: %s\n", 1097 stpui_show_all_paper_sizes ? "True" : "False"); 1098 for (i = 0; i < global_settings_count; i++) 1099 { 1100 stp_param_string_t *ps = stp_string_list_param(default_parameters, i); 1101 fprintf(fp, " %s \"%s\"\n", ps->name, ps->text); 1102 } 1103 fprintf(fp, "End-Global-Settings:\n"); 1104 1105 for (i = 0, p = stpui_plist; i < stpui_plist_count; i ++, p ++) 1106 { 1107 int count; 1108 int j; 1109 stp_parameter_list_t *params = stp_get_parameter_list(p->v); 1110 count = stp_parameter_list_count(params); 1111 fprintf(fp, "\nPrinter: \"%s\" \"%s\"\n", 1112 p->name, stp_get_driver(p->v)); 1113 fprintf(fp, " Command-Type: %d\n", p->command_type); 1114 fprintf(fp, " Queue-Name: \"%s\"\n", p->queue_name); 1115 fprintf(fp, " Output-Filename: \"%s\"\n", p->output_filename); 1116 fprintf(fp, " Extra-Printer-Options: \"%s\"\n", p->extra_printer_options); 1117 fprintf(fp, " Custom-Command: \"%s\"\n", p->custom_command); 1118 fprintf(fp, " Scaling: %.3f\n", p->scaling); 1119 fprintf(fp, " Orientation: %d\n", p->orientation); 1120 fprintf(fp, " Autosize-Roll-Paper: %d\n", p->auto_size_roll_feed_paper); 1121 fprintf(fp, " Unit: %d\n", p->unit); 1122 1123 fprintf(fp, " Left: %d\n", stp_get_left(p->v)); 1124 fprintf(fp, " Top: %d\n", stp_get_top(p->v)); 1125 fprintf(fp, " Custom_Page_Width: %d\n", stp_get_page_width(p->v)); 1126 fprintf(fp, " Custom_Page_Height: %d\n", stp_get_page_height(p->v)); 1127 fprintf(fp, " Parameter %s Int True %d\n", copy_count_name, 1128 stpui_plist_get_copy_count(p)); 1129 1130 for (j = 0; j < count; j++) 1131 { 1132 const stp_parameter_t *param = stp_parameter_list_param(params, j); 1133 if (strcmp(param->name, "AppGamma") == 0) 1134 continue; 1135 switch (param->p_type) 1136 { 1137 case STP_PARAMETER_TYPE_STRING_LIST: 1138 if (stp_check_string_parameter(p->v, param->name, 1139 STP_PARAMETER_INACTIVE)) 1140 fprintf(fp, " Parameter %s String %s \"%s\"\n", 1141 param->name, 1142 ((stp_get_string_parameter_active 1143 (p->v, param->name) == STP_PARAMETER_ACTIVE) ? 1144 "True" : "False"), 1145 stp_get_string_parameter(p->v, param->name)); 1146 break; 1147 case STP_PARAMETER_TYPE_FILE: 1148 if (stp_check_file_parameter(p->v, param->name, 1149 STP_PARAMETER_INACTIVE)) 1150 fprintf(fp, " Parameter %s File %s \"%s\"\n", param->name, 1151 ((stp_get_file_parameter_active 1152 (p->v, param->name) == STP_PARAMETER_ACTIVE) ? 1153 "True" : "False"), 1154 stp_get_file_parameter(p->v, param->name)); 1155 break; 1156 case STP_PARAMETER_TYPE_DOUBLE: 1157 if (stp_check_float_parameter(p->v, param->name, 1158 STP_PARAMETER_INACTIVE)) 1159 fprintf(fp, " Parameter %s Double %s %f\n", param->name, 1160 ((stp_get_float_parameter_active 1161 (p->v, param->name) == STP_PARAMETER_ACTIVE) ? 1162 "True" : "False"), 1163 stp_get_float_parameter(p->v, param->name)); 1164 break; 1165 case STP_PARAMETER_TYPE_DIMENSION: 1166 if (stp_check_dimension_parameter(p->v, param->name, 1167 STP_PARAMETER_INACTIVE)) 1168 fprintf(fp, " Parameter %s Dimension %s %d\n", param->name, 1169 ((stp_get_dimension_parameter_active 1170 (p->v, param->name) == STP_PARAMETER_ACTIVE) ? 1171 "True" : "False"), 1172 stp_get_dimension_parameter(p->v, param->name)); 1173 break; 1174 case STP_PARAMETER_TYPE_INT: 1175 if (stp_check_int_parameter(p->v, param->name, 1176 STP_PARAMETER_INACTIVE)) 1177 fprintf(fp, " Parameter %s Int %s %d\n", param->name, 1178 ((stp_get_int_parameter_active 1179 (p->v, param->name) == STP_PARAMETER_ACTIVE) ? 1180 "True" : "False"), 1181 stp_get_int_parameter(p->v, param->name)); 1182 break; 1183 case STP_PARAMETER_TYPE_BOOLEAN: 1184 if (stp_check_boolean_parameter(p->v, param->name, 1185 STP_PARAMETER_INACTIVE)) 1186 fprintf(fp, " Parameter %s Boolean %s %s\n", param->name, 1187 ((stp_get_boolean_parameter_active 1188 (p->v, param->name) == STP_PARAMETER_ACTIVE) ? 1189 "True" : "False"), 1190 (stp_get_boolean_parameter(p->v, param->name) ? 1191 "True" : "False")); 1192 break; 1193 case STP_PARAMETER_TYPE_CURVE: 1194 if (stp_check_curve_parameter(p->v, param->name, 1195 STP_PARAMETER_INACTIVE)) 1196 { 1197 const stp_curve_t *curve = 1198 stp_get_curve_parameter(p->v, param->name); 1199 if (curve) 1200 { 1201 fprintf(fp, " Parameter %s Curve %s '", 1202 param->name, 1203 ((stp_get_curve_parameter_active 1204 (p->v, param->name) == 1205 STP_PARAMETER_ACTIVE) ? 1206 "True" : "False")); 1207 stp_curve_write(fp, curve); 1208 fprintf(fp, "'\n"); 1209 } 1210 } 1211 break; 1212 default: 1213 break; 1214 } 1215 } 1216 stp_parameter_list_destroy(params); 1217#ifdef DEBUG 1218 fprintf(stderr, "Wrote printer %d: %s\n", i, p->name); 1219#endif 1220 } 1221#ifdef HAVE_LOCALE_H 1222 setlocale(LC_NUMERIC, locale); 1223 SAFE_FREE(locale); 1224#endif 1225 fclose(fp); 1226 } 1227 else 1228 fprintf(stderr, "could not open printrc file \"%s\"\n",filename); 1229} 1230 1231/* 1232 * 'compare_printers()' - Compare system printer names for qsort(). 1233 */ 1234 1235static int 1236compare_printers(stpui_plist_t *p1, stpui_plist_t *p2) 1237{ 1238 return (strcmp(p1->name, p2->name)); 1239} 1240 1241/* 1242 * 'stpui_get_system_printers()' - Get a complete list of printers from the spooler. 1243 */ 1244 1245void 1246stpui_get_system_printers(void) 1247{ 1248 FILE *pfile; /* Pipe to status command */ 1249 char line[1025]; /* Line from status command */ 1250 1251 stpui_system_print_queues = stp_string_list_create(); 1252 stp_string_list_add_string(stpui_system_print_queues, "", 1253 _("(Default Printer)")); 1254 1255 /* 1256 * Run the command, if any, to get the available printers... 1257 */ 1258 1259 identify_print_system(); 1260 if (global_printing_system) 1261 { 1262 const char *old_locale = getenv("LC_ALL"); 1263 const char *old_lc_messages = getenv("LC_MESSAGES"); 1264 const char *old_lang = getenv("LANG"); 1265 (void) setenv("LC_ALL", "C", 1); 1266 (void) setenv("LC_MESSAGES", "C", 1); 1267 (void) setenv("LANG", "C", 1); 1268 if ((pfile = popen(global_printing_system->scan_command, "r")) != NULL) 1269 { 1270 /* 1271 * Read input as needed... 1272 */ 1273 1274 while (fgets(line, sizeof(line), pfile) != NULL) 1275 { 1276 char *tmp_ptr; 1277 if ((tmp_ptr = strchr(line, '\n'))) 1278 tmp_ptr[0] = '\0'; 1279 if ((tmp_ptr = strchr(line, '\r'))) 1280 tmp_ptr[0] = '\0'; 1281 if (strlen(line) > 0) 1282 { 1283 if (!stp_string_list_is_present(stpui_system_print_queues, line)) 1284 stp_string_list_add_string(stpui_system_print_queues, 1285 line, line); 1286 } 1287 } 1288 pclose(pfile); 1289 if (old_locale) 1290 setenv("LC_ALL", old_locale, 1); 1291 else 1292 unsetenv("LC_ALL"); 1293 if (old_lc_messages) 1294 setenv("LC_MESSAGES", old_lc_messages, 1); 1295 else 1296 unsetenv("LC_MESSAGES"); 1297 if (old_lang) 1298 setenv("LANG", old_lang, 1); 1299 else 1300 unsetenv("LANG"); 1301 } 1302 } 1303} 1304 1305const stpui_plist_t * 1306stpui_get_current_printer(void) 1307{ 1308 return &(stpui_plist[stpui_plist_current]); 1309} 1310 1311/* 1312 * 'usr1_handler()' - Make a note when we receive SIGUSR1. 1313 */ 1314 1315static volatile int usr1_interrupt; 1316 1317static void 1318usr1_handler (int sig) 1319{ 1320 usr1_interrupt = 1; 1321} 1322 1323/* 1324 * 1325 * Process control for actually printing. Documented 20040821 1326 * by Robert Krawitz. 1327 * 1328 * In addition to the print command itself and the output generator, 1329 * we spawn two additional processes to monitor the print job and clean 1330 * up. We do this because the GIMP is very unfriendly about how it 1331 * terminates plugins when the user cancels an operation: it sends a 1332 * SIGKILL, which prevents the plugin from cleaning up. Since the 1333 * plugin is sending data to an lpr process, this SIGKILL closes off 1334 * the input to lpr. lpr doesn't know that its parent has died 1335 * inappropriately, and happily proceeds to print the partial job. 1336 * 1337 * (The child may not actually be lpr, of course, but we'll just use 1338 * that nomenclature for convenience.) 1339 * 1340 * The first such process is the "lpr monitor". Its job is to 1341 * watch the parent (the actual data generator). If its parent dies, 1342 * it kills the print command. Notice that it must keep the file 1343 * descriptor used to write to the lpr process open, since as soon as 1344 * the last writer to this pipe is closed, the lpr process sees its 1345 * input close. Therefore, it first kills the child with SIGTERM and 1346 * then closes the pipe. Perhaps a more robust method would be to 1347 * send a SIGTERM followed by a SIGKILL, but we can worry about that 1348 * later. The lpr monitor process is killed with SIGUSR1 by the 1349 * master upon successful completion, at which point it exits. The lpr 1350 * monitor itself detects that the master has finished by periodically 1351 * sending it a kill 0 (a null signal). When the parent exits, this 1352 * attempt to signal will return failure. This has a potential race 1353 * condition if another process is created with the same PID between 1354 * checks. A more robust (but more complicated) solution would involve 1355 * IPC of some kind. 1356 * 1357 * The second such process (the "error monitor") monitors the stderr 1358 * (and stdout) of the lpr process, to send any error messages back 1359 * to the user. Since the GIMP is normally not launched from a 1360 * terminal window, any errors would get lost. The error monitor 1361 * captures this output and reports it back. It stays around until 1362 * its input is closed (normally by the lpr process exiting), at 1363 * which point it reports to the master that it has finished, and the 1364 * master can clean up and return. 1365 * 1366 * The actual master process spawns the lpr monitor, which spawns 1367 * the process that will later run the lpr command, which itself 1368 * spawns the error monitor. 1369 * 1370 * This architecture is perhaps unnecessarily complex; the lpr monitor 1371 * and error monitor could perhaps be combined into a single process 1372 * that watches both for the parent to go away and for the error messages. 1373 * 1374 * The following diagrams illustrate the control flow during the normal 1375 * case and also when the print job is cancelled. The notation for file 1376 * descriptors is a number prefixed with < for an input file descriptor 1377 * and suffixed > for an output file descriptor. For example, <0 means 1378 * input file descriptor 0 and 1> means output file descriptor 1. The 1379 * key to the file descriptors is given below. A file descriptor named 1380 * x,y refers to file descriptor y duplicated onto file descriptor x. 1381 * So "<0,3" means input file descriptor 3 (pipefd[0]) dup2'ed onto 1382 * file descriptor 0. 1383 * 1384 * fd0 = fd 0 1385 * fd1 = fd 1 1386 * fd2 = fd 2 1387 * fd3 = pipefd[0] 1388 * fd4 = pipefd[1] 1389 * fd5 = syncfd[0] 1390 * fd6 = syncfd[1] 1391 * fd7 = errfd[0] 1392 * fd8 = errfd[1] 1393 * 1394 * 1395 * NORMAL CASE 1396 * 1397 * PARENT CHILD 1 CHILD 2 CHILD 3 1398 * (print generator) (lpr monitor) (print command) (error monitor) 1399 * | 1400 * stpui_print 1401 * | 1402 * | <0 1> 2> 1403 * | 1404 * | pipe(syncfd) 1405 * | 1406 * | <0 1> 2> <5 6> 1407 * | 1408 * | pipe(pipefd) 1409 * | 1410 * | <0 1> 2> <3 4> 1411 * | <5 6> 1412 * | 1413 * | fork =============| 1414 * | | 1415 * | close(63) | close(syncfd[0]) 1416 * | | <0 1> 2> <3 4> 1417 * | <0 1> 2> 4> <5 | 6> 1418 * | | 1419 * | | fork =============| 1420 * | | | 1421 * | | close(01263) | dup2(pipefd[0], 0) 1422 * | | | close(pipefd[0] 1423 * | | 4> | close(pipefd[1] 1424 * | | | 1425 * | | | 1> 2> <0,3 6> 1426 * | | | 1427 * | | | pipe(errfd) 1428 * | | | 1> 2> <0,3 6> 1429 * | | | <7 8> 1430 * | | | 1431 * | | | fork =============| 1432 * | | | | close(012348) 1433 * | | | close(12) | 6> <7 1434 * | | | | 1435 * | | | <0,3 6> <7 8> | 1436 * | | | | 1437 * | | | dup2(errfd[1],1) | 1438 * | | | dup2(errfd[1],2) | 1439 * | | | close(errfd[1]) | 1440 * | | | close(pipefd[0]) | 1441 * | | | close(pipefd[1]) | 1442 * | | | close(syncfd[1]) | 1443 * |<<<<<<<<<<<<<<<<<<<|kill(0,0) * EXEC lpr | 1444 * |>>>>>>>>>>>>>>>>>>>|OK | <0,3 1,8> 2,8> | 1445 * | | | | 1446 * | write>>>>>>>>>>>>>+>>>>>>>>>>>>>>>>>>>| | 1447 * | | | write(2,8)??>>>>>>|read(<7)->warn 1448 * | | | | 1449 * | close(4)>>>>>>>>>>+>>>>>>>>>>>>>>>>>>>| | 1450 * | <0 1> 2> <5 | | | 1451 * | kill>>>>>>>>>>>>>>| | | 1452 * | | close(4)>>>>>>>>>>| eof(<0,3) | 1453 * | | | | 1454 * | | *no open fd* | 1,8> 2,8> | 1455 * | | exit | | 1456 * | | | exit>>>>>>>>>>>>>>| eof(<7) 1457 * | wait<<<<<<<<<<<<<<X X | 6> 1458 * | | 1459 * | read(<5)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<| write(6>) 1460 * | | 1461 * | close(5) | exit 1462 * | X 1463 * | 0< 1> 2> 1464 * | 1465 * | return 1466 * X 1467 * 1468 * 1469 * ERROR CASE (job cancelled) 1470 * 1471 * PARENT CHILD 1 CHILD 2 CHILD 3 1472 * (print generator) (lpr monitor) (print command) (error monitor) 1473 * | 1474 * stpui_print 1475 * | 1476 * | <0 1> 2> 1477 * | 1478 * | pipe(syncfd) 1479 * | 1480 * | <0 1> 2> <5 6> 1481 * | 1482 * | pipe(pipefd) 1483 * | 1484 * | <0 1> 2> <3 4> 1485 * | <5 6> 1486 * | 1487 * | fork =============| 1488 * | | 1489 * | close(63) | close(syncfd[0] 1490 * | | <0 1> 2> <3 4> 1491 * | <0 1> 2> 4> <5 | 6> 1492 * | | 1493 * | | fork =============| 1494 * | | | 1495 * | | close(01263) | dup2(pipefd[0], 0) 1496 * | | | close(pipefd[0] 1497 * | | 4> | close(pipefd[1] 1498 * | | | 1499 * | | | 1> 2> <3,0 6> 1500 * | | | 1501 * | | | pipe(errfd) 1502 * | | | 1> 2> <3,0 6> 1503 * | | | <7 8> 1504 * | | | 1505 * | | | fork =============| 1506 * | | | | close(012348) 1507 * | | | close(12) | 6> <7 1508 * | | | | 1509 * | | | <3,0 6> <7 8> | 1510 * | | | | 1511 * | | | dup2(errfd[1],1) | 1512 * | | | dup2(errfd[1],2) | 1513 * | | | close(3468) | 1514 * |<<<<<<<<<<<<<<<<<<<|kill(0,0) * EXEC lpr | 1515 * |>>>>>>>>>>>>>>>>>>>|OK | <0,3 1,8> 2,8> | 1516 * | | | | 1517 * | write>>>>>>>>>>>>>+>>>>>>>>>>>>>>>>>>>| | 1518 * | | | write(2,8)??>>>>>>|read(<7)->warn 1519 * | KILLED | | | 1520 * | close(01245)>>>>>>+>>>>>>>>>>>>>>>>>>>| | 1521 * X | | | 1522 * <<<<<<<<<<<<<<<<<<<|kill(0,0) | | 1523 * >>>>>>>>>>>>>>>>>>>|DEAD! | | 1524 * |kill(2)>>>>>>>>>>>>|Terminated | 1525 * |close(4>)>>>>>>>>>>|eof(0,3) | 1526 * | | 1,8> 2,8> | 1527 * | *no open fd* |exit>>>>>>>>>>>>>>>|eof(7) 1528 * | exit X | 1529 * X | 6> 1530 * <| write(6) 1531 * | exit/SIGPIPE 1532 * X 1533 */ 1534 1535int 1536stpui_print(const stpui_plist_t *printer, stpui_image_t *image) 1537{ 1538 int ppid = getpid (), /* PID of plugin */ 1539 opid, /* PID of output process */ 1540 cpid = 0, /* PID of control/monitor process */ 1541 pipefd[2], /* Fds of the pipe connecting all the above */ 1542 errfd[2], /* Message logger from lp command */ 1543 syncfd[2]; /* Sync the logger */ 1544 FILE *prn = NULL; /* Print file/command */ 1545 int do_sync = 0; 1546 int print_status = 0; 1547 int dummy; 1548 1549 /* 1550 * Open the file/execute the print command... 1551 */ 1552 1553 if (stpui_plist_get_command_type(printer) == COMMAND_TYPE_DEFAULT || 1554 stpui_plist_get_command_type(printer) == COMMAND_TYPE_CUSTOM) 1555 { 1556 /* 1557 * The following IPC code is only necessary because the GIMP kills 1558 * plugins with SIGKILL if its "Cancel" button is pressed; this 1559 * gives the plugin no chance whatsoever to clean up after itself. 1560 */ 1561 do_sync = 1; 1562 usr1_interrupt = 0; 1563 signal (SIGUSR1, usr1_handler); 1564 if (pipe (syncfd) != 0) 1565 { 1566 do_sync = 0; 1567 } 1568 if (pipe (pipefd) != 0) 1569 { 1570 prn = NULL; 1571 } 1572 else 1573 { 1574 cpid = fork (); 1575 if (cpid < 0) /* Error */ 1576 { 1577 do_sync = 0; 1578 prn = NULL; 1579 } 1580 else if (cpid == 0) /* Child 1 (lpr monitor and printer command) */ 1581 { 1582 /* LPR monitor process. Printer output is piped to us. */ 1583 close(syncfd[0]); 1584 opid = fork (); 1585 if (opid < 0) 1586 { 1587 /* Errors will cause the plugin to get a SIGPIPE. */ 1588 exit (1); 1589 } 1590 else if (opid == 0) /* Child 2 (printer command) */ 1591 { 1592 dup2 (pipefd[0], 0); 1593 close (pipefd[0]); 1594 close (pipefd[1]); 1595 if (pipe(errfd) == 0) 1596 { 1597 opid = fork(); 1598 if (opid < 0) 1599 _exit(1); 1600 else if (opid == 0) /* Child 3 (monitors stderr) */ 1601 { 1602 stp_outfunc_t errfunc = stpui_get_errfunc(); 1603 void *errdata = stpui_get_errdata(); 1604 /* calls g_message on anything it sees */ 1605 char buf[4096]; 1606 1607 close (pipefd[0]); 1608 close (pipefd[1]); 1609 close (0); 1610 close (1); 1611 close (2); 1612 close (errfd[1]); 1613 while (1) 1614 { 1615 ssize_t bytes = read(errfd[0], buf, 4095); 1616 if (bytes > 0) 1617 { 1618 buf[bytes] = '\0'; 1619 (*errfunc)(errdata, buf, bytes); 1620 } 1621 else 1622 { 1623 if (bytes < 0) 1624 { 1625 snprintf(buf, 4095, 1626 "Read messages failed: %s\n", 1627 strerror(errno)); 1628 (*errfunc)(errdata, buf, strlen(buf)); 1629 } 1630 write(syncfd[1], "Done", 5); 1631 _exit(0); 1632 } 1633 } 1634 write(syncfd[1], "Done", 5); 1635 _exit(0); 1636 } 1637 else /* Child 2 (printer command) */ 1638 { 1639 char *command; 1640 char *locale; 1641 if (stpui_plist_get_command_type(printer) == 1642 COMMAND_TYPE_DEFAULT) 1643 { 1644 command = 1645 stpui_build_standard_print_command 1646 (printer, stp_get_printer(printer->v)); 1647 append_external_options(&command, printer->v); 1648 } 1649 else 1650 command = 1651 (char *) stpui_plist_get_custom_command(printer); 1652 (void) close(2); 1653 (void) close(1); 1654 dup2 (errfd[1], 2); 1655 dup2 (errfd[1], 1); 1656 close(errfd[1]); 1657 close (pipefd[0]); 1658 close (pipefd[1]); 1659 close(syncfd[1]); 1660#ifdef HAVE_LOCALE_H 1661 locale = g_strdup(setlocale(LC_NUMERIC, NULL)); 1662 setlocale(LC_NUMERIC, "C"); 1663#endif 1664 execl("/bin/sh", "/bin/sh", "-c", command, NULL); 1665 /* NOTREACHED */ 1666 _exit (1); 1667 } 1668 /* NOTREACHED */ 1669 _exit(1); 1670 } 1671 else /* pipe() failed! */ 1672 { 1673 _exit(1); 1674 } 1675 } 1676 else /* Child 1 (lpr monitor) */ 1677 { 1678 /* 1679 * If the print plugin gets SIGKILLed by gimp, we kill lpr 1680 * in turn. If the plugin signals us with SIGUSR1 that it's 1681 * finished printing normally, we close our end of the pipe, 1682 * and go away. 1683 * 1684 * Note that we keep pipefd[1] -- which is the pipe from 1685 * the print plugin to the lpr process -- open during this. 1686 * If we don't, and the parent gets killed, lpr will notice 1687 * its stdin getting closed off and start printing. 1688 * This way its stdin stays open until we kill it. 1689 */ 1690 close (0); 1691 close (1); 1692 close (2); 1693 close (syncfd[1]); 1694 close (pipefd[0]); 1695 while (usr1_interrupt == 0) 1696 { 1697 /* 1698 * Note potential race condition, if some other process 1699 * happens to get the same pid! 1700 */ 1701 if (kill (ppid, 0) < 0) 1702 { 1703 /* 1704 * The print plugin has been killed! 1705 * Note that there is no possibility of the print 1706 * job sending us a SIGUSR1 and then exiting; 1707 * the parent (print plugin) stays around after 1708 * sending us the SIGUSR1, and then waits 1709 * for us to die. 1710 */ 1711 kill (opid, SIGTERM); 1712 waitpid (opid, &dummy, 0); 1713 close (pipefd[1]); 1714 /* 1715 * We do not want to allow cleanup before exiting. 1716 * The exiting parent has already closed the 1717 * connection to the X server; if we try to clean 1718 * up, we'll notice that fact and complain. 1719 */ 1720 _exit (0); 1721 } 1722 sleep (5); 1723 } 1724 /* We got SIGUSR1. */ 1725 close (pipefd[1]); 1726 /* 1727 * We do not want to allow cleanup before exiting. 1728 * The exiting parent has already closed the connection 1729 * to the X server; if we try to clean up, we'll notice 1730 * that fact and complain. 1731 */ 1732 _exit (0); 1733 } 1734 } 1735 else /* Parent (actually generates the output) */ 1736 { 1737 close (syncfd[1]); 1738 close (pipefd[0]); 1739 /* Parent process. We generate the printer output. */ 1740 prn = fdopen (pipefd[1], "w"); 1741 /* and fall through... */ 1742 } 1743 } 1744 } 1745 else 1746 prn = fopen (stpui_plist_get_output_filename(printer), "wb"); 1747 1748 if (prn != NULL) 1749 { 1750 char tmp[32]; 1751 stpui_plist_t *np = allocate_stpui_plist_copy(printer); 1752 const stp_vars_t *current_vars = 1753 stp_printer_get_defaults(stp_get_printer(np->v)); 1754 int orientation; 1755 stp_merge_printvars(np->v, current_vars); 1756 stp_set_string_parameter(np->v, "InputImageType", image_type); 1757 if (image_raw_channels) 1758 { 1759 sprintf(tmp, "%d", image_raw_channels); 1760 stp_set_string_parameter(np->v, "RawChannels", tmp); 1761 } 1762 sprintf(tmp, "%d", image_channel_depth); 1763 stp_set_string_parameter(np->v, "ChannelBitDepth", tmp); 1764 1765 /* 1766 * Set up the orientation 1767 */ 1768 orientation = np->orientation; 1769 if (orientation == ORIENT_AUTO) 1770 orientation = stpui_compute_orientation(); 1771 switch (orientation) 1772 { 1773 case ORIENT_PORTRAIT: 1774 break; 1775 case ORIENT_LANDSCAPE: 1776 if (image->rotate_cw) 1777 (image->rotate_cw)(image); 1778 break; 1779 case ORIENT_UPSIDEDOWN: 1780 if (image->rotate_180) 1781 (image->rotate_180)(image); 1782 break; 1783 case ORIENT_SEASCAPE: 1784 if (image->rotate_ccw) 1785 (image->rotate_ccw)(image); 1786 break; 1787 } 1788 1789 /* 1790 * Finally, call the print driver to send the image to the printer 1791 * and close the output file/command... 1792 */ 1793 1794 stp_set_outfunc(np->v, writefunc); 1795 stp_set_errfunc(np->v, stpui_get_errfunc()); 1796 stp_set_outdata(np->v, prn); 1797 stp_set_errdata(np->v, stpui_get_errdata()); 1798 print_status = stp_print(np->v, &(image->im)); 1799 1800 /* 1801 * Note that we do not use popen() to create the output, therefore 1802 * we do not use pclose() to close it. See bug 1013565. 1803 */ 1804 (void) fclose(prn); 1805 if (stpui_plist_get_command_type(printer) == COMMAND_TYPE_DEFAULT || 1806 stpui_plist_get_command_type(printer) == COMMAND_TYPE_CUSTOM) 1807 { 1808 /* 1809 * It is important for us to first close off the lpr process, 1810 * then kill the lpr monitor (child 1), and then wait for it 1811 * to die before exiting. 1812 */ 1813 kill (cpid, SIGUSR1); 1814 waitpid (cpid, &dummy, 0); 1815 } 1816 1817 /* 1818 * Make sure that any errors have been reported back to the user 1819 * prior to completion. In addition, explicitly close off the 1820 * synchronization file descriptor since we're merely returning, 1821 * not exiting, and don't want to leave any pollution around. 1822 */ 1823 if (do_sync) 1824 { 1825 char buf[8]; 1826 (void) read(syncfd[0], buf, 8); 1827 (void) close(syncfd[0]); 1828 } 1829 stpui_plist_destroy(np); 1830 g_free(np); 1831 return 1; 1832 } 1833 return 0; 1834} 1835 1836/* 1837 * End of "$Id: plist.c,v 1.18 2008/07/04 14:29:28 rlk Exp $". 1838 */ 1839