plptools
Loading...
Searching...
No Matches
plpprintd.cc
Go to the documentation of this file.
1/*
2 * This file is part of plptools.
3 *
4 * Copyright (C) 1999-2001 Fritz Elfert <felfert@to.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
18 *
19 */
20#include "config.h"
21
22#include <cli_utils.h>
23#include <tcpsocket.h>
24#include <wprt.h>
25#include <psibitmap.h>
26
27#include <iostream>
28#include <string>
29
30#include <stdlib.h>
31#include <stdarg.h>
32#include <stdio.h>
33#include <syslog.h>
34#include <unistd.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38
39#include "ignore-value.h"
40
41#ifndef _GNU_SOURCE
42#define _GNU_SOURCE
43#endif
44#include <getopt.h>
45
46#define TEMPLATE "plpprint_XXXXXX"
47#define PRINTCMD "lpr -Ppsion"
48#define SPOOLDIR "/var/spool/plpprint"
49#define PSDICT "/prolog.ps"
50
51using namespace std;
52
53const char *spooldir = SPOOLDIR;
54const char *printcmd = PRINTCMD;
57bool debug = false;
58int verbose = 0;
59
60static void
61_log(int priority, const char *fmt, va_list ap)
62{
63 char *buf;
64 if (vasprintf(&buf, fmt, ap) == -1)
65 return;
66 if (debug)
67 cout << buf << endl;
68 else
69 syslog(priority, "%s", buf);
70 free(buf);
71}
72
73void
74debuglog(const char *fmt, ...)
75{
76 va_list ap;
77 va_start(ap, fmt);
78 _log(LOG_DEBUG, fmt, ap);
79 va_end(ap);
80}
81
82void
83errorlog(const char *fmt, ...)
84{
85 va_list ap;
86 va_start(ap, fmt);
87 _log(LOG_ERR, fmt, ap);
88 va_end(ap);
89}
90
91void
92infolog(const char *fmt, ...)
93{
94 va_list ap;
95 va_start(ap, fmt);
96 _log(LOG_INFO, fmt, ap);
97 va_end(ap);
98}
99
100static int minx, maxx, miny, maxy;
102
103typedef struct fontmap_entry_s {
105 char *psifont;
106 bool bold;
107 bool italic;
108 char *psfont;
110
111typedef struct const_fontmap_entry_s {
112 const char *psifont;
113 bool bold;
114 bool italic;
115 const char *psfont;
117
118#define FALLBACK_FONT "Courier"
119
121 // PsionFontname, bold, italic, PSFontName
122 { "Times New Roman", false, false, "Times-Roman"},
123 { "Times New Roman", true, false, "Times-Bold"},
124 { "Times New Roman", false, true, "Times-Italic"},
125 { "Times New Roman", true, true, "Times-BoldItalic"},
126 { "Arial", false, false, "Helvetica"},
127 { "Arial", true, false, "Helvetica-Bold"},
128 { "Arial", false, true, "Helvetica-Oblique"},
129 { "Arial", true, true, "Helvetica-BoldOblique"},
130 { "Courier New", false, false, "Courier"},
131 { "Courier New", true, false, "Courier-Bold"},
132 { "Courier New", false, true, "Courier-Oblique"},
133 { "Courier New", true, true, "Courier-BoldOblique"},
134 { "Swiss", false, false, "Courier"},
135 { "Swiss", true, false, "Courier-Bold"},
136 { "Swiss", false, true, "Courier-Oblique"},
137 { "Swiss", true, true, "Courier-BoldOblique"},
138 { NULL, false, false, NULL}
139};
140
141static fontmap_entry *fontmap = NULL;
142
143static void
145 FILE *f;
146 fontmap_entry *new_fontmap = NULL;
147 fontmap_entry *fe;
148
149 if ((f = fopen(PKGDATADIR "/fontmap", "r"))) {
150 char *p;
151 int bold;
152 int italic;
153 char *psifont;
154 char *psfont;
155 char *tmp;
156 char buf[1024];
157 while (fgets(buf, sizeof(buf), f)) {
158 char *bp = buf;
159 int ne;
160 if ((p = strchr(buf, '#')))
161 *p = '\0';
162 if ((p = strchr(buf, '\n')))
163 *p = '\0';
164
165 psifont = strsep(&bp, ":");
166 if (!psifont || !(*psifont))
167 continue;
168 tmp = strsep(&bp, ":");
169 if (!tmp || !(*tmp) || (sscanf(tmp, "%d", &bold) != 1))
170 continue;
171 tmp = strsep(&bp, ":");
172 if (!tmp || !(*tmp) || (sscanf(tmp, "%d", &italic) != 1))
173 continue;
174 psfont = strsep(&bp, ":");
175 if (!psfont || !(*psfont))
176 continue;
177 fe = (fontmap_entry *)malloc(sizeof(fontmap_entry));
178 if (!fe)
179 break;
180 if (!(fe->psifont = strdup(psifont))) {
181 free(fe);
182 break;
183 }
184 if (!(fe->psfont = strdup(psfont))) {
185 free(fe->psifont);
186 free(fe);
187 break;
188 }
189 fe->bold = bold ? true : false;
190 fe->italic = italic ? true : false;
191 fe->next = new_fontmap;
192 new_fontmap = fe;
193 }
194 fclose(f);
195 }
196 if (new_fontmap && (new_fontmap->psifont))
197 fontmap = new_fontmap;
198 else {
199 errorlog("No fontmap found in %s/fontmap, using builtin mapping",
200 PKGDATADIR);
201 for (const_fontmap_entry *cfe = default_fontmap; cfe->psifont; cfe++) {
202 fontmap_entry *nfe = (fontmap_entry *)malloc(sizeof(fontmap_entry));
203 if (!nfe)
204 break;
205 nfe->next = fontmap;
206 nfe->psifont = strdup(cfe->psifont);
207 nfe->bold = cfe->bold;
208 nfe->italic = cfe->italic;
209 nfe->psfont = strdup(cfe->psfont);
210 fontmap = nfe;
211 }
212 }
213 if (debug) {
214 debuglog("Active Font-Mapping:");
215 debuglog("%-20s%-7s%-7s%-20s", "Psion", "Bold", "Italic", "PS-Font");
216 fe = fontmap;
217 while (fe) {
218 debuglog("%-20s%-7s%-7s%-20s", fe->psifont,
219 fe->bold ? "true" : "false",
220 fe->italic ? "true" : "false",
221 fe->psfont);
222 fe = fe->next;
223 }
224 }
225}
226
227static void
228ps_setfont(FILE *f, const char *fname, bool bold, bool italic,
229 unsigned long fsize)
230{
232 const char *psf = NULL;
233 while (fe) {
234 if ((!strcmp(fe->psifont, fname)) &&
235 (fe->bold == bold) &&
236 (fe->italic == italic)) {
237 psf = fe->psfont;
238 break;
239 }
240 fe = fe->next;
241 }
242 if (!psf) {
243 psf = FALLBACK_FONT;
244 errorlog("No font mapping for '%s' (%s%s%s); fallback to %s",
245 fname, (bold) ? "Bold" : "", (italic) ? "Italic" : "",
246 (bold || italic) ? "" : "Regular", psf);
247 }
248 if (usedfonts.find(psf) == usedfonts.npos) {
249 usedfonts += "%%+ font ";
250 usedfonts += psf;
251 usedfonts += "\n";
252 }
253 fprintf(f, "%ld /%s F\n", fsize, psf);
254}
255
256static void
257ps_escape(string &text)
258{
259 int pos = 0;
260 while ((pos = text.find_first_of("()", pos)) != text.npos) {
261 text.insert(pos, "\\");
262 pos += 2;
263 }
264}
265
266static void
267ps_bitmap(FILE *f, unsigned long llx, unsigned long lly, unsigned long urx,
268 unsigned long ury, const char *buf)
269{
270 bufferStore out;
271 int width, height;
272 if (decodeBitmap((const unsigned char *)buf, width, height, out)) {
273 fprintf(f, "%lu %lu %lu %lu %d %d I\n", llx, lly, urx, ury, width, height);
274 const unsigned char *p = (const unsigned char *)out.getString(0);
275 for (int y = 0; y < height; y++) {
276 for (int x = 0; x < width; x++)
277 fprintf(f, "%02x", *p++);
278 fprintf(f, "\n");
279 }
280 } else
281 errorlog("Corrupted bitmap data");
282}
283
284static void
285convertPage(FILE *f, int page, bool last, bufferStore buf)
286{
287 int len = buf.getLen();
288 int i = 0;
289 long boffset = 0;
290 unsigned long left = 0;
291 unsigned long top = 0;
292 unsigned long right = 0;
293 unsigned long bottom = 0;
294
295 if (debug) {
296 char dumpname[128];
297 sprintf(dumpname, "/tmp/pdump_%d", page);
298 FILE *df = fopen(dumpname, "w");
299 fwrite(buf.getString(0), 1, len, df);
300 fclose(df);
301 debuglog("Saved page input to %s", dumpname);
302 }
303 if (page == 0) {
304 time_t now = time(NULL);
305 fputs(
306 "%!PS-Adobe-3.0\n"
307 "%%Creator: plpprintd " VERSION "\n"
308 "%%CreationDate: ", f);
309 fputs(ctime(&now), f);
310 fputs(
311 "%%Pages: (atend)\n"
312 "%%BoundingBox: (atend)\n"
313 "%%DocumentNeededResources: (atend)\n"
314 "%%LanguageLevel: 2\n"
315 "%%EndComments\n"
316 "%%BeginProlog\n", f);
317 char pbuf[1024];
318 FILE *pf = fopen(PKGDATADIR PSDICT, "r");
319 while (fgets(pbuf, sizeof(pbuf), pf))
320 fputs(pbuf, f);
321 fclose(pf);
322 fputs(
323 "%%EndProlog\n"
324 "%%BeginSetup\n"
325 "currentpagedevice /PageSize get 1 get /top exch def\n"
326 "ip 1 1 TH 32 DM RC 1 PS\n"
327 "%%EndSetup\n", f);
328 minx = miny = 9999;
329 maxx = maxy = 0;
330 usedfonts = "";
331 }
332 fprintf(f, "%%%%Page: %d %d\n", page+1, page+1);
333 while (i < len) {
334 unsigned char opcode = buf.getByte(i);
335 switch (opcode) {
336 case 0x00: {
337 // Start of section
338 unsigned long section = buf.getDWord(i+1) & 3;
339 unsigned long pagenr = buf.getDWord(i+1) >> 2;
340 fprintf(f, "%% @%d: Section %ld, Page %ld\n", i, section, pagenr);
341 fprintf(f, "1 1 TH 32 DM RC 1 PS CC\n");
342 // (section & 3) =
343 // 0 = Header, 1 = Body, 2 = Footer, 3 = Footer
344 i += 5;
345 }
346 break;
347 case 0x01: {
348 // End of page
349 i = len + 1;
350 }
351 break;
352 case 0x03: {
353 // Set drawing mode
354 unsigned char drwmode = buf.getByte(i+1);
355 fprintf(f, "%% @%d: Drawing mode %02x\n", i, drwmode);
356 switch (drwmode) {
357 case 0x01:
358 // ~screen
359 break;
360 case 0x02:
361 // colour ^ screen
362 break;
363 case 0x03:
364 // ~colour ^ screen
365 break;
366 case 0x04:
367 // colour | screen
368 break;
369 case 0x05:
370 // colour | ~screen
371 break;
372 case 0x08:
373 // colour & screen
374 break;
375 case 0x09:
376 // colour & ~screen
377 break;
378 case 0x14:
379 // ~colour | screen
380 break;
381 case 0x15:
382 // ~colour | ~screen
383 break;
384 case 0x18:
385 // ~colour & screen
386 break;
387 case 0x19:
388 // ~colour & ~screen
389 break;
390 case 0x20:
391 // colour
392 break;
393 case 0x30:
394 // ~colour
395 break;
396 }
397 fprintf(f, "%d DM\n", drwmode);
398 i += 2;
399 }
400 break;
401 case 0x04: {
402 // Bounding box (clipping rectangle)
403 left = buf.getDWord(i+1);
404 top = buf.getDWord(i+5);
405 right = buf.getDWord(i+9);
406 bottom = buf.getDWord(i+13);
407 if (left < minx)
408 minx = left;
409 if (right > maxx)
410 maxx = right;
411 if (top < miny)
412 miny = top;
413 if (bottom > maxy)
414 maxy = bottom;
415 i += 17;
416 fprintf(f, "%% @%d: bbox %ld %ld %ld %ld\n", i, left, top, right,
417 bottom);
418 fprintf(f, "%ld %ld %ld %ld CB\n", left, top, right, bottom);
419 }
420 break;
421 case 0x05: {
422 // Cancel clipping rect
423 left = top = right = bottom = 0;
424 fprintf(f, "%% @%d: Cancel Cliprect\n", i);
425 fprintf(f, "CC\n");
426 i++;
427 }
428 break;
429 case 0x06: {
430 // ???
431 fprintf(f, "%% @%d: U06 %d 0x%08x\n", i,
432 buf.getByte(i+1), buf.getDWord(i+2));
433 i += 6;
434 }
435 break;
436 case 0x07: {
437 // Font
438 int namelen;
439 int ofs;
440 if (buf.getByte(i+1) & 1) {
441 namelen = buf.getWord(i+1) >> 3;
442 ofs = i + 3;
443 } else {
444 namelen = buf.getByte(i+1) >> 2;
445 ofs = i + 2;
446 }
447 string fname(buf.getString(ofs), namelen);
448 ofs += namelen;
449 int screenfont = buf.getByte(ofs);
450 int basesize = buf.getWord(ofs+1);
451 unsigned long style = buf.getDWord(ofs+3);
452 bool italic = ((style & 1) != 0);
453 bool bold = ((style & 2) != 0);
454 unsigned long fontsize = buf.getDWord(ofs+7);
455 boffset = (long)buf.getDWord(ofs+11);
456 fprintf(f, "%% @%d: Font '%s' %ld %s%s%s\n", i, fname.c_str(),
457 fontsize, bold ? "Bold" : "", italic ? "Italic" : "",
458 (bold || italic) ? "" : "Regular");
459 ps_setfont(f, fname.c_str(), bold, italic, fontsize);
460 i = ofs + 15;
461 }
462 break;
463 case 0x08: {
464 // End Font
465 fprintf(f, "%% @%d: End Font\n", i);
466 i++;
467 }
468 break;
469 case 0x09: {
470 // underline
471 fprintf(f, "%% @%d: Underline %d\n", i, buf.getByte(i+1));
472 fprintf(f, "%d UL\n", buf.getByte(i+1));
473 i += 2;
474 }
475 break;
476 case 0x0a: {
477 // strikethru
478 fprintf(f, "%% @%d: Strikethru %d\n", i, buf.getByte(i+1));
479 fprintf(f, "%d ST\n", buf.getByte(i+1));
480 i += 2;
481 }
482 break;
483 case 0x0b: {
484 // newline
485 fprintf(f, "%% @%d: Newline %d %d\n", i, buf.getDWord(i+1),
486 buf.getDWord(i+5));
487 i += 9;
488 }
489 break;
490 case 0x0c: {
491 // cr
492 fprintf(f, "%% @%d: CR %d %d\n", i, buf.getDWord(i+1),
493 buf.getDWord(i+5));
494 i += 9;
495 }
496 break;
497 case 0x0d: {
498 // foreground color
499 fprintf(f, "%% @%d: Foreground %d %d %d\n", i, buf.getByte(i+1),
500 buf.getByte(i+2), buf.getByte(i+3));
501 fprintf(f, "%d %d %d FG\n", buf.getByte(i+1),
502 buf.getByte(i+2), buf.getByte(i+3));
503 i += 4;
504 }
505 break;
506 case 0x0e: {
507 // Set pen style
508 unsigned char pstyle = buf.getByte(i+1);
509 switch (pstyle) {
510 case 0x00:
511 // Don't draw
512 break;
513 case 0x01:
514 // Solid
515 break;
516 case 0x02:
517 // Dotted line
518 break;
519 case 0x03:
520 // Dashed line
521 break;
522 case 0x04:
523 // Dash Dot
524 break;
525 case 0x05:
526 // Dash Dot Dot
527 break;
528 }
529 fprintf(f, "%% @%d: Pen Style %d\n", i, pstyle);
530 fprintf(f, "%d PS\n", pstyle);
531 i += 2;
532 }
533 break;
534 case 0x0f: {
535 // Pen thickness x, y
536 fprintf(f, "%% @%d: Pen thickness %u %u\n", i, buf.getDWord(i+1),
537 buf.getDWord(i+5));
538 fprintf(f, "%u %u TH\n", buf.getDWord(i+1), buf.getDWord(i+5));
539 i += 9;
540 }
541 break;
542 case 0x10: {
543 // background color
544 fprintf(f, "%% @%d: Background %d %d %d\n", i, buf.getByte(i+1),
545 buf.getByte(i+2), buf.getByte(i+3));
546 fprintf(f, "%d %d %d BG\n", buf.getByte(i+1),
547 buf.getByte(i+2), buf.getByte(i+3));
548 i += 4;
549 }
550 break;
551 case 0x11: {
552 // Brush style
553 unsigned char bstyle = buf.getByte(i+1);
554 switch (bstyle) {
555 case 0x00:
556 // No brush
557 break;
558 case 0x01:
559 // Solid brush
560 break;
561 case 0x02:
562 // Patterned brush
563 break;
564 case 0x03:
565 // Vertical hatch brush
566 break;
567 case 0x04:
568 // Diagonal hatch brush (bottom left to top right)
569 break;
570 case 0x05:
571 // Horizontal hatch brush
572 break;
573 case 0x06:
574 // Rev. diagonal hatch brush (top left to bottom right)
575 break;
576 case 0x07:
577 // Square cross hatch (horizontal and vertical)
578 break;
579 case 0x08:
580 // Diamond cross hatch (both diagonals)
581 break;
582 }
583 fprintf(f, "%% @%d: Brush style %d\n", i, bstyle);
584 fprintf(f, "%d BS\n", bstyle);
585 i += 2;
586 }
587 break;
588 case 0x17: {
589 // ???
590 fprintf(f, "%% @%d: U17 %u %u\n", i, buf.getDWord(i+1),
591 buf.getDWord(i+5));
592 i += 9;
593 }
594 break;
595 case 0x19: {
596 // Draw line
597 fprintf(f, "%% @%d: Line %u %u %u %u\n", i,
598 buf.getDWord(i+1), buf.getDWord(i+5),
599 buf.getDWord(i+9), buf.getDWord(i+13));
600 fprintf(f, "%u %u %u %u L\n",
601 buf.getDWord(i+1), buf.getDWord(i+5),
602 buf.getDWord(i+9), buf.getDWord(i+13));
603 i += 17;
604 }
605 break;
606 case 0x1b: {
607 // ???
608 fprintf(f, "%% @%d: U1b %u %u\n", i, buf.getDWord(i+1),
609 buf.getDWord(i+5));
610 i += 9;
611 }
612 break;
613 case 0x1f: {
614 // Draw ellipse
615 fprintf(f, "%% @%d: Ellipse %u %u %u %u\n", i,
616 buf.getDWord(i+1), buf.getDWord(i+5),
617 buf.getDWord(i+9), buf.getDWord(i+13));
618 fprintf(f, "%u %u %u %u E\n",
619 buf.getDWord(i+1), buf.getDWord(i+5),
620 buf.getDWord(i+9), buf.getDWord(i+13));
621 i += 17;
622 }
623 break;
624 case 0x20: {
625 // Draw rectangle
626 fprintf(f, "%% @%d: Rectangle %u %u %u %u\n", i,
627 buf.getDWord(i+1), buf.getDWord(i+5),
628 buf.getDWord(i+9), buf.getDWord(i+13));
629 fprintf(f, "%u %u %u %u R\n",
630 buf.getDWord(i+1), buf.getDWord(i+5),
631 buf.getDWord(i+9), buf.getDWord(i+13));
632 i += 17;
633 }
634 break;
635
636 case 0x23: {
637 // Draw polygon
638 unsigned long count = buf.getDWord(i+1);
639 int o = i + 5;
640 fprintf(f, "%% @%d: Polygon (%ld segments)\n", i, count);
641 fprintf(f, "[\n");
642 for (int j = 0; j < count; j++) {
643 fprintf(f, "%d %d\n", buf.getDWord(o),
644 buf.getDWord(o+4));
645 o += 8;
646 }
647 unsigned char frule = buf.getByte(o);
648 fprintf(f, "] %s P\n", frule ? "false" : "true");
649 i = o + 1;
650 }
651 break;
652 case 0x25: {
653 // Draw bitmap
654 unsigned long llx = buf.getDWord(i+1);
655 unsigned long lly = buf.getDWord(i+13);
656 unsigned long urx = buf.getDWord(i+9);
657 unsigned long ury = buf.getDWord(i+5);
658 unsigned long blen = buf.getDWord(i+17);
659 fprintf(f, "%% @%d: Bitmap\n", i);
660 ps_bitmap(f, llx, lly, urx, ury, buf.getString(i+17));
661 i += (17 + blen);
662 }
663 break;
664 case 0x26: {
665 // Draw bitmap
666 unsigned long llx = buf.getDWord(i+1);
667 unsigned long lly = buf.getDWord(i+13);
668 unsigned long urx = buf.getDWord(i+9);
669 unsigned long ury = buf.getDWord(i+5);
670 unsigned long blen = buf.getDWord(i+17);
671 unsigned long u1 = buf.getDWord(i+17+blen);
672 unsigned long u2 = buf.getDWord(i+17+blen+4);
673 unsigned long u3 = buf.getDWord(i+17+blen+8);
674 unsigned long u4 = buf.getDWord(i+17+blen+12);
675 fprintf(f, "%% @%d: Bitmap %ld %ld %ld %ld\n", i, u1, u2, u3, u4);
676 ps_bitmap(f, llx, lly, urx, ury, buf.getString(i+17));
677 i += (17 + blen + 16);
678 }
679 break;
680 case 0x27: {
681 // Draw label
682 int tlen;
683 int ofs;
684 if (buf.getByte(i+1) & 1) {
685 tlen = buf.getWord(i+1) >> 3;
686 ofs = i + 3;
687 } else {
688 tlen = buf.getByte(i+1) >> 2;
689 ofs = i + 2;
690 }
691 string text(buf.getString(ofs), tlen);
692 ofs += tlen;
693 ps_escape(text);
694 fprintf(f, "%% @%d: Text '%s' %d %d\n", i,
695 text.c_str(), buf.getDWord(ofs), buf.getDWord(ofs+4));
696 fprintf(f, "(%s) %d %ld 0 0 -1 T\n", text.c_str(),
697 buf.getDWord(ofs), buf.getDWord(ofs+4) + boffset);
698 i = ofs + 8;
699 }
700 break;
701 case 0x28: {
702 // Draw justified text
703 int tlen;
704 int ofs;
705 if (buf.getByte(i+1) & 1) {
706 tlen = buf.getWord(i+1) >> 3;
707 ofs = i + 3;
708 } else {
709 tlen = buf.getByte(i+1) >> 2;
710 ofs = i + 2;
711 }
712 string text(buf.getString(ofs), tlen);
713 ofs += tlen;
714 int left = buf.getDWord(ofs);
715 int top = buf.getDWord(ofs+4);
716 int right = buf.getDWord(ofs+8);
717 int bottom = buf.getDWord(ofs+12);
718 int baseline = buf.getDWord(ofs+16);
719 unsigned char align = buf.getByte(ofs+20);
720 int amargin = buf.getDWord(ofs+21);
721 fprintf(f, "%% @%d: JText '%s' %d %ld %d %d %d %d %d\n", i,
722 text.c_str(), left, bottom + boffset, top, right,
723 baseline, align, amargin);
724 ps_escape(text);
725 if (align == 2)
726 right -= amargin;
727 else
728 left += amargin;
729 bottom -= ((bottom - top) / 4);
730 fprintf(f, "(%s) %d %ld %d %d %d T\n", text.c_str(),
731 left, bottom + boffset, top, right, align);
732 i = ofs + 25;
733 }
734 break;
735 default:
736 fprintf(f, "@%d: UNHANDLED OPCODE %02x\n", i, opcode);
737 debuglog("@%d: UNHANDLED OPCODE %02x", i, opcode);
738 i++;
739 break;
740 }
741 }
742 fprintf(f, "showpage\n");
743 if (last) {
744 fputs(
745 "%%Trailer\n"
746 "%%DocumentNeededResources: ", f);
747 if (usedfonts.empty())
748 fputs("none\n", f);
749 else {
750 usedfonts.erase(0, 4);
751 fputs(usedfonts.c_str(), f);
752 }
753 fprintf(f, "%%%%Pages: %d\n", page + 1);
754 fprintf(f, "%%%%BoundingBox: %d %d %d %d\n",
755 minx / 20, miny / 20, maxx / 20, maxy / 20);
756 fputs("%%EOF\n", f);
757 }
758}
759
760static unsigned char fakePage[15] = {
761 0x2a, 0x2a, 0x09, 0x00, 0x00, 0x00, 0x82, 0x2e,
762 0x00, 0x00, 0xc6, 0x41, 0x00, 0x00, 0x00,
763};
764
765const
766static void
768{
769 bool jobLoop = true;
770 while (jobLoop) {
771 bool spoolOpen = false;
772 bool pageStart = true;
773 bool cancelled = false;
774 bool jobEnd;
775 unsigned long plen;
776 int pageCount = 0;
777 bufferStore buf;
778 bufferStore pageBuf;
779 int fd;
780 FILE *f = nullptr;
781 unsigned char b;
782 char *jname =
783 (char *)malloc(strlen(spooldir) +
784 strlen(TEMPLATE) + 2);
785
786 while (jobLoop) {
787 /* Job loop */
788 buf.init();
789 switch (wPrt->getData(buf)) {
791 jobLoop = false;
792 break;
794 if ((buf.getLen() == 15) &&
795 (!memcmp(buf.getString(0), fakePage, 15))) {
796 cancelled = false;
797 if (spoolOpen) {
798 fclose(f);
799 infolog("Cancelled job %s", jname);
800 unlink(jname);
801 break;
802 }
803 continue;
804 }
805 if (!spoolOpen && !cancelled) {
806 sprintf(jname, "%s/%s", spooldir, TEMPLATE);
807 if ((fd = mkstemp(jname)) != -1) {
808 infolog("Receiving new job %s", jname);
809 spoolOpen = true;
810 pageStart = true;
811 pageCount = 0;
812 } else {
813 errorlog("Could not create spool file.");
814 cancelled = true;
815 wPrt->cancelJob();
816 }
817 f = fdopen(fd, "w");
818 plen = 0;
819 }
820 b = buf.getByte(0);
821 if ((b != 0x2a) && (b != 0xff)) {
822 errorlog("Invalid packet type 0x%02x.", b);
823 cancelled = true;
824 wPrt->cancelJob();
825 }
826 jobEnd = (b == 0xff);
827 if (!cancelled) {
828 buf.discardFirstBytes(1);
829 if (pageStart) {
830 b = buf.getByte(0);
831 plen = buf.getDWord(1) - 8;
832 buf.discardFirstBytes(5+8);
833 pageStart = false;
834 pageBuf.init();
835 }
836 pageBuf.addBuff(buf);
837 plen -= buf.getLen();
838 if (plen <= 0) {
839 convertPage(f, pageCount++, jobEnd, pageBuf);
840 pageBuf.init();
841 pageStart = true;
842 }
843 }
844 if (jobEnd) {
845 if (spoolOpen)
846 fclose(f);
847 if (!cancelled) {
848 if (pageCount > 0) {
849 if (!printcmd)
850 infolog("Output stored in %s", jname);
851 else {
852 int r;
853 char cbuf[4096];
854
855 infolog("Spooling %d pages", pageCount);
856 FILE *pipe = popen(printcmd, "w");
857 if (!pipe) {
858 errorlog("Could not execute %s: %m",
859 printcmd);
860 unlink(jname);
861 }
862 f = fopen(jname, "r");
863 if (!f) {
864 errorlog("Could not read %s: %m",
865 jname);
866 pclose(pipe);
867 unlink(jname);
868 }
869 while ((r = fread(cbuf, 1,
870 sizeof(cbuf), f)) > 0)
871 fwrite(cbuf, 1, r, pipe);
872 pclose(pipe);
873 fclose(f);
874 unlink(jname);
875 }
876 }
877 } else
878 unlink(jname);
879 spoolOpen = false;
880 }
881 break;
882 }
883 }
884 free(jname);
885 }
886}
887
888static void
890 cout <<
891 "Options of plpprintd:\n"
892 "\n"
893 " -d, --debug Debugging, do not fork.\n"
894 " -h, --help Display this text.\n"
895 " -v, --verbose Increase verbosity.\n"
896 " -V, --version Print version and exit.\n"
897 " -p, --port=[HOST:]PORT Connect to port PORT on host HOST.\n"
898 " -s, --spooldir=DIR Specify spooldir DIR.\n"
899 " Default: " SPOOLDIR "\n"
900 " -c, --printcmd=CMD Specify print command.\n"
901 " Default: " PRINTCMD "\n";
902}
903
904static void
906 cerr << "Usage: plpprintd [OPTIONS]" << endl
907 << "Use --help for more information" << endl;
908}
909
910static struct option opts[] = {
911 {"debug", no_argument, nullptr, 'd'},
912 {"help", no_argument, nullptr, 'h'},
913 {"version", no_argument, nullptr, 'V'},
914 {"verbose", no_argument, nullptr, 'v'},
915 {"port", required_argument, nullptr, 'p'},
916 {"spooldir", required_argument, nullptr, 's'},
917 {"printcmd", required_argument, nullptr, 'c'},
918 {nullptr, 0, nullptr, 0 }
919};
920
921int
922main(int argc, char **argv)
923{
924 TCPSocket *skt;
925 string host = "127.0.0.1";
926 int sockNum = cli_utils::lookup_default_port();
927 int ret = 0;
928 int c;
929
930 while (1) {
931 c = getopt_long(argc, argv, "dhVvp:s:c:", opts, NULL);
932 if (c == -1)
933 break;
934 switch (c) {
935 case '?':
936 usage();
937 return -1;
938 case 'd':
939 debug = true;
940 break;
941 case 'v':
942 verbose++;
943 break;
944 case 'V':
945 cout << "plpprintd Version " << VERSION << endl;
946 return 0;
947 case 'h':
948 help();
949 return 0;
950 case 'p':
951 if (!cli_utils::parse_port(optarg, &host, &sockNum)) {
952 cout << _("Invalid port definition.") << endl;
953 return 1;
954 }
955 break;
956 case 's':
957 spooldir = strdup(optarg);
958 break;
959 case 'c':
960 if (!strcmp(optarg, "-"))
961 printcmd = NULL;
962 else
963 printcmd = strdup(optarg);
964 break;
965 }
966 }
967 if (optind < argc) {
968 usage();
969 return -1;
970 }
971
972 skt = new TCPSocket();
973 if (!skt->connect(host.c_str(), sockNum)) {
974 cout << _("plpprintd: could not connect to ncpd") << endl;
975 return 1;
976 }
977 if (!debug)
978 ret = fork();
979 switch (ret) {
980 case 0:
981 /* child */
982 setsid();
983 ignore_value(chdir("/"));
984 if (!debug) {
985 openlog("plpprintd", LOG_PID|LOG_CONS, LOG_DAEMON);
986 int devnull =
987 open("/dev/null", O_RDWR, 0);
988 if (devnull != -1) {
989 dup2(devnull, STDIN_FILENO);
990 dup2(devnull, STDOUT_FILENO);
991 dup2(devnull, STDERR_FILENO);
992 if (devnull > 2)
993 close(devnull);
994 }
995 }
996 init_fontmap();
997 infolog("started, waiting for requests.");
998 serviceLoop = true;
999 while (serviceLoop) {
1000 wPrt = new wprt(skt);
1001 if (wPrt) {
1002 Enum<rfsv::errs> ret;
1003 ret = wPrt->initPrinter();
1004 if (ret == rfsv::E_PSI_GEN_NONE)
1005 service_loop();
1006 else {
1007 if (debug)
1008 debuglog("plpprintd: could not connect: %s",
1009 ret.toString().c_str());
1010 }
1011 delete wPrt;
1012 sleep(1);
1013 } else {
1014 errorlog("plpprintd: Could not create wprt object");
1015 exit(1);
1016 }
1017 }
1018 break;
1019 case -1:
1020 cerr << "plpprintd: fork failed" << endl;
1021 return 1;
1022 default:
1023 /* parent */
1024 break;
1025 }
1026 return 0;
1027}
Wrapper class featuring range-checking and string representation of enumerated values.
Definition: Enum.h:136
std::string toString() const
returns the String representation for the value represented by this instance.
Definition: Enum.h:214
A class for dealing with sockets.
Definition: tcpsocket.h:38
virtual bool connect(const char *const Peer, int PeerPort, const char *const Host=NULL, int HostPort=0)
Connects to a given host.
Definition: tcpsocket.cc:153
A generic container for an array of bytes.
Definition: bufferstore.h:37
void discardFirstBytes(int len=0)
Removes bytes from the start of the buffer.
Definition: bufferstore.cc:143
void init()
Initializes the bufferStore.
Definition: bufferstore.cc:77
uint16_t getWord(long pos=0) const
Retrieves the word at index pos.
Definition: bufferstore.cc:102
void addBuff(const bufferStore &b, long maxLen=-1)
Appends data to the content of this instance.
Definition: bufferstore.cc:182
const char * getString(long pos=0) const
Retrieves the characters at index pos.
Definition: bufferstore.cc:120
unsigned long getLen() const
Retrieves the length of a bufferStore.
Definition: bufferstore.cc:94
uint32_t getDWord(long pos=0) const
Retrieves the dword at index pos.
Definition: bufferstore.cc:106
unsigned char getByte(long pos=0) const
Retrieves the byte at index pos.
Definition: bufferstore.cc:98
@ E_PSI_GEN_NONE
Definition: rfsv.h:110
@ E_PSI_FILE_DISC
Definition: rfsv.h:152
Remote Print services via PLP.
Definition: wprt.h:34
Enum< rfsv::errs > cancelJob()
Cancels a running job.
Definition: wprt.cc:138
Enum< rfsv::errs > initPrinter()
Init Printer.
Definition: wprt.cc:109
Enum< rfsv::errs > getData(bufferStore &buf)
Get Print Data.
Definition: wprt.cc:128
bool parse_port(const std::string &arg, std::string *host, int *port)
Definition: cli_utils.cc:52
int lookup_default_port()
Definition: cli_utils.cc:43
Definition: doctest.h:522
static rpcs * r
Definition: main.cc:56
#define _(String)
Definition: plpintl.h:35
int verbose
Definition: plpprintd.cc:58
#define PRINTCMD
Definition: plpprintd.cc:47
wprt * wPrt
Definition: plpprintd.cc:55
static void init_fontmap()
Definition: plpprintd.cc:144
const char * spooldir
Definition: plpprintd.cc:53
static int miny
Definition: plpprintd.cc:100
void debuglog(const char *fmt,...)
Definition: plpprintd.cc:74
static int maxx
Definition: plpprintd.cc:100
bool debug
Definition: plpprintd.cc:57
int main(int argc, char **argv)
Definition: plpprintd.cc:922
static int maxy
Definition: plpprintd.cc:100
#define TEMPLATE
Definition: plpprintd.cc:46
struct const_fontmap_entry_s const_fontmap_entry
static void usage()
Definition: plpprintd.cc:905
static const void service_loop()
Definition: plpprintd.cc:767
static struct option opts[]
Definition: plpprintd.cc:910
static void ps_bitmap(FILE *f, unsigned long llx, unsigned long lly, unsigned long urx, unsigned long ury, const char *buf)
Definition: plpprintd.cc:267
static void _log(int priority, const char *fmt, va_list ap)
Definition: plpprintd.cc:61
const char * printcmd
Definition: plpprintd.cc:54
void errorlog(const char *fmt,...)
Definition: plpprintd.cc:83
static int minx
Definition: plpprintd.cc:100
static void convertPage(FILE *f, int page, bool last, bufferStore buf)
Definition: plpprintd.cc:285
struct fontmap_entry_s fontmap_entry
bool serviceLoop
Definition: plpprintd.cc:56
void infolog(const char *fmt,...)
Definition: plpprintd.cc:92
static unsigned char fakePage[15]
Definition: plpprintd.cc:760
static void ps_escape(string &text)
Definition: plpprintd.cc:257
static fontmap_entry * fontmap
Definition: plpprintd.cc:141
#define SPOOLDIR
Definition: plpprintd.cc:48
#define FALLBACK_FONT
Definition: plpprintd.cc:118
#define PSDICT
Definition: plpprintd.cc:49
static void help()
Definition: plpprintd.cc:889
string usedfonts
Definition: plpprintd.cc:101
static void ps_setfont(FILE *f, const char *fname, bool bold, bool italic, unsigned long fsize)
Definition: plpprintd.cc:228
static const_fontmap_entry default_fontmap[]
Definition: plpprintd.cc:120
bool decodeBitmap(const unsigned char *p, int &width, int &height, bufferStore &out)
Convert a Psion bitmap to a 8bit/pixel grayscale image.
Definition: psibitmap.cpp:141
Definition: plpprintd.cc:111
const char * psifont
Definition: plpprintd.cc:112
bool italic
Definition: plpprintd.cc:114
const char * psfont
Definition: plpprintd.cc:115
bool bold
Definition: plpprintd.cc:113
Definition: plpprintd.cc:103
struct fontmap_entry_s * next
Definition: plpprintd.cc:104
bool bold
Definition: plpprintd.cc:106
char * psifont
Definition: plpprintd.cc:105
bool italic
Definition: plpprintd.cc:107
char * psfont
Definition: plpprintd.cc:108