1/*
2 * "$Id: escp2-papers.c,v 1.119 2010/08/04 00:33:56 rlk Exp $"
3 *
4 *   Print plug-in EPSON ESC/P2 driver for the GIMP.
5 *
6 *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
7 *	Robert Krawitz (rlk@alum.mit.edu)
8 *
9 *   This program is free software; you can redistribute it and/or modify it
10 *   under the terms of the GNU eral Public License as published by the Free
11 *   Software Foundation; either version 2 of the License, or (at your option)
12 *   any later version.
13 *
14 *   This program is distributed in the hope that it will be useful, but
15 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 *   for more details.
18 *
19 *   You should have received a copy of the GNU General Public License
20 *   along with this program; if not, write to the Free Software
21 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27#include <gutenprint/gutenprint.h>
28#include "gutenprint-internal.h"
29#include <gutenprint/gutenprint-intl-internal.h>
30#include "print-escp2.h"
31
32static stp_mxml_node_t *
33get_media_size_xml(const stp_vars_t *v)
34{
35  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
36  return printdef->media_sizes;
37}
38
39int
40stp_escp2_load_media_sizes(const stp_vars_t *v, const char *name)
41{
42  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
43  stp_list_t *dirlist = stpi_data_path();
44  stp_list_item_t *item;
45  int found = 0;
46  item = stp_list_get_start(dirlist);
47  while (item)
48    {
49      const char *dn = (const char *) stp_list_item_get_data(item);
50      char *ffn = stpi_path_merge(dn, name);
51      stp_mxml_node_t *sizes =
52	stp_mxmlLoadFromFile(NULL, ffn, STP_MXML_NO_CALLBACK);
53      stp_free(ffn);
54      if (sizes)
55	{
56	  stp_mxml_node_t **xnode =
57	    (stp_mxml_node_t **) &(printdef->media_sizes);
58	  *xnode = sizes;
59	  found = 1;
60	  break;
61	}
62      item = stp_list_item_next(item);
63    }
64  stp_list_destroy(dirlist);
65  STPI_ASSERT(found, v);
66  return found;
67}
68
69void
70stp_escp2_set_media_size(stp_vars_t *v, const stp_vars_t *src)
71{
72  const char *name = stp_get_string_parameter(src, "PageSize");
73  if (name)
74    {
75      stp_mxml_node_t *node = get_media_size_xml(src);
76      stp_mxml_node_t *xnode = stp_mxmlFindElement(node, node, "MediaSize",
77						   "name", name, STP_MXML_DESCEND);
78      if (xnode)
79	{
80	  stp_vars_fill_from_xmltree_ref(xnode->child, node, v);
81	  return;
82	}
83      xnode = stp_mxmlFindElement(node, node, "MediaSize", "type", "default",
84				  STP_MXML_DESCEND);
85      if (xnode)
86	{
87	  stp_vars_fill_from_xmltree_ref(xnode->child, node, v);
88	  return;
89	}
90    }
91}
92
93static const char *
94paper_namefunc(const void *item)
95{
96  const paper_t *p = (const paper_t *) (item);
97  return p->cname;
98}
99
100int
101stp_escp2_load_media(const stp_vars_t *v, const char *name)
102{
103  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
104  stp_list_t *dirlist = stpi_data_path();
105  stp_list_item_t *item;
106  int found = 0;
107  item = stp_list_get_start(dirlist);
108  while (item)
109    {
110      const char *dn = (const char *) stp_list_item_get_data(item);
111      char *ffn = stpi_path_merge(dn, name);
112      stp_mxml_node_t *media =
113	stp_mxmlLoadFromFile(NULL, ffn, STP_MXML_NO_CALLBACK);
114      stp_free(ffn);
115      if (media)
116	{
117	  stp_mxml_node_t **xnode =
118	    (stp_mxml_node_t **) &(printdef->media);
119	  stp_list_t **xlist =
120	    (stp_list_t **) &(printdef->media_cache);
121	  stp_string_list_t **xpapers =
122	    (stp_string_list_t **) &(printdef->papers);
123	  stp_mxml_node_t *node = stp_mxmlFindElement(media, media,
124						      "escp2:papers", NULL,
125						      NULL, STP_MXML_DESCEND);
126	  *xnode = media;
127	  *xlist = stp_list_create();
128	  stp_list_set_namefunc(*xlist, paper_namefunc);
129	  *xpapers = stp_string_list_create();
130	  if (node)
131	    {
132	      node = node->child;
133	      while (node)
134		{
135		  if (node->type == STP_MXML_ELEMENT &&
136		      strcmp(node->value.element.name, "paper") == 0)
137		    stp_string_list_add_string(*xpapers,
138					       stp_mxmlElementGetAttr(node, "name"),
139					       stp_mxmlElementGetAttr(node, "text"));
140		  node = node->next;
141		}
142	    }
143	  found = 1;
144	  break;
145	}
146      item = stp_list_item_next(item);
147    }
148  stp_list_destroy(dirlist);
149  STPI_ASSERT(found, v);
150  return found;
151}
152
153static stp_mxml_node_t *
154get_media_xml(const stp_vars_t *v)
155{
156  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
157  return printdef->media;
158}
159
160static stp_list_t *
161get_media_cache(const stp_vars_t *v)
162{
163  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
164  return printdef->media_cache;
165}
166
167int
168stp_escp2_has_media_feature(const stp_vars_t *v, const char *name)
169{
170  stp_mxml_node_t *doc = get_media_xml(v);
171  if (doc)
172    return (stp_mxmlFindElement(doc, doc, "feature", "name", name,
173				STP_MXML_DESCEND) != NULL);
174  else
175    return 0;
176}
177
178
179static paper_t *
180build_media_type(const stp_vars_t *v, const char *name, const inklist_t *ink,
181		 const res_t *res)
182{
183  stp_mxml_node_t *node;
184  stp_mxml_node_t *doc = get_media_xml(v);
185  const char *pclass;
186  paper_t *answer;
187  stp_vars_t *vv = stp_vars_create();
188  if (!doc)
189    return NULL;
190  node = stp_mxmlFindElement(doc, doc, "paper", "name", name, STP_MXML_DESCEND);
191  if (!node)
192    return NULL;
193  answer = stp_zalloc(sizeof(paper_t));
194  answer->name = stp_mxmlElementGetAttr(node, "name");
195  answer->text = gettext(stp_mxmlElementGetAttr(node, "text"));
196  pclass = stp_mxmlElementGetAttr(node, "class");
197  answer->v = vv;
198  if (! pclass || strcasecmp(pclass, "plain") == 0)
199    answer->paper_class = PAPER_PLAIN;
200  else if (strcasecmp(pclass, "good") == 0)
201    answer->paper_class = PAPER_GOOD;
202  else if (strcasecmp(pclass, "photo") == 0)
203    answer->paper_class = PAPER_PHOTO;
204  else if (strcasecmp(pclass, "premium") == 0)
205    answer->paper_class = PAPER_PREMIUM_PHOTO;
206  else if (strcasecmp(pclass, "transparency") == 0)
207    answer->paper_class = PAPER_TRANSPARENCY;
208  else
209    answer->paper_class = PAPER_PLAIN;
210  answer->preferred_ink_type = stp_mxmlElementGetAttr(node, "PreferredInktype");
211  answer->preferred_ink_set = stp_mxmlElementGetAttr(node, "PreferredInkset");
212  stp_vars_fill_from_xmltree_ref(node->child, doc, vv);
213  if (ink && ink->name)
214    {
215      stp_mxml_node_t *inknode = stp_mxmlFindElement(node, node, "ink",
216						     "name", ink->name,
217						     STP_MXML_DESCEND);
218      STPI_ASSERT(inknode, v);
219      stp_vars_fill_from_xmltree_ref(inknode->child, doc, vv);
220    }
221  if (res && res->name)
222    {
223      stp_mxml_node_t *resnode = stp_mxmlFindElement(node, node, "resolution",
224						     "name", res->name,
225						     STP_MXML_DESCEND);
226      if (resnode)
227	stp_vars_fill_from_xmltree_ref(resnode->child, doc, vv);
228    }
229  return answer;
230}
231
232static char *
233build_media_id(const char *name, const inklist_t *ink, const res_t *res)
234{
235  char *answer;
236  stp_asprintf(&answer, "%s %s %s",
237	       name,
238	       ink ? ink->name : "",
239	       res ? res->name : "");
240  return answer;
241}
242
243static const paper_t *
244get_media_type_named(const stp_vars_t *v, const char *name,
245		     int ignore_res)
246{
247  paper_t *answer = NULL;
248  int i;
249  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
250  const stp_string_list_t *p = printdef->papers;
251  const res_t *res = ignore_res ? NULL : stp_escp2_find_resolution(v);
252  const inklist_t *inklist = stp_escp2_inklist(v);
253  char *media_id = build_media_id(name, inklist, res);
254  stp_list_t *cache = get_media_cache(v);
255  stp_list_item_t *li = stp_list_get_item_by_name(cache, media_id);
256  if (li)
257    {
258      stp_free(media_id);
259      answer = (paper_t *) stp_list_item_get_data(li);
260    }
261  else
262    {
263      int paper_type_count = stp_string_list_count(p);
264      for (i = 0; i < paper_type_count; i++)
265	{
266	  if (!strcmp(name, stp_string_list_param(p, i)->name))
267	    {
268#ifdef HAVE_LOCALE_H
269	      char *locale = stp_strdup(setlocale(LC_ALL, NULL));
270	      setlocale(LC_ALL, "C");
271#endif
272	      answer = build_media_type(v, name, inklist, res);
273#ifdef HAVE_LOCALE_H
274	      setlocale(LC_ALL, locale);
275	      stp_free(locale);
276#endif
277	      break;
278	    }
279	}
280      if (answer)
281	{
282	  answer->cname = media_id;
283	  stp_list_item_create(cache, NULL, answer);
284	}
285    }
286  return answer;
287}
288
289const paper_t *
290stp_escp2_get_media_type(const stp_vars_t *v, int ignore_res)
291{
292  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
293  const stp_string_list_t *p = printdef->papers;
294  if (p)
295    {
296      const char *name = stp_get_string_parameter(v, "MediaType");
297      if (name)
298	return get_media_type_named(v, name, ignore_res);
299    }
300  return NULL;
301}
302
303const paper_t *
304stp_escp2_get_default_media_type(const stp_vars_t *v)
305{
306  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
307  const stp_string_list_t *p = printdef->papers;
308  if (p)
309    {
310      int paper_type_count = stp_string_list_count(p);
311      if (paper_type_count >= 0)
312	return get_media_type_named(v, stp_string_list_param(p, 0)->name, 1);
313    }
314  return NULL;
315}
316
317
318static const char *
319slots_namefunc(const void *item)
320{
321  const input_slot_t *p = (const input_slot_t *) (item);
322  return p->name;
323}
324
325int
326stp_escp2_load_input_slots(const stp_vars_t *v, const char *name)
327{
328  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
329  stp_list_t *dirlist = stpi_data_path();
330  stp_list_item_t *item;
331  int found = 0;
332  item = stp_list_get_start(dirlist);
333  while (item)
334    {
335      const char *dn = (const char *) stp_list_item_get_data(item);
336      char *ffn = stpi_path_merge(dn, name);
337      stp_mxml_node_t *slots =
338	stp_mxmlLoadFromFile(NULL, ffn, STP_MXML_NO_CALLBACK);
339      stp_free(ffn);
340      if (slots)
341	{
342	  stp_mxml_node_t **xnode =
343	    (stp_mxml_node_t **) &(printdef->slots);
344	  stp_list_t **xlist =
345	    (stp_list_t **) &(printdef->slots_cache);
346	  stp_string_list_t **xslots =
347	    (stp_string_list_t **) &(printdef->input_slots);
348	  stp_mxml_node_t *node = stp_mxmlFindElement(slots, slots,
349						      "escp2:InputSlots", NULL,
350						      NULL, STP_MXML_DESCEND);
351	  *xnode = slots;
352	  *xlist = stp_list_create();
353	  stp_list_set_namefunc(*xlist, slots_namefunc);
354	  *xslots = stp_string_list_create();
355	  if (node)
356	    {
357	      node = node->child;
358	      while (node)
359		{
360		  if (node->type == STP_MXML_ELEMENT &&
361		      strcmp(node->value.element.name, "slot") == 0)
362		    stp_string_list_add_string(*xslots,
363					       stp_mxmlElementGetAttr(node, "name"),
364					       stp_mxmlElementGetAttr(node, "text"));
365		  node = node->next;
366		}
367	    }
368	  found = 1;
369	  break;
370	}
371      item = stp_list_item_next(item);
372    }
373  stp_list_destroy(dirlist);
374  STPI_ASSERT(found, v);
375  return found;
376}
377
378static stp_mxml_node_t *
379get_slots_xml(const stp_vars_t *v)
380{
381  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
382  return printdef->slots;
383}
384
385static stp_list_t *
386get_slots_cache(const stp_vars_t *v)
387{
388  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
389  return printdef->slots_cache;
390}
391
392static input_slot_t *
393build_input_slot(const stp_vars_t *v, const char *name)
394{
395  stp_mxml_node_t *node, *n1;
396  stp_mxml_node_t *doc = get_slots_xml(v);
397  input_slot_t *answer;
398  if (!doc)
399    return NULL;
400  node = stp_mxmlFindElement(doc, doc, "slot", "name", name, STP_MXML_DESCEND);
401  if (!node)
402    return NULL;
403  answer = stp_zalloc(sizeof(input_slot_t));
404  answer->name = stp_mxmlElementGetAttr(node, "name");
405  answer->text = gettext(stp_mxmlElementGetAttr(node, "text"));
406  n1 = stp_mxmlFindElement(node, node, "CD", NULL, NULL, STP_MXML_DESCEND);
407  if (n1)
408    answer->is_cd = 1;
409  n1 = stp_mxmlFindElement(node, node, "RollFeed", NULL, NULL, STP_MXML_DESCEND);
410  if (n1)
411    {
412      answer->is_roll_feed = 1;
413      if (stp_mxmlFindElement(n1, n1, "CutAll", NULL, NULL, STP_MXML_DESCEND))
414	answer->roll_feed_cut_flags |= ROLL_FEED_CUT_ALL;
415      if (stp_mxmlFindElement(n1, n1, "CutLast", NULL, NULL, STP_MXML_DESCEND))
416	answer->roll_feed_cut_flags |= ROLL_FEED_CUT_LAST;
417      if (stp_mxmlFindElement(n1, n1, "DontEject", NULL, NULL, STP_MXML_DESCEND))
418	answer->roll_feed_cut_flags |= ROLL_FEED_DONT_EJECT;
419    }
420  n1 = stp_mxmlFindElement(node, node, "Duplex", NULL, NULL, STP_MXML_DESCEND);
421  if (n1)
422    {
423      if (stp_mxmlFindElement(n1, n1, "Tumble", NULL, NULL, STP_MXML_DESCEND))
424	answer->duplex |= DUPLEX_TUMBLE;
425      if (stp_mxmlFindElement(n1, n1, "NoTumble", NULL, NULL, STP_MXML_DESCEND))
426	answer->duplex |= DUPLEX_NO_TUMBLE;
427    }
428  n1 = stp_mxmlFindElement(node, node, "InitSequence", NULL, NULL, STP_MXML_DESCEND);
429  if (n1 && n1->child && n1->child->type == STP_MXML_TEXT)
430    answer->init_sequence = stp_xmlstrtoraw(n1->child->value.text.string);
431  n1 = stp_mxmlFindElement(node, node, "DeinitSequence", NULL, NULL, STP_MXML_DESCEND);
432  if (n1 && n1->child && n1->child->type == STP_MXML_TEXT)
433    answer->deinit_sequence = stp_xmlstrtoraw(n1->child->value.text.string);
434  n1 = stp_mxmlFindElement(node, node, "ExtraHeight", NULL, NULL, STP_MXML_DESCEND);
435  if (n1 && n1->child && n1->child->type == STP_MXML_TEXT)
436    answer->extra_height = stp_xmlstrtoul(n1->child->value.text.string);
437  return answer;
438}
439
440int
441stp_escp2_printer_supports_rollfeed(const stp_vars_t *v)
442{
443  stp_mxml_node_t *node = get_slots_xml(v);
444  if (stp_mxmlFindElement(node, node, "RollFeed", NULL, NULL, STP_MXML_DESCEND))
445    return 1;
446  else
447    return 0;
448}
449
450int
451stp_escp2_printer_supports_print_to_cd(const stp_vars_t *v)
452{
453  stp_mxml_node_t *node = get_slots_xml(v);
454  if (stp_mxmlFindElement(node, node, "CD", NULL, NULL, STP_MXML_DESCEND))
455    return 1;
456  else
457    return 0;
458}
459
460int
461stp_escp2_printer_supports_duplex(const stp_vars_t *v)
462{
463  stp_mxml_node_t *node = get_slots_xml(v);
464  if (stp_mxmlFindElement(node, node, "Duplex", NULL, NULL, STP_MXML_DESCEND))
465    return 1;
466  else
467    return 0;
468}
469
470static const input_slot_t *
471get_input_slot_named(const stp_vars_t *v, const char *name)
472{
473  input_slot_t *answer = NULL;
474  int i;
475  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
476  const stp_string_list_t *p = printdef->input_slots;
477  stp_list_t *cache = get_slots_cache(v);
478  stp_list_item_t *li = stp_list_get_item_by_name(cache, name);
479  if (li)
480    answer = (input_slot_t *) stp_list_item_get_data(li);
481  else
482    {
483      int slot_count = stp_string_list_count(p);
484      for (i = 0; i < slot_count; i++)
485	{
486	  if (!strcmp(name, stp_string_list_param(p, i)->name))
487	    {
488#ifdef HAVE_LOCALE_H
489	      char *locale = stp_strdup(setlocale(LC_ALL, NULL));
490	      setlocale(LC_ALL, "C");
491#endif
492	      answer = build_input_slot(v, name);
493#ifdef HAVE_LOCALE_H
494	      setlocale(LC_ALL, locale);
495	      stp_free(locale);
496#endif
497	      break;
498	    }
499	}
500      if (answer)
501	stp_list_item_create(cache, NULL, answer);
502    }
503  return answer;
504}
505
506const input_slot_t *
507stp_escp2_get_input_slot(const stp_vars_t *v)
508{
509  stpi_escp2_printer_t *printdef = stp_escp2_get_printer(v);
510  const stp_string_list_t *p = printdef->input_slots;
511  if (p)
512    {
513      const char *name = stp_get_string_parameter(v, "InputSlot");
514      if (name)
515	return get_input_slot_named(v, name);
516    }
517  return NULL;
518}
519