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