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