39#include "ignore-value.h"
46#define TEMPLATE "plpprint_XXXXXX"
47#define PRINTCMD "lpr -Ppsion"
48#define SPOOLDIR "/var/spool/plpprint"
49#define PSDICT "/prolog.ps"
61_log(
int priority,
const char *fmt, va_list ap)
64 if (vasprintf(&buf, fmt, ap) == -1)
69 syslog(priority,
"%s", buf);
78 _log(LOG_DEBUG, fmt, ap);
87 _log(LOG_ERR, fmt, ap);
96 _log(LOG_INFO, fmt, ap);
118#define FALLBACK_FONT "Courier"
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}
149 if ((f = fopen(PKGDATADIR
"/fontmap",
"r"))) {
157 while (fgets(buf,
sizeof(buf), f)) {
160 if ((p = strchr(buf,
'#')))
162 if ((p = strchr(buf,
'\n')))
165 psifont = strsep(&bp,
":");
166 if (!psifont || !(*psifont))
168 tmp = strsep(&bp,
":");
169 if (!tmp || !(*tmp) || (sscanf(tmp,
"%d", &bold) != 1))
171 tmp = strsep(&bp,
":");
172 if (!tmp || !(*tmp) || (sscanf(tmp,
"%d", &italic) != 1))
174 psfont = strsep(&bp,
":");
175 if (!psfont || !(*psfont))
180 if (!(fe->
psifont = strdup(psifont))) {
184 if (!(fe->
psfont = strdup(psfont))) {
189 fe->
bold = bold ? true :
false;
190 fe->
italic = italic ? true :
false;
191 fe->
next = new_fontmap;
196 if (new_fontmap && (new_fontmap->
psifont))
199 errorlog(
"No fontmap found in %s/fontmap, using builtin mapping",
206 nfe->
psifont = strdup(cfe->psifont);
207 nfe->
bold = cfe->bold;
208 nfe->
italic = cfe->italic;
209 nfe->
psfont = strdup(cfe->psfont);
215 debuglog(
"%-20s%-7s%-7s%-20s",
"Psion",
"Bold",
"Italic",
"PS-Font");
219 fe->
bold ?
"true" :
"false",
220 fe->
italic ?
"true" :
"false",
228ps_setfont(FILE *f,
const char *fname,
bool bold,
bool italic,
232 const char *psf = NULL;
234 if ((!strcmp(fe->
psifont, fname)) &&
235 (fe->
bold == bold) &&
244 errorlog(
"No font mapping for '%s' (%s%s%s); fallback to %s",
245 fname, (bold) ?
"Bold" :
"", (italic) ?
"Italic" :
"",
246 (bold || italic) ?
"" :
"Regular", psf);
253 fprintf(f,
"%ld /%s F\n", fsize, psf);
260 while ((pos = text.find_first_of(
"()", pos)) != text.npos) {
261 text.insert(pos,
"\\");
267ps_bitmap(FILE *f,
unsigned long llx,
unsigned long lly,
unsigned long urx,
268 unsigned long ury,
const char *buf)
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++);
290 unsigned long left = 0;
291 unsigned long top = 0;
292 unsigned long right = 0;
293 unsigned long bottom = 0;
297 sprintf(dumpname,
"/tmp/pdump_%d", page);
298 FILE *df = fopen(dumpname,
"w");
301 debuglog(
"Saved page input to %s", dumpname);
304 time_t now = time(NULL);
307 "%%Creator: plpprintd " VERSION
"\n"
308 "%%CreationDate: ", f);
309 fputs(ctime(&now), f);
312 "%%BoundingBox: (atend)\n"
313 "%%DocumentNeededResources: (atend)\n"
314 "%%LanguageLevel: 2\n"
316 "%%BeginProlog\n", f);
318 FILE *pf = fopen(PKGDATADIR
PSDICT,
"r");
319 while (fgets(pbuf,
sizeof(pbuf), pf))
325 "currentpagedevice /PageSize get 1 get /top exch def\n"
326 "ip 1 1 TH 32 DM RC 1 PS\n"
332 fprintf(f,
"%%%%Page: %d %d\n", page+1, page+1);
334 unsigned char opcode = buf.
getByte(i);
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");
354 unsigned char drwmode = buf.
getByte(i+1);
355 fprintf(f,
"%% @%d: Drawing mode %02x\n", i, drwmode);
397 fprintf(f,
"%d DM\n", drwmode);
416 fprintf(f,
"%% @%d: bbox %ld %ld %ld %ld\n", i, left, top, right,
418 fprintf(f,
"%ld %ld %ld %ld CB\n", left, top, right, bottom);
423 left = top = right = bottom = 0;
424 fprintf(f,
"%% @%d: Cancel Cliprect\n", i);
431 fprintf(f,
"%% @%d: U06 %d 0x%08x\n", i,
441 namelen = buf.
getWord(i+1) >> 3;
444 namelen = buf.
getByte(i+1) >> 2;
447 string fname(buf.
getString(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);
465 fprintf(f,
"%% @%d: End Font\n", i);
471 fprintf(f,
"%% @%d: Underline %d\n", i, buf.
getByte(i+1));
472 fprintf(f,
"%d UL\n", buf.
getByte(i+1));
478 fprintf(f,
"%% @%d: Strikethru %d\n", i, buf.
getByte(i+1));
479 fprintf(f,
"%d ST\n", buf.
getByte(i+1));
485 fprintf(f,
"%% @%d: Newline %d %d\n", i, buf.
getDWord(i+1),
492 fprintf(f,
"%% @%d: CR %d %d\n", i, buf.
getDWord(i+1),
499 fprintf(f,
"%% @%d: Foreground %d %d %d\n", i, buf.
getByte(i+1),
501 fprintf(f,
"%d %d %d FG\n", buf.
getByte(i+1),
508 unsigned char pstyle = buf.
getByte(i+1);
529 fprintf(f,
"%% @%d: Pen Style %d\n", i, pstyle);
530 fprintf(f,
"%d PS\n", pstyle);
536 fprintf(f,
"%% @%d: Pen thickness %u %u\n", i, buf.
getDWord(i+1),
544 fprintf(f,
"%% @%d: Background %d %d %d\n", i, buf.
getByte(i+1),
546 fprintf(f,
"%d %d %d BG\n", buf.
getByte(i+1),
553 unsigned char bstyle = buf.
getByte(i+1);
583 fprintf(f,
"%% @%d: Brush style %d\n", i, bstyle);
584 fprintf(f,
"%d BS\n", bstyle);
590 fprintf(f,
"%% @%d: U17 %u %u\n", i, buf.
getDWord(i+1),
597 fprintf(f,
"%% @%d: Line %u %u %u %u\n", i,
600 fprintf(f,
"%u %u %u %u L\n",
608 fprintf(f,
"%% @%d: U1b %u %u\n", i, buf.
getDWord(i+1),
615 fprintf(f,
"%% @%d: Ellipse %u %u %u %u\n", i,
618 fprintf(f,
"%u %u %u %u E\n",
626 fprintf(f,
"%% @%d: Rectangle %u %u %u %u\n", i,
629 fprintf(f,
"%u %u %u %u R\n",
638 unsigned long count = buf.
getDWord(i+1);
640 fprintf(f,
"%% @%d: Polygon (%ld segments)\n", i, count);
642 for (
int j = 0; j < count; j++) {
643 fprintf(f,
"%d %d\n", buf.
getDWord(o),
647 unsigned char frule = buf.
getByte(o);
648 fprintf(f,
"] %s P\n", frule ?
"false" :
"true");
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);
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);
677 i += (17 + blen + 16);
694 fprintf(f,
"%% @%d: Text '%s' %d %d\n", i,
696 fprintf(f,
"(%s) %d %ld 0 0 -1 T\n", text.c_str(),
718 int baseline = buf.
getDWord(ofs+16);
719 unsigned char align = buf.
getByte(ofs+20);
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);
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);
736 fprintf(f,
"@%d: UNHANDLED OPCODE %02x\n", i, opcode);
737 debuglog(
"@%d: UNHANDLED OPCODE %02x", i, opcode);
742 fprintf(f,
"showpage\n");
746 "%%DocumentNeededResources: ", f);
753 fprintf(f,
"%%%%Pages: %d\n", page + 1);
754 fprintf(f,
"%%%%BoundingBox: %d %d %d %d\n",
761 0x2a, 0x2a, 0x09, 0x00, 0x00, 0x00, 0x82, 0x2e,
762 0x00, 0x00, 0xc6, 0x41, 0x00, 0x00, 0x00,
771 bool spoolOpen =
false;
772 bool pageStart =
true;
773 bool cancelled =
false;
794 if ((buf.
getLen() == 15) &&
799 infolog(
"Cancelled job %s", jname);
805 if (!spoolOpen && !cancelled) {
807 if ((fd = mkstemp(jname)) != -1) {
808 infolog(
"Receiving new job %s", jname);
813 errorlog(
"Could not create spool file.");
821 if ((b != 0x2a) && (b != 0xff)) {
822 errorlog(
"Invalid packet type 0x%02x.", b);
826 jobEnd = (b == 0xff);
850 infolog(
"Output stored in %s", jname);
855 infolog(
"Spooling %d pages", pageCount);
858 errorlog(
"Could not execute %s: %m",
862 f = fopen(jname,
"r");
869 while ((
r = fread(cbuf, 1,
870 sizeof(cbuf), f)) > 0)
871 fwrite(cbuf, 1,
r, pipe);
891 "Options of plpprintd:\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"
900 " -c, --printcmd=CMD Specify print command.\n"
906 cerr <<
"Usage: plpprintd [OPTIONS]" << endl
907 <<
"Use --help for more information" << endl;
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 }
925 string host =
"127.0.0.1";
931 c = getopt_long(argc, argv,
"dhVvp:s:c:",
opts, NULL);
945 cout <<
"plpprintd Version " << VERSION << endl;
952 cout <<
_(
"Invalid port definition.") << endl;
960 if (!strcmp(optarg,
"-"))
973 if (!skt->
connect(host.c_str(), sockNum)) {
974 cout <<
_(
"plpprintd: could not connect to ncpd") << endl;
983 ignore_value(chdir(
"/"));
985 openlog(
"plpprintd", LOG_PID|LOG_CONS, LOG_DAEMON);
987 open(
"/dev/null", O_RDWR, 0);
989 dup2(devnull, STDIN_FILENO);
990 dup2(devnull, STDOUT_FILENO);
991 dup2(devnull, STDERR_FILENO);
997 infolog(
"started, waiting for requests.");
1008 debuglog(
"plpprintd: could not connect: %s",
1014 errorlog(
"plpprintd: Could not create wprt object");
1020 cerr <<
"plpprintd: fork failed" << endl;
Wrapper class featuring range-checking and string representation of enumerated values.
std::string toString() const
returns the String representation for the value represented by this instance.
A class for dealing with sockets.
virtual bool connect(const char *const Peer, int PeerPort, const char *const Host=NULL, int HostPort=0)
Connects to a given host.
A generic container for an array of bytes.
void discardFirstBytes(int len=0)
Removes bytes from the start of the buffer.
void init()
Initializes the bufferStore.
uint16_t getWord(long pos=0) const
Retrieves the word at index pos.
void addBuff(const bufferStore &b, long maxLen=-1)
Appends data to the content of this instance.
const char * getString(long pos=0) const
Retrieves the characters at index pos.
unsigned long getLen() const
Retrieves the length of a bufferStore.
uint32_t getDWord(long pos=0) const
Retrieves the dword at index pos.
unsigned char getByte(long pos=0) const
Retrieves the byte at index pos.
Remote Print services via PLP.
Enum< rfsv::errs > cancelJob()
Cancels a running job.
Enum< rfsv::errs > initPrinter()
Init Printer.
Enum< rfsv::errs > getData(bufferStore &buf)
Get Print Data.
bool parse_port(const std::string &arg, std::string *host, int *port)
int lookup_default_port()
static void init_fontmap()
void debuglog(const char *fmt,...)
int main(int argc, char **argv)
struct const_fontmap_entry_s const_fontmap_entry
static const void service_loop()
static struct option opts[]
static void ps_bitmap(FILE *f, unsigned long llx, unsigned long lly, unsigned long urx, unsigned long ury, const char *buf)
static void _log(int priority, const char *fmt, va_list ap)
void errorlog(const char *fmt,...)
static void convertPage(FILE *f, int page, bool last, bufferStore buf)
struct fontmap_entry_s fontmap_entry
void infolog(const char *fmt,...)
static unsigned char fakePage[15]
static void ps_escape(string &text)
static fontmap_entry * fontmap
static void ps_setfont(FILE *f, const char *fname, bool bold, bool italic, unsigned long fsize)
static const_fontmap_entry default_fontmap[]
bool decodeBitmap(const unsigned char *p, int &width, int &height, bufferStore &out)
Convert a Psion bitmap to a 8bit/pixel grayscale image.
struct fontmap_entry_s * next